/*
Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
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
#include <jmutex.h>
#include <jthread.h>
#include <iostream>
-#include <malloc.h>
#ifdef _WIN32
#include <windows.h>
#endif
#include "common_irrlicht.h"
-//#include "heightmap.h"
#include "mapnode.h"
#include "mapblock.h"
#include "mapsector.h"
#include "constants.h"
#include "voxel.h"
#include "mapchunk.h"
+#include "nodemetadata.h"
#define MAPTYPE_BASE 0
#define MAPTYPE_SERVER 1
#define MAPTYPE_CLIENT 2
+enum MapEditEventType{
+ MEET_ADDNODE,
+ MEET_REMOVENODE,
+ MEET_OTHER
+};
+
+struct MapEditEvent
+{
+ MapEditEventType type;
+ v3s16 p;
+ MapNode n;
+ core::map<v3s16, bool> 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;
+ for(core::map<v3s16, bool>::Iterator
+ i = modified_blocks.getIterator();
+ i.atEnd()==false; i++)
+ {
+ v3s16 p = i.getNode()->getKey();
+ bool v = i.getNode()->getValue();
+ event->modified_blocks.insert(p, v);
+ }
+ return event;
+ }
+};
+
+class MapEventReceiver
+{
+public:
+ // event shall be deleted by caller after the call.
+ virtual void onMapEditEvent(MapEditEvent *event) = 0;
+};
+
class Map : public NodeContainer
{
public:
{
return MAPTYPE_BASE;
}
-
+
+ /*
+ Drop (client) or delete (server) the map.
+ */
virtual void drop()
{
delete this;
}
- void updateCamera(v3f pos, v3f dir)
- {
- JMutexAutoLock lock(m_camera_mutex);
- m_camera_position = pos;
- m_camera_direction = dir;
- }
+ void addEventReceiver(MapEventReceiver *event_receiver);
+ void removeEventReceiver(MapEventReceiver *event_receiver);
+ // event shall be deleted by caller after the call.
+ void dispatchEvent(MapEditEvent *event);
- static core::aabbox3d<f32> getNodeBox(v3s16 p)
- {
- return core::aabbox3d<f32>(
- (float)p.X * BS - 0.5*BS,
- (float)p.Y * BS - 0.5*BS,
- (float)p.Z * BS - 0.5*BS,
- (float)p.X * BS + 0.5*BS,
- (float)p.Y * BS + 0.5*BS,
- (float)p.Z * BS + 0.5*BS
- );
- }
-
// On failure returns NULL
MapSector * getSectorNoGenerateNoExNoLock(v2s16 p2d);
// On failure returns NULL
// Gets an existing block or creates an empty one
//MapBlock * getBlockCreate(v3s16 p);
- // Returns InvalidPositionException if not found
- f32 getGroundHeight(v2s16 p, bool generate=false);
- void setGroundHeight(v2s16 p, f32 y, bool generate=false);
-
// Returns InvalidPositionException if not found
bool isNodeUnderground(v3s16 p);
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
blockref->setNodeNoCheck(relpos, n);
}
-
- /*MapNode getNodeGenerate(v3s16 p)
+
+ // Returns a CONTENT_IGNORE node if not found
+ MapNode getNodeNoEx(v3s16 p)
{
- v3s16 blockpos = getNodeBlockPos(p);
- MapBlock * blockref = getBlock(blockpos);
- v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
-
- return blockref->getNode(relpos);
- }*/
+ try{
+ v3s16 blockpos = getNodeBlockPos(p);
+ MapBlock * blockref = getBlockNoCreate(blockpos);
+ v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
- /*void setNodeGenerate(v3s16 p, MapNode & n)
- {
- v3s16 blockpos = getNodeBlockPos(p);
- MapBlock * blockref = getBlock(blockpos);
- v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
- blockref->setNode(relpos, n);
- }*/
+ return blockref->getNodeNoCheck(relpos);
+ }
+ catch(InvalidPositionException &e)
+ {
+ return MapNode(CONTENT_IGNORE);
+ }
+ }
void unspreadLight(enum LightBank bank,
core::map<v3s16, u8> & from_nodes,
core::map<v3s16, MapBlock*> &modified_blocks);
void removeNodeAndUpdate(v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks);
-
-#ifndef SERVER
- void expireMeshes(bool only_daynight_diffed);
-
+
/*
- Update the faces of the given block and blocks on the
- leading edge.
+ Wrappers for the latter ones.
+ These emit events.
+ Return true if succeeded, false if not.
*/
- void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
+ bool addNodeWithEvent(v3s16 p, MapNode n);
+ bool removeNodeWithEvent(v3s16 p);
- // Update meshes that touch the node
- //void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
-#endif
-
/*
Takes the blocks at the edges into account
*/
void transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks);
+ /*
+ Node metadata
+ These are basically coordinate wrappers to MapBlock
+ */
+
+ NodeMetadata* getNodeMetadata(v3s16 p);
+ void setNodeMetadata(v3s16 p, NodeMetadata *meta);
+ void removeNodeMetadata(v3s16 p);
+ void nodeMetadataStep(float dtime,
+ core::map<v3s16, MapBlock*> &changed_blocks);
+
+ /*
+ Misc.
+ */
+ core::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;}
+
/*
Variables
*/
std::ostream &m_dout;
+ core::map<MapEventReceiver*, bool> m_event_receivers;
+
core::map<v2s16, MapSector*> m_sectors;
- JMutex m_sector_mutex;
-
- v3f m_camera_position;
- v3f m_camera_direction;
- JMutex m_camera_mutex;
+ //JMutex m_sector_mutex;
// Be sure to set this to NULL when the cached sector is deleted
MapSector *m_sector_cache;
v2s16 m_sector_cache_p;
- //WrapperHeightmap m_hwrapper;
-
// Queued transforming water nodes
UniqueQueue<v3s16> m_transforming_liquid;
};
This is the only map class that is able to generate map.
*/
+struct ChunkMakeData;
+
class ServerMap : public Map
{
public:
// Returns the position of the chunk where the sector is in
v2s16 sector_to_chunk(v2s16 sectorpos)
{
+ if(m_chunksize == 0)
+ return v2s16(0,0);
sectorpos.X += m_chunksize / 2;
sectorpos.Y += m_chunksize / 2;
v2s16 chunkpos = getContainerPos(sectorpos, m_chunksize);
// Returns the position of the (0,0) sector of the chunk
v2s16 chunk_to_sector(v2s16 chunkpos)
{
+ if(m_chunksize == 0)
+ return v2s16(0,0);
v2s16 sectorpos(
chunkpos.X * m_chunksize,
chunkpos.Y * m_chunksize
*/
bool chunkNonVolatile(v2s16 chunkpos)
{
+ if(m_chunksize == 0)
+ return true;
+
/*for(s16 x=-1; x<=1; x++)
for(s16 y=-1; y<=1; y++)*/
s16 x=0;
}
return true;
}
+
+ /*
+ Returns true if any chunk is marked as modified
+ */
+ bool anyChunkModified()
+ {
+ for(core::map<v2s16, MapChunk*>::Iterator
+ i = m_chunks.getIterator();
+ i.atEnd()==false; i++)
+ {
+ v2s16 p = i.getNode()->getKey();
+ MapChunk *chunk = i.getNode()->getValue();
+ if(chunk->isModified())
+ return true;
+ }
+ return false;
+ }
+
+ void setChunksNonModified()
+ {
+ for(core::map<v2s16, MapChunk*>::Iterator
+ i = m_chunks.getIterator();
+ i.atEnd()==false; i++)
+ {
+ v2s16 p = i.getNode()->getKey();
+ MapChunk *chunk = i.getNode()->getValue();
+ chunk->setModified(false);
+ }
+ }
+
+ /*
+ Chunks are generated by using these and makeChunk().
+ */
+ void initChunkMake(ChunkMakeData &data, v2s16 chunkpos);
+ MapChunk* finishChunkMake(ChunkMakeData &data,
+ core::map<v3s16, MapBlock*> &changed_blocks);
/*
Generate a chunk.
All chunks touching this one can be altered also.
*/
- MapChunk* generateChunkRaw(v2s16 chunkpos,
- core::map<v3s16, MapBlock*> &changed_blocks);
+ /*MapChunk* generateChunkRaw(v2s16 chunkpos,
+ core::map<v3s16, MapBlock*> &changed_blocks,
+ bool force=false);*/
/*
Generate a chunk and its neighbors so that it won't be touched
anymore.
*/
- MapChunk* generateChunk(v2s16 chunkpos,
- core::map<v3s16, MapBlock*> &changed_blocks);
+ /*MapChunk* generateChunk(v2s16 chunkpos,
+ core::map<v3s16, MapBlock*> &changed_blocks);*/
/*
Generate a sector.
- Check disk (loads blocks also)
- Generate chunk
*/
- MapSector * emergeSector(v2s16 p,
- core::map<v3s16, MapBlock*> &changed_blocks);
+ /*MapSector * emergeSector(v2s16 p,
+ core::map<v3s16, MapBlock*> &changed_blocks);*/
- MapSector * emergeSector(v2s16 p)
+ /*MapSector * emergeSector(v2s16 p)
{
core::map<v3s16, MapBlock*> changed_blocks;
return emergeSector(p, changed_blocks);
- }
+ }*/
MapBlock * generateBlock(
v3s16 p,
core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
);
#endif
+
+ // Helper for placing objects on ground level
+ s16 findGroundLevel(v2s16 p2d);
/*
Misc. helper functions for fiddling with directory and file
v3s16 getBlockPos(std::string sectordir, std::string blockfile);
void save(bool only_changed);
- void loadAll();
+ //void loadAll();
- // TODO
+ // Saves map seed and possibly other stuff
void saveMapMeta();
void loadMapMeta();
- // TODO
void saveChunkMeta();
void loadChunkMeta();
- // DEPRECATED
- void saveMasterHeightmap();
- void loadMasterHeightmap();
-
// The sector mutex should be locked when calling most of these
// This only saves sector-specific data such as the heightmap
// This will generate a sector with getSector if not found.
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
- // Gets from master heightmap
- // DEPRECATED?
- void getSectorCorners(v2s16 p2d, s16 *corners);
-
// For debug printing
virtual void PrintInfo(std::ostream &out);
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;
};
/*
ISceneNode::drop();
}
+ void updateCamera(v3f pos, v3f dir)
+ {
+ JMutexAutoLock lock(m_camera_mutex);
+ m_camera_position = pos;
+ m_camera_direction = dir;
+ }
+
/*
Forcefully get a sector from somewhere
*/
// Efficient implementation needs a cache of TempMods
//void clearTempMods();
+ void expireMeshes(bool only_daynight_diffed);
+
+ /*
+ Update the faces of the given block and blocks on the
+ leading edge.
+ */
+ void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
+
+ // Update meshes that touch the node
+ //void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
+
// For debug printing
virtual void PrintInfo(std::ostream &out);
//JMutex mesh_mutex;
MapDrawControl &m_control;
+
+ v3f m_camera_position;
+ v3f m_camera_direction;
+ JMutex m_camera_mutex;
+
};
#endif
public:
ManualMapVoxelManipulator(Map *map);
virtual ~ManualMapVoxelManipulator();
+
+ void setMap(Map *map)
+ {m_map = map;}
virtual void emerge(VoxelArea a, s32 caller_id=-1);
bool m_create_area;
};
+struct ChunkMakeData
+{
+ bool no_op;
+ ManualMapVoxelManipulator vmanip;
+ u64 seed;
+ v2s16 chunkpos;
+ s16 y_blocks_min;
+ s16 y_blocks_max;
+ v2s16 sectorpos_base;
+ s16 sectorpos_base_size;
+ v2s16 sectorpos_bigbase;
+ s16 sectorpos_bigbase_size;
+ s16 max_spread_amount;
+ UniqueQueue<v3s16> transforming_liquid;
+
+ ChunkMakeData():
+ no_op(false),
+ vmanip(NULL),
+ seed(0)
+ {}
+};
+
+void makeChunk(ChunkMakeData *data);
+
#endif