Replace std::list by std::vector into ClientMap::updateDrawList, Map::timerUpdate...
[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         void raiseModified(u32 mod, const char *reason)
170         {
171                 if (mod > m_modified){
172                         m_modified = mod;
173                         m_modified_reason = reason;
174                         m_modified_reason_too_long = false;
175
176                         if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
177                                 m_disk_timestamp = m_timestamp;
178                         }
179                 }
180                 else if (mod == m_modified){
181                         if (!m_modified_reason_too_long){
182                                 if (m_modified_reason.size() < 40)
183                                         m_modified_reason += ", " + std::string(reason);
184                                 else{
185                                         m_modified_reason += "...";
186                                         m_modified_reason_too_long = true;
187                                 }
188                         }
189                 }
190         }
191
192         u32 getModified()
193         {
194                 return m_modified;
195         }
196         std::string getModifiedReason()
197         {
198                 return m_modified_reason;
199         }
200         void resetModified()
201         {
202                 m_modified = MOD_STATE_CLEAN;
203                 m_modified_reason = "none";
204                 m_modified_reason_too_long = false;
205         }
206         
207         // is_underground getter/setter
208         bool getIsUnderground()
209         {
210                 return is_underground;
211         }
212         void setIsUnderground(bool a_is_underground)
213         {
214                 is_underground = a_is_underground;
215                 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
216         }
217
218         void setLightingExpired(bool expired)
219         {
220                 if(expired != m_lighting_expired){
221                         m_lighting_expired = expired;
222                         raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
223                 }
224         }
225         bool getLightingExpired()
226         {
227                 return m_lighting_expired;
228         }
229
230         bool isGenerated()
231         {
232                 return m_generated;
233         }
234         void setGenerated(bool b)
235         {
236                 if(b != m_generated){
237                         raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
238                         m_generated = b;
239                 }
240         }
241
242         bool isValid()
243         {
244                 if(m_lighting_expired)
245                         return false;
246                 if(data == NULL)
247                         return false;
248                 return true;
249         }
250
251         /*
252                 Position stuff
253         */
254
255         v3s16 getPos()
256         {
257                 return m_pos;
258         }
259                 
260         v3s16 getPosRelative()
261         {
262                 return m_pos * MAP_BLOCKSIZE;
263         }
264                 
265         core::aabbox3d<s16> getBox()
266         {
267                 return core::aabbox3d<s16>(getPosRelative(),
268                                 getPosRelative()
269                                 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
270                                 - v3s16(1,1,1));
271         }
272
273         /*
274                 Regular MapNode get-setters
275         */
276         
277         bool isValidPosition(s16 x, s16 y, s16 z)
278         {
279                 return data != NULL
280                                 && x >= 0 && x < MAP_BLOCKSIZE
281                                 && y >= 0 && y < MAP_BLOCKSIZE
282                                 && z >= 0 && z < MAP_BLOCKSIZE;
283         }
284
285         bool isValidPosition(v3s16 p)
286         {
287                 return isValidPosition(p.X, p.Y, p.Z);
288         }
289
290         MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
291         {
292                 *valid_position = isValidPosition(x, y, z);
293
294                 if (!*valid_position)
295                         return MapNode(CONTENT_IGNORE);
296
297                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
298         }
299         
300         MapNode getNode(v3s16 p, bool *valid_position)
301         {
302                 return getNode(p.X, p.Y, p.Z, valid_position);
303         }
304         
305         MapNode getNodeNoEx(v3s16 p)
306         {
307                 bool is_valid;
308                 MapNode node = getNode(p.X, p.Y, p.Z, &is_valid);
309                 return is_valid ? node : MapNode(CONTENT_IGNORE);
310         }
311         
312         void setNode(s16 x, s16 y, s16 z, MapNode & n)
313         {
314                 if(data == NULL)
315                         throw InvalidPositionException();
316                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
317                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
318                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
319                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
320                 raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
321         }
322         
323         void setNode(v3s16 p, MapNode & n)
324         {
325                 setNode(p.X, p.Y, p.Z, n);
326         }
327
328         /*
329                 Non-checking variants of the above
330         */
331
332         MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
333         {
334                 *valid_position = data != NULL;
335                 if(!valid_position)
336                         return MapNode(CONTENT_IGNORE);
337
338                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
339         }
340         
341         MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
342         {
343                 return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
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, "setNodeNoCheck");
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, bool *is_valid_position = NULL);
365         void setNodeParent(v3s16 p, MapNode & n);
366
367         void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
368         {
369                 for(u16 z=0; z<d; z++)
370                         for(u16 y=0; y<h; y++)
371                                 for(u16 x=0; x<w; x++)
372                                         setNode(x0+x, y0+y, z0+z, node);
373         }
374
375         // See comments in mapblock.cpp
376         bool propagateSunlight(std::set<v3s16> & light_sources,
377                         bool remove_light=false, bool *black_air_left=NULL);
378         
379         // Copies data to VoxelManipulator to getPosRelative()
380         void copyTo(VoxelManipulator &dst);
381         // Copies data from VoxelManipulator getPosRelative()
382         void copyFrom(VoxelManipulator &dst);
383
384         /*
385                 Update day-night lighting difference flag.
386                 Sets m_day_night_differs to appropriate value.
387                 These methods don't care about neighboring blocks.
388         */
389         void actuallyUpdateDayNightDiff();
390         /*
391                 Call this to schedule what the previous function does to be done
392                 when the value is actually needed.
393         */
394         void expireDayNightDiff();
395
396         bool getDayNightDiff()
397         {
398                 if(m_day_night_differs_expired)
399                         actuallyUpdateDayNightDiff();
400                 return m_day_night_differs;
401         }
402
403         /*
404                 Miscellaneous stuff
405         */
406         
407         /*
408                 Tries to measure ground level.
409                 Return value:
410                         -1 = only air
411                         -2 = only ground
412                         -3 = random fail
413                         0...MAP_BLOCKSIZE-1 = ground level
414         */
415         s16 getGroundLevel(v2s16 p2d);
416
417         /*
418                 Timestamp (see m_timestamp)
419                 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
420         */
421         void setTimestamp(u32 time)
422         {
423                 m_timestamp = time;
424                 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
425         }
426         void setTimestampNoChangedFlag(u32 time)
427         {
428                 m_timestamp = time;
429         }
430         u32 getTimestamp()
431         {
432                 return m_timestamp;
433         }
434         u32 getDiskTimestamp()
435         {
436                 return m_disk_timestamp;
437         }
438         
439         /*
440                 See m_usage_timer
441         */
442         void resetUsageTimer()
443         {
444                 m_usage_timer = 0;
445         }
446         void incrementUsageTimer(float dtime)
447         {
448                 m_usage_timer += dtime;
449         }
450         float getUsageTimer()
451         {
452                 return m_usage_timer;
453         }
454
455         /*
456                 See m_refcount
457         */
458         void refGrab()
459         {
460                 m_refcount++;
461         }
462         void refDrop()
463         {
464                 m_refcount--;
465         }
466         int refGet()
467         {
468                 return m_refcount;
469         }
470         
471         /*
472                 Node Timers
473         */
474         // Get timer
475         NodeTimer getNodeTimer(v3s16 p){ 
476                 return m_node_timers.get(p);
477         }
478         // Deletes timer
479         void removeNodeTimer(v3s16 p){
480                 m_node_timers.remove(p);
481         }
482         // Deletes old timer and sets a new one
483         void setNodeTimer(v3s16 p, NodeTimer t){
484                 m_node_timers.set(p,t);
485         }
486         // Deletes all timers
487         void clearNodeTimers(){
488                 m_node_timers.clear();
489         }
490
491         /*
492                 Serialization
493         */
494         
495         // These don't write or read version by itself
496         // Set disk to true for on-disk format, false for over-the-network format
497         // Precondition: version >= SER_FMT_CLIENT_VER_LOWEST
498         void serialize(std::ostream &os, u8 version, bool disk);
499         // If disk == true: In addition to doing other things, will add
500         // unknown blocks from id-name mapping to wndef
501         void deSerialize(std::istream &is, u8 version, bool disk);
502
503         void serializeNetworkSpecific(std::ostream &os, u16 net_proto_version);
504         void deSerializeNetworkSpecific(std::istream &is);
505
506 private:
507         /*
508                 Private methods
509         */
510
511         void deSerialize_pre22(std::istream &is, u8 version, bool disk);
512
513         /*
514                 Used only internally, because changes can't be tracked
515         */
516
517         MapNode & getNodeRef(s16 x, s16 y, s16 z)
518         {
519                 if(data == NULL)
520                         throw InvalidPositionException();
521                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
522                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
523                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
524                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
525         }
526         MapNode & getNodeRef(v3s16 &p)
527         {
528                 return getNodeRef(p.X, p.Y, p.Z);
529         }
530
531 public:
532         /*
533                 Public member variables
534         */
535
536 #ifndef SERVER // Only on client
537         MapBlockMesh *mesh;
538 #endif
539         
540         NodeMetadataList m_node_metadata;
541         NodeTimerList m_node_timers;
542         StaticObjectList m_static_objects;
543
544 private:
545         /*
546                 Private member variables
547         */
548
549         // NOTE: Lots of things rely on this being the Map
550         Map *m_parent;
551         // Position in blocks on parent
552         v3s16 m_pos;
553
554         IGameDef *m_gamedef;
555         
556         /*
557                 If NULL, block is a dummy block.
558                 Dummy blocks are used for caching not-found-on-disk blocks.
559         */
560         MapNode * data;
561
562         /*
563                 - On the server, this is used for telling whether the
564                   block has been modified from the one on disk.
565                 - On the client, this is used for nothing.
566         */
567         u32 m_modified;
568         std::string m_modified_reason;
569         bool m_modified_reason_too_long;
570
571         /*
572                 When propagating sunlight and the above block doesn't exist,
573                 sunlight is assumed if this is false.
574
575                 In practice this is set to true if the block is completely
576                 undeground with nothing visible above the ground except
577                 caves.
578         */
579         bool is_underground;
580
581         /*
582                 Set to true if changes has been made that make the old lighting
583                 values wrong but the lighting hasn't been actually updated.
584
585                 If this is false, lighting is exactly right.
586                 If this is true, lighting might be wrong or right.
587         */
588         bool m_lighting_expired;
589         
590         // Whether day and night lighting differs
591         bool m_day_night_differs;
592         bool m_day_night_differs_expired;
593
594         bool m_generated;
595         
596         /*
597                 When block is removed from active blocks, this is set to gametime.
598                 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
599         */
600         u32 m_timestamp;
601         // The on-disk (or to-be on-disk) timestamp value
602         u32 m_disk_timestamp;
603
604         /*
605                 When the block is accessed, this is set to 0.
606                 Map will unload the block when this reaches a timeout.
607         */
608         float m_usage_timer;
609
610         /*
611                 Reference count; currently used for determining if this block is in
612                 the list of blocks to be drawn.
613         */
614         int m_refcount;
615 };
616
617 typedef std::vector<MapBlock*> MapBlockVect;
618
619 inline bool blockpos_over_limit(v3s16 p)
620 {
621         return
622           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
623         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
624         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
625         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
626         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
627         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
628 }
629
630 /*
631         Returns the position of the block where the node is located
632 */
633 inline v3s16 getNodeBlockPos(v3s16 p)
634 {
635         return getContainerPos(p, MAP_BLOCKSIZE);
636 }
637
638 inline v2s16 getNodeSectorPos(v2s16 p)
639 {
640         return getContainerPos(p, MAP_BLOCKSIZE);
641 }
642
643 inline s16 getNodeBlockY(s16 y)
644 {
645         return getContainerPos(y, MAP_BLOCKSIZE);
646 }
647
648 inline void getNodeBlockPosWithOffset(const v3s16 &p, v3s16 &block, v3s16 &offset)
649 {
650         getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
651 }
652
653 inline void getNodeSectorPosWithOffset(const v2s16 &p, v2s16 &block, v2s16 &offset)
654 {
655         getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
656 }
657
658 /*
659         Get a quick string to describe what a block actually contains
660 */
661 std::string analyze_block(MapBlock *block);
662
663 #endif
664