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"
35 // Named by looking towards z+
48 video::S3DVertex vertices[4]; // Precalculated vertices
54 NODEMOD_CHANGECONTENT, //param is content id
55 NODEMOD_CRACK // param is crack progression
60 NodeMod(enum NodeModType a_type=NODEMOD_NONE, u16 a_param=0)
65 bool operator==(const NodeMod &other)
67 return (type == other.type && param == other.param);
69 enum NodeModType type;
77 returns true if the mod was different last time
79 bool set(v3s16 p, const NodeMod &mod)
81 // See if old is different, cancel if it is not different.
82 core::map<v3s16, NodeMod>::Node *n = m_mods.find(p);
85 NodeMod old = n->getValue();
93 m_mods.insert(p, mod);
98 // Returns true if there was one
99 bool get(v3s16 p, NodeMod *mod)
101 core::map<v3s16, NodeMod>::Node *n;
106 *mod = n->getValue();
120 if(m_mods.size() == 0)
125 void copy(NodeModMap &dest)
129 for(core::map<v3s16, NodeMod>::Iterator
130 i = m_mods.getIterator();
131 i.atEnd() == false; i++)
133 dest.m_mods.insert(i.getNode()->getKey(), i.getNode()->getValue());
138 core::map<v3s16, NodeMod> m_mods;
143 NODECONTAINER_ID_MAPBLOCK,
144 NODECONTAINER_ID_MAPSECTOR,
145 NODECONTAINER_ID_MAP,
146 NODECONTAINER_ID_MAPBLOCKCACHE,
147 NODECONTAINER_ID_VOXELMANIPULATOR,
153 virtual bool isValidPosition(v3s16 p) = 0;
154 virtual MapNode getNode(v3s16 p) = 0;
155 virtual void setNode(v3s16 p, MapNode & n) = 0;
156 virtual u16 nodeContainerId() const = 0;
159 class MapBlock : public NodeContainer
162 MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false);
165 virtual u16 nodeContainerId() const
167 return NODECONTAINER_ID_MAPBLOCK;
170 NodeContainer * getParent()
179 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
180 data = new MapNode[l];
181 for(u32 i=0; i<l; i++){
193 return (data == NULL);
201 bool getChangedFlag()
205 void resetChangedFlag()
209 void setChangedFlag()
214 bool getIsUnderground()
216 return is_underground;
219 void setIsUnderground(bool a_is_underground)
221 is_underground = a_is_underground;
226 void setMeshExpired(bool expired)
228 m_mesh_expired = expired;
231 bool getMeshExpired()
233 return m_mesh_expired;
237 void setLightingExpired(bool expired)
239 m_lighting_expired = expired;
242 bool getLightingExpired()
244 return m_lighting_expired;
247 bool isFullyGenerated()
249 return !m_not_fully_generated;
252 void setFullyGenerated(bool b)
255 m_not_fully_generated = !b;
260 if(m_lighting_expired)
276 v3s16 getPosRelative()
278 return m_pos * MAP_BLOCKSIZE;
281 core::aabbox3d<s16> getBox()
283 return core::aabbox3d<s16>(getPosRelative(),
285 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
290 Regular MapNode get-setters
293 bool isValidPosition(v3s16 p)
297 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
298 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
299 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
302 MapNode getNode(s16 x, s16 y, s16 z)
305 throw InvalidPositionException();
306 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
307 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
308 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
309 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
312 MapNode getNode(v3s16 p)
314 return getNode(p.X, p.Y, p.Z);
317 void setNode(s16 x, s16 y, s16 z, MapNode & n)
320 throw InvalidPositionException();
321 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
322 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
323 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
324 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
328 void setNode(v3s16 p, MapNode & n)
330 setNode(p.X, p.Y, p.Z, n);
334 Non-checking variants of the above
337 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
340 throw InvalidPositionException();
341 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
344 MapNode getNodeNoCheck(v3s16 p)
346 return getNodeNoCheck(p.X, p.Y, p.Z);
349 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
352 throw InvalidPositionException();
353 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
357 void setNodeNoCheck(v3s16 p, MapNode & n)
359 setNodeNoCheck(p.X, p.Y, p.Z, n);
363 These functions consult the parent container if the position
364 is not valid on this MapBlock.
366 bool isValidPositionParent(v3s16 p);
367 MapNode getNodeParent(v3s16 p);
368 void setNodeParent(v3s16 p, MapNode & n);
369 MapNode getNodeParentNoEx(v3s16 p);
371 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
373 for(u16 z=0; z<d; z++)
374 for(u16 y=0; y<h; y++)
375 for(u16 x=0; x<w; x++)
376 setNode(x0+x, y0+y, z0+z, node);
380 Graphics-related methods
383 // A quick version with nodes passed as parameters
384 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
386 // A more convenient version
387 u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
389 return getFaceLight(daynight_ratio,
390 getNodeParentNoEx(p),
391 getNodeParentNoEx(p + face_dir),
397 static void makeFastFace(TileSpec tile, u8 light, v3f p,
398 v3s16 dir, v3f scale, v3f posRelative_f,
399 core::array<FastFace> &dest);
401 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
402 NodeModMap &temp_mods);
403 u8 getNodeContent(v3s16 p, MapNode mn,
404 NodeModMap &temp_mods);
407 Generates the FastFaces of a node row. This has a
408 ridiculous amount of parameters because that way they
409 can be precalculated by the caller.
411 translate_dir: unit vector with only one of x, y or z
412 face_dir: unit vector with only one of x, y or z
414 void updateFastFaceRow(
423 core::array<FastFace> &dest,
424 NodeModMap &temp_mods);
427 Thread-safely updates the whole mesh of the mapblock.
429 void updateMesh(u32 daynight_ratio);
433 // See comments in mapblock.cpp
434 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
435 bool remove_light=false, bool *black_air_left=NULL,
436 bool grow_grass=false);
438 // Copies data to VoxelManipulator to getPosRelative()
439 void copyTo(VoxelManipulator &dst);
440 // Copies data from VoxelManipulator getPosRelative()
441 void copyFrom(VoxelManipulator &dst);
447 void serializeObjects(std::ostream &os, u8 version)
449 m_objects.serialize(os, version);
451 // If smgr!=NULL, new objects are added to the scene
452 void updateObjects(std::istream &is, u8 version,
453 scene::ISceneManager *smgr, u32 daynight_ratio)
455 m_objects.update(is, version, smgr, daynight_ratio);
465 void addObject(MapBlockObject *object)
466 throw(ContainerFullException, AlreadyExistsException)
468 m_objects.add(object);
472 void removeObject(s16 id)
474 m_objects.remove(id);
478 MapBlockObject * getObject(s16 id)
480 return m_objects.get(id);
482 JMutexAutoLock * getObjectLock()
484 return m_objects.getLock();
488 Moves objects, deletes objects and spawns new objects
490 void stepObjects(float dtime, bool server, u32 daynight_ratio);
492 /*void wrapObject(MapBlockObject *object)
494 m_objects.wrapObject(object);
499 // origin is relative to block
500 void getObjects(v3f origin, f32 max_d,
501 core::array<DistanceSortedObject> &dest)
503 m_objects.getObjects(origin, max_d, dest);
508 return m_objects.getCount();
513 Methods for setting temporary modifications to nodes for
516 returns true if the mod was different last time
518 bool setTempMod(v3s16 p, const NodeMod &mod)
520 /*dstream<<"setTempMod called on block"
521 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
522 <<", mod.type="<<mod.type
523 <<", mod.param="<<mod.param
525 JMutexAutoLock lock(m_temp_mods_mutex);
527 return m_temp_mods.set(p, mod);
529 // Returns true if there was one
530 bool getTempMod(v3s16 p, NodeMod *mod)
532 JMutexAutoLock lock(m_temp_mods_mutex);
534 return m_temp_mods.get(p, mod);
536 bool clearTempMod(v3s16 p)
538 JMutexAutoLock lock(m_temp_mods_mutex);
540 return m_temp_mods.clear(p);
544 JMutexAutoLock lock(m_temp_mods_mutex);
546 return m_temp_mods.clear();
551 Update day-night lighting difference flag.
553 Sets m_day_night_differs to appropriate value.
555 These methods don't care about neighboring blocks.
556 It means that to know if a block really doesn't need a mesh
557 update between day and night, the neighboring blocks have
558 to be taken into account. Use Map::dayNightDiffed().
560 void updateDayNightDiff();
562 bool dayNightDiffed()
564 return m_day_night_differs;
572 Tries to measure ground level.
577 0...MAP_BLOCKSIZE-1 = ground level
579 s16 getGroundLevel(v2s16 p2d);
585 // Doesn't write version by itself
586 void serialize(std::ostream &os, u8 version);
588 void deSerialize(std::istream &is, u8 version);
596 Used only internally, because changes can't be tracked
599 MapNode & getNodeRef(s16 x, s16 y, s16 z)
602 throw InvalidPositionException();
603 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
604 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
605 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
606 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
608 MapNode & getNodeRef(v3s16 &p)
610 return getNodeRef(p.X, p.Y, p.Z);
615 Public member variables
625 Private member variables
628 // Parent container (practically the Map)
629 // Not a MapSector, it is just a structural element.
630 NodeContainer *m_parent;
631 // Position in blocks on parent
635 If NULL, block is a dummy block.
636 Dummy blocks are used for caching not-found-on-disk blocks.
641 - On the server, this is used for telling whether the
642 block has been changed from the one on disk.
643 - On the client, this is used for nothing.
648 When propagating sunlight and the above block doesn't exist,
649 sunlight is assumed if this is false.
651 In practice this is set to true if the block is completely
652 undeground with nothing visible above the ground except
658 Set to true if changes has been made that make the old lighting
659 values wrong but the lighting hasn't been actually updated.
661 If this is false, lighting is exactly right.
662 If this is true, lighting might be wrong or right.
664 bool m_lighting_expired;
666 // Whether day and night lighting differs
667 bool m_day_night_differs;
670 Whether everything that is mainly located on this block has
671 been added to the world.
673 While this is false, a block can still be changed a bit when
674 stuff is added to the neighboring blocks that extends to this
677 When this is false on every one of a 3x3x3 chunk of blocks, the
678 central one will not be changed by the map generator in the
683 bool m_not_fully_generated;
685 MapBlockObjectList m_objects;
687 // Object spawning stuff
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 inline bool blockpos_over_limit(v3s16 p)
708 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
709 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
710 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
711 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
712 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
713 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
717 Returns the position of the block where the node is located
719 inline v3s16 getNodeBlockPos(v3s16 p)
721 return getContainerPos(p, MAP_BLOCKSIZE);
724 inline v2s16 getNodeSectorPos(v2s16 p)
726 return getContainerPos(p, MAP_BLOCKSIZE);
729 inline s16 getNodeBlockY(s16 y)
731 return getContainerPos(y, MAP_BLOCKSIZE);