X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Futility.h;h=07216a27decfb89a84762e5768c7eab70d351ba7;hb=ef0ec3155440b770103cc5ad36819659d7ce2c1b;hp=b517848b1223440d9dc3564d3d3828134075405e;hpb=bd100c5483eb77a27eeac4e476c81a1bf6afc710;p=dragonfireclient.git diff --git a/src/utility.h b/src/utility.h index b517848b1..07216a27d 100644 --- a/src/utility.h +++ b/src/utility.h @@ -24,21 +24,37 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include #include #include #include +#include #include "common_irrlicht.h" #include "debug.h" -#include "strfnd.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); @@ -58,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); @@ -73,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); } @@ -89,13 +111,26 @@ 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; @@ -105,6 +140,34 @@ 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 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); @@ -149,6 +212,153 @@ 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, u32 p) +{ + char buf[4]; + writeU32((u8*)buf, p); + os.write(buf, 4); +} +inline u32 readU32(std::istream &is) +{ + char buf[4]; + is.read(buf, 4); + return readU32((u8*)buf); +} + +inline void writeS32(std::ostream &os, s32 p) +{ + char buf[4]; + writeS32((u8*)buf, p); + os.write(buf, 4); +} +inline s32 readS32(std::istream &is) +{ + char buf[4]; + is.read(buf, 4); + return readS32((u8*)buf); +} + +inline void writeS16(std::ostream &os, s16 p) +{ + char buf[2]; + writeS16((u8*)buf, p); + os.write(buf, 2); +} +inline s16 readS16(std::istream &is) +{ + char buf[2]; + is.read(buf, 2); + return readS16((u8*)buf); +} + +inline void writeS8(std::ostream &os, s8 p) +{ + char buf[1]; + writeS8((u8*)buf, p); + os.write(buf, 1); +} +inline s8 readS8(std::istream &is) +{ + char buf[1]; + is.read(buf, 1); + return readS8((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); +} + +inline void writeV2F1000(std::ostream &os, v2f p) +{ + char buf[8]; + writeV2F1000((u8*)buf, p); + os.write(buf, 8); +} +inline v2f readV2F1000(std::istream &is) +{ + char buf[8]; + is.read(buf, 8); + return readV2F1000((u8*)buf); +} + +inline void writeV2S16(std::ostream &os, v2s16 p) +{ + char buf[4]; + writeV2S16((u8*)buf, p); + os.write(buf, 4); +} +inline v2s16 readV2S16(std::istream &is) +{ + char buf[4]; + is.read(buf, 4); + return readV2S16((u8*)buf); +} + +inline void writeV3S16(std::ostream &os, v3s16 p) +{ + char buf[6]; + writeV3S16((u8*)buf, p); + os.write(buf, 6); +} +inline v3s16 readV3S16(std::istream &is) +{ + char buf[6]; + is.read(buf, 6); + return readV3S16((u8*)buf); +} + /* None of these are used at the moment */ @@ -207,6 +417,10 @@ class SharedPtr { return ptr == t; } + T & operator[](unsigned int i) + { + return ptr[i]; + } private: void drop() { @@ -227,26 +441,59 @@ template class Buffer { public: + Buffer() + { + m_size = 0; + data = NULL; + } Buffer(unsigned int size) { m_size = size; - data = new T[size]; + if(size != 0) + data = new T[size]; + else + data = NULL; } Buffer(const Buffer &buffer) { m_size = buffer.m_size; - data = new T[buffer.m_size]; - memcpy(data, buffer.data, buffer.m_size); + if(m_size != 0) + { + data = new T[buffer.m_size]; + memcpy(data, buffer.data, buffer.m_size); + } + else + data = NULL; } - Buffer(T *t, unsigned int size) + Buffer(const T *t, unsigned int size) { m_size = size; - data = new T[size]; - memcpy(data, t, size); + if(size != 0) + { + data = new T[size]; + memcpy(data, t, size); + } + else + data = NULL; } ~Buffer() { - delete[] data; + 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 { @@ -261,6 +508,11 @@ class Buffer return m_size; } private: + void drop() + { + if(data) + delete[] data; + } T *data; unsigned int m_size; }; @@ -269,10 +521,20 @@ template 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; } @@ -302,8 +564,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; } @@ -312,9 +579,14 @@ class SharedBuffer */ SharedBuffer(const Buffer &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; } @@ -324,6 +596,7 @@ class SharedBuffer } T & operator[](unsigned int i) const { + //assert(i < m_size) return data[i]; } T * operator*() const @@ -334,6 +607,10 @@ class SharedBuffer { return m_size; } + operator Buffer() const + { + return Buffer(data, m_size); + } private: void drop() { @@ -341,7 +618,8 @@ class SharedBuffer (*refcount)--; if(*refcount == 0) { - delete[] data; + if(data) + delete[] data; delete refcount; } } @@ -395,8 +673,6 @@ class MutexedVariable TimeTaker */ -class IrrlichtWrapper; - class TimeTaker { public: @@ -418,6 +694,46 @@ class TimeTaker 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 &list, u16 d) { @@ -538,6 +854,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 ( @@ -555,13 +888,13 @@ inline bool isInArea(v2s16 p, s16 d) ); } -inline s16 rangelim(s16 i, s16 min, s16 max) +inline bool isInArea(v3s16 p, v3s16 d) { - if(i < min) - return min; - if(i > max) - return max; - return i; + 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) @@ -573,6 +906,8 @@ inline s16 rangelim(s16 i, s16 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) @@ -593,8 +928,10 @@ inline v3s16 arealim(v3s16 p, s16 d) inline std::wstring narrow_to_wide(const std::string& mbs) { size_t wcl = mbs.size(); - SharedBuffer wcs(wcl+1); + Buffer wcs(wcl+1); size_t l = mbstowcs(*wcs, mbs.c_str(), wcl); + if(l == (size_t)(-1)) + return L""; wcs[l] = 0; return *wcs; } @@ -604,13 +941,26 @@ inline std::string wide_to_narrow(const std::wstring& wcs) size_t mbl = wcs.size()*4; SharedBuffer 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 str_split(const std::wstring &str, wchar_t delimiter) +{ + std::vector 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 @@ -635,6 +985,35 @@ inline float wrapDegrees(float f) 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; @@ -656,7 +1035,7 @@ inline bool is_yes(const std::string &s) return false; } -inline s32 stoi(const std::string &s, s32 min, s32 max) +inline s32 mystoi(const std::string &s, s32 min, s32 max) { s32 i = atoi(s.c_str()); if(i < min) @@ -666,19 +1045,36 @@ inline s32 stoi(const std::string &s, s32 min, s32 max) return i; } -inline s32 stoi(std::string s) + +// 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 float stof(std::string s) +inline s32 mystoi(const std::wstring &s) +{ + return atoi(wide_to_narrow(s).c_str()); +} + +inline float mystof(const std::string &s) { - float f; + // This crap causes a segfault in certain cases on MinGW + /*float f; std::istringstream ss(s); ss>>f; - return 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; @@ -693,6 +1089,26 @@ inline std::string ftos(float 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 +class Queue { - ValueSpec(ValueType a_type, const char *a_help=NULL) +public: + void push_back(T t) { - type = a_type; - help = a_help; + m_list.push_back(t); } - ValueType type; - const char *help; -}; - -class Settings -{ -public: - - // Returns false on EOF - bool parseConfigObject(std::istream &is) + + T pop_front() { - 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: \""<::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"); - /* - Read configuration file + typename core::list::Iterator last = m_list.getLast(); + T t = *last; + m_list.erase(last); + return t; + } - Returns true on success - */ - bool readConfigFile(const char *filename) + u32 size() { - std::ifstream is(filename); - if(is.good() == false) - { - dstream<<"Error opening configuration file \"" - < &dst, - core::map &updated) - { - if(is.eof()) - return false; - - // NOTE: This function will be expanded to allow multi-line settings - std::string line; - std::getline(is, line); - - std::string trimmedline = trim(line); - - std::string line_end = ""; - if(is.eof() == false) - line_end = "\n"; - - // Ignore comments - if(trimmedline[0] == '#') - { - dst.push_back(line+line_end); - return true; - } - - Strfnd sf(trim(line)); - - std::string name = sf.next("="); - name = trim(name); - - if(name == "") - { - dst.push_back(line+line_end); - return true; - } - - std::string value = sf.next("\n"); - value = trim(value); - - if(m_settings.find(name)) - { - std::string newvalue = m_settings[name]; - - if(newvalue != value) - { - dstream<<"Changing value of \""< \""< objects; - core::map updated; - - // Read and modify stuff - { - std::ifstream is(filename); - if(is.good() == false) - { - dstream<<"Error opening configuration file" - " for reading: \"" - <::Iterator - i = objects.begin(); - i != objects.end(); i++) - { - os<<(*i); - } - - /* - Write stuff that was not already in the file - */ - for(core::map::Iterator - i = m_settings.getIterator(); - i.atEnd() == false; i++) - { - if(updated.find(i.getNode()->getKey())) - continue; - std::string name = i.getNode()->getKey(); - std::string value = i.getNode()->getValue(); - dstream<<"Adding \""< &allowed_options) - { - int i=1; - for(;;) - { - if(i >= argc) - break; - std::string argname = argv[i]; - if(argname.substr(0, 2) != "--") - { - dstream<<"Invalid command-line parameter \"" - < expected."<::Node *n; - n = allowed_options.find(name); - if(n == NULL) - { - dstream<<"Unknown command-line parameter \"" - <getValue().type; - - std::string value = ""; - - if(type == VALUETYPE_FLAG) - { - value = "true"; - } - else - { - if(i >= argc) - { - dstream<<"Invalid command-line parameter \"" - <::Node *n; - n = m_settings.find(name); - if(n == NULL) - { - n = m_defaults.find(name); - if(n == NULL) - { - throw SettingNotFoundException("Setting not found"); - } - } - - return n->getValue(); - } - - bool getBool(std::string name) - { - return is_yes(get(name)); - } - - bool getFlag(std::string name) - { - try - { - return getBool(name); - } - catch(SettingNotFoundException &e) - { - return false; - } - } - - // Asks if empty - bool getBoolAsk(std::string name, std::string question, bool def) - { - // If it is in settings - if(m_settings.find(name)) - return getBool(name); - - std::string s; - char templine[10]; - std::cout<>f; - return f; - } - - u16 getU16(std::string name) - { - return stoi(get(name), 0, 65535); - } - - u16 getU16Ask(std::string name, std::string question, u16 def) - { - // If it is in settings - if(m_settings.find(name)) - return getU16(name); - - std::string s; - char templine[10]; - std::cout<::Iterator - i = other.m_settings.getIterator(); - i.atEnd() == false; i++) - { - m_settings.insert(i.getNode()->getKey(), - i.getNode()->getValue()); - } - - for(core::map::Iterator - i = other.m_defaults.getIterator(); - i.atEnd() == false; i++) - { - m_defaults.insert(i.getNode()->getKey(), - i.getNode()->getValue()); - } - - } - - Settings & operator=(Settings &other) - { - if(&other == this) - return *this; - - clear(); - (*this) += other; - - return *this; - } - -private: - core::map m_settings; - core::map m_defaults; -}; - -/* - FIFO queue -*/ -template -class Queue -{ -public: - void push_back(T t) - { - m_list.push_back(t); - } - - T pop_front() - { - if(m_list.size() == 0) - throw ItemNotFoundException("MutexedQueue: queue is empty"); - - typename core::list::Iterator begin = m_list.begin(); - T t = *begin; - m_list.erase(begin); - return t; - } - - u32 size() - { - return m_list.size(); + return m_list.size(); } protected: @@ -1206,7 +1194,7 @@ class Queue }; /* - Thread-safe FIFO queue + Thread-safe FIFO queue (well, actually a FILO also) */ template @@ -1219,6 +1207,7 @@ class MutexedQueue } u32 size() { + JMutexAutoLock lock(m_mutex); return m_list.size(); } void push_back(T t) @@ -1252,6 +1241,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::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() { @@ -1268,6 +1283,10 @@ class MutexedQueue core::list m_list; }; +/* + A single worker thread - multiple client threads queue framework. +*/ + template class CallerInfo { @@ -1317,11 +1336,6 @@ class GetRequest core::list > callers; }; -/* - Quickhands for typical request-result queues. - Used for distributing work between threads. -*/ - template class RequestQueue { @@ -1397,235 +1411,454 @@ int myrand(void); void mysrand(unsigned seed); #define MYRAND_MAX 32767 +int myrand_range(int min, int max); + /* - Some kind of a thing that stores attributes related to - coordinate points + Miscellaneous functions */ -struct Attribute -{ - Attribute() - { - } - - Attribute(const std::string &value): - m_value(value) - { - } +bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, + f32 camera_fov, f32 range, f32 *distance_ptr=NULL); - Attribute(float value) - { - m_value = ftos(value); - } +/* + Queue with unique values with fast checking of value existence +*/ - void set(const std::string &value) - { - m_value = value; - } - - std::string get() - { - return m_value; - } - - bool getBool() - { - return is_yes(get()); - } +template +class UniqueQueue +{ +public: - float getFloat() + /* + Does nothing if value is already queued. + Return value: + true: value added + false: value already exists + */ + bool push_back(Value value) { - float f; - std::istringstream vis(get()); - vis>>f; - return f; - } + // Check if already exists + if(m_map.find(value) != NULL) + return false; - u16 getU16() - { - return stoi(get(), 0, 65535); + // Add + m_map.insert(value, 0); + m_list.push_back(value); + + return true; } - s16 getS16() + Value pop_front() { - return stoi(get(), -32768, 32767); + typename core::list::Iterator i = m_list.begin(); + Value value = *i; + m_map.remove(value); + m_list.erase(i); + return value; } - s32 getS32() + u32 size() { - return stoi(get()); + assert(m_list.size() == m_map.size()); + return m_list.size(); } - std::string m_value; +private: + core::map m_map; + core::list m_list; }; -class PointAttributeList +#if 1 +template +class MutexedMap { - struct PointWithAttr - { - v2s16 p; - Attribute attr; - }; - public: - ~PointAttributeList() + MutexedMap() { + m_mutex.Init(); + assert(m_mutex.IsInitialized()); } - - Attribute getNearAttr(v2s16 p) + + void set(const Key &name, const Value &value) { - core::list::Iterator - nearest_i = m_points.end(); - s16 nearest_d = 32767; - for(core::list::Iterator - i = m_points.begin(); - i != m_points.end(); i++) - { - PointWithAttr &pwa = *i; - s16 d = pwa.p.getDistanceFrom(p); - if(d < nearest_d) - { - nearest_i = i; - nearest_d = d; - } - } - - if(nearest_i == m_points.end()) - Attribute(); + JMutexAutoLock lock(m_mutex); - return nearest_i->attr; + m_values[name] = value; } - Attribute getNearAttr(v3s16 p) + bool get(const Key &name, Value *result) { - return getNearAttr(v2s16(p.X, p.Z)); + JMutexAutoLock lock(m_mutex); + + typename core::map::Node *n; + n = m_values.find(name); + + if(n == NULL) + return false; + + if(result != NULL) + *result = n->getValue(); + + return true; } - bool empty() +private: + core::map 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 +class MutexedIdGenerator +{ +public: + MutexedIdGenerator() { - return (m_points.size() == 0); + m_mutex.Init(); + assert(m_mutex.IsInitialized()); } - /* - Take all points in range, or at least the nearest point, - and interpolate the values as floats - */ - float getInterpolatedFloat(v2s16 p); - - float getInterpolatedFloat(v3s16 p) + // Returns true if found + bool getValue(u32 id, T &value) { - return getInterpolatedFloat(v2s16(p.X, p.Z)); + 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; } - void addPoint(v2s16 p, const Attribute &attr) + // If id exists for value, returns the id. + // Otherwise generates an id for the value. + u32 getId(const T &value) { - PointWithAttr pattr; - pattr.p = p; - pattr.attr = attr; - m_points.push_back(pattr); - } - - void addPoint(v3s16 p, const Attribute &attr) - { - addPoint(v2s16(p.X, p.Z), attr); + JMutexAutoLock lock(m_mutex); + typename core::map::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: - core::list m_points; + JMutex m_mutex; + // Values are stored here at id-1 position (id 1 = [0]) + core::array m_id_to_value; + core::map m_value_to_id; }; /* - Basically just a wrapper to core::map + Checks if a string contains only supplied characters */ - -class PointAttributeDatabase +inline bool string_allowed(const std::string &s, const std::string &allowed_chars) { -public: - ~PointAttributeDatabase() + for(u32 i=0; i::Iterator - i = m_lists.getIterator(); - i.atEnd() == false; i++) + bool confirmed = false; + for(u32 j=0; jgetValue(); + if(s[i] == allowed_chars[j]) + { + confirmed = true; + break; + } } + if(confirmed == false) + return false; } + return true; +} - PointAttributeList *getList(const 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::Node *n; - n = m_lists.find(name); - - if(n == NULL) - { - list = new PointAttributeList(); - m_lists.insert(name, list); - } - else - { - list = n->getValue(); - } +/* + Some helper stuff +*/ +#define MYMIN(a,b) ((a)<(b)?(a):(b)) +#define MYMAX(a,b) ((a)>(b)?(a):(b)) - return list; - } -private: - core::map m_lists; -}; +/* + Returns nearest 32-bit integer for given floating point number. + and in VC++ don't provide round(). +*/ +inline s32 myround(f32 f) +{ + return floor(f + 0.5); +} /* - Miscellaneous functions + 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; +} -bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range); +/* + 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; +} /* - Queue with unique values with fast checking of value existence + More serialization stuff */ -template -class UniqueQueue +// Creates a string with the length as the first two bytes +inline std::string serializeString(const std::string &plain) { -public: + //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 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 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 getNodeBox(v3s16 p, float d) +{ + return core::aabbox3d( + (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) + { + } /* - Does nothing if value is already queued. - Return value: - true: value added - false: value already exists + 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 push_back(Value value) + bool step(float dtime, float wanted_interval) { - // Check if already exists - if(m_map.find(value) != NULL) + m_accumulator += dtime; + if(m_accumulator < wanted_interval) return false; - - // Add - m_map.insert(value, 0); - m_list.push_back(value); - + m_accumulator -= wanted_interval; return true; } +protected: + float m_accumulator; +}; - Value pop_front() +/* + 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) { - typename core::list::Iterator i = m_list.begin(); - Value value = *i; - m_map.remove(value); - m_list.erase(i); - return value; + // Special cases or invalid parameters + minindex = maxindex = 0; } - - u32 size() + else if(pagecount <= length) { - assert(m_list.size() == m_map.size()); - return m_list.size(); + // 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; + } + } +} -private: - core::map m_map; - core::list m_list; +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; }; #endif