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"
40 class NodeMetadataList;
42 class IWritableNodeDefManager;
44 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
46 /*// Named by looking towards z+
58 // Has not been modified.
61 // Has been modified, and will be saved when being unloaded.
62 MOD_STATE_WRITE_AT_UNLOAD = 2,
64 // Has been modified, and will be saved as soon as possible.
65 MOD_STATE_WRITE_NEEDED = 4,
69 // NOTE: If this is enabled, set MapBlock to be initialized with
71 /*enum BlockGenerationStatus
73 // Completely non-generated (filled with CONTENT_IGNORE).
75 // Trees or similar might have been blitted from other blocks to here.
76 // Otherwise, the block contains CONTENT_IGNORE
77 BLOCKGEN_FROM_NEIGHBORS=2,
78 // Has been generated, but some neighbors might put some stuff in here
79 // when they are generated.
80 // Does not contain any CONTENT_IGNORE
81 BLOCKGEN_SELF_GENERATED=4,
82 // The block and all its neighbors have been generated
83 BLOCKGEN_FULLY_GENERATED=6
89 NODECONTAINER_ID_MAPBLOCK,
90 NODECONTAINER_ID_MAPSECTOR,
92 NODECONTAINER_ID_MAPBLOCKCACHE,
93 NODECONTAINER_ID_VOXELMANIPULATOR,
99 virtual bool isValidPosition(v3s16 p) = 0;
100 virtual MapNode getNode(v3s16 p) = 0;
101 virtual void setNode(v3s16 p, MapNode & n) = 0;
102 virtual u16 nodeContainerId() const = 0;
104 MapNode getNodeNoEx(v3s16 p)
109 catch(InvalidPositionException &e){
110 return MapNode(CONTENT_IGNORE);
120 class MapBlock /*: public NodeContainer*/
123 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
126 /*virtual u16 nodeContainerId() const
128 return NODECONTAINER_ID_MAPBLOCK;
140 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
141 data = new MapNode[l];
142 for(u32 i=0; i<l; i++){
143 //data[i] = MapNode();
144 data[i] = MapNode(CONTENT_IGNORE);
146 raiseModified(MOD_STATE_WRITE_NEEDED);
155 return (data == NULL);
164 This is called internally or externally after the block is
165 modified, so that the block is saved and possibly not deleted from
168 // DEPRECATED, use *Modified()
169 void setChangedFlag()
171 //dstream<<"Deprecated setChangedFlag() called"<<std::endl;
172 raiseModified(MOD_STATE_WRITE_NEEDED);
174 // DEPRECATED, use *Modified()
175 void resetChangedFlag()
177 //dstream<<"Deprecated resetChangedFlag() called"<<std::endl;
180 // DEPRECATED, use *Modified()
181 bool getChangedFlag()
183 //dstream<<"Deprecated getChangedFlag() called"<<std::endl;
184 if(getModified() == MOD_STATE_CLEAN)
190 // m_modified methods
191 void raiseModified(u32 mod)
193 m_modified = MYMAX(m_modified, mod);
201 m_modified = MOD_STATE_CLEAN;
204 // is_underground getter/setter
205 bool getIsUnderground()
207 return is_underground;
209 void setIsUnderground(bool a_is_underground)
211 is_underground = a_is_underground;
212 raiseModified(MOD_STATE_WRITE_NEEDED);
216 void setMeshExpired(bool expired)
218 m_mesh_expired = expired;
221 bool getMeshExpired()
223 return m_mesh_expired;
227 void setLightingExpired(bool expired)
229 if(expired != m_lighting_expired){
230 m_lighting_expired = expired;
231 raiseModified(MOD_STATE_WRITE_NEEDED);
234 bool getLightingExpired()
236 return m_lighting_expired;
243 void setGenerated(bool b)
245 if(b != m_generated){
246 raiseModified(MOD_STATE_WRITE_NEEDED);
253 if(m_lighting_expired)
269 v3s16 getPosRelative()
271 return m_pos * MAP_BLOCKSIZE;
274 core::aabbox3d<s16> getBox()
276 return core::aabbox3d<s16>(getPosRelative(),
278 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
283 Regular MapNode get-setters
286 bool isValidPosition(v3s16 p)
290 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
291 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
292 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
295 MapNode getNode(s16 x, s16 y, s16 z)
298 throw InvalidPositionException();
299 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
300 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
301 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
302 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
305 MapNode getNode(v3s16 p)
307 return getNode(p.X, p.Y, p.Z);
310 MapNode getNodeNoEx(v3s16 p)
313 return getNode(p.X, p.Y, p.Z);
314 }catch(InvalidPositionException &e){
315 return MapNode(CONTENT_IGNORE);
319 void setNode(s16 x, s16 y, s16 z, MapNode & n)
322 throw InvalidPositionException();
323 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
324 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
325 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
326 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
327 raiseModified(MOD_STATE_WRITE_NEEDED);
330 void setNode(v3s16 p, MapNode & n)
332 setNode(p.X, p.Y, p.Z, n);
336 Non-checking variants of the above
339 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
342 throw InvalidPositionException();
343 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
346 MapNode getNodeNoCheck(v3s16 p)
348 return getNodeNoCheck(p.X, p.Y, p.Z);
351 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
354 throw InvalidPositionException();
355 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
356 raiseModified(MOD_STATE_WRITE_NEEDED);
359 void setNodeNoCheck(v3s16 p, MapNode & n)
361 setNodeNoCheck(p.X, p.Y, p.Z, n);
365 These functions consult the parent container if the position
366 is not valid on this MapBlock.
368 bool isValidPositionParent(v3s16 p);
369 MapNode getNodeParent(v3s16 p);
370 void setNodeParent(v3s16 p, MapNode & n);
371 MapNode getNodeParentNoEx(v3s16 p);
373 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
375 for(u16 z=0; z<d; z++)
376 for(u16 y=0; y<h; y++)
377 for(u16 x=0; x<w; x++)
378 setNode(x0+x, y0+y, z0+z, node);
382 Graphics-related methods
385 /*// A quick version with nodes passed as parameters
386 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
388 /*// A more convenient version
389 u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
391 return getFaceLight(daynight_ratio,
392 getNodeParentNoEx(p),
393 getNodeParentNoEx(p + face_dir),
396 u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir,
397 INodeDefManager *nodemgr)
399 return getFaceLight(daynight_ratio,
400 getNodeParentNoEx(p),
401 getNodeParentNoEx(p + face_dir),
405 #ifndef SERVER // Only on client
409 Thread-safely updates the whole mesh of the mapblock.
410 NOTE: Prefer generating the mesh separately and then using
413 void updateMesh(u32 daynight_ratio);
415 // Replace the mesh with a new one
416 void replaceMesh(scene::SMesh *mesh_new);
419 // See comments in mapblock.cpp
420 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
421 bool remove_light=false, bool *black_air_left=NULL);
423 // Copies data to VoxelManipulator to getPosRelative()
424 void copyTo(VoxelManipulator &dst);
425 // Copies data from VoxelManipulator getPosRelative()
426 void copyFrom(VoxelManipulator &dst);
428 #ifndef SERVER // Only on client
430 Methods for setting temporary modifications to nodes for
433 returns true if the mod was different last time
435 bool setTempMod(v3s16 p, const NodeMod &mod)
437 /*dstream<<"setTempMod called on block"
438 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
439 <<", mod.type="<<mod.type
440 <<", mod.param="<<mod.param
442 JMutexAutoLock lock(m_temp_mods_mutex);
444 return m_temp_mods.set(p, mod);
446 // Returns true if there was one
447 bool getTempMod(v3s16 p, NodeMod *mod)
449 JMutexAutoLock lock(m_temp_mods_mutex);
451 return m_temp_mods.get(p, mod);
453 bool clearTempMod(v3s16 p)
455 JMutexAutoLock lock(m_temp_mods_mutex);
457 return m_temp_mods.clear(p);
461 JMutexAutoLock lock(m_temp_mods_mutex);
463 return m_temp_mods.clear();
465 void copyTempMods(NodeModMap &dst)
467 JMutexAutoLock lock(m_temp_mods_mutex);
468 m_temp_mods.copy(dst);
473 Update day-night lighting difference flag.
475 Sets m_day_night_differs to appropriate value.
477 These methods don't care about neighboring blocks.
478 It means that to know if a block really doesn't need a mesh
479 update between day and night, the neighboring blocks have
480 to be taken into account. Use Map::dayNightDiffed().
482 void updateDayNightDiff();
484 bool dayNightDiffed()
486 return m_day_night_differs;
494 Tries to measure ground level.
499 0...MAP_BLOCKSIZE-1 = ground level
501 s16 getGroundLevel(v2s16 p2d);
504 Timestamp (see m_timestamp)
505 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
507 void setTimestamp(u32 time)
510 raiseModified(MOD_STATE_WRITE_AT_UNLOAD);
512 void setTimestampNoChangedFlag(u32 time)
524 void resetUsageTimer()
528 void incrementUsageTimer(float dtime)
530 m_usage_timer += dtime;
534 return m_usage_timer;
541 // These don't write or read version by itself
542 void serialize(std::ostream &os, u8 version);
543 void deSerialize(std::istream &is, u8 version);
545 // Used after the basic ones when writing on disk (serverside)
546 void serializeDiskExtra(std::ostream &os, u8 version);
547 // In addition to doing other things, will add unknown blocks from
548 // id-name mapping to wndef
549 void deSerializeDiskExtra(std::istream &is, u8 version);
557 Used only internally, because changes can't be tracked
560 MapNode & getNodeRef(s16 x, s16 y, s16 z)
563 throw InvalidPositionException();
564 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
565 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
566 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
567 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
569 MapNode & getNodeRef(v3s16 &p)
571 return getNodeRef(p.X, p.Y, p.Z);
576 Public member variables
579 #ifndef SERVER // Only on client
584 NodeMetadataList *m_node_metadata;
585 StaticObjectList m_static_objects;
589 Private member variables
592 // NOTE: Lots of things rely on this being the Map
594 // Position in blocks on parent
600 If NULL, block is a dummy block.
601 Dummy blocks are used for caching not-found-on-disk blocks.
606 - On the server, this is used for telling whether the
607 block has been modified from the one on disk.
608 - On the client, this is used for nothing.
613 When propagating sunlight and the above block doesn't exist,
614 sunlight is assumed if this is false.
616 In practice this is set to true if the block is completely
617 undeground with nothing visible above the ground except
623 Set to true if changes has been made that make the old lighting
624 values wrong but the lighting hasn't been actually updated.
626 If this is false, lighting is exactly right.
627 If this is true, lighting might be wrong or right.
629 bool m_lighting_expired;
631 // Whether day and night lighting differs
632 bool m_day_night_differs;
636 #ifndef SERVER // Only on client
638 Set to true if the mesh has been ordered to be updated
639 sometime in the background.
640 In practice this is set when the day/night lighting switches.
644 // Temporary modifications to nodes
645 // These are only used when drawing
646 NodeModMap m_temp_mods;
647 JMutex m_temp_mods_mutex;
651 When block is removed from active blocks, this is set to gametime.
652 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
657 When the block is accessed, this is set to 0.
658 Map will unload the block when this reaches a timeout.
663 inline bool blockpos_over_limit(v3s16 p)
666 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
667 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
668 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
669 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
670 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
671 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
675 Returns the position of the block where the node is located
677 inline v3s16 getNodeBlockPos(v3s16 p)
679 return getContainerPos(p, MAP_BLOCKSIZE);
682 inline v2s16 getNodeSectorPos(v2s16 p)
684 return getContainerPos(p, MAP_BLOCKSIZE);
687 inline s16 getNodeBlockY(s16 y)
689 return getContainerPos(y, MAP_BLOCKSIZE);
693 Get a quick string to describe what a block actually contains
695 std::string analyze_block(MapBlock *block);