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
46 //// MapBlock modified reason flags
49 #define MOD_REASON_INITIAL (1 << 0)
50 #define MOD_REASON_REALLOCATE (1 << 1)
51 #define MOD_REASON_SET_IS_UNDERGROUND (1 << 2)
52 #define MOD_REASON_SET_LIGHTING_COMPLETE (1 << 3)
53 #define MOD_REASON_SET_GENERATED (1 << 4)
54 #define MOD_REASON_SET_NODE (1 << 5)
55 #define MOD_REASON_SET_NODE_NO_CHECK (1 << 6)
56 #define MOD_REASON_SET_TIMESTAMP (1 << 7)
57 #define MOD_REASON_REPORT_META_CHANGE (1 << 8)
58 #define MOD_REASON_CLEAR_ALL_OBJECTS (1 << 9)
59 #define MOD_REASON_BLOCK_EXPIRED (1 << 10)
60 #define MOD_REASON_ADD_ACTIVE_OBJECT_RAW (1 << 11)
61 #define MOD_REASON_REMOVE_OBJECTS_REMOVE (1 << 12)
62 #define MOD_REASON_REMOVE_OBJECTS_DEACTIVATE (1 << 13)
63 #define MOD_REASON_TOO_MANY_OBJECTS (1 << 14)
64 #define MOD_REASON_STATIC_DATA_ADDED (1 << 15)
65 #define MOD_REASON_STATIC_DATA_REMOVED (1 << 16)
66 #define MOD_REASON_STATIC_DATA_CHANGED (1 << 17)
67 #define MOD_REASON_EXPIRE_DAYNIGHTDIFF (1 << 18)
68 #define MOD_REASON_UNKNOWN (1 << 19)
77 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
80 /*virtual u16 nodeContainerId() const
82 return NODECONTAINER_ID_MAPBLOCK;
93 data = new MapNode[nodecount];
94 for (u32 i = 0; i < nodecount; i++)
95 data[i] = MapNode(CONTENT_IGNORE);
97 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_REALLOCATE);
106 //// Modification tracking methods
108 void raiseModified(u32 mod, u32 reason=MOD_REASON_UNKNOWN)
110 if (mod > m_modified) {
112 m_modified_reason = reason;
113 if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD)
114 m_disk_timestamp = m_timestamp;
115 } else if (mod == m_modified) {
116 m_modified_reason |= reason;
120 inline u32 getModified()
125 inline u32 getModifiedReason()
127 return m_modified_reason;
130 std::string getModifiedReasonString();
132 inline void resetModified()
134 m_modified = MOD_STATE_CLEAN;
135 m_modified_reason = 0;
142 inline bool isDummy()
147 inline void unDummify()
149 assert(isDummy()); // Pre-condition
153 // is_underground getter/setter
154 inline bool getIsUnderground()
156 return is_underground;
159 inline void setIsUnderground(bool a_is_underground)
161 is_underground = a_is_underground;
162 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
165 inline void setLightingComplete(u16 newflags)
167 if (newflags != m_lighting_complete) {
168 m_lighting_complete = newflags;
169 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_COMPLETE);
173 inline u16 getLightingComplete()
175 return m_lighting_complete;
178 inline void setLightingComplete(LightBank bank, u8 direction,
181 assert(direction >= 0 && direction <= 5);
182 if (bank == LIGHTBANK_NIGHT) {
185 u16 newflags = m_lighting_complete;
187 newflags |= 1 << direction;
189 newflags &= ~(1 << direction);
191 setLightingComplete(newflags);
194 inline bool isLightingComplete(LightBank bank, u8 direction)
196 assert(direction >= 0 && direction <= 5);
197 if (bank == LIGHTBANK_NIGHT) {
200 return (m_lighting_complete & (1 << direction)) != 0;
203 inline bool isGenerated()
208 inline void setGenerated(bool b)
210 if (b != m_generated) {
211 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_GENERATED);
220 inline v3s16 getPos()
225 inline v3s16 getPosRelative()
227 return m_pos_relative;
230 inline core::aabbox3d<s16> getBox()
232 return core::aabbox3d<s16>(getPosRelative(),
234 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
239 //// Regular MapNode get-setters
242 inline bool isValidPosition(s16 x, s16 y, s16 z)
245 && x >= 0 && x < MAP_BLOCKSIZE
246 && y >= 0 && y < MAP_BLOCKSIZE
247 && z >= 0 && z < MAP_BLOCKSIZE;
250 inline bool isValidPosition(v3s16 p)
252 return isValidPosition(p.X, p.Y, p.Z);
255 inline MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
257 *valid_position = isValidPosition(x, y, z);
259 if (!*valid_position)
260 return MapNode(CONTENT_IGNORE);
262 return data[z * zstride + y * ystride + x];
265 inline MapNode getNode(v3s16 p, bool *valid_position)
267 return getNode(p.X, p.Y, p.Z, valid_position);
270 inline MapNode getNodeNoEx(v3s16 p)
273 return getNode(p.X, p.Y, p.Z, &is_valid);
276 inline void setNode(s16 x, s16 y, s16 z, MapNode & n)
278 if (!isValidPosition(x, y, z))
279 throw InvalidPositionException();
281 data[z * zstride + y * ystride + x] = n;
282 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
285 inline void setNode(v3s16 p, MapNode & n)
287 setNode(p.X, p.Y, p.Z, n);
291 //// Non-checking variants of the above
294 inline MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
296 *valid_position = data != nullptr;
298 return MapNode(CONTENT_IGNORE);
300 return data[z * zstride + y * ystride + x];
303 inline MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
305 return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
309 //// Non-checking, unsafe variants of the above
310 //// MapBlock must be loaded by another function in the same scope/function
311 //// Caller must ensure that this is not a dummy block (by calling isDummy())
314 inline const MapNode &getNodeUnsafe(s16 x, s16 y, s16 z)
316 return data[z * zstride + y * ystride + x];
319 inline const MapNode &getNodeUnsafe(v3s16 &p)
321 return getNodeUnsafe(p.X, p.Y, p.Z);
324 inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
327 throw InvalidPositionException();
329 data[z * zstride + y * ystride + x] = n;
330 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE_NO_CHECK);
333 inline void setNodeNoCheck(v3s16 p, MapNode & n)
335 setNodeNoCheck(p.X, p.Y, p.Z, n);
338 // These functions consult the parent container if the position
339 // is not valid on this MapBlock.
340 bool isValidPositionParent(v3s16 p);
341 MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
342 void setNodeParent(v3s16 p, MapNode & n);
344 inline void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
346 for (u16 z = 0; z < d; z++)
347 for (u16 y = 0; y < h; y++)
348 for (u16 x = 0; x < w; x++)
349 setNode(x0 + x, y0 + y, z0 + z, node);
352 // See comments in mapblock.cpp
353 bool propagateSunlight(std::set<v3s16> &light_sources,
354 bool remove_light=false, bool *black_air_left=NULL);
356 // Copies data to VoxelManipulator to getPosRelative()
357 void copyTo(VoxelManipulator &dst);
359 // Copies data from VoxelManipulator getPosRelative()
360 void copyFrom(VoxelManipulator &dst);
362 // Update day-night lighting difference flag.
363 // Sets m_day_night_differs to appropriate value.
364 // 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.
369 void expireDayNightDiff();
371 inline bool getDayNightDiff()
373 if (m_day_night_differs_expired)
374 actuallyUpdateDayNightDiff();
375 return m_day_night_differs;
379 //// Miscellaneous stuff
383 Tries to measure ground level.
388 0...MAP_BLOCKSIZE-1 = ground level
390 s16 getGroundLevel(v2s16 p2d);
393 //// Timestamp (see m_timestamp)
396 // NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
398 inline void setTimestamp(u32 time)
401 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_TIMESTAMP);
404 inline void setTimestampNoChangedFlag(u32 time)
409 inline u32 getTimestamp()
414 inline u32 getDiskTimestamp()
416 return m_disk_timestamp;
420 //// Usage timer (see m_usage_timer)
423 inline void resetUsageTimer()
428 inline void incrementUsageTimer(float dtime)
430 m_usage_timer += dtime;
433 inline float getUsageTimer()
435 return m_usage_timer;
439 //// Reference counting (see m_refcount)
442 inline void refGrab()
447 inline void refDrop()
461 inline NodeTimer getNodeTimer(v3s16 p)
463 return m_node_timers.get(p);
466 inline void removeNodeTimer(v3s16 p)
468 m_node_timers.remove(p);
471 inline void setNodeTimer(const NodeTimer &t)
473 m_node_timers.set(t);
476 inline void clearNodeTimers()
478 m_node_timers.clear();
485 // These don't write or read version by itself
486 // Set disk to true for on-disk format, false for over-the-network format
487 // Precondition: version >= SER_FMT_VER_LOWEST_WRITE
488 void serialize(std::ostream &os, u8 version, bool disk);
489 // If disk == true: In addition to doing other things, will add
490 // unknown blocks from id-name mapping to wndef
491 void deSerialize(std::istream &is, u8 version, bool disk);
493 void serializeNetworkSpecific(std::ostream &os);
494 void deSerializeNetworkSpecific(std::istream &is);
500 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
503 Used only internally, because changes can't be tracked
506 inline MapNode &getNodeRef(s16 x, s16 y, s16 z)
508 if (!isValidPosition(x, y, z))
509 throw InvalidPositionException();
511 return data[z * zstride + y * ystride + x];
514 inline MapNode &getNodeRef(v3s16 &p)
516 return getNodeRef(p.X, p.Y, p.Z);
521 Public member variables
524 #ifndef SERVER // Only on client
525 MapBlockMesh *mesh = nullptr;
528 NodeMetadataList m_node_metadata;
529 NodeTimerList m_node_timers;
530 StaticObjectList m_static_objects;
532 static const u32 ystride = MAP_BLOCKSIZE;
533 static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
535 static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
539 Private member variables
542 // NOTE: Lots of things rely on this being the Map
544 // Position in blocks on parent
547 /* This is the precalculated m_pos_relative value
548 * This caches the value, improving performance by removing 3 s16 multiplications
549 * at runtime on each getPosRelative call
550 * For a 5 minutes runtime with valgrind this removes 3 * 19M s16 multiplications
551 * The gain can be estimated in Release Build to 3 * 100M multiply operations for 5 mins
553 v3s16 m_pos_relative;
558 If NULL, block is a dummy block.
559 Dummy blocks are used for caching not-found-on-disk blocks.
561 MapNode *data = nullptr;
564 - On the server, this is used for telling whether the
565 block has been modified from the one on disk.
566 - On the client, this is used for nothing.
568 u32 m_modified = MOD_STATE_WRITE_NEEDED;
569 u32 m_modified_reason = MOD_REASON_INITIAL;
572 When propagating sunlight and the above block doesn't exist,
573 sunlight is assumed if this is false.
575 In practice this is set to true if the block is completely
576 undeground with nothing visible above the ground except
579 bool is_underground = false;
582 * Each bit indicates if light spreading was finished
583 * in a direction. (Because the neighbor could also be unloaded.)
584 * Bits (most significant first):
585 * nothing, nothing, nothing, nothing,
586 * night X-, night Y-, night Z-, night Z+, night Y+, night X+,
587 * day X-, day Y-, day Z-, day Z+, day Y+, day X+.
589 u16 m_lighting_complete = 0xFFFF;
591 // Whether day and night lighting differs
592 bool m_day_night_differs = false;
593 bool m_day_night_differs_expired = true;
595 bool m_generated = false;
598 When block is removed from active blocks, this is set to gametime.
599 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
601 u32 m_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
602 // The on-disk (or to-be on-disk) timestamp value
603 u32 m_disk_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
606 When the block is accessed, this is set to 0.
607 Map will unload the block when this reaches a timeout.
609 float m_usage_timer = 0;
612 Reference count; currently used for determining if this block is in
613 the list of blocks to be drawn.
618 typedef std::vector<MapBlock*> MapBlockVect;
620 inline bool objectpos_over_limit(v3f p)
622 const float max_limit_bs = MAX_MAP_GENERATION_LIMIT * BS;
623 return p.X < -max_limit_bs ||
624 p.X > max_limit_bs ||
625 p.Y < -max_limit_bs ||
626 p.Y > max_limit_bs ||
627 p.Z < -max_limit_bs ||
631 inline bool blockpos_over_max_limit(v3s16 p)
633 const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
634 return p.X < -max_limit_bp ||
635 p.X > max_limit_bp ||
636 p.Y < -max_limit_bp ||
637 p.Y > max_limit_bp ||
638 p.Z < -max_limit_bp ||
643 Returns the position of the block where the node is located
645 inline v3s16 getNodeBlockPos(v3s16 p)
647 return getContainerPos(p, MAP_BLOCKSIZE);
650 inline v2s16 getNodeSectorPos(v2s16 p)
652 return getContainerPos(p, MAP_BLOCKSIZE);
655 inline s16 getNodeBlockY(s16 y)
657 return getContainerPos(y, MAP_BLOCKSIZE);
660 inline void getNodeBlockPosWithOffset(const v3s16 &p, v3s16 &block, v3s16 &offset)
662 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
665 inline void getNodeSectorPosWithOffset(const v2s16 &p, v2s16 &block, v2s16 &offset)
667 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
671 Get a quick string to describe what a block actually contains
673 std::string analyze_block(MapBlock *block);