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 "mapblock_nodemod.h"
35 #include "modifiedstate.h"
38 class NodeMetadataList;
40 class IWritableNodeDefManager;
42 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
44 /*// Named by looking towards z+
54 // NOTE: If this is enabled, set MapBlock to be initialized with
56 /*enum BlockGenerationStatus
58 // Completely non-generated (filled with CONTENT_IGNORE).
60 // Trees or similar might have been blitted from other blocks to here.
61 // Otherwise, the block contains CONTENT_IGNORE
62 BLOCKGEN_FROM_NEIGHBORS=2,
63 // Has been generated, but some neighbors might put some stuff in here
64 // when they are generated.
65 // Does not contain any CONTENT_IGNORE
66 BLOCKGEN_SELF_GENERATED=4,
67 // The block and all its neighbors have been generated
68 BLOCKGEN_FULLY_GENERATED=6
74 NODECONTAINER_ID_MAPBLOCK,
75 NODECONTAINER_ID_MAPSECTOR,
77 NODECONTAINER_ID_MAPBLOCKCACHE,
78 NODECONTAINER_ID_VOXELMANIPULATOR,
84 virtual bool isValidPosition(v3s16 p) = 0;
85 virtual MapNode getNode(v3s16 p) = 0;
86 virtual void setNode(v3s16 p, MapNode & n) = 0;
87 virtual u16 nodeContainerId() const = 0;
89 MapNode getNodeNoEx(v3s16 p)
94 catch(InvalidPositionException &e){
95 return MapNode(CONTENT_IGNORE);
105 class MapBlock /*: public NodeContainer*/
108 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
111 /*virtual u16 nodeContainerId() const
113 return NODECONTAINER_ID_MAPBLOCK;
125 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
126 data = new MapNode[l];
127 for(u32 i=0; i<l; i++){
128 //data[i] = MapNode();
129 data[i] = MapNode(CONTENT_IGNORE);
131 raiseModified(MOD_STATE_WRITE_NEEDED, "reallocate");
140 return (data == NULL);
148 // m_modified methods
149 void raiseModified(u32 mod, const std::string &reason="unknown")
151 if(mod > m_modified){
153 m_modified_reason = reason;
154 m_modified_reason_too_long = false;
156 if(m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
157 m_disk_timestamp = m_timestamp;
159 } else if(mod == m_modified){
160 if(!m_modified_reason_too_long){
161 if(m_modified_reason.size() < 40)
162 m_modified_reason += ", " + reason;
164 m_modified_reason += "...";
165 m_modified_reason_too_long = true;
174 std::string getModifiedReason()
176 return m_modified_reason;
180 m_modified = MOD_STATE_CLEAN;
181 m_modified_reason = "none";
182 m_modified_reason_too_long = false;
185 // is_underground getter/setter
186 bool getIsUnderground()
188 return is_underground;
190 void setIsUnderground(bool a_is_underground)
192 is_underground = a_is_underground;
193 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
197 void setMeshExpired(bool expired)
199 m_mesh_expired = expired;
202 bool getMeshExpired()
204 return m_mesh_expired;
208 void setLightingExpired(bool expired)
210 if(expired != m_lighting_expired){
211 m_lighting_expired = expired;
212 raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
215 bool getLightingExpired()
217 return m_lighting_expired;
224 void setGenerated(bool b)
226 if(b != m_generated){
227 raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
234 if(m_lighting_expired)
250 v3s16 getPosRelative()
252 return m_pos * MAP_BLOCKSIZE;
255 core::aabbox3d<s16> getBox()
257 return core::aabbox3d<s16>(getPosRelative(),
259 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
264 Regular MapNode get-setters
267 bool isValidPosition(v3s16 p)
271 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
272 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
273 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
276 MapNode getNode(s16 x, s16 y, s16 z)
279 throw InvalidPositionException();
280 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
281 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
282 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
283 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
286 MapNode getNode(v3s16 p)
288 return getNode(p.X, p.Y, p.Z);
291 MapNode getNodeNoEx(v3s16 p)
294 return getNode(p.X, p.Y, p.Z);
295 }catch(InvalidPositionException &e){
296 return MapNode(CONTENT_IGNORE);
300 void setNode(s16 x, s16 y, s16 z, MapNode & n)
303 throw InvalidPositionException();
304 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
305 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
306 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
307 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
308 raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
311 void setNode(v3s16 p, MapNode & n)
313 setNode(p.X, p.Y, p.Z, n);
317 Non-checking variants of the above
320 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
323 throw InvalidPositionException();
324 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
327 MapNode getNodeNoCheck(v3s16 p)
329 return getNodeNoCheck(p.X, p.Y, p.Z);
332 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
335 throw InvalidPositionException();
336 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
337 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
340 void setNodeNoCheck(v3s16 p, MapNode & n)
342 setNodeNoCheck(p.X, p.Y, p.Z, n);
346 These functions consult the parent container if the position
347 is not valid on this MapBlock.
349 bool isValidPositionParent(v3s16 p);
350 MapNode getNodeParent(v3s16 p);
351 void setNodeParent(v3s16 p, MapNode & n);
352 MapNode getNodeParentNoEx(v3s16 p);
354 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
356 for(u16 z=0; z<d; z++)
357 for(u16 y=0; y<h; y++)
358 for(u16 x=0; x<w; x++)
359 setNode(x0+x, y0+y, z0+z, node);
363 Graphics-related methods
366 #ifndef SERVER // Only on client
368 u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir,
369 INodeDefManager *nodemgr)
371 return getFaceLight(daynight_ratio,
372 getNodeParentNoEx(p),
373 getNodeParentNoEx(p + face_dir),
379 Thread-safely updates the whole mesh of the mapblock.
380 NOTE: Prefer generating the mesh separately and then using
383 void updateMesh(u32 daynight_ratio);
385 // Replace the mesh with a new one
386 void replaceMesh(scene::SMesh *mesh_new);
389 // See comments in mapblock.cpp
390 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
391 bool remove_light=false, bool *black_air_left=NULL);
393 // Copies data to VoxelManipulator to getPosRelative()
394 void copyTo(VoxelManipulator &dst);
395 // Copies data from VoxelManipulator getPosRelative()
396 void copyFrom(VoxelManipulator &dst);
398 #ifndef SERVER // Only on client
400 Methods for setting temporary modifications to nodes for
403 returns true if the mod was different last time
405 bool setTempMod(v3s16 p, const NodeMod &mod)
407 /*dstream<<"setTempMod called on block"
408 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
409 <<", mod.type="<<mod.type
410 <<", mod.param="<<mod.param
412 JMutexAutoLock lock(m_temp_mods_mutex);
414 return m_temp_mods.set(p, mod);
416 // Returns true if there was one
417 bool getTempMod(v3s16 p, NodeMod *mod)
419 JMutexAutoLock lock(m_temp_mods_mutex);
421 return m_temp_mods.get(p, mod);
423 bool clearTempMod(v3s16 p)
425 JMutexAutoLock lock(m_temp_mods_mutex);
427 return m_temp_mods.clear(p);
431 JMutexAutoLock lock(m_temp_mods_mutex);
433 return m_temp_mods.clear();
435 void copyTempMods(NodeModMap &dst)
437 JMutexAutoLock lock(m_temp_mods_mutex);
438 m_temp_mods.copy(dst);
443 Update day-night lighting difference flag.
445 Sets m_day_night_differs to appropriate value.
447 These methods don't care about neighboring blocks.
448 It means that to know if a block really doesn't need a mesh
449 update between day and night, the neighboring blocks have
450 to be taken into account. Use Map::dayNightDiffed().
452 void updateDayNightDiff();
454 bool dayNightDiffed()
456 return m_day_night_differs;
464 Tries to measure ground level.
469 0...MAP_BLOCKSIZE-1 = ground level
471 s16 getGroundLevel(v2s16 p2d);
474 Timestamp (see m_timestamp)
475 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
477 void setTimestamp(u32 time)
480 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
482 void setTimestampNoChangedFlag(u32 time)
490 u32 getDiskTimestamp()
492 return m_disk_timestamp;
498 void resetUsageTimer()
502 void incrementUsageTimer(float dtime)
504 m_usage_timer += dtime;
508 return m_usage_timer;
515 // These don't write or read version by itself
516 // Set disk to true for on-disk format, false for over-the-network format
517 void serialize(std::ostream &os, u8 version, bool disk);
518 // If disk == true: In addition to doing other things, will add
519 // unknown blocks from id-name mapping to wndef
520 void deSerialize(std::istream &is, u8 version, bool disk);
527 void serialize_pre22(std::ostream &os, u8 version, bool disk);
528 void deSerialize_pre22(std::istream &is, u8 version, bool disk);
531 Used only internally, because changes can't be tracked
534 MapNode & getNodeRef(s16 x, s16 y, s16 z)
537 throw InvalidPositionException();
538 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
539 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
540 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
541 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
543 MapNode & getNodeRef(v3s16 &p)
545 return getNodeRef(p.X, p.Y, p.Z);
550 Public member variables
553 #ifndef SERVER // Only on client
558 NodeMetadataList *m_node_metadata;
559 StaticObjectList m_static_objects;
563 Private member variables
566 // NOTE: Lots of things rely on this being the Map
568 // Position in blocks on parent
574 If NULL, block is a dummy block.
575 Dummy blocks are used for caching not-found-on-disk blocks.
580 - On the server, this is used for telling whether the
581 block has been modified from the one on disk.
582 - On the client, this is used for nothing.
585 std::string m_modified_reason;
586 bool m_modified_reason_too_long;
589 When propagating sunlight and the above block doesn't exist,
590 sunlight is assumed if this is false.
592 In practice this is set to true if the block is completely
593 undeground with nothing visible above the ground except
599 Set to true if changes has been made that make the old lighting
600 values wrong but the lighting hasn't been actually updated.
602 If this is false, lighting is exactly right.
603 If this is true, lighting might be wrong or right.
605 bool m_lighting_expired;
607 // Whether day and night lighting differs
608 bool m_day_night_differs;
612 #ifndef SERVER // Only on client
614 Set to true if the mesh has been ordered to be updated
615 sometime in the background.
616 In practice this is set when the day/night lighting switches.
620 // Temporary modifications to nodes
621 // These are only used when drawing
622 NodeModMap m_temp_mods;
623 JMutex m_temp_mods_mutex;
627 When block is removed from active blocks, this is set to gametime.
628 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
631 // The on-disk (or to-be on-disk) timestamp value
632 u32 m_disk_timestamp;
635 When the block is accessed, this is set to 0.
636 Map will unload the block when this reaches a timeout.
641 inline bool blockpos_over_limit(v3s16 p)
644 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
645 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
646 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
647 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
648 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
649 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
653 Returns the position of the block where the node is located
655 inline v3s16 getNodeBlockPos(v3s16 p)
657 return getContainerPos(p, MAP_BLOCKSIZE);
660 inline v2s16 getNodeSectorPos(v2s16 p)
662 return getContainerPos(p, MAP_BLOCKSIZE);
665 inline s16 getNodeBlockY(s16 y)
667 return getContainerPos(y, MAP_BLOCKSIZE);
671 Get a quick string to describe what a block actually contains
673 std::string analyze_block(MapBlock *block);