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