diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c06da20c4bfaa623c13d5e720c316ada8f518c95..d2f080c907d86a8186fe04b5602238a9a314194d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -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
index 0000000000000000000000000000000000000000..728ea7196b29cbefa4630da9e54655104e54ec9a
--- /dev/null
+++ b/src/emerge.cpp
@@ -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
index 0000000000000000000000000000000000000000..0acc89a6daf448bfd329f52c1b0f37841a8ba3a7
--- /dev/null
+++ b/src/emerge.h
@@ -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
diff --git a/src/environment.h b/src/environment.h
index a79ccc63d0feb022707dae7497ebb84f130b1dc4..07a4d7635673dd40dcee52f1420f2c2f236c1065 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -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;
diff --git a/src/jthread/jmutex.h b/src/jthread/jmutex.h
index 9ce013096f8a3817417d079003f2ed8319b15d5a..6675162a56b6070efdc22e3b021f5c20aa6d3f94 100644
--- a/src/jthread/jmutex.h
+++ b/src/jthread/jmutex.h
@@ -67,4 +67,54 @@ class JMutex
 	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
diff --git a/src/map.cpp b/src/map.cpp
index 696d73182addc6e94a3da8050ee2edbabf93f25d..7eb45463f7a2ab1e035c21906d1aadfbac7d415f 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -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<<")"
diff --git a/src/map.h b/src/map.h
index 1c91745c0a7a172b9bd4384497a9479045879ec8..0b2311f394cb01f62b3db4d0a35281dd1f6aaee5 100644
--- 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 @@ class ServerMap : public Map
 		Blocks are generated by using these and makeBlock().
 	*/
 	void initBlockMake(BlockMakeData *data, v3s16 blockpos);
-	MapBlock* finishBlockMake(BlockMakeData *data,
+	MapBlock *finishBlockMake(BlockMakeData *data,
 			core::map<v3s16, MapBlock*> &changed_blocks);
 
 	// A non-threaded wrapper to the above  - DEFUNCT
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index 73fe633185370cbc1b47210ccee95840115658a1..ef5da6bf1e43d85f1fdb39150ccb3ba6c0de74b1 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -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
-
-
diff --git a/src/mapgen.h b/src/mapgen.h
index 765ac3bb25f47d094c1c9012ef45e75bd4cc0a62..c3c209ad155b7c7dbea6b84799d0721d8e78fa66 100644
--- a/src/mapgen.h
+++ b/src/mapgen.h
@@ -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
 
diff --git a/src/mapgen_v6.cpp b/src/mapgen_v6.cpp
index dd4452928962634a7aec3f52ace165f38d2afa45..ef2cf5f523bdc6e3a54a8ab45cab442c43168da3 100644
--- a/src/mapgen_v6.cpp
+++ b/src/mapgen_v6.cpp
@@ -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
diff --git a/src/server.cpp b/src/server.cpp
index 686a3fea1e64e2173ae411d13bbd163b2c647b8a..f2897d46d040335d9c1f98a09b02664323cec21a 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -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)
diff --git a/src/server.h b/src/server.h
index 26973643aff3868034a58c358c7cbeee323d5499..e92cbb564be20fec08da841d4a055760fa3f4490 100644
--- a/src/server.h
+++ b/src/server.h
@@ -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 @@ class BlockEmergeQueue
 				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 @@ class BlockEmergeQueue
 		*/
 		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 @@ class ServerThread : public SimpleThread
 	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 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 	// 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