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
24 #include <jmutexautolock.h>
28 #include "irrlichttypes.h"
30 #include "irr_aabb3d.h"
32 #include "exceptions.h"
33 #include "serialization.h"
34 #include "constants.h"
36 #include "staticobject.h"
37 #include "nodemetadata.h"
38 #include "nodetimer.h"
39 #include "modifiedstate.h"
40 #include "util/numeric.h" // getContainerPos
43 class NodeMetadataList;
47 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
49 /*// Named by looking towards z+
59 // NOTE: If this is enabled, set MapBlock to be initialized with
61 /*enum BlockGenerationStatus
63 // Completely non-generated (filled with CONTENT_IGNORE).
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
79 NODECONTAINER_ID_MAPBLOCK,
80 NODECONTAINER_ID_MAPSECTOR,
82 NODECONTAINER_ID_MAPBLOCKCACHE,
83 NODECONTAINER_ID_VOXELMANIPULATOR,
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;
94 MapNode getNodeNoEx(v3s16 p)
99 catch(InvalidPositionException &e){
100 return MapNode(CONTENT_IGNORE);
110 class MapBlock /*: public NodeContainer*/
113 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
116 /*virtual u16 nodeContainerId() const
118 return NODECONTAINER_ID_MAPBLOCK;
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);
136 raiseModified(MOD_STATE_WRITE_NEEDED, "reallocate");
145 return (data == NULL);
153 // m_modified methods
154 void raiseModified(u32 mod, const std::string &reason="unknown")
156 if(mod > m_modified){
158 m_modified_reason = reason;
159 m_modified_reason_too_long = false;
161 if(m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
162 m_disk_timestamp = m_timestamp;
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;
169 m_modified_reason += "...";
170 m_modified_reason_too_long = true;
179 std::string getModifiedReason()
181 return m_modified_reason;
185 m_modified = MOD_STATE_CLEAN;
186 m_modified_reason = "none";
187 m_modified_reason_too_long = false;
190 // is_underground getter/setter
191 bool getIsUnderground()
193 return is_underground;
195 void setIsUnderground(bool a_is_underground)
197 is_underground = a_is_underground;
198 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
201 void setLightingExpired(bool expired)
203 if(expired != m_lighting_expired){
204 m_lighting_expired = expired;
205 raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
208 bool getLightingExpired()
210 return m_lighting_expired;
217 void setGenerated(bool b)
219 if(b != m_generated){
220 raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
227 if(m_lighting_expired)
243 v3s16 getPosRelative()
245 return m_pos * MAP_BLOCKSIZE;
248 core::aabbox3d<s16> getBox()
250 return core::aabbox3d<s16>(getPosRelative(),
252 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
257 Regular MapNode get-setters
260 bool isValidPosition(v3s16 p)
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);
269 MapNode getNode(s16 x, s16 y, s16 z)
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];
279 MapNode getNode(v3s16 p)
281 return getNode(p.X, p.Y, p.Z);
284 MapNode getNodeNoEx(v3s16 p)
287 return getNode(p.X, p.Y, p.Z);
288 }catch(InvalidPositionException &e){
289 return MapNode(CONTENT_IGNORE);
293 void setNode(s16 x, s16 y, s16 z, MapNode & n)
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");
304 void setNode(v3s16 p, MapNode & n)
306 setNode(p.X, p.Y, p.Z, n);
310 Non-checking variants of the above
313 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
316 throw InvalidPositionException();
317 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
320 MapNode getNodeNoCheck(v3s16 p)
322 return getNodeNoCheck(p.X, p.Y, p.Z);
325 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
328 throw InvalidPositionException();
329 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
330 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
333 void setNodeNoCheck(v3s16 p, MapNode & n)
335 setNodeNoCheck(p.X, p.Y, p.Z, n);
339 These functions consult the parent container if the position
340 is not valid on this MapBlock.
342 bool isValidPositionParent(v3s16 p);
343 MapNode getNodeParent(v3s16 p);
344 void setNodeParent(v3s16 p, MapNode & n);
345 MapNode getNodeParentNoEx(v3s16 p);
347 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
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);
355 // See comments in mapblock.cpp
356 bool propagateSunlight(std::set<v3s16> & light_sources,
357 bool remove_light=false, bool *black_air_left=NULL);
359 // Copies data to VoxelManipulator to getPosRelative()
360 void copyTo(VoxelManipulator &dst);
361 // Copies data from VoxelManipulator getPosRelative()
362 void copyFrom(VoxelManipulator &dst);
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.
369 void actuallyUpdateDayNightDiff();
371 Call this to schedule what the previous function does to be done
372 when the value is actually needed.
374 void expireDayNightDiff();
376 bool getDayNightDiff()
378 if(m_day_night_differs_expired)
379 actuallyUpdateDayNightDiff();
380 return m_day_night_differs;
388 Tries to measure ground level.
393 0...MAP_BLOCKSIZE-1 = ground level
395 s16 getGroundLevel(v2s16 p2d);
398 Timestamp (see m_timestamp)
399 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
401 void setTimestamp(u32 time)
404 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
406 void setTimestampNoChangedFlag(u32 time)
414 u32 getDiskTimestamp()
416 return m_disk_timestamp;
422 void resetUsageTimer()
426 void incrementUsageTimer(float dtime)
428 m_usage_timer += dtime;
432 return m_usage_timer;
455 NodeTimer getNodeTimer(v3s16 p){
456 return m_node_timers.get(p);
459 void removeNodeTimer(v3s16 p){
460 m_node_timers.remove(p);
462 // Deletes old timer and sets a new one
463 void setNodeTimer(v3s16 p, NodeTimer t){
464 m_node_timers.set(p,t);
466 // Deletes all timers
467 void clearNodeTimers(){
468 m_node_timers.clear();
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);
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
517 NodeMetadataList m_node_metadata;
518 NodeTimerList m_node_timers;
519 StaticObjectList m_static_objects;
523 Private member variables
526 // NOTE: Lots of things rely on this being the Map
528 // Position in blocks on parent
534 If NULL, block is a dummy block.
535 Dummy blocks are used for caching not-found-on-disk blocks.
540 - On the server, this is used for telling whether the
541 block has been modified from the one on disk.
542 - On the client, this is used for nothing.
545 std::string m_modified_reason;
546 bool m_modified_reason_too_long;
549 When propagating sunlight and the above block doesn't exist,
550 sunlight is assumed if this is false.
552 In practice this is set to true if the block is completely
553 undeground with nothing visible above the ground except
559 Set to true if changes has been made that make the old lighting
560 values wrong but the lighting hasn't been actually updated.
562 If this is false, lighting is exactly right.
563 If this is true, lighting might be wrong or right.
565 bool m_lighting_expired;
567 // Whether day and night lighting differs
568 bool m_day_night_differs;
569 bool m_day_night_differs_expired;
574 When block is removed from active blocks, this is set to gametime.
575 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
578 // The on-disk (or to-be on-disk) timestamp value
579 u32 m_disk_timestamp;
582 When the block is accessed, this is set to 0.
583 Map will unload the block when this reaches a timeout.
588 Reference count; currently used for determining if this block is in
589 the list of blocks to be drawn.
594 inline bool blockpos_over_limit(v3s16 p)
597 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
598 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
599 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
600 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
601 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
602 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
606 Returns the position of the block where the node is located
608 inline v3s16 getNodeBlockPos(v3s16 p)
610 return getContainerPos(p, MAP_BLOCKSIZE);
613 inline v2s16 getNodeSectorPos(v2s16 p)
615 return getContainerPos(p, MAP_BLOCKSIZE);
618 inline s16 getNodeBlockY(s16 y)
620 return getContainerPos(y, MAP_BLOCKSIZE);
624 Get a quick string to describe what a block actually contains
626 std::string analyze_block(MapBlock *block);