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