/* Minetest-c55 Copyright (C) 2010 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef MAPBLOCK_HEADER #define MAPBLOCK_HEADER #include #include #include #include "debug.h" #include "common_irrlicht.h" #include "mapnode.h" #include "exceptions.h" #include "serialization.h" #include "constants.h" #include "mapblockobject.h" #include "voxel.h" #include "nodemetadata.h" // Named by looking towards z+ enum{ FACE_BACK=0, FACE_TOP, FACE_RIGHT, FACE_FRONT, FACE_BOTTOM, FACE_LEFT }; struct FastFace { TileSpec tile; video::S3DVertex vertices[4]; // Precalculated vertices }; enum NodeModType { NODEMOD_NONE, NODEMOD_CHANGECONTENT, //param is content id NODEMOD_CRACK // param is crack progression }; struct NodeMod { NodeMod(enum NodeModType a_type=NODEMOD_NONE, u16 a_param=0) { type = a_type; param = a_param; } bool operator==(const NodeMod &other) { return (type == other.type && param == other.param); } enum NodeModType type; u16 param; }; class NodeModMap { public: /* returns true if the mod was different last time */ bool set(v3s16 p, const NodeMod &mod) { // See if old is different, cancel if it is not different. core::map::Node *n = m_mods.find(p); if(n) { NodeMod old = n->getValue(); if(old == mod) return false; n->setValue(mod); } else { m_mods.insert(p, mod); } return true; } // Returns true if there was one bool get(v3s16 p, NodeMod *mod) { core::map::Node *n; n = m_mods.find(p); if(n == NULL) return false; if(mod) *mod = n->getValue(); return true; } bool clear(v3s16 p) { if(m_mods.find(p)) { m_mods.remove(p); return true; } return false; } bool clear() { if(m_mods.size() == 0) return false; m_mods.clear(); return true; } void copy(NodeModMap &dest) { dest.m_mods.clear(); for(core::map::Iterator i = m_mods.getIterator(); i.atEnd() == false; i++) { dest.m_mods.insert(i.getNode()->getKey(), i.getNode()->getValue()); } } private: core::map m_mods; }; enum { NODECONTAINER_ID_MAPBLOCK, NODECONTAINER_ID_MAPSECTOR, NODECONTAINER_ID_MAP, NODECONTAINER_ID_MAPBLOCKCACHE, NODECONTAINER_ID_VOXELMANIPULATOR, }; class NodeContainer { public: virtual bool isValidPosition(v3s16 p) = 0; virtual MapNode getNode(v3s16 p) = 0; virtual void setNode(v3s16 p, MapNode & n) = 0; virtual u16 nodeContainerId() const = 0; }; class MapBlock : public NodeContainer { public: MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false); ~MapBlock(); virtual u16 nodeContainerId() const { return NODECONTAINER_ID_MAPBLOCK; } NodeContainer * getParent() { return m_parent; } void reallocate() { if(data != NULL) delete[] data; u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE; data = new MapNode[l]; for(u32 i=0; i getBox() { return core::aabbox3d(getPosRelative(), getPosRelative() + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE) - v3s16(1,1,1)); } /* Regular MapNode get-setters */ bool isValidPosition(v3s16 p) { if(data == NULL) return false; return (p.X >= 0 && p.X < MAP_BLOCKSIZE && p.Y >= 0 && p.Y < MAP_BLOCKSIZE && p.Z >= 0 && p.Z < MAP_BLOCKSIZE); } MapNode getNode(s16 x, s16 y, s16 z) { if(data == NULL) throw InvalidPositionException(); if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException(); if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException(); if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException(); return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x]; } MapNode getNode(v3s16 p) { return getNode(p.X, p.Y, p.Z); } void setNode(s16 x, s16 y, s16 z, MapNode & n) { if(data == NULL) throw InvalidPositionException(); if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException(); if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException(); if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException(); data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n; setChangedFlag(); } void setNode(v3s16 p, MapNode & n) { setNode(p.X, p.Y, p.Z, n); } /* Non-checking variants of the above */ MapNode getNodeNoCheck(s16 x, s16 y, s16 z) { if(data == NULL) throw InvalidPositionException(); return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x]; } MapNode getNodeNoCheck(v3s16 p) { return getNodeNoCheck(p.X, p.Y, p.Z); } void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n) { if(data == NULL) throw InvalidPositionException(); data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n; setChangedFlag(); } void setNodeNoCheck(v3s16 p, MapNode & n) { setNodeNoCheck(p.X, p.Y, p.Z, n); } /* These functions consult the parent container if the position is not valid on this MapBlock. */ bool isValidPositionParent(v3s16 p); MapNode getNodeParent(v3s16 p); void setNodeParent(v3s16 p, MapNode & n); MapNode getNodeParentNoEx(v3s16 p); void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node) { for(u16 z=0; z &dest); TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir, NodeModMap &temp_mods); u8 getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods); /* Generates the FastFaces of a node row. This has a ridiculous amount of parameters because that way they can be precalculated by the caller. translate_dir: unit vector with only one of x, y or z face_dir: unit vector with only one of x, y or z */ void updateFastFaceRow( u32 daynight_ratio, v3f posRelative_f, v3s16 startpos, u16 length, v3s16 translate_dir, v3f translate_dir_f, v3s16 face_dir, v3f face_dir_f, core::array &dest, NodeModMap &temp_mods); /* Thread-safely updates the whole mesh of the mapblock. */ void updateMesh(u32 daynight_ratio); #endif // !SERVER // See comments in mapblock.cpp bool propagateSunlight(core::map & light_sources, bool remove_light=false, bool *black_air_left=NULL, bool grow_grass=false); // Copies data to VoxelManipulator to getPosRelative() void copyTo(VoxelManipulator &dst); // Copies data from VoxelManipulator getPosRelative() void copyFrom(VoxelManipulator &dst); /* MapBlockObject stuff */ void serializeObjects(std::ostream &os, u8 version) { m_objects.serialize(os, version); } // If smgr!=NULL, new objects are added to the scene void updateObjects(std::istream &is, u8 version, scene::ISceneManager *smgr, u32 daynight_ratio) { m_objects.update(is, version, smgr, daynight_ratio); setChangedFlag(); } void clearObjects() { m_objects.clear(); setChangedFlag(); } void addObject(MapBlockObject *object) throw(ContainerFullException, AlreadyExistsException) { m_objects.add(object); setChangedFlag(); } void removeObject(s16 id) { m_objects.remove(id); setChangedFlag(); } MapBlockObject * getObject(s16 id) { return m_objects.get(id); } JMutexAutoLock * getObjectLock() { return m_objects.getLock(); } /* Moves objects, deletes objects and spawns new objects */ void stepObjects(float dtime, bool server, u32 daynight_ratio); /*void wrapObject(MapBlockObject *object) { m_objects.wrapObject(object); setChangedFlag(); }*/ // origin is relative to block void getObjects(v3f origin, f32 max_d, core::array &dest) { m_objects.getObjects(origin, max_d, dest); } s32 getObjectCount() { return m_objects.getCount(); } #ifndef SERVER /* Methods for setting temporary modifications to nodes for drawing returns true if the mod was different last time */ bool setTempMod(v3s16 p, const NodeMod &mod) { /*dstream<<"setTempMod called on block" <<" ("<