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"
32 #include "mapblockobject.h"
34 #include "nodemetadata.h"
35 #include "staticobject.h"
36 #include "mapblock_nodemod.h"
38 #include "mapblock_mesh.h"
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, 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)
397 return getFaceLight(daynight_ratio,
398 getNodeParentNoEx(p),
399 getNodeParentNoEx(p + face_dir),
403 #ifndef SERVER // Only on client
407 Thread-safely updates the whole mesh of the mapblock.
408 NOTE: Prefer generating the mesh separately and then using
411 void updateMesh(u32 daynight_ratio);
413 // Replace the mesh with a new one
414 void replaceMesh(scene::SMesh *mesh_new);
417 // See comments in mapblock.cpp
418 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
419 bool remove_light=false, bool *black_air_left=NULL);
421 // Copies data to VoxelManipulator to getPosRelative()
422 void copyTo(VoxelManipulator &dst);
423 // Copies data from VoxelManipulator getPosRelative()
424 void copyFrom(VoxelManipulator &dst);
431 /*void serializeObjects(std::ostream &os, u8 version)
433 m_objects.serialize(os, version);
435 // If smgr!=NULL, new objects are added to the scene
436 void updateObjects(std::istream &is, u8 version,
437 scene::ISceneManager *smgr, u32 daynight_ratio)
439 m_objects.update(is, version, smgr, daynight_ratio);
441 raiseModified(MOD_STATE_WRITE_NEEDED);
447 raiseModified(MOD_STATE_WRITE_NEEDED);
449 void addObject(MapBlockObject *object)
450 throw(ContainerFullException, AlreadyExistsException)
452 m_objects.add(object);
454 raiseModified(MOD_STATE_WRITE_NEEDED);
456 void removeObject(s16 id)
458 m_objects.remove(id);
460 raiseModified(MOD_STATE_WRITE_NEEDED);
462 MapBlockObject * getObject(s16 id)
464 return m_objects.get(id);
466 JMutexAutoLock * getObjectLock()
468 return m_objects.getLock();
472 Moves objects, deletes objects and spawns new objects
474 void stepObjects(float dtime, bool server, u32 daynight_ratio);
476 // origin is relative to block
477 void getObjects(v3f origin, f32 max_d,
478 core::array<DistanceSortedObject> &dest)
480 m_objects.getObjects(origin, max_d, dest);
485 return m_objects.getCount();
488 #ifndef SERVER // Only on client
490 Methods for setting temporary modifications to nodes for
493 returns true if the mod was different last time
495 bool setTempMod(v3s16 p, const NodeMod &mod)
497 /*dstream<<"setTempMod called on block"
498 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
499 <<", mod.type="<<mod.type
500 <<", mod.param="<<mod.param
502 JMutexAutoLock lock(m_temp_mods_mutex);
504 return m_temp_mods.set(p, mod);
506 // Returns true if there was one
507 bool getTempMod(v3s16 p, NodeMod *mod)
509 JMutexAutoLock lock(m_temp_mods_mutex);
511 return m_temp_mods.get(p, mod);
513 bool clearTempMod(v3s16 p)
515 JMutexAutoLock lock(m_temp_mods_mutex);
517 return m_temp_mods.clear(p);
521 JMutexAutoLock lock(m_temp_mods_mutex);
523 return m_temp_mods.clear();
525 void copyTempMods(NodeModMap &dst)
527 JMutexAutoLock lock(m_temp_mods_mutex);
528 m_temp_mods.copy(dst);
533 Update day-night lighting difference flag.
535 Sets m_day_night_differs to appropriate value.
537 These methods don't care about neighboring blocks.
538 It means that to know if a block really doesn't need a mesh
539 update between day and night, the neighboring blocks have
540 to be taken into account. Use Map::dayNightDiffed().
542 void updateDayNightDiff();
544 bool dayNightDiffed()
546 return m_day_night_differs;
554 Tries to measure ground level.
559 0...MAP_BLOCKSIZE-1 = ground level
561 s16 getGroundLevel(v2s16 p2d);
564 Timestamp (see m_timestamp)
565 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
567 void setTimestamp(u32 time)
570 raiseModified(MOD_STATE_WRITE_AT_UNLOAD);
572 void setTimestampNoChangedFlag(u32 time)
584 void resetUsageTimer()
588 void incrementUsageTimer(float dtime)
590 m_usage_timer += dtime;
594 return m_usage_timer;
601 // These don't write or read version by itself
602 void serialize(std::ostream &os, u8 version);
603 void deSerialize(std::istream &is, u8 version);
604 // Used after the basic ones when writing on disk (serverside)
605 void serializeDiskExtra(std::ostream &os, u8 version);
606 void deSerializeDiskExtra(std::istream &is, u8 version);
614 Used only internally, because changes can't be tracked
617 MapNode & getNodeRef(s16 x, s16 y, s16 z)
620 throw InvalidPositionException();
621 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
622 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
623 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
624 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
626 MapNode & getNodeRef(v3s16 &p)
628 return getNodeRef(p.X, p.Y, p.Z);
633 Public member variables
636 #ifndef SERVER // Only on client
641 NodeMetadataList m_node_metadata;
642 StaticObjectList m_static_objects;
646 Private member variables
649 // NOTE: Lots of things rely on this being the Map
651 // Position in blocks on parent
655 If NULL, block is a dummy block.
656 Dummy blocks are used for caching not-found-on-disk blocks.
661 - On the server, this is used for telling whether the
662 block has been modified from the one on disk.
663 - On the client, this is used for nothing.
668 When propagating sunlight and the above block doesn't exist,
669 sunlight is assumed if this is false.
671 In practice this is set to true if the block is completely
672 undeground with nothing visible above the ground except
678 Set to true if changes has been made that make the old lighting
679 values wrong but the lighting hasn't been actually updated.
681 If this is false, lighting is exactly right.
682 If this is true, lighting might be wrong or right.
684 bool m_lighting_expired;
686 // Whether day and night lighting differs
687 bool m_day_night_differs;
692 MapBlockObjectList m_objects;
694 #ifndef SERVER // Only on client
696 Set to true if the mesh has been ordered to be updated
697 sometime in the background.
698 In practice this is set when the day/night lighting switches.
702 // Temporary modifications to nodes
703 // These are only used when drawing
704 NodeModMap m_temp_mods;
705 JMutex m_temp_mods_mutex;
709 When block is removed from active blocks, this is set to gametime.
710 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
715 When the block is accessed, this is set to 0.
716 Map will unload the block when this reaches a timeout.
721 inline bool blockpos_over_limit(v3s16 p)
724 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
725 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
726 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
727 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
728 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
729 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
733 Returns the position of the block where the node is located
735 inline v3s16 getNodeBlockPos(v3s16 p)
737 return getContainerPos(p, MAP_BLOCKSIZE);
740 inline v2s16 getNodeSectorPos(v2s16 p)
742 return getContainerPos(p, MAP_BLOCKSIZE);
745 inline s16 getNodeBlockY(s16 y)
747 return getContainerPos(y, MAP_BLOCKSIZE);
751 Get a quick string to describe what a block actually contains
753 std::string analyze_block(MapBlock *block);