Skip to content
Snippets Groups Projects
map.h 14.1 KiB
Newer Older
Perttu Ahola's avatar
Perttu Ahola committed
/*
Minetest
sfan5's avatar
sfan5 committed
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Perttu Ahola's avatar
Perttu Ahola committed

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
Perttu Ahola's avatar
Perttu Ahola committed
(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 Lesser General Public License for more details.
Perttu Ahola's avatar
Perttu Ahola committed

You should have received a copy of the GNU Lesser General Public License along
Perttu Ahola's avatar
Perttu Ahola committed
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Perttu Ahola's avatar
Perttu Ahola committed
*/

#ifndef MAP_HEADER
#define MAP_HEADER

#include <iostream>
JacobF's avatar
JacobF committed
#include <sstream>
#include <set>
#include <map>
#include <list>
Perttu Ahola's avatar
Perttu Ahola committed

Perttu Ahola's avatar
Perttu Ahola committed
#include "irrlichttypes_bloated.h"
Perttu Ahola's avatar
Perttu Ahola committed
#include "mapnode.h"
#include "constants.h"
#include "util/container.h"
darkrose's avatar
darkrose committed
#include "nodetimer.h"
JacobF's avatar
JacobF committed

class Database;
class ClientMap;
Perttu Ahola's avatar
Perttu Ahola committed
class MapSector;
class ServerMapSector;
class MapBlock;
Perttu Ahola's avatar
Perttu Ahola committed
class NodeMetadata;
class IRollbackReportSink;
class EmergeManager;
Perttu Ahola's avatar
Perttu Ahola committed

/*
	MapEditEvent
*/

Perttu Ahola's avatar
Perttu Ahola committed
#define MAPTYPE_BASE 0
#define MAPTYPE_SERVER 1
#define MAPTYPE_CLIENT 2

enum MapEditEventType{
	// Node added (changed from air or something else to something)
	MEET_ADDNODE,
	MEET_REMOVENODE,
	// Node metadata of block changed (not knowing which node exactly)
	// p stores block coordinate
	MEET_BLOCK_NODE_METADATA_CHANGED,
	// Anything else (modified_blocks are set unsent)
	MEET_OTHER
};

struct MapEditEvent
{
	MapEditEventType type;
	v3s16 p;
	MapNode n;
	std::set<v3s16> modified_blocks;
	u16 already_known_by_peer;

	MapEditEvent():
		type(MEET_OTHER),
		already_known_by_peer(0)
	{
	}
	MapEditEvent * clone()
	{
		MapEditEvent *event = new MapEditEvent();
		event->type = type;
		event->p = p;
		event->n = n;
		event->modified_blocks = modified_blocks;
		return event;
	}

	VoxelArea getArea()
	{
		switch(type){
		case MEET_ADDNODE:
			return VoxelArea(p);
		case MEET_REMOVENODE:
			return VoxelArea(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);
			return VoxelArea(np1, np2);
		}
		case MEET_OTHER:
		{
			VoxelArea a;
			for(std::set<v3s16>::iterator
					i = modified_blocks.begin();
					i != modified_blocks.end(); ++i)
				v3s16 p = *i;
				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;
		}
		}
		return VoxelArea();
	}
};

class MapEventReceiver
{
public:
	// event shall be deleted by caller after the call.
	virtual void onMapEditEvent(MapEditEvent *event) = 0;
};

class Map /*: public NodeContainer*/
Perttu Ahola's avatar
Perttu Ahola committed
{
public:

Perttu Ahola's avatar
Perttu Ahola committed
	virtual ~Map();

	/*virtual u16 nodeContainerId() const
Perttu Ahola's avatar
Perttu Ahola committed
	{
		return NODECONTAINER_ID_MAP;
Perttu Ahola's avatar
Perttu Ahola committed

	virtual s32 mapType() const
	{
		return MAPTYPE_BASE;
	}
	/*
		Drop (client) or delete (server) the map.
	*/
	virtual void drop()
	{
		delete this;
	}

	void addEventReceiver(MapEventReceiver *event_receiver);
	void removeEventReceiver(MapEventReceiver *event_receiver);
	// event shall be deleted by caller after the call.
	void dispatchEvent(MapEditEvent *event);
	// On failure returns NULL
	MapSector * getSectorNoGenerateNoExNoLock(v2s16 p2d);
	// Same as the above (there exists no lock anymore)
	MapSector * getSectorNoGenerateNoEx(v2s16 p2d);
	// On failure throws InvalidPositionException
Perttu Ahola's avatar
Perttu Ahola committed
	MapSector * getSectorNoGenerate(v2s16 p2d);
	// Gets an existing sector or creates an empty one
	//MapSector * getSectorCreate(v2s16 p2d);
Perttu Ahola's avatar
Perttu Ahola committed
	/*
		This is overloaded by ClientMap and ServerMap to allow
		their differing fetch methods.
	*/
	virtual MapSector * emergeSector(v2s16 p){ return NULL; }
	virtual MapSector * emergeSector(v2s16 p,
			std::map<v3s16, MapBlock*> &changed_blocks){ return NULL; }
Perttu Ahola's avatar
Perttu Ahola committed
	// Returns InvalidPositionException if not found
	MapBlock * getBlockNoCreate(v3s16 p);
Perttu Ahola's avatar
Perttu Ahola committed
	// Returns NULL if not found
	MapBlock * getBlockNoCreateNoEx(v3s16 p);
	/* Server overrides */
	virtual MapBlock * emergeBlock(v3s16 p, bool allow_generate=true)
	{ return getBlockNoCreateNoEx(p); }

Perttu Ahola's avatar
Perttu Ahola committed
	// Returns InvalidPositionException if not found
	bool isNodeUnderground(v3s16 p);
Perttu Ahola's avatar
Perttu Ahola committed
	bool isValidPosition(v3s16 p);
Perttu Ahola's avatar
Perttu Ahola committed
	// throws InvalidPositionException if not found
Perttu Ahola's avatar
Perttu Ahola committed
	MapNode getNode(v3s16 p);
Perttu Ahola's avatar
Perttu Ahola committed

Perttu Ahola's avatar
Perttu Ahola committed
	// throws InvalidPositionException if not found
Perttu Ahola's avatar
Perttu Ahola committed
	void setNode(v3s16 p, MapNode & n);
	// Returns a CONTENT_IGNORE node if not found
Perttu Ahola's avatar
Perttu Ahola committed
	MapNode getNodeNoEx(v3s16 p);
Perttu Ahola's avatar
Perttu Ahola committed

Perttu Ahola's avatar
Perttu Ahola committed
	void unspreadLight(enum LightBank bank,
			std::map<v3s16, u8> & from_nodes,
			std::set<v3s16> & light_sources,
			std::map<v3s16, MapBlock*> & modified_blocks);
Perttu Ahola's avatar
Perttu Ahola committed

Perttu Ahola's avatar
Perttu Ahola committed
	void unLightNeighbors(enum LightBank bank,
			v3s16 pos, u8 lightwas,
			std::set<v3s16> & light_sources,
			std::map<v3s16, MapBlock*> & modified_blocks);
Perttu Ahola's avatar
Perttu Ahola committed
	void spreadLight(enum LightBank bank,
			std::set<v3s16> & from_nodes,
			std::map<v3s16, MapBlock*> & modified_blocks);
Perttu Ahola's avatar
Perttu Ahola committed
	void lightNeighbors(enum LightBank bank,
			v3s16 pos,
			std::map<v3s16, MapBlock*> & modified_blocks);
Perttu Ahola's avatar
Perttu Ahola committed

Perttu Ahola's avatar
Perttu Ahola committed
	v3s16 getBrightestNeighbour(enum LightBank bank, v3s16 p);
Perttu Ahola's avatar
Perttu Ahola committed

	s16 propagateSunlight(v3s16 start,
			std::map<v3s16, MapBlock*> & modified_blocks);
Perttu Ahola's avatar
Perttu Ahola committed
	void updateLighting(enum LightBank bank,
			std::map<v3s16, MapBlock*>  & a_blocks,
			std::map<v3s16, MapBlock*> & modified_blocks);
	void updateLighting(std::map<v3s16, MapBlock*>  & a_blocks,
			std::map<v3s16, MapBlock*> & modified_blocks);
Perttu Ahola's avatar
Perttu Ahola committed
	/*
		These handle lighting but not faces.
	*/
	void addNodeAndUpdate(v3s16 p, MapNode n,
			std::map<v3s16, MapBlock*> &modified_blocks);
Perttu Ahola's avatar
Perttu Ahola committed
	void removeNodeAndUpdate(v3s16 p,
			std::map<v3s16, MapBlock*> &modified_blocks);

	/*
		Wrappers for the latter ones.
		These emit events.
		Return true if succeeded, false if not.
	*/
	bool addNodeWithEvent(v3s16 p, MapNode n);
	bool removeNodeWithEvent(v3s16 p);
Perttu Ahola's avatar
Perttu Ahola committed
		Takes the blocks at the edges into account
Perttu Ahola's avatar
Perttu Ahola committed

	//core::aabbox3d<s16> getDisplayedBlockArea();

	//bool updateChangedVisibleArea();
JacobF's avatar
JacobF committed

	// Call these before and after saving of many blocks
	virtual void beginSave() {return;};
	virtual void endSave() {return;};
	virtual void save(ModifiedState save_level){assert(0);};
	// Server implements this.
	// Client leaves it as no-op.
	virtual void saveBlock(MapBlock *block){};
Perttu Ahola's avatar
Perttu Ahola committed

	/*
		Updates usage timers and unloads unused blocks and sectors.
		Saves modified blocks before unloading on MAPTYPE_SERVER.
Perttu Ahola's avatar
Perttu Ahola committed
	*/
	void timerUpdate(float dtime, float unload_timeout,
			std::list<v3s16> *unloaded_blocks=NULL);
	/*
		Unloads all blocks with a zero refCount().
		Saves modified blocks before unloading on MAPTYPE_SERVER.
	*/
	void unloadUnreferencedBlocks(std::list<v3s16> *unloaded_blocks=NULL);

	// Deletes sectors and their blocks from memory
Perttu Ahola's avatar
Perttu Ahola committed
	// Takes cache into account
	// If deleted sector is in sector cache, clears cache
	void deleteSectors(std::list<v2s16> &list);
	/*
		Unload unused data
		= flush changed to disk and delete from memory, if usage timer of
		  block is more than timeout
	*/
	void unloadUnusedData(float timeout,
Perttu Ahola's avatar
Perttu Ahola committed
			core::list<v3s16> *deleted_blocks=NULL);
Perttu Ahola's avatar
Perttu Ahola committed

	// For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: "
Perttu Ahola's avatar
Perttu Ahola committed
	virtual void PrintInfo(std::ostream &out);
	void transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks);
	void transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks);
	/*
		Node metadata
		These are basically coordinate wrappers to MapBlock
	*/
Perttu Ahola's avatar
Perttu Ahola committed
	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
	 */
	bool setNodeMetadata(v3s16 p, NodeMetadata *meta);
Perttu Ahola's avatar
Perttu Ahola committed
	void removeNodeMetadata(v3s16 p);
darkrose's avatar
darkrose committed
	/*
		Node Timers
		These are basically coordinate wrappers to MapBlock
	*/
darkrose's avatar
darkrose committed
	NodeTimer getNodeTimer(v3s16 p);
	void setNodeTimer(v3s16 p, NodeTimer t);
	void removeNodeTimer(v3s16 p);

	std::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;}
proller's avatar
proller committed
	void transforming_liquid_add(v3s16 p);
	s32 transforming_liquid_size();

proller's avatar
proller committed
	virtual s16 getHeat(v3s16 p);
	virtual s16 getHumidity(v3s16 p);

kwolekr's avatar
kwolekr committed
	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;
	v2s16 m_sector_cache_p;

	// Queued transforming water nodes
	UniqueQueue<v3s16> m_transforming_liquid;
Perttu Ahola's avatar
Perttu Ahola committed
};

/*
	ServerMap

	This is the only map class that is able to generate map.
*/

Perttu Ahola's avatar
Perttu Ahola committed
class ServerMap : public Map
{
public:
	/*
		savedir: directory to which map data should be saved
	*/
	ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge);
Perttu Ahola's avatar
Perttu Ahola committed
	~ServerMap();

	s32 mapType() const
	{
		return MAPTYPE_SERVER;
	}

		- Create blank one
	*/
	ServerMapSector * createSector(v2s16 p);
		Blocks are generated by using these and makeBlock().
Perttu Ahola's avatar
Perttu Ahola committed
	*/
kwolekr's avatar
kwolekr committed
	bool initBlockMake(BlockMakeData *data, v3s16 blockpos);
	MapBlock *finishBlockMake(BlockMakeData *data,
			std::map<v3s16, MapBlock*> &changed_blocks);
	/*
		Get a block from somewhere.
		- Memory
		- Create blank
	*/
	MapBlock * createBlock(v3s16 p);
Perttu Ahola's avatar
Perttu Ahola committed
	/*
		Forcefully get a block from somewhere.
		- Create blank filled with CONTENT_IGNORE
Perttu Ahola's avatar
Perttu Ahola committed
	*/
	MapBlock * emergeBlock(v3s16 p, bool create_blank=true);
kwolekr's avatar
kwolekr committed
	
	// Carries out any initialization necessary before block is sent
	void prepareBlock(MapBlock *block);
	// Helper for placing objects on ground level
	s16 findGroundLevel(v2s16 p2d);
Perttu Ahola's avatar
Perttu Ahola committed

	/*
		Misc. helper functions for fiddling with directory and file
		names when saving
	*/
Perttu Ahola's avatar
Perttu Ahola committed
	// returns something like "map/sectors/xxxxxxxx"
	std::string getSectorDir(v2s16 pos, int layout = 2);
Perttu Ahola's avatar
Perttu Ahola committed
	// dirname: final directory name
	v2s16 getSectorPos(std::string dirname);
	v3s16 getBlockPos(std::string sectordir, std::string blockfile);
	static std::string getBlockFilename(v3s16 p);
Perttu Ahola's avatar
Perttu Ahola committed

JacobF's avatar
JacobF committed
	/*
		Database functions
	*/
	// Verify we can read/write to the database
	void verifyDatabase();

	// Returns true if the database file does not exist
	bool loadFromFolders();

	// Call these before and after saving of blocks
	void beginSave();
	void endSave();

	void listAllLoadableBlocks(std::list<v3s16> &dst);
	void listAllLoadedBlocks(std::list<v3s16> &dst);
Perttu Ahola's avatar
Perttu Ahola committed
	// Saves map seed and possibly other stuff
Perttu Ahola's avatar
Perttu Ahola committed
	void saveMapMeta();
	void loadMapMeta();
	/*void saveChunkMeta();
	void loadChunkMeta();*/
Perttu Ahola's avatar
Perttu Ahola committed
	// The sector mutex should be locked when calling most of these
Perttu Ahola's avatar
Perttu Ahola committed
	// This only saves sector-specific data such as the heightmap
	// (no MapBlocks)
Perttu Ahola's avatar
Perttu Ahola committed
	// DEPRECATED? Sectors have no metadata anymore.
Perttu Ahola's avatar
Perttu Ahola committed
	void saveSectorMeta(ServerMapSector *sector);
	MapSector* loadSectorMeta(std::string dirname, bool save_after_load);
Perttu Ahola's avatar
Perttu Ahola committed
	// Full load of a sector including all blocks.
	// returns true on success, false on failure.
	bool loadSectorFull(v2s16 p2d);
	// If sector is not found in memory, try to load it from disk.
	// Returns true if sector now resides in memory
	//bool deFlushSector(v2s16 p2d);
Perttu Ahola's avatar
Perttu Ahola committed
	void saveBlock(MapBlock *block);
	// This will generate a sector with getSector if not found.
	void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
JacobF's avatar
JacobF committed
	// Database version
	void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false);
Perttu Ahola's avatar
Perttu Ahola committed

	// For debug printing
	virtual void PrintInfo(std::ostream &out);

	bool isSavingEnabled(){ return m_map_saving_enabled; }

	u64 getSeed(){ return m_seed; }

	MapgenParams *getMapgenParams(){ return m_mgparams; }

	// Parameters fed to the Mapgen
	MapgenParams *m_mgparams;
proller's avatar
proller committed

	virtual s16 updateBlockHeat(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL);
	virtual s16 updateBlockHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL);
proller's avatar
proller committed

Perttu Ahola's avatar
Perttu Ahola committed
private:
	// Seed used for all kinds of randomness in generation
	u64 m_seed;
	// Emerge manager
	EmergeManager *m_emerge;

Perttu Ahola's avatar
Perttu Ahola committed
	std::string m_savedir;
	bool m_map_saving_enabled;
	// Chunk size in MapSectors
	// If 0, chunks are disabled.
	s16 m_chunksize;
	// Chunks
	core::map<v2s16, MapChunk*> m_chunks;

	/*
		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;
	Database *dbase;
Perttu Ahola's avatar
Perttu Ahola committed
};

kwolekr's avatar
kwolekr committed
#define VMANIP_BLOCK_DATA_INEXIST     1
#define VMANIP_BLOCK_CONTAINS_CIGNORE 2

class MapVoxelManipulator : public VoxelManipulator
{
public:
	MapVoxelManipulator(Map *map);
	virtual ~MapVoxelManipulator();
	virtual void clear()
	{
		VoxelManipulator::clear();
		m_loaded_blocks.clear();
	}

	virtual void emerge(VoxelArea a, s32 caller_id=-1);
	void blitBack(std::map<v3s16, MapBlock*> & modified_blocks);

protected:
	Map *m_map;
kwolekr's avatar
kwolekr committed
		value = flags describing the block
	std::map<v3s16, u8> m_loaded_blocks;
class ManualMapVoxelManipulator : public MapVoxelManipulator
{
public:
	ManualMapVoxelManipulator(Map *map);
	virtual ~ManualMapVoxelManipulator();
	virtual void emerge(VoxelArea a, s32 caller_id=-1);

	void initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
						bool load_if_inexistent = true);
	// This is much faster with big chunks of generated data
	void blitBackAll(std::map<v3s16, MapBlock*> * modified_blocks);
Perttu Ahola's avatar
Perttu Ahola committed
#endif