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>
27 #include "irrlichttypes.h"
29 #include "irr_aabb3d.h"
31 #include "exceptions.h"
32 #include "serialization.h"
33 #include "constants.h"
35 #include "staticobject.h"
36 #include "nodemetadata.h"
37 #include "nodetimer.h"
38 #include "modifiedstate.h"
39 #include "util/numeric.h" // getContainerPos
42 class NodeMetadataList;
46 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
48 /*// Named by looking towards z+
58 // NOTE: If this is enabled, set MapBlock to be initialized with
60 /*enum BlockGenerationStatus
62 // Completely non-generated (filled with CONTENT_IGNORE).
64 // Trees or similar might have been blitted from other blocks to here.
65 // Otherwise, the block contains CONTENT_IGNORE
66 BLOCKGEN_FROM_NEIGHBORS=2,
67 // Has been generated, but some neighbors might put some stuff in here
68 // when they are generated.
69 // Does not contain any CONTENT_IGNORE
70 BLOCKGEN_SELF_GENERATED=4,
71 // The block and all its neighbors have been generated
72 BLOCKGEN_FULLY_GENERATED=6
78 NODECONTAINER_ID_MAPBLOCK,
79 NODECONTAINER_ID_MAPSECTOR,
81 NODECONTAINER_ID_MAPBLOCKCACHE,
82 NODECONTAINER_ID_VOXELMANIPULATOR,
88 virtual bool isValidPosition(v3s16 p) = 0;
89 virtual MapNode getNode(v3s16 p) = 0;
90 virtual void setNode(v3s16 p, MapNode & n) = 0;
91 virtual u16 nodeContainerId() const = 0;
93 MapNode getNodeNoEx(v3s16 p)
98 catch(InvalidPositionException &e){
99 return MapNode(CONTENT_IGNORE);
109 class MapBlock /*: public NodeContainer*/
112 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
115 /*virtual u16 nodeContainerId() const
117 return NODECONTAINER_ID_MAPBLOCK;
129 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
130 data = new MapNode[l];
131 for(u32 i=0; i<l; i++){
132 //data[i] = MapNode();
133 data[i] = MapNode(CONTENT_IGNORE);
135 raiseModified(MOD_STATE_WRITE_NEEDED, "reallocate");
144 return (data == NULL);
152 // m_modified methods
153 void raiseModified(u32 mod, const std::string &reason="unknown")
155 if(mod > m_modified){
157 m_modified_reason = reason;
158 m_modified_reason_too_long = false;
160 if(m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
161 m_disk_timestamp = m_timestamp;
163 } else if(mod == m_modified){
164 if(!m_modified_reason_too_long){
165 if(m_modified_reason.size() < 40)
166 m_modified_reason += ", " + reason;
168 m_modified_reason += "...";
169 m_modified_reason_too_long = true;
178 std::string getModifiedReason()
180 return m_modified_reason;
184 m_modified = MOD_STATE_CLEAN;
185 m_modified_reason = "none";
186 m_modified_reason_too_long = false;
189 // is_underground getter/setter
190 bool getIsUnderground()
192 return is_underground;
194 void setIsUnderground(bool a_is_underground)
196 is_underground = a_is_underground;
197 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
200 void setLightingExpired(bool expired)
202 if(expired != m_lighting_expired){
203 m_lighting_expired = expired;
204 raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
207 bool getLightingExpired()
209 return m_lighting_expired;
216 void setGenerated(bool b)
218 if(b != m_generated){
219 raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
226 if(m_lighting_expired)
242 v3s16 getPosRelative()
244 return m_pos * MAP_BLOCKSIZE;
247 core::aabbox3d<s16> getBox()
249 return core::aabbox3d<s16>(getPosRelative(),
251 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
256 Regular MapNode get-setters
259 bool isValidPosition(v3s16 p)
263 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
264 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
265 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
268 MapNode getNode(s16 x, s16 y, s16 z)
271 throw InvalidPositionException();
272 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
273 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
274 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
275 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
278 MapNode getNode(v3s16 p)
280 return getNode(p.X, p.Y, p.Z);
283 MapNode getNodeNoEx(v3s16 p)
286 return getNode(p.X, p.Y, p.Z);
287 }catch(InvalidPositionException &e){
288 return MapNode(CONTENT_IGNORE);
292 void setNode(s16 x, s16 y, s16 z, MapNode & n)
295 throw InvalidPositionException();
296 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
297 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
298 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
299 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
300 raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
303 void setNode(v3s16 p, MapNode & n)
305 setNode(p.X, p.Y, p.Z, n);
309 Non-checking variants of the above
312 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
315 throw InvalidPositionException();
316 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
319 MapNode getNodeNoCheck(v3s16 p)
321 return getNodeNoCheck(p.X, p.Y, p.Z);
324 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
327 throw InvalidPositionException();
328 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
329 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
332 void setNodeNoCheck(v3s16 p, MapNode & n)
334 setNodeNoCheck(p.X, p.Y, p.Z, n);
338 These functions consult the parent container if the position
339 is not valid on this MapBlock.
341 bool isValidPositionParent(v3s16 p);
342 MapNode getNodeParent(v3s16 p);
343 void setNodeParent(v3s16 p, MapNode & n);
344 MapNode getNodeParentNoEx(v3s16 p);
346 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
348 for(u16 z=0; z<d; z++)
349 for(u16 y=0; y<h; y++)
350 for(u16 x=0; x<w; x++)
351 setNode(x0+x, y0+y, z0+z, node);
354 // See comments in mapblock.cpp
355 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
356 bool remove_light=false, bool *black_air_left=NULL);
358 // Copies data to VoxelManipulator to getPosRelative()
359 void copyTo(VoxelManipulator &dst);
360 // Copies data from VoxelManipulator getPosRelative()
361 void copyFrom(VoxelManipulator &dst);
364 Update day-night lighting difference flag.
365 Sets m_day_night_differs to appropriate value.
366 These methods don't care about neighboring blocks.
368 void actuallyUpdateDayNightDiff();
370 Call this to schedule what the previous function does to be done
371 when the value is actually needed.
373 void expireDayNightDiff();
375 bool getDayNightDiff()
377 if(m_day_night_differs_expired)
378 actuallyUpdateDayNightDiff();
379 return m_day_night_differs;
387 Tries to measure ground level.
392 0...MAP_BLOCKSIZE-1 = ground level
394 s16 getGroundLevel(v2s16 p2d);
397 Timestamp (see m_timestamp)
398 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
400 void setTimestamp(u32 time)
403 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
405 void setTimestampNoChangedFlag(u32 time)
413 u32 getDiskTimestamp()
415 return m_disk_timestamp;
421 void resetUsageTimer()
425 void incrementUsageTimer(float dtime)
427 m_usage_timer += dtime;
431 return m_usage_timer;
454 NodeTimer getNodeTimer(v3s16 p){
455 return m_node_timers.get(p);
458 void removeNodeTimer(v3s16 p){
459 m_node_timers.remove(p);
461 // Deletes old timer and sets a new one
462 void setNodeTimer(v3s16 p, NodeTimer t){
463 m_node_timers.set(p,t);
465 // Deletes all timers
466 void clearNodeTimers(){
467 m_node_timers.clear();
474 // These don't write or read version by itself
475 // Set disk to true for on-disk format, false for over-the-network format
476 void serialize(std::ostream &os, u8 version, bool disk);
477 // If disk == true: In addition to doing other things, will add
478 // unknown blocks from id-name mapping to wndef
479 void deSerialize(std::istream &is, u8 version, bool disk);
486 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
489 Used only internally, because changes can't be tracked
492 MapNode & getNodeRef(s16 x, s16 y, s16 z)
495 throw InvalidPositionException();
496 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
497 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
498 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
499 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
501 MapNode & getNodeRef(v3s16 &p)
503 return getNodeRef(p.X, p.Y, p.Z);
508 Public member variables
511 #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);