3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #ifndef MAPBLOCK_HEADER
21 #define MAPBLOCK_HEADER
24 #include <jmutexautolock.h>
27 #include "common_irrlicht.h"
29 #include "exceptions.h"
30 #include "serialization.h"
31 #include "constants.h"
33 #include "staticobject.h"
34 #include "nodemetadata.h"
35 #include "nodetimer.h"
36 #include "modifiedstate.h"
39 class NodeMetadataList;
43 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
45 /*// Named by looking towards z+
55 // NOTE: If this is enabled, set MapBlock to be initialized with
57 /*enum BlockGenerationStatus
59 // Completely non-generated (filled with CONTENT_IGNORE).
61 // Trees or similar might have been blitted from other blocks to here.
62 // Otherwise, the block contains CONTENT_IGNORE
63 BLOCKGEN_FROM_NEIGHBORS=2,
64 // Has been generated, but some neighbors might put some stuff in here
65 // when they are generated.
66 // Does not contain any CONTENT_IGNORE
67 BLOCKGEN_SELF_GENERATED=4,
68 // The block and all its neighbors have been generated
69 BLOCKGEN_FULLY_GENERATED=6
75 NODECONTAINER_ID_MAPBLOCK,
76 NODECONTAINER_ID_MAPSECTOR,
78 NODECONTAINER_ID_MAPBLOCKCACHE,
79 NODECONTAINER_ID_VOXELMANIPULATOR,
85 virtual bool isValidPosition(v3s16 p) = 0;
86 virtual MapNode getNode(v3s16 p) = 0;
87 virtual void setNode(v3s16 p, MapNode & n) = 0;
88 virtual u16 nodeContainerId() const = 0;
90 MapNode getNodeNoEx(v3s16 p)
95 catch(InvalidPositionException &e){
96 return MapNode(CONTENT_IGNORE);
106 class MapBlock /*: public NodeContainer*/
109 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
112 /*virtual u16 nodeContainerId() const
114 return NODECONTAINER_ID_MAPBLOCK;
126 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
127 data = new MapNode[l];
128 for(u32 i=0; i<l; i++){
129 //data[i] = MapNode();
130 data[i] = MapNode(CONTENT_IGNORE);
132 raiseModified(MOD_STATE_WRITE_NEEDED, "reallocate");
141 return (data == NULL);
149 // m_modified methods
150 void raiseModified(u32 mod, const std::string &reason="unknown")
152 if(mod > m_modified){
154 m_modified_reason = reason;
155 m_modified_reason_too_long = false;
157 if(m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
158 m_disk_timestamp = m_timestamp;
160 } else if(mod == m_modified){
161 if(!m_modified_reason_too_long){
162 if(m_modified_reason.size() < 40)
163 m_modified_reason += ", " + reason;
165 m_modified_reason += "...";
166 m_modified_reason_too_long = true;
175 std::string getModifiedReason()
177 return m_modified_reason;
181 m_modified = MOD_STATE_CLEAN;
182 m_modified_reason = "none";
183 m_modified_reason_too_long = false;
186 // is_underground getter/setter
187 bool getIsUnderground()
189 return is_underground;
191 void setIsUnderground(bool a_is_underground)
193 is_underground = a_is_underground;
194 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
197 void setLightingExpired(bool expired)
199 if(expired != m_lighting_expired){
200 m_lighting_expired = expired;
201 raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
204 bool getLightingExpired()
206 return m_lighting_expired;
213 void setGenerated(bool b)
215 if(b != m_generated){
216 raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
223 if(m_lighting_expired)
239 v3s16 getPosRelative()
241 return m_pos * MAP_BLOCKSIZE;
244 core::aabbox3d<s16> getBox()
246 return core::aabbox3d<s16>(getPosRelative(),
248 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
253 Regular MapNode get-setters
256 bool isValidPosition(v3s16 p)
260 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
261 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
262 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
265 MapNode getNode(s16 x, s16 y, s16 z)
268 throw InvalidPositionException();
269 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
270 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
271 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
272 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
275 MapNode getNode(v3s16 p)
277 return getNode(p.X, p.Y, p.Z);
280 MapNode getNodeNoEx(v3s16 p)
283 return getNode(p.X, p.Y, p.Z);
284 }catch(InvalidPositionException &e){
285 return MapNode(CONTENT_IGNORE);
289 void setNode(s16 x, s16 y, s16 z, MapNode & n)
292 throw InvalidPositionException();
293 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
294 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
295 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
296 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
297 raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
300 void setNode(v3s16 p, MapNode & n)
302 setNode(p.X, p.Y, p.Z, n);
306 Non-checking variants of the above
309 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
312 throw InvalidPositionException();
313 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
316 MapNode getNodeNoCheck(v3s16 p)
318 return getNodeNoCheck(p.X, p.Y, p.Z);
321 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
324 throw InvalidPositionException();
325 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
326 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
329 void setNodeNoCheck(v3s16 p, MapNode & n)
331 setNodeNoCheck(p.X, p.Y, p.Z, n);
335 These functions consult the parent container if the position
336 is not valid on this MapBlock.
338 bool isValidPositionParent(v3s16 p);
339 MapNode getNodeParent(v3s16 p);
340 void setNodeParent(v3s16 p, MapNode & n);
341 MapNode getNodeParentNoEx(v3s16 p);
343 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
345 for(u16 z=0; z<d; z++)
346 for(u16 y=0; y<h; y++)
347 for(u16 x=0; x<w; x++)
348 setNode(x0+x, y0+y, z0+z, node);
351 // See comments in mapblock.cpp
352 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
353 bool remove_light=false, bool *black_air_left=NULL);
355 // Copies data to VoxelManipulator to getPosRelative()
356 void copyTo(VoxelManipulator &dst);
357 // Copies data from VoxelManipulator getPosRelative()
358 void copyFrom(VoxelManipulator &dst);
361 Update day-night lighting difference flag.
362 Sets m_day_night_differs to appropriate value.
363 These methods don't care about neighboring blocks.
365 void actuallyUpdateDayNightDiff();
367 Call this to schedule what the previous function does to be done
368 when the value is actually needed.
370 void expireDayNightDiff();
372 bool getDayNightDiff()
374 if(m_day_night_differs_expired)
375 actuallyUpdateDayNightDiff();
376 return m_day_night_differs;
384 Tries to measure ground level.
389 0...MAP_BLOCKSIZE-1 = ground level
391 s16 getGroundLevel(v2s16 p2d);
394 Timestamp (see m_timestamp)
395 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
397 void setTimestamp(u32 time)
400 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
402 void setTimestampNoChangedFlag(u32 time)
410 u32 getDiskTimestamp()
412 return m_disk_timestamp;
418 void resetUsageTimer()
422 void incrementUsageTimer(float dtime)
424 m_usage_timer += dtime;
428 return m_usage_timer;
435 // These don't write or read version by itself
436 // Set disk to true for on-disk format, false for over-the-network format
437 void serialize(std::ostream &os, u8 version, bool disk);
438 // If disk == true: In addition to doing other things, will add
439 // unknown blocks from id-name mapping to wndef
440 void deSerialize(std::istream &is, u8 version, bool disk);
447 void serialize_pre22(std::ostream &os, u8 version, bool disk);
448 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
451 Used only internally, because changes can't be tracked
454 MapNode & getNodeRef(s16 x, s16 y, s16 z)
457 throw InvalidPositionException();
458 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
459 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
460 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
461 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
463 MapNode & getNodeRef(v3s16 &p)
465 return getNodeRef(p.X, p.Y, p.Z);
470 Public member variables
473 #ifndef SERVER // Only on client
478 NodeMetadataList m_node_metadata;
479 NodeTimerList m_node_timers;
480 StaticObjectList m_static_objects;
484 Private member variables
487 // NOTE: Lots of things rely on this being the Map
489 // Position in blocks on parent
495 If NULL, block is a dummy block.
496 Dummy blocks are used for caching not-found-on-disk blocks.
501 - On the server, this is used for telling whether the
502 block has been modified from the one on disk.
503 - On the client, this is used for nothing.
506 std::string m_modified_reason;
507 bool m_modified_reason_too_long;
510 When propagating sunlight and the above block doesn't exist,
511 sunlight is assumed if this is false.
513 In practice this is set to true if the block is completely
514 undeground with nothing visible above the ground except
520 Set to true if changes has been made that make the old lighting
521 values wrong but the lighting hasn't been actually updated.
523 If this is false, lighting is exactly right.
524 If this is true, lighting might be wrong or right.
526 bool m_lighting_expired;
528 // Whether day and night lighting differs
529 bool m_day_night_differs;
530 bool m_day_night_differs_expired;
535 When block is removed from active blocks, this is set to gametime.
536 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
539 // The on-disk (or to-be on-disk) timestamp value
540 u32 m_disk_timestamp;
543 When the block is accessed, this is set to 0.
544 Map will unload the block when this reaches a timeout.
549 inline bool blockpos_over_limit(v3s16 p)
552 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
553 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
554 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
555 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
556 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
557 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
561 Returns the position of the block where the node is located
563 inline v3s16 getNodeBlockPos(v3s16 p)
565 return getContainerPos(p, MAP_BLOCKSIZE);
568 inline v2s16 getNodeSectorPos(v2s16 p)
570 return getContainerPos(p, MAP_BLOCKSIZE);
573 inline s16 getNodeBlockY(s16 y)
575 return getContainerPos(y, MAP_BLOCKSIZE);
579 Get a quick string to describe what a block actually contains
581 std::string analyze_block(MapBlock *block);