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;
43 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
45 /*// Named by looking towards z+
57 // Has not been modified.
60 // Has been modified, and will be saved when being unloaded.
61 MOD_STATE_WRITE_AT_UNLOAD = 2,
63 // Has been modified, and will be saved as soon as possible.
64 MOD_STATE_WRITE_NEEDED = 4,
68 // NOTE: If this is enabled, set MapBlock to be initialized with
70 /*enum BlockGenerationStatus
72 // Completely non-generated (filled with CONTENT_IGNORE).
74 // Trees or similar might have been blitted from other blocks to here.
75 // Otherwise, the block contains CONTENT_IGNORE
76 BLOCKGEN_FROM_NEIGHBORS=2,
77 // Has been generated, but some neighbors might put some stuff in here
78 // when they are generated.
79 // Does not contain any CONTENT_IGNORE
80 BLOCKGEN_SELF_GENERATED=4,
81 // The block and all its neighbors have been generated
82 BLOCKGEN_FULLY_GENERATED=6
88 NODECONTAINER_ID_MAPBLOCK,
89 NODECONTAINER_ID_MAPSECTOR,
91 NODECONTAINER_ID_MAPBLOCKCACHE,
92 NODECONTAINER_ID_VOXELMANIPULATOR,
98 virtual bool isValidPosition(v3s16 p) = 0;
99 virtual MapNode getNode(v3s16 p) = 0;
100 virtual void setNode(v3s16 p, MapNode & n) = 0;
101 virtual u16 nodeContainerId() const = 0;
103 MapNode getNodeNoEx(v3s16 p)
108 catch(InvalidPositionException &e){
109 return MapNode(CONTENT_IGNORE);
119 class MapBlock /*: public NodeContainer*/
122 MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
125 /*virtual u16 nodeContainerId() const
127 return NODECONTAINER_ID_MAPBLOCK;
139 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
140 data = new MapNode[l];
141 for(u32 i=0; i<l; i++){
142 //data[i] = MapNode();
143 data[i] = MapNode(CONTENT_IGNORE);
145 raiseModified(MOD_STATE_WRITE_NEEDED);
154 return (data == NULL);
163 This is called internally or externally after the block is
164 modified, so that the block is saved and possibly not deleted from
167 // DEPRECATED, use *Modified()
168 void setChangedFlag()
170 //dstream<<"Deprecated setChangedFlag() called"<<std::endl;
171 raiseModified(MOD_STATE_WRITE_NEEDED);
173 // DEPRECATED, use *Modified()
174 void resetChangedFlag()
176 //dstream<<"Deprecated resetChangedFlag() called"<<std::endl;
179 // DEPRECATED, use *Modified()
180 bool getChangedFlag()
182 //dstream<<"Deprecated getChangedFlag() called"<<std::endl;
183 if(getModified() == MOD_STATE_CLEAN)
189 // m_modified methods
190 void raiseModified(u32 mod)
192 m_modified = MYMAX(m_modified, mod);
200 m_modified = MOD_STATE_CLEAN;
203 // is_underground getter/setter
204 bool getIsUnderground()
206 return is_underground;
208 void setIsUnderground(bool a_is_underground)
210 is_underground = a_is_underground;
211 raiseModified(MOD_STATE_WRITE_NEEDED);
215 void setMeshExpired(bool expired)
217 m_mesh_expired = expired;
220 bool getMeshExpired()
222 return m_mesh_expired;
226 void setLightingExpired(bool expired)
228 if(expired != m_lighting_expired){
229 m_lighting_expired = expired;
230 raiseModified(MOD_STATE_WRITE_NEEDED);
233 bool getLightingExpired()
235 return m_lighting_expired;
242 void setGenerated(bool b)
244 if(b != m_generated){
245 raiseModified(MOD_STATE_WRITE_NEEDED);
252 if(m_lighting_expired)
268 v3s16 getPosRelative()
270 return m_pos * MAP_BLOCKSIZE;
273 core::aabbox3d<s16> getBox()
275 return core::aabbox3d<s16>(getPosRelative(),
277 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
282 Regular MapNode get-setters
285 bool isValidPosition(v3s16 p)
289 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
290 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
291 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
294 MapNode getNode(s16 x, s16 y, s16 z)
297 throw InvalidPositionException();
298 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
299 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
300 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
301 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
304 MapNode getNode(v3s16 p)
306 return getNode(p.X, p.Y, p.Z);
309 MapNode getNodeNoEx(v3s16 p)
312 return getNode(p.X, p.Y, p.Z);
313 }catch(InvalidPositionException &e){
314 return MapNode(CONTENT_IGNORE);
318 void setNode(s16 x, s16 y, s16 z, MapNode & n)
321 throw InvalidPositionException();
322 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
323 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
324 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
325 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
326 raiseModified(MOD_STATE_WRITE_NEEDED);
329 void setNode(v3s16 p, MapNode & n)
331 setNode(p.X, p.Y, p.Z, n);
335 Non-checking variants of the above
338 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
341 throw InvalidPositionException();
342 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
345 MapNode getNodeNoCheck(v3s16 p)
347 return getNodeNoCheck(p.X, p.Y, p.Z);
350 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
353 throw InvalidPositionException();
354 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
355 raiseModified(MOD_STATE_WRITE_NEEDED);
358 void setNodeNoCheck(v3s16 p, MapNode & n)
360 setNodeNoCheck(p.X, p.Y, p.Z, n);
364 These functions consult the parent container if the position
365 is not valid on this MapBlock.
367 bool isValidPositionParent(v3s16 p);
368 MapNode getNodeParent(v3s16 p);
369 void setNodeParent(v3s16 p, MapNode & n);
370 MapNode getNodeParentNoEx(v3s16 p);
372 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
374 for(u16 z=0; z<d; z++)
375 for(u16 y=0; y<h; y++)
376 for(u16 x=0; x<w; x++)
377 setNode(x0+x, y0+y, z0+z, node);
381 Graphics-related methods
384 /*// A quick version with nodes passed as parameters
385 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
387 /*// A more convenient version
388 u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
390 return getFaceLight(daynight_ratio,
391 getNodeParentNoEx(p),
392 getNodeParentNoEx(p + face_dir),
395 u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir,
396 INodeDefManager *nodemgr)
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);
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);
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
596 If NULL, block is a dummy block.
597 Dummy blocks are used for caching not-found-on-disk blocks.
602 - On the server, this is used for telling whether the
603 block has been modified from the one on disk.
604 - On the client, this is used for nothing.
609 When propagating sunlight and the above block doesn't exist,
610 sunlight is assumed if this is false.
612 In practice this is set to true if the block is completely
613 undeground with nothing visible above the ground except
619 Set to true if changes has been made that make the old lighting
620 values wrong but the lighting hasn't been actually updated.
622 If this is false, lighting is exactly right.
623 If this is true, lighting might be wrong or right.
625 bool m_lighting_expired;
627 // Whether day and night lighting differs
628 bool m_day_night_differs;
632 #ifndef SERVER // Only on client
634 Set to true if the mesh has been ordered to be updated
635 sometime in the background.
636 In practice this is set when the day/night lighting switches.
640 // Temporary modifications to nodes
641 // These are only used when drawing
642 NodeModMap m_temp_mods;
643 JMutex m_temp_mods_mutex;
647 When block is removed from active blocks, this is set to gametime.
648 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
653 When the block is accessed, this is set to 0.
654 Map will unload the block when this reaches a timeout.
659 inline bool blockpos_over_limit(v3s16 p)
662 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
663 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
664 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
665 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
666 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
667 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
671 Returns the position of the block where the node is located
673 inline v3s16 getNodeBlockPos(v3s16 p)
675 return getContainerPos(p, MAP_BLOCKSIZE);
678 inline v2s16 getNodeSectorPos(v2s16 p)
680 return getContainerPos(p, MAP_BLOCKSIZE);
683 inline s16 getNodeBlockY(s16 y)
685 return getContainerPos(y, MAP_BLOCKSIZE);
689 Get a quick string to describe what a block actually contains
691 std::string analyze_block(MapBlock *block);