Minetest源码分析十二:ServerMap

来源:互联网 发布:淘宝卖家网 编辑:程序博客网 时间:2024/05/20 18:47

Minetest源码分析十二:ServerMap


minetest->map.h/map.cpp

ServerMap:生成地图的类,地图数据库的存储与访问,地图meta数据的存储与读取。

处理MapBlock的存储以及获取生成;在这个类中会与数据库或者其它类型数据文件进行通信处理;另serverMap是继承于Map类的,所以还包括了Map类中的一些操作,譬如MapSector的创建以及MapNode的获取、存储、remove等操作。


ServerMap创建与调用

在minetest/server.cpp中Server类的构造函数中创建,并存储在ServerEnvironment对象中,当程序运行时,只有一个ServerEnvironment环境存在。所有后期都是通过ServerEnvironment获取出来的。

ServerMap *servermap = newServerMap(path_world, this, m_emerge);

m_env = newServerEnvironment(servermap,m_script, this);


主要使用的地方:ServerEnvironment类以及EmergeThread类中。ServerEnvironment类是存储它的地方,EmergeThread类中使用它来创建生成MapBlock


ServerMap定义

继承Map




重要函数介绍

(1)ServerMap构造函数

加载地图数据库,若没有创建(根据world.mt);加载地图元数据(map_meta.txt: chunksize、mg_flags等)

ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge): Map(dout_server, gamedef), m_emerge(emerge), m_map_metadata_changed(true){/*Try to load map; if not found, create a new one.*/// Determine which database backend to usestd::string conf_path = savedir + DIR_DELIM + "world.mt";Settings conf;bool succeeded = conf.readConfigFile(conf_path.c_str());if (!succeeded || !conf.exists("backend")) {// fall back to sqlite3dbase = new Database_SQLite3(this, savedir);conf.set("backend", "sqlite3");} else {std::string backend = conf.get("backend");if (backend == "dummy")dbase = new Database_Dummy(this);else if (backend == "sqlite3")dbase = new Database_SQLite3(this, savedir);#if USE_LEVELDBelse if (backend == "leveldb")dbase = new Database_LevelDB(this, savedir);#endif#if USE_REDISelse if (backend == "redis")dbase = new Database_Redis(this, savedir);#endifelsethrow BaseException("Unknown map backend");}m_savedir = savedir;m_map_saving_enabled = false;try{// If directory exists, check contents and load if possibleif(fs::PathExists(m_savedir)){// If directory is empty, it is safe to save into it.if(fs::GetDirListing(m_savedir).size() == 0){infostream<<"ServerMap: Empty save directory is valid."<


(2)boolServerMap::initBlockMake(BlockMakeData *data,v3s16 blockpos)


初始创建BlockMakeData,输入是block位置信息,返回BlockMakeData数据。之后一般需要使用mapgen->makeChunk(&data)来生成blockfinishBlockMake将数据设置到地图上,即设置到对应的block上。


调用:EmergeThread::getBlockOrStartGen()、MapBlock * ServerMap::generateBlock(),在这两个方法中调用。


initBlockMake这个函数作用:初始创建block在blockpos处的相关数据结构以及周围的一些数据结构,如block属于的MapSector、MapBlock、BlockMakeData。MapSector:内存已经有了不需要创建,若没有就创建空白的一个MapSector对象,最后存储在std::map<v2s16,MapSector*> m_sectors变量中,这个std::map变量存在Map对象中。MapBlock:内存中已经有了不需要创建,若没有就创建一个MapBlock对象,最后存储在MapBlock的x和z对应的MapSector中。MapSector 中有如下变量std::map<s16,MapBlock*> m_blocks;BlockMakeData:Block make 需要的一些数据,并不是block用于显示的具体数据,而是block make过程中需要用的普通参数。


bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos){bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;s16 chunksize = m_emerge->params.chunksize;s16 coffset = -chunksize / 2;v3s16 chunk_offset(coffset, coffset, coffset);v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);v3s16 blockpos_min = blockpos_div * chunksize;v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);blockpos_min += chunk_offset;blockpos_max += chunk_offset;v3s16 extra_borders(1,1,1);// Do nothing if not inside limits (+-1 because of neighbors)if(blockpos_over_limit(blockpos_min - extra_borders) ||blockpos_over_limit(blockpos_max + extra_borders))return false;data->seed = m_emerge->params.seed;data->blockpos_min = blockpos_min;data->blockpos_max = blockpos_max;data->blockpos_requested = blockpos;data->nodedef = m_gamedef->ndef();/*Create the whole area of this and the neighboring blocks*/{for(s16 x=blockpos_min.X-extra_borders.X; x<=blockpos_max.X+extra_borders.X; x++)for(s16 z=blockpos_min.Z-extra_borders.Z; z<=blockpos_max.Z+extra_borders.Z; z++){v2s16 sectorpos(x, z);// Sector metadata is loaded from disk if not already loaded.ServerMapSector *sector = createSector(sectorpos);assert(sector);(void) sector;for(s16 y=blockpos_min.Y-extra_borders.Y;y<=blockpos_max.Y+extra_borders.Y; y++){v3s16 p(x,y,z);//MapBlock *block = createBlock(p);// 1) get from memory, 2) load from diskMapBlock *block = emergeBlock(p, false);// 3) create a blank oneif(block == NULL){block = createBlock(p);/*Block gets sunlight if this is true.Refer to the map generator heuristics.*/bool ug = m_emerge->isBlockUnderground(p);block->setIsUnderground(ug);}// Lighting will not be valid after make_chunk is calledblock->setLightingExpired(true);}}}/*Now we have a big empty area.Make a ManualMapVoxelManipulator that contains this and theneighboring blocks*/// The area that contains this block and it's neighborsv3s16 bigarea_blocks_min = blockpos_min - extra_borders;v3s16 bigarea_blocks_max = blockpos_max + extra_borders;data->vmanip = new ManualMapVoxelManipulator(this);// Add the areadata->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max, false);// Data is ready now.return true;}


涉及到的函数:

minetest->emerge.h

struct BlockMakeData {

MMVManip *vmanip;

u64 seed;

v3s16 blockpos_min;

v3s16 blockpos_max;

v3s16 blockpos_requested;

UniqueQueue<v3s16> transforming_liquid;

INodeDefManager *nodedef;


BlockMakeData():

vmanip(NULL),

seed(0),

nodedef(NULL)

{}


~BlockMakeData() { deletevmanip; }

};



minetest->mapsector.h

MapSector:管理 x z固定的blocks。如deleteBlock、insertBlock等。

主要成员变量:

std::map<s16,MapBlock*> m_blocks,管理的xz固定下的所有blocks


主要方法:

MapBlock * getBlockNoCreateNoEx(s16 y)从内存中获取y位置的block。

MapBlock * createBlankBlock(s16 y)创建位置y处的block。



minetest->mapblock.h

MapBlock:管理block的一些属性以及Node的一些属性以及获取。




(3)MapBlock*ServerMap::finishBlockMake(BlockMakeData *data,std::map<v3s16,MapBlock*> &changed_blocks)

初始创建BlockMakeData,输入是block位置信息,返回BlockMakeData数据。之后一般需要使用mapgen->makeChunk(&data)来生成blockfinishBlockMake将数据设置到地图上,即设置到对应的block上。


功能:block的MapNode数据设置进去,并更新changed blocks的light、modified属性、Generated属性等。block的MapNode数据设置通过blitBackAll函数。


MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,std::map &changed_blocks){v3s16 blockpos_min = data->blockpos_min;v3s16 blockpos_max = data->blockpos_max;v3s16 blockpos_requested = data->blockpos_requested;v3s16 extra_borders(1,1,1);bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;// Make sure affected blocks are loadedfor(s16 x=blockpos_min.X-extra_borders.X;x<=blockpos_max.X+extra_borders.X; x++)for(s16 z=blockpos_min.Z-extra_borders.Z;z<=blockpos_max.Z+extra_borders.Z; z++)for(s16 y=blockpos_min.Y-extra_borders.Y;y<=blockpos_max.Y+extra_borders.Y; y++){v3s16 p(x, y, z);// Load from disk if not already in memoryemergeBlock(p, false);}/*Blit generated stuff to mapNOTE: blitBackAll adds nearly everything to changed_blocks*/{data->vmanip->blitBackAll(&changed_blocks);}/*Copy transforming liquid information*/while(data->transforming_liquid.size() > 0){v3s16 p = data->transforming_liquid.pop_front();m_transforming_liquid.push_back(p);}/*Do stuff in central blocks*//*Update lighting*/{/*Set lighting to non-expired state in all of them.This is cheating, but it is not fast enough if all of themwould actually be updated.*/for(s16 x=blockpos_min.X-extra_borders.X;x<=blockpos_max.X+extra_borders.X; x++)for(s16 z=blockpos_min.Z-extra_borders.Z;z<=blockpos_max.Z+extra_borders.Z; z++)for(s16 y=blockpos_min.Y-extra_borders.Y;y<=blockpos_max.Y+extra_borders.Y; y++){v3s16 p(x, y, z);getBlockNoCreateNoEx(p)->setLightingExpired(false);}}/*Go through changed blocks*/for(std::map::iterator i = changed_blocks.begin(); i != changed_blocks.end(); ++i){MapBlock *block = i->second;assert(block);/*Update day/night difference cache of the MapBlocks*/block->expireDayNightDiff();/*Set block as modified*/block->raiseModified(MOD_STATE_WRITE_NEEDED,"finishBlockMake expireDayNightDiff");}/*Set central blocks as generated*/for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++)for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++)for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++){v3s16 p(x, y, z);MapBlock *block = getBlockNoCreateNoEx(p);assert(block);block->setGenerated(true);}MapBlock *block = getBlockNoCreateNoEx(blockpos_requested);return block;}


主要涉及函数:

minetest->map.cpp

void ManualMapVoxelManipulator::blitBackAll(std::map<v3s16,MapBlock*> * modified_blocks)

拷贝好block的数据:block->copyFrom(*this)dst.copyTo(data, data_area, v3s16(0,0,0),getPosRelative(), data_size)dataMapBlockMapNode *data,即MapBlock的数据;返回modified_blocks



(4)voidServerMap::save(ModifiedState save_level)

功能:保存map的meta数据(map_meta.txt)、保存所有Sector的Meta数据、保存所有block数据(如sqlite文件map.sqlite)。

参数:ModifiedStatesave_level  程序运行中常用的是MOD_STATE_WRITE_NEEDED,即需要尽快保存。

enum ModifiedState

{

// Has not been modified.

MOD_STATE_CLEAN = 0,

MOD_RESERVED1 = 1,

// Has been modified, and will be saved when being unloaded.

MOD_STATE_WRITE_AT_UNLOAD = 2,

MOD_RESERVED3 = 3,

// Has been modified, and will be saved as soon as possible.

MOD_STATE_WRITE_NEEDED = 4,

MOD_RESERVED5 = 5,

};


调用:voidServer::AsyncRunStep(bool initial_step) 中调用ServeMapsave函数m_env->getMap().save(MOD_STATE_WRITE_NEEDED); AsyncRunStep()方法主要在ServerThread类的线程函数中循环体中调用,具体如下:


minetest->server.cpp

void * ServerThread::Thread()

{


ThreadStarted();


while(!StopRequested())

{

try{

m_server->AsyncRunStep();


m_server->Receive();


}

。。。

}

}


void ServerMap::save(ModifiedState save_level){if(m_map_saving_enabled == false){infostream<<"WARNING: Not saving map, saving disabled."<::iterator i = m_sectors.begin();i != m_sectors.end(); ++i){ServerMapSector *sector = (ServerMapSector*)i->second;assert(sector->getId() == MAPSECTOR_SERVER);if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN){saveSectorMeta(sector);sector_meta_count++;}std::list blocks;sector->getBlocks(blocks);for(std::list::iterator j = blocks.begin();j != blocks.end(); ++j){MapBlock *block = *j;block_count_all++;if(block->getModified() >= (u32)save_level){// Lazy beginSave()if(!save_started){beginSave();save_started = true;}modprofiler.add(block->getModifiedReason(), 1);saveBlock(block);block_count++;}}}if(save_started)endSave();}



(5)voidServerMap::saveMapMeta()

minetest->emerge.cpp

m_emerge->saveParamsToSettings(&params);


void ServerMap::loadMapMeta()

minetest->emerge.cpp

m_emerge->loadParamsFromSettings(&params);



void ServerMap::saveBlock(MapBlock *block)

将block数据保存到数据库文件中。


void ServerMap::loadBlock

从数据文件中加载。


阅读全文
0 0