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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
15 You should have received a copy of the GNU 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 "common_irrlicht.h"
29 #include "exceptions.h"
30 #include "serialization.h"
31 #include "constants.h"
33 #include "staticobject.h"
34 #include "modifiedstate.h"
37 class NodeMetadataList;
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(v3s16 p)
258 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
259 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
260 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
263 MapNode getNode(s16 x, s16 y, s16 z)
266 throw InvalidPositionException();
267 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
268 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
269 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
270 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
273 MapNode getNode(v3s16 p)
275 return getNode(p.X, p.Y, p.Z);
278 MapNode getNodeNoEx(v3s16 p)
281 return getNode(p.X, p.Y, p.Z);
282 }catch(InvalidPositionException &e){
283 return MapNode(CONTENT_IGNORE);
287 void setNode(s16 x, s16 y, s16 z, MapNode & n)
290 throw InvalidPositionException();
291 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
292 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
293 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
294 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
295 raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
298 void setNode(v3s16 p, MapNode & n)
300 setNode(p.X, p.Y, p.Z, n);
304 Non-checking variants of the above
307 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
310 throw InvalidPositionException();
311 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
314 MapNode getNodeNoCheck(v3s16 p)
316 return getNodeNoCheck(p.X, p.Y, p.Z);
319 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
322 throw InvalidPositionException();
323 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
324 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
327 void setNodeNoCheck(v3s16 p, MapNode & n)
329 setNodeNoCheck(p.X, p.Y, p.Z, n);
333 These functions consult the parent container if the position
334 is not valid on this MapBlock.
336 bool isValidPositionParent(v3s16 p);
337 MapNode getNodeParent(v3s16 p);
338 void setNodeParent(v3s16 p, MapNode & n);
339 MapNode getNodeParentNoEx(v3s16 p);
341 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
343 for(u16 z=0; z<d; z++)
344 for(u16 y=0; y<h; y++)
345 for(u16 x=0; x<w; x++)
346 setNode(x0+x, y0+y, z0+z, node);
349 // See comments in mapblock.cpp
350 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
351 bool remove_light=false, bool *black_air_left=NULL);
353 // Copies data to VoxelManipulator to getPosRelative()
354 void copyTo(VoxelManipulator &dst);
355 // Copies data from VoxelManipulator getPosRelative()
356 void copyFrom(VoxelManipulator &dst);
359 Update day-night lighting difference flag.
360 Sets m_day_night_differs to appropriate value.
361 These methods don't care about neighboring blocks.
363 void actuallyUpdateDayNightDiff();
365 Call this to schedule what the previous function does to be done
366 when the value is actually needed.
368 void expireDayNightDiff();
370 bool getDayNightDiff()
372 if(m_day_night_differs_expired)
373 actuallyUpdateDayNightDiff();
374 return m_day_night_differs;
382 Tries to measure ground level.
387 0...MAP_BLOCKSIZE-1 = ground level
389 s16 getGroundLevel(v2s16 p2d);
392 Timestamp (see m_timestamp)
393 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
395 void setTimestamp(u32 time)
398 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
400 void setTimestampNoChangedFlag(u32 time)
408 u32 getDiskTimestamp()
410 return m_disk_timestamp;
416 void resetUsageTimer()
420 void incrementUsageTimer(float dtime)
422 m_usage_timer += dtime;
426 return m_usage_timer;
433 // These don't write or read version by itself
434 // Set disk to true for on-disk format, false for over-the-network format
435 void serialize(std::ostream &os, u8 version, bool disk);
436 // If disk == true: In addition to doing other things, will add
437 // unknown blocks from id-name mapping to wndef
438 void deSerialize(std::istream &is, u8 version, bool disk);
445 void serialize_pre22(std::ostream &os, u8 version, bool disk);
446 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
449 Used only internally, because changes can't be tracked
452 MapNode & getNodeRef(s16 x, s16 y, s16 z)
455 throw InvalidPositionException();
456 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
457 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
458 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
459 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
461 MapNode & getNodeRef(v3s16 &p)
463 return getNodeRef(p.X, p.Y, p.Z);
468 Public member variables
471 #ifndef SERVER // Only on client
476 NodeMetadataList *m_node_metadata;
477 StaticObjectList m_static_objects;
481 Private member variables
484 // NOTE: Lots of things rely on this being the Map
486 // Position in blocks on parent
492 If NULL, block is a dummy block.
493 Dummy blocks are used for caching not-found-on-disk blocks.
498 - On the server, this is used for telling whether the
499 block has been modified from the one on disk.
500 - On the client, this is used for nothing.
503 std::string m_modified_reason;
504 bool m_modified_reason_too_long;
507 When propagating sunlight and the above block doesn't exist,
508 sunlight is assumed if this is false.
510 In practice this is set to true if the block is completely
511 undeground with nothing visible above the ground except
517 Set to true if changes has been made that make the old lighting
518 values wrong but the lighting hasn't been actually updated.
520 If this is false, lighting is exactly right.
521 If this is true, lighting might be wrong or right.
523 bool m_lighting_expired;
525 // Whether day and night lighting differs
526 bool m_day_night_differs;
527 bool m_day_night_differs_expired;
532 When block is removed from active blocks, this is set to gametime.
533 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
536 // The on-disk (or to-be on-disk) timestamp value
537 u32 m_disk_timestamp;
540 When the block is accessed, this is set to 0.
541 Map will unload the block when this reaches a timeout.
546 inline bool blockpos_over_limit(v3s16 p)
549 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
550 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
551 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
552 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
553 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
554 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
558 Returns the position of the block where the node is located
560 inline v3s16 getNodeBlockPos(v3s16 p)
562 return getContainerPos(p, MAP_BLOCKSIZE);
565 inline v2s16 getNodeSectorPos(v2s16 p)
567 return getContainerPos(p, MAP_BLOCKSIZE);
570 inline s16 getNodeBlockY(s16 y)
572 return getContainerPos(y, MAP_BLOCKSIZE);
576 Get a quick string to describe what a block actually contains
578 std::string analyze_block(MapBlock *block);