diff --git a/src/client.cpp b/src/client.cpp
index f97acfd43ae1900a690b780542c4a162ce368b07..6d0e6860c868d45b961bff93d4d238c8e6c0e7ec 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -5,7 +5,7 @@ Copyright (C) 2010 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 General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+MeshUpdateQueue::(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
@@ -26,6 +26,104 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <sstream>
 #include "porting.h"
 #include "mapsector.h"
+#include "mapblock_mesh.h"
+#include "mapblock.h"
+
+/*
+	QueuedMeshUpdate
+*/
+
+QueuedMeshUpdate::QueuedMeshUpdate():
+	p(-1337,-1337,-1337),
+	data(NULL),
+	ack_block_to_server(false)
+{
+}
+
+QueuedMeshUpdate::~QueuedMeshUpdate()
+{
+	if(data)
+		delete data;
+}
+
+/*
+	MeshUpdateQueue
+*/
+	
+MeshUpdateQueue::MeshUpdateQueue()
+{
+	m_mutex.Init();
+}
+
+MeshUpdateQueue::~MeshUpdateQueue()
+{
+	JMutexAutoLock lock(m_mutex);
+
+	core::list<QueuedMeshUpdate*>::Iterator i;
+	for(i=m_queue.begin(); i!=m_queue.end(); i++)
+	{
+		QueuedMeshUpdate *q = *i;
+		delete q;
+	}
+}
+
+/*
+	peer_id=0 adds with nobody to send to
+*/
+void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server)
+{
+	DSTACK(__FUNCTION_NAME);
+
+	assert(data);
+
+	JMutexAutoLock lock(m_mutex);
+
+	/*
+		Find if block is already in queue.
+		If it is, update the data and quit.
+	*/
+	core::list<QueuedMeshUpdate*>::Iterator i;
+	for(i=m_queue.begin(); i!=m_queue.end(); i++)
+	{
+		QueuedMeshUpdate *q = *i;
+		if(q->p == p)
+		{
+			if(q->data)
+				delete q->data;
+			q->data = data;
+			if(ack_block_to_server)
+				q->ack_block_to_server = true;
+			return;
+		}
+	}
+	
+	/*
+		Add the block
+	*/
+	QueuedMeshUpdate *q = new QueuedMeshUpdate;
+	q->p = p;
+	q->data = data;
+	q->ack_block_to_server = ack_block_to_server;
+	m_queue.push_back(q);
+}
+
+// Returned pointer must be deleted
+// Returns NULL if queue is empty
+QueuedMeshUpdate * MeshUpdateQueue::pop()
+{
+	JMutexAutoLock lock(m_mutex);
+
+	core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin();
+	if(i == m_queue.end())
+		return NULL;
+	QueuedMeshUpdate *q = *i;
+	m_queue.erase(i);
+	return q;
+}
+
+/*
+	MeshUpdateThread
+*/
 
 void * MeshUpdateThread::Thread()
 {
@@ -1736,7 +1834,7 @@ void Client::addNode(v3s16 p, MapNode n)
 
 	try
 	{
-		TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
+		//TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
 		m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
 	}
 	catch(InvalidPositionException &e)
@@ -1964,12 +2062,6 @@ void Client::printDebugInfo(std::ostream &os)
 		<<std::endl;*/
 }
 	
-/*s32 Client::getDayNightIndex()
-{
-	assert(m_daynight_i >= 0 && m_daynight_i < DAYNIGHT_CACHE_COUNT);
-	return m_daynight_i;
-}*/
-
 u32 Client::getDayNightRatio()
 {
 	//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
@@ -1983,6 +2075,40 @@ u16 Client::getHP()
 	return player->hp;
 }
 
+void Client::setTempMod(v3s16 p, NodeMod mod)
+{
+	//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
+	assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
+
+	core::map<v3s16, MapBlock*> affected_blocks;
+	((ClientMap&)m_env.getMap()).setTempMod(p, mod,
+			&affected_blocks);
+
+	for(core::map<v3s16, MapBlock*>::Iterator
+			i = affected_blocks.getIterator();
+			i.atEnd() == false; i++)
+	{
+		i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
+	}
+}
+
+void Client::clearTempMod(v3s16 p)
+{
+	//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
+	assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
+
+	core::map<v3s16, MapBlock*> affected_blocks;
+	((ClientMap&)m_env.getMap()).clearTempMod(p,
+			&affected_blocks);
+
+	for(core::map<v3s16, MapBlock*>::Iterator
+			i = affected_blocks.getIterator();
+			i.atEnd() == false; i++)
+	{
+		i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
+	}
+}
+
 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
 {
 	/*dstream<<"Client::addUpdateMeshTask(): "
diff --git a/src/client.h b/src/client.h
index a1b1c66b4a0d7381217b76b5533caf3354d9e6e0..442eaef5df9282ac460bffb9743f6e8738394dba 100644
--- a/src/client.h
+++ b/src/client.h
@@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <ostream>
 #include "clientobject.h"
 
+struct MeshMakeData;
+
 class ClientNotReadyException : public BaseException
 {
 public:
@@ -43,18 +45,8 @@ struct QueuedMeshUpdate
 	MeshMakeData *data;
 	bool ack_block_to_server;
 
-	QueuedMeshUpdate():
-		p(-1337,-1337,-1337),
-		data(NULL),
-		ack_block_to_server(false)
-	{
-	}
-	
-	~QueuedMeshUpdate()
-	{
-		if(data)
-			delete data;
-	}
+	QueuedMeshUpdate();
+	~QueuedMeshUpdate();
 };
 
 /*
@@ -63,76 +55,18 @@ struct QueuedMeshUpdate
 class MeshUpdateQueue
 {
 public:
-	MeshUpdateQueue()
-	{
-		m_mutex.Init();
-	}
-
-	~MeshUpdateQueue()
-	{
-		JMutexAutoLock lock(m_mutex);
+	MeshUpdateQueue();
 
-		core::list<QueuedMeshUpdate*>::Iterator i;
-		for(i=m_queue.begin(); i!=m_queue.end(); i++)
-		{
-			QueuedMeshUpdate *q = *i;
-			delete q;
-		}
-	}
+	~MeshUpdateQueue();
 	
 	/*
 		peer_id=0 adds with nobody to send to
 	*/
-	void addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server)
-	{
-		DSTACK(__FUNCTION_NAME);
-
-		assert(data);
-	
-		JMutexAutoLock lock(m_mutex);
-
-		/*
-			Find if block is already in queue.
-			If it is, update the data and quit.
-		*/
-		core::list<QueuedMeshUpdate*>::Iterator i;
-		for(i=m_queue.begin(); i!=m_queue.end(); i++)
-		{
-			QueuedMeshUpdate *q = *i;
-			if(q->p == p)
-			{
-				if(q->data)
-					delete q->data;
-				q->data = data;
-				if(ack_block_to_server)
-					q->ack_block_to_server = true;
-				return;
-			}
-		}
-		
-		/*
-			Add the block
-		*/
-		QueuedMeshUpdate *q = new QueuedMeshUpdate;
-		q->p = p;
-		q->data = data;
-		q->ack_block_to_server = ack_block_to_server;
-		m_queue.push_back(q);
-	}
+	void addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server);
 
 	// Returned pointer must be deleted
 	// Returns NULL if queue is empty
-	QueuedMeshUpdate * pop()
-	{
-		JMutexAutoLock lock(m_mutex);
-
-		core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin();
-		if(i == m_queue.end())
-			return NULL;
-		QueuedMeshUpdate *q = *i;
-		m_queue.erase(i);
-		return q;
-	}
+	QueuedMeshUpdate * pop();
 
 	u32 size()
 	{
@@ -309,40 +243,8 @@ class Client : public con::PeerHandler, public InventoryManager
 
 	u16 getHP();
 
-	//void updateSomeExpiredMeshes();
-	
-	void setTempMod(v3s16 p, NodeMod mod)
-	{
-		//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
-		assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
-
-		core::map<v3s16, MapBlock*> affected_blocks;
-		((ClientMap&)m_env.getMap()).setTempMod(p, mod,
-				&affected_blocks);
-
-		for(core::map<v3s16, MapBlock*>::Iterator
-				i = affected_blocks.getIterator();
-				i.atEnd() == false; i++)
-		{
-			i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
-		}
-	}
-	void clearTempMod(v3s16 p)
-	{
-		//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
-		assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
-
-		core::map<v3s16, MapBlock*> affected_blocks;
-		((ClientMap&)m_env.getMap()).clearTempMod(p,
-				&affected_blocks);
-
-		for(core::map<v3s16, MapBlock*>::Iterator
-				i = affected_blocks.getIterator();
-				i.atEnd() == false; i++)
-		{
-			i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
-		}
-	}
+	void setTempMod(v3s16 p, NodeMod mod);
+	void clearTempMod(v3s16 p);
 
 	float getAvgRtt()
 	{
diff --git a/src/environment.cpp b/src/environment.cpp
index cd255341f5d8b996c1600e61a14fa2e46d9665ba..6a7c8478efdc44e076fcb3b732b57c942778fb54 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "porting.h"
 #include "collision.h"
 #include "content_mapnode.h"
-
+#include "mapblock.h"
 
 Environment::Environment():
 	m_time_of_day(9000)
diff --git a/src/game.cpp b/src/game.cpp
index f3fac0c84eb5bbdb6e80fbff49bf058ef32efabe..337879cb8f2302e4a2b982023511eb5666b173bb 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -30,8 +30,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "clouds.h"
 #include "keycode.h"
 #include "farmesh.h"
+#include "mapblock.h"
 
-// TODO: Move content-aware stuff to separate file
+/*
+	TODO: Move content-aware stuff to separate file by adding properties
+	      and virtual interfaces
+*/
 #include "content_mapnode.h"
 #include "content_nodemeta.h"
 
diff --git a/src/main.cpp b/src/main.cpp
index 41da310f450344af0c99b48f3ad6c32c8cc31e76..9c7cf2e28b85c12666e8e1f167db61e492019803 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -238,8 +238,6 @@ FIXME: The new optimized map sending doesn't sometimes send enough blocks
        from big caves and such
 FIXME: Block send distance configuration does not take effect for some reason
 
-TODO: Map saving should be done by EmergeThread
-
 SUGG: Map unloading based on sector reference is not very good, it keeps
 	unnecessary stuff in memory. I guess. Investigate this.
 
diff --git a/src/map.cpp b/src/map.cpp
index d8cc34ca7808ce3e0df302464aa52ea23e91336b..3164028b7b1d2e9a7403b32ad2afdab2b744f43b 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "serverobject.h"
 #include "content_mapnode.h"
 #include "mapgen.h"
+#include "nodemetadata.h"
 
 extern "C" {
 	#include "sqlite3.h"
@@ -141,19 +142,6 @@ MapBlock * Map::getBlockNoCreate(v3s16 p3d)
 	return block;
 }
 
-
-/*MapBlock * Map::getBlockCreate(v3s16 p3d)
-{
-	v2s16 p2d(p3d.X, p3d.Z);
-	MapSector * sector = getSectorCreate(p2d);
-	assert(sector);
-	MapBlock *block = sector->getBlockNoCreate(p3d.Y);
-	if(block)
-		return block;
-	block = sector->createBlankBlock(p3d.Y);
-	return block;
-}*/
-
 bool Map::isNodeUnderground(v3s16 p)
 {
 	v3s16 blockpos = getNodeBlockPos(p);
@@ -167,6 +155,45 @@ bool Map::isNodeUnderground(v3s16 p)
 	}
 }
 
+bool Map::isValidPosition(v3s16 p)
+{
+	v3s16 blockpos = getNodeBlockPos(p);
+	MapBlock *block = getBlockNoCreate(blockpos);
+	return (block != NULL);
+}
+
+// Returns a CONTENT_IGNORE node if not found
+MapNode Map::getNodeNoEx(v3s16 p)
+{
+	v3s16 blockpos = getNodeBlockPos(p);
+	MapBlock *block = getBlockNoCreateNoEx(blockpos);
+	if(block == NULL)
+		return MapNode(CONTENT_IGNORE);
+	v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
+	return block->getNodeNoCheck(relpos);
+}
+
+// throws InvalidPositionException if not found
+MapNode Map::getNode(v3s16 p)
+{
+	v3s16 blockpos = getNodeBlockPos(p);
+	MapBlock *block = getBlockNoCreateNoEx(blockpos);
+	if(block == NULL)
+		throw InvalidPositionException();
+	v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
+	return block->getNodeNoCheck(relpos);
+}
+
+// throws InvalidPositionException if not found
+void Map::setNode(v3s16 p, MapNode & n)
+{
+	v3s16 blockpos = getNodeBlockPos(p);
+	MapBlock *block = getBlockNoCreate(blockpos);
+	v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
+	block->setNodeNoCheck(relpos, n);
+}
+
+
 /*
 	Goes recursively through the neighbours of the node.
 
@@ -2096,22 +2123,25 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
 	/*
 		Update lighting
 	*/
-
-	core::map<v3s16, MapBlock*> lighting_update_blocks;
-	// Center block
-	lighting_update_blocks.insert(block->getPos(), block);
-#if 0
-	// All modified blocks
-	for(core::map<v3s16, MapBlock*>::Iterator
-			i = changed_blocks.getIterator();
-			i.atEnd() == false; i++)
 	{
-		lighting_update_blocks.insert(i.getNode()->getKey(),
-				i.getNode()->getValue());
+		TimeTaker t("finishBlockMake lighting update");
+
+		core::map<v3s16, MapBlock*> lighting_update_blocks;
+		// Center block
+		lighting_update_blocks.insert(block->getPos(), block);
+	#if 0
+		// All modified blocks
+		for(core::map<v3s16, MapBlock*>::Iterator
+				i = changed_blocks.getIterator();
+				i.atEnd() == false; i++)
+		{
+			lighting_update_blocks.insert(i.getNode()->getKey(),
+					i.getNode()->getValue());
+		}
+	#endif
+		updateLighting(lighting_update_blocks, changed_blocks);
 	}
-#endif
-	updateLighting(lighting_update_blocks, changed_blocks);
-	
+
 	/*
 		Add random objects to block
 	*/
diff --git a/src/map.h b/src/map.h
index 406b1bc841e289f3895ccee39c472314abacf79b..c64f8cbdb7fb3e6dc3fb5bd8fcb4daebfefe076b 100644
--- a/src/map.h
+++ b/src/map.h
@@ -25,27 +25,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <jthread.h>
 #include <iostream>
 
-#ifdef _WIN32
-	#include <windows.h>
-	#define sleep_s(x) Sleep((x*1000))
-#else
-	#include <unistd.h>
-	#define sleep_s(x) sleep(x)
-#endif
-
 #include "common_irrlicht.h"
 #include "mapnode.h"
-#include "mapblock.h"
+#include "mapblock_nodemod.h"
 #include "constants.h"
 #include "voxel.h"
-#include "mapchunk.h"
-#include "nodemetadata.h"
 
 class MapSector;
 class ServerMapSector;
 class ClientMapSector;
-
 class MapBlock;
+class NodeMetadata;
 
 namespace mapgen{
 	struct BlockMakeData;
@@ -161,66 +151,20 @@ class Map /*: public NodeContainer*/
 	MapBlock * getBlockNoCreate(v3s16 p);
 	// Returns NULL if not found
 	MapBlock * getBlockNoCreateNoEx(v3s16 p);
-	// Gets an existing block or creates an empty one
-	//MapBlock * getBlockCreate(v3s16 p);
 	
 	// Returns InvalidPositionException if not found
 	bool isNodeUnderground(v3s16 p);
 	
-	// virtual from NodeContainer
-	bool isValidPosition(v3s16 p)
-	{
-		v3s16 blockpos = getNodeBlockPos(p);
-		MapBlock *blockref;
-		try{
-			blockref = getBlockNoCreate(blockpos);
-		}
-		catch(InvalidPositionException &e)
-		{
-			return false;
-		}
-		return true;
-		/*v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
-		bool is_valid = blockref->isValidPosition(relpos);
-		return is_valid;*/
-	}
+	bool isValidPosition(v3s16 p);
 	
-	// virtual from NodeContainer
 	// throws InvalidPositionException if not found
-	MapNode getNode(v3s16 p)
-	{
-		v3s16 blockpos = getNodeBlockPos(p);
-		MapBlock * blockref = getBlockNoCreate(blockpos);
-		v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
+	MapNode getNode(v3s16 p);
 
-		return blockref->getNodeNoCheck(relpos);
-	}
-
-	// virtual from NodeContainer
 	// throws InvalidPositionException if not found
-	void setNode(v3s16 p, MapNode & n)
-	{
-		v3s16 blockpos = getNodeBlockPos(p);
-		MapBlock * blockref = getBlockNoCreate(blockpos);
-		v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
-		blockref->setNodeNoCheck(relpos, n);
-	}
+	void setNode(v3s16 p, MapNode & n);
 	
 	// Returns a CONTENT_IGNORE node if not found
-	MapNode getNodeNoEx(v3s16 p)
-	{
-		try{
-			v3s16 blockpos = getNodeBlockPos(p);
-			MapBlock * blockref = getBlockNoCreate(blockpos);
-			v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
-
-			return blockref->getNodeNoCheck(relpos);
-		}
-		catch(InvalidPositionException &e)
-		{
-			return MapNode(CONTENT_IGNORE);
-		}
-	}
+	MapNode getNodeNoEx(v3s16 p);
 
 	void unspreadLight(enum LightBank bank,
 			core::map<v3s16, u8> & from_nodes,
diff --git a/src/mapblockobject.cpp b/src/mapblockobject.cpp
index 51ac4c66ba3bab5da9893d03d3166025b3d5217f..ab1c20267dfd39687446f991fa797c26ef6cb150 100644
--- a/src/mapblockobject.cpp
+++ b/src/mapblockobject.cpp
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "map.h"
 #include "inventory.h"
 #include "utility.h"
+#include "mapblock.h"
 
 /*
 	MapBlockObject
diff --git a/src/mapchunk.h b/src/mapchunk.h
index 9860abad0ad9748ee6c09e196d5c7c96c77d5c9d..98df7ce66a2691b1140d6c5784920f473c294eb7 100644
--- a/src/mapchunk.h
+++ b/src/mapchunk.h
@@ -20,6 +20,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef MAPCHUNK_HEADER
 #define MAPCHUNK_HEADER
 
+/*
+	TODO: Remove
+*/
+
+#if 0
 /*
 	MapChunk contains map-generation-time metadata for an area of
 	some MapSectors. (something like 16x16)
@@ -66,6 +71,7 @@ class MapChunk
 	u8 m_generation_level;
 	bool m_modified;
 };
+#endif
 
 #endif
 
diff --git a/src/server.cpp b/src/server.cpp
index cf8b57773a2b200f5ca47f6c48ae2ab4e64f0dea..671c3bd4e0ee6272f0e4eea0b3c8e7f5adfadbb3 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "content_mapnode.h"
 #include "content_craft.h"
 #include "content_nodemeta.h"
+#include "mapblock.h"
 
 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)