Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 :
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.
9 :
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.
14 :
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.
18 : */
19 :
20 : #ifndef MAPBLOCK_HEADER
21 : #define MAPBLOCK_HEADER
22 :
23 : #include <set>
24 : #include "debug.h"
25 : #include "irr_v3d.h"
26 : #include "mapnode.h"
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
34 :
35 : class Map;
36 : class NodeMetadataList;
37 : class IGameDef;
38 : class MapBlockMesh;
39 : class VoxelManipulator;
40 :
41 : #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
42 :
43 : /*// Named by looking towards z+
44 : enum{
45 : FACE_BACK=0,
46 : FACE_TOP,
47 : FACE_RIGHT,
48 : FACE_FRONT,
49 : FACE_BOTTOM,
50 : FACE_LEFT
51 : };*/
52 :
53 : // NOTE: If this is enabled, set MapBlock to be initialized with
54 : // CONTENT_IGNORE.
55 : /*enum BlockGenerationStatus
56 : {
57 : // Completely non-generated (filled with CONTENT_IGNORE).
58 : BLOCKGEN_UNTOUCHED=0,
59 : // Trees or similar might have been blitted from other blocks to here.
60 : // Otherwise, the block contains CONTENT_IGNORE
61 : BLOCKGEN_FROM_NEIGHBORS=2,
62 : // Has been generated, but some neighbors might put some stuff in here
63 : // when they are generated.
64 : // Does not contain any CONTENT_IGNORE
65 : BLOCKGEN_SELF_GENERATED=4,
66 : // The block and all its neighbors have been generated
67 : BLOCKGEN_FULLY_GENERATED=6
68 : };*/
69 :
70 : #if 0
71 : enum
72 : {
73 : NODECONTAINER_ID_MAPBLOCK,
74 : NODECONTAINER_ID_MAPSECTOR,
75 : NODECONTAINER_ID_MAP,
76 : NODECONTAINER_ID_MAPBLOCKCACHE,
77 : NODECONTAINER_ID_VOXELMANIPULATOR,
78 : };
79 :
80 : class NodeContainer
81 : {
82 : public:
83 : virtual bool isValidPosition(v3s16 p) = 0;
84 : virtual MapNode getNode(v3s16 p) = 0;
85 : virtual void setNode(v3s16 p, MapNode & n) = 0;
86 : virtual u16 nodeContainerId() const = 0;
87 :
88 : MapNode getNodeNoEx(v3s16 p)
89 : {
90 : try{
91 : return getNode(p);
92 : }
93 : catch(InvalidPositionException &e){
94 : return MapNode(CONTENT_IGNORE);
95 : }
96 : }
97 : };
98 : #endif
99 :
100 : ////
101 : //// MapBlock modified reason flags
102 : ////
103 :
104 : #define MOD_REASON_INITIAL (1 << 0)
105 : #define MOD_REASON_REALLOCATE (1 << 1)
106 : #define MOD_REASON_SET_IS_UNDERGROUND (1 << 2)
107 : #define MOD_REASON_SET_LIGHTING_EXPIRED (1 << 3)
108 : #define MOD_REASON_SET_GENERATED (1 << 4)
109 : #define MOD_REASON_SET_NODE (1 << 5)
110 : #define MOD_REASON_SET_NODE_NO_CHECK (1 << 6)
111 : #define MOD_REASON_SET_TIMESTAMP (1 << 7)
112 : #define MOD_REASON_REPORT_META_CHANGE (1 << 8)
113 : #define MOD_REASON_CLEAR_ALL_OBJECTS (1 << 9)
114 : #define MOD_REASON_BLOCK_EXPIRED (1 << 10)
115 : #define MOD_REASON_ADD_ACTIVE_OBJECT_RAW (1 << 11)
116 : #define MOD_REASON_REMOVE_OBJECTS_REMOVE (1 << 12)
117 : #define MOD_REASON_REMOVE_OBJECTS_DEACTIVATE (1 << 13)
118 : #define MOD_REASON_TOO_MANY_OBJECTS (1 << 14)
119 : #define MOD_REASON_STATIC_DATA_ADDED (1 << 15)
120 : #define MOD_REASON_STATIC_DATA_REMOVED (1 << 16)
121 : #define MOD_REASON_STATIC_DATA_CHANGED (1 << 17)
122 : #define MOD_REASON_EXPIRE_DAYNIGHTDIFF (1 << 18)
123 : #define MOD_REASON_UNKNOWN (1 << 19)
124 :
125 : ////
126 : //// MapBlock itself
127 : ////
128 :
129 : class MapBlock /*: public NodeContainer*/
130 : {
131 : public:
132 : MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
133 : ~MapBlock();
134 :
135 : /*virtual u16 nodeContainerId() const
136 : {
137 : return NODECONTAINER_ID_MAPBLOCK;
138 : }*/
139 :
140 3548 : Map * getParent()
141 : {
142 3548 : return m_parent;
143 : }
144 :
145 751 : void reallocate()
146 : {
147 751 : delete[] data;
148 751 : data = new MapNode[nodecount];
149 3076847 : for (u32 i = 0; i < nodecount; i++)
150 3076096 : data[i] = MapNode(CONTENT_IGNORE);
151 :
152 751 : raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_REALLOCATE);
153 751 : }
154 :
155 : ////
156 : //// Modification tracking methods
157 : ////
158 1768 : void raiseModified(u32 mod, u32 reason=MOD_REASON_UNKNOWN)
159 : {
160 1768 : if (mod > m_modified) {
161 0 : m_modified = mod;
162 0 : m_modified_reason = reason;
163 0 : if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD)
164 0 : m_disk_timestamp = m_timestamp;
165 1768 : } else if (mod == m_modified) {
166 1768 : m_modified_reason |= reason;
167 : }
168 1768 : }
169 :
170 0 : inline u32 getModified()
171 : {
172 0 : return m_modified;
173 : }
174 :
175 : inline u32 getModifiedReason()
176 : {
177 : return m_modified_reason;
178 : }
179 :
180 : std::string getModifiedReasonString();
181 :
182 0 : inline void resetModified()
183 : {
184 0 : m_modified = MOD_STATE_CLEAN;
185 0 : m_modified_reason = 0;
186 0 : }
187 :
188 : ////
189 : //// Flags
190 : ////
191 :
192 3476 : inline bool isDummy()
193 : {
194 3476 : return (data == NULL);
195 : }
196 :
197 0 : inline void unDummify()
198 : {
199 : assert(isDummy()); // Pre-condition
200 0 : reallocate();
201 0 : }
202 :
203 : // is_underground getter/setter
204 0 : inline bool getIsUnderground()
205 : {
206 0 : return is_underground;
207 : }
208 :
209 0 : inline void setIsUnderground(bool a_is_underground)
210 : {
211 0 : is_underground = a_is_underground;
212 0 : raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
213 0 : }
214 :
215 0 : inline void setLightingExpired(bool expired)
216 : {
217 0 : if (expired != m_lighting_expired){
218 0 : m_lighting_expired = expired;
219 0 : raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_EXPIRED);
220 : }
221 0 : }
222 :
223 0 : inline bool getLightingExpired()
224 : {
225 0 : return m_lighting_expired;
226 : }
227 :
228 0 : inline bool isGenerated()
229 : {
230 0 : return m_generated;
231 : }
232 :
233 0 : inline void setGenerated(bool b)
234 : {
235 0 : if (b != m_generated) {
236 0 : raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_GENERATED);
237 0 : m_generated = b;
238 : }
239 0 : }
240 :
241 0 : inline bool isValid()
242 : {
243 0 : if (m_lighting_expired)
244 0 : return false;
245 0 : if (data == NULL)
246 0 : return false;
247 0 : return true;
248 : }
249 :
250 : ////
251 : //// Position stuff
252 : ////
253 :
254 283215 : inline v3s16 getPos()
255 : {
256 283215 : return m_pos;
257 : }
258 :
259 56320 : inline v3s16 getPosRelative()
260 : {
261 56320 : return m_pos * MAP_BLOCKSIZE;
262 : }
263 :
264 : inline core::aabbox3d<s16> getBox()
265 : {
266 : return core::aabbox3d<s16>(getPosRelative(),
267 : getPosRelative()
268 : + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
269 : - v3s16(1,1,1));
270 : }
271 :
272 : ////
273 : //// Regular MapNode get-setters
274 : ////
275 :
276 24769 : inline bool isValidPosition(s16 x, s16 y, s16 z)
277 : {
278 24769 : return data != NULL
279 24769 : && x >= 0 && x < MAP_BLOCKSIZE
280 24769 : && y >= 0 && y < MAP_BLOCKSIZE
281 49538 : && z >= 0 && z < MAP_BLOCKSIZE;
282 : }
283 :
284 0 : inline bool isValidPosition(v3s16 p)
285 : {
286 0 : return isValidPosition(p.X, p.Y, p.Z);
287 : }
288 :
289 23808 : inline MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
290 : {
291 23808 : *valid_position = isValidPosition(x, y, z);
292 :
293 23808 : if (!*valid_position)
294 0 : return MapNode(CONTENT_IGNORE);
295 :
296 23808 : return data[z * zstride + y * ystride + x];
297 : }
298 :
299 23808 : inline MapNode getNode(v3s16 p, bool *valid_position)
300 : {
301 23808 : return getNode(p.X, p.Y, p.Z, valid_position);
302 : }
303 :
304 0 : inline MapNode getNodeNoEx(v3s16 p)
305 : {
306 : bool is_valid;
307 0 : MapNode node = getNode(p.X, p.Y, p.Z, &is_valid);
308 0 : return is_valid ? node : MapNode(CONTENT_IGNORE);
309 : }
310 :
311 961 : inline void setNode(s16 x, s16 y, s16 z, MapNode & n)
312 : {
313 961 : if (!isValidPosition(x, y, z))
314 0 : throw InvalidPositionException();
315 :
316 961 : data[z * zstride + y * ystride + x] = n;
317 961 : raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
318 961 : }
319 :
320 961 : inline void setNode(v3s16 p, MapNode & n)
321 : {
322 961 : setNode(p.X, p.Y, p.Z, n);
323 961 : }
324 :
325 : ////
326 : //// Non-checking variants of the above
327 : ////
328 :
329 2100429 : inline MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
330 : {
331 2100429 : *valid_position = data != NULL;
332 2100429 : if (!valid_position)
333 0 : return MapNode(CONTENT_IGNORE);
334 :
335 2100429 : return data[z * zstride + y * ystride + x];
336 : }
337 :
338 2100429 : inline MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
339 : {
340 2100429 : return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
341 : }
342 :
343 56 : inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
344 : {
345 56 : if (data == NULL)
346 0 : throw InvalidPositionException();
347 :
348 56 : data[z * zstride + y * ystride + x] = n;
349 56 : raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE_NO_CHECK);
350 56 : }
351 :
352 56 : inline void setNodeNoCheck(v3s16 p, MapNode & n)
353 : {
354 56 : setNodeNoCheck(p.X, p.Y, p.Z, n);
355 56 : }
356 :
357 : // These functions consult the parent container if the position
358 : // is not valid on this MapBlock.
359 : bool isValidPositionParent(v3s16 p);
360 : MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
361 : void setNodeParent(v3s16 p, MapNode & n);
362 :
363 : inline void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
364 : {
365 : for (u16 z = 0; z < d; z++)
366 : for (u16 y = 0; y < h; y++)
367 : for (u16 x = 0; x < w; x++)
368 : setNode(x0 + x, y0 + y, z0 + z, node);
369 : }
370 :
371 : // See comments in mapblock.cpp
372 : bool propagateSunlight(std::set<v3s16> &light_sources,
373 : bool remove_light=false, bool *black_air_left=NULL);
374 :
375 : // Copies data to VoxelManipulator to getPosRelative()
376 : void copyTo(VoxelManipulator &dst);
377 :
378 : // Copies data from VoxelManipulator getPosRelative()
379 : void copyFrom(VoxelManipulator &dst);
380 :
381 : // Update day-night lighting difference flag.
382 : // Sets m_day_night_differs to appropriate value.
383 : // These methods don't care about neighboring blocks.
384 : void actuallyUpdateDayNightDiff();
385 :
386 : // Call this to schedule what the previous function does to be done
387 : // when the value is actually needed.
388 : void expireDayNightDiff();
389 :
390 0 : inline bool getDayNightDiff()
391 : {
392 0 : if (m_day_night_differs_expired)
393 0 : actuallyUpdateDayNightDiff();
394 0 : return m_day_night_differs;
395 : }
396 :
397 : ////
398 : //// Miscellaneous stuff
399 : ////
400 :
401 : /*
402 : Tries to measure ground level.
403 : Return value:
404 : -1 = only air
405 : -2 = only ground
406 : -3 = random fail
407 : 0...MAP_BLOCKSIZE-1 = ground level
408 : */
409 : s16 getGroundLevel(v2s16 p2d);
410 :
411 : ////
412 : //// Timestamp (see m_timestamp)
413 : ////
414 :
415 : // NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
416 :
417 0 : inline void setTimestamp(u32 time)
418 : {
419 0 : m_timestamp = time;
420 0 : raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_TIMESTAMP);
421 0 : }
422 :
423 0 : inline void setTimestampNoChangedFlag(u32 time)
424 : {
425 0 : m_timestamp = time;
426 0 : }
427 :
428 0 : inline u32 getTimestamp()
429 : {
430 0 : return m_timestamp;
431 : }
432 :
433 0 : inline u32 getDiskTimestamp()
434 : {
435 0 : return m_disk_timestamp;
436 : }
437 :
438 : ////
439 : //// Usage timer (see m_usage_timer)
440 : ////
441 :
442 15421 : inline void resetUsageTimer()
443 : {
444 15421 : m_usage_timer = 0;
445 15421 : }
446 :
447 2191 : inline void incrementUsageTimer(float dtime)
448 : {
449 2191 : m_usage_timer += dtime;
450 2191 : }
451 :
452 1589 : inline float getUsageTimer()
453 : {
454 1589 : return m_usage_timer;
455 : }
456 :
457 : ////
458 : //// Reference counting (see m_refcount)
459 : ////
460 :
461 15421 : inline void refGrab()
462 : {
463 15421 : m_refcount++;
464 15421 : }
465 :
466 15306 : inline void refDrop()
467 : {
468 15306 : m_refcount--;
469 15306 : }
470 :
471 2191 : inline int refGet()
472 : {
473 2191 : return m_refcount;
474 : }
475 :
476 : ////
477 : //// Node Timers
478 : ////
479 :
480 : inline NodeTimer getNodeTimer(v3s16 p)
481 : {
482 : return m_node_timers.get(p);
483 : }
484 :
485 : inline void removeNodeTimer(v3s16 p)
486 : {
487 : m_node_timers.remove(p);
488 : }
489 :
490 0 : inline void setNodeTimer(v3s16 p, NodeTimer t)
491 : {
492 0 : m_node_timers.set(p,t);
493 0 : }
494 :
495 : inline void clearNodeTimers()
496 : {
497 : m_node_timers.clear();
498 : }
499 :
500 : ////
501 : //// Serialization
502 : ///
503 :
504 : // These don't write or read version by itself
505 : // Set disk to true for on-disk format, false for over-the-network format
506 : // Precondition: version >= SER_FMT_CLIENT_VER_LOWEST
507 : void serialize(std::ostream &os, u8 version, bool disk);
508 : // If disk == true: In addition to doing other things, will add
509 : // unknown blocks from id-name mapping to wndef
510 : void deSerialize(std::istream &is, u8 version, bool disk);
511 :
512 : void serializeNetworkSpecific(std::ostream &os, u16 net_proto_version);
513 : void deSerializeNetworkSpecific(std::istream &is);
514 :
515 : private:
516 : /*
517 : Private methods
518 : */
519 :
520 : void deSerialize_pre22(std::istream &is, u8 version, bool disk);
521 :
522 : /*
523 : Used only internally, because changes can't be tracked
524 : */
525 :
526 0 : inline MapNode &getNodeRef(s16 x, s16 y, s16 z)
527 : {
528 0 : if (!isValidPosition(x, y, z))
529 0 : throw InvalidPositionException();
530 :
531 0 : return data[z * zstride + y * ystride + x];
532 : }
533 :
534 0 : inline MapNode &getNodeRef(v3s16 &p)
535 : {
536 0 : return getNodeRef(p.X, p.Y, p.Z);
537 : }
538 :
539 : public:
540 : /*
541 : Public member variables
542 : */
543 :
544 : #ifndef SERVER // Only on client
545 : MapBlockMesh *mesh;
546 : #endif
547 :
548 : NodeMetadataList m_node_metadata;
549 : NodeTimerList m_node_timers;
550 : StaticObjectList m_static_objects;
551 :
552 : static const u32 ystride = MAP_BLOCKSIZE;
553 : static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
554 :
555 : static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
556 :
557 : private:
558 : /*
559 : Private member variables
560 : */
561 :
562 : // NOTE: Lots of things rely on this being the Map
563 : Map *m_parent;
564 : // Position in blocks on parent
565 : v3s16 m_pos;
566 :
567 : IGameDef *m_gamedef;
568 :
569 : /*
570 : If NULL, block is a dummy block.
571 : Dummy blocks are used for caching not-found-on-disk blocks.
572 : */
573 : MapNode *data;
574 :
575 : /*
576 : - On the server, this is used for telling whether the
577 : block has been modified from the one on disk.
578 : - On the client, this is used for nothing.
579 : */
580 : u32 m_modified;
581 : u32 m_modified_reason;
582 :
583 : /*
584 : When propagating sunlight and the above block doesn't exist,
585 : sunlight is assumed if this is false.
586 :
587 : In practice this is set to true if the block is completely
588 : undeground with nothing visible above the ground except
589 : caves.
590 : */
591 : bool is_underground;
592 :
593 : /*
594 : Set to true if changes has been made that make the old lighting
595 : values wrong but the lighting hasn't been actually updated.
596 :
597 : If this is false, lighting is exactly right.
598 : If this is true, lighting might be wrong or right.
599 : */
600 : bool m_lighting_expired;
601 :
602 : // Whether day and night lighting differs
603 : bool m_day_night_differs;
604 : bool m_day_night_differs_expired;
605 :
606 : bool m_generated;
607 :
608 : /*
609 : When block is removed from active blocks, this is set to gametime.
610 : Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
611 : */
612 : u32 m_timestamp;
613 : // The on-disk (or to-be on-disk) timestamp value
614 : u32 m_disk_timestamp;
615 :
616 : /*
617 : When the block is accessed, this is set to 0.
618 : Map will unload the block when this reaches a timeout.
619 : */
620 : float m_usage_timer;
621 :
622 : /*
623 : Reference count; currently used for determining if this block is in
624 : the list of blocks to be drawn.
625 : */
626 : int m_refcount;
627 : };
628 :
629 : typedef std::vector<MapBlock*> MapBlockVect;
630 :
631 0 : inline bool blockpos_over_limit(v3s16 p)
632 : {
633 : return
634 0 : (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
635 0 : || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
636 0 : || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
637 0 : || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
638 0 : || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
639 0 : || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
640 : }
641 :
642 : /*
643 : Returns the position of the block where the node is located
644 : */
645 2241169 : inline v3s16 getNodeBlockPos(v3s16 p)
646 : {
647 2241169 : return getContainerPos(p, MAP_BLOCKSIZE);
648 : }
649 :
650 : inline v2s16 getNodeSectorPos(v2s16 p)
651 : {
652 : return getContainerPos(p, MAP_BLOCKSIZE);
653 : }
654 :
655 : inline s16 getNodeBlockY(s16 y)
656 : {
657 : return getContainerPos(y, MAP_BLOCKSIZE);
658 : }
659 :
660 23798 : inline void getNodeBlockPosWithOffset(const v3s16 &p, v3s16 &block, v3s16 &offset)
661 : {
662 23798 : getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
663 23798 : }
664 :
665 : inline void getNodeSectorPosWithOffset(const v2s16 &p, v2s16 &block, v2s16 &offset)
666 : {
667 : getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
668 : }
669 :
670 : /*
671 : Get a quick string to describe what a block actually contains
672 : */
673 : std::string analyze_block(MapBlock *block);
674 :
675 : #endif
676 :
|