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"
42 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
44 /*// Named by looking towards z+
56 // Has not been modified.
59 // Has been modified, and will be saved when being unloaded.
60 MOD_STATE_WRITE_AT_UNLOAD = 2,
62 // Has been modified, and will be saved as soon as possible.
63 MOD_STATE_WRITE_NEEDED = 4,
67 // NOTE: If this is enabled, set MapBlock to be initialized with
69 /*enum BlockGenerationStatus
71 // Completely non-generated (filled with CONTENT_IGNORE).
73 // Trees or similar might have been blitted from other blocks to here.
74 // Otherwise, the block contains CONTENT_IGNORE
75 BLOCKGEN_FROM_NEIGHBORS=2,
76 // Has been generated, but some neighbors might put some stuff in here
77 // when they are generated.
78 // Does not contain any CONTENT_IGNORE
79 BLOCKGEN_SELF_GENERATED=4,
80 // The block and all its neighbors have been generated
81 BLOCKGEN_FULLY_GENERATED=6
86 NODECONTAINER_ID_MAPBLOCK,
87 NODECONTAINER_ID_MAPSECTOR,
89 NODECONTAINER_ID_MAPBLOCKCACHE,
90 NODECONTAINER_ID_VOXELMANIPULATOR,
96 virtual bool isValidPosition(v3s16 p) = 0;
97 virtual MapNode getNode(v3s16 p) = 0;
98 virtual void setNode(v3s16 p, MapNode & n) = 0;
99 virtual u16 nodeContainerId() const = 0;
101 MapNode getNodeNoEx(v3s16 p)
106 catch(InvalidPositionException &e){
107 return MapNode(CONTENT_IGNORE);
116 class MapBlock : public NodeContainer
119 MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false);
122 virtual u16 nodeContainerId() const
124 return NODECONTAINER_ID_MAPBLOCK;
127 NodeContainer * getParent()
136 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
137 data = new MapNode[l];
138 for(u32 i=0; i<l; i++){
139 //data[i] = MapNode();
140 data[i] = MapNode(CONTENT_IGNORE);
142 raiseModified(MOD_STATE_WRITE_NEEDED);
151 return (data == NULL);
160 This is called internally or externally after the block is
161 modified, so that the block is saved and possibly not deleted from
164 // DEPRECATED, use *Modified()
165 void setChangedFlag()
167 //dstream<<"Deprecated setChangedFlag() called"<<std::endl;
168 raiseModified(MOD_STATE_WRITE_NEEDED);
170 // DEPRECATED, use *Modified()
171 void resetChangedFlag()
173 //dstream<<"Deprecated resetChangedFlag() called"<<std::endl;
176 // DEPRECATED, use *Modified()
177 bool getChangedFlag()
179 //dstream<<"Deprecated getChangedFlag() called"<<std::endl;
180 if(getModified() == MOD_STATE_CLEAN)
186 // m_modified methods
187 void raiseModified(u32 mod)
189 m_modified = MYMAX(m_modified, mod);
197 m_modified = MOD_STATE_CLEAN;
200 // is_underground getter/setter
201 bool getIsUnderground()
203 return is_underground;
205 void setIsUnderground(bool a_is_underground)
207 is_underground = a_is_underground;
208 raiseModified(MOD_STATE_WRITE_NEEDED);
212 void setMeshExpired(bool expired)
214 m_mesh_expired = expired;
217 bool getMeshExpired()
219 return m_mesh_expired;
223 void setLightingExpired(bool expired)
225 m_lighting_expired = expired;
226 raiseModified(MOD_STATE_WRITE_NEEDED);
228 bool getLightingExpired()
230 return m_lighting_expired;
237 void setGenerated(bool b)
239 raiseModified(MOD_STATE_WRITE_NEEDED);
245 if(m_lighting_expired)
261 v3s16 getPosRelative()
263 return m_pos * MAP_BLOCKSIZE;
266 core::aabbox3d<s16> getBox()
268 return core::aabbox3d<s16>(getPosRelative(),
270 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
275 Regular MapNode get-setters
278 bool isValidPosition(v3s16 p)
282 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
283 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
284 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
287 MapNode getNode(s16 x, s16 y, s16 z)
290 throw InvalidPositionException();
291 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
292 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
293 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
294 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
297 MapNode getNode(v3s16 p)
299 return getNode(p.X, p.Y, p.Z);
302 MapNode getNodeNoEx(v3s16 p)
305 return getNode(p.X, p.Y, p.Z);
306 }catch(InvalidPositionException &e){
307 return MapNode(CONTENT_IGNORE);
311 void setNode(s16 x, s16 y, s16 z, MapNode & n)
314 throw InvalidPositionException();
315 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
316 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
317 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
318 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
319 raiseModified(MOD_STATE_WRITE_NEEDED);
322 void setNode(v3s16 p, MapNode & n)
324 setNode(p.X, p.Y, p.Z, n);
328 Non-checking variants of the above
331 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
334 throw InvalidPositionException();
335 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
338 MapNode getNodeNoCheck(v3s16 p)
340 return getNodeNoCheck(p.X, p.Y, p.Z);
343 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
346 throw InvalidPositionException();
347 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
348 raiseModified(MOD_STATE_WRITE_NEEDED);
351 void setNodeNoCheck(v3s16 p, MapNode & n)
353 setNodeNoCheck(p.X, p.Y, p.Z, n);
357 These functions consult the parent container if the position
358 is not valid on this MapBlock.
360 bool isValidPositionParent(v3s16 p);
361 MapNode getNodeParent(v3s16 p);
362 void setNodeParent(v3s16 p, MapNode & n);
363 MapNode getNodeParentNoEx(v3s16 p);
365 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
367 for(u16 z=0; z<d; z++)
368 for(u16 y=0; y<h; y++)
369 for(u16 x=0; x<w; x++)
370 setNode(x0+x, y0+y, z0+z, node);
374 Graphics-related methods
377 /*// A quick version with nodes passed as parameters
378 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
380 /*// A more convenient version
381 u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
383 return getFaceLight(daynight_ratio,
384 getNodeParentNoEx(p),
385 getNodeParentNoEx(p + face_dir),
388 u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
390 return getFaceLight(daynight_ratio,
391 getNodeParentNoEx(p),
392 getNodeParentNoEx(p + face_dir),
396 #ifndef SERVER // Only on client
400 Thread-safely updates the whole mesh of the mapblock.
401 NOTE: Prefer generating the mesh separately and then using
404 void updateMesh(u32 daynight_ratio);
406 // Replace the mesh with a new one
407 void replaceMesh(scene::SMesh *mesh_new);
410 // See comments in mapblock.cpp
411 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
412 bool remove_light=false, bool *black_air_left=NULL);
414 // Copies data to VoxelManipulator to getPosRelative()
415 void copyTo(VoxelManipulator &dst);
416 // Copies data from VoxelManipulator getPosRelative()
417 void copyFrom(VoxelManipulator &dst);
424 /*void serializeObjects(std::ostream &os, u8 version)
426 m_objects.serialize(os, version);
428 // If smgr!=NULL, new objects are added to the scene
429 void updateObjects(std::istream &is, u8 version,
430 scene::ISceneManager *smgr, u32 daynight_ratio)
432 m_objects.update(is, version, smgr, daynight_ratio);
434 raiseModified(MOD_STATE_WRITE_NEEDED);
440 raiseModified(MOD_STATE_WRITE_NEEDED);
442 void addObject(MapBlockObject *object)
443 throw(ContainerFullException, AlreadyExistsException)
445 m_objects.add(object);
447 raiseModified(MOD_STATE_WRITE_NEEDED);
449 void removeObject(s16 id)
451 m_objects.remove(id);
453 raiseModified(MOD_STATE_WRITE_NEEDED);
455 MapBlockObject * getObject(s16 id)
457 return m_objects.get(id);
459 JMutexAutoLock * getObjectLock()
461 return m_objects.getLock();
465 Moves objects, deletes objects and spawns new objects
467 void stepObjects(float dtime, bool server, u32 daynight_ratio);
469 // origin is relative to block
470 void getObjects(v3f origin, f32 max_d,
471 core::array<DistanceSortedObject> &dest)
473 m_objects.getObjects(origin, max_d, dest);
478 return m_objects.getCount();
481 #ifndef SERVER // Only on client
483 Methods for setting temporary modifications to nodes for
486 returns true if the mod was different last time
488 bool setTempMod(v3s16 p, const NodeMod &mod)
490 /*dstream<<"setTempMod called on block"
491 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
492 <<", mod.type="<<mod.type
493 <<", mod.param="<<mod.param
495 JMutexAutoLock lock(m_temp_mods_mutex);
497 return m_temp_mods.set(p, mod);
499 // Returns true if there was one
500 bool getTempMod(v3s16 p, NodeMod *mod)
502 JMutexAutoLock lock(m_temp_mods_mutex);
504 return m_temp_mods.get(p, mod);
506 bool clearTempMod(v3s16 p)
508 JMutexAutoLock lock(m_temp_mods_mutex);
510 return m_temp_mods.clear(p);
514 JMutexAutoLock lock(m_temp_mods_mutex);
516 return m_temp_mods.clear();
518 void copyTempMods(NodeModMap &dst)
520 JMutexAutoLock lock(m_temp_mods_mutex);
521 m_temp_mods.copy(dst);
526 Update day-night lighting difference flag.
528 Sets m_day_night_differs to appropriate value.
530 These methods don't care about neighboring blocks.
531 It means that to know if a block really doesn't need a mesh
532 update between day and night, the neighboring blocks have
533 to be taken into account. Use Map::dayNightDiffed().
535 void updateDayNightDiff();
537 bool dayNightDiffed()
539 return m_day_night_differs;
547 Tries to measure ground level.
552 0...MAP_BLOCKSIZE-1 = ground level
554 s16 getGroundLevel(v2s16 p2d);
557 Timestamp (see m_timestamp)
558 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
560 void setTimestamp(u32 time)
563 raiseModified(MOD_STATE_WRITE_AT_UNLOAD);
565 void setTimestampNoChangedFlag(u32 time)
577 void resetUsageTimer()
581 void incrementUsageTimer(float dtime)
583 m_usage_timer += dtime;
587 return m_usage_timer;
594 // These don't write or read version by itself
595 void serialize(std::ostream &os, u8 version);
596 void deSerialize(std::istream &is, u8 version);
597 // Used after the basic ones when writing on disk (serverside)
598 void serializeDiskExtra(std::ostream &os, u8 version);
599 void deSerializeDiskExtra(std::istream &is, u8 version);
607 Used only internally, because changes can't be tracked
610 MapNode & getNodeRef(s16 x, s16 y, s16 z)
613 throw InvalidPositionException();
614 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
615 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
616 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
617 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
619 MapNode & getNodeRef(v3s16 &p)
621 return getNodeRef(p.X, p.Y, p.Z);
626 Public member variables
629 #ifndef SERVER // Only on client
634 NodeMetadataList m_node_metadata;
635 StaticObjectList m_static_objects;
639 Private member variables
642 // NOTE: Lots of things rely on this being the Map
643 NodeContainer *m_parent;
644 // Position in blocks on parent
648 If NULL, block is a dummy block.
649 Dummy blocks are used for caching not-found-on-disk blocks.
654 - On the server, this is used for telling whether the
655 block has been modified from the one on disk.
656 - On the client, this is used for nothing.
661 When propagating sunlight and the above block doesn't exist,
662 sunlight is assumed if this is false.
664 In practice this is set to true if the block is completely
665 undeground with nothing visible above the ground except
671 Set to true if changes has been made that make the old lighting
672 values wrong but the lighting hasn't been actually updated.
674 If this is false, lighting is exactly right.
675 If this is true, lighting might be wrong or right.
677 bool m_lighting_expired;
679 // Whether day and night lighting differs
680 bool m_day_night_differs;
685 MapBlockObjectList m_objects;
687 #ifndef SERVER // Only on client
689 Set to true if the mesh has been ordered to be updated
690 sometime in the background.
691 In practice this is set when the day/night lighting switches.
695 // Temporary modifications to nodes
696 // These are only used when drawing
697 NodeModMap m_temp_mods;
698 JMutex m_temp_mods_mutex;
702 When block is removed from active blocks, this is set to gametime.
703 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
708 When the block is accessed, this is set to 0.
709 Map will unload the block when this reaches a timeout.
714 inline bool blockpos_over_limit(v3s16 p)
717 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
718 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
719 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
720 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
721 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
722 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
726 Returns the position of the block where the node is located
728 inline v3s16 getNodeBlockPos(v3s16 p)
730 return getContainerPos(p, MAP_BLOCKSIZE);
733 inline v2s16 getNodeSectorPos(v2s16 p)
735 return getContainerPos(p, MAP_BLOCKSIZE);
738 inline s16 getNodeBlockY(s16 y)
740 return getContainerPos(y, MAP_BLOCKSIZE);