Add emerge.cpp, initial EmergeThread changes
authorkwolekr <mirrorisim@gmail.com>
Thu, 14 Feb 2013 03:43:15 +0000 (22:43 -0500)
committerkwolekr <mirrorisim@gmail.com>
Tue, 26 Feb 2013 03:56:18 +0000 (22:56 -0500)
- Neatly placed all emerge related code into a new file, emerge.cpp
- Greatly cleaned up the code in EmergeThread::Thread()
- Reworked Emerge queue.  Now an actual std::queue of v3s16 block positions
- Removed the completely unnecessary map of peer ids requesting blocks

12 files changed:
src/CMakeLists.txt
src/emerge.cpp [new file with mode: 0644]
src/emerge.h [new file with mode: 0644]
src/environment.h
src/jthread/jmutex.h
src/map.cpp
src/map.h
src/mapgen.cpp
src/mapgen.h
src/mapgen_v6.cpp
src/server.cpp
src/server.h

index c06da20c4bfaa623c13d5e720c316ada8f518c95..d2f080c907d86a8186fe04b5602238a9a314194d 100644 (file)
@@ -209,6 +209,7 @@ set(common_SRCS
        script.cpp
        log.cpp
        content_sao.cpp
+       emerge.cpp
        mapgen.cpp
        mapgen_v6.cpp
        treegen.cpp
diff --git a/src/emerge.cpp b/src/emerge.cpp
new file mode 100644 (file)
index 0000000..728ea71
--- /dev/null
@@ -0,0 +1,677 @@
+/*
+Minetest-c55
+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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+
+#include "server.h"
+#include <iostream>
+#include <queue>
+#include "clientserver.h"
+#include "map.h"
+#include "jmutexautolock.h"
+#include "main.h"
+#include "constants.h"
+#include "voxel.h"
+#include "config.h"
+#include "mapblock.h"
+#include "serverobject.h"
+#include "settings.h"
+#include "script.h"
+#include "scriptapi.h"
+#include "profiler.h"
+#include "log.h"
+#include "nodedef.h"
+#include "biome.h"
+#include "emerge.h"
+#include "mapgen_v6.h"
+
+
+EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef) {
+       //register built-in mapgens
+       registerMapgen("v6", new MapgenFactoryV6());
+
+       this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
+       this->params   = NULL;
+       this->mapgen   = NULL;
+       
+       queuemutex.Init();
+       emergethread = new EmergeThread((Server *)gamedef);
+}
+
+
+EmergeManager::~EmergeManager() {
+       emergethread->setRun(false);
+       emergethread->stop();
+       
+       delete emergethread;
+       delete biomedef;
+       delete mapgen;
+       delete params;
+}
+
+
+void EmergeManager::initMapgens(MapgenParams *mgparams) {
+       if (mapgen)
+               return;
+       
+       this->params = mgparams;
+       this->mapgen = getMapgen(); //only one mapgen for now!
+}
+
+
+Mapgen *EmergeManager::getMapgen() {
+       if (!mapgen) {
+               mapgen = createMapgen(params->mg_name, 0, params, this);
+               if (!mapgen) {
+                       infostream << "EmergeManager: falling back to mapgen v6" << std::endl;
+                       delete params;
+                       params = createMapgenParams("v6");
+                       mapgen = createMapgen("v6", 0, params, this);
+               }
+       }
+       return mapgen;
+}
+
+
+bool EmergeManager::enqueueBlockEmerge(u16 peer_id, v3s16 p, bool allow_generate) { ///return false if adding failed, or queue full!
+       u8 flags = 0;
+       
+       if (allow_generate)
+               flags |= BLOCK_EMERGE_ALLOWGEN;
+
+       //TODO:
+       // add logic to select which emergethread to add it to
+       //  - one with the least queue contents?
+       //  - if a queue is too full, move onto another one
+       //  - use the peer id sometime
+
+       {
+               JMutexAutoLock queuelock(queuemutex);
+               
+               std::map<v3s16, u8>::const_iterator iter = blocks_enqueued.find(p);
+               if (iter != blocks_enqueued.end()) {
+                       flags |= iter->second;
+                       blocks_enqueued[p] = flags;
+                       return true;
+               }
+               
+               blocks_enqueued.insert(std::make_pair(p, flags));
+               emergethread->blockqueue.push(p);
+       }
+       emergethread->qevent.signal();
+       
+       return true;
+}
+
+
+bool EmergeManager::popBlockEmerge(v3s16 *pos, u8 *flags) {
+       JMutexAutoLock queuelock(queuemutex);
+
+       if (emergethread->blockqueue.empty())
+               return false;
+       v3s16 p = emergethread->blockqueue.front();
+       emergethread->blockqueue.pop();
+       
+       *pos = p;
+
+       std::map<v3s16, u8>::iterator iter = blocks_enqueued.find(p);
+       if (iter == blocks_enqueued.end()) //uh oh, this isn't right!!!!!!!!!!!!!!!!!!
+               return false;
+
+       *flags = iter->second;
+       blocks_enqueued.erase(iter);
+       
+       return true;
+}
+
+
+int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
+       if (!mapgen)
+               return 0;
+       return mapgen->getGroundLevelAtPoint(p);
+}
+
+
+bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
+       /*
+       v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
+                                       (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
+       int ground_level = getGroundLevelAtPoint(p);
+       return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
+       */
+
+       //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;
+}
+
+
+u32 EmergeManager::getBlockSeed(v3s16 p) {
+       return (u32)(params->seed & 0xFFFFFFFF) +
+               p.Z * 38134234 +
+               p.Y * 42123 +
+               p.Y * 23;
+}
+
+
+Mapgen *EmergeManager::createMapgen(std::string mgname, int mgid,
+                                                                       MapgenParams *mgparams, EmergeManager *emerge) {
+       std::map<std::string, MapgenFactory *>::const_iterator iter = mglist.find(mgname);
+       if (iter == mglist.end()) {
+               errorstream << "EmergeManager; mapgen " << mgname <<
+                " not registered" << std::endl;
+               return NULL;
+       }
+       
+       MapgenFactory *mgfactory = iter->second;
+       return mgfactory->createMapgen(mgid, mgparams, emerge);
+}
+
+
+MapgenParams *EmergeManager::createMapgenParams(std::string mgname) {
+       std::map<std::string, MapgenFactory *>::const_iterator iter = mglist.find(mgname);
+       if (iter == mglist.end()) {
+               errorstream << "EmergeManager: mapgen " << mgname <<
+                " not registered" << std::endl;
+               return NULL;
+       }
+       
+       MapgenFactory *mgfactory = iter->second;
+       return mgfactory->createMapgenParams();
+}
+
+
+MapgenParams *EmergeManager::getParamsFromSettings(Settings *settings) {
+       std::string mg_name = settings->get("mg_name");
+       MapgenParams *mgparams = createMapgenParams(mg_name);
+       
+       mgparams->mg_name     = mg_name;
+       mgparams->seed        = settings->getU64(settings == g_settings ? "fixed_map_seed" : "seed");
+       mgparams->water_level = settings->getS16("water_level");
+       mgparams->chunksize   = settings->getS16("chunksize");
+       mgparams->flags       = settings->getS32("mg_flags");
+
+       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);
+}
+
+
+bool EmergeManager::registerMapgen(std::string mgname, MapgenFactory *mgfactory) {
+       mglist.insert(std::make_pair(mgname, mgfactory));
+       infostream << "EmergeManager: registered mapgen " << mgname << std::endl;
+}
+
+
+
+class MapEditEventIgnorer
+{
+public:
+       MapEditEventIgnorer(bool *flag):
+               m_flag(flag)
+       {
+               if(*m_flag == false)
+                       *m_flag = true;
+               else
+                       m_flag = NULL;
+       }
+
+       ~MapEditEventIgnorer()
+       {
+               if(m_flag)
+               {
+                       assert(*m_flag);
+                       *m_flag = false;
+               }
+       }
+
+private:
+       bool *m_flag;
+};
+
+class MapEditEventAreaIgnorer
+{
+public:
+       MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
+               m_ignorevariable(ignorevariable)
+       {
+               if(m_ignorevariable->getVolume() == 0)
+                       *m_ignorevariable = a;
+               else
+                       m_ignorevariable = NULL;
+       }
+
+       ~MapEditEventAreaIgnorer()
+       {
+               if(m_ignorevariable)
+               {
+                       assert(m_ignorevariable->getVolume() != 0);
+                       *m_ignorevariable = VoxelArea();
+               }
+       }
+
+private:
+       VoxelArea *m_ignorevariable;
+};
+
+
+#if 1
+
+#define EMERGE_DBG_OUT(x) \
+       { if (enable_mapgen_debug_info) \
+       infostream << "EmergeThread: " x << std::endl; }
+
+bool EmergeThread::getBlockOrStartGen(v3s16 p, MapBlock **b, 
+                                                                       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); 
+       
+       // Load sector if it isn't loaded
+       if (map->getSectorNoGenerateNoEx(p2d) == NULL)
+               map->loadSectorMeta(p2d);
+
+       // Attempt to load block
+       MapBlock *block = map->getBlockNoCreateNoEx(p);
+       if (!block || block->isDummy() || !block->isGenerated()) {
+               EMERGE_DBG_OUT("not in memory, attempting to load from disk");
+               block = map->loadBlock(p);
+       }
+
+       // If could not load and allowed to generate,
+       // start generation inside this same envlock
+       if (allow_gen && (block == NULL || !block->isGenerated())) {
+               EMERGE_DBG_OUT("generating");
+               map->initBlockMake(data, p);
+               return true;
+       }
+       
+       *b = block;
+       return false;
+}
+
+
+void *EmergeThread::Thread() {
+       ThreadStarted();
+       log_register_thread("EmergeThread");
+       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->getMapgen();
+       
+       while (getRun())
+       try {
+               while (!emerge->popBlockEmerge(&p, &flags))
+                       qevent.wait();
+
+               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;
+               core::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::make_block (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
+                                               scriptapi_environment_on_generated(m_server->m_lua,
+                                                               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.insert(p, block);
+
+               // Set the modified blocks unsent for all the clients
+               for (core::map<u16, RemoteClient*>::Iterator
+                        i = m_server->m_clients.getIterator();
+                        i.atEnd() == false; i++) {
+                       RemoteClient *client = i.getNode()->getValue();
+                       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;
+}
+
+#else
+
+void *EmergeThread::Thread() {
+       ThreadStarted();
+       log_register_thread("EmergeThread");
+       DSTACK(__FUNCTION_NAME);
+       BEGIN_DEBUG_EXCEPTION_HANDLER
+
+       bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
+
+       v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
+       ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
+       EmergeManager *emerge = m_server->m_emerge;
+       Mapgen *mapgen = emerge->getMapgen();
+
+       while(getRun())
+       try {
+               QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
+               if(qptr == NULL)
+                       break;
+               SharedPtr<QueuedBlockEmerge> q(qptr);
+
+               v3s16 &p = q->pos;
+               v2s16 p2d(p.X,p.Z);
+
+               last_tried_pos = p;
+
+               /*
+                       Do not generate over-limit
+               */
+               if (blockpos_over_limit(p))
+                       continue;
+
+               //infostream<<"EmergeThread::Thread(): running"<<std::endl;
+
+               //TimeTaker timer("block emerge");
+
+               /*
+                       Try to emerge it from somewhere.
+
+                       If it is only wanted as optional, only loading from disk
+                       will be allowed.
+               */
+
+               /*
+                       Check if any peer wants it as non-optional. In that case it
+                       will be generated.
+
+                       Also decrement the emerge queue count in clients.
+               */
+
+               bool only_from_disk = true;
+               {
+                       core::map<u16, u8>::Iterator i;
+                       for (i=q->s.getIterator(); !i.atEnd(); i++) {
+                               u8 flags = i.getNode()->getValue();
+                               if (!(flags & BLOCK_EMERGE_FLAG_FROMDISK)) {
+                                       only_from_disk = false;
+                                       break;
+                               }
+                       }
+               }
+
+               if (enable_mapgen_debug_info)
+                       infostream<<"EmergeThread: p="
+                                       <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
+                                       <<"only_from_disk="<<only_from_disk<<std::endl;
+                                       
+               MapBlock *block = NULL;
+               bool got_block = true;
+               core::map<v3s16, MapBlock*> modified_blocks;
+
+               /*
+                       Try to fetch block from memory or disk.
+                       If not found and asked to generate, initialize generator.
+               */
+
+               bool started_generate = false;
+               BlockMakeData data;
+               {
+                       JMutexAutoLock envlock(m_server->m_env_mutex);
+                       
+                       // Load sector if it isn't loaded
+                       if(map.getSectorNoGenerateNoEx(p2d) == NULL)
+                               map.loadSectorMeta(p2d);
+
+                       // Attempt to load block
+                       block = map.getBlockNoCreateNoEx(p);
+                       if(!block || block->isDummy() || !block->isGenerated()) {
+                               if(enable_mapgen_debug_info)
+                                       infostream<<"EmergeThread: not in memory, "
+                                                       <<"attempting to load from disk"<<std::endl;
+
+                               block = map.loadBlock(p);
+                       }
+
+                       // If could not load and allowed to generate, start generation
+                       // inside this same envlock
+                       if(only_from_disk == false &&
+                                       (block == NULL || block->isGenerated() == false)){
+                               if(enable_mapgen_debug_info)
+                                       infostream<<"EmergeThread: generating"<<std::endl;
+                               started_generate = true;
+
+                               map.initBlockMake(&data, p);
+                       }
+               }
+
+               /*
+                       If generator was initialized, generate now when envlock is free.
+               */
+               if(started_generate) {
+                       {
+                               ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
+                                               SPT_AVG);
+                               TimeTaker t("mapgen::make_block()");
+
+                               mapgen->makeChunk(&data);
+
+                               if (enable_mapgen_debug_info == false)
+                                       t.stop(true); // Hide output
+                       }
+
+                       do{ // enable break
+                               // Lock environment again to access the map
+                               JMutexAutoLock envlock(m_server->m_env_mutex);
+
+                               ScopeProfiler sp(g_profiler, "EmergeThread: after "
+                                               "mapgen::make_block (envlock)", SPT_AVG);
+
+                               // Blit data back on map, update lighting, add mobs and
+                               // whatever this does
+                               map.finishBlockMake(&data, modified_blocks);
+                               
+                               // Get central block
+                               block = map.getBlockNoCreateNoEx(p);
+
+                               // If block doesn't exist, don't try doing anything with it
+                               // This happens if the block is not in generation boundaries
+                               if(!block)
+                                       break;
+
+                               /*
+                                       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));
+                               {
+                                       TimeTaker timer("on_generated");
+                                       scriptapi_environment_on_generated(m_server->m_lua,
+                                                       minp, maxp, emerge->getBlockSeed(minp));
+                                       //int t = timer.stop(true);
+                                       //dstream<<"on_generated took "<<t<<"ms"<<std::endl;
+                               }
+
+                               if (enable_mapgen_debug_info)
+                                       infostream << "EmergeThread: ended up with: "
+                                                       << analyze_block(block) << std::endl;
+
+                               // Activate objects and stuff
+                               m_server->m_env->activateBlock(block, 0);
+                       }while(false);
+               }
+
+               if(block == NULL)
+                       got_block = false;
+
+               /*
+                       Set sent status of modified blocks on clients
+               */
+
+               // NOTE: Server's clients are also behind the connection mutex
+               JMutexAutoLock lock(m_server->m_con_mutex);
+
+               /*
+                       Add the originally fetched block to the modified list
+               */
+               if(got_block)
+                       modified_blocks.insert(p, block);
+
+               /*
+                       Set the modified blocks unsent for all the clients
+               */
+               for(core::map<u16, RemoteClient*>::Iterator
+                               i = m_server->m_clients.getIterator();
+                               i.atEnd() == false; i++) {
+                       RemoteClient *client = i.getNode()->getValue();
+                       if(modified_blocks.size() > 0) {
+                               // Remove block from sent history
+                               client->SetBlocksNotSent(modified_blocks);
+                       }
+               }
+                                                       
+
+niters++;
+       }
+       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());
+       }
+printf("emergethread iterated %d times\n", niters);
+       END_DEBUG_EXCEPTION_HANDLER(errorstream)
+       log_deregister_thread();
+       return NULL;
+}
+
+#endif
diff --git a/src/emerge.h b/src/emerge.h
new file mode 100644 (file)
index 0000000..0acc89a
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef EMERGE_HEADER
+#define EMERGE_HEADER
+
+#include <map>
+#include <queue>
+#include "util/thread.h"
+
+#define BLOCK_EMERGE_ALLOWGEN (1<<0)
+
+class Mapgen;
+class MapgenParams;
+class MapgenFactory;
+class Biome;
+class BiomeDefManager;
+class EmergeThread;
+class ManualMapVoxelManipulator;
+//class ServerMap;
+//class MapBlock;
+
+#include "server.h"
+
+struct BlockMakeData {
+       bool no_op;
+       ManualMapVoxelManipulator *vmanip;
+       u64 seed;
+       v3s16 blockpos_min;
+       v3s16 blockpos_max;
+       v3s16 blockpos_requested;
+       UniqueQueue<v3s16> transforming_liquid;
+       INodeDefManager *nodedef;
+
+//     BlockMakeData();
+//     ~BlockMakeData();
+       
+BlockMakeData():
+       no_op(false),
+       vmanip(NULL),
+       seed(0),
+       nodedef(NULL)
+{}
+
+~BlockMakeData()
+{
+       delete vmanip;
+}
+};
+
+class EmergeManager {
+public:
+       std::map<std::string, MapgenFactory *> mglist;
+
+       //settings
+       MapgenParams *params;
+
+       JMutex queuemutex;
+       std::map<v3s16, u8> blocks_enqueued; //change to a hashtable later
+       Mapgen *mapgen;
+       EmergeThread *emergethread;
+
+       //biome manager
+       BiomeDefManager *biomedef;
+
+       EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef);
+       ~EmergeManager();
+
+       void initMapgens(MapgenParams *mgparams);
+       Mapgen *createMapgen(std::string mgname, int mgid,
+                                               MapgenParams *mgparams, EmergeManager *emerge);
+       MapgenParams *createMapgenParams(std::string mgname);
+       Mapgen *getMapgen();
+       bool enqueueBlockEmerge(u16 peer_id, v3s16 p, bool allow_generate);
+       bool popBlockEmerge(v3s16 *pos, u8 *flags);
+       
+       bool registerMapgen(std::string name, MapgenFactory *mgfactory);
+       MapgenParams *getParamsFromSettings(Settings *settings);
+       void setParamsToSettings(Settings *settings);
+       
+       //mapgen helper methods
+       Biome *getBiomeAtPoint(v3s16 p);
+       int getGroundLevelAtPoint(v2s16 p);
+       bool isBlockUnderground(v3s16 blockpos);
+       u32 getBlockSeed(v3s16 p);
+};
+
+class EmergeThread : public SimpleThread
+{
+       Server *m_server;
+       ServerMap *map;
+       EmergeManager *emerge;
+       Mapgen *mapgen;
+       bool enable_mapgen_debug_info;
+       
+public:
+       Event qevent;
+       std::queue<v3s16> blockqueue;
+       
+       EmergeThread(Server *server):
+               SimpleThread(),
+               m_server(server),
+               map(NULL),
+               emerge(NULL),
+               mapgen(NULL)
+       {
+               enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
+       }
+
+       void *Thread();
+
+       void trigger()
+       {
+               setRun(true);
+               if(IsRunning() == false)
+               {
+                       Start();
+               }
+       }
+
+       bool getBlockOrStartGen(v3s16 p, MapBlock **b, 
+                                                       BlockMakeData *data, bool allow_generate);
+};
+
+#endif
index a79ccc63d0feb022707dae7497ebb84f130b1dc4..07a4d7635673dd40dcee52f1420f2c2f236c1065 100644 (file)
@@ -40,7 +40,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapnode.h"
 #include "mapblock.h"
 
-class Server;
 class ServerEnvironment;
 class ActiveBlockModifier;
 class ServerActiveObject;
index 9ce013096f8a3817417d079003f2ed8319b15d5a..6675162a56b6070efdc22e3b021f5c20aa6d3f94 100644 (file)
@@ -67,4 +67,54 @@ private:
        bool initialized;
 };
 
+#ifdef _WIN32
+
+class Event {
+       HANDLE hEvent;
+
+public:
+       Event() {
+               hEvent = CreateEvent(NULL, 0, 0, NULL);
+       }
+       
+       ~Event() {
+               CloseHandle(hEvent);
+       }
+       
+       void wait() {
+               WaitForSingleObject(hEvent, INFINITE); 
+       }
+       
+       void signal() {
+               SetEvent(hEvent);
+       }
+}
+
+#else
+
+#include <semaphore.h>
+
+class Event {
+       sem_t sem;
+
+public:
+       Event() {
+               sem_init(&sem, 0, 0);
+       }
+       
+       ~Event() {
+               sem_destroy(&sem);
+       }
+       
+       void wait() {
+               sem_wait(&sem);
+       }
+       
+       void signal() {
+               sem_post(&sem);
+       }
+};
+
+#endif
+
 #endif // JMUTEX_H
index 696d73182addc6e94a3da8050ee2edbabf93f25d..7eb45463f7a2ab1e035c21906d1aadfbac7d415f 100644 (file)
@@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "gamedef.h"
 #include "util/directiontables.h"
 #include "rollback_interface.h"
+#include "emerge.h"
 #include "mapgen_v6.h"
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
index 1c91745c0a7a172b9bd4384497a9479045879ec8..0b2311f394cb01f62b3db4d0a35281dd1f6aaee5 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -46,6 +46,8 @@ class MapBlock;
 class NodeMetadata;
 class IGameDef;
 class IRollbackReportSink;
+class EmergeManager;
+class BlockMakeData;
 
 
 /*
@@ -378,7 +380,7 @@ public:
                Blocks are generated by using these and makeBlock().
        */
        void initBlockMake(BlockMakeData *data, v3s16 blockpos);
-       MapBlockfinishBlockMake(BlockMakeData *data,
+       MapBlock *finishBlockMake(BlockMakeData *data,
                        core::map<v3s16, MapBlock*> &changed_blocks);
 
        // A non-threaded wrapper to the above  - DEFUNCT
index 73fe633185370cbc1b47210ccee95840115658a1..ef5da6bf1e43d85f1fdb39150ccb3ba6c0de74b1 100644 (file)
@@ -46,144 +46,6 @@ FlagDesc flagdesc_mapgen[] = {
 };
 
 ///////////////////////////////////////////////////////////////////////////////
-/////////////////////////////// Emerge Manager ////////////////////////////////
-
-
-EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef) {
-       //register built-in mapgens
-       registerMapgen("v6", new MapgenFactoryV6());
-               
-       //the order of these assignments is pretty important
-       this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
-       this->params   = NULL;
-       this->mapgen   = NULL;
-}
-
-
-EmergeManager::~EmergeManager() {
-       delete biomedef;
-       delete mapgen;
-       delete params;
-}
-
-
-void EmergeManager::initMapgens(MapgenParams *mgparams) {
-       if (mapgen)
-               return;
-       
-       this->params = mgparams;
-       this->mapgen = getMapgen(); //only one mapgen for now!
-}
-
-
-Mapgen *EmergeManager::getMapgen() {
-       if (!mapgen) {
-               mapgen = createMapgen(params->mg_name, 0, params, this);
-               if (!mapgen) {
-                       infostream << "EmergeManager: falling back to mapgen v6" << std::endl;
-                       delete params;
-                       params = createMapgenParams("v6");
-                       mapgen = createMapgen("v6", 0, params, this);
-               }
-       }
-       return mapgen;
-}
-
-void EmergeManager::addBlockToQueue() {
-       //STUB
-}
-
-
-int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
-       if (!mapgen)
-               return 0;
-       return mapgen->getGroundLevelAtPoint(p);
-}
-
-
-bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
-       /*
-       v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
-                                       (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
-       int ground_level = getGroundLevelAtPoint(p);
-       return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
-       */
-
-       //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;
-}
-
-
-u32 EmergeManager::getBlockSeed(v3s16 p) {
-       return (u32)(params->seed & 0xFFFFFFFF) +
-               p.Z * 38134234 +
-               p.Y * 42123 +
-               p.Y * 23;
-}
-
-
-Mapgen *EmergeManager::createMapgen(std::string mgname, int mgid,
-                                                                       MapgenParams *mgparams, EmergeManager *emerge) {
-       std::map<std::string, MapgenFactory *>::const_iterator iter = mglist.find(mgname);
-       if (iter == mglist.end()) {
-               errorstream << "EmergeManager; mapgen " << mgname <<
-                " not registered" << std::endl;
-               return NULL;
-       }
-       
-       MapgenFactory *mgfactory = iter->second;
-       return mgfactory->createMapgen(mgid, mgparams, emerge);
-}
-
-
-MapgenParams *EmergeManager::createMapgenParams(std::string mgname) {
-       std::map<std::string, MapgenFactory *>::const_iterator iter = mglist.find(mgname);
-       if (iter == mglist.end()) {
-               errorstream << "EmergeManager: mapgen " << mgname <<
-                " not registered" << std::endl;
-               return NULL;
-       }
-       
-       MapgenFactory *mgfactory = iter->second;
-       return mgfactory->createMapgenParams();
-}
-
-
-MapgenParams *EmergeManager::getParamsFromSettings(Settings *settings) {
-       std::string mg_name = settings->get("mg_name");
-       MapgenParams *mgparams = createMapgenParams(mg_name);
-       
-       mgparams->mg_name     = mg_name;
-       mgparams->seed        = settings->getU64(settings == g_settings ? "fixed_map_seed" : "seed");
-       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;
-}
-
 
 /////////////////////
 
@@ -2986,18 +2848,3 @@ void make_block(BlockMakeData *data)
 
 #endif ///BIG COMMENT
 
-BlockMakeData::BlockMakeData():
-       no_op(false),
-       vmanip(NULL),
-       seed(0),
-       nodedef(NULL)
-{}
-
-BlockMakeData::~BlockMakeData()
-{
-       delete vmanip;
-}
-
-//}; // namespace mapgen
-
-
index 765ac3bb25f47d094c1c9012ef45e75bd4cc0a62..c3c209ad155b7c7dbea6b84799d0721d8e78fa66 100644 (file)
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapnode.h"
 #include "noise.h"
 #include "settings.h"
+//#include "emerge.h"
 #include <map>
 
 /////////////////// Mapgen flags
@@ -36,6 +37,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define MGV6_BIOME_BLEND 0x10
 #define MG_FLAT          0x20
 
+extern FlagDesc flagdesc_mapgen[];
+
 class BiomeDefManager;
 class Biome;
 class EmergeManager;
@@ -43,20 +46,7 @@ class MapBlock;
 class ManualMapVoxelManipulator;
 class VoxelManipulator;
 class INodeDefManager;
-
-struct BlockMakeData {
-       bool no_op;
-       ManualMapVoxelManipulator *vmanip;
-       u64 seed;
-       v3s16 blockpos_min;
-       v3s16 blockpos_max;
-       v3s16 blockpos_requested;
-       UniqueQueue<v3s16> transforming_liquid;
-       INodeDefManager *nodedef;
-
-       BlockMakeData();
-       ~BlockMakeData();
-};
+class BlockMakeData;
 
 struct MapgenParams {
        std::string mg_name;
@@ -99,39 +89,5 @@ struct MapgenFactory {
        virtual MapgenParams *createMapgenParams() = 0;
 };
 
-class EmergeManager {
-public:
-       std::map<std::string, MapgenFactory *> mglist;
-
-       //settings
-       MapgenParams *params;
-
-       //mapgen objects here
-       Mapgen *mapgen;
-
-       //biome manager
-       BiomeDefManager *biomedef;
-
-       EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef);
-       ~EmergeManager();
-
-       void initMapgens(MapgenParams *mgparams);
-       Mapgen *createMapgen(std::string mgname, int mgid,
-                                               MapgenParams *mgparams, EmergeManager *emerge);
-       MapgenParams *createMapgenParams(std::string mgname);
-       Mapgen *getMapgen();
-       void addBlockToQueue();
-       
-       void registerMapgen(std::string name, MapgenFactory *mgfactory);
-       MapgenParams *getParamsFromSettings(Settings *settings);
-       void setParamsToSettings(Settings *settings);
-       
-       //mapgen helper methods
-       Biome *getBiomeAtPoint(v3s16 p);
-       int getGroundLevelAtPoint(v2s16 p);
-       bool isBlockUnderground(v3s16 blockpos);
-       u32 getBlockSeed(v3s16 p);
-};
-
 #endif
 
index dd4452928962634a7aec3f52ace165f38d2afa45..ef2cf5f523bdc6e3a54a8ab45cab442c43168da3 100644 (file)
@@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "profiler.h"
 #include "settings.h" // For g_settings
 #include "main.h" // For g_profiler
+#include "emerge.h"
 #include "mapgen_v6.h"
 
 /////////////////// Mapgen V6 perlin noise default values
index 686a3fea1e64e2173ae411d13bbd163b2c647b8a..f2897d46d040335d9c1f98a09b02664323cec21a 100644 (file)
@@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "nodedef.h"
 #include "itemdef.h"
 #include "craftdef.h"
+#include "emerge.h"
 #include "mapgen.h"
 #include "biome.h"
 #include "content_mapnode.h"
@@ -58,60 +59,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "rollback.h"
 #include "util/serialize.h"
 
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
-
-#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
-
-class MapEditEventIgnorer
-{
-public:
-       MapEditEventIgnorer(bool *flag):
-               m_flag(flag)
-       {
-               if(*m_flag == false)
-                       *m_flag = true;
-               else
-                       m_flag = NULL;
-       }
-
-       ~MapEditEventIgnorer()
-       {
-               if(m_flag)
-               {
-                       assert(*m_flag);
-                       *m_flag = false;
-               }
-       }
-
-private:
-       bool *m_flag;
-};
-
-class MapEditEventAreaIgnorer
-{
-public:
-       MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
-               m_ignorevariable(ignorevariable)
-       {
-               if(m_ignorevariable->getVolume() == 0)
-                       *m_ignorevariable = a;
-               else
-                       m_ignorevariable = NULL;
-       }
-
-       ~MapEditEventAreaIgnorer()
-       {
-               if(m_ignorevariable)
-               {
-                       assert(m_ignorevariable->getVolume() != 0);
-                       *m_ignorevariable = VoxelArea();
-               }
-       }
-
-private:
-       VoxelArea *m_ignorevariable;
-};
-
 void * ServerThread::Thread()
 {
        ThreadStarted();
@@ -157,265 +104,6 @@ void * ServerThread::Thread()
        return NULL;
 }
 
-void * EmergeThread::Thread()
-{
-       ThreadStarted();
-
-       log_register_thread("EmergeThread");
-
-       DSTACK(__FUNCTION_NAME);
-
-       BEGIN_DEBUG_EXCEPTION_HANDLER
-
-       bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
-
-       v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
-
-       ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
-       EmergeManager *emerge = m_server->m_emerge;
-       Mapgen *mapgen = emerge->getMapgen();
-
-       /*
-               Get block info from queue, emerge them and send them
-               to clients.
-
-               After queue is empty, exit.
-       */
-       while(getRun())
-       try{
-               QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
-               if(qptr == NULL)
-                       break;
-
-               SharedPtr<QueuedBlockEmerge> q(qptr);
-
-               v3s16 &p = q->pos;
-               v2s16 p2d(p.X,p.Z);
-
-               last_tried_pos = p;
-
-               /*
-                       Do not generate over-limit
-               */
-               if(blockpos_over_limit(p))
-                       continue;
-
-               //infostream<<"EmergeThread::Thread(): running"<<std::endl;
-
-               //TimeTaker timer("block emerge");
-
-               /*
-                       Try to emerge it from somewhere.
-
-                       If it is only wanted as optional, only loading from disk
-                       will be allowed.
-               */
-
-               /*
-                       Check if any peer wants it as non-optional. In that case it
-                       will be generated.
-
-                       Also decrement the emerge queue count in clients.
-               */
-
-               bool only_from_disk = true;
-
-               {
-                       core::map<u16, u8>::Iterator i;
-                       for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
-                       {
-                               //u16 peer_id = i.getNode()->getKey();
-
-                               // Check flags
-                               u8 flags = i.getNode()->getValue();
-                               if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
-                                       only_from_disk = false;
-
-                       }
-               }
-
-               if(enable_mapgen_debug_info)
-                       infostream<<"EmergeThread: p="
-                                       <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
-                                       <<"only_from_disk="<<only_from_disk<<std::endl;
-
-
-
-               MapBlock *block = NULL;
-               bool got_block = true;
-               core::map<v3s16, MapBlock*> modified_blocks;
-
-               /*
-                       Try to fetch block from memory or disk.
-                       If not found and asked to generate, initialize generator.
-               */
-
-               bool started_generate = false;
-               BlockMakeData data;
-
-               {
-                       JMutexAutoLock envlock(m_server->m_env_mutex);
-
-                       // Load sector if it isn't loaded
-                       if(map.getSectorNoGenerateNoEx(p2d) == NULL)
-                               map.loadSectorMeta(p2d);
-
-                       // Attempt to load block
-                       block = map.getBlockNoCreateNoEx(p);
-                       if(!block || block->isDummy() || !block->isGenerated())
-                       {
-                               if(enable_mapgen_debug_info)
-                                       infostream<<"EmergeThread: not in memory, "
-                                                       <<"attempting to load from disk"<<std::endl;
-
-                               block = map.loadBlock(p);
-                       }
-
-                       // If could not load and allowed to generate, start generation
-                       // inside this same envlock
-                       if(only_from_disk == false &&
-                                       (block == NULL || block->isGenerated() == false)){
-                               if(enable_mapgen_debug_info)
-                                       infostream<<"EmergeThread: generating"<<std::endl;
-                               started_generate = true;
-
-                               map.initBlockMake(&data, p);
-                       }
-               }
-
-               /*
-                       If generator was initialized, generate now when envlock is free.
-               */
-               if(started_generate)
-               {
-                       {
-                               ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
-                                               SPT_AVG);
-                               TimeTaker t("mapgen::make_block()");
-
-                               mapgen->makeChunk(&data);
-                               //mapgen::make_block(&data);
-
-                               if(enable_mapgen_debug_info == false)
-                                       t.stop(true); // Hide output
-                       }
-
-                       do{ // enable break
-                               // Lock environment again to access the map
-                               JMutexAutoLock envlock(m_server->m_env_mutex);
-
-                               ScopeProfiler sp(g_profiler, "EmergeThread: after "
-                                               "mapgen::make_block (envlock)", SPT_AVG);
-
-                               // Blit data back on map, update lighting, add mobs and
-                               // whatever this does
-                               map.finishBlockMake(&data, modified_blocks);
-
-                               // Get central block
-                               block = map.getBlockNoCreateNoEx(p);
-
-                               // If block doesn't exist, don't try doing anything with it
-                               // This happens if the block is not in generation boundaries
-                               if(!block)
-                                       break;
-
-                               /*
-                                       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
-                               */
-                               //MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
-                               MapEditEventAreaIgnorer ign(
-                                               &m_server->m_ignore_map_edit_events_area,
-                                               VoxelArea(minp, maxp));
-                               {
-                                       TimeTaker timer("on_generated");
-                                       scriptapi_environment_on_generated(m_server->m_lua,
-                                                       minp, maxp, emerge->getBlockSeed(minp));
-                                       /*int t = timer.stop(true);
-                                       dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
-                               }
-
-                               if(enable_mapgen_debug_info)
-                                       infostream<<"EmergeThread: ended up with: "
-                                                       <<analyze_block(block)<<std::endl;
-
-                               // Activate objects and stuff
-                               m_server->m_env->activateBlock(block, 0);
-                       }while(false);
-               }
-
-               if(block == NULL)
-                       got_block = false;
-
-               /*
-                       Set sent status of modified blocks on clients
-               */
-
-               // NOTE: Server's clients are also behind the connection mutex
-               JMutexAutoLock lock(m_server->m_con_mutex);
-
-               /*
-                       Add the originally fetched block to the modified list
-               */
-               if(got_block)
-               {
-                       modified_blocks.insert(p, block);
-               }
-
-               /*
-                       Set the modified blocks unsent for all the clients
-               */
-
-               for(core::map<u16, RemoteClient*>::Iterator
-                               i = m_server->m_clients.getIterator();
-                               i.atEnd() == false; i++)
-               {
-                       RemoteClient *client = i.getNode()->getValue();
-
-                       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;
-}
-
 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
 {
        if(pos_exists) *pos_exists = false;
@@ -770,7 +458,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                        */
                        if(block == NULL || surely_not_found_on_disk || block_is_invalid)
                        {
-                               //TODO: Get value from somewhere
+                       /*      //TODO: Get value from somewhere
                                // Allow only one block in emerge queue
                                //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
                                // Allow two blocks in queue per client
@@ -799,7 +487,17 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                                                nearest_emergefull_d = d;
                                        goto queue_full_break;
                                }
+                       */
 
+                               if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
+                                       if (nearest_emerged_d == -1)
+                                               nearest_emerged_d = d;
+                               } else {
+                                       if (nearest_emergefull_d == -1)
+                                               nearest_emergefull_d = d;
+                                       goto queue_full_break;
+                               }
+                               
                                // get next one.
                                continue;
                        }
@@ -953,7 +651,7 @@ Server::Server(
        m_craftdef(createCraftDefManager()),
        m_event(new EventManager()),
        m_thread(this),
-       m_emergethread(this),
+       //m_emergethread(this),
        m_time_of_day_send_timer(0),
        m_uptime(0),
        m_shutdown_requested(false),
@@ -1278,9 +976,9 @@ void Server::stop()
 
        // Stop threads (set run=false first so both start stopping)
        m_thread.setRun(false);
-       m_emergethread.setRun(false);
+       //m_emergethread.setRun(false);
        m_thread.stop();
-       m_emergethread.stop();
+       //m_emergethread.stop();
 
        infostream<<"Server: Threads stopped"<<std::endl;
 }
@@ -1951,7 +1649,7 @@ void Server::AsyncRunStep()
                {
                        counter = 0.0;
 
-                       m_emergethread.trigger();
+                       m_emerge->emergethread->trigger();
 
                        // Update m_enable_rollback_recording here too
                        m_enable_rollback_recording =
@@ -3115,8 +2813,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        infostream<<"Server: Not punching: Node not found."
                                                        <<" Adding block to emerge queue."
                                                        <<std::endl;
-                                       m_emerge_queue.addBlock(peer_id,
-                                                       getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
+                                       m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
                                }
                                if(n.getContent() != CONTENT_IGNORE)
                                        scriptapi_node_on_punch(m_lua, p_under, n, playersao);
@@ -3172,8 +2869,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        infostream<<"Server: Not finishing digging: Node not found."
                                                        <<" Adding block to emerge queue."
                                                        <<std::endl;
-                                       m_emerge_queue.addBlock(peer_id,
-                                                       getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
+                                       m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
                                }
 
                                /* Cheat prevention */
@@ -4728,10 +4424,7 @@ void Server::notifyPlayers(const std::wstring msg)
 
 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
 {
-       u8 flags = 0;
-       if(!allow_generate)
-               flags |= BLOCK_EMERGE_FLAG_FROMDISK;
-       m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
+       m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
 }
 
 Inventory* Server::createDetachedInventory(const std::string &name)
index 26973643aff3868034a58c358c7cbeee323d5499..e92cbb564be20fec08da841d4a055760fa3f4490 100644 (file)
@@ -39,6 +39,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "rollback_interface.h" // Needed for rollbackRevertActions()
 #include <list> // Needed for rollbackRevertActions()
 
+#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
+
 struct LuaState;
 typedef struct lua_State lua_State;
 class IWritableItemDefManager;
@@ -47,6 +49,7 @@ class IWritableCraftDefManager;
 class EventManager;
 class PlayerSAO;
 class IRollbackManager;
+class EmergeManager;
 
 class ServerError : public std::exception
 {
@@ -120,11 +123,9 @@ public:
                                If it is, update the peer to it and quit.
                        */
                        core::list<QueuedBlockEmerge*>::Iterator i;
-                       for(i=m_queue.begin(); i!=m_queue.end(); i++)
-                       {
+                       for(i=m_queue.begin(); i!=m_queue.end(); i++) {
                                QueuedBlockEmerge *q = *i;
-                               if(q->pos == pos)
-                               {
+                               if (q->pos == pos) {
                                        q->peer_ids[peer_id] = flags;
                                        return;
                                }
@@ -136,7 +137,7 @@ public:
                */
                QueuedBlockEmerge *q = new QueuedBlockEmerge;
                q->pos = pos;
-               if(peer_id != 0)
+               if (peer_id != 0)
                        q->peer_ids[peer_id] = flags;
                m_queue.push_back(q);
        }
@@ -200,30 +201,6 @@ public:
        void * Thread();
 };
 
-class EmergeThread : public SimpleThread
-{
-       Server *m_server;
-
-public:
-
-       EmergeThread(Server *server):
-               SimpleThread(),
-               m_server(server)
-       {
-       }
-
-       void * Thread();
-
-       void trigger()
-       {
-               setRun(true);
-               if(IsRunning() == false)
-               {
-                       Start();
-               }
-       }
-};
-
 struct PlayerInfo
 {
        u16 id;
@@ -785,9 +762,9 @@ private:
        // The server mainly operates in this thread
        ServerThread m_thread;
        // This thread fetches and generates map
-       EmergeThread m_emergethread;
+       //EmergeThread m_emergethread;
        // Queue of block coordinates to be processed by the emerge thread
-       BlockEmergeQueue m_emerge_queue;
+       //BlockEmergeQueue m_emerge_queue;
 
        /*
                Time related stuff