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