#include "log.h"
#include "map.h"
#include "mapblock.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:
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},
- {"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;
+ verbosestream << "Using " << nthreads << " emerge threads." << std::endl;
m_qlimit_total = g_settings->getU16("emergequeue_limit_total");
if (!g_settings->getU16NoEx("emergequeue_limit_diskonly", m_qlimit_diskonly))
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;
}
}
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, ¶ms, 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;
}
bool EmergeManager::enqueueBlockEmerge(
- u16 peer_id,
+ session_t peer_id,
v3s16 blockpos,
bool allow_generate,
bool ignore_queue_limits)
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);
}
// 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;
}
+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;
return m_mapgens[0]->getGroundLevelAtPoint(p);
}
-
+// TODO(hmmmm): Move this to ServerMap
bool EmergeManager::isBlockUnderground(v3s16 blockpos)
{
#if 0
#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];
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;
}
-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())
m_emerge(NULL),
m_mapgen(NULL)
{
- name = "Emerge-" + itos(ethreadid);
-}
-
-
-EmergeThread::~EmergeThread()
-{
- //cancelPendingItems();
+ m_name = "Emerge-" + itos(ethreadid);
}
}
-bool EmergeThread::pushBlock(v3s16 pos)
+bool EmergeThread::pushBlock(const v3s16 &pos)
{
m_block_queue.push(pos);
return true;
}
-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++) {
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))
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));
/*
void *EmergeThread::run()
{
- DSTACK(__FUNCTION_NAME);
BEGIN_DEBUG_EXCEPTION_HANDLER
v3s16 pos;
continue;
}
- if (blockpos_over_limit(pos))
+ if (blockpos_over_max_limit(pos))
continue;
bool allow_gen = bedata.flags & BLOCK_EMERGE_ALLOW_GEN;
{
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);
if (block)
modified_blocks[pos] = block;
- if (modified_blocks.size() > 0)
+ if (!modified_blocks.empty())
m_server->SetBlocksNotSent(modified_blocks);
}
} catch (VersionMismatchException &e) {
m_server->setAsyncFatalError(err.str());
}
- END_DEBUG_EXCEPTION_HANDLER(errorstream)
+ END_DEBUG_EXCEPTION_HANDLER
return NULL;
}