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