mapblock.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #pragma once
  17. #include <vector>
  18. #include "irr_v3d.h"
  19. #include "mapnode.h"
  20. #include "exceptions.h"
  21. #include "constants.h"
  22. #include "staticobject.h"
  23. #include "nodemetadata.h"
  24. #include "nodetimer.h"
  25. #include "modifiedstate.h"
  26. #include "util/numeric.h" // getContainerPos
  27. #include "settings.h"
  28. class Map;
  29. class NodeMetadataList;
  30. class IGameDef;
  31. class MapBlockMesh;
  32. class VoxelManipulator;
  33. #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
  34. ////
  35. //// MapBlock modified reason flags
  36. ////
  37. enum ModReason : u32 {
  38. MOD_REASON_REALLOCATE = 1 << 0,
  39. MOD_REASON_SET_IS_UNDERGROUND = 1 << 1,
  40. MOD_REASON_SET_LIGHTING_COMPLETE = 1 << 2,
  41. MOD_REASON_SET_GENERATED = 1 << 3,
  42. MOD_REASON_SET_NODE = 1 << 4,
  43. MOD_REASON_SET_TIMESTAMP = 1 << 5,
  44. MOD_REASON_REPORT_META_CHANGE = 1 << 6,
  45. MOD_REASON_CLEAR_ALL_OBJECTS = 1 << 7,
  46. MOD_REASON_BLOCK_EXPIRED = 1 << 8,
  47. MOD_REASON_ADD_ACTIVE_OBJECT_RAW = 1 << 9,
  48. MOD_REASON_REMOVE_OBJECTS_REMOVE = 1 << 10,
  49. MOD_REASON_REMOVE_OBJECTS_DEACTIVATE = 1 << 11,
  50. MOD_REASON_TOO_MANY_OBJECTS = 1 << 12,
  51. MOD_REASON_STATIC_DATA_ADDED = 1 << 13,
  52. MOD_REASON_STATIC_DATA_REMOVED = 1 << 14,
  53. MOD_REASON_STATIC_DATA_CHANGED = 1 << 15,
  54. MOD_REASON_EXPIRE_IS_AIR = 1 << 16,
  55. MOD_REASON_VMANIP = 1 << 17,
  56. MOD_REASON_UNKNOWN = 1 << 18,
  57. };
  58. ////
  59. //// MapBlock itself
  60. ////
  61. class MapBlock
  62. {
  63. public:
  64. MapBlock(v3s16 pos, IGameDef *gamedef);
  65. ~MapBlock();
  66. // Any server-modding code can "delete" arbitrary blocks (i.e. with
  67. // core.delete_area), which makes them orphan. Avoid using orphan blocks for
  68. // anything.
  69. bool isOrphan() const
  70. {
  71. return m_orphan;
  72. }
  73. void makeOrphan()
  74. {
  75. m_orphan = true;
  76. }
  77. void reallocate()
  78. {
  79. for (u32 i = 0; i < nodecount; i++)
  80. data[i] = MapNode(CONTENT_IGNORE);
  81. raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_REALLOCATE);
  82. }
  83. MapNode* getData()
  84. {
  85. return data;
  86. }
  87. ////
  88. //// Modification tracking methods
  89. ////
  90. void raiseModified(u32 mod, u32 reason=MOD_REASON_UNKNOWN)
  91. {
  92. if (mod > m_modified) {
  93. m_modified = mod;
  94. m_modified_reason = reason;
  95. if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD)
  96. m_disk_timestamp = m_timestamp;
  97. } else if (mod == m_modified) {
  98. m_modified_reason |= reason;
  99. }
  100. if (mod == MOD_STATE_WRITE_NEEDED)
  101. contents.clear();
  102. }
  103. inline u32 getModified()
  104. {
  105. return m_modified;
  106. }
  107. inline u32 getModifiedReason()
  108. {
  109. return m_modified_reason;
  110. }
  111. std::string getModifiedReasonString();
  112. inline void resetModified()
  113. {
  114. m_modified = MOD_STATE_CLEAN;
  115. m_modified_reason = 0;
  116. }
  117. ////
  118. //// Flags
  119. ////
  120. // is_underground getter/setter
  121. inline bool getIsUnderground()
  122. {
  123. return is_underground;
  124. }
  125. inline void setIsUnderground(bool a_is_underground)
  126. {
  127. is_underground = a_is_underground;
  128. raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
  129. }
  130. inline void setLightingComplete(u16 newflags)
  131. {
  132. if (newflags != m_lighting_complete) {
  133. m_lighting_complete = newflags;
  134. raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_LIGHTING_COMPLETE);
  135. }
  136. }
  137. inline u16 getLightingComplete()
  138. {
  139. return m_lighting_complete;
  140. }
  141. inline void setLightingComplete(LightBank bank, u8 direction,
  142. bool is_complete)
  143. {
  144. assert(direction >= 0 && direction <= 5);
  145. if (bank == LIGHTBANK_NIGHT) {
  146. direction += 6;
  147. }
  148. u16 newflags = m_lighting_complete;
  149. if (is_complete) {
  150. newflags |= 1 << direction;
  151. } else {
  152. newflags &= ~(1 << direction);
  153. }
  154. setLightingComplete(newflags);
  155. }
  156. inline bool isLightingComplete(LightBank bank, u8 direction)
  157. {
  158. assert(direction >= 0 && direction <= 5);
  159. if (bank == LIGHTBANK_NIGHT) {
  160. direction += 6;
  161. }
  162. return (m_lighting_complete & (1 << direction)) != 0;
  163. }
  164. inline bool isGenerated()
  165. {
  166. return m_generated;
  167. }
  168. inline void setGenerated(bool b)
  169. {
  170. if (b != m_generated) {
  171. raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_GENERATED);
  172. m_generated = b;
  173. }
  174. }
  175. ////
  176. //// Position stuff
  177. ////
  178. inline v3s16 getPos()
  179. {
  180. return m_pos;
  181. }
  182. inline v3s16 getPosRelative()
  183. {
  184. return m_pos_relative;
  185. }
  186. inline core::aabbox3d<s16> getBox() {
  187. return getBox(getPosRelative());
  188. }
  189. static inline core::aabbox3d<s16> getBox(const v3s16 &pos_relative)
  190. {
  191. return core::aabbox3d<s16>(pos_relative,
  192. pos_relative
  193. + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
  194. - v3s16(1,1,1));
  195. }
  196. ////
  197. //// Regular MapNode get-setters
  198. ////
  199. inline bool isValidPosition(s16 x, s16 y, s16 z)
  200. {
  201. return x >= 0 && x < MAP_BLOCKSIZE
  202. && y >= 0 && y < MAP_BLOCKSIZE
  203. && z >= 0 && z < MAP_BLOCKSIZE;
  204. }
  205. inline bool isValidPosition(v3s16 p)
  206. {
  207. return isValidPosition(p.X, p.Y, p.Z);
  208. }
  209. inline MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
  210. {
  211. *valid_position = isValidPosition(x, y, z);
  212. if (!*valid_position)
  213. return {CONTENT_IGNORE};
  214. return data[z * zstride + y * ystride + x];
  215. }
  216. inline MapNode getNode(v3s16 p, bool *valid_position)
  217. {
  218. return getNode(p.X, p.Y, p.Z, valid_position);
  219. }
  220. inline MapNode getNodeNoEx(v3s16 p)
  221. {
  222. bool is_valid;
  223. return getNode(p.X, p.Y, p.Z, &is_valid);
  224. }
  225. inline void setNode(s16 x, s16 y, s16 z, MapNode n)
  226. {
  227. if (!isValidPosition(x, y, z))
  228. throw InvalidPositionException();
  229. data[z * zstride + y * ystride + x] = n;
  230. raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
  231. }
  232. inline void setNode(v3s16 p, MapNode n)
  233. {
  234. setNode(p.X, p.Y, p.Z, n);
  235. }
  236. ////
  237. //// Non-checking variants of the above
  238. ////
  239. inline MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
  240. {
  241. return data[z * zstride + y * ystride + x];
  242. }
  243. inline MapNode getNodeNoCheck(v3s16 p)
  244. {
  245. return getNodeNoCheck(p.X, p.Y, p.Z);
  246. }
  247. inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode n)
  248. {
  249. data[z * zstride + y * ystride + x] = n;
  250. raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
  251. }
  252. inline void setNodeNoCheck(v3s16 p, MapNode n)
  253. {
  254. setNodeNoCheck(p.X, p.Y, p.Z, n);
  255. }
  256. // Copies data to VoxelManipulator to getPosRelative()
  257. void copyTo(VoxelManipulator &dst);
  258. // Copies data from VoxelManipulator getPosRelative()
  259. void copyFrom(VoxelManipulator &dst);
  260. // Update is air flag.
  261. // Sets m_is_air to appropriate value.
  262. void actuallyUpdateIsAir();
  263. // Call this to schedule what the previous function does to be done
  264. // when the value is actually needed.
  265. void expireIsAirCache();
  266. inline bool isAir()
  267. {
  268. if (m_is_air_expired)
  269. actuallyUpdateIsAir();
  270. return m_is_air;
  271. }
  272. bool onObjectsActivation();
  273. bool saveStaticObject(u16 id, const StaticObject &obj, u32 reason);
  274. void step(float dtime, const std::function<bool(v3s16, MapNode, f32)> &on_timer_cb);
  275. ////
  276. //// Timestamp (see m_timestamp)
  277. ////
  278. // NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
  279. inline void setTimestamp(u32 time)
  280. {
  281. m_timestamp = time;
  282. raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_TIMESTAMP);
  283. }
  284. inline void setTimestampNoChangedFlag(u32 time)
  285. {
  286. m_timestamp = time;
  287. }
  288. inline u32 getTimestamp()
  289. {
  290. return m_timestamp;
  291. }
  292. inline u32 getDiskTimestamp()
  293. {
  294. return m_disk_timestamp;
  295. }
  296. ////
  297. //// Usage timer (see m_usage_timer)
  298. ////
  299. inline void resetUsageTimer()
  300. {
  301. m_usage_timer = 0;
  302. }
  303. inline void incrementUsageTimer(float dtime)
  304. {
  305. m_usage_timer += dtime;
  306. }
  307. inline float getUsageTimer()
  308. {
  309. return m_usage_timer;
  310. }
  311. ////
  312. //// Reference counting (see m_refcount)
  313. ////
  314. inline void refGrab()
  315. {
  316. assert(m_refcount < SHRT_MAX);
  317. m_refcount++;
  318. }
  319. inline void refDrop()
  320. {
  321. assert(m_refcount > 0);
  322. m_refcount--;
  323. }
  324. inline short refGet()
  325. {
  326. return m_refcount;
  327. }
  328. ////
  329. //// Node Timers
  330. ////
  331. inline NodeTimer getNodeTimer(v3s16 p)
  332. {
  333. return m_node_timers.get(p);
  334. }
  335. inline void removeNodeTimer(v3s16 p)
  336. {
  337. m_node_timers.remove(p);
  338. }
  339. inline void setNodeTimer(const NodeTimer &t)
  340. {
  341. m_node_timers.set(t);
  342. }
  343. inline void clearNodeTimers()
  344. {
  345. m_node_timers.clear();
  346. }
  347. ////
  348. //// Serialization
  349. ///
  350. // These don't write or read version by itself
  351. // Set disk to true for on-disk format, false for over-the-network format
  352. // Precondition: version >= SER_FMT_VER_LOWEST_WRITE
  353. void serialize(std::ostream &result, u8 version, bool disk, int compression_level);
  354. // If disk == true: In addition to doing other things, will add
  355. // unknown blocks from id-name mapping to wndef
  356. void deSerialize(std::istream &is, u8 version, bool disk);
  357. void serializeNetworkSpecific(std::ostream &os);
  358. void deSerializeNetworkSpecific(std::istream &is);
  359. bool storeActiveObject(u16 id);
  360. // clearObject and return removed objects count
  361. u32 clearObjects();
  362. static const u32 ystride = MAP_BLOCKSIZE;
  363. static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
  364. static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
  365. private:
  366. /*
  367. Private methods
  368. */
  369. void deSerialize_pre22(std::istream &is, u8 version, bool disk);
  370. /*
  371. * PLEASE NOTE: When adding something here be mindful of position and size
  372. * of member variables! This is also the reason for the weird public-private
  373. * interleaving.
  374. * If in doubt consult `pahole` to see the effects.
  375. */
  376. public:
  377. #ifndef SERVER // Only on client
  378. MapBlockMesh *mesh = nullptr;
  379. // marks the sides which are opaque: 00+Z-Z+Y-Y+X-X
  380. u8 solid_sides = 0;
  381. #endif
  382. private:
  383. // see isOrphan()
  384. bool m_orphan = false;
  385. // Position in blocks on parent
  386. v3s16 m_pos;
  387. /* Precalculated m_pos_relative value
  388. * This caches the value, improving performance by removing 3 s16 multiplications
  389. * at runtime on each getPosRelative call.
  390. * For a 5 minutes runtime with valgrind this removes 3 * 19M s16 multiplications.
  391. * The gain can be estimated in Release Build to 3 * 100M multiply operations for 5 mins.
  392. */
  393. v3s16 m_pos_relative;
  394. /*
  395. Reference count; currently used for determining if this block is in
  396. the list of blocks to be drawn.
  397. */
  398. short m_refcount = 0;
  399. /*
  400. * Note that this is not an inline array because that has implications for
  401. * heap fragmentation (the array is exactly 16K), CPU caches and/or
  402. * optimizability of algorithms working on this array.
  403. */
  404. MapNode *const data; // of `nodecount` elements
  405. // provides the item and node definitions
  406. IGameDef *m_gamedef;
  407. /*
  408. When the block is accessed, this is set to 0.
  409. Map will unload the block when this reaches a timeout.
  410. */
  411. float m_usage_timer = 0;
  412. public:
  413. //// ABM optimizations ////
  414. // True if we never want to cache content types for this block
  415. bool do_not_cache_contents = false;
  416. // Cache of content types
  417. // This is actually a set but for the small sizes we have a vector should be
  418. // more efficient.
  419. // Can be empty, in which case nothing was cached yet.
  420. std::vector<content_t> contents;
  421. private:
  422. // Whether day and night lighting differs
  423. bool m_is_air = false;
  424. bool m_is_air_expired = true;
  425. /*
  426. - On the server, this is used for telling whether the
  427. block has been modified from the one on disk.
  428. - On the client, this is used for nothing.
  429. */
  430. u16 m_modified = MOD_STATE_CLEAN;
  431. u32 m_modified_reason = 0;
  432. /*
  433. When block is removed from active blocks, this is set to gametime.
  434. Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
  435. */
  436. u32 m_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
  437. // The on-disk (or to-be on-disk) timestamp value
  438. u32 m_disk_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
  439. /*!
  440. * Each bit indicates if light spreading was finished
  441. * in a direction. (Because the neighbor could also be unloaded.)
  442. * Bits (most significant first):
  443. * nothing, nothing, nothing, nothing,
  444. * night X-, night Y-, night Z-, night Z+, night Y+, night X+,
  445. * day X-, day Y-, day Z-, day Z+, day Y+, day X+.
  446. */
  447. u16 m_lighting_complete = 0xFFFF;
  448. // Whether mapgen has generated the content of this block (persisted)
  449. bool m_generated = false;
  450. /*
  451. When propagating sunlight and the above block doesn't exist,
  452. sunlight is assumed if this is false.
  453. In practice this is set to true if the block is completely
  454. undeground with nothing visible above the ground except
  455. caves.
  456. */
  457. bool is_underground = false;
  458. public:
  459. NodeMetadataList m_node_metadata;
  460. StaticObjectList m_static_objects;
  461. private:
  462. NodeTimerList m_node_timers;
  463. };
  464. typedef std::vector<MapBlock*> MapBlockVect;
  465. inline bool objectpos_over_limit(v3f p)
  466. {
  467. const float max_limit_bs = (MAX_MAP_GENERATION_LIMIT + 0.5f) * BS;
  468. return p.X < -max_limit_bs ||
  469. p.X > max_limit_bs ||
  470. p.Y < -max_limit_bs ||
  471. p.Y > max_limit_bs ||
  472. p.Z < -max_limit_bs ||
  473. p.Z > max_limit_bs;
  474. }
  475. inline bool blockpos_over_max_limit(v3s16 p)
  476. {
  477. const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
  478. return p.X < -max_limit_bp ||
  479. p.X > max_limit_bp ||
  480. p.Y < -max_limit_bp ||
  481. p.Y > max_limit_bp ||
  482. p.Z < -max_limit_bp ||
  483. p.Z > max_limit_bp;
  484. }
  485. /*
  486. Returns the position of the block where the node is located
  487. */
  488. inline v3s16 getNodeBlockPos(v3s16 p)
  489. {
  490. return getContainerPos(p, MAP_BLOCKSIZE);
  491. }
  492. inline void getNodeBlockPosWithOffset(v3s16 p, v3s16 &block, v3s16 &offset)
  493. {
  494. getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
  495. }
  496. /*
  497. Get a quick string to describe what a block actually contains
  498. */
  499. std::string analyze_block(MapBlock *block);