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
37 class NodeMetadataList;
40 class VoxelManipulator;
42 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
44 /*// Named by looking towards z+
54 // NOTE: If this is enabled, set MapBlock to be initialized with
56 /*enum BlockGenerationStatus
58 // Completely non-generated (filled with CONTENT_IGNORE).
60 // Trees or similar might have been blitted from other blocks to here.
61 // Otherwise, the block contains CONTENT_IGNORE
62 BLOCKGEN_FROM_NEIGHBORS=2,
63 // Has been generated, but some neighbors might put some stuff in here
64 // when they are generated.
65 // Does not contain any CONTENT_IGNORE
66 BLOCKGEN_SELF_GENERATED=4,
67 // The block and all its neighbors have been generated
68 BLOCKGEN_FULLY_GENERATED=6
74 NODECONTAINER_ID_MAPBLOCK,
75 NODECONTAINER_ID_MAPSECTOR,
77 NODECONTAINER_ID_MAPBLOCKCACHE,
78 NODECONTAINER_ID_VOXELMANIPULATOR,
84 virtual bool isValidPosition(v3s16 p) = 0;
85 virtual MapNode getNode(v3s16 p) = 0;
86 virtual void setNode(v3s16 p, MapNode & n) = 0;
87 virtual u16 nodeContainerId() const = 0;
89 MapNode getNodeNoEx(v3s16 p)
94 catch(InvalidPositionException &e){
95 return MapNode(CONTENT_IGNORE);
102 //// MapBlock modified reason flags
105 #define MOD_REASON_INITIAL (1 << 0)
106 #define MOD_REASON_REALLOCATE (1 << 1)
107 #define MOD_REASON_SET_IS_UNDERGROUND (1 << 2)
108 #define MOD_REASON_SET_LIGHTING_COMPLETE (1 << 3)
109 #define MOD_REASON_SET_GENERATED (1 << 4)
110 #define MOD_REASON_SET_NODE (1 << 5)
111 #define MOD_REASON_SET_NODE_NO_CHECK (1 << 6)
112 #define MOD_REASON_SET_TIMESTAMP (1 << 7)
113 #define MOD_REASON_REPORT_META_CHANGE (1 << 8)
114 #define MOD_REASON_CLEAR_ALL_OBJECTS (1 << 9)
115 #define MOD_REASON_BLOCK_EXPIRED (1 << 10)
116 #define MOD_REASON_ADD_ACTIVE_OBJECT_RAW (1 << 11)
117 #define MOD_REASON_REMOVE_OBJECTS_REMOVE (1 << 12)
118 #define MOD_REASON_REMOVE_OBJECTS_DEACTIVATE (1 << 13)
119 #define MOD_REASON_TOO_MANY_OBJECTS (1 << 14)
120 #define MOD_REASON_STATIC_DATA_ADDED (1 << 15)
121 #define MOD_REASON_STATIC_DATA_REMOVED (1 << 16)
122 #define MOD_REASON_STATIC_DATA_CHANGED (1 << 17)
123 #define MOD_REASON_EXPIRE_DAYNIGHTDIFF (1 << 18)
124 #define MOD_REASON_UNKNOWN (1 << 19)
130 class MapBlock /*: public NodeContainer*/
133 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
136 /*virtual u16 nodeContainerId() const
138 return NODECONTAINER_ID_MAPBLOCK;
149 data = new MapNode[nodecount];
150 for (u32 i = 0; i < nodecount; i++)
151 data[i] = MapNode(CONTENT_IGNORE);
153 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_REALLOCATE);
157 //// Modification tracking methods
159 void raiseModified(u32 mod, u32 reason=MOD_REASON_UNKNOWN)
161 if (mod > m_modified) {
163 m_modified_reason = reason;
164 if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD)
165 m_disk_timestamp = m_timestamp;
166 } else if (mod == m_modified) {
167 m_modified_reason |= reason;
171 inline u32 getModified()
176 inline u32 getModifiedReason()
178 return m_modified_reason;
181 std::string getModifiedReasonString();
183 inline void resetModified()
185 m_modified = MOD_STATE_CLEAN;
186 m_modified_reason = 0;
193 inline bool isDummy()
195 return (data == NULL);
198 inline void unDummify()
200 assert(isDummy()); // Pre-condition
204 // is_underground getter/setter
205 inline bool getIsUnderground()
207 return is_underground;
210 inline void setIsUnderground(bool a_is_underground)
212 is_underground = a_is_underground;
213 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
216 inline void setLightingComplete(u16 newflags)
218 if (newflags != m_lighting_complete) {
219 m_lighting_complete = newflags;
220 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_COMPLETE);
224 inline u16 getLightingComplete()
226 return m_lighting_complete;
229 inline void setLightingComplete(LightBank bank, u8 direction,
232 assert(direction >= 0 && direction <= 5);
233 if (bank == LIGHTBANK_NIGHT) {
236 u16 newflags = m_lighting_complete;
238 newflags |= 1 << direction;
240 newflags &= ~(1 << direction);
242 setLightingComplete(newflags);
245 inline bool isLightingComplete(LightBank bank, u8 direction)
247 assert(direction >= 0 && direction <= 5);
248 if (bank == LIGHTBANK_NIGHT) {
251 return (m_lighting_complete & (1 << direction)) != 0;
254 inline bool isGenerated()
259 inline void setGenerated(bool b)
261 if (b != m_generated) {
262 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_GENERATED);
271 inline v3s16 getPos()
276 inline v3s16 getPosRelative()
278 return m_pos_relative;
281 inline core::aabbox3d<s16> getBox()
283 return core::aabbox3d<s16>(getPosRelative(),
285 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
290 //// Regular MapNode get-setters
293 inline bool isValidPosition(s16 x, s16 y, s16 z)
296 && x >= 0 && x < MAP_BLOCKSIZE
297 && y >= 0 && y < MAP_BLOCKSIZE
298 && z >= 0 && z < MAP_BLOCKSIZE;
301 inline bool isValidPosition(v3s16 p)
303 return isValidPosition(p.X, p.Y, p.Z);
306 inline MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
308 *valid_position = isValidPosition(x, y, z);
310 if (!*valid_position)
311 return MapNode(CONTENT_IGNORE);
313 return data[z * zstride + y * ystride + x];
316 inline MapNode getNode(v3s16 p, bool *valid_position)
318 return getNode(p.X, p.Y, p.Z, valid_position);
321 inline MapNode getNodeNoEx(v3s16 p)
324 return getNode(p.X, p.Y, p.Z, &is_valid);
327 inline void setNode(s16 x, s16 y, s16 z, MapNode & n)
329 if (!isValidPosition(x, y, z))
330 throw InvalidPositionException();
332 data[z * zstride + y * ystride + x] = n;
333 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
336 inline void setNode(v3s16 p, MapNode & n)
338 setNode(p.X, p.Y, p.Z, n);
342 //// Non-checking variants of the above
345 inline MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
347 *valid_position = data != NULL;
349 return MapNode(CONTENT_IGNORE);
351 return data[z * zstride + y * ystride + x];
354 inline MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
356 return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
360 //// Non-checking, unsafe variants of the above
361 //// MapBlock must be loaded by another function in the same scope/function
362 //// Caller must ensure that this is not a dummy block (by calling isDummy())
365 inline const MapNode &getNodeUnsafe(s16 x, s16 y, s16 z)
367 return data[z * zstride + y * ystride + x];
370 inline const MapNode &getNodeUnsafe(v3s16 &p)
372 return getNodeUnsafe(p.X, p.Y, p.Z);
375 inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
378 throw InvalidPositionException();
380 data[z * zstride + y * ystride + x] = n;
381 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE_NO_CHECK);
384 inline void setNodeNoCheck(v3s16 p, MapNode & n)
386 setNodeNoCheck(p.X, p.Y, p.Z, n);
389 // These functions consult the parent container if the position
390 // is not valid on this MapBlock.
391 bool isValidPositionParent(v3s16 p);
392 MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
393 void setNodeParent(v3s16 p, MapNode & n);
395 inline void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
397 for (u16 z = 0; z < d; z++)
398 for (u16 y = 0; y < h; y++)
399 for (u16 x = 0; x < w; x++)
400 setNode(x0 + x, y0 + y, z0 + z, node);
403 // See comments in mapblock.cpp
404 bool propagateSunlight(std::set<v3s16> &light_sources,
405 bool remove_light=false, bool *black_air_left=NULL);
407 // Copies data to VoxelManipulator to getPosRelative()
408 void copyTo(VoxelManipulator &dst);
410 // Copies data from VoxelManipulator getPosRelative()
411 void copyFrom(VoxelManipulator &dst);
413 // Update day-night lighting difference flag.
414 // Sets m_day_night_differs to appropriate value.
415 // These methods don't care about neighboring blocks.
416 void actuallyUpdateDayNightDiff();
418 // Call this to schedule what the previous function does to be done
419 // when the value is actually needed.
420 void expireDayNightDiff();
422 inline bool getDayNightDiff()
424 if (m_day_night_differs_expired)
425 actuallyUpdateDayNightDiff();
426 return m_day_night_differs;
430 //// Miscellaneous stuff
434 Tries to measure ground level.
439 0...MAP_BLOCKSIZE-1 = ground level
441 s16 getGroundLevel(v2s16 p2d);
444 //// Timestamp (see m_timestamp)
447 // NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
449 inline void setTimestamp(u32 time)
452 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_TIMESTAMP);
455 inline void setTimestampNoChangedFlag(u32 time)
460 inline u32 getTimestamp()
465 inline u32 getDiskTimestamp()
467 return m_disk_timestamp;
471 //// Usage timer (see m_usage_timer)
474 inline void resetUsageTimer()
479 inline void incrementUsageTimer(float dtime)
481 m_usage_timer += dtime;
484 inline float getUsageTimer()
486 return m_usage_timer;
490 //// Reference counting (see m_refcount)
493 inline void refGrab()
498 inline void refDrop()
512 inline NodeTimer getNodeTimer(v3s16 p)
514 return m_node_timers.get(p);
517 inline void removeNodeTimer(v3s16 p)
519 m_node_timers.remove(p);
522 inline void setNodeTimer(const NodeTimer &t)
524 m_node_timers.set(t);
527 inline void clearNodeTimers()
529 m_node_timers.clear();
536 // These don't write or read version by itself
537 // Set disk to true for on-disk format, false for over-the-network format
538 // Precondition: version >= SER_FMT_VER_LOWEST_WRITE
539 void serialize(std::ostream &os, u8 version, bool disk);
540 // If disk == true: In addition to doing other things, will add
541 // unknown blocks from id-name mapping to wndef
542 void deSerialize(std::istream &is, u8 version, bool disk);
544 void serializeNetworkSpecific(std::ostream &os);
545 void deSerializeNetworkSpecific(std::istream &is);
551 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
554 Used only internally, because changes can't be tracked
557 inline MapNode &getNodeRef(s16 x, s16 y, s16 z)
559 if (!isValidPosition(x, y, z))
560 throw InvalidPositionException();
562 return data[z * zstride + y * ystride + x];
565 inline MapNode &getNodeRef(v3s16 &p)
567 return getNodeRef(p.X, p.Y, p.Z);
572 Public member variables
575 #ifndef SERVER // Only on client
579 NodeMetadataList m_node_metadata;
580 NodeTimerList m_node_timers;
581 StaticObjectList m_static_objects;
583 static const u32 ystride = MAP_BLOCKSIZE;
584 static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
586 static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
590 Private member variables
593 // NOTE: Lots of things rely on this being the Map
595 // Position in blocks on parent
598 /* This is the precalculated m_pos_relative value
599 * This caches the value, improving performance by removing 3 s16 multiplications
600 * at runtime on each getPosRelative call
601 * For a 5 minutes runtime with valgrind this removes 3 * 19M s16 multiplications
602 * The gain can be estimated in Release Build to 3 * 100M multiply operations for 5 mins
604 v3s16 m_pos_relative;
609 If NULL, block is a dummy block.
610 Dummy blocks are used for caching not-found-on-disk blocks.
615 - On the server, this is used for telling whether the
616 block has been modified from the one on disk.
617 - On the client, this is used for nothing.
620 u32 m_modified_reason;
623 When propagating sunlight and the above block doesn't exist,
624 sunlight is assumed if this is false.
626 In practice this is set to true if the block is completely
627 undeground with nothing visible above the ground except
633 * Each bit indicates if light spreading was finished
634 * in a direction. (Because the neighbor could also be unloaded.)
635 * Bits: day X+, day Y+, day Z+, day Z-, day Y-, day X-,
636 * night X+, night Y+, night Z+, night Z-, night Y-, night X-,
637 * nothing, nothing, nothing, nothing.
639 u16 m_lighting_complete;
641 // Whether day and night lighting differs
642 bool m_day_night_differs;
643 bool m_day_night_differs_expired;
648 When block is removed from active blocks, this is set to gametime.
649 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
652 // The on-disk (or to-be on-disk) timestamp value
653 u32 m_disk_timestamp;
656 When the block is accessed, this is set to 0.
657 Map will unload the block when this reaches a timeout.
662 Reference count; currently used for determining if this block is in
663 the list of blocks to be drawn.
668 typedef std::vector<MapBlock*> MapBlockVect;
670 inline bool objectpos_over_limit(v3f p)
672 const float max_limit_bs = MAX_MAP_GENERATION_LIMIT * BS;
673 return p.X < -max_limit_bs ||
674 p.X > max_limit_bs ||
675 p.Y < -max_limit_bs ||
676 p.Y > max_limit_bs ||
677 p.Z < -max_limit_bs ||
681 inline bool blockpos_over_max_limit(v3s16 p)
683 const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
684 return p.X < -max_limit_bp ||
685 p.X > max_limit_bp ||
686 p.Y < -max_limit_bp ||
687 p.Y > max_limit_bp ||
688 p.Z < -max_limit_bp ||
692 inline bool blockpos_over_mapgen_limit(v3s16 p)
694 const s16 mapgen_limit_bp = rangelim(
695 g_settings->getS16("map_generation_limit"), 0, MAX_MAP_GENERATION_LIMIT) /
697 return p.X < -mapgen_limit_bp ||
698 p.X > mapgen_limit_bp ||
699 p.Y < -mapgen_limit_bp ||
700 p.Y > mapgen_limit_bp ||
701 p.Z < -mapgen_limit_bp ||
702 p.Z > mapgen_limit_bp;
706 Returns the position of the block where the node is located
708 inline v3s16 getNodeBlockPos(v3s16 p)
710 return getContainerPos(p, MAP_BLOCKSIZE);
713 inline v2s16 getNodeSectorPos(v2s16 p)
715 return getContainerPos(p, MAP_BLOCKSIZE);
718 inline s16 getNodeBlockY(s16 y)
720 return getContainerPos(y, MAP_BLOCKSIZE);
723 inline void getNodeBlockPosWithOffset(const v3s16 &p, v3s16 &block, v3s16 &offset)
725 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
728 inline void getNodeSectorPosWithOffset(const v2s16 &p, v2s16 &block, v2s16 &offset)
730 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
734 Get a quick string to describe what a block actually contains
736 std::string analyze_block(MapBlock *block);