]> git.lizzy.rs Git - minetest.git/blob - src/mapblock.h
Minimal: Add snow biome and jungleleaves nodes. Add mapgen aliases
[minetest.git] / src / mapblock.h
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         Map * getParent()
141         {
142                 return m_parent;
143         }
144
145         void reallocate()
146         {
147                 delete[] data;
148                 data = new MapNode[nodecount];
149                 for (u32 i = 0; i < nodecount; i++)
150                         data[i] = MapNode(CONTENT_IGNORE);
151
152                 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_REALLOCATE);
153         }
154
155         ////
156         //// Modification tracking methods
157         ////
158         void raiseModified(u32 mod, u32 reason=MOD_REASON_UNKNOWN)
159         {
160                 if (mod > m_modified) {
161                         m_modified = mod;
162                         m_modified_reason = reason;
163                         if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD)
164                                 m_disk_timestamp = m_timestamp;
165                 } else if (mod == m_modified) {
166                         m_modified_reason |= reason;
167                 }
168         }
169
170         inline u32 getModified()
171         {
172                 return m_modified;
173         }
174
175         inline u32 getModifiedReason()
176         {
177                 return m_modified_reason;
178         }
179
180         std::string getModifiedReasonString();
181
182         inline void resetModified()
183         {
184                 m_modified = MOD_STATE_CLEAN;
185                 m_modified_reason = 0;
186         }
187
188         ////
189         //// Flags
190         ////
191
192         inline bool isDummy()
193         {
194                 return (data == NULL);
195         }
196
197         inline void unDummify()
198         {
199                 assert(isDummy()); // Pre-condition
200                 reallocate();
201         }
202
203         // is_underground getter/setter
204         inline bool getIsUnderground()
205         {
206                 return is_underground;
207         }
208
209         inline void setIsUnderground(bool a_is_underground)
210         {
211                 is_underground = a_is_underground;
212                 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
213         }
214
215         inline void setLightingExpired(bool expired)
216         {
217                 if (expired != m_lighting_expired){
218                         m_lighting_expired = expired;
219                         raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_EXPIRED);
220                 }
221         }
222
223         inline bool getLightingExpired()
224         {
225                 return m_lighting_expired;
226         }
227
228         inline bool isGenerated()
229         {
230                 return m_generated;
231         }
232
233         inline void setGenerated(bool b)
234         {
235                 if (b != m_generated) {
236                         raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_GENERATED);
237                         m_generated = b;
238                 }
239         }
240
241         inline bool isValid()
242         {
243                 if (m_lighting_expired)
244                         return false;
245                 if (data == NULL)
246                         return false;
247                 return true;
248         }
249
250         ////
251         //// Position stuff
252         ////
253
254         inline v3s16 getPos()
255         {
256                 return m_pos;
257         }
258
259         inline v3s16 getPosRelative()
260         {
261                 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         inline bool isValidPosition(s16 x, s16 y, s16 z)
277         {
278                 return data != NULL
279                         && x >= 0 && x < MAP_BLOCKSIZE
280                         && y >= 0 && y < MAP_BLOCKSIZE
281                         && z >= 0 && z < MAP_BLOCKSIZE;
282         }
283
284         inline bool isValidPosition(v3s16 p)
285         {
286                 return isValidPosition(p.X, p.Y, p.Z);
287         }
288
289         inline MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
290         {
291                 *valid_position = isValidPosition(x, y, z);
292
293                 if (!*valid_position)
294                         return MapNode(CONTENT_IGNORE);
295
296                 return data[z * zstride + y * ystride + x];
297         }
298
299         inline MapNode getNode(v3s16 p, bool *valid_position)
300         {
301                 return getNode(p.X, p.Y, p.Z, valid_position);
302         }
303
304         inline MapNode getNodeNoEx(v3s16 p)
305         {
306                 bool is_valid;
307                 MapNode node = getNode(p.X, p.Y, p.Z, &is_valid);
308                 return is_valid ? node : MapNode(CONTENT_IGNORE);
309         }
310
311         inline void setNode(s16 x, s16 y, s16 z, MapNode & n)
312         {
313                 if (!isValidPosition(x, y, z))
314                         throw InvalidPositionException();
315
316                 data[z * zstride + y * ystride + x] = n;
317                 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
318         }
319
320         inline void setNode(v3s16 p, MapNode & n)
321         {
322                 setNode(p.X, p.Y, p.Z, n);
323         }
324
325         ////
326         //// Non-checking variants of the above
327         ////
328
329         inline MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
330         {
331                 *valid_position = data != NULL;
332                 if (!valid_position)
333                         return MapNode(CONTENT_IGNORE);
334
335                 return data[z * zstride + y * ystride + x];
336         }
337
338         inline MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
339         {
340                 return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
341         }
342
343         inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
344         {
345                 if (data == NULL)
346                         throw InvalidPositionException();
347
348                 data[z * zstride + y * ystride + x] = n;
349                 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE_NO_CHECK);
350         }
351
352         inline void setNodeNoCheck(v3s16 p, MapNode & n)
353         {
354                 setNodeNoCheck(p.X, p.Y, p.Z, n);
355         }
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         inline bool getDayNightDiff()
391         {
392                 if (m_day_night_differs_expired)
393                         actuallyUpdateDayNightDiff();
394                 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         inline void setTimestamp(u32 time)
418         {
419                 m_timestamp = time;
420                 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_TIMESTAMP);
421         }
422
423         inline void setTimestampNoChangedFlag(u32 time)
424         {
425                 m_timestamp = time;
426         }
427
428         inline u32 getTimestamp()
429         {
430                 return m_timestamp;
431         }
432
433         inline u32 getDiskTimestamp()
434         {
435                 return m_disk_timestamp;
436         }
437
438         ////
439         //// Usage timer (see m_usage_timer)
440         ////
441
442         inline void resetUsageTimer()
443         {
444                 m_usage_timer = 0;
445         }
446
447         inline void incrementUsageTimer(float dtime)
448         {
449                 m_usage_timer += dtime;
450         }
451
452         inline float getUsageTimer()
453         {
454                 return m_usage_timer;
455         }
456
457         ////
458         //// Reference counting (see m_refcount)
459         ////
460
461         inline void refGrab()
462         {
463                 m_refcount++;
464         }
465
466         inline void refDrop()
467         {
468                 m_refcount--;
469         }
470
471         inline int refGet()
472         {
473                 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         inline void setNodeTimer(v3s16 p, NodeTimer t)
491         {
492                 m_node_timers.set(p,t);
493         }
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         inline MapNode &getNodeRef(s16 x, s16 y, s16 z)
527         {
528                 if (!isValidPosition(x, y, z))
529                         throw InvalidPositionException();
530
531                 return data[z * zstride + y * ystride + x];
532         }
533
534         inline MapNode &getNodeRef(v3s16 &p)
535         {
536                 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 inline bool blockpos_over_limit(v3s16 p)
632 {
633         return
634           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
635         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
636         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
637         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
638         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
639         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
640 }
641
642 /*
643         Returns the position of the block where the node is located
644 */
645 inline v3s16 getNodeBlockPos(v3s16 p)
646 {
647         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 inline void getNodeBlockPosWithOffset(const v3s16 &p, v3s16 &block, v3s16 &offset)
661 {
662         getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
663 }
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