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"
36 // Named by looking towards z+
49 video::S3DVertex vertices[4]; // Precalculated vertices
55 NODEMOD_CHANGECONTENT, //param is content id
56 NODEMOD_CRACK // param is crack progression
61 NodeMod(enum NodeModType a_type=NODEMOD_NONE, u16 a_param=0)
66 bool operator==(const NodeMod &other)
68 return (type == other.type && param == other.param);
70 enum NodeModType type;
78 returns true if the mod was different last time
80 bool set(v3s16 p, const NodeMod &mod)
82 // See if old is different, cancel if it is not different.
83 core::map<v3s16, NodeMod>::Node *n = m_mods.find(p);
86 NodeMod old = n->getValue();
94 m_mods.insert(p, mod);
99 // Returns true if there was one
100 bool get(v3s16 p, NodeMod *mod)
102 core::map<v3s16, NodeMod>::Node *n;
107 *mod = n->getValue();
121 if(m_mods.size() == 0)
126 void copy(NodeModMap &dest)
130 for(core::map<v3s16, NodeMod>::Iterator
131 i = m_mods.getIterator();
132 i.atEnd() == false; i++)
134 dest.m_mods.insert(i.getNode()->getKey(), i.getNode()->getValue());
139 core::map<v3s16, NodeMod> m_mods;
144 NODECONTAINER_ID_MAPBLOCK,
145 NODECONTAINER_ID_MAPSECTOR,
146 NODECONTAINER_ID_MAP,
147 NODECONTAINER_ID_MAPBLOCKCACHE,
148 NODECONTAINER_ID_VOXELMANIPULATOR,
154 virtual bool isValidPosition(v3s16 p) = 0;
155 virtual MapNode getNode(v3s16 p) = 0;
156 virtual void setNode(v3s16 p, MapNode & n) = 0;
157 virtual u16 nodeContainerId() const = 0;
160 class MapBlock : public NodeContainer
163 MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false);
166 virtual u16 nodeContainerId() const
168 return NODECONTAINER_ID_MAPBLOCK;
171 NodeContainer * getParent()
180 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
181 data = new MapNode[l];
182 for(u32 i=0; i<l; i++){
194 return (data == NULL);
202 bool getChangedFlag()
206 void resetChangedFlag()
210 void setChangedFlag()
215 bool getIsUnderground()
217 return is_underground;
220 void setIsUnderground(bool a_is_underground)
222 is_underground = a_is_underground;
227 void setMeshExpired(bool expired)
229 m_mesh_expired = expired;
232 bool getMeshExpired()
234 return m_mesh_expired;
238 void setLightingExpired(bool expired)
240 m_lighting_expired = expired;
243 bool getLightingExpired()
245 return m_lighting_expired;
248 /*bool isFullyGenerated()
250 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
623 NodeMetadataList m_node_metadata;
627 Private member variables
630 // Parent container (practically the Map)
631 // Not a MapSector, it is just a structural element.
632 NodeContainer *m_parent;
633 // Position in blocks on parent
637 If NULL, block is a dummy block.
638 Dummy blocks are used for caching not-found-on-disk blocks.
643 - On the server, this is used for telling whether the
644 block has been changed from the one on disk.
645 - On the client, this is used for nothing.
650 When propagating sunlight and the above block doesn't exist,
651 sunlight is assumed if this is false.
653 In practice this is set to true if the block is completely
654 undeground with nothing visible above the ground except
660 Set to true if changes has been made that make the old lighting
661 values wrong but the lighting hasn't been actually updated.
663 If this is false, lighting is exactly right.
664 If this is true, lighting might be wrong or right.
666 bool m_lighting_expired;
668 // Whether day and night lighting differs
669 bool m_day_night_differs;
671 MapBlockObjectList m_objects;
673 // Object spawning stuff
676 #ifndef SERVER // Only on client
678 Set to true if the mesh has been ordered to be updated
679 sometime in the background.
680 In practice this is set when the day/night lighting switches.
684 // Temporary modifications to nodes
685 // These are only used when drawing
686 NodeModMap m_temp_mods;
687 JMutex m_temp_mods_mutex;
691 inline bool blockpos_over_limit(v3s16 p)
694 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
695 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
696 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
697 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
698 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
699 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
703 Returns the position of the block where the node is located
705 inline v3s16 getNodeBlockPos(v3s16 p)
707 return getContainerPos(p, MAP_BLOCKSIZE);
710 inline v2s16 getNodeSectorPos(v2s16 p)
712 return getContainerPos(p, MAP_BLOCKSIZE);
715 inline s16 getNodeBlockY(s16 y)
717 return getContainerPos(y, MAP_BLOCKSIZE);