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 NodeTimer getNodeTimer(v3s16 p){
439 return m_node_timers.get(p);
442 void removeNodeTimer(v3s16 p){
443 m_node_timers.remove(p);
445 // Deletes old timer and sets a new one
446 void setNodeTimer(v3s16 p, NodeTimer t){
447 m_node_timers.set(p,t);
449 // Deletes all timers
450 void clearNodeTimers(){
451 m_node_timers.clear();
458 // These don't write or read version by itself
459 // Set disk to true for on-disk format, false for over-the-network format
460 void serialize(std::ostream &os, u8 version, bool disk);
461 // If disk == true: In addition to doing other things, will add
462 // unknown blocks from id-name mapping to wndef
463 void deSerialize(std::istream &is, u8 version, bool disk);
470 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
473 Used only internally, because changes can't be tracked
476 MapNode & getNodeRef(s16 x, s16 y, s16 z)
479 throw InvalidPositionException();
480 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
481 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
482 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
483 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
485 MapNode & getNodeRef(v3s16 &p)
487 return getNodeRef(p.X, p.Y, p.Z);
492 Public member variables
495 #ifndef SERVER // Only on client
500 NodeMetadataList m_node_metadata;
501 NodeTimerList m_node_timers;
502 StaticObjectList m_static_objects;
506 Private member variables
509 // NOTE: Lots of things rely on this being the Map
511 // Position in blocks on parent
517 If NULL, block is a dummy block.
518 Dummy blocks are used for caching not-found-on-disk blocks.
523 - On the server, this is used for telling whether the
524 block has been modified from the one on disk.
525 - On the client, this is used for nothing.
528 std::string m_modified_reason;
529 bool m_modified_reason_too_long;
532 When propagating sunlight and the above block doesn't exist,
533 sunlight is assumed if this is false.
535 In practice this is set to true if the block is completely
536 undeground with nothing visible above the ground except
542 Set to true if changes has been made that make the old lighting
543 values wrong but the lighting hasn't been actually updated.
545 If this is false, lighting is exactly right.
546 If this is true, lighting might be wrong or right.
548 bool m_lighting_expired;
550 // Whether day and night lighting differs
551 bool m_day_night_differs;
552 bool m_day_night_differs_expired;
557 When block is removed from active blocks, this is set to gametime.
558 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
561 // The on-disk (or to-be on-disk) timestamp value
562 u32 m_disk_timestamp;
565 When the block is accessed, this is set to 0.
566 Map will unload the block when this reaches a timeout.
571 inline bool blockpos_over_limit(v3s16 p)
574 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
575 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
576 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
577 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
578 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
579 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
583 Returns the position of the block where the node is located
585 inline v3s16 getNodeBlockPos(v3s16 p)
587 return getContainerPos(p, MAP_BLOCKSIZE);
590 inline v2s16 getNodeSectorPos(v2s16 p)
592 return getContainerPos(p, MAP_BLOCKSIZE);
595 inline s16 getNodeBlockY(s16 y)
597 return getContainerPos(y, MAP_BLOCKSIZE);
601 Get a quick string to describe what a block actually contains
603 std::string analyze_block(MapBlock *block);