]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/emerge.cpp
Formspecs: Add state-selection to style elements (#9378)
[dragonfireclient.git] / src / emerge.cpp
index 3532ca29dea40f79feecf14049c127a43c68086c..fe885447c5480460f26754bd73f5f5e03d88c5fc 100644 (file)
@@ -34,48 +34,35 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "log.h"
 #include "map.h"
 #include "mapblock.h"
-#include "mapgen_fractal.h"
-#include "mapgen_v5.h"
-#include "mapgen_v6.h"
-#include "mapgen_v7.h"
-#include "mapgen_singlenode.h"
-#include "mg_biome.h"
-#include "mg_ore.h"
-#include "mg_decoration.h"
-#include "mg_schematic.h"
+#include "mapgen/mg_biome.h"
+#include "mapgen/mg_ore.h"
+#include "mapgen/mg_decoration.h"
+#include "mapgen/mg_schematic.h"
 #include "nodedef.h"
 #include "profiler.h"
-#include "scripting_game.h"
+#include "scripting_server.h"
 #include "server.h"
-#include "serverobject.h"
 #include "settings.h"
 #include "voxel.h"
 
-
-struct MapgenDesc {
-       const char *name;
-       MapgenFactory *factory;
-       bool is_user_visible;
-};
-
 class EmergeThread : public Thread {
 public:
        bool enable_mapgen_debug_info;
        int id;
 
        EmergeThread(Server *server, int ethreadid);
-       ~EmergeThread();
+       ~EmergeThread() = default;
 
        void *run();
        void signal();
 
        // Requires queue mutex held
-       bool pushBlock(v3s16 pos);
+       bool pushBlock(const v3s16 &pos);
 
        void cancelPendingItems();
 
        static void runCompletionCallbacks(
-               v3s16 pos, EmergeAction action,
+               const v3s16 &pos, EmergeAction action,
                const EmergeCallbackList &callbacks);
 
 private:
@@ -90,49 +77,61 @@ class EmergeThread : public Thread {
        bool popBlockEmerge(v3s16 *pos, BlockEmergeData *bedata);
 
        EmergeAction getBlockOrStartGen(
-               v3s16 pos, bool allow_gen, MapBlock **block, BlockMakeData *data);
+               const v3s16 &pos, bool allow_gen, MapBlock **block, BlockMakeData *data);
        MapBlock *finishGen(v3s16 pos, BlockMakeData *bmdata,
                std::map<v3s16, MapBlock *> *modified_blocks);
 
        friend class EmergeManager;
 };
 
-////
-//// Built-in mapgens
-////
+class MapEditEventAreaIgnorer
+{
+public:
+       MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
+               m_ignorevariable(ignorevariable)
+       {
+               if(m_ignorevariable->getVolume() == 0)
+                       *m_ignorevariable = a;
+               else
+                       m_ignorevariable = NULL;
+       }
 
-MapgenDesc g_reg_mapgens[] = {
-       {"v5",         new MapgenFactoryV5,         true},
-       {"v6",         new MapgenFactoryV6,         true},
-       {"v7",         new MapgenFactoryV7,         true},
-       {"fractal",    new MapgenFactoryFractal,    false},
-       {"singlenode", new MapgenFactorySinglenode, false},
+       ~MapEditEventAreaIgnorer()
+       {
+               if(m_ignorevariable)
+               {
+                       assert(m_ignorevariable->getVolume() != 0);
+                       *m_ignorevariable = VoxelArea();
+               }
+       }
+
+private:
+       VoxelArea *m_ignorevariable;
 };
 
 ////
 //// EmergeManager
 ////
 
-EmergeManager::EmergeManager(IGameDef *gamedef)
+EmergeManager::EmergeManager(Server *server)
 {
-       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;
+       this->ndef      = server->getNodeDefManager();
+       this->biomemgr  = new BiomeManager(server);
+       this->oremgr    = new OreManager(server);
+       this->decomgr   = new DecorationManager(server);
+       this->schemmgr  = new SchematicManager(server);
 
        // 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->m_threads_active = false;
 
        enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
 
-       // If unspecified, leave a proc for the main thread and one for
+       s16 nthreads = 1;
+       g_settings->getS16NoEx("num_emerge_threads", nthreads);
+       // If automatic, 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))
+       if (nthreads == 0)
                nthreads = Thread::getNumberOfProcessors() - 2;
        if (nthreads < 1)
                nthreads = 1;
@@ -152,7 +151,7 @@ EmergeManager::EmergeManager(IGameDef *gamedef)
                m_qlimit_generate = 1;
 
        for (s16 i = 0; i < nthreads; i++)
-               m_threads.push_back(new EmergeThread((Server *)gamedef, i));
+               m_threads.push_back(new EmergeThread(server, i));
 
        infostream << "EmergeManager: using " << nthreads << " threads" << std::endl;
 }
@@ -170,60 +169,41 @@ EmergeManager::~EmergeManager()
                }
 
                delete thread;
-               delete m_mapgens[i];
+
+               // Mapgen init might not be finished if there is an error during startup.
+               if (m_mapgens.size() > i)
+                       delete m_mapgens[i];
        }
 
        delete biomemgr;
        delete oremgr;
        delete decomgr;
        delete schemmgr;
-
-       delete params.sparams;
-}
-
-
-void EmergeManager::loadMapgenParams()
-{
-       params.load(*g_settings);
 }
 
 
-void EmergeManager::initMapgens()
+void EmergeManager::initMapgens(MapgenParams *params)
 {
-       if (m_mapgens.size())
-               return;
+       FATAL_ERROR_IF(!m_mapgens.empty(), "Mapgen already initialised.");
 
-       MapgenFactory *mgfactory = getMapgenFactory(params.mg_name);
-       if (!mgfactory) {
-               errorstream << "EmergeManager: mapgen " << params.mg_name <<
-                       " not registered; falling back to " << DEFAULT_MAPGEN << std::endl;
+       mgparams = params;
 
-               params.mg_name = DEFAULT_MAPGEN;
-
-               mgfactory = getMapgenFactory(params.mg_name);
-               FATAL_ERROR_IF(mgfactory == NULL, "Couldn't use any mapgen!");
-       }
-
-       if (!params.sparams) {
-               params.sparams = mgfactory->createMapgenParams();
-               params.sparams->readParams(g_settings);
-       }
-
-       for (u32 i = 0; i != m_threads.size(); i++) {
-               Mapgen *mg = mgfactory->createMapgen(i, &params, this);
-               m_mapgens.push_back(mg);
-       }
+       for (u32 i = 0; i != m_threads.size(); i++)
+               m_mapgens.push_back(Mapgen::createMapgen(params->mgtype, params, this));
 }
 
 
 Mapgen *EmergeManager::getCurrentMapgen()
 {
+       if (!m_threads_active)
+               return nullptr;
+
        for (u32 i = 0; i != m_threads.size(); i++) {
-               if (m_threads[i]->isSameThread())
+               if (m_threads[i]->isCurrentThread())
                        return m_threads[i]->m_mapgen;
        }
 
-       return NULL;
+       return nullptr;
 }
 
 
@@ -265,7 +245,7 @@ bool EmergeManager::isRunning()
 
 
 bool EmergeManager::enqueueBlockEmerge(
-       u16 peer_id,
+       session_t peer_id,
        v3s16 blockpos,
        bool allow_generate,
        bool ignore_queue_limits)
@@ -282,20 +262,24 @@ bool EmergeManager::enqueueBlockEmerge(
 
 bool EmergeManager::enqueueBlockEmergeEx(
        v3s16 blockpos,
-       u16 peer_id,
+       session_t peer_id,
        u16 flags,
        EmergeCompletionCallback callback,
        void *callback_param)
 {
        EmergeThread *thread = NULL;
+       bool entry_already_exists = false;
 
        {
                MutexAutoLock queuelock(m_queue_mutex);
 
                if (!pushBlockEmergeData(blockpos, peer_id, flags,
-                               callback, callback_param))
+                               callback, callback_param, &entry_already_exists))
                        return false;
 
+               if (entry_already_exists)
+                       return true;
+
                thread = getOptimalThread();
                thread->pushBlock(blockpos);
        }
@@ -310,12 +294,14 @@ bool EmergeManager::enqueueBlockEmergeEx(
 // Mapgen-related helper functions
 //
 
+
+// TODO(hmmmm): Move this to ServerMap
 v3s16 EmergeManager::getContainingChunk(v3s16 blockpos)
 {
-       return getContainingChunk(blockpos, params.chunksize);
+       return getContainingChunk(blockpos, mgparams->chunksize);
 }
 
-
+// TODO(hmmmm): Move this to ServerMap
 v3s16 EmergeManager::getContainingChunk(v3s16 blockpos, s16 chunksize)
 {
        s16 coff = -chunksize / 2;
@@ -326,9 +312,21 @@ v3s16 EmergeManager::getContainingChunk(v3s16 blockpos, s16 chunksize)
 }
 
 
+int EmergeManager::getSpawnLevelAtPoint(v2s16 p)
+{
+       if (m_mapgens.empty() || !m_mapgens[0]) {
+               errorstream << "EmergeManager: getSpawnLevelAtPoint() called"
+                       " before mapgen init" << std::endl;
+               return 0;
+       }
+
+       return m_mapgens[0]->getSpawnLevelAtPoint(p);
+}
+
+
 int EmergeManager::getGroundLevelAtPoint(v2s16 p)
 {
-       if (m_mapgens.size() == 0 || !m_mapgens[0]) {
+       if (m_mapgens.empty() || !m_mapgens[0]) {
                errorstream << "EmergeManager: getGroundLevelAtPoint() called"
                        " before mapgen init" << std::endl;
                return 0;
@@ -337,7 +335,7 @@ int EmergeManager::getGroundLevelAtPoint(v2s16 p)
        return m_mapgens[0]->getGroundLevelAtPoint(p);
 }
 
-
+// TODO(hmmmm): Move this to ServerMap
 bool EmergeManager::isBlockUnderground(v3s16 blockpos)
 {
 #if 0
@@ -348,37 +346,16 @@ bool EmergeManager::isBlockUnderground(v3s16 blockpos)
 #endif
 
        // Use a simple heuristic; the above method is wildly inaccurate anyway.
-       return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params.water_level;
-}
-
-
-void EmergeManager::getMapgenNames(
-       std::vector<const char *> *mgnames, bool include_hidden)
-{
-       for (u32 i = 0; i != ARRLEN(g_reg_mapgens); i++) {
-               if (include_hidden || g_reg_mapgens[i].is_user_visible)
-                       mgnames->push_back(g_reg_mapgens[i].name);
-       }
+       return blockpos.Y * (MAP_BLOCKSIZE + 1) <= mgparams->water_level;
 }
 
-
-MapgenFactory *EmergeManager::getMapgenFactory(const std::string &mgname)
-{
-       for (u32 i = 0; i != ARRLEN(g_reg_mapgens); i++) {
-               if (mgname == g_reg_mapgens[i].name)
-                       return g_reg_mapgens[i].factory;
-       }
-
-       return NULL;
-}
-
-
 bool EmergeManager::pushBlockEmergeData(
        v3s16 pos,
        u16 peer_requested,
        u16 flags,
        EmergeCompletionCallback callback,
-       void *callback_param)
+       void *callback_param,
+       bool *entry_already_exists)
 {
        u16 &count_peer = m_peer_queue_count[peer_requested];
 
@@ -398,12 +375,12 @@ bool EmergeManager::pushBlockEmergeData(
        findres = m_blocks_enqueued.insert(std::make_pair(pos, BlockEmergeData()));
 
        BlockEmergeData &bedata = findres.first->second;
-       bool update_existing    = !findres.second;
+       *entry_already_exists   = !findres.second;
 
        if (callback)
-               bedata.callbacks.push_back(std::make_pair(callback, callback_param));
+               bedata.callbacks.emplace_back(callback, callback_param);
 
-       if (update_existing) {
+       if (*entry_already_exists) {
                bedata.flags |= flags;
        } else {
                bedata.flags = flags;
@@ -416,12 +393,10 @@ bool EmergeManager::pushBlockEmergeData(
 }
 
 
-bool EmergeManager::popBlockEmergeData(
-       v3s16 pos,
-       BlockEmergeData *bedata)
+bool EmergeManager::popBlockEmergeData(v3s16 pos, BlockEmergeData *bedata)
 {
        std::map<v3s16, BlockEmergeData>::iterator it;
-       std::map<u16, u16>::iterator it2;
+       std::unordered_map<u16, u16>::iterator it2;
 
        it = m_blocks_enqueued.find(pos);
        if (it == m_blocks_enqueued.end())
@@ -476,13 +451,7 @@ EmergeThread::EmergeThread(Server *server, int ethreadid) :
        m_emerge(NULL),
        m_mapgen(NULL)
 {
-       name = "Emerge-" + itos(ethreadid);
-}
-
-
-EmergeThread::~EmergeThread()
-{
-       //cancelPendingItems();
+       m_name = "Emerge-" + itos(ethreadid);
 }
 
 
@@ -492,7 +461,7 @@ void EmergeThread::signal()
 }
 
 
-bool EmergeThread::pushBlock(v3s16 pos)
+bool EmergeThread::pushBlock(const v3s16 &pos)
 {
        m_block_queue.push(pos);
        return true;
@@ -517,9 +486,7 @@ void EmergeThread::cancelPendingItems()
 }
 
 
-void EmergeThread::runCompletionCallbacks(
-       v3s16 pos,
-       EmergeAction action,
+void EmergeThread::runCompletionCallbacks(const v3s16 &pos, EmergeAction action,
        const EmergeCallbackList &callbacks)
 {
        for (size_t i = 0; i != callbacks.size(); i++) {
@@ -551,19 +518,21 @@ bool EmergeThread::popBlockEmerge(v3s16 *pos, BlockEmergeData *bedata)
 
 
 EmergeAction EmergeThread::getBlockOrStartGen(
-       v3s16 pos, bool allow_gen, MapBlock **block, BlockMakeData *bmdata)
+       const v3s16 &pos, bool allow_gen, MapBlock **block, BlockMakeData *bmdata)
 {
        MutexAutoLock envlock(m_server->m_env_mutex);
 
        // 1). Attempt to fetch block from memory
        *block = m_map->getBlockNoCreateNoEx(pos);
-       if (*block && !(*block)->isDummy() && (*block)->isGenerated())
-               return EMERGE_FROM_MEMORY;
-
-       // 2). Attempt to load block from disk
-       *block = m_map->loadBlock(pos);
-       if (*block && (*block)->isGenerated())
-               return EMERGE_FROM_DISK;
+       if (*block && !(*block)->isDummy()) {
+               if ((*block)->isGenerated())
+                       return EMERGE_FROM_MEMORY;
+       } else {
+               // 2). Attempt to load block from disk if it was not in the memory
+               *block = m_map->loadBlock(pos);
+               if (*block && (*block)->isGenerated())
+                       return EMERGE_FROM_DISK;
+       }
 
        // 3). Attempt to start generation
        if (allow_gen && m_map->initBlockMake(pos, bmdata))
@@ -611,9 +580,15 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata,
                m_server->getScriptIface()->environment_OnGenerated(
                        minp, maxp, m_mapgen->blockseed);
        } catch (LuaError &e) {
-               m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
+               m_server->setAsyncFatalError("Lua: finishGen" + std::string(e.what()));
        }
 
+       /*
+               Clear generate notifier events
+       */
+       Mapgen *mg = m_emerge->getCurrentMapgen();
+       mg->gennotify.clearEvents();
+
        EMERGE_DBG_OUT("ended up with: " << analyze_block(block));
 
        /*
@@ -627,7 +602,6 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata,
 
 void *EmergeThread::run()
 {
-       DSTACK(__FUNCTION_NAME);
        BEGIN_DEBUG_EXCEPTION_HANDLER
 
        v3s16 pos;
@@ -650,7 +624,7 @@ void *EmergeThread::run()
                        continue;
                }
 
-               if (blockpos_over_limit(pos))
+               if (blockpos_over_max_limit(pos))
                        continue;
 
                bool allow_gen = bedata.flags & BLOCK_EMERGE_ALLOW_GEN;
@@ -661,12 +635,8 @@ void *EmergeThread::run()
                        {
                                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);
@@ -677,7 +647,7 @@ void *EmergeThread::run()
                if (block)
                        modified_blocks[pos] = block;
 
-               if (modified_blocks.size() > 0)
+               if (!modified_blocks.empty())
                        m_server->SetBlocksNotSent(modified_blocks);
        }
        } catch (VersionMismatchException &e) {
@@ -700,6 +670,6 @@ void *EmergeThread::run()
                m_server->setAsyncFatalError(err.str());
        }
 
-       END_DEBUG_EXCEPTION_HANDLER(errorstream)
+       END_DEBUG_EXCEPTION_HANDLER
        return NULL;
 }