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 "common_irrlicht.h"
29 #include "exceptions.h"
30 #include "serialization.h"
31 #include "constants.h"
33 #include "staticobject.h"
34 #include "nodemetadata.h"
35 #include "nodetimer.h"
36 #include "modifiedstate.h"
37 #include "util/numeric.h" // getContainerPos
40 class NodeMetadataList;
44 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
46 /*// Named by looking towards z+
56 // NOTE: If this is enabled, set MapBlock to be initialized with
58 /*enum BlockGenerationStatus
60 // Completely non-generated (filled with CONTENT_IGNORE).
62 // Trees or similar might have been blitted from other blocks to here.
63 // Otherwise, the block contains CONTENT_IGNORE
64 BLOCKGEN_FROM_NEIGHBORS=2,
65 // Has been generated, but some neighbors might put some stuff in here
66 // when they are generated.
67 // Does not contain any CONTENT_IGNORE
68 BLOCKGEN_SELF_GENERATED=4,
69 // The block and all its neighbors have been generated
70 BLOCKGEN_FULLY_GENERATED=6
76 NODECONTAINER_ID_MAPBLOCK,
77 NODECONTAINER_ID_MAPSECTOR,
79 NODECONTAINER_ID_MAPBLOCKCACHE,
80 NODECONTAINER_ID_VOXELMANIPULATOR,
86 virtual bool isValidPosition(v3s16 p) = 0;
87 virtual MapNode getNode(v3s16 p) = 0;
88 virtual void setNode(v3s16 p, MapNode & n) = 0;
89 virtual u16 nodeContainerId() const = 0;
91 MapNode getNodeNoEx(v3s16 p)
96 catch(InvalidPositionException &e){
97 return MapNode(CONTENT_IGNORE);
107 class MapBlock /*: public NodeContainer*/
110 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
113 /*virtual u16 nodeContainerId() const
115 return NODECONTAINER_ID_MAPBLOCK;
127 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
128 data = new MapNode[l];
129 for(u32 i=0; i<l; i++){
130 //data[i] = MapNode();
131 data[i] = MapNode(CONTENT_IGNORE);
133 raiseModified(MOD_STATE_WRITE_NEEDED, "reallocate");
142 return (data == NULL);
150 // m_modified methods
151 void raiseModified(u32 mod, const std::string &reason="unknown")
153 if(mod > m_modified){
155 m_modified_reason = reason;
156 m_modified_reason_too_long = false;
158 if(m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
159 m_disk_timestamp = m_timestamp;
161 } else if(mod == m_modified){
162 if(!m_modified_reason_too_long){
163 if(m_modified_reason.size() < 40)
164 m_modified_reason += ", " + reason;
166 m_modified_reason += "...";
167 m_modified_reason_too_long = true;
176 std::string getModifiedReason()
178 return m_modified_reason;
182 m_modified = MOD_STATE_CLEAN;
183 m_modified_reason = "none";
184 m_modified_reason_too_long = false;
187 // is_underground getter/setter
188 bool getIsUnderground()
190 return is_underground;
192 void setIsUnderground(bool a_is_underground)
194 is_underground = a_is_underground;
195 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
198 void setLightingExpired(bool expired)
200 if(expired != m_lighting_expired){
201 m_lighting_expired = expired;
202 raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
205 bool getLightingExpired()
207 return m_lighting_expired;
214 void setGenerated(bool b)
216 if(b != m_generated){
217 raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
224 if(m_lighting_expired)
240 v3s16 getPosRelative()
242 return m_pos * MAP_BLOCKSIZE;
245 core::aabbox3d<s16> getBox()
247 return core::aabbox3d<s16>(getPosRelative(),
249 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
254 Regular MapNode get-setters
257 bool isValidPosition(v3s16 p)
261 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
262 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
263 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
266 MapNode getNode(s16 x, s16 y, s16 z)
269 throw InvalidPositionException();
270 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
271 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
272 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
273 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
276 MapNode getNode(v3s16 p)
278 return getNode(p.X, p.Y, p.Z);
281 MapNode getNodeNoEx(v3s16 p)
284 return getNode(p.X, p.Y, p.Z);
285 }catch(InvalidPositionException &e){
286 return MapNode(CONTENT_IGNORE);
290 void setNode(s16 x, s16 y, s16 z, MapNode & n)
293 throw InvalidPositionException();
294 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
295 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
296 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
297 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
298 raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
301 void setNode(v3s16 p, MapNode & n)
303 setNode(p.X, p.Y, p.Z, n);
307 Non-checking variants of the above
310 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
313 throw InvalidPositionException();
314 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
317 MapNode getNodeNoCheck(v3s16 p)
319 return getNodeNoCheck(p.X, p.Y, p.Z);
322 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
325 throw InvalidPositionException();
326 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
327 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
330 void setNodeNoCheck(v3s16 p, MapNode & n)
332 setNodeNoCheck(p.X, p.Y, p.Z, n);
336 These functions consult the parent container if the position
337 is not valid on this MapBlock.
339 bool isValidPositionParent(v3s16 p);
340 MapNode getNodeParent(v3s16 p);
341 void setNodeParent(v3s16 p, MapNode & n);
342 MapNode getNodeParentNoEx(v3s16 p);
344 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
346 for(u16 z=0; z<d; z++)
347 for(u16 y=0; y<h; y++)
348 for(u16 x=0; x<w; x++)
349 setNode(x0+x, y0+y, z0+z, node);
352 // See comments in mapblock.cpp
353 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
354 bool remove_light=false, bool *black_air_left=NULL);
356 // Copies data to VoxelManipulator to getPosRelative()
357 void copyTo(VoxelManipulator &dst);
358 // Copies data from VoxelManipulator getPosRelative()
359 void copyFrom(VoxelManipulator &dst);
362 Update day-night lighting difference flag.
363 Sets m_day_night_differs to appropriate value.
364 These methods don't care about neighboring blocks.
366 void actuallyUpdateDayNightDiff();
368 Call this to schedule what the previous function does to be done
369 when the value is actually needed.
371 void expireDayNightDiff();
373 bool getDayNightDiff()
375 if(m_day_night_differs_expired)
376 actuallyUpdateDayNightDiff();
377 return m_day_night_differs;
385 Tries to measure ground level.
390 0...MAP_BLOCKSIZE-1 = ground level
392 s16 getGroundLevel(v2s16 p2d);
395 Timestamp (see m_timestamp)
396 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
398 void setTimestamp(u32 time)
401 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
403 void setTimestampNoChangedFlag(u32 time)
411 u32 getDiskTimestamp()
413 return m_disk_timestamp;
419 void resetUsageTimer()
423 void incrementUsageTimer(float dtime)
425 m_usage_timer += dtime;
429 return m_usage_timer;
436 // These don't write or read version by itself
437 // Set disk to true for on-disk format, false for over-the-network format
438 void serialize(std::ostream &os, u8 version, bool disk);
439 // If disk == true: In addition to doing other things, will add
440 // unknown blocks from id-name mapping to wndef
441 void deSerialize(std::istream &is, u8 version, bool disk);
448 void serialize_pre22(std::ostream &os, u8 version, bool disk);
449 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
452 Used only internally, because changes can't be tracked
455 MapNode & getNodeRef(s16 x, s16 y, s16 z)
458 throw InvalidPositionException();
459 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
460 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
461 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
462 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
464 MapNode & getNodeRef(v3s16 &p)
466 return getNodeRef(p.X, p.Y, p.Z);
471 Public member variables
474 #ifndef SERVER // Only on client
479 NodeMetadataList m_node_metadata;
480 NodeTimerList m_node_timers;
481 StaticObjectList m_static_objects;
485 Private member variables
488 // NOTE: Lots of things rely on this being the Map
490 // Position in blocks on parent
496 If NULL, block is a dummy block.
497 Dummy blocks are used for caching not-found-on-disk blocks.
502 - On the server, this is used for telling whether the
503 block has been modified from the one on disk.
504 - On the client, this is used for nothing.
507 std::string m_modified_reason;
508 bool m_modified_reason_too_long;
511 When propagating sunlight and the above block doesn't exist,
512 sunlight is assumed if this is false.
514 In practice this is set to true if the block is completely
515 undeground with nothing visible above the ground except
521 Set to true if changes has been made that make the old lighting
522 values wrong but the lighting hasn't been actually updated.
524 If this is false, lighting is exactly right.
525 If this is true, lighting might be wrong or right.
527 bool m_lighting_expired;
529 // Whether day and night lighting differs
530 bool m_day_night_differs;
531 bool m_day_night_differs_expired;
536 When block is removed from active blocks, this is set to gametime.
537 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
540 // The on-disk (or to-be on-disk) timestamp value
541 u32 m_disk_timestamp;
544 When the block is accessed, this is set to 0.
545 Map will unload the block when this reaches a timeout.
550 inline bool blockpos_over_limit(v3s16 p)
553 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
554 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
555 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
556 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
557 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
558 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
562 Returns the position of the block where the node is located
564 inline v3s16 getNodeBlockPos(v3s16 p)
566 return getContainerPos(p, MAP_BLOCKSIZE);
569 inline v2s16 getNodeSectorPos(v2s16 p)
571 return getContainerPos(p, MAP_BLOCKSIZE);
574 inline s16 getNodeBlockY(s16 y)
576 return getContainerPos(y, MAP_BLOCKSIZE);
580 Get a quick string to describe what a block actually contains
582 std::string analyze_block(MapBlock *block);