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 m_lighting_expired = expired;
229 raiseModified(MOD_STATE_WRITE_NEEDED);
231 bool getLightingExpired()
233 return m_lighting_expired;
240 void setGenerated(bool b)
242 raiseModified(MOD_STATE_WRITE_NEEDED);
248 if(m_lighting_expired)
264 v3s16 getPosRelative()
266 return m_pos * MAP_BLOCKSIZE;
269 core::aabbox3d<s16> getBox()
271 return core::aabbox3d<s16>(getPosRelative(),
273 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
278 Regular MapNode get-setters
281 bool isValidPosition(v3s16 p)
285 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
286 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
287 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
290 MapNode getNode(s16 x, s16 y, s16 z)
293 throw InvalidPositionException();
294 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
295 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
296 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
297 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
300 MapNode getNode(v3s16 p)
302 return getNode(p.X, p.Y, p.Z);
305 MapNode getNodeNoEx(v3s16 p)
308 return getNode(p.X, p.Y, p.Z);
309 }catch(InvalidPositionException &e){
310 return MapNode(CONTENT_IGNORE);
314 void setNode(s16 x, s16 y, s16 z, MapNode & n)
317 throw InvalidPositionException();
318 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
319 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
320 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
321 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
322 raiseModified(MOD_STATE_WRITE_NEEDED);
325 void setNode(v3s16 p, MapNode & n)
327 setNode(p.X, p.Y, p.Z, n);
331 Non-checking variants of the above
334 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
337 throw InvalidPositionException();
338 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
341 MapNode getNodeNoCheck(v3s16 p)
343 return getNodeNoCheck(p.X, p.Y, p.Z);
346 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
349 throw InvalidPositionException();
350 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
351 raiseModified(MOD_STATE_WRITE_NEEDED);
354 void setNodeNoCheck(v3s16 p, MapNode & n)
356 setNodeNoCheck(p.X, p.Y, p.Z, n);
360 These functions consult the parent container if the position
361 is not valid on this MapBlock.
363 bool isValidPositionParent(v3s16 p);
364 MapNode getNodeParent(v3s16 p);
365 void setNodeParent(v3s16 p, MapNode & n);
366 MapNode getNodeParentNoEx(v3s16 p);
368 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
370 for(u16 z=0; z<d; z++)
371 for(u16 y=0; y<h; y++)
372 for(u16 x=0; x<w; x++)
373 setNode(x0+x, y0+y, z0+z, node);
377 Graphics-related methods
380 /*// A quick version with nodes passed as parameters
381 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
383 /*// A more convenient version
384 u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
386 return getFaceLight(daynight_ratio,
387 getNodeParentNoEx(p),
388 getNodeParentNoEx(p + face_dir),
391 u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
393 return getFaceLight(daynight_ratio,
394 getNodeParentNoEx(p),
395 getNodeParentNoEx(p + face_dir),
399 #ifndef SERVER // Only on client
403 Thread-safely updates the whole mesh of the mapblock.
404 NOTE: Prefer generating the mesh separately and then using
407 void updateMesh(u32 daynight_ratio);
409 // Replace the mesh with a new one
410 void replaceMesh(scene::SMesh *mesh_new);
413 // See comments in mapblock.cpp
414 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
415 bool remove_light=false, bool *black_air_left=NULL);
417 // Copies data to VoxelManipulator to getPosRelative()
418 void copyTo(VoxelManipulator &dst);
419 // Copies data from VoxelManipulator getPosRelative()
420 void copyFrom(VoxelManipulator &dst);
427 /*void serializeObjects(std::ostream &os, u8 version)
429 m_objects.serialize(os, version);
431 // If smgr!=NULL, new objects are added to the scene
432 void updateObjects(std::istream &is, u8 version,
433 scene::ISceneManager *smgr, u32 daynight_ratio)
435 m_objects.update(is, version, smgr, daynight_ratio);
437 raiseModified(MOD_STATE_WRITE_NEEDED);
443 raiseModified(MOD_STATE_WRITE_NEEDED);
445 void addObject(MapBlockObject *object)
446 throw(ContainerFullException, AlreadyExistsException)
448 m_objects.add(object);
450 raiseModified(MOD_STATE_WRITE_NEEDED);
452 void removeObject(s16 id)
454 m_objects.remove(id);
456 raiseModified(MOD_STATE_WRITE_NEEDED);
458 MapBlockObject * getObject(s16 id)
460 return m_objects.get(id);
462 JMutexAutoLock * getObjectLock()
464 return m_objects.getLock();
468 Moves objects, deletes objects and spawns new objects
470 void stepObjects(float dtime, bool server, u32 daynight_ratio);
472 // origin is relative to block
473 void getObjects(v3f origin, f32 max_d,
474 core::array<DistanceSortedObject> &dest)
476 m_objects.getObjects(origin, max_d, dest);
481 return m_objects.getCount();
484 #ifndef SERVER // Only on client
486 Methods for setting temporary modifications to nodes for
489 returns true if the mod was different last time
491 bool setTempMod(v3s16 p, const NodeMod &mod)
493 /*dstream<<"setTempMod called on block"
494 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
495 <<", mod.type="<<mod.type
496 <<", mod.param="<<mod.param
498 JMutexAutoLock lock(m_temp_mods_mutex);
500 return m_temp_mods.set(p, mod);
502 // Returns true if there was one
503 bool getTempMod(v3s16 p, NodeMod *mod)
505 JMutexAutoLock lock(m_temp_mods_mutex);
507 return m_temp_mods.get(p, mod);
509 bool clearTempMod(v3s16 p)
511 JMutexAutoLock lock(m_temp_mods_mutex);
513 return m_temp_mods.clear(p);
517 JMutexAutoLock lock(m_temp_mods_mutex);
519 return m_temp_mods.clear();
521 void copyTempMods(NodeModMap &dst)
523 JMutexAutoLock lock(m_temp_mods_mutex);
524 m_temp_mods.copy(dst);
529 Update day-night lighting difference flag.
531 Sets m_day_night_differs to appropriate value.
533 These methods don't care about neighboring blocks.
534 It means that to know if a block really doesn't need a mesh
535 update between day and night, the neighboring blocks have
536 to be taken into account. Use Map::dayNightDiffed().
538 void updateDayNightDiff();
540 bool dayNightDiffed()
542 return m_day_night_differs;
550 Tries to measure ground level.
555 0...MAP_BLOCKSIZE-1 = ground level
557 s16 getGroundLevel(v2s16 p2d);
560 Timestamp (see m_timestamp)
561 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
563 void setTimestamp(u32 time)
566 raiseModified(MOD_STATE_WRITE_AT_UNLOAD);
568 void setTimestampNoChangedFlag(u32 time)
580 void resetUsageTimer()
584 void incrementUsageTimer(float dtime)
586 m_usage_timer += dtime;
590 return m_usage_timer;
597 // These don't write or read version by itself
598 void serialize(std::ostream &os, u8 version);
599 void deSerialize(std::istream &is, u8 version);
600 // Used after the basic ones when writing on disk (serverside)
601 void serializeDiskExtra(std::ostream &os, u8 version);
602 void deSerializeDiskExtra(std::istream &is, u8 version);
610 Used only internally, because changes can't be tracked
613 MapNode & getNodeRef(s16 x, s16 y, s16 z)
616 throw InvalidPositionException();
617 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
618 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
619 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
620 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
622 MapNode & getNodeRef(v3s16 &p)
624 return getNodeRef(p.X, p.Y, p.Z);
629 Public member variables
632 #ifndef SERVER // Only on client
637 NodeMetadataList m_node_metadata;
638 StaticObjectList m_static_objects;
642 Private member variables
645 // NOTE: Lots of things rely on this being the Map
647 // Position in blocks on parent
651 If NULL, block is a dummy block.
652 Dummy blocks are used for caching not-found-on-disk blocks.
657 - On the server, this is used for telling whether the
658 block has been modified from the one on disk.
659 - On the client, this is used for nothing.
664 When propagating sunlight and the above block doesn't exist,
665 sunlight is assumed if this is false.
667 In practice this is set to true if the block is completely
668 undeground with nothing visible above the ground except
674 Set to true if changes has been made that make the old lighting
675 values wrong but the lighting hasn't been actually updated.
677 If this is false, lighting is exactly right.
678 If this is true, lighting might be wrong or right.
680 bool m_lighting_expired;
682 // Whether day and night lighting differs
683 bool m_day_night_differs;
688 MapBlockObjectList m_objects;
690 #ifndef SERVER // Only on client
692 Set to true if the mesh has been ordered to be updated
693 sometime in the background.
694 In practice this is set when the day/night lighting switches.
698 // Temporary modifications to nodes
699 // These are only used when drawing
700 NodeModMap m_temp_mods;
701 JMutex m_temp_mods_mutex;
705 When block is removed from active blocks, this is set to gametime.
706 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
711 When the block is accessed, this is set to 0.
712 Map will unload the block when this reaches a timeout.
717 inline bool blockpos_over_limit(v3s16 p)
720 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
721 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
722 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
723 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
724 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
725 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
729 Returns the position of the block where the node is located
731 inline v3s16 getNodeBlockPos(v3s16 p)
733 return getContainerPos(p, MAP_BLOCKSIZE);
736 inline v2s16 getNodeSectorPos(v2s16 p)
738 return getContainerPos(p, MAP_BLOCKSIZE);
741 inline s16 getNodeBlockY(s16 y)
743 return getContainerPos(y, MAP_BLOCKSIZE);