]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapblock.h
Fix MSVC build
[dragonfireclient.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 itself
102 */
103
104 class MapBlock /*: public NodeContainer*/
105 {
106 public:
107         MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
108         ~MapBlock();
109         
110         /*virtual u16 nodeContainerId() const
111         {
112                 return NODECONTAINER_ID_MAPBLOCK;
113         }*/
114         
115         Map * getParent()
116         {
117                 return m_parent;
118         }
119
120         void reallocate()
121         {
122                 if(data != NULL)
123                         delete[] data;
124                 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
125                 data = new MapNode[l];
126                 for(u32 i=0; i<l; i++){
127                         //data[i] = MapNode();
128                         data[i] = MapNode(CONTENT_IGNORE);
129                 }
130                 raiseModified(MOD_STATE_WRITE_NEEDED, "reallocate");
131         }
132
133         /*
134                 Flags
135         */
136
137         bool isDummy()
138         {
139                 return (data == NULL);
140         }
141         void unDummify()
142         {
143                 assert(isDummy());
144                 reallocate();
145         }
146         
147         // m_modified methods
148         void raiseModified(u32 mod, const std::string &reason="unknown")
149         {
150                 if(mod > m_modified){
151                         m_modified = mod;
152                         m_modified_reason = reason;
153                         m_modified_reason_too_long = false;
154
155                         if(m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
156                                 m_disk_timestamp = m_timestamp;
157                         }
158                 } else if(mod == m_modified){
159                         if(!m_modified_reason_too_long){
160                                 if(m_modified_reason.size() < 40)
161                                         m_modified_reason += ", " + reason;
162                                 else{
163                                         m_modified_reason += "...";
164                                         m_modified_reason_too_long = true;
165                                 }
166                         }
167                 }
168         }
169         u32 getModified()
170         {
171                 return m_modified;
172         }
173         std::string getModifiedReason()
174         {
175                 return m_modified_reason;
176         }
177         void resetModified()
178         {
179                 m_modified = MOD_STATE_CLEAN;
180                 m_modified_reason = "none";
181                 m_modified_reason_too_long = false;
182         }
183         
184         // is_underground getter/setter
185         bool getIsUnderground()
186         {
187                 return is_underground;
188         }
189         void setIsUnderground(bool a_is_underground)
190         {
191                 is_underground = a_is_underground;
192                 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
193         }
194
195         void setLightingExpired(bool expired)
196         {
197                 if(expired != m_lighting_expired){
198                         m_lighting_expired = expired;
199                         raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
200                 }
201         }
202         bool getLightingExpired()
203         {
204                 return m_lighting_expired;
205         }
206
207         bool isGenerated()
208         {
209                 return m_generated;
210         }
211         void setGenerated(bool b)
212         {
213                 if(b != m_generated){
214                         raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
215                         m_generated = b;
216                 }
217         }
218
219         bool isValid()
220         {
221                 if(m_lighting_expired)
222                         return false;
223                 if(data == NULL)
224                         return false;
225                 return true;
226         }
227
228         /*
229                 Position stuff
230         */
231
232         v3s16 getPos()
233         {
234                 return m_pos;
235         }
236                 
237         v3s16 getPosRelative()
238         {
239                 return m_pos * MAP_BLOCKSIZE;
240         }
241                 
242         core::aabbox3d<s16> getBox()
243         {
244                 return core::aabbox3d<s16>(getPosRelative(),
245                                 getPosRelative()
246                                 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
247                                 - v3s16(1,1,1));
248         }
249
250         /*
251                 Regular MapNode get-setters
252         */
253         
254         bool isValidPosition(s16 x, s16 y, s16 z)
255         {
256                 return data != NULL
257                                 && x >= 0 && x < MAP_BLOCKSIZE
258                                 && y >= 0 && y < MAP_BLOCKSIZE
259                                 && z >= 0 && z < MAP_BLOCKSIZE;
260         }
261
262         bool isValidPosition(v3s16 p)
263         {
264                 return isValidPosition(p.X, p.Y, p.Z);
265         }
266
267         MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
268         {
269                 *valid_position = isValidPosition(x, y, z);
270
271                 if (!*valid_position)
272                         return MapNode(CONTENT_IGNORE);
273
274                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
275         }
276         
277         MapNode getNode(v3s16 p, bool *valid_position)
278         {
279                 return getNode(p.X, p.Y, p.Z, valid_position);
280         }
281         
282         MapNode getNodeNoEx(v3s16 p)
283         {
284                 bool is_valid;
285                 MapNode node = getNode(p.X, p.Y, p.Z, &is_valid);
286                 return is_valid ? node : MapNode(CONTENT_IGNORE);
287         }
288         
289         void setNode(s16 x, s16 y, s16 z, MapNode & n)
290         {
291                 if(data == NULL)
292                         throw InvalidPositionException();
293                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
294                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
295                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
296                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
297                 raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
298         }
299         
300         void setNode(v3s16 p, MapNode & n)
301         {
302                 setNode(p.X, p.Y, p.Z, n);
303         }
304
305         /*
306                 Non-checking variants of the above
307         */
308
309         MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
310         {
311                 *valid_position = data != NULL;
312                 if(!valid_position)
313                         return MapNode(CONTENT_IGNORE);
314
315                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
316         }
317         
318         MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
319         {
320                 return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
321         }
322         
323         void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
324         {
325                 if(data == NULL)
326                         throw InvalidPositionException();
327                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
328                 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
329         }
330         
331         void setNodeNoCheck(v3s16 p, MapNode & n)
332         {
333                 setNodeNoCheck(p.X, p.Y, p.Z, n);
334         }
335
336         /*
337                 These functions consult the parent container if the position
338                 is not valid on this MapBlock.
339         */
340         bool isValidPositionParent(v3s16 p);
341         MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
342         void setNodeParent(v3s16 p, MapNode & n);
343
344         void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
345         {
346                 for(u16 z=0; z<d; z++)
347                         for(u16 y=0; y<h; y++)
348                                 for(u16 x=0; x<w; x++)
349                                         setNode(x0+x, y0+y, z0+z, node);
350         }
351
352         // See comments in mapblock.cpp
353         bool propagateSunlight(std::set<v3s16> & light_sources,
354                         bool remove_light=false, bool *black_air_left=NULL);
355         
356         // Copies data to VoxelManipulator to getPosRelative()
357         void copyTo(VoxelManipulator &dst);
358         // Copies data from VoxelManipulator getPosRelative()
359         void copyFrom(VoxelManipulator &dst);
360
361         /*
362                 Update day-night lighting difference flag.
363                 Sets m_day_night_differs to appropriate value.
364                 These methods don't care about neighboring blocks.
365         */
366         void actuallyUpdateDayNightDiff();
367         /*
368                 Call this to schedule what the previous function does to be done
369                 when the value is actually needed.
370         */
371         void expireDayNightDiff();
372
373         bool getDayNightDiff()
374         {
375                 if(m_day_night_differs_expired)
376                         actuallyUpdateDayNightDiff();
377                 return m_day_night_differs;
378         }
379
380         /*
381                 Miscellaneous stuff
382         */
383         
384         /*
385                 Tries to measure ground level.
386                 Return value:
387                         -1 = only air
388                         -2 = only ground
389                         -3 = random fail
390                         0...MAP_BLOCKSIZE-1 = ground level
391         */
392         s16 getGroundLevel(v2s16 p2d);
393
394         /*
395                 Timestamp (see m_timestamp)
396                 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
397         */
398         void setTimestamp(u32 time)
399         {
400                 m_timestamp = time;
401                 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
402         }
403         void setTimestampNoChangedFlag(u32 time)
404         {
405                 m_timestamp = time;
406         }
407         u32 getTimestamp()
408         {
409                 return m_timestamp;
410         }
411         u32 getDiskTimestamp()
412         {
413                 return m_disk_timestamp;
414         }
415         
416         /*
417                 See m_usage_timer
418         */
419         void resetUsageTimer()
420         {
421                 m_usage_timer = 0;
422         }
423         void incrementUsageTimer(float dtime)
424         {
425                 m_usage_timer += dtime;
426         }
427         u32 getUsageTimer()
428         {
429                 return m_usage_timer;
430         }
431
432         /*
433                 See m_refcount
434         */
435         void refGrab()
436         {
437                 m_refcount++;
438         }
439         void refDrop()
440         {
441                 m_refcount--;
442         }
443         int refGet()
444         {
445                 return m_refcount;
446         }
447         
448         /*
449                 Node Timers
450         */
451         // Get timer
452         NodeTimer getNodeTimer(v3s16 p){ 
453                 return m_node_timers.get(p);
454         }
455         // Deletes timer
456         void removeNodeTimer(v3s16 p){
457                 m_node_timers.remove(p);
458         }
459         // Deletes old timer and sets a new one
460         void setNodeTimer(v3s16 p, NodeTimer t){
461                 m_node_timers.set(p,t);
462         }
463         // Deletes all timers
464         void clearNodeTimers(){
465                 m_node_timers.clear();
466         }
467
468         /*
469                 Serialization
470         */
471         
472         // These don't write or read version by itself
473         // Set disk to true for on-disk format, false for over-the-network format
474         void serialize(std::ostream &os, u8 version, bool disk);
475         // If disk == true: In addition to doing other things, will add
476         // unknown blocks from id-name mapping to wndef
477         void deSerialize(std::istream &is, u8 version, bool disk);
478
479         void serializeNetworkSpecific(std::ostream &os, u16 net_proto_version);
480         void deSerializeNetworkSpecific(std::istream &is);
481
482 private:
483         /*
484                 Private methods
485         */
486
487         void deSerialize_pre22(std::istream &is, u8 version, bool disk);
488
489         /*
490                 Used only internally, because changes can't be tracked
491         */
492
493         MapNode & getNodeRef(s16 x, s16 y, s16 z)
494         {
495                 if(data == NULL)
496                         throw InvalidPositionException();
497                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
498                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
499                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
500                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
501         }
502         MapNode & getNodeRef(v3s16 &p)
503         {
504                 return getNodeRef(p.X, p.Y, p.Z);
505         }
506
507 public:
508         /*
509                 Public member variables
510         */
511
512 #ifndef SERVER // Only on client
513         MapBlockMesh *mesh;
514 #endif
515         
516         NodeMetadataList m_node_metadata;
517         NodeTimerList m_node_timers;
518         StaticObjectList m_static_objects;
519
520 private:
521         /*
522                 Private member variables
523         */
524
525         // NOTE: Lots of things rely on this being the Map
526         Map *m_parent;
527         // Position in blocks on parent
528         v3s16 m_pos;
529
530         IGameDef *m_gamedef;
531         
532         /*
533                 If NULL, block is a dummy block.
534                 Dummy blocks are used for caching not-found-on-disk blocks.
535         */
536         MapNode * data;
537
538         /*
539                 - On the server, this is used for telling whether the
540                   block has been modified from the one on disk.
541                 - On the client, this is used for nothing.
542         */
543         u32 m_modified;
544         std::string m_modified_reason;
545         bool m_modified_reason_too_long;
546
547         /*
548                 When propagating sunlight and the above block doesn't exist,
549                 sunlight is assumed if this is false.
550
551                 In practice this is set to true if the block is completely
552                 undeground with nothing visible above the ground except
553                 caves.
554         */
555         bool is_underground;
556
557         /*
558                 Set to true if changes has been made that make the old lighting
559                 values wrong but the lighting hasn't been actually updated.
560
561                 If this is false, lighting is exactly right.
562                 If this is true, lighting might be wrong or right.
563         */
564         bool m_lighting_expired;
565         
566         // Whether day and night lighting differs
567         bool m_day_night_differs;
568         bool m_day_night_differs_expired;
569
570         bool m_generated;
571         
572         /*
573                 When block is removed from active blocks, this is set to gametime.
574                 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
575         */
576         u32 m_timestamp;
577         // The on-disk (or to-be on-disk) timestamp value
578         u32 m_disk_timestamp;
579
580         /*
581                 When the block is accessed, this is set to 0.
582                 Map will unload the block when this reaches a timeout.
583         */
584         float m_usage_timer;
585
586         /*
587                 Reference count; currently used for determining if this block is in
588                 the list of blocks to be drawn.
589         */
590         int m_refcount;
591 };
592
593 inline bool blockpos_over_limit(v3s16 p)
594 {
595         return
596           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
597         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
598         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
599         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
600         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
601         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
602 }
603
604 /*
605         Returns the position of the block where the node is located
606 */
607 inline v3s16 getNodeBlockPos(v3s16 p)
608 {
609         return getContainerPos(p, MAP_BLOCKSIZE);
610 }
611
612 inline v2s16 getNodeSectorPos(v2s16 p)
613 {
614         return getContainerPos(p, MAP_BLOCKSIZE);
615 }
616
617 inline s16 getNodeBlockY(s16 y)
618 {
619         return getContainerPos(y, MAP_BLOCKSIZE);
620 }
621
622 /*
623         Get a quick string to describe what a block actually contains
624 */
625 std::string analyze_block(MapBlock *block);
626
627 #endif
628