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.
25 #include "exceptions.h"
26 #include "constants.h"
27 #include "staticobject.h"
28 #include "nodemetadata.h"
29 #include "nodetimer.h"
30 #include "modifiedstate.h"
31 #include "util/numeric.h" // getContainerPos
33 #include "mapgen/mapgen.h"
36 class NodeMetadataList;
39 class VoxelManipulator;
41 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
44 //// MapBlock modified reason flags
47 #define MOD_REASON_INITIAL (1 << 0)
48 #define MOD_REASON_REALLOCATE (1 << 1)
49 #define MOD_REASON_SET_IS_UNDERGROUND (1 << 2)
50 #define MOD_REASON_SET_LIGHTING_COMPLETE (1 << 3)
51 #define MOD_REASON_SET_GENERATED (1 << 4)
52 #define MOD_REASON_SET_NODE (1 << 5)
53 #define MOD_REASON_SET_NODE_NO_CHECK (1 << 6)
54 #define MOD_REASON_SET_TIMESTAMP (1 << 7)
55 #define MOD_REASON_REPORT_META_CHANGE (1 << 8)
56 #define MOD_REASON_CLEAR_ALL_OBJECTS (1 << 9)
57 #define MOD_REASON_BLOCK_EXPIRED (1 << 10)
58 #define MOD_REASON_ADD_ACTIVE_OBJECT_RAW (1 << 11)
59 #define MOD_REASON_REMOVE_OBJECTS_REMOVE (1 << 12)
60 #define MOD_REASON_REMOVE_OBJECTS_DEACTIVATE (1 << 13)
61 #define MOD_REASON_TOO_MANY_OBJECTS (1 << 14)
62 #define MOD_REASON_STATIC_DATA_ADDED (1 << 15)
63 #define MOD_REASON_STATIC_DATA_REMOVED (1 << 16)
64 #define MOD_REASON_STATIC_DATA_CHANGED (1 << 17)
65 #define MOD_REASON_EXPIRE_DAYNIGHTDIFF (1 << 18)
66 #define MOD_REASON_VMANIP (1 << 19)
67 #define MOD_REASON_UNKNOWN (1 << 20)
76 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef);
79 /*virtual u16 nodeContainerId() const
81 return NODECONTAINER_ID_MAPBLOCK;
91 for (u32 i = 0; i < nodecount; i++)
92 data[i] = MapNode(CONTENT_IGNORE);
93 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_REALLOCATE);
102 //// Modification tracking methods
104 void raiseModified(u32 mod, u32 reason=MOD_REASON_UNKNOWN)
106 if (mod > m_modified) {
108 m_modified_reason = reason;
109 if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD)
110 m_disk_timestamp = m_timestamp;
111 } else if (mod == m_modified) {
112 m_modified_reason |= reason;
114 if (mod == MOD_STATE_WRITE_NEEDED)
115 contents_cached = false;
118 inline u32 getModified()
123 inline u32 getModifiedReason()
125 return m_modified_reason;
128 std::string getModifiedReasonString();
130 inline void resetModified()
132 m_modified = MOD_STATE_CLEAN;
133 m_modified_reason = 0;
140 // is_underground getter/setter
141 inline bool getIsUnderground()
143 return is_underground;
146 inline void setIsUnderground(bool a_is_underground)
148 is_underground = a_is_underground;
149 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
152 inline void setLightingComplete(u16 newflags)
154 if (newflags != m_lighting_complete) {
155 m_lighting_complete = newflags;
156 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_COMPLETE);
160 inline u16 getLightingComplete()
162 return m_lighting_complete;
165 inline void setLightingComplete(LightBank bank, u8 direction,
168 assert(direction >= 0 && direction <= 5);
169 if (bank == LIGHTBANK_NIGHT) {
172 u16 newflags = m_lighting_complete;
174 newflags |= 1 << direction;
176 newflags &= ~(1 << direction);
178 setLightingComplete(newflags);
181 inline bool isLightingComplete(LightBank bank, u8 direction)
183 assert(direction >= 0 && direction <= 5);
184 if (bank == LIGHTBANK_NIGHT) {
187 return (m_lighting_complete & (1 << direction)) != 0;
190 inline bool isGenerated()
195 inline void setGenerated(bool b)
197 if (b != m_generated) {
198 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_GENERATED);
207 inline v3s16 getPos()
212 inline v3s16 getPosRelative()
214 return m_pos_relative;
217 inline core::aabbox3d<s16> getBox()
219 return core::aabbox3d<s16>(getPosRelative(),
221 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
226 //// Regular MapNode get-setters
229 inline bool isValidPosition(s16 x, s16 y, s16 z)
231 return x >= 0 && x < MAP_BLOCKSIZE
232 && y >= 0 && y < MAP_BLOCKSIZE
233 && z >= 0 && z < MAP_BLOCKSIZE;
236 inline bool isValidPosition(v3s16 p)
238 return isValidPosition(p.X, p.Y, p.Z);
241 inline MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
243 *valid_position = isValidPosition(x, y, z);
245 if (!*valid_position)
246 return {CONTENT_IGNORE};
248 return data[z * zstride + y * ystride + x];
251 inline MapNode getNode(v3s16 p, bool *valid_position)
253 return getNode(p.X, p.Y, p.Z, valid_position);
256 inline MapNode getNodeNoEx(v3s16 p)
259 return getNode(p.X, p.Y, p.Z, &is_valid);
262 inline void setNode(s16 x, s16 y, s16 z, MapNode n)
264 if (!isValidPosition(x, y, z))
265 throw InvalidPositionException();
267 data[z * zstride + y * ystride + x] = n;
268 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
271 inline void setNode(v3s16 p, MapNode n)
273 setNode(p.X, p.Y, p.Z, n);
277 //// Non-checking variants of the above
280 inline MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
282 return data[z * zstride + y * ystride + x];
285 inline MapNode getNodeNoCheck(v3s16 p)
287 return getNodeNoCheck(p.X, p.Y, p.Z);
290 inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode n)
292 data[z * zstride + y * ystride + x] = n;
293 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE_NO_CHECK);
296 inline void setNodeNoCheck(v3s16 p, MapNode n)
298 setNodeNoCheck(p.X, p.Y, p.Z, n);
301 // These functions consult the parent container if the position
302 // is not valid on this MapBlock.
303 bool isValidPositionParent(v3s16 p);
304 MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
306 // Copies data to VoxelManipulator to getPosRelative()
307 void copyTo(VoxelManipulator &dst);
309 // Copies data from VoxelManipulator getPosRelative()
310 void copyFrom(VoxelManipulator &dst);
312 // Update day-night lighting difference flag.
313 // Sets m_day_night_differs to appropriate value.
314 // These methods don't care about neighboring blocks.
315 void actuallyUpdateDayNightDiff();
317 // Call this to schedule what the previous function does to be done
318 // when the value is actually needed.
319 void expireDayNightDiff();
321 inline bool getDayNightDiff()
323 if (m_day_night_differs_expired)
324 actuallyUpdateDayNightDiff();
325 return m_day_night_differs;
328 bool onObjectsActivation();
329 bool saveStaticObject(u16 id, const StaticObject &obj, u32 reason);
331 void step(float dtime, const std::function<bool(v3s16, MapNode, f32)> &on_timer_cb);
334 //// Timestamp (see m_timestamp)
337 // NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
339 inline void setTimestamp(u32 time)
342 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_TIMESTAMP);
345 inline void setTimestampNoChangedFlag(u32 time)
350 inline u32 getTimestamp()
355 inline u32 getDiskTimestamp()
357 return m_disk_timestamp;
361 //// Usage timer (see m_usage_timer)
364 inline void resetUsageTimer()
369 inline void incrementUsageTimer(float dtime)
371 m_usage_timer += dtime;
374 inline float getUsageTimer()
376 return m_usage_timer;
380 //// Reference counting (see m_refcount)
383 inline void refGrab()
388 inline void refDrop()
402 inline NodeTimer getNodeTimer(v3s16 p)
404 return m_node_timers.get(p);
407 inline void removeNodeTimer(v3s16 p)
409 m_node_timers.remove(p);
412 inline void setNodeTimer(const NodeTimer &t)
414 m_node_timers.set(t);
417 inline void clearNodeTimers()
419 m_node_timers.clear();
426 // These don't write or read version by itself
427 // Set disk to true for on-disk format, false for over-the-network format
428 // Precondition: version >= SER_FMT_VER_LOWEST_WRITE
429 void serialize(std::ostream &result, u8 version, bool disk, int compression_level);
430 // If disk == true: In addition to doing other things, will add
431 // unknown blocks from id-name mapping to wndef
432 void deSerialize(std::istream &is, u8 version, bool disk);
434 void serializeNetworkSpecific(std::ostream &os);
435 void deSerializeNetworkSpecific(std::istream &is);
437 bool storeActiveObject(u16 id);
438 // clearObject and return removed objects count
446 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
450 Public member variables
453 #ifndef SERVER // Only on client
454 MapBlockMesh *mesh = nullptr;
457 NodeMetadataList m_node_metadata;
458 StaticObjectList m_static_objects;
460 static const u32 ystride = MAP_BLOCKSIZE;
461 static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
463 static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
465 //// ABM optimizations ////
466 // Cache of content types
467 std::unordered_set<content_t> contents;
468 // True if content types are cached
469 bool contents_cached = false;
470 // True if we never want to cache content types for this block
471 bool do_not_cache_contents = false;
475 Private member variables
478 // NOTE: Lots of things rely on this being the Map
480 // Position in blocks on parent
483 /* This is the precalculated m_pos_relative value
484 * This caches the value, improving performance by removing 3 s16 multiplications
485 * at runtime on each getPosRelative call
486 * For a 5 minutes runtime with valgrind this removes 3 * 19M s16 multiplications
487 * The gain can be estimated in Release Build to 3 * 100M multiply operations for 5 mins
489 v3s16 m_pos_relative;
494 - On the server, this is used for telling whether the
495 block has been modified from the one on disk.
496 - On the client, this is used for nothing.
498 u32 m_modified = MOD_STATE_WRITE_NEEDED;
499 u32 m_modified_reason = MOD_REASON_INITIAL;
502 When propagating sunlight and the above block doesn't exist,
503 sunlight is assumed if this is false.
505 In practice this is set to true if the block is completely
506 undeground with nothing visible above the ground except
509 bool is_underground = false;
512 * Each bit indicates if light spreading was finished
513 * in a direction. (Because the neighbor could also be unloaded.)
514 * Bits (most significant first):
515 * nothing, nothing, nothing, nothing,
516 * night X-, night Y-, night Z-, night Z+, night Y+, night X+,
517 * day X-, day Y-, day Z-, day Z+, day Y+, day X+.
519 u16 m_lighting_complete = 0xFFFF;
521 // Whether day and night lighting differs
522 bool m_day_night_differs = false;
523 bool m_day_night_differs_expired = true;
525 bool m_generated = false;
528 When block is removed from active blocks, this is set to gametime.
529 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
531 u32 m_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
532 // The on-disk (or to-be on-disk) timestamp value
533 u32 m_disk_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
536 When the block is accessed, this is set to 0.
537 Map will unload the block when this reaches a timeout.
539 float m_usage_timer = 0;
542 Reference count; currently used for determining if this block is in
543 the list of blocks to be drawn.
547 MapNode data[nodecount];
548 NodeTimerList m_node_timers;
551 typedef std::vector<MapBlock*> MapBlockVect;
553 inline bool objectpos_over_limit(v3f p)
555 const float max_limit_bs = (MAX_MAP_GENERATION_LIMIT + 0.5f) * BS;
556 return p.X < -max_limit_bs ||
557 p.X > max_limit_bs ||
558 p.Y < -max_limit_bs ||
559 p.Y > max_limit_bs ||
560 p.Z < -max_limit_bs ||
564 inline bool blockpos_over_max_limit(v3s16 p)
566 const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
567 return p.X < -max_limit_bp ||
568 p.X > max_limit_bp ||
569 p.Y < -max_limit_bp ||
570 p.Y > max_limit_bp ||
571 p.Z < -max_limit_bp ||
576 Returns the position of the block where the node is located
578 inline v3s16 getNodeBlockPos(v3s16 p)
580 return getContainerPos(p, MAP_BLOCKSIZE);
583 inline void getNodeBlockPosWithOffset(v3s16 p, v3s16 &block, v3s16 &offset)
585 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
589 Get a quick string to describe what a block actually contains
591 std::string analyze_block(MapBlock *block);