aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/client.cpp2
-rw-r--r--src/constants.h13
-rw-r--r--src/debug.h12
-rw-r--r--src/filecache.cpp3
-rw-r--r--src/main.cpp2
-rw-r--r--src/player.h1
-rw-r--r--src/porting.cpp2
-rw-r--r--src/server.cpp2
-rw-r--r--src/sound_openal.cpp5
-rw-r--r--src/subgame.cpp2
-rw-r--r--src/test.cpp2
-rw-r--r--src/tile.cpp2
-rw-r--r--src/util/container.h305
-rw-r--r--src/util/directiontables.cpp101
-rw-r--r--src/util/directiontables.h33
-rw-r--r--src/util/numeric.cpp202
-rw-r--r--src/util/numeric.h331
-rw-r--r--src/util/pointedthing.cpp125
-rw-r--r--src/util/pointedthing.h50
-rw-r--r--src/util/pointer.h298
-rw-r--r--src/util/serialize.cpp119
-rw-r--r--src/util/serialize.h456
-rw-r--r--src/util/string.cpp (renamed from src/utility_string.h)47
-rw-r--r--src/util/string.h264
-rw-r--r--src/util/thread.h227
-rw-r--r--src/util/timetaker.cpp61
-rw-r--r--src/util/timetaker.h51
-rw-r--r--src/utility.cpp434
-rw-r--r--src/utility.h1852
30 files changed, 2684 insertions, 2326 deletions
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
@@ -31,19 +31,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/utility_string.h b/src/util/string.cpp
index 903cd3dcb..ee4df849e 100644
--- a/src/utility_string.h
+++ b/src/util/string.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,34 +17,27 @@ 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
+#include "string.h"
-// Note: Some stuff could be moved to here from utility.h
+#include "sha1.h"
+#include "base64.h"
-#include <string>
-
-static inline std::string padStringRight(std::string s, size_t len)
+// 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(len > s.size())
- s.insert(s.end(), len - s.size(), ' ');
- return s;
+ 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;
}
-// 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
-
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