Weather backward compatibility
[oweals/minetest.git] / src / mapblock.h
1 /*
2 Minetest
3 Copyright (C) 2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 <set>
27 #include "debug.h"
28 #include "irrlichttypes.h"
29 #include "irr_v3d.h"
30 #include "irr_aabb3d.h"
31 #include "mapnode.h"
32 #include "exceptions.h"
33 #include "serialization.h"
34 #include "constants.h"
35 #include "voxel.h"
36 #include "staticobject.h"
37 #include "nodemetadata.h"
38 #include "nodetimer.h"
39 #include "modifiedstate.h"
40 #include "util/numeric.h" // getContainerPos
41
42 class Map;
43 class NodeMetadataList;
44 class IGameDef;
45 class MapBlockMesh;
46
47 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
48
49 /*// Named by looking towards z+
50 enum{
51         FACE_BACK=0,
52         FACE_TOP,
53         FACE_RIGHT,
54         FACE_FRONT,
55         FACE_BOTTOM,
56         FACE_LEFT
57 };*/
58
59 // NOTE: If this is enabled, set MapBlock to be initialized with
60 //       CONTENT_IGNORE.
61 /*enum BlockGenerationStatus
62 {
63         // Completely non-generated (filled with CONTENT_IGNORE).
64         BLOCKGEN_UNTOUCHED=0,
65         // Trees or similar might have been blitted from other blocks to here.
66         // Otherwise, the block contains CONTENT_IGNORE
67         BLOCKGEN_FROM_NEIGHBORS=2,
68         // Has been generated, but some neighbors might put some stuff in here
69         // when they are generated.
70         // Does not contain any CONTENT_IGNORE
71         BLOCKGEN_SELF_GENERATED=4,
72         // The block and all its neighbors have been generated
73         BLOCKGEN_FULLY_GENERATED=6
74 };*/
75
76 #if 0
77 enum
78 {
79         NODECONTAINER_ID_MAPBLOCK,
80         NODECONTAINER_ID_MAPSECTOR,
81         NODECONTAINER_ID_MAP,
82         NODECONTAINER_ID_MAPBLOCKCACHE,
83         NODECONTAINER_ID_VOXELMANIPULATOR,
84 };
85
86 class NodeContainer
87 {
88 public:
89         virtual bool isValidPosition(v3s16 p) = 0;
90         virtual MapNode getNode(v3s16 p) = 0;
91         virtual void setNode(v3s16 p, MapNode & n) = 0;
92         virtual u16 nodeContainerId() const = 0;
93
94         MapNode getNodeNoEx(v3s16 p)
95         {
96                 try{
97                         return getNode(p);
98                 }
99                 catch(InvalidPositionException &e){
100                         return MapNode(CONTENT_IGNORE);
101                 }
102         }
103 };
104 #endif
105
106 /*
107         MapBlock itself
108 */
109
110 class MapBlock /*: public NodeContainer*/
111 {
112 public:
113         MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
114         ~MapBlock();
115         
116         /*virtual u16 nodeContainerId() const
117         {
118                 return NODECONTAINER_ID_MAPBLOCK;
119         }*/
120         
121         Map * getParent()
122         {
123                 return m_parent;
124         }
125
126         void reallocate()
127         {
128                 if(data != NULL)
129                         delete[] data;
130                 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
131                 data = new MapNode[l];
132                 for(u32 i=0; i<l; i++){
133                         //data[i] = MapNode();
134                         data[i] = MapNode(CONTENT_IGNORE);
135                 }
136                 raiseModified(MOD_STATE_WRITE_NEEDED, "reallocate");
137         }
138
139         /*
140                 Flags
141         */
142
143         bool isDummy()
144         {
145                 return (data == NULL);
146         }
147         void unDummify()
148         {
149                 assert(isDummy());
150                 reallocate();
151         }
152         
153         // m_modified methods
154         void raiseModified(u32 mod, const std::string &reason="unknown")
155         {
156                 if(mod > m_modified){
157                         m_modified = mod;
158                         m_modified_reason = reason;
159                         m_modified_reason_too_long = false;
160
161                         if(m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
162                                 m_disk_timestamp = m_timestamp;
163                         }
164                 } else if(mod == m_modified){
165                         if(!m_modified_reason_too_long){
166                                 if(m_modified_reason.size() < 40)
167                                         m_modified_reason += ", " + reason;
168                                 else{
169                                         m_modified_reason += "...";
170                                         m_modified_reason_too_long = true;
171                                 }
172                         }
173                 }
174         }
175         u32 getModified()
176         {
177                 return m_modified;
178         }
179         std::string getModifiedReason()
180         {
181                 return m_modified_reason;
182         }
183         void resetModified()
184         {
185                 m_modified = MOD_STATE_CLEAN;
186                 m_modified_reason = "none";
187                 m_modified_reason_too_long = false;
188         }
189         
190         // is_underground getter/setter
191         bool getIsUnderground()
192         {
193                 return is_underground;
194         }
195         void setIsUnderground(bool a_is_underground)
196         {
197                 is_underground = a_is_underground;
198                 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
199         }
200
201         void setLightingExpired(bool expired)
202         {
203                 if(expired != m_lighting_expired){
204                         m_lighting_expired = expired;
205                         raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
206                 }
207         }
208         bool getLightingExpired()
209         {
210                 return m_lighting_expired;
211         }
212
213         bool isGenerated()
214         {
215                 return m_generated;
216         }
217         void setGenerated(bool b)
218         {
219                 if(b != m_generated){
220                         raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
221                         m_generated = b;
222                 }
223         }
224
225         bool isValid()
226         {
227                 if(m_lighting_expired)
228                         return false;
229                 if(data == NULL)
230                         return false;
231                 return true;
232         }
233
234         /*
235                 Position stuff
236         */
237
238         v3s16 getPos()
239         {
240                 return m_pos;
241         }
242                 
243         v3s16 getPosRelative()
244         {
245                 return m_pos * MAP_BLOCKSIZE;
246         }
247                 
248         core::aabbox3d<s16> getBox()
249         {
250                 return core::aabbox3d<s16>(getPosRelative(),
251                                 getPosRelative()
252                                 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
253                                 - v3s16(1,1,1));
254         }
255
256         /*
257                 Regular MapNode get-setters
258         */
259         
260         bool isValidPosition(v3s16 p)
261         {
262                 if(data == NULL)
263                         return false;
264                 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
265                                 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
266                                 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
267         }
268
269         MapNode getNode(s16 x, s16 y, s16 z)
270         {
271                 if(data == NULL)
272                         throw InvalidPositionException();
273                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
274                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
275                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
276                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
277         }
278         
279         MapNode getNode(v3s16 p)
280         {
281                 return getNode(p.X, p.Y, p.Z);
282         }
283         
284         MapNode getNodeNoEx(v3s16 p)
285         {
286                 try{
287                         return getNode(p.X, p.Y, p.Z);
288                 }catch(InvalidPositionException &e){
289                         return MapNode(CONTENT_IGNORE);
290                 }
291         }
292         
293         void setNode(s16 x, s16 y, s16 z, MapNode & n)
294         {
295                 if(data == NULL)
296                         throw InvalidPositionException();
297                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
298                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
299                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
300                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
301                 raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
302         }
303         
304         void setNode(v3s16 p, MapNode & n)
305         {
306                 setNode(p.X, p.Y, p.Z, n);
307         }
308
309         /*
310                 Non-checking variants of the above
311         */
312
313         MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
314         {
315                 if(data == NULL)
316                         throw InvalidPositionException();
317                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
318         }
319         
320         MapNode getNodeNoCheck(v3s16 p)
321         {
322                 return getNodeNoCheck(p.X, p.Y, p.Z);
323         }
324         
325         void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
326         {
327                 if(data == NULL)
328                         throw InvalidPositionException();
329                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
330                 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
331         }
332         
333         void setNodeNoCheck(v3s16 p, MapNode & n)
334         {
335                 setNodeNoCheck(p.X, p.Y, p.Z, n);
336         }
337
338         /*
339                 These functions consult the parent container if the position
340                 is not valid on this MapBlock.
341         */
342         bool isValidPositionParent(v3s16 p);
343         MapNode getNodeParent(v3s16 p);
344         void setNodeParent(v3s16 p, MapNode & n);
345         MapNode getNodeParentNoEx(v3s16 p);
346
347         void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
348         {
349                 for(u16 z=0; z<d; z++)
350                         for(u16 y=0; y<h; y++)
351                                 for(u16 x=0; x<w; x++)
352                                         setNode(x0+x, y0+y, z0+z, node);
353         }
354
355         // See comments in mapblock.cpp
356         bool propagateSunlight(std::set<v3s16> & 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                 Update day-night lighting difference flag.
366                 Sets m_day_night_differs to appropriate value.
367                 These methods don't care about neighboring blocks.
368         */
369         void actuallyUpdateDayNightDiff();
370         /*
371                 Call this to schedule what the previous function does to be done
372                 when the value is actually needed.
373         */
374         void expireDayNightDiff();
375
376         bool getDayNightDiff()
377         {
378                 if(m_day_night_differs_expired)
379                         actuallyUpdateDayNightDiff();
380                 return m_day_night_differs;
381         }
382
383         /*
384                 Miscellaneous stuff
385         */
386         
387         /*
388                 Tries to measure ground level.
389                 Return value:
390                         -1 = only air
391                         -2 = only ground
392                         -3 = random fail
393                         0...MAP_BLOCKSIZE-1 = ground level
394         */
395         s16 getGroundLevel(v2s16 p2d);
396
397         /*
398                 Timestamp (see m_timestamp)
399                 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
400         */
401         void setTimestamp(u32 time)
402         {
403                 m_timestamp = time;
404                 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
405         }
406         void setTimestampNoChangedFlag(u32 time)
407         {
408                 m_timestamp = time;
409         }
410         u32 getTimestamp()
411         {
412                 return m_timestamp;
413         }
414         u32 getDiskTimestamp()
415         {
416                 return m_disk_timestamp;
417         }
418         
419         /*
420                 See m_usage_timer
421         */
422         void resetUsageTimer()
423         {
424                 m_usage_timer = 0;
425         }
426         void incrementUsageTimer(float dtime)
427         {
428                 m_usage_timer += dtime;
429         }
430         u32 getUsageTimer()
431         {
432                 return m_usage_timer;
433         }
434
435         /*
436                 See m_refcount
437         */
438         void refGrab()
439         {
440                 m_refcount++;
441         }
442         void refDrop()
443         {
444                 m_refcount--;
445         }
446         int refGet()
447         {
448                 return m_refcount;
449         }
450         
451         /*
452                 Node Timers
453         */
454         // Get timer
455         NodeTimer getNodeTimer(v3s16 p){ 
456                 return m_node_timers.get(p);
457         }
458         // Deletes timer
459         void removeNodeTimer(v3s16 p){
460                 m_node_timers.remove(p);
461         }
462         // Deletes old timer and sets a new one
463         void setNodeTimer(v3s16 p, NodeTimer t){
464                 m_node_timers.set(p,t);
465         }
466         // Deletes all timers
467         void clearNodeTimers(){
468                 m_node_timers.clear();
469         }
470
471         /*
472                 Serialization
473         */
474         
475         // These don't write or read version by itself
476         // Set disk to true for on-disk format, false for over-the-network format
477         void serialize(std::ostream &os, u8 version, bool disk);
478         // If disk == true: In addition to doing other things, will add
479         // unknown blocks from id-name mapping to wndef
480         void deSerialize(std::istream &is, u8 version, bool disk);
481
482         void serializeNetworkSpecific(std::ostream &os, u16 net_proto_version);
483         void deSerializeNetworkSpecific(std::istream &is);
484
485 private:
486         /*
487                 Private methods
488         */
489
490         void deSerialize_pre22(std::istream &is, u8 version, bool disk);
491
492         /*
493                 Used only internally, because changes can't be tracked
494         */
495
496         MapNode & getNodeRef(s16 x, s16 y, s16 z)
497         {
498                 if(data == NULL)
499                         throw InvalidPositionException();
500                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
501                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
502                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
503                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
504         }
505         MapNode & getNodeRef(v3s16 &p)
506         {
507                 return getNodeRef(p.X, p.Y, p.Z);
508         }
509
510 public:
511         /*
512                 Public member variables
513         */
514
515 #ifndef SERVER // Only on client
516         MapBlockMesh *mesh;
517         //JMutex mesh_mutex;
518 #endif
519         
520         NodeMetadataList m_node_metadata;
521         NodeTimerList m_node_timers;
522         StaticObjectList m_static_objects;
523         
524         s16 heat;
525         u32 heat_time;
526         s16 humidity;
527         u32 humidity_time;
528
529 private:
530         /*
531                 Private member variables
532         */
533
534         // NOTE: Lots of things rely on this being the Map
535         Map *m_parent;
536         // Position in blocks on parent
537         v3s16 m_pos;
538
539         IGameDef *m_gamedef;
540         
541         /*
542                 If NULL, block is a dummy block.
543                 Dummy blocks are used for caching not-found-on-disk blocks.
544         */
545         MapNode * data;
546
547         /*
548                 - On the server, this is used for telling whether the
549                   block has been modified from the one on disk.
550                 - On the client, this is used for nothing.
551         */
552         u32 m_modified;
553         std::string m_modified_reason;
554         bool m_modified_reason_too_long;
555
556         /*
557                 When propagating sunlight and the above block doesn't exist,
558                 sunlight is assumed if this is false.
559
560                 In practice this is set to true if the block is completely
561                 undeground with nothing visible above the ground except
562                 caves.
563         */
564         bool is_underground;
565
566         /*
567                 Set to true if changes has been made that make the old lighting
568                 values wrong but the lighting hasn't been actually updated.
569
570                 If this is false, lighting is exactly right.
571                 If this is true, lighting might be wrong or right.
572         */
573         bool m_lighting_expired;
574         
575         // Whether day and night lighting differs
576         bool m_day_night_differs;
577         bool m_day_night_differs_expired;
578
579         bool m_generated;
580         
581         /*
582                 When block is removed from active blocks, this is set to gametime.
583                 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
584         */
585         u32 m_timestamp;
586         // The on-disk (or to-be on-disk) timestamp value
587         u32 m_disk_timestamp;
588
589         /*
590                 When the block is accessed, this is set to 0.
591                 Map will unload the block when this reaches a timeout.
592         */
593         float m_usage_timer;
594
595         /*
596                 Reference count; currently used for determining if this block is in
597                 the list of blocks to be drawn.
598         */
599         int m_refcount;
600 };
601
602 inline bool blockpos_over_limit(v3s16 p)
603 {
604         return
605           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
606         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
607         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
608         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
609         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
610         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
611 }
612
613 /*
614         Returns the position of the block where the node is located
615 */
616 inline v3s16 getNodeBlockPos(v3s16 p)
617 {
618         return getContainerPos(p, MAP_BLOCKSIZE);
619 }
620
621 inline v2s16 getNodeSectorPos(v2s16 p)
622 {
623         return getContainerPos(p, MAP_BLOCKSIZE);
624 }
625
626 inline s16 getNodeBlockY(s16 y)
627 {
628         return getContainerPos(y, MAP_BLOCKSIZE);
629 }
630
631 /*
632         Get a quick string to describe what a block actually contains
633 */
634 std::string analyze_block(MapBlock *block);
635
636 #endif
637