void *EmergeThread::Thread() { ThreadStarted(); log_register_thread("EmergeThread" + itos(id)); DSTACK(__FUNCTION_NAME); BEGIN_DEBUG_EXCEPTION_HANDLER v3s16 last_tried_pos(-32768,-32768,-32768); // For error output v3s16 p; u8 flags; 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()) try { if (!popBlockEmerge(&p, &flags)) { qevent.wait(); continue; } last_tried_pos = p; if (blockpos_over_limit(p)) continue; bool allow_generate = flags & BLOCK_EMERGE_ALLOWGEN; EMERGE_DBG_OUT("p=" PP(p) " allow_generate=" << allow_generate); /* Try to fetch block from memory or disk. If not found and asked to generate, initialize generator. */ BlockMakeData data; MapBlock *block = NULL; std::map<v3s16, MapBlock *> modified_blocks; if (getBlockOrStartGen(p, &block, &data, allow_generate)) { { ScopeProfiler sp(g_profiler, "EmergeThread: Mapgen::makeChunk", SPT_AVG); TimeTaker t("mapgen::make_block()"); mapgen->makeChunk(&data); if (enable_mapgen_debug_info == false) t.stop(true); // Hide output } { //envlock: usually 0ms, but can take either 30 or 400ms to acquire JMutexAutoLock envlock(m_server->m_env_mutex); ScopeProfiler sp(g_profiler, "EmergeThread: after " "Mapgen::makeChunk (envlock)", SPT_AVG); map->finishBlockMake(&data, modified_blocks); block = map->getBlockNoCreateNoEx(p); if (block) { /* Do some post-generate stuff */ v3s16 minp = data.blockpos_min * MAP_BLOCKSIZE; v3s16 maxp = data.blockpos_max * MAP_BLOCKSIZE + v3s16(1,1,1) * (MAP_BLOCKSIZE - 1); // Ignore map edit events, they will not need to be sent // to anybody because the block hasn't been sent to anybody MapEditEventAreaIgnorer ign(&m_server->m_ignore_map_edit_events_area, VoxelArea(minp, maxp)); { // takes about 90ms with -O1 on an e3-1230v2 m_server->getScriptIface()-> environment_OnGenerated( minp, maxp, emerge->getBlockSeed(minp)); } EMERGE_DBG_OUT("ended up with: " << analyze_block(block)); m_server->m_env->activateBlock(block, 0); } } } /* 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; // Update weather data in mapblock for(std::map<v3s16, MapBlock *>::iterator i = modified_blocks.begin(); i != modified_blocks.end(); ++i) { map->getHeat(m_server->m_env, MAP_BLOCKSIZE*i->first ,i->second); map->getHumidity(m_server->m_env, MAP_BLOCKSIZE*i->first, i->second); } // Set the modified blocks unsent for all the clients for (std::map<u16, RemoteClient*>::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); } } } catch (VersionMismatchException &e) { std::ostringstream err; err << "World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl; err << "----"<<std::endl; err << "\""<<e.what()<<"\""<<std::endl; err << "See debug.txt."<<std::endl; err << "World probably saved by a newer version of Minetest."<<std::endl; m_server->setAsyncFatalError(err.str()); } catch (SerializationError &e) { std::ostringstream err; err << "Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl; err << "----"<<std::endl; err << "\""<<e.what()<<"\""<<std::endl; err << "See debug.txt."<<std::endl; err << "You can ignore this using [ignore_world_load_errors = true]."<<std::endl; m_server->setAsyncFatalError(err.str()); } END_DEBUG_EXCEPTION_HANDLER(errorstream) log_deregister_thread(); return NULL; }
void *EmergeThread::Thread() { ThreadStarted(); log_register_thread("EmergeThread" + itos(id)); DSTACK(__FUNCTION_NAME); BEGIN_DEBUG_EXCEPTION_HANDLER v3s16 last_tried_pos(-32768,-32768,-32768); // For error output v3s16 p; 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; porting::setThreadName("EmergeThread"); while (!StopRequested()) try { if (!popBlockEmerge(&p, &flags)) { qevent.wait(); continue; } last_tried_pos = p; if (blockpos_over_limit(p)) continue; bool allow_generate = flags & BLOCK_EMERGE_ALLOWGEN; EMERGE_DBG_OUT("p=" PP(p) " allow_generate=" << allow_generate); /* Try to fetch block from memory or disk. If not found and asked to generate, initialize generator. */ BlockMakeData data; MapBlock *block = NULL; std::map<v3s16, MapBlock *> modified_blocks; if (getBlockOrStartGen(p, &block, &data, allow_generate) && mapgen) { { ScopeProfiler sp(g_profiler, "EmergeThread: Mapgen::makeChunk", SPT_AVG); TimeTaker t("mapgen::make_block()"); mapgen->makeChunk(&data); if (enable_mapgen_debug_info == false) t.stop(true); // Hide output } { //envlock: usually 0ms, but can take either 30 or 400ms to acquire JMutexAutoLock envlock(m_server->m_env_mutex); ScopeProfiler sp(g_profiler, "EmergeThread: after " "Mapgen::makeChunk (envlock)", SPT_AVG); map->finishBlockMake(&data, modified_blocks); block = map->getBlockNoCreateNoEx(p); if (block) { /* Do some post-generate stuff */ v3s16 minp = data.blockpos_min * MAP_BLOCKSIZE; v3s16 maxp = data.blockpos_max * MAP_BLOCKSIZE + v3s16(1,1,1) * (MAP_BLOCKSIZE - 1); // Ignore map edit events, they will not need to be sent // to anybody because the block hasn't been sent to anybody MapEditEventAreaIgnorer ign(&m_server->m_ignore_map_edit_events_area, VoxelArea(minp, maxp)); try { // takes about 90ms with -O1 on an e3-1230v2 m_server->getScriptIface()->environment_OnGenerated( minp, maxp, mapgen->blockseed); } catch(LuaError &e) { m_server->setAsyncFatalError(e.what()); } EMERGE_DBG_OUT("ended up with: " << analyze_block(block)); m_server->m_env->activateBlock(block, 0); } } } /* Set sent status of modified blocks on clients */ // Add the originally fetched block to the modified list if (block) modified_blocks[p] = block; if (modified_blocks.size() > 0) { m_server->SetBlocksNotSent(modified_blocks); } } catch (VersionMismatchException &e) { std::ostringstream err; err << "World data version mismatch in MapBlock " << PP(last_tried_pos) << std::endl << "----" << std::endl << "\"" << e.what() << "\"" << std::endl << "See debug.txt." << std::endl << "World probably saved by a newer version of " PROJECT_NAME_C "." << std::endl; m_server->setAsyncFatalError(err.str()); } catch (SerializationError &e) { std::ostringstream err; err << "Invalid data in MapBlock " << PP(last_tried_pos) << std::endl << "----" << std::endl << "\"" << e.what() << "\"" << std::endl << "See debug.txt." << std::endl << "You can ignore this using [ignore_world_load_errors = true]." << std::endl; m_server->setAsyncFatalError(err.str()); } { JMutexAutoLock queuelock(emerge->queuemutex); while (!blockqueue.empty()) { v3s16 p = blockqueue.front(); blockqueue.pop(); std::map<v3s16, BlockEmergeData *>::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; }
void *EmergeThread::run() { DSTACK(FUNCTION_NAME); BEGIN_DEBUG_EXCEPTION_HANDLER v3s16 pos; m_map = (ServerMap *)&(m_server->m_env->getMap()); m_emerge = m_server->m_emerge; m_mapgen = m_emerge->m_mapgens[id]; enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info; reg("EmergeThread" + itos(id), 5); while (!stopRequested()) { try { std::map<v3s16, MapBlock *> modified_blocks; BlockEmergeData bedata; BlockMakeData bmdata; EmergeAction action; MapBlock *block; if (!popBlockEmerge(&pos, &bedata)) { m_queue_event.wait(); continue; } if (blockpos_over_limit(pos)) continue; bool allow_gen = bedata.flags & BLOCK_EMERGE_ALLOW_GEN; EMERGE_DBG_OUT("pos=" PP(pos) " allow_gen=" << allow_gen); action = getBlockOrStartGen(pos, allow_gen, &block, &bmdata); if (action == EMERGE_GENERATED) { { ScopeProfiler sp(g_profiler, "EmergeThread: Mapgen::makeChunk", SPT_AVG); TimeTaker t("mapgen::make_block()"); m_mapgen->makeChunk(&bmdata); if (enable_mapgen_debug_info == false) t.stop(true); // Hide output } block = finishGen(pos, &bmdata, &modified_blocks); } runCompletionCallbacks(pos, action, bedata.callbacks); if (block) { //modified_blocks[pos] = block; } else if (allow_gen) verbosestream<<"nothing generated at "<<pos<< " emerge action="<< action <<std::endl; if (modified_blocks.size() > 0) m_server->SetBlocksNotSent(/*modified_blocks*/); if (m_mapgen->heat_cache.size() > 1000) { m_mapgen->heat_cache.clear(); m_mapgen->humidity_cache.clear(); } } catch (VersionMismatchException &e) { std::ostringstream err; err << "World data version mismatch in MapBlock " << PP(pos) << std::endl << "----" << std::endl << "\"" << e.what() << "\"" << std::endl << "See debug.txt." << std::endl << "World probably saved by a newer version of " PROJECT_NAME_C "." << std::endl; debug_stacks_print(); m_server->setAsyncFatalError(err.str()); } catch (SerializationError &e) { std::ostringstream err; err << "Invalid data in MapBlock " << PP(pos) << std::endl << "----" << std::endl << "\"" << e.what() << "\"" << std::endl << "See debug.txt." << std::endl << "You can ignore this using [ignore_world_load_errors = true]." << std::endl; debug_stacks_print(); m_server->setAsyncFatalError(err.str()); } catch (std::exception &e) { errorstream << "emerge: exception at " << pos << " : " << e.what() << std::endl; } } END_DEBUG_EXCEPTION_HANDLER return NULL; }