From 1bc37d576ce790c1169c5f9996be7bbc8026db2c Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Sun, 17 Jun 2012 01:29:13 +0300
Subject: Initially split utility.h to multiple files in util/

---
 src/CMakeLists.txt           |    6 +
 src/client.cpp               |    2 +-
 src/constants.h              |   13 -
 src/debug.h                  |   12 +-
 src/filecache.cpp            |    3 +-
 src/main.cpp                 |    2 +-
 src/player.h                 |    1 +
 src/porting.cpp              |    2 +-
 src/server.cpp               |    2 +-
 src/sound_openal.cpp         |    5 +-
 src/subgame.cpp              |    2 +-
 src/test.cpp                 |    2 +-
 src/tile.cpp                 |    2 +-
 src/util/container.h         |  305 +++++++
 src/util/directiontables.cpp |  101 +++
 src/util/directiontables.h   |   33 +
 src/util/numeric.cpp         |  202 +++++
 src/util/numeric.h           |  331 ++++++++
 src/util/pointedthing.cpp    |  125 +++
 src/util/pointedthing.h      |   50 ++
 src/util/pointer.h           |  298 +++++++
 src/util/serialize.cpp       |  119 +++
 src/util/serialize.h         |  456 +++++++++++
 src/util/string.cpp          |   43 +
 src/util/string.h            |  264 ++++++
 src/util/thread.h            |  227 ++++++
 src/util/timetaker.cpp       |   61 ++
 src/util/timetaker.h         |   51 ++
 src/utility.cpp              |  434 +---------
 src/utility.h                | 1852 +-----------------------------------------
 src/utility_string.h         |   50 --
 31 files changed, 2707 insertions(+), 2349 deletions(-)
 create mode 100644 src/util/container.h
 create mode 100644 src/util/directiontables.cpp
 create mode 100644 src/util/directiontables.h
 create mode 100644 src/util/numeric.cpp
 create mode 100644 src/util/numeric.h
 create mode 100644 src/util/pointedthing.cpp
 create mode 100644 src/util/pointedthing.h
 create mode 100644 src/util/pointer.h
 create mode 100644 src/util/serialize.cpp
 create mode 100644 src/util/serialize.h
 create mode 100644 src/util/string.cpp
 create mode 100644 src/util/string.h
 create mode 100644 src/util/thread.h
 create mode 100644 src/util/timetaker.cpp
 create mode 100644 src/util/timetaker.h
 delete mode 100644 src/utility_string.h

(limited to 'src')

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6137c669e..324353038 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -204,6 +204,12 @@ set(common_SRCS
 	sha1.cpp
 	base64.cpp
 	ban.cpp
+	util/serialize.cpp
+	util/directiontables.cpp
+	util/numeric.cpp
+	util/pointedthing.cpp
+	util/string.cpp
+	util/timetaker.cpp
 )
 
 # This gives us the icon
diff --git a/src/client.cpp b/src/client.cpp
index 06745eab0..a563949d4 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -40,7 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "clientmap.h"
 #include "filecache.h"
 #include "sound.h"
-#include "utility_string.h"
+#include "util/string.h"
 #include "hex.h"
 
 static std::string getMediaCacheDir()
diff --git a/src/constants.h b/src/constants.h
index 6faeaf1b8..a65ee6524 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -30,19 +30,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #define PI 3.14159
 
-/*
-    Build-time stuff
-*/
-
-// Whether to catch all std::exceptions.
-// Assert will be called on such an event.
-// In debug mode, leave these for the debugger and don't catch them.
-#ifdef NDEBUG
-	#define CATCH_UNHANDLED_EXCEPTIONS 1
-#else
-	#define CATCH_UNHANDLED_EXCEPTIONS 0
-#endif
-
 /*
     Connection
 */
diff --git a/src/debug.h b/src/debug.h
index 8c5714f8c..7a3c60144 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -24,10 +24,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <jmutex.h>
 #include <jmutexautolock.h>
 #include <iostream>
-#include "common_irrlicht.h"
+#include "irrlichttypes.h"
 #include "threads.h"
 #include "gettime.h"
-#include "constants.h"
 #include "exceptions.h"
 
 #ifdef _WIN32
@@ -39,6 +38,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #else
 #endif
 
+// Whether to catch all std::exceptions.
+// Assert will be called on such an event.
+// In debug mode, leave these for the debugger and don't catch them.
+#ifdef NDEBUG
+	#define CATCH_UNHANDLED_EXCEPTIONS 1
+#else
+	#define CATCH_UNHANDLED_EXCEPTIONS 0
+#endif
+
 /*
 	Debug output
 */
diff --git a/src/filecache.cpp b/src/filecache.cpp
index 7af21236a..47e346596 100644
--- a/src/filecache.cpp
+++ b/src/filecache.cpp
@@ -19,15 +19,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 
 #include "filecache.h"
+
 #include "clientserver.h"
 #include "log.h"
 #include "filesys.h"
 #include "utility.h"
 #include "hex.h"
 #include "sha1.h"
-
 #include <string>
 #include <iostream>
+#include <fstream>
 
 bool FileCache::loadByPath(const std::string &path, std::ostream &os)
 {
diff --git a/src/main.cpp b/src/main.cpp
index 3c9184e2e..3352b866c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -68,7 +68,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "profiler.h"
 #include "log.h"
 #include "mods.h"
-#include "utility_string.h"
+#include "util/string.h"
 #include "subgame.h"
 #include "quicktune.h"
 
diff --git a/src/player.h b/src/player.h
index 4ffac7ef0..3b5497721 100644
--- a/src/player.h
+++ b/src/player.h
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "irrlichttypes.h"
 #include "inventory.h"
+#include "constants.h" // BS
 
 #define PLAYERNAME_SIZE 20
 
diff --git a/src/porting.cpp b/src/porting.cpp
index b327985d4..fb999abf9 100644
--- a/src/porting.cpp
+++ b/src/porting.cpp
@@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "debug.h"
 #include "filesys.h"
 #include "log.h"
-#include "utility_string.h"
+#include "util/string.h"
 
 #ifdef __APPLE__
 	#include "CoreFoundation/CoreFoundation.h"
diff --git a/src/server.cpp b/src/server.cpp
index 98072e854..70e33aaf7 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -49,7 +49,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "sha1.h"
 #include "base64.h"
 #include "tool.h"
-#include "utility_string.h"
+#include "util/string.h"
 #include "sound.h" // dummySoundManager
 #include "event_manager.h"
 #include "hex.h"
diff --git a/src/sound_openal.cpp b/src/sound_openal.cpp
index 258a5c195..e95b31b7f 100644
--- a/src/sound_openal.cpp
+++ b/src/sound_openal.cpp
@@ -38,10 +38,11 @@ with this program; ifnot, write to the Free Software Foundation, Inc.,
 #endif
 #include <vorbis/vorbisfile.h>
 #include "log.h"
-#include <map>
-#include <vector>
 #include "utility.h" // myrand()
 #include "filesys.h"
+#include <map>
+#include <vector>
+#include <fstream>
 
 #define BUFFER_SIZE 30000
 
diff --git a/src/subgame.cpp b/src/subgame.cpp
index 16e7cc8e0..c36189933 100644
--- a/src/subgame.cpp
+++ b/src/subgame.cpp
@@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "filesys.h"
 #include "settings.h"
 #include "log.h"
-#include "utility_string.h"
+#include "util/string.h"
 
 std::string getGameName(const std::string &game_path)
 {
diff --git a/src/test.cpp b/src/test.cpp
index 448ba23ce..95b204064 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -35,7 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapsector.h"
 #include "settings.h"
 #include "log.h"
-#include "utility_string.h"
+#include "util/string.h"
 #include "voxelalgorithms.h"
 #include "inventory.h"
 
diff --git a/src/tile.cpp b/src/tile.cpp
index f0b905c4a..919298fab 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapnode.h" // For texture atlas making
 #include "nodedef.h" // For texture atlas making
 #include "gamedef.h"
-#include "utility_string.h"
+#include "util/string.h"
 
 /*
 	A cache from texture name to texture path
diff --git a/src/util/container.h b/src/util/container.h
new file mode 100644
index 000000000..bdf560979
--- /dev/null
+++ b/src/util/container.h
@@ -0,0 +1,305 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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.
+*/
+
+#ifndef UTIL_CONTAINER_HEADER
+#define UTIL_CONTAINER_HEADER
+
+#include "../irrlichttypes.h"
+#include <jmutex.h>
+#include <jmutexautolock.h>
+#include "../porting.h" // For sleep_ms
+
+/*
+	Queue with unique values with fast checking of value existence
+*/
+
+template<typename Value>
+class UniqueQueue
+{
+public:
+	
+	/*
+		Does nothing if value is already queued.
+		Return value:
+			true: value added
+			false: value already exists
+	*/
+	bool push_back(Value value)
+	{
+		// Check if already exists
+		if(m_map.find(value) != NULL)
+			return false;
+
+		// Add
+		m_map.insert(value, 0);
+		m_list.push_back(value);
+		
+		return true;
+	}
+
+	Value pop_front()
+	{
+		typename core::list<Value>::Iterator i = m_list.begin();
+		Value value = *i;
+		m_map.remove(value);
+		m_list.erase(i);
+		return value;
+	}
+
+	u32 size()
+	{
+		assert(m_list.size() == m_map.size());
+		return m_list.size();
+	}
+
+private:
+	core::map<Value, u8> m_map;
+	core::list<Value> m_list;
+};
+
+#if 1
+template<typename Key, typename Value>
+class MutexedMap
+{
+public:
+	MutexedMap()
+	{
+		m_mutex.Init();
+		assert(m_mutex.IsInitialized());
+	}
+	
+	void set(const Key &name, const Value &value)
+	{
+		JMutexAutoLock lock(m_mutex);
+
+		m_values[name] = value;
+	}
+	
+	bool get(const Key &name, Value *result)
+	{
+		JMutexAutoLock lock(m_mutex);
+
+		typename core::map<Key, Value>::Node *n;
+		n = m_values.find(name);
+
+		if(n == NULL)
+			return false;
+		
+		if(result != NULL)
+			*result = n->getValue();
+			
+		return true;
+	}
+
+private:
+	core::map<Key, Value> m_values;
+	JMutex m_mutex;
+};
+#endif
+
+/*
+	Generates ids for comparable values.
+	Id=0 is reserved for "no value".
+
+	Is fast at:
+	- Returning value by id (very fast)
+	- Returning id by value
+	- Generating a new id for a value
+
+	Is not able to:
+	- Remove an id/value pair (is possible to implement but slow)
+*/
+template<typename T>
+class MutexedIdGenerator
+{
+public:
+	MutexedIdGenerator()
+	{
+		m_mutex.Init();
+		assert(m_mutex.IsInitialized());
+	}
+	
+	// Returns true if found
+	bool getValue(u32 id, T &value)
+	{
+		if(id == 0)
+			return false;
+		JMutexAutoLock lock(m_mutex);
+		if(m_id_to_value.size() < id)
+			return false;
+		value = m_id_to_value[id-1];
+		return true;
+	}
+	
+	// If id exists for value, returns the id.
+	// Otherwise generates an id for the value.
+	u32 getId(const T &value)
+	{
+		JMutexAutoLock lock(m_mutex);
+		typename core::map<T, u32>::Node *n;
+		n = m_value_to_id.find(value);
+		if(n != NULL)
+			return n->getValue();
+		m_id_to_value.push_back(value);
+		u32 new_id = m_id_to_value.size();
+		m_value_to_id.insert(value, new_id);
+		return new_id;
+	}
+
+private:
+	JMutex m_mutex;
+	// Values are stored here at id-1 position (id 1 = [0])
+	core::array<T> m_id_to_value;
+	core::map<T, u32> m_value_to_id;
+};
+
+/*
+	FIFO queue (well, actually a FILO also)
+*/
+template<typename T>
+class Queue
+{
+public:
+	void push_back(T t)
+	{
+		m_list.push_back(t);
+	}
+	
+	T pop_front()
+	{
+		if(m_list.size() == 0)
+			throw ItemNotFoundException("Queue: queue is empty");
+
+		typename core::list<T>::Iterator begin = m_list.begin();
+		T t = *begin;
+		m_list.erase(begin);
+		return t;
+	}
+	T pop_back()
+	{
+		if(m_list.size() == 0)
+			throw ItemNotFoundException("Queue: queue is empty");
+
+		typename core::list<T>::Iterator last = m_list.getLast();
+		T t = *last;
+		m_list.erase(last);
+		return t;
+	}
+
+	u32 size()
+	{
+		return m_list.size();
+	}
+
+protected:
+	core::list<T> m_list;
+};
+
+/*
+	Thread-safe FIFO queue (well, actually a FILO also)
+*/
+
+template<typename T>
+class MutexedQueue
+{
+public:
+	MutexedQueue()
+	{
+		m_mutex.Init();
+	}
+	u32 size()
+	{
+		JMutexAutoLock lock(m_mutex);
+		return m_list.size();
+	}
+	void push_back(T t)
+	{
+		JMutexAutoLock lock(m_mutex);
+		m_list.push_back(t);
+	}
+	T pop_front(u32 wait_time_max_ms=0)
+	{
+		u32 wait_time_ms = 0;
+
+		for(;;)
+		{
+			{
+				JMutexAutoLock lock(m_mutex);
+
+				if(m_list.size() > 0)
+				{
+					typename core::list<T>::Iterator begin = m_list.begin();
+					T t = *begin;
+					m_list.erase(begin);
+					return t;
+				}
+
+				if(wait_time_ms >= wait_time_max_ms)
+					throw ItemNotFoundException("MutexedQueue: queue is empty");
+			}
+
+			// Wait a while before trying again
+			sleep_ms(10);
+			wait_time_ms += 10;
+		}
+	}
+	T pop_back(u32 wait_time_max_ms=0)
+	{
+		u32 wait_time_ms = 0;
+
+		for(;;)
+		{
+			{
+				JMutexAutoLock lock(m_mutex);
+
+				if(m_list.size() > 0)
+				{
+					typename core::list<T>::Iterator last = m_list.getLast();
+					T t = *last;
+					m_list.erase(last);
+					return t;
+				}
+
+				if(wait_time_ms >= wait_time_max_ms)
+					throw ItemNotFoundException("MutexedQueue: queue is empty");
+			}
+
+			// Wait a while before trying again
+			sleep_ms(10);
+			wait_time_ms += 10;
+		}
+	}
+
+	JMutex & getMutex()
+	{
+		return m_mutex;
+	}
+
+	core::list<T> & getList()
+	{
+		return m_list;
+	}
+
+protected:
+	JMutex m_mutex;
+	core::list<T> m_list;
+};
+
+#endif
+
diff --git a/src/util/directiontables.cpp b/src/util/directiontables.cpp
new file mode 100644
index 000000000..a5d2faa7c
--- /dev/null
+++ b/src/util/directiontables.cpp
@@ -0,0 +1,101 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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 "directiontables.h"
+
+const v3s16 g_6dirs[6] =
+{
+	// +right, +top, +back
+	v3s16( 0, 0, 1), // back
+	v3s16( 0, 1, 0), // top
+	v3s16( 1, 0, 0), // right
+	v3s16( 0, 0,-1), // front
+	v3s16( 0,-1, 0), // bottom
+	v3s16(-1, 0, 0) // left
+};
+
+const v3s16 g_26dirs[26] =
+{
+	// +right, +top, +back
+	v3s16( 0, 0, 1), // back
+	v3s16( 0, 1, 0), // top
+	v3s16( 1, 0, 0), // right
+	v3s16( 0, 0,-1), // front
+	v3s16( 0,-1, 0), // bottom
+	v3s16(-1, 0, 0), // left
+	// 6
+	v3s16(-1, 1, 0), // top left
+	v3s16( 1, 1, 0), // top right
+	v3s16( 0, 1, 1), // top back
+	v3s16( 0, 1,-1), // top front
+	v3s16(-1, 0, 1), // back left
+	v3s16( 1, 0, 1), // back right
+	v3s16(-1, 0,-1), // front left
+	v3s16( 1, 0,-1), // front right
+	v3s16(-1,-1, 0), // bottom left
+	v3s16( 1,-1, 0), // bottom right
+	v3s16( 0,-1, 1), // bottom back
+	v3s16( 0,-1,-1), // bottom front
+	// 18
+	v3s16(-1, 1, 1), // top back-left
+	v3s16( 1, 1, 1), // top back-right
+	v3s16(-1, 1,-1), // top front-left
+	v3s16( 1, 1,-1), // top front-right
+	v3s16(-1,-1, 1), // bottom back-left
+	v3s16( 1,-1, 1), // bottom back-right
+	v3s16(-1,-1,-1), // bottom front-left
+	v3s16( 1,-1,-1), // bottom front-right
+	// 26
+};
+
+const v3s16 g_27dirs[27] =
+{
+	// +right, +top, +back
+	v3s16( 0, 0, 1), // back
+	v3s16( 0, 1, 0), // top
+	v3s16( 1, 0, 0), // right
+	v3s16( 0, 0,-1), // front
+	v3s16( 0,-1, 0), // bottom
+	v3s16(-1, 0, 0), // left
+	// 6
+	v3s16(-1, 1, 0), // top left
+	v3s16( 1, 1, 0), // top right
+	v3s16( 0, 1, 1), // top back
+	v3s16( 0, 1,-1), // top front
+	v3s16(-1, 0, 1), // back left
+	v3s16( 1, 0, 1), // back right
+	v3s16(-1, 0,-1), // front left
+	v3s16( 1, 0,-1), // front right
+	v3s16(-1,-1, 0), // bottom left
+	v3s16( 1,-1, 0), // bottom right
+	v3s16( 0,-1, 1), // bottom back
+	v3s16( 0,-1,-1), // bottom front
+	// 18
+	v3s16(-1, 1, 1), // top back-left
+	v3s16( 1, 1, 1), // top back-right
+	v3s16(-1, 1,-1), // top front-left
+	v3s16( 1, 1,-1), // top front-right
+	v3s16(-1,-1, 1), // bottom back-left
+	v3s16( 1,-1, 1), // bottom back-right
+	v3s16(-1,-1,-1), // bottom front-left
+	v3s16( 1,-1,-1), // bottom front-right
+	// 26
+	v3s16(0,0,0),
+};
+
diff --git a/src/util/directiontables.h b/src/util/directiontables.h
new file mode 100644
index 000000000..c02b3d124
--- /dev/null
+++ b/src/util/directiontables.h
@@ -0,0 +1,33 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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.
+*/
+
+#ifndef UTIL_DIRECTIONTABLES_HEADER
+#define UTIL_DIRECTIONTABLES_HEADER
+
+#include "../irrlichttypes.h"
+
+extern const v3s16 g_6dirs[6];
+
+extern const v3s16 g_26dirs[26];
+
+// 26th is (0,0,0)
+extern const v3s16 g_27dirs[27];
+
+#endif
+
diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp
new file mode 100644
index 000000000..d082cdb76
--- /dev/null
+++ b/src/util/numeric.cpp
@@ -0,0 +1,202 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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 "numeric.h"
+
+#include "log.h"
+#include "constants.h" // BS, MAP_BLOCKSIZE
+#include <iostream>
+
+// Calculate the borders of a "d-radius" cube
+void getFacePositions(core::list<v3s16> &list, u16 d)
+{
+	if(d == 0)
+	{
+		list.push_back(v3s16(0,0,0));
+		return;
+	}
+	if(d == 1)
+	{
+		/*
+			This is an optimized sequence of coordinates.
+		*/
+		list.push_back(v3s16( 0, 1, 0)); // top
+		list.push_back(v3s16( 0, 0, 1)); // back
+		list.push_back(v3s16(-1, 0, 0)); // left
+		list.push_back(v3s16( 1, 0, 0)); // right
+		list.push_back(v3s16( 0, 0,-1)); // front
+		list.push_back(v3s16( 0,-1, 0)); // bottom
+		// 6
+		list.push_back(v3s16(-1, 0, 1)); // back left
+		list.push_back(v3s16( 1, 0, 1)); // back right
+		list.push_back(v3s16(-1, 0,-1)); // front left
+		list.push_back(v3s16( 1, 0,-1)); // front right
+		list.push_back(v3s16(-1,-1, 0)); // bottom left
+		list.push_back(v3s16( 1,-1, 0)); // bottom right
+		list.push_back(v3s16( 0,-1, 1)); // bottom back
+		list.push_back(v3s16( 0,-1,-1)); // bottom front
+		list.push_back(v3s16(-1, 1, 0)); // top left
+		list.push_back(v3s16( 1, 1, 0)); // top right
+		list.push_back(v3s16( 0, 1, 1)); // top back
+		list.push_back(v3s16( 0, 1,-1)); // top front
+		// 18
+		list.push_back(v3s16(-1, 1, 1)); // top back-left
+		list.push_back(v3s16( 1, 1, 1)); // top back-right
+		list.push_back(v3s16(-1, 1,-1)); // top front-left
+		list.push_back(v3s16( 1, 1,-1)); // top front-right
+		list.push_back(v3s16(-1,-1, 1)); // bottom back-left
+		list.push_back(v3s16( 1,-1, 1)); // bottom back-right
+		list.push_back(v3s16(-1,-1,-1)); // bottom front-left
+		list.push_back(v3s16( 1,-1,-1)); // bottom front-right
+		// 26
+		return;
+	}
+
+	// Take blocks in all sides, starting from y=0 and going +-y
+	for(s16 y=0; y<=d-1; y++)
+	{
+		// Left and right side, including borders
+		for(s16 z=-d; z<=d; z++)
+		{
+			list.push_back(v3s16(d,y,z));
+			list.push_back(v3s16(-d,y,z));
+			if(y != 0)
+			{
+				list.push_back(v3s16(d,-y,z));
+				list.push_back(v3s16(-d,-y,z));
+			}
+		}
+		// Back and front side, excluding borders
+		for(s16 x=-d+1; x<=d-1; x++)
+		{
+			list.push_back(v3s16(x,y,d));
+			list.push_back(v3s16(x,y,-d));
+			if(y != 0)
+			{
+				list.push_back(v3s16(x,-y,d));
+				list.push_back(v3s16(x,-y,-d));
+			}
+		}
+	}
+
+	// Take the bottom and top face with borders
+	// -d<x<d, y=+-d, -d<z<d
+	for(s16 x=-d; x<=d; x++)
+	for(s16 z=-d; z<=d; z++)
+	{
+		list.push_back(v3s16(x,-d,z));
+		list.push_back(v3s16(x,d,z));
+	}
+}
+
+/*
+    myrand
+*/
+
+static unsigned long next = 1;
+
+/* RAND_MAX assumed to be 32767 */
+int myrand(void)
+{
+   next = next * 1103515245 + 12345;
+   return((unsigned)(next/65536) % 32768);
+}
+
+void mysrand(unsigned seed)
+{
+   next = seed;
+}
+
+int myrand_range(int min, int max)
+{
+	if(max-min > MYRAND_MAX)
+	{
+		errorstream<<"WARNING: myrand_range: max-min > MYRAND_MAX"<<std::endl;
+        max = min + MYRAND_MAX;
+	}
+	if(min > max)
+	{
+		errorstream<<"WARNING: myrand_range: min > max"<<std::endl;
+		return max;
+	}
+	return (myrand()%(max-min+1))+min;
+}
+
+/*
+	blockpos: position of block in block coordinates
+	camera_pos: position of camera in nodes
+	camera_dir: an unit vector pointing to camera direction
+	range: viewing range
+*/
+bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
+		f32 camera_fov, f32 range, f32 *distance_ptr)
+{
+	v3s16 blockpos_nodes = blockpos_b * MAP_BLOCKSIZE;
+	
+	// Block center position
+	v3f blockpos(
+			((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
+			((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
+			((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
+	);
+
+	// Block position relative to camera
+	v3f blockpos_relative = blockpos - camera_pos;
+
+	// Distance in camera direction (+=front, -=back)
+	f32 dforward = blockpos_relative.dotProduct(camera_dir);
+
+	// Total distance
+	f32 d = blockpos_relative.getLength();
+
+	if(distance_ptr)
+		*distance_ptr = d;
+	
+	// If block is very close, it is always in sight
+	if(d < 1.44*1.44*MAP_BLOCKSIZE*BS/2)
+		return true;
+
+	// If block is far away, it's not in sight
+	if(d > range)
+		return false;
+
+	// Maximum radius of a block
+	f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
+	
+	// If block is (nearly) touching the camera, don't
+	// bother validating further (that is, render it anyway)
+	if(d < block_max_radius)
+		return true;
+	
+	// Cosine of the angle between the camera direction
+	// and the block direction (camera_dir is an unit vector)
+	f32 cosangle = dforward / d;
+	
+	// Compensate for the size of the block
+	// (as the block has to be shown even if it's a bit off FOV)
+	// This is an estimate, plus an arbitary factor
+	cosangle += block_max_radius / d * 0.5;
+
+	// If block is not in the field of view, skip it
+	if(cosangle < cos(camera_fov / 2))
+		return false;
+
+	return true;
+}
+
diff --git a/src/util/numeric.h b/src/util/numeric.h
new file mode 100644
index 000000000..0ce21b7e3
--- /dev/null
+++ b/src/util/numeric.h
@@ -0,0 +1,331 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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.
+*/
+
+#ifndef UTIL_NUMERIC_HEADER
+#define UTIL_NUMERIC_HEADER
+
+#include "../irrlichttypes.h"
+
+// Calculate the borders of a "d-radius" cube
+void getFacePositions(core::list<v3s16> &list, u16 d);
+
+class IndentationRaiser
+{
+public:
+	IndentationRaiser(u16 *indentation)
+	{
+		m_indentation = indentation;
+		(*m_indentation)++;
+	}
+	~IndentationRaiser()
+	{
+		(*m_indentation)--;
+	}
+private:
+	u16 *m_indentation;
+};
+
+inline s16 getContainerPos(s16 p, s16 d)
+{
+	return (p>=0 ? p : p-d+1) / d;
+}
+
+inline v2s16 getContainerPos(v2s16 p, s16 d)
+{
+	return v2s16(
+		getContainerPos(p.X, d),
+		getContainerPos(p.Y, d)
+	);
+}
+
+inline v3s16 getContainerPos(v3s16 p, s16 d)
+{
+	return v3s16(
+		getContainerPos(p.X, d),
+		getContainerPos(p.Y, d),
+		getContainerPos(p.Z, d)
+	);
+}
+
+inline v2s16 getContainerPos(v2s16 p, v2s16 d)
+{
+	return v2s16(
+		getContainerPos(p.X, d.X),
+		getContainerPos(p.Y, d.Y)
+	);
+}
+
+inline v3s16 getContainerPos(v3s16 p, v3s16 d)
+{
+	return v3s16(
+		getContainerPos(p.X, d.X),
+		getContainerPos(p.Y, d.Y),
+		getContainerPos(p.Z, d.Z)
+	);
+}
+
+inline bool isInArea(v3s16 p, s16 d)
+{
+	return (
+		p.X >= 0 && p.X < d &&
+		p.Y >= 0 && p.Y < d &&
+		p.Z >= 0 && p.Z < d
+	);
+}
+
+inline bool isInArea(v2s16 p, s16 d)
+{
+	return (
+		p.X >= 0 && p.X < d &&
+		p.Y >= 0 && p.Y < d
+	);
+}
+
+inline bool isInArea(v3s16 p, v3s16 d)
+{
+	return (
+		p.X >= 0 && p.X < d.X &&
+		p.Y >= 0 && p.Y < d.Y &&
+		p.Z >= 0 && p.Z < d.Z
+	);
+}
+
+inline s16 rangelim(s16 i, s16 max)
+{
+	if(i < 0)
+		return 0;
+	if(i > max)
+		return max;
+	return i;
+}
+
+#define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d)))
+
+inline v3s16 arealim(v3s16 p, s16 d)
+{
+	if(p.X < 0)
+		p.X = 0;
+	if(p.Y < 0)
+		p.Y = 0;
+	if(p.Z < 0)
+		p.Z = 0;
+	if(p.X > d-1)
+		p.X = d-1;
+	if(p.Y > d-1)
+		p.Y = d-1;
+	if(p.Z > d-1)
+		p.Z = d-1;
+	return p;
+}
+
+
+/*
+	See test.cpp for example cases.
+	wraps degrees to the range of -360...360
+	NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
+*/
+inline float wrapDegrees(float f)
+{
+	// Take examples of f=10, f=720.5, f=-0.5, f=-360.5
+	// This results in
+	// 10, 720, -1, -361
+	int i = floor(f);
+	// 0, 2, 0, -1
+	int l = i / 360;
+	// NOTE: This would be used for wrapping to 0...360
+	// 0, 2, -1, -2
+	/*if(i < 0)
+		l -= 1;*/
+	// 0, 720, 0, -360
+	int k = l * 360;
+	// 10, 0.5, -0.5, -0.5
+	f -= float(k);
+	return f;
+}
+
+/* Wrap to 0...360 */
+inline float wrapDegrees_0_360(float f)
+{
+	// Take examples of f=10, f=720.5, f=-0.5, f=-360.5
+	// This results in
+	// 10, 720, -1, -361
+	int i = floor(f);
+	// 0, 2, 0, -1
+	int l = i / 360;
+	// Wrap to 0...360
+	// 0, 2, -1, -2
+	if(i < 0)
+		l -= 1;
+	// 0, 720, 0, -360
+	int k = l * 360;
+	// 10, 0.5, -0.5, -0.5
+	f -= float(k);
+	return f;
+}
+
+/* Wrap to -180...180 */
+inline float wrapDegrees_180(float f)
+{
+	f += 180;
+	f = wrapDegrees_0_360(f);
+	f -= 180;
+	return f;
+}
+
+/*
+	Pseudo-random (VC++ rand() sucks)
+*/
+int myrand(void);
+void mysrand(unsigned seed);
+#define MYRAND_MAX 32767
+
+int myrand_range(int min, int max);
+
+/*
+	Miscellaneous functions
+*/
+
+bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
+		f32 camera_fov, f32 range, f32 *distance_ptr=NULL);
+
+/*
+	Some helper stuff
+*/
+#define MYMIN(a,b) ((a)<(b)?(a):(b))
+#define MYMAX(a,b) ((a)>(b)?(a):(b))
+
+/*
+	Returns nearest 32-bit integer for given floating point number.
+	<cmath> and <math.h> in VC++ don't provide round().
+*/
+inline s32 myround(f32 f)
+{
+	return floor(f + 0.5);
+}
+
+/*
+	Returns integer position of node in given floating point position
+*/
+inline v3s16 floatToInt(v3f p, f32 d)
+{
+	v3s16 p2(
+		(p.X + (p.X>0 ? d/2 : -d/2))/d,
+		(p.Y + (p.Y>0 ? d/2 : -d/2))/d,
+		(p.Z + (p.Z>0 ? d/2 : -d/2))/d);
+	return p2;
+}
+
+/*
+	Returns floating point position of node in given integer position
+*/
+inline v3f intToFloat(v3s16 p, f32 d)
+{
+	v3f p2(
+		(f32)p.X * d,
+		(f32)p.Y * d,
+		(f32)p.Z * d
+	);
+	return p2;
+}
+
+// Random helper. Usually d=BS
+inline core::aabbox3d<f32> getNodeBox(v3s16 p, float d)
+{
+	return core::aabbox3d<f32>(
+		(float)p.X * d - 0.5*d,
+		(float)p.Y * d - 0.5*d,
+		(float)p.Z * d - 0.5*d,
+		(float)p.X * d + 0.5*d,
+		(float)p.Y * d + 0.5*d,
+		(float)p.Z * d + 0.5*d
+	);
+}
+
+class IntervalLimiter
+{
+public:
+	IntervalLimiter():
+		m_accumulator(0)
+	{
+	}
+	/*
+		dtime: time from last call to this method
+		wanted_interval: interval wanted
+		return value:
+			true: action should be skipped
+			false: action should be done
+	*/
+	bool step(float dtime, float wanted_interval)
+	{
+		m_accumulator += dtime;
+		if(m_accumulator < wanted_interval)
+			return false;
+		m_accumulator -= wanted_interval;
+		return true;
+	}
+protected:
+	float m_accumulator;
+};
+
+/*
+	Splits a list into "pages". For example, the list [1,2,3,4,5] split
+	into two pages would be [1,2,3],[4,5]. This function computes the
+	minimum and maximum indices of a single page.
+
+	length: Length of the list that should be split
+	page: Page number, 1 <= page <= pagecount
+	pagecount: The number of pages, >= 1
+	minindex: Receives the minimum index (inclusive).
+	maxindex: Receives the maximum index (exclusive).
+
+	Ensures 0 <= minindex <= maxindex <= length.
+*/
+inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxindex)
+{
+	if(length < 1 || pagecount < 1 || page < 1 || page > pagecount)
+	{
+		// Special cases or invalid parameters
+		minindex = maxindex = 0;
+	}
+	else if(pagecount <= length)
+	{
+		// Less pages than entries in the list:
+		// Each page contains at least one entry
+		minindex = (length * (page-1) + (pagecount-1)) / pagecount;
+		maxindex = (length * page + (pagecount-1)) / pagecount;
+	}
+	else
+	{
+		// More pages than entries in the list:
+		// Make sure the empty pages are at the end
+		if(page < length)
+		{
+			minindex = page-1;
+			maxindex = page;
+		}
+		else
+		{
+			minindex = 0;
+			maxindex = 0;
+		}
+	}
+}
+
+#endif
+
diff --git a/src/util/pointedthing.cpp b/src/util/pointedthing.cpp
new file mode 100644
index 000000000..d1be2d6b6
--- /dev/null
+++ b/src/util/pointedthing.cpp
@@ -0,0 +1,125 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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 "pointedthing.h"
+
+#include "serialize.h"
+#include <sstream>
+
+PointedThing::PointedThing():
+	type(POINTEDTHING_NOTHING),
+	node_undersurface(0,0,0),
+	node_abovesurface(0,0,0),
+	object_id(-1)
+{}
+
+std::string PointedThing::dump() const
+{
+	std::ostringstream os(std::ios::binary);
+	if(type == POINTEDTHING_NOTHING)
+	{
+		os<<"[nothing]";
+	}
+	else if(type == POINTEDTHING_NODE)
+	{
+		const v3s16 &u = node_undersurface;
+		const v3s16 &a = node_abovesurface;
+		os<<"[node under="<<u.X<<","<<u.Y<<","<<u.Z
+			<< " above="<<a.X<<","<<a.Y<<","<<a.Z<<"]";
+	}
+	else if(type == POINTEDTHING_OBJECT)
+	{
+		os<<"[object "<<object_id<<"]";
+	}
+	else
+	{
+		os<<"[unknown PointedThing]";
+	}
+	return os.str();
+}
+
+void PointedThing::serialize(std::ostream &os) const
+{
+	writeU8(os, 0); // version
+	writeU8(os, (u8)type);
+	if(type == POINTEDTHING_NOTHING)
+	{
+		// nothing
+	}
+	else if(type == POINTEDTHING_NODE)
+	{
+		writeV3S16(os, node_undersurface);
+		writeV3S16(os, node_abovesurface);
+	}
+	else if(type == POINTEDTHING_OBJECT)
+	{
+		writeS16(os, object_id);
+	}
+}
+
+void PointedThing::deSerialize(std::istream &is)
+{
+	int version = readU8(is);
+	if(version != 0) throw SerializationError(
+			"unsupported PointedThing version");
+	type = (PointedThingType) readU8(is);
+	if(type == POINTEDTHING_NOTHING)
+	{
+		// nothing
+	}
+	else if(type == POINTEDTHING_NODE)
+	{
+		node_undersurface = readV3S16(is);
+		node_abovesurface = readV3S16(is);
+	}
+	else if(type == POINTEDTHING_OBJECT)
+	{
+		object_id = readS16(is);
+	}
+	else
+	{
+		throw SerializationError(
+			"unsupported PointedThingType");
+	}
+}
+
+bool PointedThing::operator==(const PointedThing &pt2) const
+{
+	if(type != pt2.type)
+		return false;
+	if(type == POINTEDTHING_NODE)
+	{
+		if(node_undersurface != pt2.node_undersurface)
+			return false;
+		if(node_abovesurface != pt2.node_abovesurface)
+			return false;
+	}
+	else if(type == POINTEDTHING_OBJECT)
+	{
+		if(object_id != pt2.object_id)
+			return false;
+	}
+	return true;
+}
+
+bool PointedThing::operator!=(const PointedThing &pt2) const
+{
+	return !(*this == pt2);
+}
+
diff --git a/src/util/pointedthing.h b/src/util/pointedthing.h
new file mode 100644
index 000000000..82d66dfa8
--- /dev/null
+++ b/src/util/pointedthing.h
@@ -0,0 +1,50 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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.
+*/
+
+#ifndef UTIL_POINTEDTHING_HEADER
+#define UTIL_POINTEDTHING_HEADER
+
+#include "../irrlichttypes.h"
+#include <iostream>
+#include <string>
+
+enum PointedThingType
+{
+	POINTEDTHING_NOTHING,
+	POINTEDTHING_NODE,
+	POINTEDTHING_OBJECT
+};
+
+struct PointedThing
+{
+	PointedThingType type;
+	v3s16 node_undersurface;
+	v3s16 node_abovesurface;
+	s16 object_id;
+
+	PointedThing();
+	std::string dump() const;
+	void serialize(std::ostream &os) const;
+	void deSerialize(std::istream &is);
+	bool operator==(const PointedThing &pt2) const;
+	bool operator!=(const PointedThing &pt2) const;
+};
+
+#endif
+
diff --git a/src/util/pointer.h b/src/util/pointer.h
new file mode 100644
index 000000000..02f11c2ea
--- /dev/null
+++ b/src/util/pointer.h
@@ -0,0 +1,298 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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.
+*/
+
+#ifndef UTIL_POINTER_HEADER
+#define UTIL_POINTER_HEADER
+
+#include "../irrlichttypes.h"
+#include "../debug.h" // For assert()
+
+template <typename T>
+class SharedPtr
+{
+public:
+	SharedPtr(T *t=NULL)
+	{
+		refcount = new int;
+		*refcount = 1;
+		ptr = t;
+	}
+	SharedPtr(SharedPtr<T> &t)
+	{
+		//*this = t;
+		drop();
+		refcount = t.refcount;
+		(*refcount)++;
+		ptr = t.ptr;
+	}
+	~SharedPtr()
+	{
+		drop();
+	}
+	SharedPtr<T> & operator=(T *t)
+	{
+		drop();
+		refcount = new int;
+		*refcount = 1;
+		ptr = t;
+		return *this;
+	}
+	SharedPtr<T> & operator=(SharedPtr<T> &t)
+	{
+		drop();
+		refcount = t.refcount;
+		(*refcount)++;
+		ptr = t.ptr;
+		return *this;
+	}
+	T* operator->()
+	{
+		return ptr;
+	}
+	T & operator*()
+	{
+		return *ptr;
+	}
+	bool operator!=(T *t)
+	{
+		return ptr != t;
+	}
+	bool operator==(T *t)
+	{
+		return ptr == t;
+	}
+	T & operator[](unsigned int i)
+	{
+		return ptr[i];
+	}
+private:
+	void drop()
+	{
+		assert((*refcount) > 0);
+		(*refcount)--;
+		if(*refcount == 0)
+		{
+			delete refcount;
+			if(ptr != NULL)
+				delete ptr;
+		}
+	}
+	T *ptr;
+	int *refcount;
+};
+
+template <typename T>
+class Buffer
+{
+public:
+	Buffer()
+	{
+		m_size = 0;
+		data = NULL;
+	}
+	Buffer(unsigned int size)
+	{
+		m_size = size;
+		if(size != 0)
+			data = new T[size];
+		else
+			data = NULL;
+	}
+	Buffer(const Buffer &buffer)
+	{
+		m_size = buffer.m_size;
+		if(m_size != 0)
+		{
+			data = new T[buffer.m_size];
+			memcpy(data, buffer.data, buffer.m_size);
+		}
+		else
+			data = NULL;
+	}
+	Buffer(const T *t, unsigned int size)
+	{
+		m_size = size;
+		if(size != 0)
+		{
+			data = new T[size];
+			memcpy(data, t, size);
+		}
+		else
+			data = NULL;
+	}
+	~Buffer()
+	{
+		drop();
+	}
+	Buffer& operator=(const Buffer &buffer)
+	{
+		if(this == &buffer)
+			return *this;
+		drop();
+		m_size = buffer.m_size;
+		if(m_size != 0)
+		{
+			data = new T[buffer.m_size];
+			memcpy(data, buffer.data, buffer.m_size);
+		}
+		else
+			data = NULL;
+		return *this;
+	}
+	T & operator[](unsigned int i) const
+	{
+		return data[i];
+	}
+	T * operator*() const
+	{
+		return data;
+	}
+	unsigned int getSize() const
+	{
+		return m_size;
+	}
+private:
+	void drop()
+	{
+		if(data)
+			delete[] data;
+	}
+	T *data;
+	unsigned int m_size;
+};
+
+template <typename T>
+class SharedBuffer
+{
+public:
+	SharedBuffer()
+	{
+		m_size = 0;
+		data = NULL;
+		refcount = new unsigned int;
+		(*refcount) = 1;
+	}
+	SharedBuffer(unsigned int size)
+	{
+		m_size = size;
+		if(m_size != 0)
+			data = new T[m_size];
+		else
+			data = NULL;
+		refcount = new unsigned int;
+		(*refcount) = 1;
+	}
+	SharedBuffer(const SharedBuffer &buffer)
+	{
+		//std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
+		m_size = buffer.m_size;
+		data = buffer.data;
+		refcount = buffer.refcount;
+		(*refcount)++;
+	}
+	SharedBuffer & operator=(const SharedBuffer & buffer)
+	{
+		//std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
+		if(this == &buffer)
+			return *this;
+		drop();
+		m_size = buffer.m_size;
+		data = buffer.data;
+		refcount = buffer.refcount;
+		(*refcount)++;
+		return *this;
+	}
+	/*
+		Copies whole buffer
+	*/
+	SharedBuffer(T *t, unsigned int size)
+	{
+		m_size = size;
+		if(m_size != 0)
+		{
+			data = new T[m_size];
+			memcpy(data, t, m_size);
+		}
+		else
+			data = NULL;
+		refcount = new unsigned int;
+		(*refcount) = 1;
+	}
+	/*
+		Copies whole buffer
+	*/
+	SharedBuffer(const Buffer<T> &buffer)
+	{
+		m_size = buffer.getSize();
+		if(m_size != 0)
+		{
+			data = new T[m_size];
+			memcpy(data, *buffer, buffer.getSize());
+		}
+		else
+			data = NULL;
+		refcount = new unsigned int;
+		(*refcount) = 1;
+	}
+	~SharedBuffer()
+	{
+		drop();
+	}
+	T & operator[](unsigned int i) const
+	{
+		//assert(i < m_size)
+		return data[i];
+	}
+	T * operator*() const
+	{
+		return data;
+	}
+	unsigned int getSize() const
+	{
+		return m_size;
+	}
+	operator Buffer<T>() const
+	{
+		return Buffer<T>(data, m_size);
+	}
+private:
+	void drop()
+	{
+		assert((*refcount) > 0);
+		(*refcount)--;
+		if(*refcount == 0)
+		{
+			if(data)
+				delete[] data;
+			delete refcount;
+		}
+	}
+	T *data;
+	unsigned int m_size;
+	unsigned int *refcount;
+};
+
+inline SharedBuffer<u8> SharedBufferFromString(const char *string)
+{
+	SharedBuffer<u8> b((u8*)string, strlen(string)+1);
+	return b;
+}
+
+#endif
+
diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp
new file mode 100644
index 000000000..16825b677
--- /dev/null
+++ b/src/util/serialize.cpp
@@ -0,0 +1,119 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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 "serialize.h"
+
+#include <sstream>
+#include <iomanip>
+
+// Creates a string encoded in JSON format (almost equivalent to a C string literal)
+std::string serializeJsonString(const std::string &plain)
+{
+	std::ostringstream os(std::ios::binary);
+	os<<"\"";
+	for(size_t i = 0; i < plain.size(); i++)
+	{
+		char c = plain[i];
+		switch(c)
+		{
+			case '"': os<<"\\\""; break;
+			case '\\': os<<"\\\\"; break;
+			case '/': os<<"\\/"; break;
+			case '\b': os<<"\\b"; break;
+			case '\f': os<<"\\f"; break;
+			case '\n': os<<"\\n"; break;
+			case '\r': os<<"\\r"; break;
+			case '\t': os<<"\\t"; break;
+			default:
+			{
+				if(c >= 32 && c <= 126)
+				{
+					os<<c;
+				}
+				else
+				{
+					u32 cnum = (u32) (u8) c;
+					os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum;
+				}
+				break;
+			}
+		}
+	}
+	os<<"\"";
+	return os.str();
+}
+
+// Reads a string encoded in JSON format
+std::string deSerializeJsonString(std::istream &is)
+{
+	std::ostringstream os(std::ios::binary);
+	char c, c2;
+
+	// Parse initial doublequote
+	is >> c;
+	if(c != '"')
+		throw SerializationError("JSON string must start with doublequote");
+
+	// Parse characters
+	for(;;)
+	{
+		c = is.get();
+		if(is.eof())
+			throw SerializationError("JSON string ended prematurely");
+		if(c == '"')
+		{
+			return os.str();
+		}
+		else if(c == '\\')
+		{
+			c2 = is.get();
+			if(is.eof())
+				throw SerializationError("JSON string ended prematurely");
+			switch(c2)
+			{
+				default:  os<<c2; break;
+				case 'b': os<<'\b'; break;
+				case 'f': os<<'\f'; break;
+				case 'n': os<<'\n'; break;
+				case 'r': os<<'\r'; break;
+				case 't': os<<'\t'; break;
+				case 'u':
+				{
+					char hexdigits[4+1];
+					is.read(hexdigits, 4);
+					if(is.eof())
+						throw SerializationError("JSON string ended prematurely");
+					hexdigits[4] = 0;
+					std::istringstream tmp_is(hexdigits, std::ios::binary);
+					int hexnumber;
+					tmp_is >> std::hex >> hexnumber;
+					os<<((char)hexnumber);
+					break;
+				}
+			}
+		}
+		else
+		{
+			os<<c;
+		}
+	}
+	return os.str();
+}
+
+
diff --git a/src/util/serialize.h b/src/util/serialize.h
new file mode 100644
index 000000000..e229a00be
--- /dev/null
+++ b/src/util/serialize.h
@@ -0,0 +1,456 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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.
+*/
+
+#ifndef UTIL_SERIALIZE_HEADER
+#define UTIL_SERIALIZE_HEADER
+
+#include "../irrlichttypes.h"
+#include <iostream>
+#include <string>
+#include "../exceptions.h"
+#include "pointer.h"
+
+inline void writeU64(u8 *data, u64 i)
+{
+	data[0] = ((i>>56)&0xff);
+	data[1] = ((i>>48)&0xff);
+	data[2] = ((i>>40)&0xff);
+	data[3] = ((i>>32)&0xff);
+	data[4] = ((i>>24)&0xff);
+	data[5] = ((i>>16)&0xff);
+	data[6] = ((i>> 8)&0xff);
+	data[7] = ((i>> 0)&0xff);
+}
+
+inline void writeU32(u8 *data, u32 i)
+{
+	data[0] = ((i>>24)&0xff);
+	data[1] = ((i>>16)&0xff);
+	data[2] = ((i>> 8)&0xff);
+	data[3] = ((i>> 0)&0xff);
+}
+
+inline void writeU16(u8 *data, u16 i)
+{
+	data[0] = ((i>> 8)&0xff);
+	data[1] = ((i>> 0)&0xff);
+}
+
+inline void writeU8(u8 *data, u8 i)
+{
+	data[0] = ((i>> 0)&0xff);
+}
+
+inline u64 readU64(u8 *data)
+{
+	return ((u64)data[0]<<56) | ((u64)data[1]<<48)
+		| ((u64)data[2]<<40) | ((u64)data[3]<<32)
+		| ((u64)data[4]<<24) | ((u64)data[5]<<16)
+		| ((u64)data[6]<<8) | ((u64)data[7]<<0);
+}
+
+inline u32 readU32(u8 *data)
+{
+	return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
+}
+
+inline u16 readU16(u8 *data)
+{
+	return (data[0]<<8) | (data[1]<<0);
+}
+
+inline u8 readU8(u8 *data)
+{
+	return (data[0]<<0);
+}
+
+inline void writeS32(u8 *data, s32 i){
+	writeU32(data, (u32)i);
+}
+inline s32 readS32(u8 *data){
+	return (s32)readU32(data);
+}
+
+inline void writeS16(u8 *data, s16 i){
+	writeU16(data, (u16)i);
+}
+inline s16 readS16(u8 *data){
+	return (s16)readU16(data);
+}
+
+inline void writeS8(u8 *data, s8 i){
+	writeU8(data, (u8)i);
+}
+inline s8 readS8(u8 *data){
+	return (s8)readU8(data);
+}
+
+inline void writeF1000(u8 *data, f32 i){
+	writeS32(data, i*1000);
+}
+inline f32 readF1000(u8 *data){
+	return (f32)readS32(data)/1000.;
+}
+
+inline void writeV3S32(u8 *data, v3s32 p)
+{
+	writeS32(&data[0], p.X);
+	writeS32(&data[4], p.Y);
+	writeS32(&data[8], p.Z);
+}
+inline v3s32 readV3S32(u8 *data)
+{
+	v3s32 p;
+	p.X = readS32(&data[0]);
+	p.Y = readS32(&data[4]);
+	p.Z = readS32(&data[8]);
+	return p;
+}
+
+inline void writeV3F1000(u8 *data, v3f p)
+{
+	writeF1000(&data[0], p.X);
+	writeF1000(&data[4], p.Y);
+	writeF1000(&data[8], p.Z);
+}
+inline v3f readV3F1000(u8 *data)
+{
+	v3f p;
+	p.X = (float)readF1000(&data[0]);
+	p.Y = (float)readF1000(&data[4]);
+	p.Z = (float)readF1000(&data[8]);
+	return p;
+}
+
+inline void writeV2F1000(u8 *data, v2f p)
+{
+	writeF1000(&data[0], p.X);
+	writeF1000(&data[4], p.Y);
+}
+inline v2f readV2F1000(u8 *data)
+{
+	v2f p;
+	p.X = (float)readF1000(&data[0]);
+	p.Y = (float)readF1000(&data[4]);
+	return p;
+}
+
+inline void writeV2S16(u8 *data, v2s16 p)
+{
+	writeS16(&data[0], p.X);
+	writeS16(&data[2], p.Y);
+}
+
+inline v2s16 readV2S16(u8 *data)
+{
+	v2s16 p;
+	p.X = readS16(&data[0]);
+	p.Y = readS16(&data[2]);
+	return p;
+}
+
+inline void writeV2S32(u8 *data, v2s32 p)
+{
+	writeS32(&data[0], p.X);
+	writeS32(&data[2], p.Y);
+}
+
+inline v2s32 readV2S32(u8 *data)
+{
+	v2s32 p;
+	p.X = readS32(&data[0]);
+	p.Y = readS32(&data[2]);
+	return p;
+}
+
+inline void writeV3S16(u8 *data, v3s16 p)
+{
+	writeS16(&data[0], p.X);
+	writeS16(&data[2], p.Y);
+	writeS16(&data[4], p.Z);
+}
+
+inline v3s16 readV3S16(u8 *data)
+{
+	v3s16 p;
+	p.X = readS16(&data[0]);
+	p.Y = readS16(&data[2]);
+	p.Z = readS16(&data[4]);
+	return p;
+}
+
+/*
+	The above stuff directly interfaced to iostream
+*/
+
+inline void writeU8(std::ostream &os, u8 p)
+{
+	char buf[1] = {0};
+	writeU8((u8*)buf, p);
+	os.write(buf, 1);
+}
+inline u8 readU8(std::istream &is)
+{
+	char buf[1] = {0};
+	is.read(buf, 1);
+	return readU8((u8*)buf);
+}
+
+inline void writeU16(std::ostream &os, u16 p)
+{
+	char buf[2] = {0};
+	writeU16((u8*)buf, p);
+	os.write(buf, 2);
+}
+inline u16 readU16(std::istream &is)
+{
+	char buf[2] = {0};
+	is.read(buf, 2);
+	return readU16((u8*)buf);
+}
+
+inline void writeU32(std::ostream &os, u32 p)
+{
+	char buf[4] = {0};
+	writeU32((u8*)buf, p);
+	os.write(buf, 4);
+}
+inline u32 readU32(std::istream &is)
+{
+	char buf[4] = {0};
+	is.read(buf, 4);
+	return readU32((u8*)buf);
+}
+
+inline void writeS32(std::ostream &os, s32 p)
+{
+	char buf[4] = {0};
+	writeS32((u8*)buf, p);
+	os.write(buf, 4);
+}
+inline s32 readS32(std::istream &is)
+{
+	char buf[4] = {0};
+	is.read(buf, 4);
+	return readS32((u8*)buf);
+}
+
+inline void writeS16(std::ostream &os, s16 p)
+{
+	char buf[2] = {0};
+	writeS16((u8*)buf, p);
+	os.write(buf, 2);
+}
+inline s16 readS16(std::istream &is)
+{
+	char buf[2] = {0};
+	is.read(buf, 2);
+	return readS16((u8*)buf);
+}
+
+inline void writeS8(std::ostream &os, s8 p)
+{
+	char buf[1] = {0};
+	writeS8((u8*)buf, p);
+	os.write(buf, 1);
+}
+inline s8 readS8(std::istream &is)
+{
+	char buf[1] = {0};
+	is.read(buf, 1);
+	return readS8((u8*)buf);
+}
+
+inline void writeF1000(std::ostream &os, f32 p)
+{
+	char buf[4] = {0};
+	writeF1000((u8*)buf, p);
+	os.write(buf, 4);
+}
+inline f32 readF1000(std::istream &is)
+{
+	char buf[4] = {0};
+	is.read(buf, 4);
+	return readF1000((u8*)buf);
+}
+
+inline void writeV3F1000(std::ostream &os, v3f p)
+{
+	char buf[12];
+	writeV3F1000((u8*)buf, p);
+	os.write(buf, 12);
+}
+inline v3f readV3F1000(std::istream &is)
+{
+	char buf[12];
+	is.read(buf, 12);
+	return readV3F1000((u8*)buf);
+}
+
+inline void writeV2F1000(std::ostream &os, v2f p)
+{
+	char buf[8] = {0};
+	writeV2F1000((u8*)buf, p);
+	os.write(buf, 8);
+}
+inline v2f readV2F1000(std::istream &is)
+{
+	char buf[8] = {0};
+	is.read(buf, 8);
+	return readV2F1000((u8*)buf);
+}
+
+inline void writeV2S16(std::ostream &os, v2s16 p)
+{
+	char buf[4] = {0};
+	writeV2S16((u8*)buf, p);
+	os.write(buf, 4);
+}
+inline v2s16 readV2S16(std::istream &is)
+{
+	char buf[4] = {0};
+	is.read(buf, 4);
+	return readV2S16((u8*)buf);
+}
+
+inline void writeV3S16(std::ostream &os, v3s16 p)
+{
+	char buf[6] = {0};
+	writeV3S16((u8*)buf, p);
+	os.write(buf, 6);
+}
+inline v3s16 readV3S16(std::istream &is)
+{
+	char buf[6] = {0};
+	is.read(buf, 6);
+	return readV3S16((u8*)buf);
+}
+
+/*
+	More serialization stuff
+*/
+
+// Creates a string with the length as the first two bytes
+inline std::string serializeString(const std::string &plain)
+{
+	//assert(plain.size() <= 65535);
+	if(plain.size() > 65535)
+		throw SerializationError("String too long for serializeString");
+	char buf[2];
+	writeU16((u8*)&buf[0], plain.size());
+	std::string s;
+	s.append(buf, 2);
+	s.append(plain);
+	return s;
+}
+
+// Creates a string with the length as the first two bytes from wide string
+inline std::string serializeWideString(const std::wstring &plain)
+{
+	//assert(plain.size() <= 65535);
+	if(plain.size() > 65535)
+		throw SerializationError("String too long for serializeString");
+	char buf[2];
+	writeU16((u8*)buf, plain.size());
+	std::string s;
+	s.append(buf, 2);
+	for(u32 i=0; i<plain.size(); i++)
+	{
+		writeU16((u8*)buf, plain[i]);
+		s.append(buf, 2);
+	}
+	return s;
+}
+
+// Reads a string with the length as the first two bytes
+inline std::string deSerializeString(std::istream &is)
+{
+	char buf[2];
+	is.read(buf, 2);
+	if(is.gcount() != 2)
+		throw SerializationError("deSerializeString: size not read");
+	u16 s_size = readU16((u8*)buf);
+	if(s_size == 0)
+		return "";
+	Buffer<char> buf2(s_size);
+	is.read(&buf2[0], s_size);
+	std::string s;
+	s.reserve(s_size);
+	s.append(&buf2[0], s_size);
+	return s;
+}
+
+// Reads a wide string with the length as the first two bytes
+inline std::wstring deSerializeWideString(std::istream &is)
+{
+	char buf[2];
+	is.read(buf, 2);
+	if(is.gcount() != 2)
+		throw SerializationError("deSerializeString: size not read");
+	u16 s_size = readU16((u8*)buf);
+	if(s_size == 0)
+		return L"";
+	std::wstring s;
+	s.reserve(s_size);
+	for(u32 i=0; i<s_size; i++)
+	{
+		is.read(&buf[0], 2);
+		wchar_t c16 = readU16((u8*)buf);
+		s.append(&c16, 1);
+	}
+	return s;
+}
+
+// Creates a string with the length as the first four bytes
+inline std::string serializeLongString(const std::string &plain)
+{
+	char buf[4];
+	writeU32((u8*)&buf[0], plain.size());
+	std::string s;
+	s.append(buf, 4);
+	s.append(plain);
+	return s;
+}
+
+// Reads a string with the length as the first four bytes
+inline std::string deSerializeLongString(std::istream &is)
+{
+	char buf[4];
+	is.read(buf, 4);
+	if(is.gcount() != 4)
+		throw SerializationError("deSerializeLongString: size not read");
+	u32 s_size = readU32((u8*)buf);
+	if(s_size == 0)
+		return "";
+	Buffer<char> buf2(s_size);
+	is.read(&buf2[0], s_size);
+	std::string s;
+	s.reserve(s_size);
+	s.append(&buf2[0], s_size);
+	return s;
+}
+
+// Creates a string encoded in JSON format (almost equivalent to a C string literal)
+std::string serializeJsonString(const std::string &plain);
+
+// Reads a string encoded in JSON format
+std::string deSerializeJsonString(std::istream &is);
+
+#endif
+
diff --git a/src/util/string.cpp b/src/util/string.cpp
new file mode 100644
index 000000000..ee4df849e
--- /dev/null
+++ b/src/util/string.cpp
@@ -0,0 +1,43 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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 "string.h"
+
+#include "sha1.h"
+#include "base64.h"
+
+// Get an sha-1 hash of the player's name combined with
+// the password entered. That's what the server uses as
+// their password. (Exception : if the password field is
+// blank, we send a blank password - this is for backwards
+// compatibility with password-less players).
+std::string translatePassword(std::string playername, std::wstring password)
+{
+	if(password.length() == 0)
+		return "";
+
+	std::string slt = playername + wide_to_narrow(password);
+	SHA1 sha1;
+	sha1.addBytes(slt.c_str(), slt.length());
+	unsigned char *digest = sha1.getDigest();
+	std::string pwd = base64_encode(digest, 20);
+	free(digest);
+	return pwd;
+}
+
diff --git a/src/util/string.h b/src/util/string.h
new file mode 100644
index 000000000..97b07f2ff
--- /dev/null
+++ b/src/util/string.h
@@ -0,0 +1,264 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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.
+*/
+
+#ifndef UTIL_STRING_HEADER
+#define UTIL_STRING_HEADER
+
+#include "../irrlichttypes.h"
+#include "../strfnd.h" // For trim()
+#include "pointer.h"
+#include <string>
+#include <cstring>
+#include <vector>
+#include <sstream>
+
+static inline std::string padStringRight(std::string s, size_t len)
+{
+	if(len > s.size())
+		s.insert(s.end(), len - s.size(), ' ');
+	return s;
+}
+
+// ends: NULL- or ""-terminated array of strings
+// Returns "" if no end could be removed.
+static inline std::string removeStringEnd(const std::string &s, const char *ends[])
+{
+	const char **p = ends;
+	for(; (*p) && (*p)[0] != '\0'; p++){
+		std::string end = *p;
+		if(s.size() < end.size())
+			continue;
+		if(s.substr(s.size()-end.size(), end.size()) == end)
+			return s.substr(0, s.size() - end.size());
+	}
+	return "";
+}
+
+// Tests if two strings are equal, optionally case insensitive
+inline bool str_equal(const std::wstring& s1, const std::wstring& s2,
+		bool case_insensitive = false)
+{
+	if(case_insensitive)
+	{
+		if(s1.size() != s2.size())
+			return false;
+		for(size_t i = 0; i < s1.size(); ++i)
+			if(tolower(s1[i]) != tolower(s2[i]))
+				return false;
+		return true;
+	}
+	else
+	{
+		return s1 == s2;
+	}
+}
+
+// Tests if the second string is a prefix of the first, optionally case insensitive
+inline bool str_starts_with(const std::wstring& str, const std::wstring& prefix,
+		bool case_insensitive = false)
+{
+	if(str.size() < prefix.size())
+		return false;
+	if(case_insensitive)
+	{
+		for(size_t i = 0; i < prefix.size(); ++i)
+			if(tolower(str[i]) != tolower(prefix[i]))
+				return false;
+	}
+	else
+	{
+		for(size_t i = 0; i < prefix.size(); ++i)
+			if(str[i] != prefix[i])
+				return false;
+	}
+	return true;
+}
+
+inline std::wstring narrow_to_wide(const std::string& mbs)
+{
+	size_t wcl = mbs.size();
+	Buffer<wchar_t> wcs(wcl+1);
+	size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
+	if(l == (size_t)(-1))
+		return L"<invalid multibyte string>";
+	wcs[l] = 0;
+	return *wcs;
+}
+
+inline std::string wide_to_narrow(const std::wstring& wcs)
+{
+	size_t mbl = wcs.size()*4;
+	SharedBuffer<char> mbs(mbl+1);
+	size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
+	if(l == (size_t)(-1))
+		mbs[0] = 0;
+	else
+		mbs[l] = 0;
+	return *mbs;
+}
+
+// Split a string using the given delimiter. Returns a vector containing
+// the component parts.
+inline std::vector<std::wstring> str_split(const std::wstring &str, wchar_t delimiter)
+{
+	std::vector<std::wstring> parts;
+	std::wstringstream sstr(str);
+	std::wstring part;
+	while(std::getline(sstr, part, delimiter))
+		parts.push_back(part);
+	return parts;
+}
+
+inline std::string lowercase(const std::string &s)
+{
+	std::string s2;
+	for(size_t i=0; i<s.size(); i++)
+	{
+		char c = s[i];
+		if(c >= 'A' && c <= 'Z')
+			c -= 'A' - 'a';
+		s2 += c;
+	}
+	return s2;
+}
+
+inline bool is_yes(const std::string &s)
+{
+	std::string s2 = lowercase(trim(s));
+	if(s2 == "y" || s2 == "yes" || s2 == "true" || s2 == "1")
+		return true;
+	return false;
+}
+
+inline s32 mystoi(const std::string &s, s32 min, s32 max)
+{
+	s32 i = atoi(s.c_str());
+	if(i < min)
+		i = min;
+	if(i > max)
+		i = max;
+	return i;
+}
+
+
+// MSVC2010 includes it's own versions of these
+//#if !defined(_MSC_VER) || _MSC_VER < 1600
+
+inline s32 mystoi(const std::string &s)
+{
+	return atoi(s.c_str());
+}
+
+inline s32 mystoi(const std::wstring &s)
+{
+	return atoi(wide_to_narrow(s).c_str());
+}
+
+inline float mystof(const std::string &s)
+{
+	// This crap causes a segfault in certain cases on MinGW
+	/*float f;
+	std::istringstream ss(s);
+	ss>>f;
+	return f;*/
+	// This works in that case
+	return atof(s.c_str());
+}
+
+//#endif
+
+#define stoi mystoi
+#define stof mystof
+
+inline std::string itos(s32 i)
+{
+	std::ostringstream o;
+	o<<i;
+	return o.str();
+}
+
+inline std::string ftos(float f)
+{
+	std::ostringstream o;
+	o<<f;
+	return o.str();
+}
+
+inline void str_replace(std::string & str, std::string const & pattern,
+		std::string const & replacement)
+{
+	std::string::size_type start = str.find(pattern, 0);
+	while(start != str.npos)
+	{
+		str.replace(start, pattern.size(), replacement);
+		start = str.find(pattern, start+replacement.size());
+	}
+}
+
+inline void str_replace_char(std::string & str, char from, char to)
+{
+	for(unsigned int i=0; i<str.size(); i++)
+	{
+		if(str[i] == from)
+			str[i] = to;
+	}
+}
+
+/*
+	Checks if a string contains only supplied characters
+*/
+inline bool string_allowed(const std::string &s, const std::string &allowed_chars)
+{
+	for(u32 i=0; i<s.size(); i++)
+	{
+		bool confirmed = false;
+		for(u32 j=0; j<allowed_chars.size(); j++)
+		{
+			if(s[i] == allowed_chars[j])
+			{
+				confirmed = true;
+				break;
+			}
+		}
+		if(confirmed == false)
+			return false;
+	}
+	return true;
+}
+
+/*
+	Forcefully wraps string into rows using \n
+	(no word wrap, used for showing paths in gui)
+*/
+inline std::string wrap_rows(const std::string &from, u32 rowlen)
+{
+	std::string to;
+	for(u32 i=0; i<from.size(); i++)
+	{
+		if(i != 0 && i%rowlen == 0)
+			to += '\n';
+		to += from[i];
+	}
+	return to;
+}
+
+std::string translatePassword(std::string playername, std::wstring password);
+
+#endif
+
diff --git a/src/util/thread.h b/src/util/thread.h
new file mode 100644
index 000000000..8e8c74ac5
--- /dev/null
+++ b/src/util/thread.h
@@ -0,0 +1,227 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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.
+*/
+
+#ifndef UTIL_THREAD_HEADER
+#define UTIL_THREAD_HEADER
+
+#include "../irrlichttypes.h"
+#include <jthread.h>
+#include <jmutex.h>
+#include <jmutexautolock.h>
+
+template<typename T>
+class MutexedVariable
+{
+public:
+	MutexedVariable(T value):
+		m_value(value)
+	{
+		m_mutex.Init();
+	}
+
+	T get()
+	{
+		JMutexAutoLock lock(m_mutex);
+		return m_value;
+	}
+
+	void set(T value)
+	{
+		JMutexAutoLock lock(m_mutex);
+		m_value = value;
+	}
+	
+	// You'll want to grab this in a SharedPtr
+	JMutexAutoLock * getLock()
+	{
+		return new JMutexAutoLock(m_mutex);
+	}
+	
+	// You pretty surely want to grab the lock when accessing this
+	T m_value;
+
+private:
+	JMutex m_mutex;
+};
+
+/*
+	A base class for simple background thread implementation
+*/
+
+class SimpleThread : public JThread
+{
+	bool run;
+	JMutex run_mutex;
+
+public:
+
+	SimpleThread():
+		JThread(),
+		run(true)
+	{
+		run_mutex.Init();
+	}
+
+	virtual ~SimpleThread()
+	{}
+
+	virtual void * Thread() = 0;
+
+	bool getRun()
+	{
+		JMutexAutoLock lock(run_mutex);
+		return run;
+	}
+	void setRun(bool a_run)
+	{
+		JMutexAutoLock lock(run_mutex);
+		run = a_run;
+	}
+
+	void stop()
+	{
+		setRun(false);
+		while(IsRunning())
+			sleep_ms(100);
+	}
+};
+
+/*
+	A single worker thread - multiple client threads queue framework.
+*/
+
+template<typename Caller, typename Data>
+class CallerInfo
+{
+public:
+	Caller caller;
+	Data data;
+};
+
+template<typename Key, typename T, typename Caller, typename CallerData>
+class GetResult
+{
+public:
+	Key key;
+	T item;
+	core::list<CallerInfo<Caller, CallerData> > callers;
+};
+
+template<typename Key, typename T, typename Caller, typename CallerData>
+class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
+{
+};
+
+template<typename Key, typename T, typename Caller, typename CallerData>
+class GetRequest
+{
+public:
+	GetRequest()
+	{
+		dest = NULL;
+	}
+	GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
+	{
+		dest = a_dest;
+	}
+	GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
+			Key a_key)
+	{
+		dest = a_dest;
+		key = a_key;
+	}
+	~GetRequest()
+	{
+	}
+	
+	Key key;
+	ResultQueue<Key, T, Caller, CallerData> *dest;
+	core::list<CallerInfo<Caller, CallerData> > callers;
+};
+
+template<typename Key, typename T, typename Caller, typename CallerData>
+class RequestQueue
+{
+public:
+	u32 size()
+	{
+		return m_queue.size();
+	}
+
+	void add(Key key, Caller caller, CallerData callerdata,
+			ResultQueue<Key, T, Caller, CallerData> *dest)
+	{
+		JMutexAutoLock lock(m_queue.getMutex());
+		
+		/*
+			If the caller is already on the list, only update CallerData
+		*/
+		for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
+				i = m_queue.getList().begin();
+				i != m_queue.getList().end(); i++)
+		{
+			GetRequest<Key, T, Caller, CallerData> &request = *i;
+
+			if(request.key == key)
+			{
+				for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
+						i = request.callers.begin();
+						i != request.callers.end(); i++)
+				{
+					CallerInfo<Caller, CallerData> &ca = *i;
+					if(ca.caller == caller)
+					{
+						ca.data = callerdata;
+						return;
+					}
+				}
+				CallerInfo<Caller, CallerData> ca;
+				ca.caller = caller;
+				ca.data = callerdata;
+				request.callers.push_back(ca);
+				return;
+			}
+		}
+
+		/*
+			Else add a new request to the queue
+		*/
+
+		GetRequest<Key, T, Caller, CallerData> request;
+		request.key = key;
+		CallerInfo<Caller, CallerData> ca;
+		ca.caller = caller;
+		ca.data = callerdata;
+		request.callers.push_back(ca);
+		request.dest = dest;
+		
+		m_queue.getList().push_back(request);
+	}
+
+	GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
+	{
+		return m_queue.pop_front(wait_if_empty);
+	}
+
+private:
+	MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
+};
+
+#endif
+
diff --git a/src/util/timetaker.cpp b/src/util/timetaker.cpp
new file mode 100644
index 000000000..9cc87f3ea
--- /dev/null
+++ b/src/util/timetaker.cpp
@@ -0,0 +1,61 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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 "timetaker.h"
+
+#include "gettime.h"
+#include "log.h"
+#include <ostream>
+
+TimeTaker::TimeTaker(const char *name, u32 *result)
+{
+	m_name = name;
+	m_result = result;
+	m_running = true;
+	m_time1 = getTimeMs();
+}
+
+u32 TimeTaker::stop(bool quiet)
+{
+	if(m_running)
+	{
+		u32 time2 = getTimeMs();
+		u32 dtime = time2 - m_time1;
+		if(m_result != NULL)
+		{
+			(*m_result) += dtime;
+		}
+		else
+		{
+			if(quiet == false)
+				infostream<<m_name<<" took "<<dtime<<"ms"<<std::endl;
+		}
+		m_running = false;
+		return dtime;
+	}
+	return 0;
+}
+
+u32 TimeTaker::getTime()
+{
+	u32 time2 = getTimeMs();
+	u32 dtime = time2 - m_time1;
+	return dtime;
+}
+
diff --git a/src/util/timetaker.h b/src/util/timetaker.h
new file mode 100644
index 000000000..8aad97d0f
--- /dev/null
+++ b/src/util/timetaker.h
@@ -0,0 +1,51 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 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.
+*/
+
+#ifndef UTIL_TIMETAKER_HEADER
+#define UTIL_TIMETAKER_HEADER
+
+#include "../irrlichttypes.h"
+
+/*
+	TimeTaker
+*/
+
+class TimeTaker
+{
+public:
+	TimeTaker(const char *name, u32 *result=NULL);
+
+	~TimeTaker()
+	{
+		stop();
+	}
+
+	u32 stop(bool quiet=false);
+
+	u32 getTime();
+
+private:
+	const char *m_name;
+	u32 m_time1;
+	bool m_running;
+	u32 *m_result;
+};
+
+#endif
+
diff --git a/src/utility.cpp b/src/utility.cpp
index 6b664ea8c..66127fc3b 100644
--- a/src/utility.cpp
+++ b/src/utility.cpp
@@ -1,6 +1,6 @@
 /*
 Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2012 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
@@ -17,436 +17,4 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-/*
-(c) 2010 Perttu Ahola <celeron55@gmail.com>
-*/
-
-#include "utility.h"
-#include "gettime.h"
-#include "sha1.h"
-#include "base64.h"
-#include "log.h"
-#include <iomanip>
-
-TimeTaker::TimeTaker(const char *name, u32 *result)
-{
-	m_name = name;
-	m_result = result;
-	m_running = true;
-	m_time1 = getTimeMs();
-}
-
-u32 TimeTaker::stop(bool quiet)
-{
-	if(m_running)
-	{
-		u32 time2 = getTimeMs();
-		u32 dtime = time2 - m_time1;
-		if(m_result != NULL)
-		{
-			(*m_result) += dtime;
-		}
-		else
-		{
-			if(quiet == false)
-				infostream<<m_name<<" took "<<dtime<<"ms"<<std::endl;
-		}
-		m_running = false;
-		return dtime;
-	}
-	return 0;
-}
-
-u32 TimeTaker::getTime()
-{
-	u32 time2 = getTimeMs();
-	u32 dtime = time2 - m_time1;
-	return dtime;
-}
-
-const v3s16 g_6dirs[6] =
-{
-	// +right, +top, +back
-	v3s16( 0, 0, 1), // back
-	v3s16( 0, 1, 0), // top
-	v3s16( 1, 0, 0), // right
-	v3s16( 0, 0,-1), // front
-	v3s16( 0,-1, 0), // bottom
-	v3s16(-1, 0, 0) // left
-};
-
-const v3s16 g_26dirs[26] =
-{
-	// +right, +top, +back
-	v3s16( 0, 0, 1), // back
-	v3s16( 0, 1, 0), // top
-	v3s16( 1, 0, 0), // right
-	v3s16( 0, 0,-1), // front
-	v3s16( 0,-1, 0), // bottom
-	v3s16(-1, 0, 0), // left
-	// 6
-	v3s16(-1, 1, 0), // top left
-	v3s16( 1, 1, 0), // top right
-	v3s16( 0, 1, 1), // top back
-	v3s16( 0, 1,-1), // top front
-	v3s16(-1, 0, 1), // back left
-	v3s16( 1, 0, 1), // back right
-	v3s16(-1, 0,-1), // front left
-	v3s16( 1, 0,-1), // front right
-	v3s16(-1,-1, 0), // bottom left
-	v3s16( 1,-1, 0), // bottom right
-	v3s16( 0,-1, 1), // bottom back
-	v3s16( 0,-1,-1), // bottom front
-	// 18
-	v3s16(-1, 1, 1), // top back-left
-	v3s16( 1, 1, 1), // top back-right
-	v3s16(-1, 1,-1), // top front-left
-	v3s16( 1, 1,-1), // top front-right
-	v3s16(-1,-1, 1), // bottom back-left
-	v3s16( 1,-1, 1), // bottom back-right
-	v3s16(-1,-1,-1), // bottom front-left
-	v3s16( 1,-1,-1), // bottom front-right
-	// 26
-};
-
-const v3s16 g_27dirs[27] =
-{
-	// +right, +top, +back
-	v3s16( 0, 0, 1), // back
-	v3s16( 0, 1, 0), // top
-	v3s16( 1, 0, 0), // right
-	v3s16( 0, 0,-1), // front
-	v3s16( 0,-1, 0), // bottom
-	v3s16(-1, 0, 0), // left
-	// 6
-	v3s16(-1, 1, 0), // top left
-	v3s16( 1, 1, 0), // top right
-	v3s16( 0, 1, 1), // top back
-	v3s16( 0, 1,-1), // top front
-	v3s16(-1, 0, 1), // back left
-	v3s16( 1, 0, 1), // back right
-	v3s16(-1, 0,-1), // front left
-	v3s16( 1, 0,-1), // front right
-	v3s16(-1,-1, 0), // bottom left
-	v3s16( 1,-1, 0), // bottom right
-	v3s16( 0,-1, 1), // bottom back
-	v3s16( 0,-1,-1), // bottom front
-	// 18
-	v3s16(-1, 1, 1), // top back-left
-	v3s16( 1, 1, 1), // top back-right
-	v3s16(-1, 1,-1), // top front-left
-	v3s16( 1, 1,-1), // top front-right
-	v3s16(-1,-1, 1), // bottom back-left
-	v3s16( 1,-1, 1), // bottom back-right
-	v3s16(-1,-1,-1), // bottom front-left
-	v3s16( 1,-1,-1), // bottom front-right
-	// 26
-	v3s16(0,0,0),
-};
-
-static unsigned long next = 1;
-
-/* RAND_MAX assumed to be 32767 */
-int myrand(void)
-{
-   next = next * 1103515245 + 12345;
-   return((unsigned)(next/65536) % 32768);
-}
-
-void mysrand(unsigned seed)
-{
-   next = seed;
-}
-
-int myrand_range(int min, int max)
-{
-	if(max-min > MYRAND_MAX)
-	{
-		errorstream<<"WARNING: myrand_range: max-min > MYRAND_MAX"<<std::endl;
-		assert(0);
-	}
-	if(min > max)
-	{
-		assert(0);
-		return max;
-	}
-	return (myrand()%(max-min+1))+min;
-}
-
-/*
-	blockpos: position of block in block coordinates
-	camera_pos: position of camera in nodes
-	camera_dir: an unit vector pointing to camera direction
-	range: viewing range
-*/
-bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
-		f32 camera_fov, f32 range, f32 *distance_ptr)
-{
-	v3s16 blockpos_nodes = blockpos_b * MAP_BLOCKSIZE;
-	
-	// Block center position
-	v3f blockpos(
-			((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
-			((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
-			((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
-	);
-
-	// Block position relative to camera
-	v3f blockpos_relative = blockpos - camera_pos;
-
-	// Distance in camera direction (+=front, -=back)
-	f32 dforward = blockpos_relative.dotProduct(camera_dir);
-
-	// Total distance
-	f32 d = blockpos_relative.getLength();
-
-	if(distance_ptr)
-		*distance_ptr = d;
-	
-	// If block is very close, it is always in sight
-	if(d < 1.44*1.44*MAP_BLOCKSIZE*BS/2)
-		return true;
-
-	// If block is far away, it's not in sight
-	if(d > range)
-		return false;
-
-	// Maximum radius of a block
-	f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
-	
-	// If block is (nearly) touching the camera, don't
-	// bother validating further (that is, render it anyway)
-	if(d < block_max_radius)
-		return true;
-	
-	// Cosine of the angle between the camera direction
-	// and the block direction (camera_dir is an unit vector)
-	f32 cosangle = dforward / d;
-	
-	// Compensate for the size of the block
-	// (as the block has to be shown even if it's a bit off FOV)
-	// This is an estimate, plus an arbitary factor
-	cosangle += block_max_radius / d * 0.5;
-
-	// If block is not in the field of view, skip it
-	if(cosangle < cos(camera_fov / 2))
-		return false;
-
-	return true;
-}
-
-// Creates a string encoded in JSON format (almost equivalent to a C string literal)
-std::string serializeJsonString(const std::string &plain)
-{
-	std::ostringstream os(std::ios::binary);
-	os<<"\"";
-	for(size_t i = 0; i < plain.size(); i++)
-	{
-		char c = plain[i];
-		switch(c)
-		{
-			case '"': os<<"\\\""; break;
-			case '\\': os<<"\\\\"; break;
-			case '/': os<<"\\/"; break;
-			case '\b': os<<"\\b"; break;
-			case '\f': os<<"\\f"; break;
-			case '\n': os<<"\\n"; break;
-			case '\r': os<<"\\r"; break;
-			case '\t': os<<"\\t"; break;
-			default:
-			{
-				if(c >= 32 && c <= 126)
-				{
-					os<<c;
-				}
-				else
-				{
-					u32 cnum = (u32) (u8) c;
-					os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum;
-				}
-				break;
-			}
-		}
-	}
-	os<<"\"";
-	return os.str();
-}
-
-// Reads a string encoded in JSON format
-std::string deSerializeJsonString(std::istream &is)
-{
-	std::ostringstream os(std::ios::binary);
-	char c, c2;
-
-	// Parse initial doublequote
-	is >> c;
-	if(c != '"')
-		throw SerializationError("JSON string must start with doublequote");
-
-	// Parse characters
-	for(;;)
-	{
-		c = is.get();
-		if(is.eof())
-			throw SerializationError("JSON string ended prematurely");
-		if(c == '"')
-		{
-			return os.str();
-		}
-		else if(c == '\\')
-		{
-			c2 = is.get();
-			if(is.eof())
-				throw SerializationError("JSON string ended prematurely");
-			switch(c2)
-			{
-				default:  os<<c2; break;
-				case 'b': os<<'\b'; break;
-				case 'f': os<<'\f'; break;
-				case 'n': os<<'\n'; break;
-				case 'r': os<<'\r'; break;
-				case 't': os<<'\t'; break;
-				case 'u':
-				{
-					char hexdigits[4+1];
-					is.read(hexdigits, 4);
-					if(is.eof())
-						throw SerializationError("JSON string ended prematurely");
-					hexdigits[4] = 0;
-					std::istringstream tmp_is(hexdigits, std::ios::binary);
-					int hexnumber;
-					tmp_is >> std::hex >> hexnumber;
-					os<<((char)hexnumber);
-					break;
-				}
-			}
-		}
-		else
-		{
-			os<<c;
-		}
-	}
-	return os.str();
-}
-
-// Get an sha-1 hash of the player's name combined with
-// the password entered. That's what the server uses as
-// their password. (Exception : if the password field is
-// blank, we send a blank password - this is for backwards
-// compatibility with password-less players).
-std::string translatePassword(std::string playername, std::wstring password)
-{
-	if(password.length() == 0)
-		return "";
-
-	std::string slt = playername + wide_to_narrow(password);
-	SHA1 sha1;
-	sha1.addBytes(slt.c_str(), slt.length());
-	unsigned char *digest = sha1.getDigest();
-	std::string pwd = base64_encode(digest, 20);
-	free(digest);
-	return pwd;
-}
-
-
-
-PointedThing::PointedThing():
-	type(POINTEDTHING_NOTHING),
-	node_undersurface(0,0,0),
-	node_abovesurface(0,0,0),
-	object_id(-1)
-{}
-
-std::string PointedThing::dump() const
-{
-	std::ostringstream os(std::ios::binary);
-	if(type == POINTEDTHING_NOTHING)
-	{
-		os<<"[nothing]";
-	}
-	else if(type == POINTEDTHING_NODE)
-	{
-		const v3s16 &u = node_undersurface;
-		const v3s16 &a = node_abovesurface;
-		os<<"[node under="<<u.X<<","<<u.Y<<","<<u.Z
-			<< " above="<<a.X<<","<<a.Y<<","<<a.Z<<"]";
-	}
-	else if(type == POINTEDTHING_OBJECT)
-	{
-		os<<"[object "<<object_id<<"]";
-	}
-	else
-	{
-		os<<"[unknown PointedThing]";
-	}
-	return os.str();
-}
-
-void PointedThing::serialize(std::ostream &os) const
-{
-	writeU8(os, 0); // version
-	writeU8(os, (u8)type);
-	if(type == POINTEDTHING_NOTHING)
-	{
-		// nothing
-	}
-	else if(type == POINTEDTHING_NODE)
-	{
-		writeV3S16(os, node_undersurface);
-		writeV3S16(os, node_abovesurface);
-	}
-	else if(type == POINTEDTHING_OBJECT)
-	{
-		writeS16(os, object_id);
-	}
-}
-
-void PointedThing::deSerialize(std::istream &is)
-{
-	int version = readU8(is);
-	if(version != 0) throw SerializationError(
-			"unsupported PointedThing version");
-	type = (PointedThingType) readU8(is);
-	if(type == POINTEDTHING_NOTHING)
-	{
-		// nothing
-	}
-	else if(type == POINTEDTHING_NODE)
-	{
-		node_undersurface = readV3S16(is);
-		node_abovesurface = readV3S16(is);
-	}
-	else if(type == POINTEDTHING_OBJECT)
-	{
-		object_id = readS16(is);
-	}
-	else
-	{
-		throw SerializationError(
-			"unsupported PointedThingType");
-	}
-}
-
-bool PointedThing::operator==(const PointedThing &pt2) const
-{
-	if(type != pt2.type)
-		return false;
-	if(type == POINTEDTHING_NODE)
-	{
-		if(node_undersurface != pt2.node_undersurface)
-			return false;
-		if(node_abovesurface != pt2.node_abovesurface)
-			return false;
-	}
-	else if(type == POINTEDTHING_OBJECT)
-	{
-		if(object_id != pt2.object_id)
-			return false;
-	}
-	return true;
-}
 
-bool PointedThing::operator!=(const PointedThing &pt2) const
-{
-	return !(*this == pt2);
-}
diff --git a/src/utility.h b/src/utility.h
index c365f8fce..58e75ce78 100644
--- a/src/utility.h
+++ b/src/utility.h
@@ -1,6 +1,6 @@
 /*
 Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2012 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
@@ -20,1846 +20,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef UTILITY_HEADER
 #define UTILITY_HEADER
 
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <sstream>
-#include <vector>
-#include <jthread.h>
-#include <jmutex.h>
-#include <jmutexautolock.h>
-#include <cstring>
-
-#include "common_irrlicht.h"
-#include "debug.h"
-#include "exceptions.h"
-#include "porting.h"
-#include "strfnd.h" // For trim()
-
-extern const v3s16 g_6dirs[6];
-
-extern const v3s16 g_26dirs[26];
-
-// 26th is (0,0,0)
-extern const v3s16 g_27dirs[27];
-
-inline void writeU64(u8 *data, u64 i)
-{
-	data[0] = ((i>>56)&0xff);
-	data[1] = ((i>>48)&0xff);
-	data[2] = ((i>>40)&0xff);
-	data[3] = ((i>>32)&0xff);
-	data[4] = ((i>>24)&0xff);
-	data[5] = ((i>>16)&0xff);
-	data[6] = ((i>> 8)&0xff);
-	data[7] = ((i>> 0)&0xff);
-}
-
-inline void writeU32(u8 *data, u32 i)
-{
-	data[0] = ((i>>24)&0xff);
-	data[1] = ((i>>16)&0xff);
-	data[2] = ((i>> 8)&0xff);
-	data[3] = ((i>> 0)&0xff);
-}
-
-inline void writeU16(u8 *data, u16 i)
-{
-	data[0] = ((i>> 8)&0xff);
-	data[1] = ((i>> 0)&0xff);
-}
-
-inline void writeU8(u8 *data, u8 i)
-{
-	data[0] = ((i>> 0)&0xff);
-}
-
-inline u64 readU64(u8 *data)
-{
-	return ((u64)data[0]<<56) | ((u64)data[1]<<48)
-		| ((u64)data[2]<<40) | ((u64)data[3]<<32)
-		| ((u64)data[4]<<24) | ((u64)data[5]<<16)
-		| ((u64)data[6]<<8) | ((u64)data[7]<<0);
-}
-
-inline u32 readU32(u8 *data)
-{
-	return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
-}
-
-inline u16 readU16(u8 *data)
-{
-	return (data[0]<<8) | (data[1]<<0);
-}
-
-inline u8 readU8(u8 *data)
-{
-	return (data[0]<<0);
-}
-
-inline void writeS32(u8 *data, s32 i){
-	writeU32(data, (u32)i);
-}
-inline s32 readS32(u8 *data){
-	return (s32)readU32(data);
-}
-
-inline void writeS16(u8 *data, s16 i){
-	writeU16(data, (u16)i);
-}
-inline s16 readS16(u8 *data){
-	return (s16)readU16(data);
-}
-
-inline void writeS8(u8 *data, s8 i){
-	writeU8(data, (u8)i);
-}
-inline s8 readS8(u8 *data){
-	return (s8)readU8(data);
-}
-
-inline void writeF1000(u8 *data, f32 i){
-	writeS32(data, i*1000);
-}
-inline f32 readF1000(u8 *data){
-	return (f32)readS32(data)/1000.;
-}
-
-inline void writeV3S32(u8 *data, v3s32 p)
-{
-	writeS32(&data[0], p.X);
-	writeS32(&data[4], p.Y);
-	writeS32(&data[8], p.Z);
-}
-inline v3s32 readV3S32(u8 *data)
-{
-	v3s32 p;
-	p.X = readS32(&data[0]);
-	p.Y = readS32(&data[4]);
-	p.Z = readS32(&data[8]);
-	return p;
-}
-
-inline void writeV3F1000(u8 *data, v3f p)
-{
-	writeF1000(&data[0], p.X);
-	writeF1000(&data[4], p.Y);
-	writeF1000(&data[8], p.Z);
-}
-inline v3f readV3F1000(u8 *data)
-{
-	v3f p;
-	p.X = (float)readF1000(&data[0]);
-	p.Y = (float)readF1000(&data[4]);
-	p.Z = (float)readF1000(&data[8]);
-	return p;
-}
-
-inline void writeV2F1000(u8 *data, v2f p)
-{
-	writeF1000(&data[0], p.X);
-	writeF1000(&data[4], p.Y);
-}
-inline v2f readV2F1000(u8 *data)
-{
-	v2f p;
-	p.X = (float)readF1000(&data[0]);
-	p.Y = (float)readF1000(&data[4]);
-	return p;
-}
-
-inline void writeV2S16(u8 *data, v2s16 p)
-{
-	writeS16(&data[0], p.X);
-	writeS16(&data[2], p.Y);
-}
-
-inline v2s16 readV2S16(u8 *data)
-{
-	v2s16 p;
-	p.X = readS16(&data[0]);
-	p.Y = readS16(&data[2]);
-	return p;
-}
-
-inline void writeV2S32(u8 *data, v2s32 p)
-{
-	writeS32(&data[0], p.X);
-	writeS32(&data[2], p.Y);
-}
-
-inline v2s32 readV2S32(u8 *data)
-{
-	v2s32 p;
-	p.X = readS32(&data[0]);
-	p.Y = readS32(&data[2]);
-	return p;
-}
-
-inline void writeV3S16(u8 *data, v3s16 p)
-{
-	writeS16(&data[0], p.X);
-	writeS16(&data[2], p.Y);
-	writeS16(&data[4], p.Z);
-}
-
-inline v3s16 readV3S16(u8 *data)
-{
-	v3s16 p;
-	p.X = readS16(&data[0]);
-	p.Y = readS16(&data[2]);
-	p.Z = readS16(&data[4]);
-	return p;
-}
-
-/*
-	The above stuff directly interfaced to iostream
-*/
-
-inline void writeU8(std::ostream &os, u8 p)
-{
-	char buf[1] = {0};
-	writeU8((u8*)buf, p);
-	os.write(buf, 1);
-}
-inline u8 readU8(std::istream &is)
-{
-	char buf[1] = {0};
-	is.read(buf, 1);
-	return readU8((u8*)buf);
-}
-
-inline void writeU16(std::ostream &os, u16 p)
-{
-	char buf[2] = {0};
-	writeU16((u8*)buf, p);
-	os.write(buf, 2);
-}
-inline u16 readU16(std::istream &is)
-{
-	char buf[2] = {0};
-	is.read(buf, 2);
-	return readU16((u8*)buf);
-}
-
-inline void writeU32(std::ostream &os, u32 p)
-{
-	char buf[4] = {0};
-	writeU32((u8*)buf, p);
-	os.write(buf, 4);
-}
-inline u32 readU32(std::istream &is)
-{
-	char buf[4] = {0};
-	is.read(buf, 4);
-	return readU32((u8*)buf);
-}
-
-inline void writeS32(std::ostream &os, s32 p)
-{
-	char buf[4] = {0};
-	writeS32((u8*)buf, p);
-	os.write(buf, 4);
-}
-inline s32 readS32(std::istream &is)
-{
-	char buf[4] = {0};
-	is.read(buf, 4);
-	return readS32((u8*)buf);
-}
-
-inline void writeS16(std::ostream &os, s16 p)
-{
-	char buf[2] = {0};
-	writeS16((u8*)buf, p);
-	os.write(buf, 2);
-}
-inline s16 readS16(std::istream &is)
-{
-	char buf[2] = {0};
-	is.read(buf, 2);
-	return readS16((u8*)buf);
-}
-
-inline void writeS8(std::ostream &os, s8 p)
-{
-	char buf[1] = {0};
-	writeS8((u8*)buf, p);
-	os.write(buf, 1);
-}
-inline s8 readS8(std::istream &is)
-{
-	char buf[1] = {0};
-	is.read(buf, 1);
-	return readS8((u8*)buf);
-}
-
-inline void writeF1000(std::ostream &os, f32 p)
-{
-	char buf[4] = {0};
-	writeF1000((u8*)buf, p);
-	os.write(buf, 4);
-}
-inline f32 readF1000(std::istream &is)
-{
-	char buf[4] = {0};
-	is.read(buf, 4);
-	return readF1000((u8*)buf);
-}
-
-inline void writeV3F1000(std::ostream &os, v3f p)
-{
-	char buf[12];
-	writeV3F1000((u8*)buf, p);
-	os.write(buf, 12);
-}
-inline v3f readV3F1000(std::istream &is)
-{
-	char buf[12];
-	is.read(buf, 12);
-	return readV3F1000((u8*)buf);
-}
-
-inline void writeV2F1000(std::ostream &os, v2f p)
-{
-	char buf[8] = {0};
-	writeV2F1000((u8*)buf, p);
-	os.write(buf, 8);
-}
-inline v2f readV2F1000(std::istream &is)
-{
-	char buf[8] = {0};
-	is.read(buf, 8);
-	return readV2F1000((u8*)buf);
-}
-
-inline void writeV2S16(std::ostream &os, v2s16 p)
-{
-	char buf[4] = {0};
-	writeV2S16((u8*)buf, p);
-	os.write(buf, 4);
-}
-inline v2s16 readV2S16(std::istream &is)
-{
-	char buf[4] = {0};
-	is.read(buf, 4);
-	return readV2S16((u8*)buf);
-}
-
-inline void writeV3S16(std::ostream &os, v3s16 p)
-{
-	char buf[6] = {0};
-	writeV3S16((u8*)buf, p);
-	os.write(buf, 6);
-}
-inline v3s16 readV3S16(std::istream &is)
-{
-	char buf[6] = {0};
-	is.read(buf, 6);
-	return readV3S16((u8*)buf);
-}
-
-/*
-	None of these are used at the moment
-*/
-
-template <typename T>
-class SharedPtr
-{
-public:
-	SharedPtr(T *t=NULL)
-	{
-		refcount = new int;
-		*refcount = 1;
-		ptr = t;
-	}
-	SharedPtr(SharedPtr<T> &t)
-	{
-		//*this = t;
-		drop();
-		refcount = t.refcount;
-		(*refcount)++;
-		ptr = t.ptr;
-	}
-	~SharedPtr()
-	{
-		drop();
-	}
-	SharedPtr<T> & operator=(T *t)
-	{
-		drop();
-		refcount = new int;
-		*refcount = 1;
-		ptr = t;
-		return *this;
-	}
-	SharedPtr<T> & operator=(SharedPtr<T> &t)
-	{
-		drop();
-		refcount = t.refcount;
-		(*refcount)++;
-		ptr = t.ptr;
-		return *this;
-	}
-	T* operator->()
-	{
-		return ptr;
-	}
-	T & operator*()
-	{
-		return *ptr;
-	}
-	bool operator!=(T *t)
-	{
-		return ptr != t;
-	}
-	bool operator==(T *t)
-	{
-		return ptr == t;
-	}
-	T & operator[](unsigned int i)
-	{
-		return ptr[i];
-	}
-private:
-	void drop()
-	{
-		assert((*refcount) > 0);
-		(*refcount)--;
-		if(*refcount == 0)
-		{
-			delete refcount;
-			if(ptr != NULL)
-				delete ptr;
-		}
-	}
-	T *ptr;
-	int *refcount;
-};
-
-template <typename T>
-class Buffer
-{
-public:
-	Buffer()
-	{
-		m_size = 0;
-		data = NULL;
-	}
-	Buffer(unsigned int size)
-	{
-		m_size = size;
-		if(size != 0)
-			data = new T[size];
-		else
-			data = NULL;
-	}
-	Buffer(const Buffer &buffer)
-	{
-		m_size = buffer.m_size;
-		if(m_size != 0)
-		{
-			data = new T[buffer.m_size];
-			memcpy(data, buffer.data, buffer.m_size);
-		}
-		else
-			data = NULL;
-	}
-	Buffer(const T *t, unsigned int size)
-	{
-		m_size = size;
-		if(size != 0)
-		{
-			data = new T[size];
-			memcpy(data, t, size);
-		}
-		else
-			data = NULL;
-	}
-	~Buffer()
-	{
-		drop();
-	}
-	Buffer& operator=(const Buffer &buffer)
-	{
-		if(this == &buffer)
-			return *this;
-		drop();
-		m_size = buffer.m_size;
-		if(m_size != 0)
-		{
-			data = new T[buffer.m_size];
-			memcpy(data, buffer.data, buffer.m_size);
-		}
-		else
-			data = NULL;
-		return *this;
-	}
-	T & operator[](unsigned int i) const
-	{
-		return data[i];
-	}
-	T * operator*() const
-	{
-		return data;
-	}
-	unsigned int getSize() const
-	{
-		return m_size;
-	}
-private:
-	void drop()
-	{
-		if(data)
-			delete[] data;
-	}
-	T *data;
-	unsigned int m_size;
-};
-
-template <typename T>
-class SharedBuffer
-{
-public:
-	SharedBuffer()
-	{
-		m_size = 0;
-		data = NULL;
-		refcount = new unsigned int;
-		(*refcount) = 1;
-	}
-	SharedBuffer(unsigned int size)
-	{
-		m_size = size;
-		if(m_size != 0)
-			data = new T[m_size];
-		else
-			data = NULL;
-		refcount = new unsigned int;
-		(*refcount) = 1;
-	}
-	SharedBuffer(const SharedBuffer &buffer)
-	{
-		//std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
-		m_size = buffer.m_size;
-		data = buffer.data;
-		refcount = buffer.refcount;
-		(*refcount)++;
-	}
-	SharedBuffer & operator=(const SharedBuffer & buffer)
-	{
-		//std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
-		if(this == &buffer)
-			return *this;
-		drop();
-		m_size = buffer.m_size;
-		data = buffer.data;
-		refcount = buffer.refcount;
-		(*refcount)++;
-		return *this;
-	}
-	/*
-		Copies whole buffer
-	*/
-	SharedBuffer(T *t, unsigned int size)
-	{
-		m_size = size;
-		if(m_size != 0)
-		{
-			data = new T[m_size];
-			memcpy(data, t, m_size);
-		}
-		else
-			data = NULL;
-		refcount = new unsigned int;
-		(*refcount) = 1;
-	}
-	/*
-		Copies whole buffer
-	*/
-	SharedBuffer(const Buffer<T> &buffer)
-	{
-		m_size = buffer.getSize();
-		if(m_size != 0)
-		{
-			data = new T[m_size];
-			memcpy(data, *buffer, buffer.getSize());
-		}
-		else
-			data = NULL;
-		refcount = new unsigned int;
-		(*refcount) = 1;
-	}
-	~SharedBuffer()
-	{
-		drop();
-	}
-	T & operator[](unsigned int i) const
-	{
-		//assert(i < m_size)
-		return data[i];
-	}
-	T * operator*() const
-	{
-		return data;
-	}
-	unsigned int getSize() const
-	{
-		return m_size;
-	}
-	operator Buffer<T>() const
-	{
-		return Buffer<T>(data, m_size);
-	}
-private:
-	void drop()
-	{
-		assert((*refcount) > 0);
-		(*refcount)--;
-		if(*refcount == 0)
-		{
-			if(data)
-				delete[] data;
-			delete refcount;
-		}
-	}
-	T *data;
-	unsigned int m_size;
-	unsigned int *refcount;
-};
-
-inline SharedBuffer<u8> SharedBufferFromString(const char *string)
-{
-	SharedBuffer<u8> b((u8*)string, strlen(string)+1);
-	return b;
-}
-
-template<typename T>
-class MutexedVariable
-{
-public:
-	MutexedVariable(T value):
-		m_value(value)
-	{
-		m_mutex.Init();
-	}
-
-	T get()
-	{
-		JMutexAutoLock lock(m_mutex);
-		return m_value;
-	}
-
-	void set(T value)
-	{
-		JMutexAutoLock lock(m_mutex);
-		m_value = value;
-	}
-	
-	// You'll want to grab this in a SharedPtr
-	JMutexAutoLock * getLock()
-	{
-		return new JMutexAutoLock(m_mutex);
-	}
-	
-	// You pretty surely want to grab the lock when accessing this
-	T m_value;
-
-private:
-	JMutex m_mutex;
-};
-
-/*
-	TimeTaker
-*/
-
-class TimeTaker
-{
-public:
-	TimeTaker(const char *name, u32 *result=NULL);
-
-	~TimeTaker()
-	{
-		stop();
-	}
-
-	u32 stop(bool quiet=false);
-
-	u32 getTime();
-
-private:
-	const char *m_name;
-	u32 m_time1;
-	bool m_running;
-	u32 *m_result;
-};
-
-// Tests if two strings are equal, optionally case insensitive
-inline bool str_equal(const std::wstring& s1, const std::wstring& s2,
-		bool case_insensitive = false)
-{
-	if(case_insensitive)
-	{
-		if(s1.size() != s2.size())
-			return false;
-		for(size_t i = 0; i < s1.size(); ++i)
-			if(tolower(s1[i]) != tolower(s2[i]))
-				return false;
-		return true;
-	}
-	else
-	{
-		return s1 == s2;
-	}
-}
-
-// Tests if the second string is a prefix of the first, optionally case insensitive
-inline bool str_starts_with(const std::wstring& str, const std::wstring& prefix,
-		bool case_insensitive = false)
-{
-	if(str.size() < prefix.size())
-		return false;
-	if(case_insensitive)
-	{
-		for(size_t i = 0; i < prefix.size(); ++i)
-			if(tolower(str[i]) != tolower(prefix[i]))
-				return false;
-	}
-	else
-	{
-		for(size_t i = 0; i < prefix.size(); ++i)
-			if(str[i] != prefix[i])
-				return false;
-	}
-	return true;
-}
-
-// Calculates the borders of a "d-radius" cube
-inline void getFacePositions(core::list<v3s16> &list, u16 d)
-{
-	if(d == 0)
-	{
-		list.push_back(v3s16(0,0,0));
-		return;
-	}
-	if(d == 1)
-	{
-		/*
-			This is an optimized sequence of coordinates.
-		*/
-		list.push_back(v3s16( 0, 1, 0)); // top
-		list.push_back(v3s16( 0, 0, 1)); // back
-		list.push_back(v3s16(-1, 0, 0)); // left
-		list.push_back(v3s16( 1, 0, 0)); // right
-		list.push_back(v3s16( 0, 0,-1)); // front
-		list.push_back(v3s16( 0,-1, 0)); // bottom
-		// 6
-		list.push_back(v3s16(-1, 0, 1)); // back left
-		list.push_back(v3s16( 1, 0, 1)); // back right
-		list.push_back(v3s16(-1, 0,-1)); // front left
-		list.push_back(v3s16( 1, 0,-1)); // front right
-		list.push_back(v3s16(-1,-1, 0)); // bottom left
-		list.push_back(v3s16( 1,-1, 0)); // bottom right
-		list.push_back(v3s16( 0,-1, 1)); // bottom back
-		list.push_back(v3s16( 0,-1,-1)); // bottom front
-		list.push_back(v3s16(-1, 1, 0)); // top left
-		list.push_back(v3s16( 1, 1, 0)); // top right
-		list.push_back(v3s16( 0, 1, 1)); // top back
-		list.push_back(v3s16( 0, 1,-1)); // top front
-		// 18
-		list.push_back(v3s16(-1, 1, 1)); // top back-left
-		list.push_back(v3s16( 1, 1, 1)); // top back-right
-		list.push_back(v3s16(-1, 1,-1)); // top front-left
-		list.push_back(v3s16( 1, 1,-1)); // top front-right
-		list.push_back(v3s16(-1,-1, 1)); // bottom back-left
-		list.push_back(v3s16( 1,-1, 1)); // bottom back-right
-		list.push_back(v3s16(-1,-1,-1)); // bottom front-left
-		list.push_back(v3s16( 1,-1,-1)); // bottom front-right
-		// 26
-		return;
-	}
-
-	// Take blocks in all sides, starting from y=0 and going +-y
-	for(s16 y=0; y<=d-1; y++)
-	{
-		// Left and right side, including borders
-		for(s16 z=-d; z<=d; z++)
-		{
-			list.push_back(v3s16(d,y,z));
-			list.push_back(v3s16(-d,y,z));
-			if(y != 0)
-			{
-				list.push_back(v3s16(d,-y,z));
-				list.push_back(v3s16(-d,-y,z));
-			}
-		}
-		// Back and front side, excluding borders
-		for(s16 x=-d+1; x<=d-1; x++)
-		{
-			list.push_back(v3s16(x,y,d));
-			list.push_back(v3s16(x,y,-d));
-			if(y != 0)
-			{
-				list.push_back(v3s16(x,-y,d));
-				list.push_back(v3s16(x,-y,-d));
-			}
-		}
-	}
-
-	// Take the bottom and top face with borders
-	// -d<x<d, y=+-d, -d<z<d
-	for(s16 x=-d; x<=d; x++)
-	for(s16 z=-d; z<=d; z++)
-	{
-		list.push_back(v3s16(x,-d,z));
-		list.push_back(v3s16(x,d,z));
-	}
-}
-
-class IndentationRaiser
-{
-public:
-	IndentationRaiser(u16 *indentation)
-	{
-		m_indentation = indentation;
-		(*m_indentation)++;
-	}
-	~IndentationRaiser()
-	{
-		(*m_indentation)--;
-	}
-private:
-	u16 *m_indentation;
-};
-
-inline s16 getContainerPos(s16 p, s16 d)
-{
-	return (p>=0 ? p : p-d+1) / d;
-}
-
-inline v2s16 getContainerPos(v2s16 p, s16 d)
-{
-	return v2s16(
-		getContainerPos(p.X, d),
-		getContainerPos(p.Y, d)
-	);
-}
-
-inline v3s16 getContainerPos(v3s16 p, s16 d)
-{
-	return v3s16(
-		getContainerPos(p.X, d),
-		getContainerPos(p.Y, d),
-		getContainerPos(p.Z, d)
-	);
-}
-
-inline v2s16 getContainerPos(v2s16 p, v2s16 d)
-{
-	return v2s16(
-		getContainerPos(p.X, d.X),
-		getContainerPos(p.Y, d.Y)
-	);
-}
-
-inline v3s16 getContainerPos(v3s16 p, v3s16 d)
-{
-	return v3s16(
-		getContainerPos(p.X, d.X),
-		getContainerPos(p.Y, d.Y),
-		getContainerPos(p.Z, d.Z)
-	);
-}
-
-inline bool isInArea(v3s16 p, s16 d)
-{
-	return (
-		p.X >= 0 && p.X < d &&
-		p.Y >= 0 && p.Y < d &&
-		p.Z >= 0 && p.Z < d
-	);
-}
-
-inline bool isInArea(v2s16 p, s16 d)
-{
-	return (
-		p.X >= 0 && p.X < d &&
-		p.Y >= 0 && p.Y < d
-	);
-}
-
-inline bool isInArea(v3s16 p, v3s16 d)
-{
-	return (
-		p.X >= 0 && p.X < d.X &&
-		p.Y >= 0 && p.Y < d.Y &&
-		p.Z >= 0 && p.Z < d.Z
-	);
-}
-
-inline s16 rangelim(s16 i, s16 max)
-{
-	if(i < 0)
-		return 0;
-	if(i > max)
-		return max;
-	return i;
-}
-
-#define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d)))
-
-inline v3s16 arealim(v3s16 p, s16 d)
-{
-	if(p.X < 0)
-		p.X = 0;
-	if(p.Y < 0)
-		p.Y = 0;
-	if(p.Z < 0)
-		p.Z = 0;
-	if(p.X > d-1)
-		p.X = d-1;
-	if(p.Y > d-1)
-		p.Y = d-1;
-	if(p.Z > d-1)
-		p.Z = d-1;
-	return p;
-}
-
-inline std::wstring narrow_to_wide(const std::string& mbs)
-{
-	size_t wcl = mbs.size();
-	Buffer<wchar_t> wcs(wcl+1);
-	size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
-	if(l == (size_t)(-1))
-		return L"<invalid multibyte string>";
-	wcs[l] = 0;
-	return *wcs;
-}
-
-inline std::string wide_to_narrow(const std::wstring& wcs)
-{
-	size_t mbl = wcs.size()*4;
-	SharedBuffer<char> mbs(mbl+1);
-	size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
-	if(l == (size_t)(-1))
-		mbs[0] = 0;
-	else
-		mbs[l] = 0;
-	return *mbs;
-}
-
-// Split a string using the given delimiter. Returns a vector containing
-// the component parts.
-inline std::vector<std::wstring> str_split(const std::wstring &str, wchar_t delimiter)
-{
-	std::vector<std::wstring> parts;
-	std::wstringstream sstr(str);
-	std::wstring part;
-	while(std::getline(sstr, part, delimiter))
-		parts.push_back(part);
-	return parts;
-}
-
-
-/*
-	See test.cpp for example cases.
-	wraps degrees to the range of -360...360
-	NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
-*/
-inline float wrapDegrees(float f)
-{
-	// Take examples of f=10, f=720.5, f=-0.5, f=-360.5
-	// This results in
-	// 10, 720, -1, -361
-	int i = floor(f);
-	// 0, 2, 0, -1
-	int l = i / 360;
-	// NOTE: This would be used for wrapping to 0...360
-	// 0, 2, -1, -2
-	/*if(i < 0)
-		l -= 1;*/
-	// 0, 720, 0, -360
-	int k = l * 360;
-	// 10, 0.5, -0.5, -0.5
-	f -= float(k);
-	return f;
-}
-
-/* Wrap to 0...360 */
-inline float wrapDegrees_0_360(float f)
-{
-	// Take examples of f=10, f=720.5, f=-0.5, f=-360.5
-	// This results in
-	// 10, 720, -1, -361
-	int i = floor(f);
-	// 0, 2, 0, -1
-	int l = i / 360;
-	// Wrap to 0...360
-	// 0, 2, -1, -2
-	if(i < 0)
-		l -= 1;
-	// 0, 720, 0, -360
-	int k = l * 360;
-	// 10, 0.5, -0.5, -0.5
-	f -= float(k);
-	return f;
-}
-
-/* Wrap to -180...180 */
-inline float wrapDegrees_180(float f)
-{
-	f += 180;
-	f = wrapDegrees_0_360(f);
-	f -= 180;
-	return f;
-}
-
-inline std::string lowercase(const std::string &s)
-{
-	std::string s2;
-	for(size_t i=0; i<s.size(); i++)
-	{
-		char c = s[i];
-		if(c >= 'A' && c <= 'Z')
-			c -= 'A' - 'a';
-		s2 += c;
-	}
-	return s2;
-}
-
-inline bool is_yes(const std::string &s)
-{
-	std::string s2 = lowercase(trim(s));
-	if(s2 == "y" || s2 == "yes" || s2 == "true" || s2 == "1")
-		return true;
-	return false;
-}
-
-inline s32 mystoi(const std::string &s, s32 min, s32 max)
-{
-	s32 i = atoi(s.c_str());
-	if(i < min)
-		i = min;
-	if(i > max)
-		i = max;
-	return i;
-}
-
-
-// MSVC2010 includes it's own versions of these
-//#if !defined(_MSC_VER) || _MSC_VER < 1600
-
-inline s32 mystoi(const std::string &s)
-{
-	return atoi(s.c_str());
-}
-
-inline s32 mystoi(const std::wstring &s)
-{
-	return atoi(wide_to_narrow(s).c_str());
-}
-
-inline float mystof(const std::string &s)
-{
-	// This crap causes a segfault in certain cases on MinGW
-	/*float f;
-	std::istringstream ss(s);
-	ss>>f;
-	return f;*/
-	// This works in that case
-	return atof(s.c_str());
-}
-
-//#endif
-
-#define stoi mystoi
-#define stof mystof
-
-inline std::string itos(s32 i)
-{
-	std::ostringstream o;
-	o<<i;
-	return o.str();
-}
-
-inline std::string ftos(float f)
-{
-	std::ostringstream o;
-	o<<f;
-	return o.str();
-}
-
-inline void str_replace(std::string & str, std::string const & pattern,
-		std::string const & replacement)
-{
-	std::string::size_type start = str.find(pattern, 0);
-	while(start != str.npos)
-	{
-		str.replace(start, pattern.size(), replacement);
-		start = str.find(pattern, start+replacement.size());
-	}
-}
-
-inline void str_replace_char(std::string & str, char from, char to)
-{
-	for(unsigned int i=0; i<str.size(); i++)
-	{
-		if(str[i] == from)
-			str[i] = to;
-	}
-}
-
-/*
-	A base class for simple background thread implementation
-*/
-
-class SimpleThread : public JThread
-{
-	bool run;
-	JMutex run_mutex;
-
-public:
-
-	SimpleThread():
-		JThread(),
-		run(true)
-	{
-		run_mutex.Init();
-	}
-
-	virtual ~SimpleThread()
-	{}
-
-	virtual void * Thread() = 0;
-
-	bool getRun()
-	{
-		JMutexAutoLock lock(run_mutex);
-		return run;
-	}
-	void setRun(bool a_run)
-	{
-		JMutexAutoLock lock(run_mutex);
-		run = a_run;
-	}
-
-	void stop()
-	{
-		setRun(false);
-		while(IsRunning())
-			sleep_ms(100);
-	}
-};
-
-/*
-	FIFO queue (well, actually a FILO also)
-*/
-template<typename T>
-class Queue
-{
-public:
-	void push_back(T t)
-	{
-		m_list.push_back(t);
-	}
-	
-	T pop_front()
-	{
-		if(m_list.size() == 0)
-			throw ItemNotFoundException("Queue: queue is empty");
-
-		typename core::list<T>::Iterator begin = m_list.begin();
-		T t = *begin;
-		m_list.erase(begin);
-		return t;
-	}
-	T pop_back()
-	{
-		if(m_list.size() == 0)
-			throw ItemNotFoundException("Queue: queue is empty");
-
-		typename core::list<T>::Iterator last = m_list.getLast();
-		T t = *last;
-		m_list.erase(last);
-		return t;
-	}
-
-	u32 size()
-	{
-		return m_list.size();
-	}
-
-protected:
-	core::list<T> m_list;
-};
-
-/*
-	Thread-safe FIFO queue (well, actually a FILO also)
-*/
-
-template<typename T>
-class MutexedQueue
-{
-public:
-	MutexedQueue()
-	{
-		m_mutex.Init();
-	}
-	u32 size()
-	{
-		JMutexAutoLock lock(m_mutex);
-		return m_list.size();
-	}
-	void push_back(T t)
-	{
-		JMutexAutoLock lock(m_mutex);
-		m_list.push_back(t);
-	}
-	T pop_front(u32 wait_time_max_ms=0)
-	{
-		u32 wait_time_ms = 0;
-
-		for(;;)
-		{
-			{
-				JMutexAutoLock lock(m_mutex);
-
-				if(m_list.size() > 0)
-				{
-					typename core::list<T>::Iterator begin = m_list.begin();
-					T t = *begin;
-					m_list.erase(begin);
-					return t;
-				}
-
-				if(wait_time_ms >= wait_time_max_ms)
-					throw ItemNotFoundException("MutexedQueue: queue is empty");
-			}
-
-			// Wait a while before trying again
-			sleep_ms(10);
-			wait_time_ms += 10;
-		}
-	}
-	T pop_back(u32 wait_time_max_ms=0)
-	{
-		u32 wait_time_ms = 0;
-
-		for(;;)
-		{
-			{
-				JMutexAutoLock lock(m_mutex);
-
-				if(m_list.size() > 0)
-				{
-					typename core::list<T>::Iterator last = m_list.getLast();
-					T t = *last;
-					m_list.erase(last);
-					return t;
-				}
-
-				if(wait_time_ms >= wait_time_max_ms)
-					throw ItemNotFoundException("MutexedQueue: queue is empty");
-			}
-
-			// Wait a while before trying again
-			sleep_ms(10);
-			wait_time_ms += 10;
-		}
-	}
-
-	JMutex & getMutex()
-	{
-		return m_mutex;
-	}
-
-	core::list<T> & getList()
-	{
-		return m_list;
-	}
-
-protected:
-	JMutex m_mutex;
-	core::list<T> m_list;
-};
-
-/*
-	A single worker thread - multiple client threads queue framework.
-*/
-
-template<typename Caller, typename Data>
-class CallerInfo
-{
-public:
-	Caller caller;
-	Data data;
-};
-
-template<typename Key, typename T, typename Caller, typename CallerData>
-class GetResult
-{
-public:
-	Key key;
-	T item;
-	core::list<CallerInfo<Caller, CallerData> > callers;
-};
-
-template<typename Key, typename T, typename Caller, typename CallerData>
-class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
-{
-};
-
-template<typename Key, typename T, typename Caller, typename CallerData>
-class GetRequest
-{
-public:
-	GetRequest()
-	{
-		dest = NULL;
-	}
-	GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
-	{
-		dest = a_dest;
-	}
-	GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
-			Key a_key)
-	{
-		dest = a_dest;
-		key = a_key;
-	}
-	~GetRequest()
-	{
-	}
-	
-	Key key;
-	ResultQueue<Key, T, Caller, CallerData> *dest;
-	core::list<CallerInfo<Caller, CallerData> > callers;
-};
-
-template<typename Key, typename T, typename Caller, typename CallerData>
-class RequestQueue
-{
-public:
-	u32 size()
-	{
-		return m_queue.size();
-	}
-
-	void add(Key key, Caller caller, CallerData callerdata,
-			ResultQueue<Key, T, Caller, CallerData> *dest)
-	{
-		JMutexAutoLock lock(m_queue.getMutex());
-		
-		/*
-			If the caller is already on the list, only update CallerData
-		*/
-		for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
-				i = m_queue.getList().begin();
-				i != m_queue.getList().end(); i++)
-		{
-			GetRequest<Key, T, Caller, CallerData> &request = *i;
-
-			if(request.key == key)
-			{
-				for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
-						i = request.callers.begin();
-						i != request.callers.end(); i++)
-				{
-					CallerInfo<Caller, CallerData> &ca = *i;
-					if(ca.caller == caller)
-					{
-						ca.data = callerdata;
-						return;
-					}
-				}
-				CallerInfo<Caller, CallerData> ca;
-				ca.caller = caller;
-				ca.data = callerdata;
-				request.callers.push_back(ca);
-				return;
-			}
-		}
-
-		/*
-			Else add a new request to the queue
-		*/
-
-		GetRequest<Key, T, Caller, CallerData> request;
-		request.key = key;
-		CallerInfo<Caller, CallerData> ca;
-		ca.caller = caller;
-		ca.data = callerdata;
-		request.callers.push_back(ca);
-		request.dest = dest;
-		
-		m_queue.getList().push_back(request);
-	}
-
-	GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
-	{
-		return m_queue.pop_front(wait_if_empty);
-	}
-
-private:
-	MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
-};
-
-/*
-	Pseudo-random (VC++ rand() sucks)
-*/
-int myrand(void);
-void mysrand(unsigned seed);
-#define MYRAND_MAX 32767
-
-int myrand_range(int min, int max);
-
-/*
-	Miscellaneous functions
-*/
-
-bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
-		f32 camera_fov, f32 range, f32 *distance_ptr=NULL);
-
-/*
-	Queue with unique values with fast checking of value existence
-*/
-
-template<typename Value>
-class UniqueQueue
-{
-public:
-	
-	/*
-		Does nothing if value is already queued.
-		Return value:
-			true: value added
-			false: value already exists
-	*/
-	bool push_back(Value value)
-	{
-		// Check if already exists
-		if(m_map.find(value) != NULL)
-			return false;
-
-		// Add
-		m_map.insert(value, 0);
-		m_list.push_back(value);
-		
-		return true;
-	}
-
-	Value pop_front()
-	{
-		typename core::list<Value>::Iterator i = m_list.begin();
-		Value value = *i;
-		m_map.remove(value);
-		m_list.erase(i);
-		return value;
-	}
-
-	u32 size()
-	{
-		assert(m_list.size() == m_map.size());
-		return m_list.size();
-	}
-
-private:
-	core::map<Value, u8> m_map;
-	core::list<Value> m_list;
-};
-
-#if 1
-template<typename Key, typename Value>
-class MutexedMap
-{
-public:
-	MutexedMap()
-	{
-		m_mutex.Init();
-		assert(m_mutex.IsInitialized());
-	}
-	
-	void set(const Key &name, const Value &value)
-	{
-		JMutexAutoLock lock(m_mutex);
-
-		m_values[name] = value;
-	}
-	
-	bool get(const Key &name, Value *result)
-	{
-		JMutexAutoLock lock(m_mutex);
-
-		typename core::map<Key, Value>::Node *n;
-		n = m_values.find(name);
-
-		if(n == NULL)
-			return false;
-		
-		if(result != NULL)
-			*result = n->getValue();
-			
-		return true;
-	}
-
-private:
-	core::map<Key, Value> m_values;
-	JMutex m_mutex;
-};
-#endif
-
-/*
-	Generates ids for comparable values.
-	Id=0 is reserved for "no value".
-
-	Is fast at:
-	- Returning value by id (very fast)
-	- Returning id by value
-	- Generating a new id for a value
-
-	Is not able to:
-	- Remove an id/value pair (is possible to implement but slow)
-*/
-template<typename T>
-class MutexedIdGenerator
-{
-public:
-	MutexedIdGenerator()
-	{
-		m_mutex.Init();
-		assert(m_mutex.IsInitialized());
-	}
-	
-	// Returns true if found
-	bool getValue(u32 id, T &value)
-	{
-		if(id == 0)
-			return false;
-		JMutexAutoLock lock(m_mutex);
-		if(m_id_to_value.size() < id)
-			return false;
-		value = m_id_to_value[id-1];
-		return true;
-	}
-	
-	// If id exists for value, returns the id.
-	// Otherwise generates an id for the value.
-	u32 getId(const T &value)
-	{
-		JMutexAutoLock lock(m_mutex);
-		typename core::map<T, u32>::Node *n;
-		n = m_value_to_id.find(value);
-		if(n != NULL)
-			return n->getValue();
-		m_id_to_value.push_back(value);
-		u32 new_id = m_id_to_value.size();
-		m_value_to_id.insert(value, new_id);
-		return new_id;
-	}
-
-private:
-	JMutex m_mutex;
-	// Values are stored here at id-1 position (id 1 = [0])
-	core::array<T> m_id_to_value;
-	core::map<T, u32> m_value_to_id;
-};
-
-/*
-	Checks if a string contains only supplied characters
-*/
-inline bool string_allowed(const std::string &s, const std::string &allowed_chars)
-{
-	for(u32 i=0; i<s.size(); i++)
-	{
-		bool confirmed = false;
-		for(u32 j=0; j<allowed_chars.size(); j++)
-		{
-			if(s[i] == allowed_chars[j])
-			{
-				confirmed = true;
-				break;
-			}
-		}
-		if(confirmed == false)
-			return false;
-	}
-	return true;
-}
-
-/*
-	Forcefully wraps string into rows using \n
-	(no word wrap, used for showing paths in gui)
-*/
-inline std::string wrap_rows(const std::string &from, u32 rowlen)
-{
-	std::string to;
-	for(u32 i=0; i<from.size(); i++)
-	{
-		if(i != 0 && i%rowlen == 0)
-			to += '\n';
-		to += from[i];
-	}
-	return to;
-}
-
-/*
-	Some helper stuff
-*/
-#define MYMIN(a,b) ((a)<(b)?(a):(b))
-#define MYMAX(a,b) ((a)>(b)?(a):(b))
-
-/*
-	Returns nearest 32-bit integer for given floating point number.
-	<cmath> and <math.h> in VC++ don't provide round().
-*/
-inline s32 myround(f32 f)
-{
-	return floor(f + 0.5);
-}
-
-/*
-	Returns integer position of node in given floating point position
-*/
-inline v3s16 floatToInt(v3f p, f32 d)
-{
-	v3s16 p2(
-		(p.X + (p.X>0 ? d/2 : -d/2))/d,
-		(p.Y + (p.Y>0 ? d/2 : -d/2))/d,
-		(p.Z + (p.Z>0 ? d/2 : -d/2))/d);
-	return p2;
-}
-
-/*
-	Returns floating point position of node in given integer position
-*/
-inline v3f intToFloat(v3s16 p, f32 d)
-{
-	v3f p2(
-		(f32)p.X * d,
-		(f32)p.Y * d,
-		(f32)p.Z * d
-	);
-	return p2;
-}
-
-/*
-	More serialization stuff
-*/
-
-// Creates a string with the length as the first two bytes
-inline std::string serializeString(const std::string &plain)
-{
-	//assert(plain.size() <= 65535);
-	if(plain.size() > 65535)
-		throw SerializationError("String too long for serializeString");
-	char buf[2];
-	writeU16((u8*)&buf[0], plain.size());
-	std::string s;
-	s.append(buf, 2);
-	s.append(plain);
-	return s;
-}
-
-// Creates a string with the length as the first two bytes from wide string
-inline std::string serializeWideString(const std::wstring &plain)
-{
-	//assert(plain.size() <= 65535);
-	if(plain.size() > 65535)
-		throw SerializationError("String too long for serializeString");
-	char buf[2];
-	writeU16((u8*)buf, plain.size());
-	std::string s;
-	s.append(buf, 2);
-	for(u32 i=0; i<plain.size(); i++)
-	{
-		writeU16((u8*)buf, plain[i]);
-		s.append(buf, 2);
-	}
-	return s;
-}
-
-// Reads a string with the length as the first two bytes
-inline std::string deSerializeString(std::istream &is)
-{
-	char buf[2];
-	is.read(buf, 2);
-	if(is.gcount() != 2)
-		throw SerializationError("deSerializeString: size not read");
-	u16 s_size = readU16((u8*)buf);
-	if(s_size == 0)
-		return "";
-	Buffer<char> buf2(s_size);
-	is.read(&buf2[0], s_size);
-	std::string s;
-	s.reserve(s_size);
-	s.append(&buf2[0], s_size);
-	return s;
-}
-
-// Reads a wide string with the length as the first two bytes
-inline std::wstring deSerializeWideString(std::istream &is)
-{
-	char buf[2];
-	is.read(buf, 2);
-	if(is.gcount() != 2)
-		throw SerializationError("deSerializeString: size not read");
-	u16 s_size = readU16((u8*)buf);
-	if(s_size == 0)
-		return L"";
-	std::wstring s;
-	s.reserve(s_size);
-	for(u32 i=0; i<s_size; i++)
-	{
-		is.read(&buf[0], 2);
-		wchar_t c16 = readU16((u8*)buf);
-		s.append(&c16, 1);
-	}
-	return s;
-}
-
-// Creates a string with the length as the first four bytes
-inline std::string serializeLongString(const std::string &plain)
-{
-	char buf[4];
-	writeU32((u8*)&buf[0], plain.size());
-	std::string s;
-	s.append(buf, 4);
-	s.append(plain);
-	return s;
-}
-
-// Reads a string with the length as the first four bytes
-inline std::string deSerializeLongString(std::istream &is)
-{
-	char buf[4];
-	is.read(buf, 4);
-	if(is.gcount() != 4)
-		throw SerializationError("deSerializeLongString: size not read");
-	u32 s_size = readU32((u8*)buf);
-	if(s_size == 0)
-		return "";
-	Buffer<char> buf2(s_size);
-	is.read(&buf2[0], s_size);
-	std::string s;
-	s.reserve(s_size);
-	s.append(&buf2[0], s_size);
-	return s;
-}
-
-// Creates a string encoded in JSON format (almost equivalent to a C string literal)
-std::string serializeJsonString(const std::string &plain);
-
-// Reads a string encoded in JSON format
-std::string deSerializeJsonString(std::istream &is);
-
-//
-
-// Random helper. Usually d=BS
-inline core::aabbox3d<f32> getNodeBox(v3s16 p, float d)
-{
-	return core::aabbox3d<f32>(
-		(float)p.X * d - 0.5*d,
-		(float)p.Y * d - 0.5*d,
-		(float)p.Z * d - 0.5*d,
-		(float)p.X * d + 0.5*d,
-		(float)p.Y * d + 0.5*d,
-		(float)p.Z * d + 0.5*d
-	);
-}
-	
-class IntervalLimiter
-{
-public:
-	IntervalLimiter():
-		m_accumulator(0)
-	{
-	}
-	/*
-		dtime: time from last call to this method
-		wanted_interval: interval wanted
-		return value:
-			true: action should be skipped
-			false: action should be done
-	*/
-	bool step(float dtime, float wanted_interval)
-	{
-		m_accumulator += dtime;
-		if(m_accumulator < wanted_interval)
-			return false;
-		m_accumulator -= wanted_interval;
-		return true;
-	}
-protected:
-	float m_accumulator;
-};
-
-/*
-	Splits a list into "pages". For example, the list [1,2,3,4,5] split
-	into two pages would be [1,2,3],[4,5]. This function computes the
-	minimum and maximum indices of a single page.
-
-	length: Length of the list that should be split
-	page: Page number, 1 <= page <= pagecount
-	pagecount: The number of pages, >= 1
-	minindex: Receives the minimum index (inclusive).
-	maxindex: Receives the maximum index (exclusive).
-
-	Ensures 0 <= minindex <= maxindex <= length.
-*/
-inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxindex)
-{
-	if(length < 1 || pagecount < 1 || page < 1 || page > pagecount)
-	{
-		// Special cases or invalid parameters
-		minindex = maxindex = 0;
-	}
-	else if(pagecount <= length)
-	{
-		// Less pages than entries in the list:
-		// Each page contains at least one entry
-		minindex = (length * (page-1) + (pagecount-1)) / pagecount;
-		maxindex = (length * page + (pagecount-1)) / pagecount;
-	}
-	else
-	{
-		// More pages than entries in the list:
-		// Make sure the empty pages are at the end
-		if(page < length)
-		{
-			minindex = page-1;
-			maxindex = page;
-		}
-		else
-		{
-			minindex = 0;
-			maxindex = 0;
-		}
-	}
-}
-
-std::string translatePassword(std::string playername, std::wstring password);
-
-enum PointedThingType
-{
-	POINTEDTHING_NOTHING,
-	POINTEDTHING_NODE,
-	POINTEDTHING_OBJECT
-};
-
-struct PointedThing
-{
-	PointedThingType type;
-	v3s16 node_undersurface;
-	v3s16 node_abovesurface;
-	s16 object_id;
-
-	PointedThing();
-	std::string dump() const;
-	void serialize(std::ostream &os) const;
-	void deSerialize(std::istream &is);
-	bool operator==(const PointedThing &pt2) const;
-	bool operator!=(const PointedThing &pt2) const;
-};
+// Headers whose content was previously here
+#include "util/serialize.h"
+#include "util/directiontables.h"
+#include "util/pointer.h"
+#include "util/string.h"
+#include "util/container.h"
+#include "util/thread.h"
+#include "util/numeric.h"
+#include "util/timetaker.h"
+#include "util/pointedthing.h"
 
 #endif
 
diff --git a/src/utility_string.h b/src/utility_string.h
deleted file mode 100644
index 903cd3dcb..000000000
--- a/src/utility_string.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-Minetest-c55
-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 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.
-*/
-
-#ifndef UTILITY_STRING_HEADER
-#define UTILITY_STRING_HEADER
-
-// Note: Some stuff could be moved to here from utility.h
-
-#include <string>
-
-static inline std::string padStringRight(std::string s, size_t len)
-{
-	if(len > s.size())
-		s.insert(s.end(), len - s.size(), ' ');
-	return s;
-}
-
-// ends: NULL- or ""-terminated array of strings
-// Returns "" if no end could be removed.
-static inline std::string removeStringEnd(const std::string &s, const char *ends[])
-{
-	const char **p = ends;
-	for(; (*p) && (*p)[0] != '\0'; p++){
-		std::string end = *p;
-		if(s.size() < end.size())
-			continue;
-		if(s.substr(s.size()-end.size(), end.size()) == end)
-			return s.substr(0, s.size() - end.size());
-	}
-	return "";
-}
-
-#endif
-
-- 
cgit v1.2.3