diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/container.h | 305 | ||||
-rw-r--r-- | src/util/directiontables.cpp | 101 | ||||
-rw-r--r-- | src/util/directiontables.h | 33 | ||||
-rw-r--r-- | src/util/numeric.cpp | 202 | ||||
-rw-r--r-- | src/util/numeric.h | 331 | ||||
-rw-r--r-- | src/util/pointedthing.cpp | 125 | ||||
-rw-r--r-- | src/util/pointedthing.h | 50 | ||||
-rw-r--r-- | src/util/pointer.h | 298 | ||||
-rw-r--r-- | src/util/serialize.cpp | 119 | ||||
-rw-r--r-- | src/util/serialize.h | 456 | ||||
-rw-r--r-- | src/util/string.cpp | 43 | ||||
-rw-r--r-- | src/util/string.h | 264 | ||||
-rw-r--r-- | src/util/thread.h | 227 | ||||
-rw-r--r-- | src/util/timetaker.cpp | 61 | ||||
-rw-r--r-- | src/util/timetaker.h | 51 |
15 files changed, 2666 insertions, 0 deletions
diff --git a/src/util/container.h b/src/util/container.h new file mode 100644 index 000000000..bdf560979 --- /dev/null +++ b/src/util/container.h @@ -0,0 +1,305 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef UTIL_CONTAINER_HEADER +#define UTIL_CONTAINER_HEADER + +#include "../irrlichttypes.h" +#include <jmutex.h> +#include <jmutexautolock.h> +#include "../porting.h" // For sleep_ms + +/* + Queue with unique values with fast checking of value existence +*/ + +template<typename Value> +class UniqueQueue +{ +public: + + /* + Does nothing if value is already queued. + Return value: + true: value added + false: value already exists + */ + bool push_back(Value value) + { + // Check if already exists + if(m_map.find(value) != NULL) + return false; + + // Add + m_map.insert(value, 0); + m_list.push_back(value); + + return true; + } + + Value pop_front() + { + typename core::list<Value>::Iterator i = m_list.begin(); + Value value = *i; + m_map.remove(value); + m_list.erase(i); + return value; + } + + u32 size() + { + assert(m_list.size() == m_map.size()); + return m_list.size(); + } + +private: + core::map<Value, u8> m_map; + core::list<Value> m_list; +}; + +#if 1 +template<typename Key, typename Value> +class MutexedMap +{ +public: + MutexedMap() + { + m_mutex.Init(); + assert(m_mutex.IsInitialized()); + } + + void set(const Key &name, const Value &value) + { + JMutexAutoLock lock(m_mutex); + + m_values[name] = value; + } + + bool get(const Key &name, Value *result) + { + JMutexAutoLock lock(m_mutex); + + typename core::map<Key, Value>::Node *n; + n = m_values.find(name); + + if(n == NULL) + return false; + + if(result != NULL) + *result = n->getValue(); + + return true; + } + +private: + core::map<Key, Value> m_values; + JMutex m_mutex; +}; +#endif + +/* + Generates ids for comparable values. + Id=0 is reserved for "no value". + + Is fast at: + - Returning value by id (very fast) + - Returning id by value + - Generating a new id for a value + + Is not able to: + - Remove an id/value pair (is possible to implement but slow) +*/ +template<typename T> +class MutexedIdGenerator +{ +public: + MutexedIdGenerator() + { + m_mutex.Init(); + assert(m_mutex.IsInitialized()); + } + + // Returns true if found + bool getValue(u32 id, T &value) + { + if(id == 0) + return false; + JMutexAutoLock lock(m_mutex); + if(m_id_to_value.size() < id) + return false; + value = m_id_to_value[id-1]; + return true; + } + + // If id exists for value, returns the id. + // Otherwise generates an id for the value. + u32 getId(const T &value) + { + JMutexAutoLock lock(m_mutex); + typename core::map<T, u32>::Node *n; + n = m_value_to_id.find(value); + if(n != NULL) + return n->getValue(); + m_id_to_value.push_back(value); + u32 new_id = m_id_to_value.size(); + m_value_to_id.insert(value, new_id); + return new_id; + } + +private: + JMutex m_mutex; + // Values are stored here at id-1 position (id 1 = [0]) + core::array<T> m_id_to_value; + core::map<T, u32> m_value_to_id; +}; + +/* + FIFO queue (well, actually a FILO also) +*/ +template<typename T> +class Queue +{ +public: + void push_back(T t) + { + m_list.push_back(t); + } + + T pop_front() + { + if(m_list.size() == 0) + throw ItemNotFoundException("Queue: queue is empty"); + + typename core::list<T>::Iterator begin = m_list.begin(); + T t = *begin; + m_list.erase(begin); + return t; + } + T pop_back() + { + if(m_list.size() == 0) + throw ItemNotFoundException("Queue: queue is empty"); + + typename core::list<T>::Iterator last = m_list.getLast(); + T t = *last; + m_list.erase(last); + return t; + } + + u32 size() + { + return m_list.size(); + } + +protected: + core::list<T> m_list; +}; + +/* + Thread-safe FIFO queue (well, actually a FILO also) +*/ + +template<typename T> +class MutexedQueue +{ +public: + MutexedQueue() + { + m_mutex.Init(); + } + u32 size() + { + JMutexAutoLock lock(m_mutex); + return m_list.size(); + } + void push_back(T t) + { + JMutexAutoLock lock(m_mutex); + m_list.push_back(t); + } + T pop_front(u32 wait_time_max_ms=0) + { + u32 wait_time_ms = 0; + + for(;;) + { + { + JMutexAutoLock lock(m_mutex); + + if(m_list.size() > 0) + { + typename core::list<T>::Iterator begin = m_list.begin(); + T t = *begin; + m_list.erase(begin); + return t; + } + + if(wait_time_ms >= wait_time_max_ms) + throw ItemNotFoundException("MutexedQueue: queue is empty"); + } + + // Wait a while before trying again + sleep_ms(10); + wait_time_ms += 10; + } + } + T pop_back(u32 wait_time_max_ms=0) + { + u32 wait_time_ms = 0; + + for(;;) + { + { + JMutexAutoLock lock(m_mutex); + + if(m_list.size() > 0) + { + typename core::list<T>::Iterator last = m_list.getLast(); + T t = *last; + m_list.erase(last); + return t; + } + + if(wait_time_ms >= wait_time_max_ms) + throw ItemNotFoundException("MutexedQueue: queue is empty"); + } + + // Wait a while before trying again + sleep_ms(10); + wait_time_ms += 10; + } + } + + JMutex & getMutex() + { + return m_mutex; + } + + core::list<T> & getList() + { + return m_list; + } + +protected: + JMutex m_mutex; + core::list<T> m_list; +}; + +#endif + diff --git a/src/util/directiontables.cpp b/src/util/directiontables.cpp new file mode 100644 index 000000000..a5d2faa7c --- /dev/null +++ b/src/util/directiontables.cpp @@ -0,0 +1,101 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "directiontables.h" + +const v3s16 g_6dirs[6] = +{ + // +right, +top, +back + v3s16( 0, 0, 1), // back + v3s16( 0, 1, 0), // top + v3s16( 1, 0, 0), // right + v3s16( 0, 0,-1), // front + v3s16( 0,-1, 0), // bottom + v3s16(-1, 0, 0) // left +}; + +const v3s16 g_26dirs[26] = +{ + // +right, +top, +back + v3s16( 0, 0, 1), // back + v3s16( 0, 1, 0), // top + v3s16( 1, 0, 0), // right + v3s16( 0, 0,-1), // front + v3s16( 0,-1, 0), // bottom + v3s16(-1, 0, 0), // left + // 6 + v3s16(-1, 1, 0), // top left + v3s16( 1, 1, 0), // top right + v3s16( 0, 1, 1), // top back + v3s16( 0, 1,-1), // top front + v3s16(-1, 0, 1), // back left + v3s16( 1, 0, 1), // back right + v3s16(-1, 0,-1), // front left + v3s16( 1, 0,-1), // front right + v3s16(-1,-1, 0), // bottom left + v3s16( 1,-1, 0), // bottom right + v3s16( 0,-1, 1), // bottom back + v3s16( 0,-1,-1), // bottom front + // 18 + v3s16(-1, 1, 1), // top back-left + v3s16( 1, 1, 1), // top back-right + v3s16(-1, 1,-1), // top front-left + v3s16( 1, 1,-1), // top front-right + v3s16(-1,-1, 1), // bottom back-left + v3s16( 1,-1, 1), // bottom back-right + v3s16(-1,-1,-1), // bottom front-left + v3s16( 1,-1,-1), // bottom front-right + // 26 +}; + +const v3s16 g_27dirs[27] = +{ + // +right, +top, +back + v3s16( 0, 0, 1), // back + v3s16( 0, 1, 0), // top + v3s16( 1, 0, 0), // right + v3s16( 0, 0,-1), // front + v3s16( 0,-1, 0), // bottom + v3s16(-1, 0, 0), // left + // 6 + v3s16(-1, 1, 0), // top left + v3s16( 1, 1, 0), // top right + v3s16( 0, 1, 1), // top back + v3s16( 0, 1,-1), // top front + v3s16(-1, 0, 1), // back left + v3s16( 1, 0, 1), // back right + v3s16(-1, 0,-1), // front left + v3s16( 1, 0,-1), // front right + v3s16(-1,-1, 0), // bottom left + v3s16( 1,-1, 0), // bottom right + v3s16( 0,-1, 1), // bottom back + v3s16( 0,-1,-1), // bottom front + // 18 + v3s16(-1, 1, 1), // top back-left + v3s16( 1, 1, 1), // top back-right + v3s16(-1, 1,-1), // top front-left + v3s16( 1, 1,-1), // top front-right + v3s16(-1,-1, 1), // bottom back-left + v3s16( 1,-1, 1), // bottom back-right + v3s16(-1,-1,-1), // bottom front-left + v3s16( 1,-1,-1), // bottom front-right + // 26 + v3s16(0,0,0), +}; + diff --git a/src/util/directiontables.h b/src/util/directiontables.h new file mode 100644 index 000000000..c02b3d124 --- /dev/null +++ b/src/util/directiontables.h @@ -0,0 +1,33 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef UTIL_DIRECTIONTABLES_HEADER +#define UTIL_DIRECTIONTABLES_HEADER + +#include "../irrlichttypes.h" + +extern const v3s16 g_6dirs[6]; + +extern const v3s16 g_26dirs[26]; + +// 26th is (0,0,0) +extern const v3s16 g_27dirs[27]; + +#endif + diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp new file mode 100644 index 000000000..d082cdb76 --- /dev/null +++ b/src/util/numeric.cpp @@ -0,0 +1,202 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "numeric.h" + +#include "log.h" +#include "constants.h" // BS, MAP_BLOCKSIZE +#include <iostream> + +// Calculate the borders of a "d-radius" cube +void getFacePositions(core::list<v3s16> &list, u16 d) +{ + if(d == 0) + { + list.push_back(v3s16(0,0,0)); + return; + } + if(d == 1) + { + /* + This is an optimized sequence of coordinates. + */ + list.push_back(v3s16( 0, 1, 0)); // top + list.push_back(v3s16( 0, 0, 1)); // back + list.push_back(v3s16(-1, 0, 0)); // left + list.push_back(v3s16( 1, 0, 0)); // right + list.push_back(v3s16( 0, 0,-1)); // front + list.push_back(v3s16( 0,-1, 0)); // bottom + // 6 + list.push_back(v3s16(-1, 0, 1)); // back left + list.push_back(v3s16( 1, 0, 1)); // back right + list.push_back(v3s16(-1, 0,-1)); // front left + list.push_back(v3s16( 1, 0,-1)); // front right + list.push_back(v3s16(-1,-1, 0)); // bottom left + list.push_back(v3s16( 1,-1, 0)); // bottom right + list.push_back(v3s16( 0,-1, 1)); // bottom back + list.push_back(v3s16( 0,-1,-1)); // bottom front + list.push_back(v3s16(-1, 1, 0)); // top left + list.push_back(v3s16( 1, 1, 0)); // top right + list.push_back(v3s16( 0, 1, 1)); // top back + list.push_back(v3s16( 0, 1,-1)); // top front + // 18 + list.push_back(v3s16(-1, 1, 1)); // top back-left + list.push_back(v3s16( 1, 1, 1)); // top back-right + list.push_back(v3s16(-1, 1,-1)); // top front-left + list.push_back(v3s16( 1, 1,-1)); // top front-right + list.push_back(v3s16(-1,-1, 1)); // bottom back-left + list.push_back(v3s16( 1,-1, 1)); // bottom back-right + list.push_back(v3s16(-1,-1,-1)); // bottom front-left + list.push_back(v3s16( 1,-1,-1)); // bottom front-right + // 26 + return; + } + + // Take blocks in all sides, starting from y=0 and going +-y + for(s16 y=0; y<=d-1; y++) + { + // Left and right side, including borders + for(s16 z=-d; z<=d; z++) + { + list.push_back(v3s16(d,y,z)); + list.push_back(v3s16(-d,y,z)); + if(y != 0) + { + list.push_back(v3s16(d,-y,z)); + list.push_back(v3s16(-d,-y,z)); + } + } + // Back and front side, excluding borders + for(s16 x=-d+1; x<=d-1; x++) + { + list.push_back(v3s16(x,y,d)); + list.push_back(v3s16(x,y,-d)); + if(y != 0) + { + list.push_back(v3s16(x,-y,d)); + list.push_back(v3s16(x,-y,-d)); + } + } + } + + // Take the bottom and top face with borders + // -d<x<d, y=+-d, -d<z<d + for(s16 x=-d; x<=d; x++) + for(s16 z=-d; z<=d; z++) + { + list.push_back(v3s16(x,-d,z)); + list.push_back(v3s16(x,d,z)); + } +} + +/* + myrand +*/ + +static unsigned long next = 1; + +/* RAND_MAX assumed to be 32767 */ +int myrand(void) +{ + next = next * 1103515245 + 12345; + return((unsigned)(next/65536) % 32768); +} + +void mysrand(unsigned seed) +{ + next = seed; +} + +int myrand_range(int min, int max) +{ + if(max-min > MYRAND_MAX) + { + errorstream<<"WARNING: myrand_range: max-min > MYRAND_MAX"<<std::endl; + max = min + MYRAND_MAX; + } + if(min > max) + { + errorstream<<"WARNING: myrand_range: min > max"<<std::endl; + return max; + } + return (myrand()%(max-min+1))+min; +} + +/* + blockpos: position of block in block coordinates + camera_pos: position of camera in nodes + camera_dir: an unit vector pointing to camera direction + range: viewing range +*/ +bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, + f32 camera_fov, f32 range, f32 *distance_ptr) +{ + v3s16 blockpos_nodes = blockpos_b * MAP_BLOCKSIZE; + + // Block center position + v3f blockpos( + ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS, + ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS, + ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS + ); + + // Block position relative to camera + v3f blockpos_relative = blockpos - camera_pos; + + // Distance in camera direction (+=front, -=back) + f32 dforward = blockpos_relative.dotProduct(camera_dir); + + // Total distance + f32 d = blockpos_relative.getLength(); + + if(distance_ptr) + *distance_ptr = d; + + // If block is very close, it is always in sight + if(d < 1.44*1.44*MAP_BLOCKSIZE*BS/2) + return true; + + // If block is far away, it's not in sight + if(d > range) + return false; + + // Maximum radius of a block + f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS; + + // If block is (nearly) touching the camera, don't + // bother validating further (that is, render it anyway) + if(d < block_max_radius) + return true; + + // Cosine of the angle between the camera direction + // and the block direction (camera_dir is an unit vector) + f32 cosangle = dforward / d; + + // Compensate for the size of the block + // (as the block has to be shown even if it's a bit off FOV) + // This is an estimate, plus an arbitary factor + cosangle += block_max_radius / d * 0.5; + + // If block is not in the field of view, skip it + if(cosangle < cos(camera_fov / 2)) + return false; + + return true; +} + diff --git a/src/util/numeric.h b/src/util/numeric.h new file mode 100644 index 000000000..0ce21b7e3 --- /dev/null +++ b/src/util/numeric.h @@ -0,0 +1,331 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef UTIL_NUMERIC_HEADER +#define UTIL_NUMERIC_HEADER + +#include "../irrlichttypes.h" + +// Calculate the borders of a "d-radius" cube +void getFacePositions(core::list<v3s16> &list, u16 d); + +class IndentationRaiser +{ +public: + IndentationRaiser(u16 *indentation) + { + m_indentation = indentation; + (*m_indentation)++; + } + ~IndentationRaiser() + { + (*m_indentation)--; + } +private: + u16 *m_indentation; +}; + +inline s16 getContainerPos(s16 p, s16 d) +{ + return (p>=0 ? p : p-d+1) / d; +} + +inline v2s16 getContainerPos(v2s16 p, s16 d) +{ + return v2s16( + getContainerPos(p.X, d), + getContainerPos(p.Y, d) + ); +} + +inline v3s16 getContainerPos(v3s16 p, s16 d) +{ + return v3s16( + getContainerPos(p.X, d), + getContainerPos(p.Y, d), + getContainerPos(p.Z, d) + ); +} + +inline v2s16 getContainerPos(v2s16 p, v2s16 d) +{ + return v2s16( + getContainerPos(p.X, d.X), + getContainerPos(p.Y, d.Y) + ); +} + +inline v3s16 getContainerPos(v3s16 p, v3s16 d) +{ + return v3s16( + getContainerPos(p.X, d.X), + getContainerPos(p.Y, d.Y), + getContainerPos(p.Z, d.Z) + ); +} + +inline bool isInArea(v3s16 p, s16 d) +{ + return ( + p.X >= 0 && p.X < d && + p.Y >= 0 && p.Y < d && + p.Z >= 0 && p.Z < d + ); +} + +inline bool isInArea(v2s16 p, s16 d) +{ + return ( + p.X >= 0 && p.X < d && + p.Y >= 0 && p.Y < d + ); +} + +inline bool isInArea(v3s16 p, v3s16 d) +{ + return ( + p.X >= 0 && p.X < d.X && + p.Y >= 0 && p.Y < d.Y && + p.Z >= 0 && p.Z < d.Z + ); +} + +inline s16 rangelim(s16 i, s16 max) +{ + if(i < 0) + return 0; + if(i > max) + return max; + return i; +} + +#define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d))) + +inline v3s16 arealim(v3s16 p, s16 d) +{ + if(p.X < 0) + p.X = 0; + if(p.Y < 0) + p.Y = 0; + if(p.Z < 0) + p.Z = 0; + if(p.X > d-1) + p.X = d-1; + if(p.Y > d-1) + p.Y = d-1; + if(p.Z > d-1) + p.Z = d-1; + return p; +} + + +/* + See test.cpp for example cases. + wraps degrees to the range of -360...360 + NOTE: Wrapping to 0...360 is not used because pitch needs negative values. +*/ +inline float wrapDegrees(float f) +{ + // Take examples of f=10, f=720.5, f=-0.5, f=-360.5 + // This results in + // 10, 720, -1, -361 + int i = floor(f); + // 0, 2, 0, -1 + int l = i / 360; + // NOTE: This would be used for wrapping to 0...360 + // 0, 2, -1, -2 + /*if(i < 0) + l -= 1;*/ + // 0, 720, 0, -360 + int k = l * 360; + // 10, 0.5, -0.5, -0.5 + f -= float(k); + return f; +} + +/* Wrap to 0...360 */ +inline float wrapDegrees_0_360(float f) +{ + // Take examples of f=10, f=720.5, f=-0.5, f=-360.5 + // This results in + // 10, 720, -1, -361 + int i = floor(f); + // 0, 2, 0, -1 + int l = i / 360; + // Wrap to 0...360 + // 0, 2, -1, -2 + if(i < 0) + l -= 1; + // 0, 720, 0, -360 + int k = l * 360; + // 10, 0.5, -0.5, -0.5 + f -= float(k); + return f; +} + +/* Wrap to -180...180 */ +inline float wrapDegrees_180(float f) +{ + f += 180; + f = wrapDegrees_0_360(f); + f -= 180; + return f; +} + +/* + Pseudo-random (VC++ rand() sucks) +*/ +int myrand(void); +void mysrand(unsigned seed); +#define MYRAND_MAX 32767 + +int myrand_range(int min, int max); + +/* + Miscellaneous functions +*/ + +bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, + f32 camera_fov, f32 range, f32 *distance_ptr=NULL); + +/* + Some helper stuff +*/ +#define MYMIN(a,b) ((a)<(b)?(a):(b)) +#define MYMAX(a,b) ((a)>(b)?(a):(b)) + +/* + Returns nearest 32-bit integer for given floating point number. + <cmath> and <math.h> in VC++ don't provide round(). +*/ +inline s32 myround(f32 f) +{ + return floor(f + 0.5); +} + +/* + Returns integer position of node in given floating point position +*/ +inline v3s16 floatToInt(v3f p, f32 d) +{ + v3s16 p2( + (p.X + (p.X>0 ? d/2 : -d/2))/d, + (p.Y + (p.Y>0 ? d/2 : -d/2))/d, + (p.Z + (p.Z>0 ? d/2 : -d/2))/d); + return p2; +} + +/* + Returns floating point position of node in given integer position +*/ +inline v3f intToFloat(v3s16 p, f32 d) +{ + v3f p2( + (f32)p.X * d, + (f32)p.Y * d, + (f32)p.Z * d + ); + return p2; +} + +// Random helper. Usually d=BS +inline core::aabbox3d<f32> getNodeBox(v3s16 p, float d) +{ + return core::aabbox3d<f32>( + (float)p.X * d - 0.5*d, + (float)p.Y * d - 0.5*d, + (float)p.Z * d - 0.5*d, + (float)p.X * d + 0.5*d, + (float)p.Y * d + 0.5*d, + (float)p.Z * d + 0.5*d + ); +} + +class IntervalLimiter +{ +public: + IntervalLimiter(): + m_accumulator(0) + { + } + /* + dtime: time from last call to this method + wanted_interval: interval wanted + return value: + true: action should be skipped + false: action should be done + */ + bool step(float dtime, float wanted_interval) + { + m_accumulator += dtime; + if(m_accumulator < wanted_interval) + return false; + m_accumulator -= wanted_interval; + return true; + } +protected: + float m_accumulator; +}; + +/* + Splits a list into "pages". For example, the list [1,2,3,4,5] split + into two pages would be [1,2,3],[4,5]. This function computes the + minimum and maximum indices of a single page. + + length: Length of the list that should be split + page: Page number, 1 <= page <= pagecount + pagecount: The number of pages, >= 1 + minindex: Receives the minimum index (inclusive). + maxindex: Receives the maximum index (exclusive). + + Ensures 0 <= minindex <= maxindex <= length. +*/ +inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxindex) +{ + if(length < 1 || pagecount < 1 || page < 1 || page > pagecount) + { + // Special cases or invalid parameters + minindex = maxindex = 0; + } + else if(pagecount <= length) + { + // Less pages than entries in the list: + // Each page contains at least one entry + minindex = (length * (page-1) + (pagecount-1)) / pagecount; + maxindex = (length * page + (pagecount-1)) / pagecount; + } + else + { + // More pages than entries in the list: + // Make sure the empty pages are at the end + if(page < length) + { + minindex = page-1; + maxindex = page; + } + else + { + minindex = 0; + maxindex = 0; + } + } +} + +#endif + diff --git a/src/util/pointedthing.cpp b/src/util/pointedthing.cpp new file mode 100644 index 000000000..d1be2d6b6 --- /dev/null +++ b/src/util/pointedthing.cpp @@ -0,0 +1,125 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "pointedthing.h" + +#include "serialize.h" +#include <sstream> + +PointedThing::PointedThing(): + type(POINTEDTHING_NOTHING), + node_undersurface(0,0,0), + node_abovesurface(0,0,0), + object_id(-1) +{} + +std::string PointedThing::dump() const +{ + std::ostringstream os(std::ios::binary); + if(type == POINTEDTHING_NOTHING) + { + os<<"[nothing]"; + } + else if(type == POINTEDTHING_NODE) + { + const v3s16 &u = node_undersurface; + const v3s16 &a = node_abovesurface; + os<<"[node under="<<u.X<<","<<u.Y<<","<<u.Z + << " above="<<a.X<<","<<a.Y<<","<<a.Z<<"]"; + } + else if(type == POINTEDTHING_OBJECT) + { + os<<"[object "<<object_id<<"]"; + } + else + { + os<<"[unknown PointedThing]"; + } + return os.str(); +} + +void PointedThing::serialize(std::ostream &os) const +{ + writeU8(os, 0); // version + writeU8(os, (u8)type); + if(type == POINTEDTHING_NOTHING) + { + // nothing + } + else if(type == POINTEDTHING_NODE) + { + writeV3S16(os, node_undersurface); + writeV3S16(os, node_abovesurface); + } + else if(type == POINTEDTHING_OBJECT) + { + writeS16(os, object_id); + } +} + +void PointedThing::deSerialize(std::istream &is) +{ + int version = readU8(is); + if(version != 0) throw SerializationError( + "unsupported PointedThing version"); + type = (PointedThingType) readU8(is); + if(type == POINTEDTHING_NOTHING) + { + // nothing + } + else if(type == POINTEDTHING_NODE) + { + node_undersurface = readV3S16(is); + node_abovesurface = readV3S16(is); + } + else if(type == POINTEDTHING_OBJECT) + { + object_id = readS16(is); + } + else + { + throw SerializationError( + "unsupported PointedThingType"); + } +} + +bool PointedThing::operator==(const PointedThing &pt2) const +{ + if(type != pt2.type) + return false; + if(type == POINTEDTHING_NODE) + { + if(node_undersurface != pt2.node_undersurface) + return false; + if(node_abovesurface != pt2.node_abovesurface) + return false; + } + else if(type == POINTEDTHING_OBJECT) + { + if(object_id != pt2.object_id) + return false; + } + return true; +} + +bool PointedThing::operator!=(const PointedThing &pt2) const +{ + return !(*this == pt2); +} + diff --git a/src/util/pointedthing.h b/src/util/pointedthing.h new file mode 100644 index 000000000..82d66dfa8 --- /dev/null +++ b/src/util/pointedthing.h @@ -0,0 +1,50 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef UTIL_POINTEDTHING_HEADER +#define UTIL_POINTEDTHING_HEADER + +#include "../irrlichttypes.h" +#include <iostream> +#include <string> + +enum PointedThingType +{ + POINTEDTHING_NOTHING, + POINTEDTHING_NODE, + POINTEDTHING_OBJECT +}; + +struct PointedThing +{ + PointedThingType type; + v3s16 node_undersurface; + v3s16 node_abovesurface; + s16 object_id; + + PointedThing(); + std::string dump() const; + void serialize(std::ostream &os) const; + void deSerialize(std::istream &is); + bool operator==(const PointedThing &pt2) const; + bool operator!=(const PointedThing &pt2) const; +}; + +#endif + diff --git a/src/util/pointer.h b/src/util/pointer.h new file mode 100644 index 000000000..02f11c2ea --- /dev/null +++ b/src/util/pointer.h @@ -0,0 +1,298 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef UTIL_POINTER_HEADER +#define UTIL_POINTER_HEADER + +#include "../irrlichttypes.h" +#include "../debug.h" // For assert() + +template <typename T> +class SharedPtr +{ +public: + SharedPtr(T *t=NULL) + { + refcount = new int; + *refcount = 1; + ptr = t; + } + SharedPtr(SharedPtr<T> &t) + { + //*this = t; + drop(); + refcount = t.refcount; + (*refcount)++; + ptr = t.ptr; + } + ~SharedPtr() + { + drop(); + } + SharedPtr<T> & operator=(T *t) + { + drop(); + refcount = new int; + *refcount = 1; + ptr = t; + return *this; + } + SharedPtr<T> & operator=(SharedPtr<T> &t) + { + drop(); + refcount = t.refcount; + (*refcount)++; + ptr = t.ptr; + return *this; + } + T* operator->() + { + return ptr; + } + T & operator*() + { + return *ptr; + } + bool operator!=(T *t) + { + return ptr != t; + } + bool operator==(T *t) + { + return ptr == t; + } + T & operator[](unsigned int i) + { + return ptr[i]; + } +private: + void drop() + { + assert((*refcount) > 0); + (*refcount)--; + if(*refcount == 0) + { + delete refcount; + if(ptr != NULL) + delete ptr; + } + } + T *ptr; + int *refcount; +}; + +template <typename T> +class Buffer +{ +public: + Buffer() + { + m_size = 0; + data = NULL; + } + Buffer(unsigned int size) + { + m_size = size; + if(size != 0) + data = new T[size]; + else + data = NULL; + } + Buffer(const Buffer &buffer) + { + m_size = buffer.m_size; + if(m_size != 0) + { + data = new T[buffer.m_size]; + memcpy(data, buffer.data, buffer.m_size); + } + else + data = NULL; + } + Buffer(const T *t, unsigned int size) + { + m_size = size; + if(size != 0) + { + data = new T[size]; + memcpy(data, t, size); + } + else + data = NULL; + } + ~Buffer() + { + drop(); + } + Buffer& operator=(const Buffer &buffer) + { + if(this == &buffer) + return *this; + drop(); + m_size = buffer.m_size; + if(m_size != 0) + { + data = new T[buffer.m_size]; + memcpy(data, buffer.data, buffer.m_size); + } + else + data = NULL; + return *this; + } + T & operator[](unsigned int i) const + { + return data[i]; + } + T * operator*() const + { + return data; + } + unsigned int getSize() const + { + return m_size; + } +private: + void drop() + { + if(data) + delete[] data; + } + T *data; + unsigned int m_size; +}; + +template <typename T> +class SharedBuffer +{ +public: + SharedBuffer() + { + m_size = 0; + data = NULL; + refcount = new unsigned int; + (*refcount) = 1; + } + SharedBuffer(unsigned int size) + { + m_size = size; + if(m_size != 0) + data = new T[m_size]; + else + data = NULL; + refcount = new unsigned int; + (*refcount) = 1; + } + SharedBuffer(const SharedBuffer &buffer) + { + //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl; + m_size = buffer.m_size; + data = buffer.data; + refcount = buffer.refcount; + (*refcount)++; + } + SharedBuffer & operator=(const SharedBuffer & buffer) + { + //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl; + if(this == &buffer) + return *this; + drop(); + m_size = buffer.m_size; + data = buffer.data; + refcount = buffer.refcount; + (*refcount)++; + return *this; + } + /* + Copies whole buffer + */ + SharedBuffer(T *t, unsigned int size) + { + m_size = size; + if(m_size != 0) + { + data = new T[m_size]; + memcpy(data, t, m_size); + } + else + data = NULL; + refcount = new unsigned int; + (*refcount) = 1; + } + /* + Copies whole buffer + */ + SharedBuffer(const Buffer<T> &buffer) + { + m_size = buffer.getSize(); + if(m_size != 0) + { + data = new T[m_size]; + memcpy(data, *buffer, buffer.getSize()); + } + else + data = NULL; + refcount = new unsigned int; + (*refcount) = 1; + } + ~SharedBuffer() + { + drop(); + } + T & operator[](unsigned int i) const + { + //assert(i < m_size) + return data[i]; + } + T * operator*() const + { + return data; + } + unsigned int getSize() const + { + return m_size; + } + operator Buffer<T>() const + { + return Buffer<T>(data, m_size); + } +private: + void drop() + { + assert((*refcount) > 0); + (*refcount)--; + if(*refcount == 0) + { + if(data) + delete[] data; + delete refcount; + } + } + T *data; + unsigned int m_size; + unsigned int *refcount; +}; + +inline SharedBuffer<u8> SharedBufferFromString(const char *string) +{ + SharedBuffer<u8> b((u8*)string, strlen(string)+1); + return b; +} + +#endif + diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp new file mode 100644 index 000000000..16825b677 --- /dev/null +++ b/src/util/serialize.cpp @@ -0,0 +1,119 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "serialize.h" + +#include <sstream> +#include <iomanip> + +// Creates a string encoded in JSON format (almost equivalent to a C string literal) +std::string serializeJsonString(const std::string &plain) +{ + std::ostringstream os(std::ios::binary); + os<<"\""; + for(size_t i = 0; i < plain.size(); i++) + { + char c = plain[i]; + switch(c) + { + case '"': os<<"\\\""; break; + case '\\': os<<"\\\\"; break; + case '/': os<<"\\/"; break; + case '\b': os<<"\\b"; break; + case '\f': os<<"\\f"; break; + case '\n': os<<"\\n"; break; + case '\r': os<<"\\r"; break; + case '\t': os<<"\\t"; break; + default: + { + if(c >= 32 && c <= 126) + { + os<<c; + } + else + { + u32 cnum = (u32) (u8) c; + os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum; + } + break; + } + } + } + os<<"\""; + return os.str(); +} + +// Reads a string encoded in JSON format +std::string deSerializeJsonString(std::istream &is) +{ + std::ostringstream os(std::ios::binary); + char c, c2; + + // Parse initial doublequote + is >> c; + if(c != '"') + throw SerializationError("JSON string must start with doublequote"); + + // Parse characters + for(;;) + { + c = is.get(); + if(is.eof()) + throw SerializationError("JSON string ended prematurely"); + if(c == '"') + { + return os.str(); + } + else if(c == '\\') + { + c2 = is.get(); + if(is.eof()) + throw SerializationError("JSON string ended prematurely"); + switch(c2) + { + default: os<<c2; break; + case 'b': os<<'\b'; break; + case 'f': os<<'\f'; break; + case 'n': os<<'\n'; break; + case 'r': os<<'\r'; break; + case 't': os<<'\t'; break; + case 'u': + { + char hexdigits[4+1]; + is.read(hexdigits, 4); + if(is.eof()) + throw SerializationError("JSON string ended prematurely"); + hexdigits[4] = 0; + std::istringstream tmp_is(hexdigits, std::ios::binary); + int hexnumber; + tmp_is >> std::hex >> hexnumber; + os<<((char)hexnumber); + break; + } + } + } + else + { + os<<c; + } + } + return os.str(); +} + + diff --git a/src/util/serialize.h b/src/util/serialize.h new file mode 100644 index 000000000..e229a00be --- /dev/null +++ b/src/util/serialize.h @@ -0,0 +1,456 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef UTIL_SERIALIZE_HEADER +#define UTIL_SERIALIZE_HEADER + +#include "../irrlichttypes.h" +#include <iostream> +#include <string> +#include "../exceptions.h" +#include "pointer.h" + +inline void writeU64(u8 *data, u64 i) +{ + data[0] = ((i>>56)&0xff); + data[1] = ((i>>48)&0xff); + data[2] = ((i>>40)&0xff); + data[3] = ((i>>32)&0xff); + data[4] = ((i>>24)&0xff); + data[5] = ((i>>16)&0xff); + data[6] = ((i>> 8)&0xff); + data[7] = ((i>> 0)&0xff); +} + +inline void writeU32(u8 *data, u32 i) +{ + data[0] = ((i>>24)&0xff); + data[1] = ((i>>16)&0xff); + data[2] = ((i>> 8)&0xff); + data[3] = ((i>> 0)&0xff); +} + +inline void writeU16(u8 *data, u16 i) +{ + data[0] = ((i>> 8)&0xff); + data[1] = ((i>> 0)&0xff); +} + +inline void writeU8(u8 *data, u8 i) +{ + data[0] = ((i>> 0)&0xff); +} + +inline u64 readU64(u8 *data) +{ + return ((u64)data[0]<<56) | ((u64)data[1]<<48) + | ((u64)data[2]<<40) | ((u64)data[3]<<32) + | ((u64)data[4]<<24) | ((u64)data[5]<<16) + | ((u64)data[6]<<8) | ((u64)data[7]<<0); +} + +inline u32 readU32(u8 *data) +{ + return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0); +} + +inline u16 readU16(u8 *data) +{ + return (data[0]<<8) | (data[1]<<0); +} + +inline u8 readU8(u8 *data) +{ + return (data[0]<<0); +} + +inline void writeS32(u8 *data, s32 i){ + writeU32(data, (u32)i); +} +inline s32 readS32(u8 *data){ + return (s32)readU32(data); +} + +inline void writeS16(u8 *data, s16 i){ + writeU16(data, (u16)i); +} +inline s16 readS16(u8 *data){ + return (s16)readU16(data); +} + +inline void writeS8(u8 *data, s8 i){ + writeU8(data, (u8)i); +} +inline s8 readS8(u8 *data){ + return (s8)readU8(data); +} + +inline void writeF1000(u8 *data, f32 i){ + writeS32(data, i*1000); +} +inline f32 readF1000(u8 *data){ + return (f32)readS32(data)/1000.; +} + +inline void writeV3S32(u8 *data, v3s32 p) +{ + writeS32(&data[0], p.X); + writeS32(&data[4], p.Y); + writeS32(&data[8], p.Z); +} +inline v3s32 readV3S32(u8 *data) +{ + v3s32 p; + p.X = readS32(&data[0]); + p.Y = readS32(&data[4]); + p.Z = readS32(&data[8]); + return p; +} + +inline void writeV3F1000(u8 *data, v3f p) +{ + writeF1000(&data[0], p.X); + writeF1000(&data[4], p.Y); + writeF1000(&data[8], p.Z); +} +inline v3f readV3F1000(u8 *data) +{ + v3f p; + p.X = (float)readF1000(&data[0]); + p.Y = (float)readF1000(&data[4]); + p.Z = (float)readF1000(&data[8]); + return p; +} + +inline void writeV2F1000(u8 *data, v2f p) +{ + writeF1000(&data[0], p.X); + writeF1000(&data[4], p.Y); +} +inline v2f readV2F1000(u8 *data) +{ + v2f p; + p.X = (float)readF1000(&data[0]); + p.Y = (float)readF1000(&data[4]); + return p; +} + +inline void writeV2S16(u8 *data, v2s16 p) +{ + writeS16(&data[0], p.X); + writeS16(&data[2], p.Y); +} + +inline v2s16 readV2S16(u8 *data) +{ + v2s16 p; + p.X = readS16(&data[0]); + p.Y = readS16(&data[2]); + return p; +} + +inline void writeV2S32(u8 *data, v2s32 p) +{ + writeS32(&data[0], p.X); + writeS32(&data[2], p.Y); +} + +inline v2s32 readV2S32(u8 *data) +{ + v2s32 p; + p.X = readS32(&data[0]); + p.Y = readS32(&data[2]); + return p; +} + +inline void writeV3S16(u8 *data, v3s16 p) +{ + writeS16(&data[0], p.X); + writeS16(&data[2], p.Y); + writeS16(&data[4], p.Z); +} + +inline v3s16 readV3S16(u8 *data) +{ + v3s16 p; + p.X = readS16(&data[0]); + p.Y = readS16(&data[2]); + p.Z = readS16(&data[4]); + return p; +} + +/* + The above stuff directly interfaced to iostream +*/ + +inline void writeU8(std::ostream &os, u8 p) +{ + char buf[1] = {0}; + writeU8((u8*)buf, p); + os.write(buf, 1); +} +inline u8 readU8(std::istream &is) +{ + char buf[1] = {0}; + is.read(buf, 1); + return readU8((u8*)buf); +} + +inline void writeU16(std::ostream &os, u16 p) +{ + char buf[2] = {0}; + writeU16((u8*)buf, p); + os.write(buf, 2); +} +inline u16 readU16(std::istream &is) +{ + char buf[2] = {0}; + is.read(buf, 2); + return readU16((u8*)buf); +} + +inline void writeU32(std::ostream &os, u32 p) +{ + char buf[4] = {0}; + writeU32((u8*)buf, p); + os.write(buf, 4); +} +inline u32 readU32(std::istream &is) +{ + char buf[4] = {0}; + is.read(buf, 4); + return readU32((u8*)buf); +} + +inline void writeS32(std::ostream &os, s32 p) +{ + char buf[4] = {0}; + writeS32((u8*)buf, p); + os.write(buf, 4); +} +inline s32 readS32(std::istream &is) +{ + char buf[4] = {0}; + is.read(buf, 4); + return readS32((u8*)buf); +} + +inline void writeS16(std::ostream &os, s16 p) +{ + char buf[2] = {0}; + writeS16((u8*)buf, p); + os.write(buf, 2); +} +inline s16 readS16(std::istream &is) +{ + char buf[2] = {0}; + is.read(buf, 2); + return readS16((u8*)buf); +} + +inline void writeS8(std::ostream &os, s8 p) +{ + char buf[1] = {0}; + writeS8((u8*)buf, p); + os.write(buf, 1); +} +inline s8 readS8(std::istream &is) +{ + char buf[1] = {0}; + is.read(buf, 1); + return readS8((u8*)buf); +} + +inline void writeF1000(std::ostream &os, f32 p) +{ + char buf[4] = {0}; + writeF1000((u8*)buf, p); + os.write(buf, 4); +} +inline f32 readF1000(std::istream &is) +{ + char buf[4] = {0}; + is.read(buf, 4); + return readF1000((u8*)buf); +} + +inline void writeV3F1000(std::ostream &os, v3f p) +{ + char buf[12]; + writeV3F1000((u8*)buf, p); + os.write(buf, 12); +} +inline v3f readV3F1000(std::istream &is) +{ + char buf[12]; + is.read(buf, 12); + return readV3F1000((u8*)buf); +} + +inline void writeV2F1000(std::ostream &os, v2f p) +{ + char buf[8] = {0}; + writeV2F1000((u8*)buf, p); + os.write(buf, 8); +} +inline v2f readV2F1000(std::istream &is) +{ + char buf[8] = {0}; + is.read(buf, 8); + return readV2F1000((u8*)buf); +} + +inline void writeV2S16(std::ostream &os, v2s16 p) +{ + char buf[4] = {0}; + writeV2S16((u8*)buf, p); + os.write(buf, 4); +} +inline v2s16 readV2S16(std::istream &is) +{ + char buf[4] = {0}; + is.read(buf, 4); + return readV2S16((u8*)buf); +} + +inline void writeV3S16(std::ostream &os, v3s16 p) +{ + char buf[6] = {0}; + writeV3S16((u8*)buf, p); + os.write(buf, 6); +} +inline v3s16 readV3S16(std::istream &is) +{ + char buf[6] = {0}; + is.read(buf, 6); + return readV3S16((u8*)buf); +} + +/* + More serialization stuff +*/ + +// Creates a string with the length as the first two bytes +inline std::string serializeString(const std::string &plain) +{ + //assert(plain.size() <= 65535); + if(plain.size() > 65535) + throw SerializationError("String too long for serializeString"); + char buf[2]; + writeU16((u8*)&buf[0], plain.size()); + std::string s; + s.append(buf, 2); + s.append(plain); + return s; +} + +// Creates a string with the length as the first two bytes from wide string +inline std::string serializeWideString(const std::wstring &plain) +{ + //assert(plain.size() <= 65535); + if(plain.size() > 65535) + throw SerializationError("String too long for serializeString"); + char buf[2]; + writeU16((u8*)buf, plain.size()); + std::string s; + s.append(buf, 2); + for(u32 i=0; i<plain.size(); i++) + { + writeU16((u8*)buf, plain[i]); + s.append(buf, 2); + } + return s; +} + +// Reads a string with the length as the first two bytes +inline std::string deSerializeString(std::istream &is) +{ + char buf[2]; + is.read(buf, 2); + if(is.gcount() != 2) + throw SerializationError("deSerializeString: size not read"); + u16 s_size = readU16((u8*)buf); + if(s_size == 0) + return ""; + Buffer<char> buf2(s_size); + is.read(&buf2[0], s_size); + std::string s; + s.reserve(s_size); + s.append(&buf2[0], s_size); + return s; +} + +// Reads a wide string with the length as the first two bytes +inline std::wstring deSerializeWideString(std::istream &is) +{ + char buf[2]; + is.read(buf, 2); + if(is.gcount() != 2) + throw SerializationError("deSerializeString: size not read"); + u16 s_size = readU16((u8*)buf); + if(s_size == 0) + return L""; + std::wstring s; + s.reserve(s_size); + for(u32 i=0; i<s_size; i++) + { + is.read(&buf[0], 2); + wchar_t c16 = readU16((u8*)buf); + s.append(&c16, 1); + } + return s; +} + +// Creates a string with the length as the first four bytes +inline std::string serializeLongString(const std::string &plain) +{ + char buf[4]; + writeU32((u8*)&buf[0], plain.size()); + std::string s; + s.append(buf, 4); + s.append(plain); + return s; +} + +// Reads a string with the length as the first four bytes +inline std::string deSerializeLongString(std::istream &is) +{ + char buf[4]; + is.read(buf, 4); + if(is.gcount() != 4) + throw SerializationError("deSerializeLongString: size not read"); + u32 s_size = readU32((u8*)buf); + if(s_size == 0) + return ""; + Buffer<char> buf2(s_size); + is.read(&buf2[0], s_size); + std::string s; + s.reserve(s_size); + s.append(&buf2[0], s_size); + return s; +} + +// Creates a string encoded in JSON format (almost equivalent to a C string literal) +std::string serializeJsonString(const std::string &plain); + +// Reads a string encoded in JSON format +std::string deSerializeJsonString(std::istream &is); + +#endif + diff --git a/src/util/string.cpp b/src/util/string.cpp new file mode 100644 index 000000000..ee4df849e --- /dev/null +++ b/src/util/string.cpp @@ -0,0 +1,43 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "string.h" + +#include "sha1.h" +#include "base64.h" + +// Get an sha-1 hash of the player's name combined with +// the password entered. That's what the server uses as +// their password. (Exception : if the password field is +// blank, we send a blank password - this is for backwards +// compatibility with password-less players). +std::string translatePassword(std::string playername, std::wstring password) +{ + if(password.length() == 0) + return ""; + + std::string slt = playername + wide_to_narrow(password); + SHA1 sha1; + sha1.addBytes(slt.c_str(), slt.length()); + unsigned char *digest = sha1.getDigest(); + std::string pwd = base64_encode(digest, 20); + free(digest); + return pwd; +} + diff --git a/src/util/string.h b/src/util/string.h new file mode 100644 index 000000000..97b07f2ff --- /dev/null +++ b/src/util/string.h @@ -0,0 +1,264 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef UTIL_STRING_HEADER +#define UTIL_STRING_HEADER + +#include "../irrlichttypes.h" +#include "../strfnd.h" // For trim() +#include "pointer.h" +#include <string> +#include <cstring> +#include <vector> +#include <sstream> + +static inline std::string padStringRight(std::string s, size_t len) +{ + if(len > s.size()) + s.insert(s.end(), len - s.size(), ' '); + return s; +} + +// ends: NULL- or ""-terminated array of strings +// Returns "" if no end could be removed. +static inline std::string removeStringEnd(const std::string &s, const char *ends[]) +{ + const char **p = ends; + for(; (*p) && (*p)[0] != '\0'; p++){ + std::string end = *p; + if(s.size() < end.size()) + continue; + if(s.substr(s.size()-end.size(), end.size()) == end) + return s.substr(0, s.size() - end.size()); + } + return ""; +} + +// Tests if two strings are equal, optionally case insensitive +inline bool str_equal(const std::wstring& s1, const std::wstring& s2, + bool case_insensitive = false) +{ + if(case_insensitive) + { + if(s1.size() != s2.size()) + return false; + for(size_t i = 0; i < s1.size(); ++i) + if(tolower(s1[i]) != tolower(s2[i])) + return false; + return true; + } + else + { + return s1 == s2; + } +} + +// Tests if the second string is a prefix of the first, optionally case insensitive +inline bool str_starts_with(const std::wstring& str, const std::wstring& prefix, + bool case_insensitive = false) +{ + if(str.size() < prefix.size()) + return false; + if(case_insensitive) + { + for(size_t i = 0; i < prefix.size(); ++i) + if(tolower(str[i]) != tolower(prefix[i])) + return false; + } + else + { + for(size_t i = 0; i < prefix.size(); ++i) + if(str[i] != prefix[i]) + return false; + } + return true; +} + +inline std::wstring narrow_to_wide(const std::string& mbs) +{ + size_t wcl = mbs.size(); + Buffer<wchar_t> wcs(wcl+1); + size_t l = mbstowcs(*wcs, mbs.c_str(), wcl); + if(l == (size_t)(-1)) + return L"<invalid multibyte string>"; + wcs[l] = 0; + return *wcs; +} + +inline std::string wide_to_narrow(const std::wstring& wcs) +{ + size_t mbl = wcs.size()*4; + SharedBuffer<char> mbs(mbl+1); + size_t l = wcstombs(*mbs, wcs.c_str(), mbl); + if(l == (size_t)(-1)) + mbs[0] = 0; + else + mbs[l] = 0; + return *mbs; +} + +// Split a string using the given delimiter. Returns a vector containing +// the component parts. +inline std::vector<std::wstring> str_split(const std::wstring &str, wchar_t delimiter) +{ + std::vector<std::wstring> parts; + std::wstringstream sstr(str); + std::wstring part; + while(std::getline(sstr, part, delimiter)) + parts.push_back(part); + return parts; +} + +inline std::string lowercase(const std::string &s) +{ + std::string s2; + for(size_t i=0; i<s.size(); i++) + { + char c = s[i]; + if(c >= 'A' && c <= 'Z') + c -= 'A' - 'a'; + s2 += c; + } + return s2; +} + +inline bool is_yes(const std::string &s) +{ + std::string s2 = lowercase(trim(s)); + if(s2 == "y" || s2 == "yes" || s2 == "true" || s2 == "1") + return true; + return false; +} + +inline s32 mystoi(const std::string &s, s32 min, s32 max) +{ + s32 i = atoi(s.c_str()); + if(i < min) + i = min; + if(i > max) + i = max; + return i; +} + + +// MSVC2010 includes it's own versions of these +//#if !defined(_MSC_VER) || _MSC_VER < 1600 + +inline s32 mystoi(const std::string &s) +{ + return atoi(s.c_str()); +} + +inline s32 mystoi(const std::wstring &s) +{ + return atoi(wide_to_narrow(s).c_str()); +} + +inline float mystof(const std::string &s) +{ + // This crap causes a segfault in certain cases on MinGW + /*float f; + std::istringstream ss(s); + ss>>f; + return f;*/ + // This works in that case + return atof(s.c_str()); +} + +//#endif + +#define stoi mystoi +#define stof mystof + +inline std::string itos(s32 i) +{ + std::ostringstream o; + o<<i; + return o.str(); +} + +inline std::string ftos(float f) +{ + std::ostringstream o; + o<<f; + return o.str(); +} + +inline void str_replace(std::string & str, std::string const & pattern, + std::string const & replacement) +{ + std::string::size_type start = str.find(pattern, 0); + while(start != str.npos) + { + str.replace(start, pattern.size(), replacement); + start = str.find(pattern, start+replacement.size()); + } +} + +inline void str_replace_char(std::string & str, char from, char to) +{ + for(unsigned int i=0; i<str.size(); i++) + { + if(str[i] == from) + str[i] = to; + } +} + +/* + Checks if a string contains only supplied characters +*/ +inline bool string_allowed(const std::string &s, const std::string &allowed_chars) +{ + for(u32 i=0; i<s.size(); i++) + { + bool confirmed = false; + for(u32 j=0; j<allowed_chars.size(); j++) + { + if(s[i] == allowed_chars[j]) + { + confirmed = true; + break; + } + } + if(confirmed == false) + return false; + } + return true; +} + +/* + Forcefully wraps string into rows using \n + (no word wrap, used for showing paths in gui) +*/ +inline std::string wrap_rows(const std::string &from, u32 rowlen) +{ + std::string to; + for(u32 i=0; i<from.size(); i++) + { + if(i != 0 && i%rowlen == 0) + to += '\n'; + to += from[i]; + } + return to; +} + +std::string translatePassword(std::string playername, std::wstring password); + +#endif + diff --git a/src/util/thread.h b/src/util/thread.h new file mode 100644 index 000000000..8e8c74ac5 --- /dev/null +++ b/src/util/thread.h @@ -0,0 +1,227 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef UTIL_THREAD_HEADER +#define UTIL_THREAD_HEADER + +#include "../irrlichttypes.h" +#include <jthread.h> +#include <jmutex.h> +#include <jmutexautolock.h> + +template<typename T> +class MutexedVariable +{ +public: + MutexedVariable(T value): + m_value(value) + { + m_mutex.Init(); + } + + T get() + { + JMutexAutoLock lock(m_mutex); + return m_value; + } + + void set(T value) + { + JMutexAutoLock lock(m_mutex); + m_value = value; + } + + // You'll want to grab this in a SharedPtr + JMutexAutoLock * getLock() + { + return new JMutexAutoLock(m_mutex); + } + + // You pretty surely want to grab the lock when accessing this + T m_value; + +private: + JMutex m_mutex; +}; + +/* + A base class for simple background thread implementation +*/ + +class SimpleThread : public JThread +{ + bool run; + JMutex run_mutex; + +public: + + SimpleThread(): + JThread(), + run(true) + { + run_mutex.Init(); + } + + virtual ~SimpleThread() + {} + + virtual void * Thread() = 0; + + bool getRun() + { + JMutexAutoLock lock(run_mutex); + return run; + } + void setRun(bool a_run) + { + JMutexAutoLock lock(run_mutex); + run = a_run; + } + + void stop() + { + setRun(false); + while(IsRunning()) + sleep_ms(100); + } +}; + +/* + A single worker thread - multiple client threads queue framework. +*/ + +template<typename Caller, typename Data> +class CallerInfo +{ +public: + Caller caller; + Data data; +}; + +template<typename Key, typename T, typename Caller, typename CallerData> +class GetResult +{ +public: + Key key; + T item; + core::list<CallerInfo<Caller, CallerData> > callers; +}; + +template<typename Key, typename T, typename Caller, typename CallerData> +class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> > +{ +}; + +template<typename Key, typename T, typename Caller, typename CallerData> +class GetRequest +{ +public: + GetRequest() + { + dest = NULL; + } + GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest) + { + dest = a_dest; + } + GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest, + Key a_key) + { + dest = a_dest; + key = a_key; + } + ~GetRequest() + { + } + + Key key; + ResultQueue<Key, T, Caller, CallerData> *dest; + core::list<CallerInfo<Caller, CallerData> > callers; +}; + +template<typename Key, typename T, typename Caller, typename CallerData> +class RequestQueue +{ +public: + u32 size() + { + return m_queue.size(); + } + + void add(Key key, Caller caller, CallerData callerdata, + ResultQueue<Key, T, Caller, CallerData> *dest) + { + JMutexAutoLock lock(m_queue.getMutex()); + + /* + If the caller is already on the list, only update CallerData + */ + for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator + i = m_queue.getList().begin(); + i != m_queue.getList().end(); i++) + { + GetRequest<Key, T, Caller, CallerData> &request = *i; + + if(request.key == key) + { + for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator + i = request.callers.begin(); + i != request.callers.end(); i++) + { + CallerInfo<Caller, CallerData> &ca = *i; + if(ca.caller == caller) + { + ca.data = callerdata; + return; + } + } + CallerInfo<Caller, CallerData> ca; + ca.caller = caller; + ca.data = callerdata; + request.callers.push_back(ca); + return; + } + } + + /* + Else add a new request to the queue + */ + + GetRequest<Key, T, Caller, CallerData> request; + request.key = key; + CallerInfo<Caller, CallerData> ca; + ca.caller = caller; + ca.data = callerdata; + request.callers.push_back(ca); + request.dest = dest; + + m_queue.getList().push_back(request); + } + + GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false) + { + return m_queue.pop_front(wait_if_empty); + } + +private: + MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue; +}; + +#endif + diff --git a/src/util/timetaker.cpp b/src/util/timetaker.cpp new file mode 100644 index 000000000..9cc87f3ea --- /dev/null +++ b/src/util/timetaker.cpp @@ -0,0 +1,61 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "timetaker.h" + +#include "gettime.h" +#include "log.h" +#include <ostream> + +TimeTaker::TimeTaker(const char *name, u32 *result) +{ + m_name = name; + m_result = result; + m_running = true; + m_time1 = getTimeMs(); +} + +u32 TimeTaker::stop(bool quiet) +{ + if(m_running) + { + u32 time2 = getTimeMs(); + u32 dtime = time2 - m_time1; + if(m_result != NULL) + { + (*m_result) += dtime; + } + else + { + if(quiet == false) + infostream<<m_name<<" took "<<dtime<<"ms"<<std::endl; + } + m_running = false; + return dtime; + } + return 0; +} + +u32 TimeTaker::getTime() +{ + u32 time2 = getTimeMs(); + u32 dtime = time2 - m_time1; + return dtime; +} + diff --git a/src/util/timetaker.h b/src/util/timetaker.h new file mode 100644 index 000000000..8aad97d0f --- /dev/null +++ b/src/util/timetaker.h @@ -0,0 +1,51 @@ +/* +Minetest-c55 +Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef UTIL_TIMETAKER_HEADER +#define UTIL_TIMETAKER_HEADER + +#include "../irrlichttypes.h" + +/* + TimeTaker +*/ + +class TimeTaker +{ +public: + TimeTaker(const char *name, u32 *result=NULL); + + ~TimeTaker() + { + stop(); + } + + u32 stop(bool quiet=false); + + u32 getTime(); + +private: + const char *m_name; + u32 m_time1; + bool m_running; + u32 *m_result; +}; + +#endif + |