X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Futility.h;h=28732a099f3a8cc77b6361530f4cde4ebe6d7d94;hb=ea3c653a8b6352b1df234e6a9663499e9a42bf90;hp=93fd9d4a7fe443ca38f04b57216356b6ddf95369;hpb=fc26dcdb19dd4e296d850714019ed7da1de0b021;p=dragonfireclient.git diff --git a/src/utility.h b/src/utility.h index 93fd9d4a7..28732a099 100644 --- a/src/utility.h +++ b/src/utility.h @@ -17,24 +17,43 @@ 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 -*/ - #ifndef UTILITY_HEADER #define UTILITY_HEADER -#include "common_irrlicht.h" -#include "debug.h" -#include "strfnd.h" -#include "exceptions.h" #include #include #include #include +#include +#include +#include +#include + +#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 +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); @@ -69,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); } @@ -78,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); } @@ -91,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; @@ -101,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); @@ -145,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 */ @@ -203,6 +305,10 @@ class SharedPtr { return ptr == t; } + T & operator[](unsigned int i) + { + return ptr[i]; + } private: void drop() { @@ -394,35 +500,22 @@ class MutexedVariable class TimeTaker { public: - TimeTaker(const char *name, IrrlichtDevice *dev) - { - m_name = name; - m_dev = dev; - m_time1 = m_dev->getTimer()->getRealTime(); - m_running = true; - } + TimeTaker(const char *name, u32 *result=NULL); + ~TimeTaker() { stop(); } - u32 stop(bool quiet=false) - { - if(m_running) - { - u32 time2 = m_dev->getTimer()->getRealTime(); - u32 dtime = time2 - m_time1; - if(quiet == false) - std::cout< &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 @@ -545,6 +638,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 ( @@ -562,11 +672,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 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; } @@ -576,13 +725,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 @@ -607,25 +769,28 @@ inline float wrapDegrees(float f) return f; } -inline std::string lowercase(std::string s) +inline std::string lowercase(const std::string &s) { + std::string s2; for(size_t i=0; 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) @@ -635,30 +800,153 @@ 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 float stof(std::string s) +{ + float f; + std::istringstream ss(s); + ss>>f; + return f; +} + +#endif + +inline s32 stoi(std::wstring s) +{ + return atoi(wide_to_narrow(s).c_str()); +} + +inline std::string itos(s32 i) +{ + std::ostringstream o; + o<::Iterator + i = m_settings.getIterator(); + i.atEnd() == false; i++) + { + std::string name = i.getNode()->getKey(); + std::string value = i.getNode()->getValue(); + os<::Node *n; - n = m_settings.find(name); - if(n == NULL) - throw SettingNotFoundException("Setting not found"); + /* + Reads a configuration object from stream (usually a single line) + and adds it to dst. + + Preserves comments and empty lines. - return n->getValue(); - } + Settings that were added to dst are also added to updated. + key of updated is setting name, value of updated is dummy. - bool getBool(std::string name) - { - return is_yes(get(name)); - } - - // Asks if empty - bool getBoolAsk(std::string name, std::string question, bool def) + Returns false on EOF + */ + bool getUpdatedConfigObject(std::istream &is, + core::list &dst, + core::map &updated) { - std::string s = get(name); - if(s != "") - return is_yes(s); + JMutexAutoLock lock(m_mutex); - char templine[10]; - std::cout<>f; - return f; - } + Strfnd sf(trim(line)); - u16 getU16(std::string name) - { - return stoi(get(name), 0, 65535); - } + std::string name = sf.next("="); + name = trim(name); - u16 getU16Ask(std::string name, std::string question, u16 def) - { - std::string s = get(name); - if(s != "") - return stoi(s, 0, 65535); + if(name == "") + { + dst.push_back(line+line_end); + return true; + } - char templine[10]; - std::cout< \""< objects; + core::map updated; + + // Read and modify stuff + { + std::ifstream is(filename); + if(is.good() == false) + { + dstream<<"INFO: updateConfigFile():" + " 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) + { + dstream<<"INFO: Settings: Setting not found: \"" + <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(exists(name)) + return getBool(name); + + std::string s; + char templine[10]; + std::cout<>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)); + } + + void setFloat(std::string name, float value) + { + set(name, ftos(value)); + } + + void setV3F(std::string name, v3f value) + { + std::ostringstream os; + os<<"("<::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) + { + JMutexAutoLock lock(m_mutex); + JMutexAutoLock lock2(other.m_mutex); + + if(&other == this) + return *this; + + clear(); + (*this) += other; + + return *this; + } + private: core::map m_settings; + core::map m_defaults; + // All methods that access m_settings/m_defaults directly should lock this. + JMutex m_mutex; +}; + +/* + FIFO queue (well, actually a FILO also) +*/ +template +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::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::Iterator last = m_list.getLast(); + T t = *last; + m_list.erase(last); + return t; + } + + u32 size() + { + return m_list.size(); + } + +protected: + core::list m_list; +}; + +/* + Thread-safe FIFO queue (well, actually a FILO also) +*/ + +template +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::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::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 & getList() + { + return m_list; + } + +protected: + JMutex m_mutex; + core::list m_list; +}; + +/* + A single worker thread - multiple client threads queue framework. +*/ + +template +class CallerInfo +{ +public: + Caller caller; + Data data; +}; + +template +class GetResult +{ +public: + Key key; + T item; + core::list > callers; +}; + +template +class ResultQueue: public MutexedQueue< GetResult > +{ +}; + +template +class GetRequest +{ +public: + GetRequest() + { + dest = NULL; + } + GetRequest(ResultQueue *a_dest) + { + dest = a_dest; + } + GetRequest(ResultQueue *a_dest, + Key a_key) + { + dest = a_dest; + key = a_key; + } + ~GetRequest() + { + } + + Key key; + ResultQueue *dest; + core::list > callers; +}; + +template +class RequestQueue +{ +public: + u32 size() + { + return m_queue.size(); + } + + void add(Key key, Caller caller, CallerData callerdata, + ResultQueue *dest) + { + JMutexAutoLock lock(m_queue.getMutex()); + + /* + If the caller is already on the list, only update CallerData + */ + for(typename core::list< GetRequest >::Iterator + i = m_queue.getList().begin(); + i != m_queue.getList().end(); i++) + { + GetRequest &request = *i; + + if(request.key == key) + { + for(typename core::list< CallerInfo >::Iterator + i = request.callers.begin(); + i != request.callers.end(); i++) + { + CallerInfo &ca = *i; + if(ca.caller == caller) + { + ca.data = callerdata; + return; + } + } + CallerInfo ca; + ca.caller = caller; + ca.data = callerdata; + request.callers.push_back(ca); + return; + } + } + + /* + Else add a new request to the queue + */ + + GetRequest request; + request.key = key; + CallerInfo ca; + ca.caller = caller; + ca.data = callerdata; + request.callers.push_back(ca); + request.dest = dest; + + m_queue.getList().push_back(request); + } + + GetRequest pop(bool wait_if_empty=false) + { + return m_queue.pop_front(wait_if_empty); + } + +private: + MutexedQueue< GetRequest > m_queue; +}; + +/* + Pseudo-random (VC++ rand() sucks) +*/ +int myrand(void); +void mysrand(unsigned seed); +#define MYRAND_MAX 32767 + +inline int myrand_range(int min, int max) +{ + if(min > max) + { + assert(0); + return max; + } + return (myrand()%(max-min+1))+min; +} + +/* + Miscellaneous functions +*/ + +bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range, + f32 *distance_ptr=NULL); + +/* + Queue with unique values with fast checking of value existence +*/ + +template +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::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 m_map; + core::list m_list; +}; + +#if 0 +template +class MutexedCache +{ +public: + MutexedCache() + { + 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::Node *n; + n = m_values.find(name); + + if(n == NULL) + return false; + + *result = n->getValue(); + return true; + } + +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() + { + 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::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 m_id_to_value; + core::map 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(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 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 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 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) + { + } + /* + 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