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