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"
36 #include "mapblock_mesh.h"
38 #include "modifiedstate.h"
41 class NodeMetadataList;
43 class IWritableNodeDefManager;
45 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
47 /*// Named by looking towards z+
57 // NOTE: If this is enabled, set MapBlock to be initialized with
59 /*enum BlockGenerationStatus
61 // Completely non-generated (filled with CONTENT_IGNORE).
63 // Trees or similar might have been blitted from other blocks to here.
64 // Otherwise, the block contains CONTENT_IGNORE
65 BLOCKGEN_FROM_NEIGHBORS=2,
66 // Has been generated, but some neighbors might put some stuff in here
67 // when they are generated.
68 // Does not contain any CONTENT_IGNORE
69 BLOCKGEN_SELF_GENERATED=4,
70 // The block and all its neighbors have been generated
71 BLOCKGEN_FULLY_GENERATED=6
77 NODECONTAINER_ID_MAPBLOCK,
78 NODECONTAINER_ID_MAPSECTOR,
80 NODECONTAINER_ID_MAPBLOCKCACHE,
81 NODECONTAINER_ID_VOXELMANIPULATOR,
87 virtual bool isValidPosition(v3s16 p) = 0;
88 virtual MapNode getNode(v3s16 p) = 0;
89 virtual void setNode(v3s16 p, MapNode & n) = 0;
90 virtual u16 nodeContainerId() const = 0;
92 MapNode getNodeNoEx(v3s16 p)
97 catch(InvalidPositionException &e){
98 return MapNode(CONTENT_IGNORE);
108 class MapBlock /*: public NodeContainer*/
111 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
114 /*virtual u16 nodeContainerId() const
116 return NODECONTAINER_ID_MAPBLOCK;
128 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
129 data = new MapNode[l];
130 for(u32 i=0; i<l; i++){
131 //data[i] = MapNode();
132 data[i] = MapNode(CONTENT_IGNORE);
134 raiseModified(MOD_STATE_WRITE_NEEDED, "reallocate");
143 return (data == NULL);
151 // m_modified methods
152 void raiseModified(u32 mod, const std::string &reason="unknown")
154 if(mod > m_modified){
156 m_modified_reason = reason;
157 m_modified_reason_too_long = false;
159 if(m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
160 m_disk_timestamp = m_timestamp;
162 } else if(mod == m_modified){
163 if(!m_modified_reason_too_long){
164 if(m_modified_reason.size() < 40)
165 m_modified_reason += ", " + reason;
167 m_modified_reason += "...";
168 m_modified_reason_too_long = true;
177 std::string getModifiedReason()
179 return m_modified_reason;
183 m_modified = MOD_STATE_CLEAN;
184 m_modified_reason = "none";
185 m_modified_reason_too_long = false;
188 // is_underground getter/setter
189 bool getIsUnderground()
191 return is_underground;
193 void setIsUnderground(bool a_is_underground)
195 is_underground = a_is_underground;
196 raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
200 void setMeshExpired(bool expired)
202 m_mesh_expired = expired;
205 bool getMeshExpired()
207 return m_mesh_expired;
211 void setLightingExpired(bool expired)
213 if(expired != m_lighting_expired){
214 m_lighting_expired = expired;
215 raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
218 bool getLightingExpired()
220 return m_lighting_expired;
227 void setGenerated(bool b)
229 if(b != m_generated){
230 raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
237 if(m_lighting_expired)
253 v3s16 getPosRelative()
255 return m_pos * MAP_BLOCKSIZE;
258 core::aabbox3d<s16> getBox()
260 return core::aabbox3d<s16>(getPosRelative(),
262 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
267 Regular MapNode get-setters
270 bool isValidPosition(v3s16 p)
274 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
275 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
276 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
279 MapNode getNode(s16 x, s16 y, s16 z)
282 throw InvalidPositionException();
283 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
284 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
285 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
286 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
289 MapNode getNode(v3s16 p)
291 return getNode(p.X, p.Y, p.Z);
294 MapNode getNodeNoEx(v3s16 p)
297 return getNode(p.X, p.Y, p.Z);
298 }catch(InvalidPositionException &e){
299 return MapNode(CONTENT_IGNORE);
303 void setNode(s16 x, s16 y, s16 z, MapNode & n)
306 throw InvalidPositionException();
307 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
308 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
309 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
310 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
311 raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
314 void setNode(v3s16 p, MapNode & n)
316 setNode(p.X, p.Y, p.Z, n);
320 Non-checking variants of the above
323 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
326 throw InvalidPositionException();
327 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
330 MapNode getNodeNoCheck(v3s16 p)
332 return getNodeNoCheck(p.X, p.Y, p.Z);
335 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
338 throw InvalidPositionException();
339 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
340 raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
343 void setNodeNoCheck(v3s16 p, MapNode & n)
345 setNodeNoCheck(p.X, p.Y, p.Z, n);
349 These functions consult the parent container if the position
350 is not valid on this MapBlock.
352 bool isValidPositionParent(v3s16 p);
353 MapNode getNodeParent(v3s16 p);
354 void setNodeParent(v3s16 p, MapNode & n);
355 MapNode getNodeParentNoEx(v3s16 p);
357 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
359 for(u16 z=0; z<d; z++)
360 for(u16 y=0; y<h; y++)
361 for(u16 x=0; x<w; x++)
362 setNode(x0+x, y0+y, z0+z, node);
366 Graphics-related methods
369 /*// A quick version with nodes passed as parameters
370 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
372 /*// A more convenient version
373 u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
375 return getFaceLight(daynight_ratio,
376 getNodeParentNoEx(p),
377 getNodeParentNoEx(p + face_dir),
380 u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir,
381 INodeDefManager *nodemgr)
383 return getFaceLight(daynight_ratio,
384 getNodeParentNoEx(p),
385 getNodeParentNoEx(p + face_dir),
389 #ifndef SERVER // Only on client
393 Thread-safely updates the whole mesh of the mapblock.
394 NOTE: Prefer generating the mesh separately and then using
397 void updateMesh(u32 daynight_ratio);
399 // Replace the mesh with a new one
400 void replaceMesh(scene::SMesh *mesh_new);
403 // See comments in mapblock.cpp
404 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
405 bool remove_light=false, bool *black_air_left=NULL);
407 // Copies data to VoxelManipulator to getPosRelative()
408 void copyTo(VoxelManipulator &dst);
409 // Copies data from VoxelManipulator getPosRelative()
410 void copyFrom(VoxelManipulator &dst);
412 #ifndef SERVER // Only on client
414 Methods for setting temporary modifications to nodes for
417 returns true if the mod was different last time
419 bool setTempMod(v3s16 p, const NodeMod &mod)
421 /*dstream<<"setTempMod called on block"
422 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
423 <<", mod.type="<<mod.type
424 <<", mod.param="<<mod.param
426 JMutexAutoLock lock(m_temp_mods_mutex);
428 return m_temp_mods.set(p, mod);
430 // Returns true if there was one
431 bool getTempMod(v3s16 p, NodeMod *mod)
433 JMutexAutoLock lock(m_temp_mods_mutex);
435 return m_temp_mods.get(p, mod);
437 bool clearTempMod(v3s16 p)
439 JMutexAutoLock lock(m_temp_mods_mutex);
441 return m_temp_mods.clear(p);
445 JMutexAutoLock lock(m_temp_mods_mutex);
447 return m_temp_mods.clear();
449 void copyTempMods(NodeModMap &dst)
451 JMutexAutoLock lock(m_temp_mods_mutex);
452 m_temp_mods.copy(dst);
457 Update day-night lighting difference flag.
459 Sets m_day_night_differs to appropriate value.
461 These methods don't care about neighboring blocks.
462 It means that to know if a block really doesn't need a mesh
463 update between day and night, the neighboring blocks have
464 to be taken into account. Use Map::dayNightDiffed().
466 void updateDayNightDiff();
468 bool dayNightDiffed()
470 return m_day_night_differs;
478 Tries to measure ground level.
483 0...MAP_BLOCKSIZE-1 = ground level
485 s16 getGroundLevel(v2s16 p2d);
488 Timestamp (see m_timestamp)
489 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
491 void setTimestamp(u32 time)
494 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
496 void setTimestampNoChangedFlag(u32 time)
504 u32 getDiskTimestamp()
506 return m_disk_timestamp;
512 void resetUsageTimer()
516 void incrementUsageTimer(float dtime)
518 m_usage_timer += dtime;
522 return m_usage_timer;
529 // These don't write or read version by itself
530 void serialize(std::ostream &os, u8 version);
531 void deSerialize(std::istream &is, u8 version);
533 // Used after the basic ones when writing on disk (serverside)
534 void serializeDiskExtra(std::ostream &os, u8 version);
535 // In addition to doing other things, will add unknown blocks from
536 // id-name mapping to wndef
537 void deSerializeDiskExtra(std::istream &is, u8 version);
545 Used only internally, because changes can't be tracked
548 MapNode & getNodeRef(s16 x, s16 y, s16 z)
551 throw InvalidPositionException();
552 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
553 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
554 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
555 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
557 MapNode & getNodeRef(v3s16 &p)
559 return getNodeRef(p.X, p.Y, p.Z);
564 Public member variables
567 #ifndef SERVER // Only on client
572 NodeMetadataList *m_node_metadata;
573 StaticObjectList m_static_objects;
577 Private member variables
580 // NOTE: Lots of things rely on this being the Map
582 // Position in blocks on parent
588 If NULL, block is a dummy block.
589 Dummy blocks are used for caching not-found-on-disk blocks.
594 - On the server, this is used for telling whether the
595 block has been modified from the one on disk.
596 - On the client, this is used for nothing.
599 std::string m_modified_reason;
600 bool m_modified_reason_too_long;
603 When propagating sunlight and the above block doesn't exist,
604 sunlight is assumed if this is false.
606 In practice this is set to true if the block is completely
607 undeground with nothing visible above the ground except
613 Set to true if changes has been made that make the old lighting
614 values wrong but the lighting hasn't been actually updated.
616 If this is false, lighting is exactly right.
617 If this is true, lighting might be wrong or right.
619 bool m_lighting_expired;
621 // Whether day and night lighting differs
622 bool m_day_night_differs;
626 #ifndef SERVER // Only on client
628 Set to true if the mesh has been ordered to be updated
629 sometime in the background.
630 In practice this is set when the day/night lighting switches.
634 // Temporary modifications to nodes
635 // These are only used when drawing
636 NodeModMap m_temp_mods;
637 JMutex m_temp_mods_mutex;
641 When block is removed from active blocks, this is set to gametime.
642 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
645 // The on-disk (or to-be on-disk) timestamp value
646 u32 m_disk_timestamp;
649 When the block is accessed, this is set to 0.
650 Map will unload the block when this reaches a timeout.
655 inline bool blockpos_over_limit(v3s16 p)
658 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
659 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
660 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
661 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
662 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
663 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
667 Returns the position of the block where the node is located
669 inline v3s16 getNodeBlockPos(v3s16 p)
671 return getContainerPos(p, MAP_BLOCKSIZE);
674 inline v2s16 getNodeSectorPos(v2s16 p)
676 return getContainerPos(p, MAP_BLOCKSIZE);
679 inline s16 getNodeBlockY(s16 y)
681 return getContainerPos(y, MAP_BLOCKSIZE);
685 Get a quick string to describe what a block actually contains
687 std::string analyze_block(MapBlock *block);