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 /*// A quick version with nodes passed as parameters
367 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
369 /*// A more convenient version
370 u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
372 return getFaceLight(daynight_ratio,
373 getNodeParentNoEx(p),
374 getNodeParentNoEx(p + face_dir),
377 u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir,
378 INodeDefManager *nodemgr)
380 return getFaceLight(daynight_ratio,
381 getNodeParentNoEx(p),
382 getNodeParentNoEx(p + face_dir),
386 #ifndef SERVER // Only on client
390 Thread-safely updates the whole mesh of the mapblock.
391 NOTE: Prefer generating the mesh separately and then using
394 void updateMesh(u32 daynight_ratio);
396 // Replace the mesh with a new one
397 void replaceMesh(scene::SMesh *mesh_new);
400 // See comments in mapblock.cpp
401 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
402 bool remove_light=false, bool *black_air_left=NULL);
404 // Copies data to VoxelManipulator to getPosRelative()
405 void copyTo(VoxelManipulator &dst);
406 // Copies data from VoxelManipulator getPosRelative()
407 void copyFrom(VoxelManipulator &dst);
409 #ifndef SERVER // Only on client
411 Methods for setting temporary modifications to nodes for
414 returns true if the mod was different last time
416 bool setTempMod(v3s16 p, const NodeMod &mod)
418 /*dstream<<"setTempMod called on block"
419 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
420 <<", mod.type="<<mod.type
421 <<", mod.param="<<mod.param
423 JMutexAutoLock lock(m_temp_mods_mutex);
425 return m_temp_mods.set(p, mod);
427 // Returns true if there was one
428 bool getTempMod(v3s16 p, NodeMod *mod)
430 JMutexAutoLock lock(m_temp_mods_mutex);
432 return m_temp_mods.get(p, mod);
434 bool clearTempMod(v3s16 p)
436 JMutexAutoLock lock(m_temp_mods_mutex);
438 return m_temp_mods.clear(p);
442 JMutexAutoLock lock(m_temp_mods_mutex);
444 return m_temp_mods.clear();
446 void copyTempMods(NodeModMap &dst)
448 JMutexAutoLock lock(m_temp_mods_mutex);
449 m_temp_mods.copy(dst);
454 Update day-night lighting difference flag.
456 Sets m_day_night_differs to appropriate value.
458 These methods don't care about neighboring blocks.
459 It means that to know if a block really doesn't need a mesh
460 update between day and night, the neighboring blocks have
461 to be taken into account. Use Map::dayNightDiffed().
463 void updateDayNightDiff();
465 bool dayNightDiffed()
467 return m_day_night_differs;
475 Tries to measure ground level.
480 0...MAP_BLOCKSIZE-1 = ground level
482 s16 getGroundLevel(v2s16 p2d);
485 Timestamp (see m_timestamp)
486 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
488 void setTimestamp(u32 time)
491 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
493 void setTimestampNoChangedFlag(u32 time)
501 u32 getDiskTimestamp()
503 return m_disk_timestamp;
509 void resetUsageTimer()
513 void incrementUsageTimer(float dtime)
515 m_usage_timer += dtime;
519 return m_usage_timer;
526 // These don't write or read version by itself
527 void serialize(std::ostream &os, u8 version);
528 void deSerialize(std::istream &is, u8 version);
530 // Used after the basic ones when writing on disk (serverside)
531 void serializeDiskExtra(std::ostream &os, u8 version);
532 // In addition to doing other things, will add unknown blocks from
533 // id-name mapping to wndef
534 void deSerializeDiskExtra(std::istream &is, u8 version);
542 Used only internally, because changes can't be tracked
545 MapNode & getNodeRef(s16 x, s16 y, s16 z)
548 throw InvalidPositionException();
549 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
550 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
551 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
552 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
554 MapNode & getNodeRef(v3s16 &p)
556 return getNodeRef(p.X, p.Y, p.Z);
561 Public member variables
564 #ifndef SERVER // Only on client
569 NodeMetadataList *m_node_metadata;
570 StaticObjectList m_static_objects;
574 Private member variables
577 // NOTE: Lots of things rely on this being the Map
579 // Position in blocks on parent
585 If NULL, block is a dummy block.
586 Dummy blocks are used for caching not-found-on-disk blocks.
591 - On the server, this is used for telling whether the
592 block has been modified from the one on disk.
593 - On the client, this is used for nothing.
596 std::string m_modified_reason;
597 bool m_modified_reason_too_long;
600 When propagating sunlight and the above block doesn't exist,
601 sunlight is assumed if this is false.
603 In practice this is set to true if the block is completely
604 undeground with nothing visible above the ground except
610 Set to true if changes has been made that make the old lighting
611 values wrong but the lighting hasn't been actually updated.
613 If this is false, lighting is exactly right.
614 If this is true, lighting might be wrong or right.
616 bool m_lighting_expired;
618 // Whether day and night lighting differs
619 bool m_day_night_differs;
623 #ifndef SERVER // Only on client
625 Set to true if the mesh has been ordered to be updated
626 sometime in the background.
627 In practice this is set when the day/night lighting switches.
631 // Temporary modifications to nodes
632 // These are only used when drawing
633 NodeModMap m_temp_mods;
634 JMutex m_temp_mods_mutex;
638 When block is removed from active blocks, this is set to gametime.
639 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
642 // The on-disk (or to-be on-disk) timestamp value
643 u32 m_disk_timestamp;
646 When the block is accessed, this is set to 0.
647 Map will unload the block when this reaches a timeout.
652 inline bool blockpos_over_limit(v3s16 p)
655 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
656 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
657 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
658 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
659 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
660 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
664 Returns the position of the block where the node is located
666 inline v3s16 getNodeBlockPos(v3s16 p)
668 return getContainerPos(p, MAP_BLOCKSIZE);
671 inline v2s16 getNodeSectorPos(v2s16 p)
673 return getContainerPos(p, MAP_BLOCKSIZE);
676 inline s16 getNodeBlockY(s16 y)
678 return getContainerPos(y, MAP_BLOCKSIZE);
682 Get a quick string to describe what a block actually contains
684 std::string analyze_block(MapBlock *block);