a77bf40c06c794c4b7cfc49da7f431e84bca6735
[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 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 "mapblockobject.h"
33 #include "voxel.h"
34 #include "nodemetadata.h"
35
36
37 // Named by looking towards z+
38 enum{
39         FACE_BACK=0,
40         FACE_TOP,
41         FACE_RIGHT,
42         FACE_FRONT,
43         FACE_BOTTOM,
44         FACE_LEFT
45 };
46
47 struct FastFace
48 {
49         TileSpec tile;
50         video::S3DVertex vertices[4]; // Precalculated vertices
51 };
52
53 enum NodeModType
54 {
55         NODEMOD_NONE,
56         NODEMOD_CHANGECONTENT, //param is content id
57         NODEMOD_CRACK // param is crack progression
58 };
59
60 struct NodeMod
61 {
62         NodeMod(enum NodeModType a_type=NODEMOD_NONE, u16 a_param=0)
63         {
64                 type = a_type;
65                 param = a_param;
66         }
67         bool operator==(const NodeMod &other)
68         {
69                 return (type == other.type && param == other.param);
70         }
71         enum NodeModType type;
72         u16 param;
73 };
74
75 class NodeModMap
76 {
77 public:
78         /*
79                 returns true if the mod was different last time
80         */
81         bool set(v3s16 p, const NodeMod &mod)
82         {
83                 // See if old is different, cancel if it is not different.
84                 core::map<v3s16, NodeMod>::Node *n = m_mods.find(p);
85                 if(n)
86                 {
87                         NodeMod old = n->getValue();
88                         if(old == mod)
89                                 return false;
90
91                         n->setValue(mod);
92                 }
93                 else
94                 {
95                         m_mods.insert(p, mod);
96                 }
97                 
98                 return true;
99         }
100         // Returns true if there was one
101         bool get(v3s16 p, NodeMod *mod)
102         {
103                 core::map<v3s16, NodeMod>::Node *n;
104                 n = m_mods.find(p);
105                 if(n == NULL)
106                         return false;
107                 if(mod)
108                         *mod = n->getValue();
109                 return true;
110         }
111         bool clear(v3s16 p)
112         {
113                 if(m_mods.find(p))
114                 {
115                         m_mods.remove(p);
116                         return true;
117                 }
118                 return false;
119         }
120         bool clear()
121         {
122                 if(m_mods.size() == 0)
123                         return false;
124                 m_mods.clear();
125                 return true;
126         }
127         void copy(NodeModMap &dest)
128         {
129                 dest.m_mods.clear();
130
131                 for(core::map<v3s16, NodeMod>::Iterator
132                                 i = m_mods.getIterator();
133                                 i.atEnd() == false; i++)
134                 {
135                         dest.m_mods.insert(i.getNode()->getKey(), i.getNode()->getValue());
136                 }
137         }
138
139 private:
140         core::map<v3s16, NodeMod> m_mods;
141 };
142
143 enum
144 {
145         NODECONTAINER_ID_MAPBLOCK,
146         NODECONTAINER_ID_MAPSECTOR,
147         NODECONTAINER_ID_MAP,
148         NODECONTAINER_ID_MAPBLOCKCACHE,
149         NODECONTAINER_ID_VOXELMANIPULATOR,
150 };
151
152 class NodeContainer
153 {
154 public:
155         virtual bool isValidPosition(v3s16 p) = 0;
156         virtual MapNode getNode(v3s16 p) = 0;
157         virtual void setNode(v3s16 p, MapNode & n) = 0;
158         virtual u16 nodeContainerId() const = 0;
159
160         MapNode getNodeNoEx(v3s16 p)
161         {
162                 try{
163                         return getNode(p);
164                 }
165                 catch(InvalidPositionException &e){
166                         return MapNode(CONTENT_IGNORE);
167                 }
168         }
169 };
170
171 /*
172         Mesh making stuff
173 */
174
175 class MapBlock;
176
177 #ifndef SERVER
178
179 struct MeshMakeData
180 {
181         u32 m_daynight_ratio;
182         NodeModMap m_temp_mods;
183         VoxelManipulator m_vmanip;
184         v3s16 m_blockpos;
185         
186         /*
187                 Copy central data directly from block, and other data from
188                 parent of block.
189         */
190         void fill(u32 daynight_ratio, MapBlock *block);
191 };
192
193 scene::SMesh* makeMapBlockMesh(MeshMakeData *data);
194
195 #endif
196
197 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
198                 v3s16 face_dir);
199
200 /*
201         MapBlock itself
202 */
203
204 class MapBlock : public NodeContainer
205 {
206 public:
207         MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false);
208         ~MapBlock();
209         
210         virtual u16 nodeContainerId() const
211         {
212                 return NODECONTAINER_ID_MAPBLOCK;
213         }
214         
215         NodeContainer * getParent()
216         {
217                 return m_parent;
218         }
219
220         void reallocate()
221         {
222                 if(data != NULL)
223                         delete[] data;
224                 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
225                 data = new MapNode[l];
226                 for(u32 i=0; i<l; i++){
227                         data[i] = MapNode();
228                 }
229                 setChangedFlag();
230         }
231
232         /*
233                 Flags
234         */
235
236         bool isDummy()
237         {
238                 return (data == NULL);
239         }
240         void unDummify()
241         {
242                 assert(isDummy());
243                 reallocate();
244         }
245         
246         bool getChangedFlag()
247         {
248                 return changed;
249         }
250         void resetChangedFlag()
251         {
252                 changed = false;
253         }
254         void setChangedFlag()
255         {
256                 changed = true;
257         }
258
259         bool getIsUnderground()
260         {
261                 return is_underground;
262         }
263
264         void setIsUnderground(bool a_is_underground)
265         {
266                 is_underground = a_is_underground;
267                 setChangedFlag();
268         }
269
270 #ifndef SERVER
271         void setMeshExpired(bool expired)
272         {
273                 m_mesh_expired = expired;
274         }
275         
276         bool getMeshExpired()
277         {
278                 return m_mesh_expired;
279         }
280 #endif
281
282         void setLightingExpired(bool expired)
283         {
284                 m_lighting_expired = expired;
285                 setChangedFlag();
286         }
287         bool getLightingExpired()
288         {
289                 return m_lighting_expired;
290         }
291
292         /*bool isFullyGenerated()
293         {
294                 return !m_not_fully_generated;
295         }
296         void setFullyGenerated(bool b)
297         {
298                 setChangedFlag();
299                 m_not_fully_generated = !b;
300         }*/
301
302         bool isValid()
303         {
304                 if(m_lighting_expired)
305                         return false;
306                 if(data == NULL)
307                         return false;
308                 return true;
309         }
310
311         /*
312                 Position stuff
313         */
314
315         v3s16 getPos()
316         {
317                 return m_pos;
318         }
319                 
320         v3s16 getPosRelative()
321         {
322                 return m_pos * MAP_BLOCKSIZE;
323         }
324                 
325         core::aabbox3d<s16> getBox()
326         {
327                 return core::aabbox3d<s16>(getPosRelative(),
328                                 getPosRelative()
329                                 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
330                                 - v3s16(1,1,1));
331         }
332
333         /*
334                 Regular MapNode get-setters
335         */
336         
337         bool isValidPosition(v3s16 p)
338         {
339                 if(data == NULL)
340                         return false;
341                 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
342                                 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
343                                 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
344         }
345
346         MapNode getNode(s16 x, s16 y, s16 z)
347         {
348                 if(data == NULL)
349                         throw InvalidPositionException();
350                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
351                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
352                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
353                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
354         }
355         
356         MapNode getNode(v3s16 p)
357         {
358                 return getNode(p.X, p.Y, p.Z);
359         }
360         
361         void setNode(s16 x, s16 y, s16 z, MapNode & n)
362         {
363                 if(data == NULL)
364                         throw InvalidPositionException();
365                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
366                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
367                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
368                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
369                 setChangedFlag();
370         }
371         
372         void setNode(v3s16 p, MapNode & n)
373         {
374                 setNode(p.X, p.Y, p.Z, n);
375         }
376
377         /*
378                 Non-checking variants of the above
379         */
380
381         MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
382         {
383                 if(data == NULL)
384                         throw InvalidPositionException();
385                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
386         }
387         
388         MapNode getNodeNoCheck(v3s16 p)
389         {
390                 return getNodeNoCheck(p.X, p.Y, p.Z);
391         }
392         
393         void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
394         {
395                 if(data == NULL)
396                         throw InvalidPositionException();
397                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
398                 setChangedFlag();
399         }
400         
401         void setNodeNoCheck(v3s16 p, MapNode & n)
402         {
403                 setNodeNoCheck(p.X, p.Y, p.Z, n);
404         }
405
406         /*
407                 These functions consult the parent container if the position
408                 is not valid on this MapBlock.
409         */
410         bool isValidPositionParent(v3s16 p);
411         MapNode getNodeParent(v3s16 p);
412         void setNodeParent(v3s16 p, MapNode & n);
413         MapNode getNodeParentNoEx(v3s16 p);
414
415         void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
416         {
417                 for(u16 z=0; z<d; z++)
418                         for(u16 y=0; y<h; y++)
419                                 for(u16 x=0; x<w; x++)
420                                         setNode(x0+x, y0+y, z0+z, node);
421         }
422
423         /*
424                 Graphics-related methods
425         */
426         
427         /*// A quick version with nodes passed as parameters
428         u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
429                         v3s16 face_dir);*/
430         /*// A more convenient version
431         u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
432         {
433                 return getFaceLight(daynight_ratio,
434                                 getNodeParentNoEx(p),
435                                 getNodeParentNoEx(p + face_dir),
436                                 face_dir);
437         }*/
438         u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
439         {
440                 return getFaceLight(daynight_ratio,
441                                 getNodeParentNoEx(p),
442                                 getNodeParentNoEx(p + face_dir),
443                                 face_dir);
444         }
445         
446 #ifndef SERVER
447         // light = 0...255
448         /*static void makeFastFace(TileSpec tile, u8 light, v3f p,
449                         v3s16 dir, v3f scale, v3f posRelative_f,
450                         core::array<FastFace> &dest);*/
451         
452         /*TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
453                         NodeModMap &temp_mods);*/
454         /*u8 getNodeContent(v3s16 p, MapNode mn,
455                         NodeModMap &temp_mods);*/
456
457         /*
458                 Generates the FastFaces of a node row. This has a
459                 ridiculous amount of parameters because that way they
460                 can be precalculated by the caller.
461
462                 translate_dir: unit vector with only one of x, y or z
463                 face_dir: unit vector with only one of x, y or z
464         */
465         /*void updateFastFaceRow(
466                         u32 daynight_ratio,
467                         v3f posRelative_f,
468                         v3s16 startpos,
469                         u16 length,
470                         v3s16 translate_dir,
471                         v3f translate_dir_f,
472                         v3s16 face_dir,
473                         v3f face_dir_f,
474                         core::array<FastFace> &dest,
475                         NodeModMap &temp_mods);*/
476         
477         /*
478                 Thread-safely updates the whole mesh of the mapblock.
479         */
480 #if 1
481         void updateMesh(u32 daynight_ratio);
482 #endif
483
484         void replaceMesh(scene::SMesh *mesh_new);
485         
486 #endif // !SERVER
487         
488         // See comments in mapblock.cpp
489         bool propagateSunlight(core::map<v3s16, bool> & light_sources,
490                         bool remove_light=false, bool *black_air_left=NULL,
491                         bool grow_grass=false);
492         
493         // Copies data to VoxelManipulator to getPosRelative()
494         void copyTo(VoxelManipulator &dst);
495         // Copies data from VoxelManipulator getPosRelative()
496         void copyFrom(VoxelManipulator &dst);
497
498         /*
499                 MapBlockObject stuff
500         */
501         
502         void serializeObjects(std::ostream &os, u8 version)
503         {
504                 m_objects.serialize(os, version);
505         }
506         // If smgr!=NULL, new objects are added to the scene
507         void updateObjects(std::istream &is, u8 version,
508                         scene::ISceneManager *smgr, u32 daynight_ratio)
509         {
510                 m_objects.update(is, version, smgr, daynight_ratio);
511
512                 setChangedFlag();
513         }
514         void clearObjects()
515         {
516                 m_objects.clear();
517
518                 setChangedFlag();
519         }
520         void addObject(MapBlockObject *object)
521                         throw(ContainerFullException, AlreadyExistsException)
522         {
523                 m_objects.add(object);
524
525                 setChangedFlag();
526         }
527         void removeObject(s16 id)
528         {
529                 m_objects.remove(id);
530
531                 setChangedFlag();
532         }
533         MapBlockObject * getObject(s16 id)
534         {
535                 return m_objects.get(id);
536         }
537         JMutexAutoLock * getObjectLock()
538         {
539                 return m_objects.getLock();
540         }
541
542         /*
543                 Moves objects, deletes objects and spawns new objects
544         */
545         void stepObjects(float dtime, bool server, u32 daynight_ratio);
546
547         /*void wrapObject(MapBlockObject *object)
548         {
549                 m_objects.wrapObject(object);
550
551                 setChangedFlag();
552         }*/
553
554         // origin is relative to block
555         void getObjects(v3f origin, f32 max_d,
556                         core::array<DistanceSortedObject> &dest)
557         {
558                 m_objects.getObjects(origin, max_d, dest);
559         }
560
561         s32 getObjectCount()
562         {
563                 return m_objects.getCount();
564         }
565
566 #ifndef SERVER
567         /*
568                 Methods for setting temporary modifications to nodes for
569                 drawing
570
571                 returns true if the mod was different last time
572         */
573         bool setTempMod(v3s16 p, const NodeMod &mod)
574         {
575                 /*dstream<<"setTempMod called on block"
576                                 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
577                                 <<", mod.type="<<mod.type
578                                 <<", mod.param="<<mod.param
579                                 <<std::endl;*/
580                 JMutexAutoLock lock(m_temp_mods_mutex);
581
582                 return m_temp_mods.set(p, mod);
583         }
584         // Returns true if there was one
585         bool getTempMod(v3s16 p, NodeMod *mod)
586         {
587                 JMutexAutoLock lock(m_temp_mods_mutex);
588
589                 return m_temp_mods.get(p, mod);
590         }
591         bool clearTempMod(v3s16 p)
592         {
593                 JMutexAutoLock lock(m_temp_mods_mutex);
594
595                 return m_temp_mods.clear(p);
596         }
597         bool clearTempMods()
598         {
599                 JMutexAutoLock lock(m_temp_mods_mutex);
600                 
601                 return m_temp_mods.clear();
602         }
603         void copyTempMods(NodeModMap &dst)
604         {
605                 JMutexAutoLock lock(m_temp_mods_mutex);
606                 m_temp_mods.copy(dst);
607         }
608 #endif
609
610         /*
611                 Update day-night lighting difference flag.
612                 
613                 Sets m_day_night_differs to appropriate value.
614                 
615                 These methods don't care about neighboring blocks.
616                 It means that to know if a block really doesn't need a mesh
617                 update between day and night, the neighboring blocks have
618                 to be taken into account. Use Map::dayNightDiffed().
619         */
620         void updateDayNightDiff();
621
622         bool dayNightDiffed()
623         {
624                 return m_day_night_differs;
625         }
626
627         /*
628                 Miscellaneous stuff
629         */
630         
631         /*
632                 Tries to measure ground level.
633                 Return value:
634                         -1 = only air
635                         -2 = only ground
636                         -3 = random fail
637                         0...MAP_BLOCKSIZE-1 = ground level
638         */
639         s16 getGroundLevel(v2s16 p2d);
640
641         /*
642                 Serialization
643         */
644         
645         // Doesn't write version by itself
646         void serialize(std::ostream &os, u8 version);
647
648         void deSerialize(std::istream &is, u8 version);
649
650 private:
651         /*
652                 Private methods
653         */
654
655         /*
656                 Used only internally, because changes can't be tracked
657         */
658
659         MapNode & getNodeRef(s16 x, s16 y, s16 z)
660         {
661                 if(data == NULL)
662                         throw InvalidPositionException();
663                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
664                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
665                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
666                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
667         }
668         MapNode & getNodeRef(v3s16 &p)
669         {
670                 return getNodeRef(p.X, p.Y, p.Z);
671         }
672
673 public:
674         /*
675                 Public member variables
676         */
677
678 #ifndef SERVER
679         scene::SMesh *mesh;
680         JMutex mesh_mutex;
681 #endif
682         
683         NodeMetadataList m_node_metadata;
684         
685 private:
686         /*
687                 Private member variables
688         */
689
690         // NOTE: Lots of things rely on this being the Map
691         NodeContainer *m_parent;
692         // Position in blocks on parent
693         v3s16 m_pos;
694         
695         /*
696                 If NULL, block is a dummy block.
697                 Dummy blocks are used for caching not-found-on-disk blocks.
698         */
699         MapNode * data;
700
701         /*
702                 - On the server, this is used for telling whether the
703                   block has been changed from the one on disk.
704                 - On the client, this is used for nothing.
705         */
706         bool changed;
707
708         /*
709                 When propagating sunlight and the above block doesn't exist,
710                 sunlight is assumed if this is false.
711
712                 In practice this is set to true if the block is completely
713                 undeground with nothing visible above the ground except
714                 caves.
715         */
716         bool is_underground;
717
718         /*
719                 Set to true if changes has been made that make the old lighting
720                 values wrong but the lighting hasn't been actually updated.
721
722                 If this is false, lighting is exactly right.
723                 If this is true, lighting might be wrong or right.
724         */
725         bool m_lighting_expired;
726         
727         // Whether day and night lighting differs
728         bool m_day_night_differs;
729         
730         MapBlockObjectList m_objects;
731
732         // Object spawning stuff
733         float m_spawn_timer;
734
735 #ifndef SERVER // Only on client
736         /*
737                 Set to true if the mesh has been ordered to be updated
738                 sometime in the background.
739                 In practice this is set when the day/night lighting switches.
740         */
741         bool m_mesh_expired;
742         
743         // Temporary modifications to nodes
744         // These are only used when drawing
745         NodeModMap m_temp_mods;
746         JMutex m_temp_mods_mutex;
747 #endif
748 };
749
750 inline bool blockpos_over_limit(v3s16 p)
751 {
752         return
753           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
754         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
755         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
756         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
757         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
758         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
759 }
760
761 /*
762         Returns the position of the block where the node is located
763 */
764 inline v3s16 getNodeBlockPos(v3s16 p)
765 {
766         return getContainerPos(p, MAP_BLOCKSIZE);
767 }
768
769 inline v2s16 getNodeSectorPos(v2s16 p)
770 {
771         return getContainerPos(p, MAP_BLOCKSIZE);
772 }
773
774 inline s16 getNodeBlockY(s16 y)
775 {
776         return getContainerPos(y, MAP_BLOCKSIZE);
777 }
778
779 #endif
780