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