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