Properly and efficiently use split utility headers
[oweals/minetest.git] / src / mapblock.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010 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 <jmutex.h>
24 #include <jmutexautolock.h>
25 #include <exception>
26 #include "debug.h"
27 #include "common_irrlicht.h"
28 #include "mapnode.h"
29 #include "exceptions.h"
30 #include "serialization.h"
31 #include "constants.h"
32 #include "voxel.h"
33 #include "staticobject.h"
34 #include "nodemetadata.h"
35 #include "nodetimer.h"
36 #include "modifiedstate.h"
37 #include "util/numeric.h" // getContainerPos
38
39 class Map;
40 class NodeMetadataList;
41 class IGameDef;
42 class MapBlockMesh;
43
44 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
45
46 /*// Named by looking towards z+
47 enum{
48         FACE_BACK=0,
49         FACE_TOP,
50         FACE_RIGHT,
51         FACE_FRONT,
52         FACE_BOTTOM,
53         FACE_LEFT
54 };*/
55
56 // NOTE: If this is enabled, set MapBlock to be initialized with
57 //       CONTENT_IGNORE.
58 /*enum BlockGenerationStatus
59 {
60         // Completely non-generated (filled with CONTENT_IGNORE).
61         BLOCKGEN_UNTOUCHED=0,
62         // Trees or similar might have been blitted from other blocks to here.
63         // Otherwise, the block contains CONTENT_IGNORE
64         BLOCKGEN_FROM_NEIGHBORS=2,
65         // Has been generated, but some neighbors might put some stuff in here
66         // when they are generated.
67         // Does not contain any CONTENT_IGNORE
68         BLOCKGEN_SELF_GENERATED=4,
69         // The block and all its neighbors have been generated
70         BLOCKGEN_FULLY_GENERATED=6
71 };*/
72
73 #if 0
74 enum
75 {
76         NODECONTAINER_ID_MAPBLOCK,
77         NODECONTAINER_ID_MAPSECTOR,
78         NODECONTAINER_ID_MAP,
79         NODECONTAINER_ID_MAPBLOCKCACHE,
80         NODECONTAINER_ID_VOXELMANIPULATOR,
81 };
82
83 class NodeContainer
84 {
85 public:
86         virtual bool isValidPosition(v3s16 p) = 0;
87         virtual MapNode getNode(v3s16 p) = 0;
88         virtual void setNode(v3s16 p, MapNode & n) = 0;
89         virtual u16 nodeContainerId() const = 0;
90
91         MapNode getNodeNoEx(v3s16 p)
92         {
93                 try{
94                         return getNode(p);
95                 }
96                 catch(InvalidPositionException &e){
97                         return MapNode(CONTENT_IGNORE);
98                 }
99         }
100 };
101 #endif
102
103 /*
104         MapBlock itself
105 */
106
107 class MapBlock /*: public NodeContainer*/
108 {
109 public:
110         MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
111         ~MapBlock();
112         
113         /*virtual u16 nodeContainerId() const
114         {
115                 return NODECONTAINER_ID_MAPBLOCK;
116         }*/
117         
118         Map * getParent()
119         {
120                 return m_parent;
121         }
122
123         void reallocate()
124         {
125                 if(data != NULL)
126                         delete[] data;
127                 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
128                 data = new MapNode[l];
129                 for(u32 i=0; i<l; i++){
130                         //data[i] = MapNode();
131                         data[i] = MapNode(CONTENT_IGNORE);
132                 }
133                 raiseModified(MOD_STATE_WRITE_NEEDED, "reallocate");
134         }
135
136         /*
137                 Flags
138         */
139
140         bool isDummy()
141         {
142                 return (data == NULL);
143         }
144         void unDummify()
145         {
146                 assert(isDummy());
147                 reallocate();
148         }
149         
150         // m_modified methods
151         void raiseModified(u32 mod, const std::string &reason="unknown")
152         {
153                 if(mod > m_modified){
154                         m_modified = mod;
155                         m_modified_reason = reason;
156                         m_modified_reason_too_long = false;
157
158                         if(m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
159                                 m_disk_timestamp = m_timestamp;
160                         }
161                 } else if(mod == m_modified){
162                         if(!m_modified_reason_too_long){
163                                 if(m_modified_reason.size() < 40)
164                                         m_modified_reason += ", " + reason;
165                                 else{
166                                         m_modified_reason += "...";
167                                         m_modified_reason_too_long = true;
168                                 }
169                         }
170                 }
171         }
172         u32 getModified()
173         {
174                 return m_modified;
175         }
176         std::string getModifiedReason()
177         {
178                 return m_modified_reason;
179         }
180         void resetModified()
181         {
182                 m_modified = MOD_STATE_CLEAN;
183                 m_modified_reason = "none";
184                 m_modified_reason_too_long = false;
185         }
186         
187         // is_underground getter/setter
188         bool getIsUnderground()
189         {
190                 return is_underground;
191         }
192         void setIsUnderground(bool a_is_underground)
193         {
194                 is_underground = a_is_underground;
195                 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
196         }
197
198         void setLightingExpired(bool expired)
199         {
200                 if(expired != m_lighting_expired){
201                         m_lighting_expired = expired;
202                         raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
203                 }
204         }
205         bool getLightingExpired()
206         {
207                 return m_lighting_expired;
208         }
209
210         bool isGenerated()
211         {
212                 return m_generated;
213         }
214         void setGenerated(bool b)
215         {
216                 if(b != m_generated){
217                         raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
218                         m_generated = b;
219                 }
220         }
221
222         bool isValid()
223         {
224                 if(m_lighting_expired)
225                         return false;
226                 if(data == NULL)
227                         return false;
228                 return true;
229         }
230
231         /*
232                 Position stuff
233         */
234
235         v3s16 getPos()
236         {
237                 return m_pos;
238         }
239                 
240         v3s16 getPosRelative()
241         {
242                 return m_pos * MAP_BLOCKSIZE;
243         }
244                 
245         core::aabbox3d<s16> getBox()
246         {
247                 return core::aabbox3d<s16>(getPosRelative(),
248                                 getPosRelative()
249                                 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
250                                 - v3s16(1,1,1));
251         }
252
253         /*
254                 Regular MapNode get-setters
255         */
256         
257         bool isValidPosition(v3s16 p)
258         {
259                 if(data == NULL)
260                         return false;
261                 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
262                                 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
263                                 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
264         }
265
266         MapNode getNode(s16 x, s16 y, s16 z)
267         {
268                 if(data == NULL)
269                         throw InvalidPositionException();
270                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
271                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
272                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
273                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
274         }
275         
276         MapNode getNode(v3s16 p)
277         {
278                 return getNode(p.X, p.Y, p.Z);
279         }
280         
281         MapNode getNodeNoEx(v3s16 p)
282         {
283                 try{
284                         return getNode(p.X, p.Y, p.Z);
285                 }catch(InvalidPositionException &e){
286                         return MapNode(CONTENT_IGNORE);
287                 }
288         }
289         
290         void setNode(s16 x, s16 y, s16 z, MapNode & n)
291         {
292                 if(data == NULL)
293                         throw InvalidPositionException();
294                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
295                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
296                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
297                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
298                 raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
299         }
300         
301         void setNode(v3s16 p, MapNode & n)
302         {
303                 setNode(p.X, p.Y, p.Z, n);
304         }
305
306         /*
307                 Non-checking variants of the above
308         */
309
310         MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
311         {
312                 if(data == NULL)
313                         throw InvalidPositionException();
314                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
315         }
316         
317         MapNode getNodeNoCheck(v3s16 p)
318         {
319                 return getNodeNoCheck(p.X, p.Y, p.Z);
320         }
321         
322         void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
323         {
324                 if(data == NULL)
325                         throw InvalidPositionException();
326                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
327                 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
328         }
329         
330         void setNodeNoCheck(v3s16 p, MapNode & n)
331         {
332                 setNodeNoCheck(p.X, p.Y, p.Z, n);
333         }
334
335         /*
336                 These functions consult the parent container if the position
337                 is not valid on this MapBlock.
338         */
339         bool isValidPositionParent(v3s16 p);
340         MapNode getNodeParent(v3s16 p);
341         void setNodeParent(v3s16 p, MapNode & n);
342         MapNode getNodeParentNoEx(v3s16 p);
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(core::map<v3s16, bool> & 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                 Serialization
434         */
435         
436         // These don't write or read version by itself
437         // Set disk to true for on-disk format, false for over-the-network format
438         void serialize(std::ostream &os, u8 version, bool disk);
439         // If disk == true: In addition to doing other things, will add
440         // unknown blocks from id-name mapping to wndef
441         void deSerialize(std::istream &is, u8 version, bool disk);
442
443 private:
444         /*
445                 Private methods
446         */
447
448         void serialize_pre22(std::ostream &os, u8 version, bool disk);
449         void deSerialize_pre22(std::istream &is, u8 version, bool disk);
450
451         /*
452                 Used only internally, because changes can't be tracked
453         */
454
455         MapNode & getNodeRef(s16 x, s16 y, s16 z)
456         {
457                 if(data == NULL)
458                         throw InvalidPositionException();
459                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
460                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
461                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
462                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
463         }
464         MapNode & getNodeRef(v3s16 &p)
465         {
466                 return getNodeRef(p.X, p.Y, p.Z);
467         }
468
469 public:
470         /*
471                 Public member variables
472         */
473
474 #ifndef SERVER // Only on client
475         MapBlockMesh *mesh;
476         //JMutex mesh_mutex;
477 #endif
478         
479         NodeMetadataList m_node_metadata;
480         NodeTimerList m_node_timers;
481         StaticObjectList m_static_objects;
482         
483 private:
484         /*
485                 Private member variables
486         */
487
488         // NOTE: Lots of things rely on this being the Map
489         Map *m_parent;
490         // Position in blocks on parent
491         v3s16 m_pos;
492
493         IGameDef *m_gamedef;
494         
495         /*
496                 If NULL, block is a dummy block.
497                 Dummy blocks are used for caching not-found-on-disk blocks.
498         */
499         MapNode * data;
500
501         /*
502                 - On the server, this is used for telling whether the
503                   block has been modified from the one on disk.
504                 - On the client, this is used for nothing.
505         */
506         u32 m_modified;
507         std::string m_modified_reason;
508         bool m_modified_reason_too_long;
509
510         /*
511                 When propagating sunlight and the above block doesn't exist,
512                 sunlight is assumed if this is false.
513
514                 In practice this is set to true if the block is completely
515                 undeground with nothing visible above the ground except
516                 caves.
517         */
518         bool is_underground;
519
520         /*
521                 Set to true if changes has been made that make the old lighting
522                 values wrong but the lighting hasn't been actually updated.
523
524                 If this is false, lighting is exactly right.
525                 If this is true, lighting might be wrong or right.
526         */
527         bool m_lighting_expired;
528         
529         // Whether day and night lighting differs
530         bool m_day_night_differs;
531         bool m_day_night_differs_expired;
532
533         bool m_generated;
534         
535         /*
536                 When block is removed from active blocks, this is set to gametime.
537                 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
538         */
539         u32 m_timestamp;
540         // The on-disk (or to-be on-disk) timestamp value
541         u32 m_disk_timestamp;
542
543         /*
544                 When the block is accessed, this is set to 0.
545                 Map will unload the block when this reaches a timeout.
546         */
547         float m_usage_timer;
548 };
549
550 inline bool blockpos_over_limit(v3s16 p)
551 {
552         return
553           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
554         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
555         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
556         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
557         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
558         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
559 }
560
561 /*
562         Returns the position of the block where the node is located
563 */
564 inline v3s16 getNodeBlockPos(v3s16 p)
565 {
566         return getContainerPos(p, MAP_BLOCKSIZE);
567 }
568
569 inline v2s16 getNodeSectorPos(v2s16 p)
570 {
571         return getContainerPos(p, MAP_BLOCKSIZE);
572 }
573
574 inline s16 getNodeBlockY(s16 y)
575 {
576         return getContainerPos(y, MAP_BLOCKSIZE);
577 }
578
579 /*
580         Get a quick string to describe what a block actually contains
581 */
582 std::string analyze_block(MapBlock *block);
583
584 #endif
585