3 Copyright (C) 2010 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;
438 // These don't write or read version by itself
439 // Set disk to true for on-disk format, false for over-the-network format
440 void serialize(std::ostream &os, u8 version, bool disk);
441 // If disk == true: In addition to doing other things, will add
442 // unknown blocks from id-name mapping to wndef
443 void deSerialize(std::istream &is, u8 version, bool disk);
450 void serialize_pre22(std::ostream &os, u8 version, bool disk);
451 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
454 Used only internally, because changes can't be tracked
457 MapNode & getNodeRef(s16 x, s16 y, s16 z)
460 throw InvalidPositionException();
461 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
462 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
463 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
464 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
466 MapNode & getNodeRef(v3s16 &p)
468 return getNodeRef(p.X, p.Y, p.Z);
473 Public member variables
476 #ifndef SERVER // Only on client
481 NodeMetadataList m_node_metadata;
482 NodeTimerList m_node_timers;
483 StaticObjectList m_static_objects;
487 Private member variables
490 // NOTE: Lots of things rely on this being the Map
492 // Position in blocks on parent
498 If NULL, block is a dummy block.
499 Dummy blocks are used for caching not-found-on-disk blocks.
504 - On the server, this is used for telling whether the
505 block has been modified from the one on disk.
506 - On the client, this is used for nothing.
509 std::string m_modified_reason;
510 bool m_modified_reason_too_long;
513 When propagating sunlight and the above block doesn't exist,
514 sunlight is assumed if this is false.
516 In practice this is set to true if the block is completely
517 undeground with nothing visible above the ground except
523 Set to true if changes has been made that make the old lighting
524 values wrong but the lighting hasn't been actually updated.
526 If this is false, lighting is exactly right.
527 If this is true, lighting might be wrong or right.
529 bool m_lighting_expired;
531 // Whether day and night lighting differs
532 bool m_day_night_differs;
533 bool m_day_night_differs_expired;
538 When block is removed from active blocks, this is set to gametime.
539 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
542 // The on-disk (or to-be on-disk) timestamp value
543 u32 m_disk_timestamp;
546 When the block is accessed, this is set to 0.
547 Map will unload the block when this reaches a timeout.
552 inline bool blockpos_over_limit(v3s16 p)
555 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
556 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
557 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
558 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
559 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
560 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
564 Returns the position of the block where the node is located
566 inline v3s16 getNodeBlockPos(v3s16 p)
568 return getContainerPos(p, MAP_BLOCKSIZE);
571 inline v2s16 getNodeSectorPos(v2s16 p)
573 return getContainerPos(p, MAP_BLOCKSIZE);
576 inline s16 getNodeBlockY(s16 y)
578 return getContainerPos(y, MAP_BLOCKSIZE);
582 Get a quick string to describe what a block actually contains
584 std::string analyze_block(MapBlock *block);