]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/utility.h
All textures are are now searched first from the directory specified by the texture_p...
[dragonfireclient.git] / src / utility.h
index deaa78d90a7bb8735c8b295358f18b617896d113..cc8891a0797c1345d0325460c8a4821c373528c9 100644 (file)
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <fstream>
 #include <string>
 #include <sstream>
+#include <vector>
 #include <jthread.h>
 #include <jmutex.h>
 #include <jmutexautolock.h>
@@ -34,11 +35,25 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #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);
@@ -58,6 +73,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);
@@ -73,8 +96,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);
 }
@@ -82,6 +103,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);
 }
@@ -95,7 +123,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;
@@ -105,6 +132,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);
@@ -149,6 +191,62 @@ 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 writeF1000(std::ostream &os, f32 p)
+{
+       char buf[2];
+       writeF1000((u8*)buf, p);
+       os.write(buf, 2);
+}
+inline f32 readF1000(std::istream &is)
+{
+       char buf[2];
+       is.read(buf, 2);
+       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
 */
@@ -399,8 +497,6 @@ class MutexedVariable
        TimeTaker
 */
 
-class IrrlichtWrapper;
-
 class TimeTaker
 {
 public:
@@ -616,8 +712,10 @@ inline v3s16 arealim(v3s16 p, s16 d)
 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;
 }
@@ -627,13 +725,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
@@ -689,11 +800,20 @@ inline s32 stoi(const 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;
@@ -702,6 +822,8 @@ inline float stof(std::string s)
        return f;
 }
 
+#endif
+
 inline std::string itos(s32 i)
 {
        std::ostringstream o;
@@ -802,9 +924,15 @@ struct ValueSpec
 class Settings
 {
 public:
+       Settings()
+       {
+               m_mutex.Init();
+       }
 
        void writeLines(std::ostream &os)
        {
+               JMutexAutoLock lock(m_mutex);
+               
                for(core::map<std::string, std::string>::Iterator
                                i = m_settings.getIterator();
                                i.atEnd() == false; i++)
@@ -817,6 +945,8 @@ class Settings
 
        bool parseConfigLine(const std::string &line)
        {
+               JMutexAutoLock lock(m_mutex);
+               
                std::string trimmedline = trim(line);
                
                // Ignore comments
@@ -899,6 +1029,8 @@ class Settings
                        core::list<std::string> &dst,
                        core::map<std::string, bool> &updated)
        {
+               JMutexAutoLock lock(m_mutex);
+               
                if(is.eof())
                        return false;
                
@@ -970,15 +1102,19 @@ class Settings
                        std::ifstream is(filename);
                        if(is.good() == false)
                        {
-                               dstream<<"Error opening configuration file"
+                               dstream<<"INFO: updateConfigFile():"
+                                               " Error opening configuration file"
                                                " for reading: \""
                                                <<filename<<"\""<<std::endl;
-                               return false;
                        }
-
-                       while(getUpdatedConfigObject(is, objects, updated));
+                       else
+                       {
+                               while(getUpdatedConfigObject(is, objects, updated));
+                       }
                }
                
+               JMutexAutoLock lock(m_mutex);
+               
                // Write stuff back
                {
                        std::ofstream os(filename);
@@ -1085,21 +1221,29 @@ class Settings
 
        void set(std::string name, std::string value)
        {
+               JMutexAutoLock lock(m_mutex);
+               
                m_settings[name] = value;
        }
 
        void setDefault(std::string name, std::string value)
        {
+               JMutexAutoLock lock(m_mutex);
+               
                m_defaults[name] = value;
        }
 
        bool exists(std::string name)
        {
+               JMutexAutoLock lock(m_mutex);
+               
                return (m_settings.find(name) || m_defaults.find(name));
        }
 
        std::string get(std::string name)
        {
+               JMutexAutoLock lock(m_mutex);
+               
                core::map<std::string, std::string>::Node *n;
                n = m_settings.find(name);
                if(n == NULL)
@@ -1137,7 +1281,7 @@ class Settings
        bool getBoolAsk(std::string name, std::string question, bool def)
        {
                // If it is in settings
-               if(m_settings.find(name))
+               if(exists(name))
                        return getBool(name);
                
                std::string s;
@@ -1165,7 +1309,7 @@ class Settings
        u16 getU16Ask(std::string name, std::string question, u16 def)
        {
                // If it is in settings
-               if(m_settings.find(name))
+               if(exists(name))
                        return getU16(name);
                
                std::string s;
@@ -1201,6 +1345,23 @@ class Settings
                return value;
        }
 
+       u64 getU64(std::string name)
+       {
+               u64 value = 0;
+               std::string s = get(name);
+               std::istringstream ss(s);
+               ss>>value;
+               return value;
+       }
+
+       void setBool(std::string name, bool value)
+       {
+               if(value)
+                       set(name, "true");
+               else
+                       set(name, "false");
+       }
+
        void setS32(std::string name, s32 value)
        {
                set(name, itos(value));
@@ -1218,14 +1379,26 @@ class Settings
                set(name, os.str());
        }
 
+       void setU64(std::string name, u64 value)
+       {
+               std::ostringstream os;
+               os<<value;
+               set(name, os.str());
+       }
+
        void clear()
        {
+               JMutexAutoLock lock(m_mutex);
+               
                m_settings.clear();
                m_defaults.clear();
        }
 
        Settings & operator+=(Settings &other)
        {
+               JMutexAutoLock lock(m_mutex);
+               JMutexAutoLock lock2(other.m_mutex);
+               
                if(&other == this)
                        return *this;
 
@@ -1249,6 +1422,9 @@ class Settings
 
        Settings & operator=(Settings &other)
        {
+               JMutexAutoLock lock(m_mutex);
+               JMutexAutoLock lock2(other.m_mutex);
+               
                if(&other == this)
                        return *this;
 
@@ -1261,10 +1437,12 @@ class Settings
 private:
        core::map<std::string, std::string> m_settings;
        core::map<std::string, std::string> m_defaults;
+       // All methods that access m_settings/m_defaults directly should lock this.
+       JMutex m_mutex;
 };
 
 /*
-       FIFO queue
+       FIFO queue (well, actually a FILO also)
 */
 template<typename T>
 class Queue
@@ -1278,13 +1456,23 @@ class Queue
        T pop_front()
        {
                if(m_list.size() == 0)
-                       throw ItemNotFoundException("MutexedQueue: queue is empty");
+                       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()
        {
@@ -1296,7 +1484,7 @@ class Queue
 };
 
 /*
-       Thread-safe FIFO queue
+       Thread-safe FIFO queue (well, actually a FILO also)
 */
 
 template<typename T>
@@ -1309,6 +1497,7 @@ class MutexedQueue
        }
        u32 size()
        {
+               JMutexAutoLock lock(m_mutex);
                return m_list.size();
        }
        void push_back(T t)
@@ -1342,6 +1531,32 @@ class MutexedQueue
                        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()
        {
@@ -1358,6 +1573,10 @@ class MutexedQueue
        core::list<T> m_list;
 };
 
+/*
+       A single worker thread - multiple client threads queue framework.
+*/
+
 template<typename Caller, typename Data>
 class CallerInfo
 {
@@ -1407,11 +1626,6 @@ class GetRequest
        core::list<CallerInfo<Caller, CallerData> > callers;
 };
 
-/*
-       Quickhands for typical request-result queues.
-       Used for distributing work between threads.
-*/
-
 template<typename Key, typename T, typename Caller, typename CallerData>
 class RequestQueue
 {
@@ -1552,12 +1766,12 @@ class UniqueQueue
        core::list<Value> m_list;
 };
 
-#if 0
+#if 1
 template<typename Key, typename Value>
-class MutexedCache
+class MutexedMap
 {
 public:
-       MutexedCache()
+       MutexedMap()
        {
                m_mutex.Init();
                assert(m_mutex.IsInitialized());
@@ -1579,8 +1793,10 @@ class MutexedCache
 
                if(n == NULL)
                        return false;
-
-               *result = n->getValue();
+               
+               if(result != NULL)
+                       *result = n->getValue();
+                       
                return true;
        }
 
@@ -1668,11 +1884,199 @@ inline bool string_allowed(const std::string &s, const std::string &allowed_char
        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 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;
+}
+
+/*// Reads a string with the length as the first two bytes
+inline std::string deSerializeString(const std::string encoded)
+{
+       u16 s_size = readU16((u8*)&encoded.c_str()[0]);
+       if(s_size > encoded.length() - 2)
+               return "";
+       std::string s;
+       s.reserve(s_size);
+       s.append(&encoded.c_str()[2], s_size);
+       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;
+}
+
+// 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(const std::string encoded)
+{
+       u32 s_size = readU32((u8*)&encoded.c_str()[0]);
+       if(s_size > encoded.length() - 4)
+               return "";
+       std::string s;
+       s.reserve(s_size);
+       s.append(&encoded.c_str()[4], s_size);
+       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;
+};
+
+
 #endif