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_EXPIRED (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 setLightingExpired(bool expired)
218 if (expired != m_lighting_expired){
219 m_lighting_expired = expired;
220 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_EXPIRED);
224 inline bool getLightingExpired()
226 return m_lighting_expired;
229 inline bool isGenerated()
234 inline void setGenerated(bool b)
236 if (b != m_generated) {
237 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_GENERATED);
242 inline bool isValid()
244 if (m_lighting_expired)
255 inline v3s16 getPos()
260 inline v3s16 getPosRelative()
262 return m_pos_relative;
265 inline core::aabbox3d<s16> getBox()
267 return core::aabbox3d<s16>(getPosRelative(),
269 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
274 //// Regular MapNode get-setters
277 inline bool isValidPosition(s16 x, s16 y, s16 z)
280 && x >= 0 && x < MAP_BLOCKSIZE
281 && y >= 0 && y < MAP_BLOCKSIZE
282 && z >= 0 && z < MAP_BLOCKSIZE;
285 inline bool isValidPosition(v3s16 p)
287 return isValidPosition(p.X, p.Y, p.Z);
290 inline MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
292 *valid_position = isValidPosition(x, y, z);
294 if (!*valid_position)
295 return MapNode(CONTENT_IGNORE);
297 return data[z * zstride + y * ystride + x];
300 inline MapNode getNode(v3s16 p, bool *valid_position)
302 return getNode(p.X, p.Y, p.Z, valid_position);
305 inline MapNode getNodeNoEx(v3s16 p)
308 return getNode(p.X, p.Y, p.Z, &is_valid);
311 inline void setNode(s16 x, s16 y, s16 z, MapNode & n)
313 if (!isValidPosition(x, y, z))
314 throw InvalidPositionException();
316 data[z * zstride + y * ystride + x] = n;
317 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
320 inline void setNode(v3s16 p, MapNode & n)
322 setNode(p.X, p.Y, p.Z, n);
326 //// Non-checking variants of the above
329 inline MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
331 *valid_position = data != NULL;
333 return MapNode(CONTENT_IGNORE);
335 return data[z * zstride + y * ystride + x];
338 inline MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
340 return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
344 //// Non-checking, unsafe variants of the above
345 //// MapBlock must be loaded by another function in the same scope/function
346 //// Caller must ensure that this is not a dummy block (by calling isDummy())
349 inline const MapNode &getNodeUnsafe(s16 x, s16 y, s16 z)
351 return data[z * zstride + y * ystride + x];
354 inline const MapNode &getNodeUnsafe(v3s16 &p)
356 return getNodeUnsafe(p.X, p.Y, p.Z);
359 inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
362 throw InvalidPositionException();
364 data[z * zstride + y * ystride + x] = n;
365 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE_NO_CHECK);
368 inline void setNodeNoCheck(v3s16 p, MapNode & n)
370 setNodeNoCheck(p.X, p.Y, p.Z, n);
373 // These functions consult the parent container if the position
374 // is not valid on this MapBlock.
375 bool isValidPositionParent(v3s16 p);
376 MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
377 void setNodeParent(v3s16 p, MapNode & n);
379 inline void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
381 for (u16 z = 0; z < d; z++)
382 for (u16 y = 0; y < h; y++)
383 for (u16 x = 0; x < w; x++)
384 setNode(x0 + x, y0 + y, z0 + z, node);
387 // See comments in mapblock.cpp
388 bool propagateSunlight(std::set<v3s16> &light_sources,
389 bool remove_light=false, bool *black_air_left=NULL);
391 // Copies data to VoxelManipulator to getPosRelative()
392 void copyTo(VoxelManipulator &dst);
394 // Copies data from VoxelManipulator getPosRelative()
395 void copyFrom(VoxelManipulator &dst);
397 // Update day-night lighting difference flag.
398 // Sets m_day_night_differs to appropriate value.
399 // These methods don't care about neighboring blocks.
400 void actuallyUpdateDayNightDiff();
402 // Call this to schedule what the previous function does to be done
403 // when the value is actually needed.
404 void expireDayNightDiff();
406 inline bool getDayNightDiff()
408 if (m_day_night_differs_expired)
409 actuallyUpdateDayNightDiff();
410 return m_day_night_differs;
414 //// Miscellaneous stuff
418 Tries to measure ground level.
423 0...MAP_BLOCKSIZE-1 = ground level
425 s16 getGroundLevel(v2s16 p2d);
428 //// Timestamp (see m_timestamp)
431 // NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
433 inline void setTimestamp(u32 time)
436 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_TIMESTAMP);
439 inline void setTimestampNoChangedFlag(u32 time)
444 inline u32 getTimestamp()
449 inline u32 getDiskTimestamp()
451 return m_disk_timestamp;
455 //// Usage timer (see m_usage_timer)
458 inline void resetUsageTimer()
463 inline void incrementUsageTimer(float dtime)
465 m_usage_timer += dtime;
468 inline float getUsageTimer()
470 return m_usage_timer;
474 //// Reference counting (see m_refcount)
477 inline void refGrab()
482 inline void refDrop()
496 inline NodeTimer getNodeTimer(v3s16 p)
498 return m_node_timers.get(p);
501 inline void removeNodeTimer(v3s16 p)
503 m_node_timers.remove(p);
506 inline void setNodeTimer(const NodeTimer &t)
508 m_node_timers.set(t);
511 inline void clearNodeTimers()
513 m_node_timers.clear();
520 // These don't write or read version by itself
521 // Set disk to true for on-disk format, false for over-the-network format
522 // Precondition: version >= SER_FMT_VER_LOWEST_WRITE
523 void serialize(std::ostream &os, u8 version, bool disk);
524 // If disk == true: In addition to doing other things, will add
525 // unknown blocks from id-name mapping to wndef
526 void deSerialize(std::istream &is, u8 version, bool disk);
528 void serializeNetworkSpecific(std::ostream &os, u16 net_proto_version);
529 void deSerializeNetworkSpecific(std::istream &is);
535 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
538 Used only internally, because changes can't be tracked
541 inline MapNode &getNodeRef(s16 x, s16 y, s16 z)
543 if (!isValidPosition(x, y, z))
544 throw InvalidPositionException();
546 return data[z * zstride + y * ystride + x];
549 inline MapNode &getNodeRef(v3s16 &p)
551 return getNodeRef(p.X, p.Y, p.Z);
556 Public member variables
559 #ifndef SERVER // Only on client
563 NodeMetadataList m_node_metadata;
564 NodeTimerList m_node_timers;
565 StaticObjectList m_static_objects;
567 static const u32 ystride = MAP_BLOCKSIZE;
568 static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
570 static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
574 Private member variables
577 // NOTE: Lots of things rely on this being the Map
579 // Position in blocks on parent
582 /* This is the precalculated m_pos_relative value
583 * This caches the value, improving performance by removing 3 s16 multiplications
584 * at runtime on each getPosRelative call
585 * For a 5 minutes runtime with valgrind this removes 3 * 19M s16 multiplications
586 * The gain can be estimated in Release Build to 3 * 100M multiply operations for 5 mins
588 v3s16 m_pos_relative;
593 If NULL, block is a dummy block.
594 Dummy blocks are used for caching not-found-on-disk blocks.
599 - On the server, this is used for telling whether the
600 block has been modified from the one on disk.
601 - On the client, this is used for nothing.
604 u32 m_modified_reason;
607 When propagating sunlight and the above block doesn't exist,
608 sunlight is assumed if this is false.
610 In practice this is set to true if the block is completely
611 undeground with nothing visible above the ground except
617 Set to true if changes has been made that make the old lighting
618 values wrong but the lighting hasn't been actually updated.
620 If this is false, lighting is exactly right.
621 If this is true, lighting might be wrong or right.
623 bool m_lighting_expired;
625 // Whether day and night lighting differs
626 bool m_day_night_differs;
627 bool m_day_night_differs_expired;
632 When block is removed from active blocks, this is set to gametime.
633 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
636 // The on-disk (or to-be on-disk) timestamp value
637 u32 m_disk_timestamp;
640 When the block is accessed, this is set to 0.
641 Map will unload the block when this reaches a timeout.
646 Reference count; currently used for determining if this block is in
647 the list of blocks to be drawn.
652 typedef std::vector<MapBlock*> MapBlockVect;
654 inline bool objectpos_over_limit(v3f p)
656 const float map_gen_limit_bs = MYMIN(MAX_MAP_GENERATION_LIMIT,
657 g_settings->getU16("map_generation_limit")) * BS;
658 return (p.X < -map_gen_limit_bs
659 || p.X > map_gen_limit_bs
660 || p.Y < -map_gen_limit_bs
661 || p.Y > map_gen_limit_bs
662 || p.Z < -map_gen_limit_bs
663 || p.Z > map_gen_limit_bs);
667 We are checking for any node of the mapblock being beyond the limit.
669 At the negative limit we are checking for
670 block minimum nodepos < -mapgenlimit.
671 At the positive limit we are checking for
672 block maximum nodepos > mapgenlimit.
674 Block minimum nodepos = blockpos * mapblocksize.
675 Block maximum nodepos = (blockpos + 1) * mapblocksize - 1.
677 inline bool blockpos_over_limit(v3s16 p)
679 const u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
680 g_settings->getU16("map_generation_limit"));
681 return (p.X * MAP_BLOCKSIZE < -map_gen_limit
682 || (p.X + 1) * MAP_BLOCKSIZE - 1 > map_gen_limit
683 || p.Y * MAP_BLOCKSIZE < -map_gen_limit
684 || (p.Y + 1) * MAP_BLOCKSIZE - 1 > map_gen_limit
685 || p.Z * MAP_BLOCKSIZE < -map_gen_limit
686 || (p.Z + 1) * MAP_BLOCKSIZE - 1 > map_gen_limit);
690 Returns the position of the block where the node is located
692 inline v3s16 getNodeBlockPos(v3s16 p)
694 return getContainerPos(p, MAP_BLOCKSIZE);
697 inline v2s16 getNodeSectorPos(v2s16 p)
699 return getContainerPos(p, MAP_BLOCKSIZE);
702 inline s16 getNodeBlockY(s16 y)
704 return getContainerPos(y, MAP_BLOCKSIZE);
707 inline void getNodeBlockPosWithOffset(const v3s16 &p, v3s16 &block, v3s16 &offset)
709 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
712 inline void getNodeSectorPosWithOffset(const v2s16 &p, v2s16 &block, v2s16 &offset)
714 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
718 Get a quick string to describe what a block actually contains
720 std::string analyze_block(MapBlock *block);