X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Femerge.cpp;h=443d70384819de64b90a4f0ef45bea81bd298e7e;hb=35ec3855f689cf2c6b1504a5813b7c3d9697ae14;hp=f096bb874a21e84dbd41250556a66d0ca1aee1d4;hpb=c3708b456e90bccf19e7c82c54a93c8cb7c8896c;p=dragonfireclient.git diff --git a/src/emerge.cpp b/src/emerge.cpp index f096bb874..443d70384 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -47,7 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen_math.h" -class EmergeThread : public SimpleThread +class EmergeThread : public JThread { public: Server *m_server; @@ -61,26 +61,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); @@ -91,42 +82,44 @@ class EmergeThread : public SimpleThread EmergeManager::EmergeManager(IGameDef *gamedef) { //register built-in mapgens - registerMapgen("v6", new MapgenFactoryV6()); - registerMapgen("v7", new MapgenFactoryV7()); - registerMapgen("indev", new MapgenFactoryIndev()); + registerMapgen("v6", new MapgenFactoryV6()); + registerMapgen("v7", new MapgenFactoryV7()); + registerMapgen("indev", new MapgenFactoryIndev()); registerMapgen("singlenode", new MapgenFactorySinglenode()); - registerMapgen("math", new MapgenFactoryMath()); + 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; + // 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 + int 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)); @@ -137,9 +130,11 @@ EmergeManager::EmergeManager(IGameDef *gamedef) { EmergeManager::~EmergeManager() { for (unsigned int i = 0; i != emergethread.size(); i++) { - emergethread[i]->setRun(false); - emergethread[i]->qevent.signal(); - emergethread[i]->stop(); + if (threads_active) { + emergethread[i]->Stop(); + emergethread[i]->qevent.signal(); + emergethread[i]->Wait(); + } delete emergethread[i]; delete mapgen[i]; } @@ -164,9 +159,19 @@ EmergeManager::~EmergeManager() { } -void EmergeManager::initMapgens(MapgenParams *mgparams) { - Mapgen *mg; +void EmergeManager::loadMapgenParams() { + loadParamsFromSettings(g_settings); + + if (g_settings->get("fixed_map_seed").empty()) { + params.seed = (((u64)(myrand() & 0xffff) << 0) + | ((u64)(myrand() & 0xffff) << 16) + | ((u64)(myrand() & 0xffff) << 32) + | ((u64)(myrand() & 0xffff) << 48)); + } +} + +void EmergeManager::initMapgens() { if (mapgen.size()) return; @@ -180,77 +185,25 @@ void EmergeManager::initMapgens(MapgenParams *mgparams) { 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; - } - } + 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; - } - - newparams->mg_name = newname; - newparams->seed = mgparams->seed; - newparams->water_level = mgparams->water_level; - newparams->chunksize = mgparams->chunksize; - newparams->flags = mgparams->flags; - - if (!newparams->readParams(g_settings)) { - errorstream << "EmergeManager: Mapgen override failed" << std::endl; - delete newparams; - return NULL; - } - - delete mgparams; - return newparams; -} - - Mapgen *EmergeManager::getCurrentMapgen() { for (unsigned int i = 0; i != emergethread.size(); i++) { if (emergethread[i]->IsSameThread()) @@ -261,9 +214,32 @@ Mapgen *EmergeManager::getCurrentMapgen() { } -void EmergeManager::triggerAllThreads() { +void EmergeManager::startThreads() { + if (threads_active) + return; + for (unsigned int i = 0; i != emergethread.size(); i++) - emergethread[i]->trigger(); + emergethread[i]->Start(); + + threads_active = true; +} + + +void EmergeManager::stopThreads() { + if (!threads_active) + return; + + // Request thread stop in parallel + for (unsigned int i = 0; i != emergethread.size(); i++) { + emergethread[i]->Stop(); + emergethread[i]->qevent.signal(); + } + + // Then do the waiting for each + for (unsigned int i = 0; i != emergethread.size(); i++) + emergethread[i]->Wait(); + + threads_active = false; } @@ -342,12 +318,12 @@ 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) + + return (u32)(params.seed & 0xFFFFFFFF) + p.Z * 38134234 + p.Y * 42123 + p.X * 23; @@ -369,7 +345,7 @@ Mapgen *EmergeManager::createMapgen(std::string mgname, int mgid, } -MapgenParams *EmergeManager::createMapgenParams(std::string mgname) { +MapgenSpecificParams *EmergeManager::createMapgenParams(std::string mgname) { std::map::const_iterator iter; iter = mglist.find(mgname); if (iter == mglist.end()) { @@ -383,37 +359,34 @@ MapgenParams *EmergeManager::createMapgenParams(std::string mgname) { } -MapgenParams *EmergeManager::getParamsFromSettings(Settings *settings) { - std::string mg_name = settings->get("mg_name"); - MapgenParams *mgparams = createMapgenParams(mg_name); - if (!mgparams) - return NULL; +void EmergeManager::loadParamsFromSettings(Settings *settings) { + std::string seed_str; + const char *setname = (settings == g_settings) ? "fixed_map_seed" : "seed"; - std::string seedstr = settings->get(settings == g_settings ? - "fixed_map_seed" : "seed"); + if (settings->getNoEx(setname, seed_str)) + params.seed = read_seed(seed_str.c_str()); - 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); + settings->getNoEx("mg_name", params.mg_name); + settings->getS16NoEx("water_level", params.water_level); + settings->getS16NoEx("chunksize", params.chunksize); + settings->getFlagStrNoEx("mg_flags", params.flags, flagdesc_mapgen); - if (!mgparams->readParams(settings)) { - delete mgparams; - return NULL; - } - return mgparams; + delete params.sparams; + params.sparams = createMapgenParams(params.mg_name); + if (params.sparams) + params.sparams->readParams(settings); } -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); +void EmergeManager::saveParamsToSettings(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, (u32)-1); - params->writeParams(settings); + if (params.sparams) + params.sparams->writeParams(settings); } @@ -492,14 +465,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(); @@ -554,9 +529,11 @@ void *EmergeThread::Thread() { MapEditEventAreaIgnorer ign(&m_server->m_ignore_map_edit_events_area, VoxelArea(minp, maxp)); - { // takes about 90ms with -O1 on an e3-1230v2 + try { // takes about 90ms with -O1 on an e3-1230v2 m_server->getScriptIface()->environment_OnGenerated( minp, maxp, emerge->getBlockSeed(minp)); + } catch(LuaError &e) { + m_server->setAsyncFatalError(e.what()); } EMERGE_DBG_OUT("ended up with: " << analyze_block(block)); @@ -569,23 +546,12 @@ 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) {