3 Copyright (C) 2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser 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
27 #include "exceptions.h"
28 #include "constants.h"
29 #include "staticobject.h"
30 #include "nodemetadata.h"
31 #include "nodetimer.h"
32 #include "modifiedstate.h"
33 #include "util/numeric.h" // getContainerPos
38 class NodeMetadataList;
41 class VoxelManipulator;
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);
103 //// MapBlock modified reason flags
106 #define MOD_REASON_INITIAL (1 << 0)
107 #define MOD_REASON_REALLOCATE (1 << 1)
108 #define MOD_REASON_SET_IS_UNDERGROUND (1 << 2)
109 #define MOD_REASON_SET_LIGHTING_COMPLETE (1 << 3)
110 #define MOD_REASON_SET_GENERATED (1 << 4)
111 #define MOD_REASON_SET_NODE (1 << 5)
112 #define MOD_REASON_SET_NODE_NO_CHECK (1 << 6)
113 #define MOD_REASON_SET_TIMESTAMP (1 << 7)
114 #define MOD_REASON_REPORT_META_CHANGE (1 << 8)
115 #define MOD_REASON_CLEAR_ALL_OBJECTS (1 << 9)
116 #define MOD_REASON_BLOCK_EXPIRED (1 << 10)
117 #define MOD_REASON_ADD_ACTIVE_OBJECT_RAW (1 << 11)
118 #define MOD_REASON_REMOVE_OBJECTS_REMOVE (1 << 12)
119 #define MOD_REASON_REMOVE_OBJECTS_DEACTIVATE (1 << 13)
120 #define MOD_REASON_TOO_MANY_OBJECTS (1 << 14)
121 #define MOD_REASON_STATIC_DATA_ADDED (1 << 15)
122 #define MOD_REASON_STATIC_DATA_REMOVED (1 << 16)
123 #define MOD_REASON_STATIC_DATA_CHANGED (1 << 17)
124 #define MOD_REASON_EXPIRE_DAYNIGHTDIFF (1 << 18)
125 #define MOD_REASON_UNKNOWN (1 << 19)
131 class MapBlock /*: public NodeContainer*/
134 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
137 /*virtual u16 nodeContainerId() const
139 return NODECONTAINER_ID_MAPBLOCK;
150 data = new MapNode[nodecount];
151 for (u32 i = 0; i < nodecount; i++)
152 data[i] = MapNode(CONTENT_IGNORE);
154 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_REALLOCATE);
163 //// Modification tracking methods
165 void raiseModified(u32 mod, u32 reason=MOD_REASON_UNKNOWN)
167 if (mod > m_modified) {
169 m_modified_reason = reason;
170 if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD)
171 m_disk_timestamp = m_timestamp;
172 } else if (mod == m_modified) {
173 m_modified_reason |= reason;
177 inline u32 getModified()
182 inline u32 getModifiedReason()
184 return m_modified_reason;
187 std::string getModifiedReasonString();
189 inline void resetModified()
191 m_modified = MOD_STATE_CLEAN;
192 m_modified_reason = 0;
199 inline bool isDummy()
201 return (data == NULL);
204 inline void unDummify()
206 assert(isDummy()); // Pre-condition
210 // is_underground getter/setter
211 inline bool getIsUnderground()
213 return is_underground;
216 inline void setIsUnderground(bool a_is_underground)
218 is_underground = a_is_underground;
219 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
222 inline void setLightingComplete(u16 newflags)
224 if (newflags != m_lighting_complete) {
225 m_lighting_complete = newflags;
226 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_COMPLETE);
230 inline u16 getLightingComplete()
232 return m_lighting_complete;
235 inline void setLightingComplete(LightBank bank, u8 direction,
238 assert(direction >= 0 && direction <= 5);
239 if (bank == LIGHTBANK_NIGHT) {
242 u16 newflags = m_lighting_complete;
244 newflags |= 1 << direction;
246 newflags &= ~(1 << direction);
248 setLightingComplete(newflags);
251 inline bool isLightingComplete(LightBank bank, u8 direction)
253 assert(direction >= 0 && direction <= 5);
254 if (bank == LIGHTBANK_NIGHT) {
257 return (m_lighting_complete & (1 << direction)) != 0;
260 inline bool isGenerated()
265 inline void setGenerated(bool b)
267 if (b != m_generated) {
268 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_GENERATED);
277 inline v3s16 getPos()
282 inline v3s16 getPosRelative()
284 return m_pos_relative;
287 inline core::aabbox3d<s16> getBox()
289 return core::aabbox3d<s16>(getPosRelative(),
291 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
296 //// Regular MapNode get-setters
299 inline bool isValidPosition(s16 x, s16 y, s16 z)
302 && x >= 0 && x < MAP_BLOCKSIZE
303 && y >= 0 && y < MAP_BLOCKSIZE
304 && z >= 0 && z < MAP_BLOCKSIZE;
307 inline bool isValidPosition(v3s16 p)
309 return isValidPosition(p.X, p.Y, p.Z);
312 inline MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
314 *valid_position = isValidPosition(x, y, z);
316 if (!*valid_position)
317 return MapNode(CONTENT_IGNORE);
319 return data[z * zstride + y * ystride + x];
322 inline MapNode getNode(v3s16 p, bool *valid_position)
324 return getNode(p.X, p.Y, p.Z, valid_position);
327 inline MapNode getNodeNoEx(v3s16 p)
330 return getNode(p.X, p.Y, p.Z, &is_valid);
333 inline void setNode(s16 x, s16 y, s16 z, MapNode & n)
335 if (!isValidPosition(x, y, z))
336 throw InvalidPositionException();
338 data[z * zstride + y * ystride + x] = n;
339 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
342 inline void setNode(v3s16 p, MapNode & n)
344 setNode(p.X, p.Y, p.Z, n);
348 //// Non-checking variants of the above
351 inline MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
353 *valid_position = data != NULL;
355 return MapNode(CONTENT_IGNORE);
357 return data[z * zstride + y * ystride + x];
360 inline MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
362 return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
366 //// Non-checking, unsafe variants of the above
367 //// MapBlock must be loaded by another function in the same scope/function
368 //// Caller must ensure that this is not a dummy block (by calling isDummy())
371 inline const MapNode &getNodeUnsafe(s16 x, s16 y, s16 z)
373 return data[z * zstride + y * ystride + x];
376 inline const MapNode &getNodeUnsafe(v3s16 &p)
378 return getNodeUnsafe(p.X, p.Y, p.Z);
381 inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
384 throw InvalidPositionException();
386 data[z * zstride + y * ystride + x] = n;
387 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE_NO_CHECK);
390 inline void setNodeNoCheck(v3s16 p, MapNode & n)
392 setNodeNoCheck(p.X, p.Y, p.Z, n);
395 // These functions consult the parent container if the position
396 // is not valid on this MapBlock.
397 bool isValidPositionParent(v3s16 p);
398 MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
399 void setNodeParent(v3s16 p, MapNode & n);
401 inline void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
403 for (u16 z = 0; z < d; z++)
404 for (u16 y = 0; y < h; y++)
405 for (u16 x = 0; x < w; x++)
406 setNode(x0 + x, y0 + y, z0 + z, node);
409 // See comments in mapblock.cpp
410 bool propagateSunlight(std::set<v3s16> &light_sources,
411 bool remove_light=false, bool *black_air_left=NULL);
413 // Copies data to VoxelManipulator to getPosRelative()
414 void copyTo(VoxelManipulator &dst);
416 // Copies data from VoxelManipulator getPosRelative()
417 void copyFrom(VoxelManipulator &dst);
419 // Update day-night lighting difference flag.
420 // Sets m_day_night_differs to appropriate value.
421 // These methods don't care about neighboring blocks.
422 void actuallyUpdateDayNightDiff();
424 // Call this to schedule what the previous function does to be done
425 // when the value is actually needed.
426 void expireDayNightDiff();
428 inline bool getDayNightDiff()
430 if (m_day_night_differs_expired)
431 actuallyUpdateDayNightDiff();
432 return m_day_night_differs;
436 //// Miscellaneous stuff
440 Tries to measure ground level.
445 0...MAP_BLOCKSIZE-1 = ground level
447 s16 getGroundLevel(v2s16 p2d);
450 //// Timestamp (see m_timestamp)
453 // NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
455 inline void setTimestamp(u32 time)
458 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_TIMESTAMP);
461 inline void setTimestampNoChangedFlag(u32 time)
466 inline u32 getTimestamp()
471 inline u32 getDiskTimestamp()
473 return m_disk_timestamp;
477 //// Usage timer (see m_usage_timer)
480 inline void resetUsageTimer()
485 inline void incrementUsageTimer(float dtime)
487 m_usage_timer += dtime;
490 inline float getUsageTimer()
492 return m_usage_timer;
496 //// Reference counting (see m_refcount)
499 inline void refGrab()
504 inline void refDrop()
518 inline NodeTimer getNodeTimer(v3s16 p)
520 return m_node_timers.get(p);
523 inline void removeNodeTimer(v3s16 p)
525 m_node_timers.remove(p);
528 inline void setNodeTimer(const NodeTimer &t)
530 m_node_timers.set(t);
533 inline void clearNodeTimers()
535 m_node_timers.clear();
542 // These don't write or read version by itself
543 // Set disk to true for on-disk format, false for over-the-network format
544 // Precondition: version >= SER_FMT_VER_LOWEST_WRITE
545 void serialize(std::ostream &os, u8 version, bool disk);
546 // If disk == true: In addition to doing other things, will add
547 // unknown blocks from id-name mapping to wndef
548 void deSerialize(std::istream &is, u8 version, bool disk);
550 void serializeNetworkSpecific(std::ostream &os);
551 void deSerializeNetworkSpecific(std::istream &is);
557 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
560 Used only internally, because changes can't be tracked
563 inline MapNode &getNodeRef(s16 x, s16 y, s16 z)
565 if (!isValidPosition(x, y, z))
566 throw InvalidPositionException();
568 return data[z * zstride + y * ystride + x];
571 inline MapNode &getNodeRef(v3s16 &p)
573 return getNodeRef(p.X, p.Y, p.Z);
578 Public member variables
581 #ifndef SERVER // Only on client
585 NodeMetadataList m_node_metadata;
586 NodeTimerList m_node_timers;
587 StaticObjectList m_static_objects;
589 static const u32 ystride = MAP_BLOCKSIZE;
590 static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
592 static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
596 Private member variables
599 // NOTE: Lots of things rely on this being the Map
601 // Position in blocks on parent
604 /* This is the precalculated m_pos_relative value
605 * This caches the value, improving performance by removing 3 s16 multiplications
606 * at runtime on each getPosRelative call
607 * For a 5 minutes runtime with valgrind this removes 3 * 19M s16 multiplications
608 * The gain can be estimated in Release Build to 3 * 100M multiply operations for 5 mins
610 v3s16 m_pos_relative;
615 If NULL, block is a dummy block.
616 Dummy blocks are used for caching not-found-on-disk blocks.
621 - On the server, this is used for telling whether the
622 block has been modified from the one on disk.
623 - On the client, this is used for nothing.
626 u32 m_modified_reason;
629 When propagating sunlight and the above block doesn't exist,
630 sunlight is assumed if this is false.
632 In practice this is set to true if the block is completely
633 undeground with nothing visible above the ground except
639 * Each bit indicates if light spreading was finished
640 * in a direction. (Because the neighbor could also be unloaded.)
641 * Bits (most significant first):
642 * nothing, nothing, nothing, nothing,
643 * night X-, night Y-, night Z-, night Z+, night Y+, night X+,
644 * day X-, day Y-, day Z-, day Z+, day Y+, day X+.
646 u16 m_lighting_complete;
648 // Whether day and night lighting differs
649 bool m_day_night_differs;
650 bool m_day_night_differs_expired;
655 When block is removed from active blocks, this is set to gametime.
656 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
659 // The on-disk (or to-be on-disk) timestamp value
660 u32 m_disk_timestamp;
663 When the block is accessed, this is set to 0.
664 Map will unload the block when this reaches a timeout.
669 Reference count; currently used for determining if this block is in
670 the list of blocks to be drawn.
675 typedef std::vector<MapBlock*> MapBlockVect;
677 inline bool objectpos_over_limit(v3f p)
679 const float max_limit_bs = MAX_MAP_GENERATION_LIMIT * BS;
680 return p.X < -max_limit_bs ||
681 p.X > max_limit_bs ||
682 p.Y < -max_limit_bs ||
683 p.Y > max_limit_bs ||
684 p.Z < -max_limit_bs ||
688 inline bool blockpos_over_max_limit(v3s16 p)
690 const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
691 return p.X < -max_limit_bp ||
692 p.X > max_limit_bp ||
693 p.Y < -max_limit_bp ||
694 p.Y > max_limit_bp ||
695 p.Z < -max_limit_bp ||
700 Returns the position of the block where the node is located
702 inline v3s16 getNodeBlockPos(v3s16 p)
704 return getContainerPos(p, MAP_BLOCKSIZE);
707 inline v2s16 getNodeSectorPos(v2s16 p)
709 return getContainerPos(p, MAP_BLOCKSIZE);
712 inline s16 getNodeBlockY(s16 y)
714 return getContainerPos(y, MAP_BLOCKSIZE);
717 inline void getNodeBlockPosWithOffset(const v3s16 &p, v3s16 &block, v3s16 &offset)
719 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
722 inline void getNodeSectorPosWithOffset(const v2s16 &p, v2s16 &block, v2s16 &offset)
724 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
728 Get a quick string to describe what a block actually contains
730 std::string analyze_block(MapBlock *block);