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;
173 std::string getModifiedReason()
175 return m_modified_reason;
179 m_modified = MOD_STATE_CLEAN;
180 m_modified_reason = "none";
181 m_modified_reason_too_long = false;
184 // is_underground getter/setter
185 bool getIsUnderground()
187 return is_underground;
189 void setIsUnderground(bool a_is_underground)
191 is_underground = a_is_underground;
192 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
195 void setLightingExpired(bool expired)
197 if(expired != m_lighting_expired){
198 m_lighting_expired = expired;
199 raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
202 bool getLightingExpired()
204 return m_lighting_expired;
211 void setGenerated(bool b)
213 if(b != m_generated){
214 raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
221 if(m_lighting_expired)
237 v3s16 getPosRelative()
239 return m_pos * MAP_BLOCKSIZE;
242 core::aabbox3d<s16> getBox()
244 return core::aabbox3d<s16>(getPosRelative(),
246 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
251 Regular MapNode get-setters
254 bool isValidPosition(s16 x, s16 y, s16 z)
257 && x >= 0 && x < MAP_BLOCKSIZE
258 && y >= 0 && y < MAP_BLOCKSIZE
259 && z >= 0 && z < MAP_BLOCKSIZE;
262 bool isValidPosition(v3s16 p)
264 return isValidPosition(p.X, p.Y, p.Z);
267 MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
269 *valid_position = isValidPosition(x, y, z);
271 if (!*valid_position)
272 return MapNode(CONTENT_IGNORE);
274 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
277 MapNode getNode(v3s16 p, bool *valid_position)
279 return getNode(p.X, p.Y, p.Z, valid_position);
282 MapNode getNodeNoEx(v3s16 p)
285 MapNode node = getNode(p.X, p.Y, p.Z, &is_valid);
286 return is_valid ? node : MapNode(CONTENT_IGNORE);
289 void setNode(s16 x, s16 y, s16 z, MapNode & n)
292 throw InvalidPositionException();
293 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
294 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
295 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
296 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
297 raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
300 void setNode(v3s16 p, MapNode & n)
302 setNode(p.X, p.Y, p.Z, n);
306 Non-checking variants of the above
309 MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
311 *valid_position = data != NULL;
313 return MapNode(CONTENT_IGNORE);
315 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
318 MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
320 return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
323 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
326 throw InvalidPositionException();
327 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
328 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
331 void setNodeNoCheck(v3s16 p, MapNode & n)
333 setNodeNoCheck(p.X, p.Y, p.Z, n);
337 These functions consult the parent container if the position
338 is not valid on this MapBlock.
340 bool isValidPositionParent(v3s16 p);
341 MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
342 void setNodeParent(v3s16 p, MapNode & n);
344 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
346 for(u16 z=0; z<d; z++)
347 for(u16 y=0; y<h; y++)
348 for(u16 x=0; x<w; x++)
349 setNode(x0+x, y0+y, z0+z, node);
352 // See comments in mapblock.cpp
353 bool propagateSunlight(std::set<v3s16> & light_sources,
354 bool remove_light=false, bool *black_air_left=NULL);
356 // Copies data to VoxelManipulator to getPosRelative()
357 void copyTo(VoxelManipulator &dst);
358 // Copies data from VoxelManipulator getPosRelative()
359 void copyFrom(VoxelManipulator &dst);
362 Update day-night lighting difference flag.
363 Sets m_day_night_differs to appropriate value.
364 These methods don't care about neighboring blocks.
366 void actuallyUpdateDayNightDiff();
368 Call this to schedule what the previous function does to be done
369 when the value is actually needed.
371 void expireDayNightDiff();
373 bool getDayNightDiff()
375 if(m_day_night_differs_expired)
376 actuallyUpdateDayNightDiff();
377 return m_day_night_differs;
385 Tries to measure ground level.
390 0...MAP_BLOCKSIZE-1 = ground level
392 s16 getGroundLevel(v2s16 p2d);
395 Timestamp (see m_timestamp)
396 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
398 void setTimestamp(u32 time)
401 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
403 void setTimestampNoChangedFlag(u32 time)
411 u32 getDiskTimestamp()
413 return m_disk_timestamp;
419 void resetUsageTimer()
423 void incrementUsageTimer(float dtime)
425 m_usage_timer += dtime;
427 float getUsageTimer()
429 return m_usage_timer;
452 NodeTimer getNodeTimer(v3s16 p){
453 return m_node_timers.get(p);
456 void removeNodeTimer(v3s16 p){
457 m_node_timers.remove(p);
459 // Deletes old timer and sets a new one
460 void setNodeTimer(v3s16 p, NodeTimer t){
461 m_node_timers.set(p,t);
463 // Deletes all timers
464 void clearNodeTimers(){
465 m_node_timers.clear();
472 // These don't write or read version by itself
473 // Set disk to true for on-disk format, false for over-the-network format
474 void serialize(std::ostream &os, u8 version, bool disk);
475 // If disk == true: In addition to doing other things, will add
476 // unknown blocks from id-name mapping to wndef
477 void deSerialize(std::istream &is, u8 version, bool disk);
479 void serializeNetworkSpecific(std::ostream &os, u16 net_proto_version);
480 void deSerializeNetworkSpecific(std::istream &is);
487 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
490 Used only internally, because changes can't be tracked
493 MapNode & getNodeRef(s16 x, s16 y, s16 z)
496 throw InvalidPositionException();
497 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
498 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
499 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
500 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
502 MapNode & getNodeRef(v3s16 &p)
504 return getNodeRef(p.X, p.Y, p.Z);
509 Public member variables
512 #ifndef SERVER // Only on client
516 NodeMetadataList m_node_metadata;
517 NodeTimerList m_node_timers;
518 StaticObjectList m_static_objects;
522 Private member variables
525 // NOTE: Lots of things rely on this being the Map
527 // Position in blocks on parent
533 If NULL, block is a dummy block.
534 Dummy blocks are used for caching not-found-on-disk blocks.
539 - On the server, this is used for telling whether the
540 block has been modified from the one on disk.
541 - On the client, this is used for nothing.
544 std::string m_modified_reason;
545 bool m_modified_reason_too_long;
548 When propagating sunlight and the above block doesn't exist,
549 sunlight is assumed if this is false.
551 In practice this is set to true if the block is completely
552 undeground with nothing visible above the ground except
558 Set to true if changes has been made that make the old lighting
559 values wrong but the lighting hasn't been actually updated.
561 If this is false, lighting is exactly right.
562 If this is true, lighting might be wrong or right.
564 bool m_lighting_expired;
566 // Whether day and night lighting differs
567 bool m_day_night_differs;
568 bool m_day_night_differs_expired;
573 When block is removed from active blocks, this is set to gametime.
574 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
577 // The on-disk (or to-be on-disk) timestamp value
578 u32 m_disk_timestamp;
581 When the block is accessed, this is set to 0.
582 Map will unload the block when this reaches a timeout.
587 Reference count; currently used for determining if this block is in
588 the list of blocks to be drawn.
593 inline bool blockpos_over_limit(v3s16 p)
596 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
597 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
598 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
599 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
600 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
601 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
605 Returns the position of the block where the node is located
607 inline v3s16 getNodeBlockPos(v3s16 p)
609 return getContainerPos(p, MAP_BLOCKSIZE);
612 inline v2s16 getNodeSectorPos(v2s16 p)
614 return getContainerPos(p, MAP_BLOCKSIZE);
617 inline s16 getNodeBlockY(s16 y)
619 return getContainerPos(y, MAP_BLOCKSIZE);
623 Get a quick string to describe what a block actually contains
625 std::string analyze_block(MapBlock *block);