X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Femerge.cpp;h=9c5ee452ef6f0bd6389f5f181582bfdef3b2b6ee;hb=d4d561fbcdac0175584e4f62bc6c3bfdf83510f1;hp=2f757a760e3183c655f99684f5c7b1aa36c7c990;hpb=15c316765d2ee2a0b8aec78fd6b13d9367f3c91e;p=dragonfireclient.git diff --git a/src/emerge.cpp b/src/emerge.cpp index 2f757a760..9c5ee452e 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "environment.h" #include "util/container.h" #include "util/thread.h" -#include "main.h" #include "constants.h" #include "voxel.h" #include "config.h" @@ -39,15 +38,28 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "profiler.h" #include "log.h" #include "nodedef.h" -#include "biome.h" +#include "mg_biome.h" +#include "mg_ore.h" +#include "mg_decoration.h" +#include "mg_schematic.h" +#include "mapgen_v5.h" #include "mapgen_v6.h" #include "mapgen_v7.h" -#include "mapgen_indev.h" #include "mapgen_singlenode.h" -#include "mapgen_math.h" +struct MapgenDesc { + const char *name; + MapgenFactory *factory; +}; + +MapgenDesc reg_mapgens[] = { + {"v5", new MapgenFactoryV5}, + {"v6", new MapgenFactoryV6}, + {"v7", new MapgenFactoryV7}, + {"singlenode", new MapgenFactorySinglenode}, +}; -class EmergeThread : public SimpleThread +class EmergeThread : public JThread { public: Server *m_server; @@ -61,26 +73,17 @@ class EmergeThread : public SimpleThread std::queue blockqueue; EmergeThread(Server *server, int ethreadid): - SimpleThread(), + JThread(), m_server(server), map(NULL), emerge(NULL), mapgen(NULL), + enable_mapgen_debug_info(false), id(ethreadid) { } void *Thread(); - - void trigger() - { - setRun(true); - if(IsRunning() == false) - { - Start(); - } - } - bool popBlockEmerge(v3s16 *pos, u8 *flags); bool getBlockOrStartGen(v3s16 p, MapBlock **b, BlockMakeData *data, bool allow_generate); @@ -89,185 +92,151 @@ class EmergeThread : public SimpleThread /////////////////////////////// Emerge Manager //////////////////////////////// -EmergeManager::EmergeManager(IGameDef *gamedef) { - //register built-in mapgens - registerMapgen("v6", new MapgenFactoryV6()); - registerMapgen("v7", new MapgenFactoryV7()); - registerMapgen("indev", new MapgenFactoryIndev()); - registerMapgen("singlenode", new MapgenFactorySinglenode()); - registerMapgen("math", new MapgenFactoryMath()); - - this->ndef = gamedef->getNodeDefManager(); - this->biomedef = new BiomeDefManager(); - this->params = NULL; - - this->luaoverride_params = NULL; - this->luaoverride_params_modified = 0; - this->luaoverride_flagmask = 0; - - this->gennotify = 0; +EmergeManager::EmergeManager(IGameDef *gamedef) +{ + this->ndef = gamedef->getNodeDefManager(); + this->biomemgr = new BiomeManager(gamedef); + this->oremgr = new OreManager(gamedef); + this->decomgr = new DecorationManager(gamedef); + this->schemmgr = new SchematicManager(gamedef); + this->gen_notify_on = 0; + + // Note that accesses to this variable are not synchronized. + // This is because the *only* thread ever starting or stopping + // EmergeThreads should be the ServerThread. + this->threads_active = false; mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info"); - int nthreads; - if (g_settings->get("num_emerge_threads").empty()) { - int nprocs = porting::getNumberOfProcessors(); - // leave a proc for the main thread and one for some other misc threads - nthreads = (nprocs > 2) ? nprocs - 2 : 1; - } else { - nthreads = g_settings->getU16("num_emerge_threads"); - } + // if unspecified, leave a proc for the main thread and one for + // some other misc thread + s16 nthreads = 0; + if (!g_settings->getS16NoEx("num_emerge_threads", nthreads)) + nthreads = porting::getNumberOfProcessors() - 2; if (nthreads < 1) nthreads = 1; - qlimit_total = g_settings->getU16("emergequeue_limit_total"); - qlimit_diskonly = g_settings->get("emergequeue_limit_diskonly").empty() ? - nthreads * 5 + 1 : - g_settings->getU16("emergequeue_limit_diskonly"); - qlimit_generate = g_settings->get("emergequeue_limit_generate").empty() ? - nthreads + 1 : - g_settings->getU16("emergequeue_limit_generate"); + qlimit_total = g_settings->getU16("emergequeue_limit_total"); + if (!g_settings->getU16NoEx("emergequeue_limit_diskonly", qlimit_diskonly)) + qlimit_diskonly = nthreads * 5 + 1; + if (!g_settings->getU16NoEx("emergequeue_limit_generate", qlimit_generate)) + qlimit_generate = nthreads + 1; + + // don't trust user input for something very important like this + if (qlimit_total < 1) + qlimit_total = 1; + if (qlimit_diskonly < 1) + qlimit_diskonly = 1; + if (qlimit_generate < 1) + qlimit_generate = 1; - for (int i = 0; i != nthreads; i++) - emergethread.push_back(new EmergeThread((Server *)gamedef, i)); + for (s16 i = 0; i < nthreads; i++) + emergethread.push_back(new EmergeThread((Server *) gamedef, i)); infostream << "EmergeManager: using " << nthreads << " threads" << std::endl; } -EmergeManager::~EmergeManager() { - for (unsigned int i = 0; i != emergethread.size(); i++) { - emergethread[i]->setRun(false); - emergethread[i]->qevent.signal(); - emergethread[i]->stop(); +EmergeManager::~EmergeManager() +{ + for (u32 i = 0; i != emergethread.size(); i++) { + if (threads_active) { + emergethread[i]->Stop(); + emergethread[i]->qevent.signal(); + emergethread[i]->Wait(); + } delete emergethread[i]; delete mapgen[i]; } emergethread.clear(); mapgen.clear(); - for (unsigned int i = 0; i < ores.size(); i++) - delete ores[i]; - ores.clear(); + delete biomemgr; + delete oremgr; + delete decomgr; + delete schemmgr; - for (unsigned int i = 0; i < decorations.size(); i++) - delete decorations[i]; - decorations.clear(); - - for (std::map::iterator iter = mglist.begin(); - iter != mglist.end(); iter ++) { - delete iter->second; + if (params.sparams) { + delete params.sparams; + params.sparams = NULL; } - mglist.clear(); - - delete biomedef; } -void EmergeManager::initMapgens(MapgenParams *mgparams) { - Mapgen *mg; +void EmergeManager::loadMapgenParams() +{ + params.load(*g_settings); +} + +void EmergeManager::initMapgens() +{ if (mapgen.size()) return; - // Resolve names of nodes for things that were registered - // (at this point, the registration period is over) - biomedef->resolveNodeNames(ndef); - - for (size_t i = 0; i != ores.size(); i++) - ores[i]->resolveNodeNames(ndef); - - for (size_t i = 0; i != decorations.size(); i++) - decorations[i]->resolveNodeNames(ndef); - - // Apply mapgen parameter overrides from Lua - if (luaoverride_params) { - if (luaoverride_params_modified & MGPARAMS_SET_MGNAME) { - MapgenParams *mgp = setMapgenType(mgparams, luaoverride_params->mg_name); - if (!mgp) { - errorstream << "EmergeManager: Failed to set new mapgen name" - << std::endl; - } else { - mgparams = mgp; - } - } - - if (luaoverride_params_modified & MGPARAMS_SET_SEED) - mgparams->seed = luaoverride_params->seed; - - if (luaoverride_params_modified & MGPARAMS_SET_WATER_LEVEL) - mgparams->water_level = luaoverride_params->water_level; - - if (luaoverride_params_modified & MGPARAMS_SET_FLAGS) { - mgparams->flags &= ~luaoverride_flagmask; - mgparams->flags |= luaoverride_params->flags; + if (!params.sparams) { + params.sparams = createMapgenParams(params.mg_name); + if (!params.sparams) { + params.mg_name = DEFAULT_MAPGEN; + params.sparams = createMapgenParams(params.mg_name); + assert(params.sparams); } - - delete luaoverride_params; - luaoverride_params = NULL; + params.sparams->readParams(g_settings); } // Create the mapgens - this->params = mgparams; - for (size_t i = 0; i != emergethread.size(); i++) { - mg = createMapgen(params->mg_name, i, params); - if (!mg) { - infostream << "EmergeManager: Falling back to Mapgen V6" << std::endl; - - params = setMapgenType(params, "v6"); - mg = createMapgen(params->mg_name, i, params); - if (!mg) { - errorstream << "EmergeManager: CRITICAL ERROR: Failed to fall" - "back to Mapgen V6, not generating map" << std::endl; - } - } + for (u32 i = 0; i != emergethread.size(); i++) { + Mapgen *mg = createMapgen(params.mg_name, i, ¶ms); + assert(mg); mapgen.push_back(mg); } } -MapgenParams *EmergeManager::setMapgenType(MapgenParams *mgparams, - std::string newname) { - MapgenParams *newparams = createMapgenParams(newname); - if (!newparams) { - errorstream << "EmergeManager: Mapgen override failed" << std::endl; - return NULL; +Mapgen *EmergeManager::getCurrentMapgen() +{ + for (u32 i = 0; i != emergethread.size(); i++) { + if (emergethread[i]->IsSameThread()) + return emergethread[i]->mapgen; } - newparams->mg_name = newname; - newparams->seed = mgparams->seed; - newparams->water_level = mgparams->water_level; - newparams->chunksize = mgparams->chunksize; - newparams->flags = mgparams->flags; + return NULL; +} - if (!newparams->readParams(g_settings)) { - errorstream << "EmergeManager: Mapgen override failed" << std::endl; - delete newparams; - return NULL; - } - delete mgparams; - return newparams; +void EmergeManager::startThreads() +{ + if (threads_active) + return; + + for (u32 i = 0; i != emergethread.size(); i++) + emergethread[i]->Start(); + + threads_active = true; } -Mapgen *EmergeManager::getCurrentMapgen() { - for (unsigned int i = 0; i != emergethread.size(); i++) { - if (emergethread[i]->IsSameThread()) - return emergethread[i]->mapgen; - } +void EmergeManager::stopThreads() +{ + if (!threads_active) + return; - return NULL; -} + // Request thread stop in parallel + for (u32 i = 0; i != emergethread.size(); i++) { + emergethread[i]->Stop(); + emergethread[i]->qevent.signal(); + } + // Then do the waiting for each + for (u32 i = 0; i != emergethread.size(); i++) + emergethread[i]->Wait(); -void EmergeManager::triggerAllThreads() { - for (unsigned int i = 0; i != emergethread.size(); i++) - emergethread[i]->trigger(); + threads_active = false; } -bool EmergeManager::enqueueBlockEmerge(u16 peer_id, v3s16 p, bool allow_generate) { +bool EmergeManager::enqueueBlockEmerge(u16 peer_id, v3s16 p, bool allow_generate) +{ std::map::const_iterator iter; BlockEmergeData *bedata; u16 count; @@ -305,7 +274,7 @@ bool EmergeManager::enqueueBlockEmerge(u16 peer_id, v3s16 p, bool allow_generate // insert into the EmergeThread queue with the least items int lowestitems = emergethread[0]->blockqueue.size(); - for (unsigned int i = 1; i != emergethread.size(); i++) { + for (u32 i = 1; i != emergethread.size(); i++) { int nitems = emergethread[i]->blockqueue.size(); if (nitems < lowestitems) { idx = i; @@ -321,7 +290,8 @@ bool EmergeManager::enqueueBlockEmerge(u16 peer_id, v3s16 p, bool allow_generate } -int EmergeManager::getGroundLevelAtPoint(v2s16 p) { +int EmergeManager::getGroundLevelAtPoint(v2s16 p) +{ if (mapgen.size() == 0 || !mapgen[0]) { errorstream << "EmergeManager: getGroundLevelAtPoint() called" " before mapgen initialized" << std::endl; @@ -332,7 +302,8 @@ int EmergeManager::getGroundLevelAtPoint(v2s16 p) { } -bool EmergeManager::isBlockUnderground(v3s16 blockpos) { +bool EmergeManager::isBlockUnderground(v3s16 blockpos) +{ /* v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2, (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2); @@ -342,90 +313,52 @@ bool EmergeManager::isBlockUnderground(v3s16 blockpos) { //yuck, but then again, should i bother being accurate? //the height of the nodes in a single block is quite variable - return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params->water_level; + return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params.water_level; } -u32 EmergeManager::getBlockSeed(v3s16 p) { - return (u32)(params->seed & 0xFFFFFFFF) + - p.Z * 38134234 + - p.Y * 42123 + - p.X * 23; +void EmergeManager::getMapgenNames(std::list &mgnames) +{ + for (u32 i = 0; i != ARRLEN(reg_mapgens); i++) + mgnames.push_back(reg_mapgens[i].name); } -Mapgen *EmergeManager::createMapgen(std::string mgname, int mgid, - MapgenParams *mgparams) { - std::map::const_iterator iter; - iter = mglist.find(mgname); - if (iter == mglist.end()) { +Mapgen *EmergeManager::createMapgen(const std::string &mgname, int mgid, + MapgenParams *mgparams) +{ + u32 i; + for (i = 0; i != ARRLEN(reg_mapgens) && mgname != reg_mapgens[i].name; i++); + if (i == ARRLEN(reg_mapgens)) { errorstream << "EmergeManager; mapgen " << mgname << - " not registered" << std::endl; + " not registered" << std::endl; return NULL; } - MapgenFactory *mgfactory = iter->second; + MapgenFactory *mgfactory = reg_mapgens[i].factory; return mgfactory->createMapgen(mgid, mgparams, this); } -MapgenParams *EmergeManager::createMapgenParams(std::string mgname) { - std::map::const_iterator iter; - iter = mglist.find(mgname); - if (iter == mglist.end()) { - errorstream << "EmergeManager: mapgen " << mgname << - " not registered" << std::endl; +MapgenSpecificParams *EmergeManager::createMapgenParams(const std::string &mgname) +{ + u32 i; + for (i = 0; i < ARRLEN(reg_mapgens) && mgname != reg_mapgens[i].name; i++); + if (i == ARRLEN(reg_mapgens)) { + errorstream << "EmergeManager: Mapgen " << mgname << + " not registered" << std::endl; return NULL; } - MapgenFactory *mgfactory = iter->second; + MapgenFactory *mgfactory = reg_mapgens[i].factory; return mgfactory->createMapgenParams(); } -MapgenParams *EmergeManager::getParamsFromSettings(Settings *settings) { - std::string mg_name = settings->get("mg_name"); - MapgenParams *mgparams = createMapgenParams(mg_name); - if (!mgparams) - return NULL; - - std::string seedstr = settings->get(settings == g_settings ? - "fixed_map_seed" : "seed"); - - mgparams->mg_name = mg_name; - mgparams->seed = read_seed(seedstr.c_str()); - mgparams->water_level = settings->getS16("water_level"); - mgparams->chunksize = settings->getS16("chunksize"); - mgparams->flags = settings->getFlagStr("mg_flags", flagdesc_mapgen); - - if (!mgparams->readParams(settings)) { - delete mgparams; - return NULL; - } - return mgparams; -} - - -void EmergeManager::setParamsToSettings(Settings *settings) { - settings->set("mg_name", params->mg_name); - settings->setU64("seed", params->seed); - settings->setS16("water_level", params->water_level); - settings->setS16("chunksize", params->chunksize); - settings->setFlagStr("mg_flags", params->flags, flagdesc_mapgen); - - params->writeParams(settings); -} - - -void EmergeManager::registerMapgen(std::string mgname, MapgenFactory *mgfactory) { - mglist.insert(std::make_pair(mgname, mgfactory)); - infostream << "EmergeManager: registered mapgen " << mgname << std::endl; -} - - ////////////////////////////// Emerge Thread ////////////////////////////////// -bool EmergeThread::popBlockEmerge(v3s16 *pos, u8 *flags) { +bool EmergeThread::popBlockEmerge(v3s16 *pos, u8 *flags) +{ std::map::iterator iter; JMutexAutoLock queuelock(emerge->queuemutex); @@ -453,7 +386,8 @@ bool EmergeThread::popBlockEmerge(v3s16 *pos, u8 *flags) { bool EmergeThread::getBlockOrStartGen(v3s16 p, MapBlock **b, - BlockMakeData *data, bool allow_gen) { + BlockMakeData *data, bool allow_gen) +{ v2s16 p2d(p.X, p.Z); //envlock: usually takes <=1ms, sometimes 90ms or ~400ms to acquire JMutexAutoLock envlock(m_server->m_env_mutex); @@ -484,7 +418,8 @@ bool EmergeThread::getBlockOrStartGen(v3s16 p, MapBlock **b, } -void *EmergeThread::Thread() { +void *EmergeThread::Thread() +{ ThreadStarted(); log_register_thread("EmergeThread" + itos(id)); DSTACK(__FUNCTION_NAME); @@ -492,14 +427,16 @@ void *EmergeThread::Thread() { v3s16 last_tried_pos(-32768,-32768,-32768); // For error output v3s16 p; - u8 flags; + u8 flags = 0; map = (ServerMap *)&(m_server->m_env->getMap()); emerge = m_server->m_emerge; mapgen = emerge->mapgen[id]; enable_mapgen_debug_info = emerge->mapgen_debug_info; - while (getRun()) + porting::setThreadName("EmergeThread"); + + while (!StopRequested()) try { if (!popBlockEmerge(&p, &flags)) { qevent.wait(); @@ -556,7 +493,7 @@ void *EmergeThread::Thread() { VoxelArea(minp, maxp)); try { // takes about 90ms with -O1 on an e3-1230v2 m_server->getScriptIface()->environment_OnGenerated( - minp, maxp, emerge->getBlockSeed(minp)); + minp, maxp, mapgen->blockseed); } catch(LuaError &e) { m_server->setAsyncFatalError(e.what()); } @@ -571,44 +508,52 @@ void *EmergeThread::Thread() { /* Set sent status of modified blocks on clients */ - - // NOTE: Server's clients are also behind the connection mutex - //conlock: consistently takes 30-40ms to acquire - JMutexAutoLock lock(m_server->m_con_mutex); // Add the originally fetched block to the modified list if (block) modified_blocks[p] = block; - // Set the modified blocks unsent for all the clients - for (std::map::iterator - i = m_server->m_clients.begin(); - i != m_server->m_clients.end(); ++i) { - RemoteClient *client = i->second; - if (modified_blocks.size() > 0) { - // Remove block from sent history - client->SetBlocksNotSent(modified_blocks); - } + if (modified_blocks.size() > 0) { + m_server->SetBlocksNotSent(modified_blocks); } } catch (VersionMismatchException &e) { std::ostringstream err; - err << "World data version mismatch in MapBlock "<setAsyncFatalError(err.str()); } catch (SerializationError &e) { std::ostringstream err; - err << "Invalid data in MapBlock "<setAsyncFatalError(err.str()); } + { + JMutexAutoLock queuelock(emerge->queuemutex); + while (!blockqueue.empty()) + { + v3s16 p = blockqueue.front(); + blockqueue.pop(); + + std::map::iterator iter; + iter = emerge->blocks_enqueued.find(p); + if (iter == emerge->blocks_enqueued.end()) + continue; //uh oh, queue and map out of sync!! + + BlockEmergeData *bedata = iter->second; + delete bedata; + } + } + END_DEBUG_EXCEPTION_HANDLER(errorstream) log_deregister_thread(); return NULL;