]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/utility.h
Use the logger; also, default to not showing much crap in console. Use --info-on...
[dragonfireclient.git] / src / utility.h
index c9b13546c8f8d455fd9e6f2f117fd74b7e3b8a84..c741ab0477e123ce2663ecc89cfa8e145fc75235 100644 (file)
@@ -17,24 +17,44 @@ 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>
-*/
-
 #ifndef UTILITY_HEADER
 #define UTILITY_HEADER
 
-#include "common_irrlicht.h"
-#include "debug.h"
-#include "strfnd.h"
-#include "exceptions.h"
 #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 "strfnd.h"
+#include "exceptions.h"
+#include "porting.h"
+
+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);
@@ -54,6 +74,14 @@ 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);
@@ -69,8 +97,6 @@ inline u8 readU8(u8 *data)
        return (data[0]<<0);
 }
 
-// Signed variants of the above
-
 inline void writeS32(u8 *data, s32 i){
        writeU32(data, (u32)i);
 }
@@ -78,6 +104,13 @@ inline s32 readS32(u8 *data){
        return (s32)readU32(data);
 }
 
+inline void writeF1000(u8 *data, f32 i){
+       writeS32(data, i*1000);
+}
+inline f32 readF1000(u8 *data){
+       return (f32)readS32(data)/1000.;
+}
+
 inline void writeS16(u8 *data, s16 i){
        writeU16(data, (u16)i);
 }
@@ -91,7 +124,6 @@ inline void writeV3S32(u8 *data, v3s32 p)
        writeS32(&data[4], p.Y);
        writeS32(&data[8], p.Z);
 }
-
 inline v3s32 readV3S32(u8 *data)
 {
        v3s32 p;
@@ -101,6 +133,21 @@ inline v3s32 readV3S32(u8 *data)
        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 writeV2S16(u8 *data, v2s16 p)
 {
        writeS16(&data[0], p.X);
@@ -145,6 +192,75 @@ inline v3s16 readV3S16(u8 *data)
        return p;
 }
 
+/*
+       The above stuff directly interfaced to iostream
+*/
+
+inline void writeU8(std::ostream &os, u8 p)
+{
+       char buf[1];
+       writeU8((u8*)buf, p);
+       os.write(buf, 1);
+}
+inline u8 readU8(std::istream &is)
+{
+       char buf[1];
+       is.read(buf, 1);
+       return readU8((u8*)buf);
+}
+
+inline void writeU16(std::ostream &os, u16 p)
+{
+       char buf[2];
+       writeU16((u8*)buf, p);
+       os.write(buf, 2);
+}
+inline u16 readU16(std::istream &is)
+{
+       char buf[2];
+       is.read(buf, 2);
+       return readU16((u8*)buf);
+}
+
+inline void writeU32(std::ostream &os, u16 p)
+{
+       char buf[4];
+       writeU16((u8*)buf, p);
+       os.write(buf, 4);
+}
+inline u16 readU32(std::istream &is)
+{
+       char buf[4];
+       is.read(buf, 4);
+       return readU32((u8*)buf);
+}
+
+inline void writeF1000(std::ostream &os, f32 p)
+{
+       char buf[4];
+       writeF1000((u8*)buf, p);
+       os.write(buf, 4);
+}
+inline f32 readF1000(std::istream &is)
+{
+       char buf[4];
+       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);
+}
+
 /*
        None of these are used at the moment
 */
@@ -203,6 +319,10 @@ class SharedPtr
        {
                return ptr == t;
        }
+       T & operator[](unsigned int i)
+       {
+               return ptr[i];
+       }
 private:
        void drop()
        {
@@ -265,10 +385,20 @@ 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;
-               data = new T[size];
+               if(m_size != 0)
+                       data = new T[m_size];
+               else
+                       data = NULL;
                refcount = new unsigned int;
                (*refcount) = 1;
        }
@@ -298,8 +428,13 @@ class SharedBuffer
        SharedBuffer(T *t, unsigned int size)
        {
                m_size = size;
-               data = new T[size];
-               memcpy(data, t, size);
+               if(m_size != 0)
+               {
+                       data = new T[m_size];
+                       memcpy(data, t, m_size);
+               }
+               else
+                       data = NULL;
                refcount = new unsigned int;
                (*refcount) = 1;
        }
@@ -308,9 +443,14 @@ class SharedBuffer
        */
        SharedBuffer(const Buffer<T> &buffer)
        {
-               m_size = buffer.m_size;
-               data = new T[buffer.getSize()];
-               memcpy(data, *buffer, buffer.getSize());
+               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;
        }
@@ -320,6 +460,7 @@ class SharedBuffer
        }
        T & operator[](unsigned int i) const
        {
+               //assert(i < m_size)
                return data[i];
        }
        T * operator*() const
@@ -337,7 +478,8 @@ class SharedBuffer
                (*refcount)--;
                if(*refcount == 0)
                {
-                       delete[] data;
+                       if(data)
+                               delete[] data;
                        delete refcount;
                }
        }
@@ -394,58 +536,29 @@ class MutexedVariable
 class TimeTaker
 {
 public:
-       TimeTaker(const char *name, IrrlichtDevice *dev, u32 *result=NULL)
-       {
-               m_name = name;
-               m_dev = dev;
-               m_result = result;
-               m_running = true;
-               if(dev == NULL)
-               {
-                       m_time1 = 0;
-                       return;
-               }
-               m_time1 = m_dev->getTimer()->getRealTime();
-       }
+       TimeTaker(const char *name, u32 *result=NULL);
+
        ~TimeTaker()
        {
                stop();
        }
-       u32 stop(bool quiet=false)
-       {
-               if(m_running)
-               {
-                       if(m_dev == NULL)
-                       {
-                               /*if(quiet == false)
-                                       std::cout<<"Couldn't measure time for "<<m_name
-                                                       <<": dev==NULL"<<std::endl;*/
-                               return 0;
-                       }
-                       u32 time2 = m_dev->getTimer()->getRealTime();
-                       u32 dtime = time2 - m_time1;
-                       if(m_result != NULL)
-                       {
-                               (*m_result) += dtime;
-                       }
-                       else
-                       {
-                               if(quiet == false)
-                                       std::cout<<m_name<<" took "<<dtime<<"ms"<<std::endl;
-                       }
-                       m_running = false;
-                       return dtime;
-               }
-               return 0;
-       }
+
+       u32 stop(bool quiet=false);
+
+       u32 getTime();
+
 private:
        const char *m_name;
-       IrrlichtDevice *m_dev;
        u32 m_time1;
        bool m_running;
        u32 *m_result;
 };
 
+#ifndef SERVER
+// Sets the color of all vertices in the mesh
+void setMeshVerticesColor(scene::IMesh* mesh, video::SColor& color);
+#endif
+
 // Calculates the borders of a "d-radius" cube
 inline void getFacePositions(core::list<v3s16> &list, u16 d)
 {
@@ -459,12 +572,12 @@ inline void getFacePositions(core::list<v3s16> &list, u16 d)
                /*
                        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
-               list.push_back(v3s16( 0, 1, 0)); // top
                // 6
                list.push_back(v3s16(-1, 0, 1)); // back left
                list.push_back(v3s16( 1, 0, 1)); // back right
@@ -566,6 +679,23 @@ inline v3s16 getContainerPos(v3s16 p, s16 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 (
@@ -583,11 +713,50 @@ inline bool isInArea(v2s16 p, s16 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();
-       SharedBuffer<wchar_t> wcs(wcl+1);
+       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;
 }
@@ -597,13 +766,26 @@ 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((int)l == -1)
+       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
@@ -628,25 +810,57 @@ inline float wrapDegrees(float f)
        return f;
 }
 
-inline std::string lowercase(std::string s)
+/* 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++)
        {
-               if(s[i] >= 'A' && s[i] <= 'Z')
-                       s[i] -= 'A' - 'a';
+               char c = s[i];
+               if(c >= 'A' && c <= 'Z')
+                       c -= 'A' - 'a';
+               s2 += c;
        }
-       return s;
+       return s2;
 }
 
-inline bool is_yes(std::string s)
+inline bool is_yes(const std::string &s)
 {
-       s = lowercase(trim(s));
-       if(s == "y" || s == "yes" || s == "true")
+       std::string s2 = lowercase(trim(s));
+       if(s2 == "y" || s2 == "yes" || s2 == "true" || s2 == "1")
                return true;
        return false;
 }
 
-inline s32 stoi(std::string s, s32 min, s32 max)
+inline s32 stoi(const std::string &s, s32 min, s32 max)
 {
        s32 i = atoi(s.c_str());
        if(i < min)
@@ -656,157 +870,750 @@ inline s32 stoi(std::string s, s32 min, s32 max)
        return i;
 }
 
+
+// MSVC2010 includes it's own versions of these
+#if !defined(_MSC_VER) || _MSC_VER < 1600
+
 inline s32 stoi(std::string s)
 {
        return atoi(s.c_str());
 }
 
+inline s32 stoi(std::wstring s)
+{
+       return atoi(wide_to_narrow(s).c_str());
+}
+
+inline float stof(std::string s)
+{
+       float f;
+       std::istringstream ss(s);
+       ss>>f;
+       return f;
+}
+
+#endif
+
+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;
+       }
+}
+
 /*
-       Config stuff
+       A base class for simple background thread implementation
 */
 
-class Settings
+class SimpleThread : public JThread
 {
+       bool run;
+       JMutex run_mutex;
+
 public:
 
-       // Returns false on EOF
-       bool parseConfigObject(std::istream &is)
+       SimpleThread():
+               JThread(),
+               run(true)
        {
-               if(is.eof())
-                       return false;
-               
-               // NOTE: This function will be expanded to allow multi-line settings
-               std::string line;
-               std::getline(is, line);
-               //dstream<<"got line: \""<<line<<"\""<<std::endl;
+               run_mutex.Init();
+       }
 
-               std::string trimmedline = trim(line);
-               
-               // Ignore comments
-               if(trimmedline[0] == '#')
-                       return true;
+       virtual ~SimpleThread()
+       {}
 
-               //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
+       virtual void * Thread() = 0;
 
-               Strfnd sf(trim(line));
+       bool getRun()
+       {
+               JMutexAutoLock lock(run_mutex);
+               return run;
+       }
+       void setRun(bool a_run)
+       {
+               JMutexAutoLock lock(run_mutex);
+               run = a_run;
+       }
 
-               std::string name = sf.next("=");
-               name = trim(name);
+       void stop()
+       {
+               setRun(false);
+               while(IsRunning())
+                       sleep_ms(100);
+       }
+};
 
-               if(name == "")
-                       return true;
-               
-               std::string value = sf.next("\n");
-               value = trim(value);
+/*
+       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");
 
-               dstream<<"Config name=\""<<name<<"\" value=\""
-                               <<value<<"\""<<std::endl;
-               
-               m_settings[name] = value;
-               
-               return true;
+               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");
+                       }
 
-       // Returns true on success
-       bool readConfigFile(const char *filename)
+                       // Wait a while before trying again
+                       sleep_ms(10);
+                       wait_time_ms += 10;
+               }
+       }
+       T pop_back(u32 wait_time_max_ms=0)
        {
-               std::ifstream is(filename);
-               if(is.good() == false)
+               u32 wait_time_ms = 0;
+
+               for(;;)
                {
-                       dstream<<"Error opening configuration file: "
-                                       <<filename<<std::endl;
-                       return false;
+                       {
+                               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;
                }
+       }
 
-               dstream<<"Parsing configuration file: "
-                               <<filename<<std::endl;
-                               
-               while(parseConfigObject(is));
-               
-               return true;
+       JMutex & getMutex()
+       {
+               return m_mutex;
        }
 
-       void set(std::string name, std::string value)
+       core::list<T> & getList()
        {
-               m_settings[name] = value;
+               return m_list;
        }
 
-       std::string get(std::string name)
+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()
        {
-               core::map<std::string, std::string>::Node *n;
-               n = m_settings.find(name);
-               if(n == NULL)
-                       throw SettingNotFoundException("Setting not found");
+               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;
+};
 
-               return n->getValue();
+template<typename Key, typename T, typename Caller, typename CallerData>
+class RequestQueue
+{
+public:
+       u32 size()
+       {
+               return m_queue.size();
        }
 
-       bool getBool(std::string name)
+       void add(Key key, Caller caller, CallerData callerdata,
+                       ResultQueue<Key, T, Caller, CallerData> *dest)
        {
-               return is_yes(get(name));
+               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:
        
-       // Asks if empty
-       bool getBoolAsk(std::string name, std::string question, bool def)
+       /*
+               Does nothing if value is already queued.
+               Return value:
+                       true: value added
+                       false: value already exists
+       */
+       bool push_back(Value value)
        {
-               std::string s = get(name);
-               if(s != "")
-                       return is_yes(s);
-               
-               char templine[10];
-               std::cout<<question<<" [y/N]: ";
-               std::cin.getline(templine, 10);
-               s = templine;
+               // Check if already exists
+               if(m_map.find(value) != NULL)
+                       return false;
 
-               if(s == "")
-                       return def;
+               // Add
+               m_map.insert(value, 0);
+               m_list.push_back(value);
+               
+               return true;
+       }
 
-               return is_yes(s);
+       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;
        }
 
-       float getFloat(std::string name)
+       u32 size()
        {
-               float f;
-               std::istringstream vis(get(name));
-               vis>>f;
-               return f;
+               assert(m_list.size() == m_map.size());
+               return m_list.size();
        }
 
-       u16 getU16(std::string name)
+private:
+       core::map<Value, u8> m_map;
+       core::list<Value> m_list;
+};
+
+#if 1
+template<typename Key, typename Value>
+class MutexedMap
+{
+public:
+       MutexedMap()
        {
-               return stoi(get(name), 0, 65535);
+               m_mutex.Init();
+               assert(m_mutex.IsInitialized());
        }
+       
+       void set(const Key &name, const Value &value)
+       {
+               JMutexAutoLock lock(m_mutex);
 
-       u16 getU16Ask(std::string name, std::string question, u16 def)
+               m_values[name] = value;
+       }
+       
+       bool get(const Key &name, Value *result)
        {
-               std::string s = get(name);
-               if(s != "")
-                       return stoi(s, 0, 65535);
+               JMutexAutoLock lock(m_mutex);
+
+               typename core::map<Key, Value>::Node *n;
+               n = m_values.find(name);
+
+               if(n == NULL)
+                       return false;
                
-               char templine[10];
-               std::cout<<question<<" ["<<def<<"]: ";
-               std::cin.getline(templine, 10);
-               s = templine;
+               if(result != NULL)
+                       *result = n->getValue();
+                       
+               return true;
+       }
+
+private:
+       core::map<Key, Value> m_values;
+       JMutex m_mutex;
+};
+#endif
 
-               if(s == "")
-                       return def;
+/*
+       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
 
-               return stoi(s, 0, 65535);
+       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;
        }
 
-       s16 getS16(std::string name)
+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++)
        {
-               return stoi(get(name), -32768, 32767);
+               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;
+}
 
-       s32 getS32(std::string name)
+/*
+       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++)
        {
-               return stoi(get(name));
+               if(i != 0 && i%rowlen == 0)
+                       to += '\n';
+               to += from[i];
        }
+       return to;
+}
 
-private:
-       core::map<std::string, std::string> m_settings;
+/*
+       Some helper stuff
+*/
+#define MYMIN(a,b) ((a)<(b)?(a):(b))
+#define MYMAX(a,b) ((a)>(b)?(a):(b))
+
+/*
+       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;
+}
+
+//
+
+inline u32 time_to_daynight_ratio(u32 time_of_day)
+{
+       const s32 daylength = 16;
+       const s32 nightlength = 6;
+       const s32 daytimelength = 8;
+       s32 d = daylength;
+       s32 t = (((time_of_day)%24000)/(24000/d));
+       if(t < nightlength/2 || t >= d - nightlength/2)
+               //return 300;
+               return 350;
+       else if(t >= d/2 - daytimelength/2 && t < d/2 + daytimelength/2)
+               return 1000;
+       else
+               return 750;
+}
+
+// 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;
 };
 
+std::string translatePassword(std::string playername, std::wstring password);
+
 #endif