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;
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, 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)
398 return getFaceLight(daynight_ratio,
399 getNodeParentNoEx(p),
400 getNodeParentNoEx(p + face_dir),
404 #ifndef SERVER // Only on client
408 Thread-safely updates the whole mesh of the mapblock.
409 NOTE: Prefer generating the mesh separately and then using
412 void updateMesh(u32 daynight_ratio, ITextureSource *tsrc);
414 // Replace the mesh with a new one
415 void replaceMesh(scene::SMesh *mesh_new);
418 // See comments in mapblock.cpp
419 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
420 bool remove_light=false, bool *black_air_left=NULL);
422 // Copies data to VoxelManipulator to getPosRelative()
423 void copyTo(VoxelManipulator &dst);
424 // Copies data from VoxelManipulator getPosRelative()
425 void copyFrom(VoxelManipulator &dst);
427 #ifndef SERVER // Only on client
429 Methods for setting temporary modifications to nodes for
432 returns true if the mod was different last time
434 bool setTempMod(v3s16 p, const NodeMod &mod)
436 /*dstream<<"setTempMod called on block"
437 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
438 <<", mod.type="<<mod.type
439 <<", mod.param="<<mod.param
441 JMutexAutoLock lock(m_temp_mods_mutex);
443 return m_temp_mods.set(p, mod);
445 // Returns true if there was one
446 bool getTempMod(v3s16 p, NodeMod *mod)
448 JMutexAutoLock lock(m_temp_mods_mutex);
450 return m_temp_mods.get(p, mod);
452 bool clearTempMod(v3s16 p)
454 JMutexAutoLock lock(m_temp_mods_mutex);
456 return m_temp_mods.clear(p);
460 JMutexAutoLock lock(m_temp_mods_mutex);
462 return m_temp_mods.clear();
464 void copyTempMods(NodeModMap &dst)
466 JMutexAutoLock lock(m_temp_mods_mutex);
467 m_temp_mods.copy(dst);
472 Update day-night lighting difference flag.
474 Sets m_day_night_differs to appropriate value.
476 These methods don't care about neighboring blocks.
477 It means that to know if a block really doesn't need a mesh
478 update between day and night, the neighboring blocks have
479 to be taken into account. Use Map::dayNightDiffed().
481 void updateDayNightDiff();
483 bool dayNightDiffed()
485 return m_day_night_differs;
493 Tries to measure ground level.
498 0...MAP_BLOCKSIZE-1 = ground level
500 s16 getGroundLevel(v2s16 p2d);
503 Timestamp (see m_timestamp)
504 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
506 void setTimestamp(u32 time)
509 raiseModified(MOD_STATE_WRITE_AT_UNLOAD);
511 void setTimestampNoChangedFlag(u32 time)
523 void resetUsageTimer()
527 void incrementUsageTimer(float dtime)
529 m_usage_timer += dtime;
533 return m_usage_timer;
540 // These don't write or read version by itself
541 void serialize(std::ostream &os, u8 version);
542 void deSerialize(std::istream &is, u8 version, IGameDef *gamedef);
543 // Used after the basic ones when writing on disk (serverside)
544 void serializeDiskExtra(std::ostream &os, u8 version);
545 void deSerializeDiskExtra(std::istream &is, u8 version);
553 Used only internally, because changes can't be tracked
556 MapNode & getNodeRef(s16 x, s16 y, s16 z)
559 throw InvalidPositionException();
560 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
561 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
562 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
563 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
565 MapNode & getNodeRef(v3s16 &p)
567 return getNodeRef(p.X, p.Y, p.Z);
572 Public member variables
575 #ifndef SERVER // Only on client
580 NodeMetadataList *m_node_metadata;
581 StaticObjectList m_static_objects;
585 Private member variables
588 // NOTE: Lots of things rely on this being the Map
590 // Position in blocks on parent
594 If NULL, block is a dummy block.
595 Dummy blocks are used for caching not-found-on-disk blocks.
600 - On the server, this is used for telling whether the
601 block has been modified from the one on disk.
602 - On the client, this is used for nothing.
607 When propagating sunlight and the above block doesn't exist,
608 sunlight is assumed if this is false.
610 In practice this is set to true if the block is completely
611 undeground with nothing visible above the ground except
617 Set to true if changes has been made that make the old lighting
618 values wrong but the lighting hasn't been actually updated.
620 If this is false, lighting is exactly right.
621 If this is true, lighting might be wrong or right.
623 bool m_lighting_expired;
625 // Whether day and night lighting differs
626 bool m_day_night_differs;
630 #ifndef SERVER // Only on client
632 Set to true if the mesh has been ordered to be updated
633 sometime in the background.
634 In practice this is set when the day/night lighting switches.
638 // Temporary modifications to nodes
639 // These are only used when drawing
640 NodeModMap m_temp_mods;
641 JMutex m_temp_mods_mutex;
645 When block is removed from active blocks, this is set to gametime.
646 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
651 When the block is accessed, this is set to 0.
652 Map will unload the block when this reaches a timeout.
657 inline bool blockpos_over_limit(v3s16 p)
660 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
661 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
662 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
663 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
664 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
665 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
669 Returns the position of the block where the node is located
671 inline v3s16 getNodeBlockPos(v3s16 p)
673 return getContainerPos(p, MAP_BLOCKSIZE);
676 inline v2s16 getNodeSectorPos(v2s16 p)
678 return getContainerPos(p, MAP_BLOCKSIZE);
681 inline s16 getNodeBlockY(s16 y)
683 return getContainerPos(y, MAP_BLOCKSIZE);
687 Get a quick string to describe what a block actually contains
689 std::string analyze_block(MapBlock *block);