Add emerge completion callback mechanism

Major refactor of emerge.cpp and Map::init/finishBlockMake
This commit is contained in:
kwolekr 2015-10-04 02:54:25 -04:00
parent 1f9c5a4a7b
commit 0850d3bb93
6 changed files with 624 additions and 572 deletions

@ -20,77 +20,95 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "emerge.h" #include "emerge.h"
#include "server.h"
#include <iostream> #include <iostream>
#include <queue> #include <queue>
#include "threading/event.h"
#include "map.h"
#include "environment.h"
#include "util/container.h" #include "util/container.h"
#include "util/thread.h" #include "util/thread.h"
#include "constants.h" #include "threading/event.h"
#include "voxel.h"
#include "config.h" #include "config.h"
#include "mapblock.h" #include "constants.h"
#include "serverobject.h" #include "environment.h"
#include "settings.h"
#include "scripting_game.h"
#include "profiler.h"
#include "log.h" #include "log.h"
#include "nodedef.h" #include "map.h"
#include "mg_biome.h" #include "mapblock.h"
#include "mg_ore.h"
#include "mg_decoration.h"
#include "mg_schematic.h"
#include "mapgen_v5.h" #include "mapgen_v5.h"
#include "mapgen_v6.h" #include "mapgen_v6.h"
#include "mapgen_v7.h" #include "mapgen_v7.h"
#include "mapgen_singlenode.h" #include "mapgen_singlenode.h"
#include "mg_biome.h"
#include "mg_ore.h"
#include "mg_decoration.h"
#include "mg_schematic.h"
#include "nodedef.h"
#include "profiler.h"
#include "scripting_game.h"
#include "server.h"
#include "serverobject.h"
#include "settings.h"
#include "voxel.h"
struct MapgenDesc { struct MapgenDesc {
const char *name; const char *name;
MapgenFactory *factory; MapgenFactory *factory;
}; };
MapgenDesc reg_mapgens[] = { class EmergeThread : public Thread {
public:
bool enable_mapgen_debug_info;
int id;
EmergeThread(Server *server, int ethreadid);
~EmergeThread();
void *run();
void signal();
// Requires queue mutex held
bool pushBlock(v3s16 pos);
void cancelPendingItems();
static void runCompletionCallbacks(
v3s16 pos, EmergeAction action,
const EmergeCallbackList &callbacks);
private:
Server *m_server;
ServerMap *m_map;
EmergeManager *m_emerge;
Mapgen *m_mapgen;
Event m_queue_event;
std::queue<v3s16> m_block_queue;
bool popBlockEmerge(v3s16 *pos, BlockEmergeData *bedata);
EmergeAction getBlockOrStartGen(
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
////
MapgenDesc g_reg_mapgens[] = {
{"v5", new MapgenFactoryV5}, {"v5", new MapgenFactoryV5},
{"v6", new MapgenFactoryV6}, {"v6", new MapgenFactoryV6},
{"v7", new MapgenFactoryV7}, {"v7", new MapgenFactoryV7},
{"singlenode", new MapgenFactorySinglenode}, {"singlenode", new MapgenFactorySinglenode},
}; };
class EmergeThread : public Thread ////
{ //// EmergeManager
public: ////
Server *m_server;
ServerMap *map;
EmergeManager *emerge;
Mapgen *mapgen;
bool enable_mapgen_debug_info;
int id;
Event qevent;
std::queue<v3s16> blockqueue;
EmergeThread(Server *server, int ethreadid):
m_server(server),
map(NULL),
emerge(NULL),
mapgen(NULL),
enable_mapgen_debug_info(false),
id(ethreadid)
{
name = "Emerge-" + itos(id);
}
void *run();
bool popBlockEmerge(v3s16 *pos, u8 *flags);
bool getBlockOrStartGen(v3s16 p, MapBlock **b,
BlockMakeData *data, bool allow_generate);
};
/////////////////////////////// Emerge Manager ////////////////////////////////
EmergeManager::EmergeManager(IGameDef *gamedef) EmergeManager::EmergeManager(IGameDef *gamedef)
{ {
@ -104,11 +122,11 @@ EmergeManager::EmergeManager(IGameDef *gamedef)
// Note that accesses to this variable are not synchronized. // Note that accesses to this variable are not synchronized.
// This is because the *only* thread ever starting or stopping // This is because the *only* thread ever starting or stopping
// EmergeThreads should be the ServerThread. // EmergeThreads should be the ServerThread.
this->threads_active = false; this->m_threads_active = false;
mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info"); enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
// if unspecified, leave a proc for the main thread and one for // If unspecified, leave a proc for the main thread and one for
// some other misc thread // some other misc thread
s16 nthreads = 0; s16 nthreads = 0;
if (!g_settings->getS16NoEx("num_emerge_threads", nthreads)) if (!g_settings->getS16NoEx("num_emerge_threads", nthreads))
@ -116,22 +134,22 @@ EmergeManager::EmergeManager(IGameDef *gamedef)
if (nthreads < 1) if (nthreads < 1)
nthreads = 1; nthreads = 1;
qlimit_total = g_settings->getU16("emergequeue_limit_total"); m_qlimit_total = g_settings->getU16("emergequeue_limit_total");
if (!g_settings->getU16NoEx("emergequeue_limit_diskonly", qlimit_diskonly)) if (!g_settings->getU16NoEx("emergequeue_limit_diskonly", m_qlimit_diskonly))
qlimit_diskonly = nthreads * 5 + 1; m_qlimit_diskonly = nthreads * 5 + 1;
if (!g_settings->getU16NoEx("emergequeue_limit_generate", qlimit_generate)) if (!g_settings->getU16NoEx("emergequeue_limit_generate", m_qlimit_generate))
qlimit_generate = nthreads + 1; m_qlimit_generate = nthreads + 1;
// don't trust user input for something very important like this // don't trust user input for something very important like this
if (qlimit_total < 1) if (m_qlimit_total < 1)
qlimit_total = 1; m_qlimit_total = 1;
if (qlimit_diskonly < 1) if (m_qlimit_diskonly < 1)
qlimit_diskonly = 1; m_qlimit_diskonly = 1;
if (qlimit_generate < 1) if (m_qlimit_generate < 1)
qlimit_generate = 1; m_qlimit_generate = 1;
for (s16 i = 0; i < nthreads; i++) for (s16 i = 0; i < nthreads; i++)
emergethread.push_back(new EmergeThread((Server *) gamedef, i)); m_threads.push_back(new EmergeThread((Server *)gamedef, i));
infostream << "EmergeManager: using " << nthreads << " threads" << std::endl; infostream << "EmergeManager: using " << nthreads << " threads" << std::endl;
} }
@ -139,27 +157,25 @@ EmergeManager::EmergeManager(IGameDef *gamedef)
EmergeManager::~EmergeManager() EmergeManager::~EmergeManager()
{ {
for (u32 i = 0; i != emergethread.size(); i++) { for (u32 i = 0; i != m_threads.size(); i++) {
if (threads_active) { EmergeThread *thread = m_threads[i];
emergethread[i]->stop();
emergethread[i]->qevent.signal(); if (m_threads_active) {
emergethread[i]->wait(); thread->stop();
thread->signal();
thread->wait();
} }
delete emergethread[i];
delete mapgen[i]; delete thread;
delete m_mapgens[i];
} }
emergethread.clear();
mapgen.clear();
delete biomemgr; delete biomemgr;
delete oremgr; delete oremgr;
delete decomgr; delete decomgr;
delete schemmgr; delete schemmgr;
if (params.sparams) {
delete params.sparams; delete params.sparams;
params.sparams = NULL;
}
} }
@ -171,33 +187,37 @@ void EmergeManager::loadMapgenParams()
void EmergeManager::initMapgens() void EmergeManager::initMapgens()
{ {
if (mapgen.size()) if (m_mapgens.size())
return; return;
if (!params.sparams) { MapgenFactory *mgfactory = getMapgenFactory(params.mg_name);
params.sparams = createMapgenParams(params.mg_name); if (!mgfactory) {
if (!params.sparams) { errorstream << "EmergeManager: mapgen " << params.mg_name <<
" not registered; falling back to " << DEFAULT_MAPGEN << std::endl;
params.mg_name = DEFAULT_MAPGEN; params.mg_name = DEFAULT_MAPGEN;
params.sparams = createMapgenParams(params.mg_name);
assert(params.sparams); 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); params.sparams->readParams(g_settings);
} }
// Create the mapgens for (u32 i = 0; i != m_threads.size(); i++) {
for (u32 i = 0; i != emergethread.size(); i++) { Mapgen *mg = mgfactory->createMapgen(i, &params, this);
Mapgen *mg = createMapgen(params.mg_name, i, &params); m_mapgens.push_back(mg);
assert(mg);
mapgen.push_back(mg);
} }
} }
Mapgen *EmergeManager::getCurrentMapgen() Mapgen *EmergeManager::getCurrentMapgen()
{ {
for (u32 i = 0; i != emergethread.size(); i++) { for (u32 i = 0; i != m_threads.size(); i++) {
if (emergethread[i]->isSameThread()) if (m_threads[i]->isSameThread())
return emergethread[i]->mapgen; return m_threads[i]->m_mapgen;
} }
return NULL; return NULL;
@ -206,94 +226,81 @@ Mapgen *EmergeManager::getCurrentMapgen()
void EmergeManager::startThreads() void EmergeManager::startThreads()
{ {
if (threads_active) if (m_threads_active)
return; return;
for (u32 i = 0; i != emergethread.size(); i++) for (u32 i = 0; i != m_threads.size(); i++)
emergethread[i]->start(); m_threads[i]->start();
threads_active = true; m_threads_active = true;
} }
void EmergeManager::stopThreads() void EmergeManager::stopThreads()
{ {
if (!threads_active) if (!m_threads_active)
return; return;
// Request thread stop in parallel // Request thread stop in parallel
for (u32 i = 0; i != emergethread.size(); i++) { for (u32 i = 0; i != m_threads.size(); i++) {
emergethread[i]->stop(); m_threads[i]->stop();
emergethread[i]->qevent.signal(); m_threads[i]->signal();
} }
// Then do the waiting for each // Then do the waiting for each
for (u32 i = 0; i != emergethread.size(); i++) for (u32 i = 0; i != m_threads.size(); i++)
emergethread[i]->wait(); m_threads[i]->wait();
threads_active = false; m_threads_active = false;
} }
bool EmergeManager::enqueueBlockEmerge(u16 peer_id, v3s16 p, bool EmergeManager::enqueueBlockEmerge(
bool allow_generate, bool force_queue_block) u16 peer_id,
v3s16 blockpos,
bool allow_generate,
bool ignore_queue_limits)
{ {
std::map<v3s16, BlockEmergeData *>::const_iterator iter; u16 flags = 0;
BlockEmergeData *bedata;
u16 count_global = 0;
u16 count_peer = 0;
u8 flags = 0;
int idx = 0;
if (allow_generate) if (allow_generate)
flags |= BLOCK_EMERGE_ALLOWGEN; flags |= BLOCK_EMERGE_ALLOW_GEN;
if (ignore_queue_limits)
flags |= BLOCK_EMERGE_FORCE_QUEUE;
return enqueueBlockEmergeEx(blockpos, peer_id, flags, NULL, NULL);
}
bool EmergeManager::enqueueBlockEmergeEx(
v3s16 blockpos,
u16 peer_id,
u16 flags,
EmergeCompletionCallback callback,
void *callback_param)
{
EmergeThread *thread = NULL;
{ {
MutexAutoLock queuelock(queuemutex); MutexAutoLock queuelock(m_queue_mutex);
count_global = blocks_enqueued.size(); if (!pushBlockEmergeData(blockpos, peer_id, flags,
count_peer = peer_queue_count[peer_id]; callback, callback_param))
if (!force_queue_block) {
if (count_global >= qlimit_total)
return false; return false;
u16 qlimit_peer = allow_generate ? qlimit_generate : qlimit_diskonly; thread = getOptimalThread();
if (count_peer >= qlimit_peer) thread->pushBlock(blockpos);
return false;
} }
iter = blocks_enqueued.find(p); thread->signal();
if (iter != blocks_enqueued.end()) {
bedata = iter->second;
bedata->flags |= flags;
return true;
}
bedata = new BlockEmergeData;
bedata->flags = flags;
bedata->peer_requested = peer_id;
blocks_enqueued.insert(std::make_pair(p, bedata));
peer_queue_count[peer_id] = count_peer + 1;
// insert into the EmergeThread queue with the least items
int lowestitems = emergethread[0]->blockqueue.size();
for (u32 i = 1; i != emergethread.size(); i++) {
int nitems = emergethread[i]->blockqueue.size();
if (nitems < lowestitems) {
idx = i;
lowestitems = nitems;
}
}
emergethread[idx]->blockqueue.push(p);
}
emergethread[idx]->qevent.signal();
return true; return true;
} }
//
// Mapgen-related helper functions
//
v3s16 EmergeManager::getContainingChunk(v3s16 blockpos) v3s16 EmergeManager::getContainingChunk(v3s16 blockpos)
{ {
return getContainingChunk(blockpos, params.chunksize); return getContainingChunk(blockpos, params.chunksize);
@ -312,129 +319,297 @@ v3s16 EmergeManager::getContainingChunk(v3s16 blockpos, s16 chunksize)
int EmergeManager::getGroundLevelAtPoint(v2s16 p) int EmergeManager::getGroundLevelAtPoint(v2s16 p)
{ {
if (mapgen.size() == 0 || !mapgen[0]) { if (m_mapgens.size() == 0 || !m_mapgens[0]) {
errorstream << "EmergeManager: getGroundLevelAtPoint() called" errorstream << "EmergeManager: getGroundLevelAtPoint() called"
" before mapgen initialized" << std::endl; " before mapgen init" << std::endl;
return 0; return 0;
} }
return mapgen[0]->getGroundLevelAtPoint(p); return m_mapgens[0]->getGroundLevelAtPoint(p);
} }
bool EmergeManager::isBlockUnderground(v3s16 blockpos) bool EmergeManager::isBlockUnderground(v3s16 blockpos)
{ {
/* #if 0
v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2, v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
(blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2); (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
int ground_level = getGroundLevelAtPoint(p); int ground_level = getGroundLevelAtPoint(p);
return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level); return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
*/ #endif
//yuck, but then again, should i bother being accurate? // Use a simple heuristic; the above method is wildly inaccurate anyway.
//the height of the nodes in a single block is quite variable
return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params.water_level; return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params.water_level;
} }
void EmergeManager::getMapgenNames(std::list<const char *> &mgnames) void EmergeManager::getMapgenNames(std::vector<const char *> *mgnames)
{ {
for (u32 i = 0; i != ARRLEN(reg_mapgens); i++) for (u32 i = 0; i != ARRLEN(g_reg_mapgens); i++)
mgnames.push_back(reg_mapgens[i].name); mgnames->push_back(g_reg_mapgens[i].name);
} }
Mapgen *EmergeManager::createMapgen(const std::string &mgname, int mgid, MapgenFactory *EmergeManager::getMapgenFactory(const std::string &mgname)
MapgenParams *mgparams)
{ {
u32 i; for (u32 i = 0; i != ARRLEN(g_reg_mapgens); i++) {
for (i = 0; i != ARRLEN(reg_mapgens) && mgname != reg_mapgens[i].name; i++); if (mgname == g_reg_mapgens[i].name)
if (i == ARRLEN(reg_mapgens)) { return g_reg_mapgens[i].factory;
errorstream << "EmergeManager; mapgen " << mgname <<
" not registered" << std::endl;
return NULL;
} }
MapgenFactory *mgfactory = reg_mapgens[i].factory;
return mgfactory->createMapgen(mgid, mgparams, this);
}
MapgenSpecificParams *EmergeManager::createMapgenParams(const std::string &mgname)
{
u32 i;
for (i = 0; i < ARRLEN(reg_mapgens) && mgname != reg_mapgens[i].name; i++);
if (i == ARRLEN(reg_mapgens)) {
errorstream << "EmergeManager: Mapgen " << mgname <<
" not registered" << std::endl;
return NULL; return NULL;
}
MapgenFactory *mgfactory = reg_mapgens[i].factory;
return mgfactory->createMapgenParams();
} }
////////////////////////////// Emerge Thread ////////////////////////////////// bool EmergeManager::pushBlockEmergeData(
v3s16 pos,
bool EmergeThread::popBlockEmerge(v3s16 *pos, u8 *flags) u16 peer_requested,
u16 flags,
EmergeCompletionCallback callback,
void *callback_param)
{ {
std::map<v3s16, BlockEmergeData *>::iterator iter; u16 &count_peer = m_peer_queue_count[peer_requested];
MutexAutoLock queuelock(emerge->queuemutex);
if (blockqueue.empty()) if ((flags & BLOCK_EMERGE_FORCE_QUEUE) == 0) {
if (m_blocks_enqueued.size() >= m_qlimit_total)
return false; return false;
v3s16 p = blockqueue.front();
blockqueue.pop();
*pos = p; if (peer_requested != PEER_ID_INEXISTENT) {
u16 qlimit_peer = (flags & BLOCK_EMERGE_ALLOW_GEN) ?
m_qlimit_generate : m_qlimit_diskonly;
if (count_peer >= qlimit_peer)
return false;
}
}
iter = emerge->blocks_enqueued.find(p); std::pair<std::map<v3s16, BlockEmergeData>::iterator, bool> findres;
if (iter == emerge->blocks_enqueued.end()) findres = m_blocks_enqueued.insert(std::make_pair(pos, BlockEmergeData()));
return false; //uh oh, queue and map out of sync!!
BlockEmergeData *bedata = iter->second; BlockEmergeData &bedata = findres.first->second;
*flags = bedata->flags; bool update_existing = !findres.second;
emerge->peer_queue_count[bedata->peer_requested]--; if (callback)
bedata.callbacks.push_back(std::make_pair(callback, callback_param));
delete bedata; if (update_existing) {
emerge->blocks_enqueued.erase(iter); bedata.flags |= flags;
} else {
bedata.flags = flags;
bedata.peer_requested = peer_requested;
count_peer++;
}
return true; return true;
} }
bool EmergeThread::getBlockOrStartGen(v3s16 p, MapBlock **b, bool EmergeManager::popBlockEmergeData(
BlockMakeData *data, bool allow_gen) v3s16 pos,
BlockEmergeData *bedata)
{
std::map<v3s16, BlockEmergeData>::iterator it;
std::map<u16, u16>::iterator it2;
it = m_blocks_enqueued.find(pos);
if (it == m_blocks_enqueued.end())
return false;
*bedata = it->second;
it2 = m_peer_queue_count.find(bedata->peer_requested);
if (it2 == m_peer_queue_count.end())
return false;
u16 &count_peer = it2->second;
assert(count_peer != 0);
count_peer--;
m_blocks_enqueued.erase(it);
return true;
}
EmergeThread *EmergeManager::getOptimalThread()
{
size_t nthreads = m_threads.size();
FATAL_ERROR_IF(nthreads == 0, "No emerge threads!");
size_t index = 0;
size_t nitems_lowest = m_threads[0]->m_block_queue.size();
for (size_t i = 1; i < nthreads; i++) {
size_t nitems = m_threads[i]->m_block_queue.size();
if (nitems < nitems_lowest) {
index = i;
nitems_lowest = nitems;
}
}
return m_threads[index];
}
////
//// EmergeThread
////
EmergeThread::EmergeThread(Server *server, int ethreadid) :
enable_mapgen_debug_info(false),
id(ethreadid),
m_server(server),
m_map(NULL),
m_emerge(NULL),
m_mapgen(NULL)
{
name = "Emerge-" + itos(ethreadid);
}
EmergeThread::~EmergeThread()
{
//cancelPendingItems();
}
void EmergeThread::signal()
{
m_queue_event.signal();
}
bool EmergeThread::pushBlock(v3s16 pos)
{
m_block_queue.push(pos);
return true;
}
void EmergeThread::cancelPendingItems()
{
MutexAutoLock queuelock(m_emerge->m_queue_mutex);
while (!m_block_queue.empty()) {
BlockEmergeData bedata;
v3s16 pos;
pos = m_block_queue.front();
m_block_queue.pop();
m_emerge->popBlockEmergeData(pos, &bedata);
runCompletionCallbacks(pos, EMERGE_CANCELLED, bedata.callbacks);
}
}
void EmergeThread::runCompletionCallbacks(
v3s16 pos,
EmergeAction action,
const EmergeCallbackList &callbacks)
{
for (size_t i = 0; i != callbacks.size(); i++) {
EmergeCompletionCallback callback;
void *param;
callback = callbacks[i].first;
param = callbacks[i].second;
callback(pos, action, param);
}
}
bool EmergeThread::popBlockEmerge(v3s16 *pos, BlockEmergeData *bedata)
{
MutexAutoLock queuelock(m_emerge->m_queue_mutex);
if (m_block_queue.empty())
return false;
*pos = m_block_queue.front();
m_block_queue.pop();
m_emerge->popBlockEmergeData(*pos, bedata);
return true;
}
EmergeAction EmergeThread::getBlockOrStartGen(
v3s16 pos, bool allow_gen, MapBlock **block, BlockMakeData *bmdata)
{ {
v2s16 p2d(p.X, p.Z);
//envlock: usually takes <=1ms, sometimes 90ms or ~400ms to acquire
MutexAutoLock envlock(m_server->m_env_mutex); MutexAutoLock envlock(m_server->m_env_mutex);
// Load sector if it isn't loaded // 1). Attempt to fetch block from memory
if (map->getSectorNoGenerateNoEx(p2d) == NULL) *block = m_map->getBlockNoCreateNoEx(pos);
map->loadSectorMeta(p2d); if (*block && !(*block)->isDummy() && (*block)->isGenerated())
return EMERGE_FROM_MEMORY;
// Attempt to load block // 2). Attempt to load block from disk
MapBlock *block = map->getBlockNoCreateNoEx(p); *block = m_map->loadBlock(pos);
if (!block || block->isDummy() || !block->isGenerated()) { if (*block && (*block)->isGenerated())
EMERGE_DBG_OUT("not in memory, attempting to load from disk"); return EMERGE_FROM_DISK;
block = map->loadBlock(p);
if (block && block->isGenerated()) // 3). Attempt to start generation
map->prepareBlock(block); if (allow_gen && m_map->initBlockMake(pos, bmdata))
return EMERGE_GENERATED;
// All attempts failed; cancel this block emerge
return EMERGE_CANCELLED;
}
MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata,
std::map<v3s16, MapBlock *> *modified_blocks)
{
MutexAutoLock envlock(m_server->m_env_mutex);
ScopeProfiler sp(g_profiler,
"EmergeThread: after Mapgen::makeChunk", SPT_AVG);
/*
Perform post-processing on blocks (invalidate lighting, queue liquid
transforms, etc.) to finish block make
*/
m_map->finishBlockMake(bmdata, modified_blocks);
MapBlock *block = m_map->getBlockNoCreateNoEx(pos);
if (!block) {
errorstream << "EmergeThread::finishGen: Couldn't grab block we "
"just generated: " << PP(pos) << std::endl;
return NULL;
} }
// If could not load and allowed to generate, v3s16 minp = bmdata->blockpos_min * MAP_BLOCKSIZE;
// start generation inside this same envlock v3s16 maxp = bmdata->blockpos_max * MAP_BLOCKSIZE +
if (allow_gen && (block == NULL || !block->isGenerated())) { v3s16(1,1,1) * (MAP_BLOCKSIZE - 1);
EMERGE_DBG_OUT("generating");
*b = block; // Ignore map edit events, they will not need to be sent
return map->initBlockMake(data, p); // to anybody because the block hasn't been sent to anybody
MapEditEventAreaIgnorer ign(
&m_server->m_ignore_map_edit_events_area,
VoxelArea(minp, maxp));
/*
Run Lua on_generated callbacks
*/
try {
m_server->getScriptIface()->environment_OnGenerated(
minp, maxp, m_mapgen->blockseed);
} catch (LuaError &e) {
m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
} }
*b = block; EMERGE_DBG_OUT("ended up with: " << analyze_block(block));
return false;
/*
Activate the block
*/
m_server->m_env->activateBlock(block, 0);
return block;
} }
@ -443,108 +618,68 @@ void *EmergeThread::run()
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
BEGIN_DEBUG_EXCEPTION_HANDLER BEGIN_DEBUG_EXCEPTION_HANDLER
v3s16 last_tried_pos(-32768,-32768,-32768); // For error output v3s16 pos;
v3s16 p;
u8 flags = 0;
map = (ServerMap *)&(m_server->m_env->getMap()); m_map = (ServerMap *)&(m_server->m_env->getMap());
emerge = m_server->m_emerge; m_emerge = m_server->m_emerge;
mapgen = emerge->mapgen[id]; m_mapgen = m_emerge->m_mapgens[id];
enable_mapgen_debug_info = emerge->mapgen_debug_info; enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
while (!stopRequested())
try { try {
if (!popBlockEmerge(&p, &flags)) { while (!stopRequested()) {
qevent.wait(); std::map<v3s16, MapBlock *> modified_blocks;
BlockEmergeData bedata;
BlockMakeData bmdata;
EmergeAction action;
MapBlock *block;
if (!popBlockEmerge(&pos, &bedata)) {
m_queue_event.wait();
continue; continue;
} }
last_tried_pos = p; if (blockpos_over_limit(pos))
if (blockpos_over_limit(p))
continue; continue;
bool allow_generate = flags & BLOCK_EMERGE_ALLOWGEN; bool allow_gen = bedata.flags & BLOCK_EMERGE_ALLOW_GEN;
EMERGE_DBG_OUT("p=" PP(p) " allow_generate=" << allow_generate); EMERGE_DBG_OUT("pos=" PP(pos) " allow_gen=" << allow_gen);
/* action = getBlockOrStartGen(pos, allow_gen, &block, &bmdata);
Try to fetch block from memory or disk. if (action == EMERGE_GENERATED) {
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); ScopeProfiler sp(g_profiler,
"EmergeThread: Mapgen::makeChunk", SPT_AVG);
TimeTaker t("mapgen::make_block()"); TimeTaker t("mapgen::make_block()");
mapgen->makeChunk(&data); m_mapgen->makeChunk(&bmdata);
if (enable_mapgen_debug_info == false) if (enable_mapgen_debug_info == false)
t.stop(true); // Hide output t.stop(true); // Hide output
} }
{ block = finishGen(pos, &bmdata, &modified_blocks);
//envlock: usually 0ms, but can take either 30 or 400ms to acquire
MutexAutoLock 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("Lua: " + std::string(e.what()));
} }
EMERGE_DBG_OUT("ended up with: " << analyze_block(block)); runCompletionCallbacks(pos, action, bedata.callbacks);
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) if (block)
modified_blocks[p] = block; modified_blocks[pos] = block;
if (modified_blocks.size() > 0) { if (modified_blocks.size() > 0)
m_server->SetBlocksNotSent(modified_blocks); m_server->SetBlocksNotSent(modified_blocks);
} }
} } catch (VersionMismatchException &e) {
catch (VersionMismatchException &e) {
std::ostringstream err; std::ostringstream err;
err << "World data version mismatch in MapBlock " << PP(last_tried_pos) << std::endl err << "World data version mismatch in MapBlock " << PP(pos) << std::endl
<< "----" << std::endl << "----" << std::endl
<< "\"" << e.what() << "\"" << std::endl << "\"" << e.what() << "\"" << std::endl
<< "See debug.txt." << std::endl << "See debug.txt." << std::endl
<< "World probably saved by a newer version of " PROJECT_NAME_C "." << "World probably saved by a newer version of " PROJECT_NAME_C "."
<< std::endl; << std::endl;
m_server->setAsyncFatalError(err.str()); m_server->setAsyncFatalError(err.str());
} } catch (SerializationError &e) {
catch (SerializationError &e) {
std::ostringstream err; std::ostringstream err;
err << "Invalid data in MapBlock " << PP(last_tried_pos) << std::endl err << "Invalid data in MapBlock " << PP(pos) << std::endl
<< "----" << std::endl << "----" << std::endl
<< "\"" << e.what() << "\"" << std::endl << "\"" << e.what() << "\"" << std::endl
<< "See debug.txt." << std::endl << "See debug.txt." << std::endl
@ -553,23 +688,6 @@ void *EmergeThread::run()
m_server->setAsyncFatalError(err.str()); m_server->setAsyncFatalError(err.str());
} }
{
MutexAutoLock 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) END_DEBUG_EXCEPTION_HANDLER(errorstream)
return NULL; return NULL;
} }

@ -26,13 +26,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen.h" // for MapgenParams #include "mapgen.h" // for MapgenParams
#include "map.h" #include "map.h"
#define BLOCK_EMERGE_ALLOWGEN (1<<0) #define BLOCK_EMERGE_ALLOW_GEN (1 << 0)
#define BLOCK_EMERGE_FORCE_QUEUE (1 << 1)
#define EMERGE_DBG_OUT(x) \ #define EMERGE_DBG_OUT(x) do { \
do { \
if (enable_mapgen_debug_info) \ if (enable_mapgen_debug_info) \
infostream << "EmergeThread: " x << std::endl; \ infostream << "EmergeThread: " x << std::endl; \
} while (0) } while (0)
class EmergeThread; class EmergeThread;
class INodeDefManager; class INodeDefManager;
@ -43,6 +43,7 @@ class OreManager;
class DecorationManager; class DecorationManager;
class SchematicManager; class SchematicManager;
// Structure containing inputs/outputs for chunk generation
struct BlockMakeData { struct BlockMakeData {
MMVManip *vmanip; MMVManip *vmanip;
u64 seed; u64 seed;
@ -61,64 +62,106 @@ struct BlockMakeData {
~BlockMakeData() { delete vmanip; } ~BlockMakeData() { delete vmanip; }
}; };
// Result from processing an item on the emerge queue
enum EmergeAction {
EMERGE_CANCELLED,
EMERGE_ERRORED,
EMERGE_FROM_MEMORY,
EMERGE_FROM_DISK,
EMERGE_GENERATED,
};
// Callback
typedef void (*EmergeCompletionCallback)(
v3s16 blockpos, EmergeAction action, void *param);
typedef std::vector<
std::pair<
EmergeCompletionCallback,
void *
>
> EmergeCallbackList;
struct BlockEmergeData { struct BlockEmergeData {
u16 peer_requested; u16 peer_requested;
u8 flags; u16 flags;
EmergeCallbackList callbacks;
}; };
class EmergeManager { class EmergeManager {
public: public:
INodeDefManager *ndef; INodeDefManager *ndef;
bool enable_mapgen_debug_info;
std::vector<Mapgen *> mapgen; // Generation Notify
std::vector<EmergeThread *> emergethread;
bool threads_active;
//settings
MapgenParams params;
bool mapgen_debug_info;
u16 qlimit_total;
u16 qlimit_diskonly;
u16 qlimit_generate;
u32 gen_notify_on; u32 gen_notify_on;
std::set<u32> gen_notify_on_deco_ids; std::set<u32> gen_notify_on_deco_ids;
//// Block emerge queue data structures // Map generation parameters
Mutex queuemutex; MapgenParams params;
std::map<v3s16, BlockEmergeData *> blocks_enqueued;
std::map<u16, u16> peer_queue_count;
//// Managers of map generation-related components // Managers of various map generation-related components
BiomeManager *biomemgr; BiomeManager *biomemgr;
OreManager *oremgr; OreManager *oremgr;
DecorationManager *decomgr; DecorationManager *decomgr;
SchematicManager *schemmgr; SchematicManager *schemmgr;
//// Methods // Methods
EmergeManager(IGameDef *gamedef); EmergeManager(IGameDef *gamedef);
~EmergeManager(); ~EmergeManager();
void loadMapgenParams(); void loadMapgenParams();
static MapgenSpecificParams *createMapgenParams(const std::string &mgname);
void initMapgens(); void initMapgens();
Mapgen *getCurrentMapgen();
Mapgen *createMapgen(const std::string &mgname, int mgid,
MapgenParams *mgparams);
static void getMapgenNames(std::list<const char *> &mgnames);
void startThreads(); void startThreads();
void stopThreads(); void stopThreads();
bool enqueueBlockEmerge(u16 peer_id, v3s16 p, bool allow_generate,
bool force_queue_block=false); bool enqueueBlockEmerge(
u16 peer_id,
v3s16 blockpos,
bool allow_generate,
bool ignore_queue_limits=false);
bool enqueueBlockEmergeEx(
v3s16 blockpos,
u16 peer_id,
u16 flags,
EmergeCompletionCallback callback,
void *callback_param);
v3s16 getContainingChunk(v3s16 blockpos); v3s16 getContainingChunk(v3s16 blockpos);
static v3s16 getContainingChunk(v3s16 blockpos, s16 chunksize);
// mapgen helper methods Mapgen *getCurrentMapgen();
// Mapgen helpers methods
Biome *getBiomeAtPoint(v3s16 p); Biome *getBiomeAtPoint(v3s16 p);
int getGroundLevelAtPoint(v2s16 p); int getGroundLevelAtPoint(v2s16 p);
bool isBlockUnderground(v3s16 blockpos); bool isBlockUnderground(v3s16 blockpos);
static MapgenFactory *getMapgenFactory(const std::string &mgname);
static void getMapgenNames(std::vector<const char *> *mgnames);
static v3s16 getContainingChunk(v3s16 blockpos, s16 chunksize);
private:
std::vector<Mapgen *> m_mapgens;
std::vector<EmergeThread *> m_threads;
bool m_threads_active;
Mutex m_queue_mutex;
std::map<v3s16, BlockEmergeData> m_blocks_enqueued;
std::map<u16, u16> m_peer_queue_count;
u16 m_qlimit_total;
u16 m_qlimit_diskonly;
u16 m_qlimit_generate;
// Requires m_queue_mutex held
EmergeThread *getOptimalThread();
bool pushBlockEmergeData(v3s16 pos, u16 peer_requested, u16 flags,
EmergeCompletionCallback callback, void *callback_param);
bool popBlockEmergeData(v3s16 pos, BlockEmergeData *bedata);
friend class EmergeThread;
}; };
#endif #endif

@ -2254,71 +2254,52 @@ s16 ServerMap::getWaterLevel()
return m_emerge->params.water_level; return m_emerge->params.water_level;
} }
bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
{ {
bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos));
s16 csize = m_emerge->params.chunksize; s16 csize = m_emerge->params.chunksize;
v3s16 blockpos_min = EmergeManager::getContainingChunk(blockpos, csize); v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
v3s16 blockpos_max = blockpos_min + v3s16(1, 1, 1) * (csize - 1); v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
v3s16 extra_borders(1,1,1); bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
EMERGE_DBG_OUT("initBlockMake(): " PP(bpmin) " - " PP(bpmax));
v3s16 extra_borders(1, 1, 1);
v3s16 full_bpmin = bpmin - extra_borders;
v3s16 full_bpmax = bpmax + extra_borders;
// Do nothing if not inside limits (+-1 because of neighbors) // Do nothing if not inside limits (+-1 because of neighbors)
if(blockpos_over_limit(blockpos_min - extra_borders) || if (blockpos_over_limit(full_bpmin) ||
blockpos_over_limit(blockpos_max + extra_borders)) blockpos_over_limit(full_bpmax))
return false; return false;
data->seed = m_emerge->params.seed; data->seed = m_emerge->params.seed;
data->blockpos_min = blockpos_min; data->blockpos_min = bpmin;
data->blockpos_max = blockpos_max; data->blockpos_max = bpmax;
data->blockpos_requested = blockpos; data->blockpos_requested = blockpos;
data->nodedef = m_gamedef->ndef(); data->nodedef = m_gamedef->ndef();
/* /*
Create the whole area of this and the neighboring blocks Create the whole area of this and the neighboring blocks
*/ */
{ for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
//TimeTaker timer("initBlockMake() create area"); for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) {
for(s16 x=blockpos_min.X-extra_borders.X;
x<=blockpos_max.X+extra_borders.X; x++)
for(s16 z=blockpos_min.Z-extra_borders.Z;
z<=blockpos_max.Z+extra_borders.Z; z++)
{
v2s16 sectorpos(x, z); v2s16 sectorpos(x, z);
// Sector metadata is loaded from disk if not already loaded. // Sector metadata is loaded from disk if not already loaded.
ServerMapSector *sector = createSector(sectorpos); ServerMapSector *sector = createSector(sectorpos);
FATAL_ERROR_IF(sector == NULL, "createSector() failed"); FATAL_ERROR_IF(sector == NULL, "createSector() failed");
(void) sector;
for(s16 y=blockpos_min.Y-extra_borders.Y; for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
y<=blockpos_max.Y+extra_borders.Y; y++) v3s16 p(x, y, z);
{
v3s16 p(x,y,z);
//MapBlock *block = createBlock(p);
// 1) get from memory, 2) load from disk
MapBlock *block = emergeBlock(p, false); MapBlock *block = emergeBlock(p, false);
// 3) create a blank one if (block == NULL) {
if(block == NULL)
{
block = createBlock(p); block = createBlock(p);
/* // Block gets sunlight if this is true.
Block gets sunlight if this is true. // Refer to the map generator heuristics.
Refer to the map generator heuristics.
*/
bool ug = m_emerge->isBlockUnderground(p); bool ug = m_emerge->isBlockUnderground(p);
block->setIsUnderground(ug); block->setIsUnderground(ug);
} }
// Lighting will not be valid after make_chunk is called
block->setLightingExpired(true);
// Lighting will be calculated
//block->setLightingExpired(false);
}
} }
} }
@ -2329,21 +2310,14 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
neighboring blocks neighboring blocks
*/ */
// The area that contains this block and it's neighbors
v3s16 bigarea_blocks_min = blockpos_min - extra_borders;
v3s16 bigarea_blocks_max = blockpos_max + extra_borders;
data->vmanip = new MMVManip(this); data->vmanip = new MMVManip(this);
//data->vmanip->setMap(this); data->vmanip->initialEmerge(full_bpmin, full_bpmax);
// Add the area // Note: we may need this again at some point.
{ #if 0
//TimeTaker timer("initBlockMake() initialEmerge"); // Ensure none of the blocks to be generated were marked as
data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max); // containing CONTENT_IGNORE
} for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
// Ensure none of the blocks to be generated were marked as containing CONTENT_IGNORE
/* for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) { for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) { for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
core::map<v3s16, u8>::Node *n; core::map<v3s16, u8>::Node *n;
@ -2355,124 +2329,62 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
n->setValue(flags); n->setValue(flags);
} }
} }
}*/ }
#endif
// Data is ready now. // Data is ready now.
return true; return true;
} }
void ServerMap::finishBlockMake(BlockMakeData *data, void ServerMap::finishBlockMake(BlockMakeData *data,
std::map<v3s16, MapBlock*> &changed_blocks) std::map<v3s16, MapBlock*> *changed_blocks)
{ {
v3s16 blockpos_min = data->blockpos_min; v3s16 bpmin = data->blockpos_min;
v3s16 blockpos_max = data->blockpos_max; v3s16 bpmax = data->blockpos_max;
v3s16 blockpos_requested = data->blockpos_requested;
/*infostream<<"finishBlockMake(): ("<<blockpos_requested.X<<","
<<blockpos_requested.Y<<","
<<blockpos_requested.Z<<")"<<std::endl;*/
v3s16 extra_borders(1,1,1); v3s16 extra_borders(1, 1, 1);
v3s16 full_bpmin = bpmin - extra_borders;
v3s16 full_bpmax = bpmax + extra_borders;
bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info; bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax));
/*infostream<<"Resulting vmanip:"<<std::endl;
data->vmanip.print(infostream);*/
// Make sure affected blocks are loaded
for(s16 x=blockpos_min.X-extra_borders.X;
x<=blockpos_max.X+extra_borders.X; x++)
for(s16 z=blockpos_min.Z-extra_borders.Z;
z<=blockpos_max.Z+extra_borders.Z; z++)
for(s16 y=blockpos_min.Y-extra_borders.Y;
y<=blockpos_max.Y+extra_borders.Y; y++)
{
v3s16 p(x, y, z);
// Load from disk if not already in memory
emergeBlock(p, false);
}
/*
Blit generated stuff to map
NOTE: blitBackAll adds nearly everything to changed_blocks
*/
{
// 70ms @cs=8
//TimeTaker timer("finishBlockMake() blitBackAll");
data->vmanip->blitBackAll(&changed_blocks);
}
EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" << changed_blocks.size());
/*
Copy transforming liquid information
*/
while(data->transforming_liquid.size() > 0)
{
m_transforming_liquid.push_back(data->transforming_liquid.front());
data->transforming_liquid.pop_front();
}
/*
Do stuff in central blocks
*/
/*
Update lighting
*/
{
#if 0
TimeTaker t("finishBlockMake lighting update");
core::map<v3s16, MapBlock*> lighting_update_blocks;
// Center blocks
for(s16 x=blockpos_min.X-extra_borders.X;
x<=blockpos_max.X+extra_borders.X; x++)
for(s16 z=blockpos_min.Z-extra_borders.Z;
z<=blockpos_max.Z+extra_borders.Z; z++)
for(s16 y=blockpos_min.Y-extra_borders.Y;
y<=blockpos_max.Y+extra_borders.Y; y++)
{
v3s16 p(x, y, z);
MapBlock *block = getBlockNoCreateNoEx(p);
assert(block);
lighting_update_blocks.insert(block->getPos(), block);
}
updateLighting(lighting_update_blocks, changed_blocks);
#endif
/* /*
Set lighting to non-expired state in all of them. Set lighting to non-expired state in all of them.
This is cheating, but it is not fast enough if all of them This is cheating, but it is not fast enough if all of them
would actually be updated. would actually be updated.
*/ */
for(s16 x=blockpos_min.X-extra_borders.X; for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
x<=blockpos_max.X+extra_borders.X; x++) for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++)
for(s16 z=blockpos_min.Z-extra_borders.Z; for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
z<=blockpos_max.Z+extra_borders.Z; z++) MapBlock *block = emergeBlock(v3s16(x, y, z), false);
for(s16 y=blockpos_min.Y-extra_borders.Y; if (!block)
y<=blockpos_max.Y+extra_borders.Y; y++) continue;
{
v3s16 p(x, y, z);
MapBlock * block = getBlockNoCreateNoEx(p);
if (block != NULL)
block->setLightingExpired(false); block->setLightingExpired(false);
} }
#if 0 /*
if(enable_mapgen_debug_info == false) Blit generated stuff to map
t.stop(true); // Hide output NOTE: blitBackAll adds nearly everything to changed_blocks
#endif */
} data->vmanip->blitBackAll(changed_blocks);
EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()="
<< changed_blocks->size());
/* /*
Go through changed blocks Copy transforming liquid information
*/ */
for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin(); while (data->transforming_liquid.size()) {
i != changed_blocks.end(); ++i) m_transforming_liquid.push_back(data->transforming_liquid.front());
{ data->transforming_liquid.pop_front();
MapBlock *block = i->second; }
for (std::map<v3s16, MapBlock *>::iterator
it = changed_blocks->begin();
it != changed_blocks->end(); ++it) {
MapBlock *block = it->second;
if (!block) if (!block)
continue; continue;
/* /*
@ -2489,14 +2401,13 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
/* /*
Set central blocks as generated Set central blocks as generated
*/ */
for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++) for (s16 x = bpmin.X; x <= bpmax.X; x++)
for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++) for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++) for (s16 y = bpmin.Y; y <= bpmax.Y; y++) {
{ MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z));
v3s16 p(x, y, z);
MapBlock *block = getBlockNoCreateNoEx(p);
if (!block) if (!block)
continue; continue;
block->setGenerated(true); block->setGenerated(true);
} }
@ -2505,39 +2416,9 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
NOTE: Will be saved later. NOTE: Will be saved later.
*/ */
//save(MOD_STATE_WRITE_AT_UNLOAD); //save(MOD_STATE_WRITE_AT_UNLOAD);
/*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
<<","<<blockpos_requested.Y<<","
<<blockpos_requested.Z<<")"<<std::endl;*/
#if 0
if(enable_mapgen_debug_info)
{
/*
Analyze resulting blocks
*/
/*for(s16 x=blockpos_min.X-1; x<=blockpos_max.X+1; x++)
for(s16 z=blockpos_min.Z-1; z<=blockpos_max.Z+1; z++)
for(s16 y=blockpos_min.Y-1; y<=blockpos_max.Y+1; y++)*/
for(s16 x=blockpos_min.X-0; x<=blockpos_max.X+0; x++)
for(s16 z=blockpos_min.Z-0; z<=blockpos_max.Z+0; z++)
for(s16 y=blockpos_min.Y-0; y<=blockpos_max.Y+0; y++)
{
v3s16 p = v3s16(x,y,z);
MapBlock *block = getBlockNoCreateNoEx(p);
char spos[20];
snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
infostream<<"Generated "<<spos<<": "
<<analyze_block(block)<<std::endl;
}
}
#endif
getBlockNoCreateNoEx(blockpos_requested);
} }
ServerMapSector * ServerMap::createSector(v2s16 p2d) ServerMapSector *ServerMap::createSector(v2s16 p2d)
{ {
DSTACKF("%s: p2d=(%d,%d)", DSTACKF("%s: p2d=(%d,%d)",
__FUNCTION_NAME, __FUNCTION_NAME,
@ -3333,7 +3214,10 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
} }
#endif #endif
Database *ServerMap::createDatabase(const std::string &name, const std::string &savedir, Settings &conf) Database *ServerMap::createDatabase(
const std::string &name,
const std::string &savedir,
Settings &conf)
{ {
if (name == "sqlite3") if (name == "sqlite3")
return new Database_SQLite3(savedir); return new Database_SQLite3(savedir);
@ -3578,6 +3462,7 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
/* /*
Make sure sector is loaded Make sure sector is loaded
*/ */
MapSector *sector = getSectorNoGenerateNoEx(p2d); MapSector *sector = getSectorNoGenerateNoEx(p2d);
if(sector == NULL) if(sector == NULL)
{ {

@ -393,21 +393,21 @@ public:
- Check disk (doesn't load blocks) - Check disk (doesn't load blocks)
- Create blank one - Create blank one
*/ */
ServerMapSector * createSector(v2s16 p); ServerMapSector *createSector(v2s16 p);
/* /*
Blocks are generated by using these and makeBlock(). Blocks are generated by using these and makeBlock().
*/ */
bool initBlockMake(BlockMakeData *data, v3s16 blockpos); bool initBlockMake(v3s16 blockpos, BlockMakeData *data);
void finishBlockMake(BlockMakeData *data, void finishBlockMake(BlockMakeData *data,
std::map<v3s16, MapBlock*> &changed_blocks); std::map<v3s16, MapBlock*> *changed_blocks);
/* /*
Get a block from somewhere. Get a block from somewhere.
- Memory - Memory
- Create blank - Create blank
*/ */
MapBlock * createBlock(v3s16 p); MapBlock *createBlock(v3s16 p);
/* /*
Forcefully get a block from somewhere. Forcefully get a block from somewhere.

@ -61,8 +61,9 @@ FlagDesc flagdesc_gennotify[] = {
}; };
/////////////////////////////////////////////////////////////////////////////// ////
//// Mapgen
////
Mapgen::Mapgen() Mapgen::Mapgen()
{ {
@ -340,8 +341,9 @@ void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
} }
////
/////////////////////////////////////////////////////////////////////////////// //// GenerateNotifier
////
GenerateNotifier::GenerateNotifier() GenerateNotifier::GenerateNotifier()
{ {
@ -407,7 +409,10 @@ void GenerateNotifier::getEvents(
m_notify_events.clear(); m_notify_events.clear();
} }
///////////////////////////////////////////////////////////////////////////////
////
//// MapgenParams
////
void MapgenParams::load(const Settings &settings) void MapgenParams::load(const Settings &settings)
{ {
@ -429,9 +434,11 @@ void MapgenParams::load(const Settings &settings)
settings.getNoiseParams("mg_biome_np_humidity_blend", np_biome_humidity_blend); settings.getNoiseParams("mg_biome_np_humidity_blend", np_biome_humidity_blend);
delete sparams; delete sparams;
sparams = EmergeManager::createMapgenParams(mg_name); MapgenFactory *mgfactory = EmergeManager::getMapgenFactory(mg_name);
if (sparams) if (mgfactory) {
sparams = mgfactory->createMapgenParams();
sparams->readParams(&settings); sparams->readParams(&settings);
}
} }

@ -706,16 +706,13 @@ int ModApiMainMenu::l_set_topleft_text(lua_State *L)
/******************************************************************************/ /******************************************************************************/
int ModApiMainMenu::l_get_mapgen_names(lua_State *L) int ModApiMainMenu::l_get_mapgen_names(lua_State *L)
{ {
std::vector<const char *> names;
EmergeManager::getMapgenNames(&names);
lua_newtable(L); lua_newtable(L);
for (size_t i = 0; i != names.size(); i++) {
std::list<const char *> names; lua_pushstring(L, names[i]);
EmergeManager::getMapgenNames(names); lua_rawseti(L, -2, i + 1);
int i = 1;
for (std::list<const char *>::const_iterator
it = names.begin(); it != names.end(); ++it) {
lua_pushstring(L, *it);
lua_rawseti(L, -2, i++);
} }
return 1; return 1;
@ -725,8 +722,8 @@ int ModApiMainMenu::l_get_mapgen_names(lua_State *L)
/******************************************************************************/ /******************************************************************************/
int ModApiMainMenu::l_get_modpath(lua_State *L) int ModApiMainMenu::l_get_modpath(lua_State *L)
{ {
std::string modpath std::string modpath = fs::RemoveRelativePathComponents(
= fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "mods" + DIR_DELIM); porting::path_user + DIR_DELIM + "mods" + DIR_DELIM);
lua_pushstring(L, modpath.c_str()); lua_pushstring(L, modpath.c_str());
return 1; return 1;
} }
@ -734,8 +731,8 @@ int ModApiMainMenu::l_get_modpath(lua_State *L)
/******************************************************************************/ /******************************************************************************/
int ModApiMainMenu::l_get_gamepath(lua_State *L) int ModApiMainMenu::l_get_gamepath(lua_State *L)
{ {
std::string gamepath std::string gamepath = fs::RemoveRelativePathComponents(
= fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "games" + DIR_DELIM); porting::path_user + DIR_DELIM + "games" + DIR_DELIM);
lua_pushstring(L, gamepath.c_str()); lua_pushstring(L, gamepath.c_str());
return 1; return 1;
} }
@ -743,16 +740,16 @@ int ModApiMainMenu::l_get_gamepath(lua_State *L)
/******************************************************************************/ /******************************************************************************/
int ModApiMainMenu::l_get_texturepath(lua_State *L) int ModApiMainMenu::l_get_texturepath(lua_State *L)
{ {
std::string gamepath std::string gamepath = fs::RemoveRelativePathComponents(
= fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "textures"); porting::path_user + DIR_DELIM + "textures");
lua_pushstring(L, gamepath.c_str()); lua_pushstring(L, gamepath.c_str());
return 1; return 1;
} }
int ModApiMainMenu::l_get_texturepath_share(lua_State *L) int ModApiMainMenu::l_get_texturepath_share(lua_State *L)
{ {
std::string gamepath std::string gamepath = fs::RemoveRelativePathComponents(
= fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "textures"); porting::path_share + DIR_DELIM + "textures");
lua_pushstring(L, gamepath.c_str()); lua_pushstring(L, gamepath.c_str());
return 1; return 1;
} }
@ -762,10 +759,11 @@ int ModApiMainMenu::l_create_dir(lua_State *L) {
const char *path = luaL_checkstring(L, 1); const char *path = luaL_checkstring(L, 1);
if (ModApiMainMenu::isMinetestPath(path)) { if (ModApiMainMenu::isMinetestPath(path)) {
lua_pushboolean(L,fs::CreateAllDirs(path)); lua_pushboolean(L, fs::CreateAllDirs(path));
return 1; return 1;
} }
lua_pushboolean(L,false);
lua_pushboolean(L, false);
return 1; return 1;
} }
@ -777,10 +775,11 @@ int ModApiMainMenu::l_delete_dir(lua_State *L)
std::string absolute_path = fs::RemoveRelativePathComponents(path); std::string absolute_path = fs::RemoveRelativePathComponents(path);
if (ModApiMainMenu::isMinetestPath(absolute_path)) { if (ModApiMainMenu::isMinetestPath(absolute_path)) {
lua_pushboolean(L,fs::RecursiveDelete(absolute_path)); lua_pushboolean(L, fs::RecursiveDelete(absolute_path));
return 1; return 1;
} }
lua_pushboolean(L,false);
lua_pushboolean(L, false);
return 1; return 1;
} }