3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
20 #ifndef MAPBLOCK_HEADER
21 #define MAPBLOCK_HEADER
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
36 class NodeMetadataList;
39 class VoxelManipulator;
41 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
43 /*// Named by looking towards z+
53 // NOTE: If this is enabled, set MapBlock to be initialized with
55 /*enum BlockGenerationStatus
57 // Completely non-generated (filled with CONTENT_IGNORE).
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
73 NODECONTAINER_ID_MAPBLOCK,
74 NODECONTAINER_ID_MAPSECTOR,
76 NODECONTAINER_ID_MAPBLOCKCACHE,
77 NODECONTAINER_ID_VOXELMANIPULATOR,
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;
88 MapNode getNodeNoEx(v3s16 p)
93 catch(InvalidPositionException &e){
94 return MapNode(CONTENT_IGNORE);
104 class MapBlock /*: public NodeContainer*/
107 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
110 /*virtual u16 nodeContainerId() const
112 return NODECONTAINER_ID_MAPBLOCK;
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);
130 raiseModified(MOD_STATE_WRITE_NEEDED, "reallocate");
139 return (data == NULL);
147 // m_modified methods
148 void raiseModified(u32 mod, const std::string &reason="unknown")
150 if(mod > m_modified){
152 m_modified_reason = reason;
153 m_modified_reason_too_long = false;
155 if(m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
156 m_disk_timestamp = m_timestamp;
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;
163 m_modified_reason += "...";
164 m_modified_reason_too_long = true;
169 void raiseModified(u32 mod, const char *reason)
171 if (mod > m_modified){
173 m_modified_reason = reason;
174 m_modified_reason_too_long = false;
176 if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
177 m_disk_timestamp = m_timestamp;
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);
185 m_modified_reason += "...";
186 m_modified_reason_too_long = true;
196 std::string getModifiedReason()
198 return m_modified_reason;
202 m_modified = MOD_STATE_CLEAN;
203 m_modified_reason = "none";
204 m_modified_reason_too_long = false;
207 // is_underground getter/setter
208 bool getIsUnderground()
210 return is_underground;
212 void setIsUnderground(bool a_is_underground)
214 is_underground = a_is_underground;
215 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
218 void setLightingExpired(bool expired)
220 if(expired != m_lighting_expired){
221 m_lighting_expired = expired;
222 raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
225 bool getLightingExpired()
227 return m_lighting_expired;
234 void setGenerated(bool b)
236 if(b != m_generated){
237 raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
244 if(m_lighting_expired)
260 v3s16 getPosRelative()
262 return m_pos * MAP_BLOCKSIZE;
265 core::aabbox3d<s16> getBox()
267 return core::aabbox3d<s16>(getPosRelative(),
269 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
274 Regular MapNode get-setters
277 bool isValidPosition(s16 x, s16 y, s16 z)
280 && x >= 0 && x < MAP_BLOCKSIZE
281 && y >= 0 && y < MAP_BLOCKSIZE
282 && z >= 0 && z < MAP_BLOCKSIZE;
285 bool isValidPosition(v3s16 p)
287 return isValidPosition(p.X, p.Y, p.Z);
290 MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
292 *valid_position = isValidPosition(x, y, z);
294 if (!*valid_position)
295 return MapNode(CONTENT_IGNORE);
297 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
300 MapNode getNode(v3s16 p, bool *valid_position)
302 return getNode(p.X, p.Y, p.Z, valid_position);
305 MapNode getNodeNoEx(v3s16 p)
308 MapNode node = getNode(p.X, p.Y, p.Z, &is_valid);
309 return is_valid ? node : MapNode(CONTENT_IGNORE);
312 void setNode(s16 x, s16 y, s16 z, MapNode & n)
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");
323 void setNode(v3s16 p, MapNode & n)
325 setNode(p.X, p.Y, p.Z, n);
329 Non-checking variants of the above
332 MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
334 *valid_position = data != NULL;
336 return MapNode(CONTENT_IGNORE);
338 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
341 MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
343 return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
346 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
349 throw InvalidPositionException();
350 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
351 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
354 void setNodeNoCheck(v3s16 p, MapNode & n)
356 setNodeNoCheck(p.X, p.Y, p.Z, n);
360 These functions consult the parent container if the position
361 is not valid on this MapBlock.
363 bool isValidPositionParent(v3s16 p);
364 MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
365 void setNodeParent(v3s16 p, MapNode & n);
367 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
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);
375 // See comments in mapblock.cpp
376 bool propagateSunlight(std::set<v3s16> & light_sources,
377 bool remove_light=false, bool *black_air_left=NULL);
379 // Copies data to VoxelManipulator to getPosRelative()
380 void copyTo(VoxelManipulator &dst);
381 // Copies data from VoxelManipulator getPosRelative()
382 void copyFrom(VoxelManipulator &dst);
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.
389 void actuallyUpdateDayNightDiff();
391 Call this to schedule what the previous function does to be done
392 when the value is actually needed.
394 void expireDayNightDiff();
396 bool getDayNightDiff()
398 if(m_day_night_differs_expired)
399 actuallyUpdateDayNightDiff();
400 return m_day_night_differs;
408 Tries to measure ground level.
413 0...MAP_BLOCKSIZE-1 = ground level
415 s16 getGroundLevel(v2s16 p2d);
418 Timestamp (see m_timestamp)
419 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
421 void setTimestamp(u32 time)
424 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
426 void setTimestampNoChangedFlag(u32 time)
434 u32 getDiskTimestamp()
436 return m_disk_timestamp;
442 void resetUsageTimer()
446 void incrementUsageTimer(float dtime)
448 m_usage_timer += dtime;
450 float getUsageTimer()
452 return m_usage_timer;
475 NodeTimer getNodeTimer(v3s16 p){
476 return m_node_timers.get(p);
479 void removeNodeTimer(v3s16 p){
480 m_node_timers.remove(p);
482 // Deletes old timer and sets a new one
483 void setNodeTimer(v3s16 p, NodeTimer t){
484 m_node_timers.set(p,t);
486 // Deletes all timers
487 void clearNodeTimers(){
488 m_node_timers.clear();
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);
503 void serializeNetworkSpecific(std::ostream &os, u16 net_proto_version);
504 void deSerializeNetworkSpecific(std::istream &is);
511 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
514 Used only internally, because changes can't be tracked
517 MapNode & getNodeRef(s16 x, s16 y, s16 z)
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];
526 MapNode & getNodeRef(v3s16 &p)
528 return getNodeRef(p.X, p.Y, p.Z);
533 Public member variables
536 #ifndef SERVER // Only on client
540 NodeMetadataList m_node_metadata;
541 NodeTimerList m_node_timers;
542 StaticObjectList m_static_objects;
546 Private member variables
549 // NOTE: Lots of things rely on this being the Map
551 // Position in blocks on parent
557 If NULL, block is a dummy block.
558 Dummy blocks are used for caching not-found-on-disk blocks.
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.
568 std::string m_modified_reason;
569 bool m_modified_reason_too_long;
572 When propagating sunlight and the above block doesn't exist,
573 sunlight is assumed if this is false.
575 In practice this is set to true if the block is completely
576 undeground with nothing visible above the ground except
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.
585 If this is false, lighting is exactly right.
586 If this is true, lighting might be wrong or right.
588 bool m_lighting_expired;
590 // Whether day and night lighting differs
591 bool m_day_night_differs;
592 bool m_day_night_differs_expired;
597 When block is removed from active blocks, this is set to gametime.
598 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
601 // The on-disk (or to-be on-disk) timestamp value
602 u32 m_disk_timestamp;
605 When the block is accessed, this is set to 0.
606 Map will unload the block when this reaches a timeout.
611 Reference count; currently used for determining if this block is in
612 the list of blocks to be drawn.
617 typedef std::vector<MapBlock*> MapBlockVect;
619 inline bool blockpos_over_limit(v3s16 p)
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);
631 Returns the position of the block where the node is located
633 inline v3s16 getNodeBlockPos(v3s16 p)
635 return getContainerPos(p, MAP_BLOCKSIZE);
638 inline v2s16 getNodeSectorPos(v2s16 p)
640 return getContainerPos(p, MAP_BLOCKSIZE);
643 inline s16 getNodeBlockY(s16 y)
645 return getContainerPos(y, MAP_BLOCKSIZE);
648 inline void getNodeBlockPosWithOffset(const v3s16 &p, v3s16 &block, v3s16 &offset)
650 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
653 inline void getNodeSectorPosWithOffset(const v2s16 &p, v2s16 &block, v2s16 &offset)
655 getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
659 Get a quick string to describe what a block actually contains
661 std::string analyze_block(MapBlock *block);