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