/*MinetestCopyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>This program is free software; you can redistribute it and/or modifyit under the terms of the GNU Lesser General Public License as published bythe Free Software Foundation; either version 2.1 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU Lesser General Public License for more details.You should have received a copy of the GNU Lesser General Public License alongwith this program; if not, write to the Free Software Foundation, Inc.,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.*/#pragma once#include <iostream>#include <sstream>#include <set>#include <map>#include <list>#include"irrlichttypes_bloated.h"#include"mapnode.h"#include"constants.h"#include"voxel.h"#include"modifiedstate.h"#include"util/container.h"#include"nodetimer.h"#include"map_settings_manager.h"#include"debug.h"class Settings;class MapDatabase;class ClientMap;class MapSector;class ServerMapSector;class MapBlock;class NodeMetadata;class IGameDef;class IRollbackManager;class EmergeManager;class ServerEnvironment;struct BlockMakeData;/* MapEditEvent*/#define MAPTYPE_BASE 0#define MAPTYPE_SERVER 1#define MAPTYPE_CLIENT 2enum MapEditEventType{// Node added (changed from air or something else to something)
MEET_ADDNODE,// Node removed (changed to air)
MEET_REMOVENODE,// Node swapped (changed without metadata change)
MEET_SWAPNODE,// Node metadata changed
MEET_BLOCK_NODE_METADATA_CHANGED,// Anything else (modified_blocks are set unsent)
MEET_OTHER
};struct MapEditEvent
{
MapEditEventType type = MEET_OTHER;
v3s16 p;
MapNode n = CONTENT_AIR;std::set<v3s16> modified_blocks;bool is_private_change =false;MapEditEvent() =default;
VoxelArea getArea()const{switch(type){case MEET_ADDNODE:returnVoxelArea(p);case MEET_REMOVENODE:returnVoxelArea(p);case MEET_SWAPNODE:returnVoxelArea(p);case MEET_BLOCK_NODE_METADATA_CHANGED:{
v3s16 np1 = p*MAP_BLOCKSIZE;
v3s16 np2 = np1 +v3s16(1,1,1)*MAP_BLOCKSIZE -v3s16(1,1,1);returnVoxelArea(np1, np2);}case MEET_OTHER:{
VoxelArea a;for(v3s16 p : modified_blocks) {
v3s16 np1 = p*MAP_BLOCKSIZE;
v3s16 np2 = np1 +v3s16(1,1,1)*MAP_BLOCKSIZE -v3s16(1,1,1);
a.addPoint(np1);
a.addPoint(np2);}return a;}}returnVoxelArea();}};class MapEventReceiver
{public:// event shall be deleted by caller after the call.virtualvoidonMapEditEvent(const MapEditEvent &event) =0;};class Map /*: public NodeContainer*/{public:Map(std::ostream &dout, IGameDef *gamedef);virtual~Map();DISABLE_CLASS_COPY(Map);virtual s32 mapType()const{return MAPTYPE_BASE;}/* Drop (client) or delete (server) the map. */virtualvoiddrop(){delete this;}voidaddEventReceiver(MapEventReceiver *event_receiver);voidremoveEventReceiver(MapEventReceiver *event_receiver);// event shall be deleted by caller after the call.voiddispatchEvent(const MapEditEvent &event);// On failure returns NULL
MapSector *getSectorNoGenerateNoLock(v2s16 p2d);// Same as the above (there exists no lock anymore)
MapSector *getSectorNoGenerate(v2s16 p2d);// Gets an existing sector or creates an empty one//MapSector * getSectorCreate(v2s16 p2d);/* This is overloaded by ClientMap and ServerMap to allow their differing fetch methods. */virtual MapSector *emergeSector(v2s16 p){return NULL; }// Returns InvalidPositionException if not found
MapBlock *getBlockNoCreate(v3s16 p);// Returns NULL if not found
MapBlock *getBlockNoCreateNoEx(v3s16 p);/* Server overrides */virtual MapBlock *emergeBlock(v3s16 p,bool create_blank=true){returngetBlockNoCreateNoEx(p); }inlineconst NodeDefManager *getNodeDefManager() {return m_nodedef; }// Returns InvalidPositionException if not foundboolisNodeUnderground(v3s16 p);boolisValidPosition(v3s16 p);// throws InvalidPositionException if not foundvoidsetNode(v3s16 p, MapNode & n);// Returns a CONTENT_IGNORE node if not found// If is_valid_position is not NULL then this will be set to true if the// position is valid, otherwise false
MapNode getNode(v3s16 p,bool*is_valid_position = NULL);/* These handle lighting but not faces. */voidaddNodeAndUpdate(v3s16 p, MapNode n,std::map<v3s16, MapBlock*> &modified_blocks,bool remove_metadata =true);voidremoveNodeAndUpdate(v3s16 p,std::map<v3s16, MapBlock*> &modified_blocks);/* Wrappers for the latter ones. These emit events. Return true if succeeded, false if not. */booladdNodeWithEvent(v3s16 p, MapNode n,bool remove_metadata =true);boolremoveNodeWithEvent(v3s16 p);// Call these before and after saving of many blocksvirtualvoidbeginSave() {}virtualvoidendSave() {}virtualvoidsave(ModifiedState save_level) {FATAL_ERROR("FIXME"); }// Server implements these.// Client leaves them as no-op.virtualboolsaveBlock(MapBlock *block) {return false; }virtualbooldeleteBlock(v3s16 blockpos) {return false; }/* Updates usage timers and unloads unused blocks and sectors. Saves modified blocks before unloading on MAPTYPE_SERVER. */voidtimerUpdate(float dtime,float unload_timeout, u32 max_loaded_blocks,std::vector<v3s16> *unloaded_blocks=NULL);/* Unloads all blocks with a zero refCount(). Saves modified blocks before unloading on MAPTYPE_SERVER. */voidunloadUnreferencedBlocks(std::vector<v3s16> *unloaded_blocks=NULL);// Deletes sectors and their blocks from memory// Takes cache into account// If deleted sector is in sector cache, clears cachevoiddeleteSectors(std::vector<v2s16> &list);// For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: "virtualvoidPrintInfo(std::ostream &out);voidtransformLiquids(std::map<v3s16, MapBlock*> & modified_blocks,
ServerEnvironment *env);/* Node metadata These are basically coordinate wrappers to MapBlock */std::vector<v3s16>findNodesWithMetadata(v3s16 p1, v3s16 p2);
NodeMetadata *getNodeMetadata(v3s16 p);/** * Sets metadata for a node. * This method sets the metadata for a given node. * On success, it returns @c true and the object pointed to * by @p meta is then managed by the system and should * not be deleted by the caller. * * In case of failure, the method returns @c false and the * caller is still responsible for deleting the object! * * @param p node coordinates * @param meta pointer to @c NodeMetadata object * @return @c true on success, false on failure */boolsetNodeMetadata(v3s16 p, NodeMetadata *meta);voidremoveNodeMetadata(v3s16 p);/* Node Timers These are basically coordinate wrappers to MapBlock */
NodeTimer getNodeTimer(v3s16 p);voidsetNodeTimer(const NodeTimer &t);voidremoveNodeTimer(v3s16 p);/* Misc. */std::map<v2s16, MapSector*> *getSectorsPtr(){return&m_sectors;}/* Variables */voidtransforming_liquid_add(v3s16 p);boolisBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes);protected:friend class LuaVoxelManip;std::ostream &m_dout;// A bit deprecated, could be removed
IGameDef *m_gamedef;std::set<MapEventReceiver*> m_event_receivers;std::map<v2s16, MapSector*> m_sectors;// Be sure to set this to NULL when the cached sector is deleted
MapSector *m_sector_cache =nullptr;
v2s16 m_sector_cache_p;// Queued transforming water nodes
UniqueQueue<v3s16> m_transforming_liquid;// This stores the properties of the nodes on the map.const NodeDefManager *m_nodedef;booldetermineAdditionalOcclusionCheck(const v3s16 &pos_camera,constcore::aabbox3d<s16> &block_bounds, v3s16 &check);boolisOccluded(const v3s16 &pos_camera,const v3s16 &pos_target,float step,float stepfac,float start_offset,float end_offset,
u32 needed_count);private:
f32 m_transforming_liquid_loop_count_multiplier =1.0f;
u32 m_unprocessed_count =0;
u64 m_inc_trending_up_start_time =0;// millisecondsbool m_queue_size_timer_started =false;};/* ServerMap This is the only map class that is able to generate map.*/class ServerMap :public Map
{public:/* savedir: directory to which map data should be saved */ServerMap(conststd::string &savedir, IGameDef *gamedef, EmergeManager *emerge);~ServerMap();
s32 mapType()const{return MAPTYPE_SERVER;}/* Get a sector from somewhere. - Check memory - Check disk (doesn't load blocks) - Create blank one */
MapSector *createSector(v2s16 p);/* Blocks are generated by using these and makeBlock(). */boolblockpos_over_mapgen_limit(v3s16 p);boolinitBlockMake(v3s16 blockpos, BlockMakeData *data);voidfinishBlockMake(BlockMakeData *data,std::map<v3s16, MapBlock*> *changed_blocks);/* Get a block from somewhere. - Memory - Create blank */
MapBlock *createBlock(v3s16 p);/* Forcefully get a block from somewhere. - Memory - Load from disk - Create blank filled with CONTENT_IGNORE */
MapBlock *emergeBlock(v3s16 p,bool create_blank=true);/* Try to get a block. If it does not exist in memory, add it to the emerge queue. - Memory - Emerge Queue (deferred disk or generate) */
MapBlock *getBlockOrEmerge(v3s16 p3d);// Helper for placing objects on ground level
s16 findGroundLevel(v2s16 p2d);/* Misc. helper functions for fiddling with directory and file names when saving */voidcreateDirs(conststd::string &path);/* Database functions */static MapDatabase *createDatabase(conststd::string &name,conststd::string &savedir, Settings &conf);// Call these before and after saving of blocksvoidbeginSave();voidendSave();voidsave(ModifiedState save_level);voidlistAllLoadableBlocks(std::vector<v3s16> &dst);voidlistAllLoadedBlocks(std::vector<v3s16> &dst);
MapgenParams *getMapgenParams();boolsaveBlock(MapBlock *block);static boolsaveBlock(MapBlock *block, MapDatabase *db);
MapBlock*loadBlock(v3s16 p);// Database versionvoidloadBlock(std::string *blob, v3s16 p3d, MapSector *sector,bool save_after_load=false);booldeleteBlock(v3s16 blockpos);voidupdateVManip(v3s16 pos);// For debug printingvirtualvoidPrintInfo(std::ostream &out);boolisSavingEnabled(){return m_map_saving_enabled; }
u64 getSeed();
s16 getWaterLevel();/*! * Fixes lighting in one map block. * May modify other blocks as well, as light can spread * out of the specified block. * Returns false if the block is not generated (so nothing * changed), true otherwise. */boolrepairBlockLight(v3s16 blockpos,std::map<v3s16, MapBlock *> *modified_blocks);
MapSettingsManager settings_mgr;private:// Emerge manager
EmergeManager *m_emerge;std::string m_savedir;bool m_map_saving_enabled;#if 0// Chunk size in MapSectors// If 0, chunks are disabled.
s16 m_chunksize;// Chunkscore::map<v2s16, MapChunk*> m_chunks;#endif/* Metadata is re-written on disk only if this is true. This is reset to false when written on disk. */bool m_map_metadata_changed =true;
MapDatabase *dbase =nullptr;
MapDatabase *dbase_ro =nullptr;};#define VMANIP_BLOCK_DATA_INEXIST 1#define VMANIP_BLOCK_CONTAINS_CIGNORE 2class MMVManip :public VoxelManipulator
{public:MMVManip(Map *map);virtual~MMVManip() =default;virtualvoidclear(){VoxelManipulator::clear();
m_loaded_blocks.clear();}voidinitialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,bool load_if_inexistent =true);// This is much faster with big chunks of generated datavoidblitBackAll(std::map<v3s16, MapBlock*> * modified_blocks,bool overwrite_generated =true);bool m_is_dirty =false;protected:
Map *m_map;/* key = blockpos value = flags describing the block */std::map<v3s16, u8> m_loaded_blocks;};