autofly: small fix
[waspsaliva.git] / src / mapblock.h
blob6b5015cabdb5f1177e9679a632fb658c51180112
1 /*
2 Minetest
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 #pragma once
22 #include <set>
23 #include "irr_v3d.h"
24 #include "mapnode.h"
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
32 #include "settings.h"
33 #include "mapgen/mapgen.h"
35 class Map;
36 class NodeMetadataList;
37 class IGameDef;
38 class MapBlockMesh;
39 class VoxelManipulator;
41 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
43 ////
44 //// MapBlock modified reason flags
45 ////
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)
69 ////
70 //// MapBlock itself
71 ////
73 class MapBlock
75 public:
76 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
77 ~MapBlock();
79 /*virtual u16 nodeContainerId() const
81 return NODECONTAINER_ID_MAPBLOCK;
82 }*/
84 Map * getParent()
86 return m_parent;
89 void reallocate()
91 delete[] data;
92 data = new MapNode[nodecount];
93 for (u32 i = 0; i < nodecount; i++)
94 data[i] = MapNode(CONTENT_IGNORE);
96 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_REALLOCATE);
99 MapNode* getData()
101 return data;
104 ////
105 //// Modification tracking methods
106 ////
107 void raiseModified(u32 mod, u32 reason=MOD_REASON_UNKNOWN)
109 if (mod > m_modified) {
110 m_modified = mod;
111 m_modified_reason = reason;
112 if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD)
113 m_disk_timestamp = m_timestamp;
114 } else if (mod == m_modified) {
115 m_modified_reason |= reason;
117 if (mod == MOD_STATE_WRITE_NEEDED)
118 contents_cached = false;
121 inline u32 getModified()
123 return m_modified;
126 inline u32 getModifiedReason()
128 return m_modified_reason;
131 std::string getModifiedReasonString();
133 inline void resetModified()
135 m_modified = MOD_STATE_CLEAN;
136 m_modified_reason = 0;
139 ////
140 //// Flags
141 ////
143 inline bool isDummy()
145 return !data;
148 inline void unDummify()
150 assert(isDummy()); // Pre-condition
151 reallocate();
154 // is_underground getter/setter
155 inline bool getIsUnderground()
157 return is_underground;
160 inline void setIsUnderground(bool a_is_underground)
162 is_underground = a_is_underground;
163 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
166 inline void setLightingComplete(u16 newflags)
168 if (newflags != m_lighting_complete) {
169 m_lighting_complete = newflags;
170 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_COMPLETE);
174 inline u16 getLightingComplete()
176 return m_lighting_complete;
179 inline void setLightingComplete(LightBank bank, u8 direction,
180 bool is_complete)
182 assert(direction >= 0 && direction <= 5);
183 if (bank == LIGHTBANK_NIGHT) {
184 direction += 6;
186 u16 newflags = m_lighting_complete;
187 if (is_complete) {
188 newflags |= 1 << direction;
189 } else {
190 newflags &= ~(1 << direction);
192 setLightingComplete(newflags);
195 inline bool isLightingComplete(LightBank bank, u8 direction)
197 assert(direction >= 0 && direction <= 5);
198 if (bank == LIGHTBANK_NIGHT) {
199 direction += 6;
201 return (m_lighting_complete & (1 << direction)) != 0;
204 inline bool isGenerated()
206 return m_generated;
209 inline void setGenerated(bool b)
211 if (b != m_generated) {
212 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_GENERATED);
213 m_generated = b;
217 ////
218 //// Position stuff
219 ////
221 inline v3s16 getPos()
223 return m_pos;
226 inline v3s16 getPosRelative()
228 return m_pos_relative;
231 inline core::aabbox3d<s16> getBox()
233 return core::aabbox3d<s16>(getPosRelative(),
234 getPosRelative()
235 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
236 - v3s16(1,1,1));
239 ////
240 //// Regular MapNode get-setters
241 ////
243 inline bool isValidPosition(s16 x, s16 y, s16 z)
245 return data
246 && x >= 0 && x < MAP_BLOCKSIZE
247 && y >= 0 && y < MAP_BLOCKSIZE
248 && z >= 0 && z < MAP_BLOCKSIZE;
251 inline bool isValidPosition(v3s16 p)
253 return isValidPosition(p.X, p.Y, p.Z);
256 inline MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
258 *valid_position = isValidPosition(x, y, z);
260 if (!*valid_position)
261 return {CONTENT_IGNORE};
263 return data[z * zstride + y * ystride + x];
266 inline MapNode getNode(v3s16 p, bool *valid_position)
268 return getNode(p.X, p.Y, p.Z, valid_position);
271 inline MapNode getNodeNoEx(v3s16 p)
273 bool is_valid;
274 return getNode(p.X, p.Y, p.Z, &is_valid);
277 inline void setNode(s16 x, s16 y, s16 z, MapNode & n)
279 if (!isValidPosition(x, y, z))
280 throw InvalidPositionException();
282 data[z * zstride + y * ystride + x] = n;
283 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
286 inline void setNode(v3s16 p, MapNode & n)
288 setNode(p.X, p.Y, p.Z, n);
291 ////
292 //// Non-checking variants of the above
293 ////
295 inline MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
297 *valid_position = data != nullptr;
298 if (!*valid_position)
299 return {CONTENT_IGNORE};
301 return data[z * zstride + y * ystride + x];
304 inline MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
306 return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
309 ////
310 //// Non-checking, unsafe variants of the above
311 //// MapBlock must be loaded by another function in the same scope/function
312 //// Caller must ensure that this is not a dummy block (by calling isDummy())
313 ////
315 inline const MapNode &getNodeUnsafe(s16 x, s16 y, s16 z)
317 return data[z * zstride + y * ystride + x];
320 inline const MapNode &getNodeUnsafe(v3s16 &p)
322 return getNodeUnsafe(p.X, p.Y, p.Z);
325 inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
327 if (!data)
328 throw InvalidPositionException();
330 data[z * zstride + y * ystride + x] = n;
331 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE_NO_CHECK);
334 inline void setNodeNoCheck(v3s16 p, MapNode & n)
336 setNodeNoCheck(p.X, p.Y, p.Z, n);
339 // These functions consult the parent container if the position
340 // is not valid on this MapBlock.
341 bool isValidPositionParent(v3s16 p);
342 MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
343 void setNodeParent(v3s16 p, MapNode & n);
345 inline void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
347 for (u16 z = 0; z < d; z++)
348 for (u16 y = 0; y < h; y++)
349 for (u16 x = 0; x < w; x++)
350 setNode(x0 + x, y0 + y, z0 + z, node);
353 // Copies data to VoxelManipulator to getPosRelative()
354 void copyTo(VoxelManipulator &dst);
356 // Copies data from VoxelManipulator getPosRelative()
357 void copyFrom(VoxelManipulator &dst);
359 // Update day-night lighting difference flag.
360 // Sets m_day_night_differs to appropriate value.
361 // These methods don't care about neighboring blocks.
362 void actuallyUpdateDayNightDiff();
364 // Call this to schedule what the previous function does to be done
365 // when the value is actually needed.
366 void expireDayNightDiff();
368 inline bool getDayNightDiff()
370 if (m_day_night_differs_expired)
371 actuallyUpdateDayNightDiff();
372 return m_day_night_differs;
375 ////
376 //// Miscellaneous stuff
377 ////
380 Tries to measure ground level.
381 Return value:
382 -1 = only air
383 -2 = only ground
384 -3 = random fail
385 0...MAP_BLOCKSIZE-1 = ground level
387 s16 getGroundLevel(v2s16 p2d);
389 ////
390 //// Timestamp (see m_timestamp)
391 ////
393 // NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
395 inline void setTimestamp(u32 time)
397 m_timestamp = time;
398 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_TIMESTAMP);
401 inline void setTimestampNoChangedFlag(u32 time)
403 m_timestamp = time;
406 inline u32 getTimestamp()
408 return m_timestamp;
411 inline u32 getDiskTimestamp()
413 return m_disk_timestamp;
416 ////
417 //// Usage timer (see m_usage_timer)
418 ////
420 inline void resetUsageTimer()
422 m_usage_timer = 0;
425 inline void incrementUsageTimer(float dtime)
427 m_usage_timer += dtime;
430 inline float getUsageTimer()
432 return m_usage_timer;
435 ////
436 //// Reference counting (see m_refcount)
437 ////
439 inline void refGrab()
441 m_refcount++;
444 inline void refDrop()
446 m_refcount--;
449 inline int refGet()
451 return m_refcount;
454 ////
455 //// Node Timers
456 ////
458 inline NodeTimer getNodeTimer(const v3s16 &p)
460 return m_node_timers.get(p);
463 inline void removeNodeTimer(const v3s16 &p)
465 m_node_timers.remove(p);
468 inline void setNodeTimer(const NodeTimer &t)
470 m_node_timers.set(t);
473 inline void clearNodeTimers()
475 m_node_timers.clear();
478 ////
479 //// Serialization
482 // These don't write or read version by itself
483 // Set disk to true for on-disk format, false for over-the-network format
484 // Precondition: version >= SER_FMT_VER_LOWEST_WRITE
485 void serialize(std::ostream &os, u8 version, bool disk);
486 // If disk == true: In addition to doing other things, will add
487 // unknown blocks from id-name mapping to wndef
488 void deSerialize(std::istream &is, u8 version, bool disk);
490 void serializeNetworkSpecific(std::ostream &os);
491 void deSerializeNetworkSpecific(std::istream &is);
492 private:
494 Private methods
497 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
500 Used only internally, because changes can't be tracked
503 inline MapNode &getNodeRef(s16 x, s16 y, s16 z)
505 if (!isValidPosition(x, y, z))
506 throw InvalidPositionException();
508 return data[z * zstride + y * ystride + x];
511 inline MapNode &getNodeRef(v3s16 &p)
513 return getNodeRef(p.X, p.Y, p.Z);
516 public:
518 Public member variables
521 #ifndef SERVER // Only on client
522 MapBlockMesh *mesh = nullptr;
523 #endif
525 NodeMetadataList m_node_metadata;
526 NodeTimerList m_node_timers;
527 StaticObjectList m_static_objects;
529 static const u32 ystride = MAP_BLOCKSIZE;
530 static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
532 static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
534 //// ABM optimizations ////
535 // Cache of content types
536 std::unordered_set<content_t> contents;
537 // True if content types are cached
538 bool contents_cached = false;
539 // True if we never want to cache content types for this block
540 bool do_not_cache_contents = false;
542 private:
544 Private member variables
547 // NOTE: Lots of things rely on this being the Map
548 Map *m_parent;
549 // Position in blocks on parent
550 v3s16 m_pos;
552 /* This is the precalculated m_pos_relative value
553 * This caches the value, improving performance by removing 3 s16 multiplications
554 * at runtime on each getPosRelative call
555 * For a 5 minutes runtime with valgrind this removes 3 * 19M s16 multiplications
556 * The gain can be estimated in Release Build to 3 * 100M multiply operations for 5 mins
558 v3s16 m_pos_relative;
560 IGameDef *m_gamedef;
563 If NULL, block is a dummy block.
564 Dummy blocks are used for caching not-found-on-disk blocks.
566 MapNode *data = nullptr;
569 - On the server, this is used for telling whether the
570 block has been modified from the one on disk.
571 - On the client, this is used for nothing.
573 u32 m_modified = MOD_STATE_WRITE_NEEDED;
574 u32 m_modified_reason = MOD_REASON_INITIAL;
577 When propagating sunlight and the above block doesn't exist,
578 sunlight is assumed if this is false.
580 In practice this is set to true if the block is completely
581 undeground with nothing visible above the ground except
582 caves.
584 bool is_underground = false;
587 * Each bit indicates if light spreading was finished
588 * in a direction. (Because the neighbor could also be unloaded.)
589 * Bits (most significant first):
590 * nothing, nothing, nothing, nothing,
591 * night X-, night Y-, night Z-, night Z+, night Y+, night X+,
592 * day X-, day Y-, day Z-, day Z+, day Y+, day X+.
594 u16 m_lighting_complete = 0xFFFF;
596 // Whether day and night lighting differs
597 bool m_day_night_differs = false;
598 bool m_day_night_differs_expired = true;
600 bool m_generated = false;
603 When block is removed from active blocks, this is set to gametime.
604 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
606 u32 m_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
607 // The on-disk (or to-be on-disk) timestamp value
608 u32 m_disk_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
611 When the block is accessed, this is set to 0.
612 Map will unload the block when this reaches a timeout.
614 float m_usage_timer = 0;
617 Reference count; currently used for determining if this block is in
618 the list of blocks to be drawn.
620 int m_refcount = 0;
623 typedef std::vector<MapBlock*> MapBlockVect;
625 inline bool objectpos_over_limit(v3f p)
627 const float max_limit_bs = MAX_MAP_GENERATION_LIMIT * BS;
628 return p.X < -max_limit_bs ||
629 p.X > max_limit_bs ||
630 p.Y < -max_limit_bs ||
631 p.Y > max_limit_bs ||
632 p.Z < -max_limit_bs ||
633 p.Z > max_limit_bs;
636 inline bool blockpos_over_max_limit(v3s16 p)
638 const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
639 return p.X < -max_limit_bp ||
640 p.X > max_limit_bp ||
641 p.Y < -max_limit_bp ||
642 p.Y > max_limit_bp ||
643 p.Z < -max_limit_bp ||
644 p.Z > max_limit_bp;
648 Returns the position of the block where the node is located
650 inline v3s16 getNodeBlockPos(const v3s16 &p)
652 return getContainerPos(p, MAP_BLOCKSIZE);
655 inline void getNodeBlockPosWithOffset(const v3s16 &p, v3s16 &block, v3s16 &offset)
657 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
661 Get a quick string to describe what a block actually contains
663 std::string analyze_block(MapBlock *block);