3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #ifndef UTILITY_HEADER
21 #define UTILITY_HEADER
29 #include <jmutexautolock.h>
31 #include "common_irrlicht.h"
34 #include "exceptions.h"
37 extern const v3s16 g_26dirs[26];
40 extern const v3s16 g_27dirs[27];
42 inline void writeU32(u8 *data, u32 i)
44 data[0] = ((i>>24)&0xff);
45 data[1] = ((i>>16)&0xff);
46 data[2] = ((i>> 8)&0xff);
47 data[3] = ((i>> 0)&0xff);
50 inline void writeU16(u8 *data, u16 i)
52 data[0] = ((i>> 8)&0xff);
53 data[1] = ((i>> 0)&0xff);
56 inline void writeU8(u8 *data, u8 i)
58 data[0] = ((i>> 0)&0xff);
61 inline u32 readU32(u8 *data)
63 return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
66 inline u16 readU16(u8 *data)
68 return (data[0]<<8) | (data[1]<<0);
71 inline u8 readU8(u8 *data)
76 // Signed variants of the above
78 inline void writeS32(u8 *data, s32 i){
79 writeU32(data, (u32)i);
81 inline s32 readS32(u8 *data){
82 return (s32)readU32(data);
85 inline void writeS16(u8 *data, s16 i){
86 writeU16(data, (u16)i);
88 inline s16 readS16(u8 *data){
89 return (s16)readU16(data);
92 inline void writeV3S32(u8 *data, v3s32 p)
94 writeS32(&data[0], p.X);
95 writeS32(&data[4], p.Y);
96 writeS32(&data[8], p.Z);
99 inline v3s32 readV3S32(u8 *data)
102 p.X = readS32(&data[0]);
103 p.Y = readS32(&data[4]);
104 p.Z = readS32(&data[8]);
108 inline void writeV2S16(u8 *data, v2s16 p)
110 writeS16(&data[0], p.X);
111 writeS16(&data[2], p.Y);
114 inline v2s16 readV2S16(u8 *data)
117 p.X = readS16(&data[0]);
118 p.Y = readS16(&data[2]);
122 inline void writeV2S32(u8 *data, v2s32 p)
124 writeS32(&data[0], p.X);
125 writeS32(&data[2], p.Y);
128 inline v2s32 readV2S32(u8 *data)
131 p.X = readS32(&data[0]);
132 p.Y = readS32(&data[2]);
136 inline void writeV3S16(u8 *data, v3s16 p)
138 writeS16(&data[0], p.X);
139 writeS16(&data[2], p.Y);
140 writeS16(&data[4], p.Z);
143 inline v3s16 readV3S16(u8 *data)
146 p.X = readS16(&data[0]);
147 p.Y = readS16(&data[2]);
148 p.Z = readS16(&data[4]);
153 None of these are used at the moment
156 template <typename T>
166 SharedPtr(SharedPtr<T> &t)
170 refcount = t.refcount;
178 SharedPtr<T> & operator=(T *t)
186 SharedPtr<T> & operator=(SharedPtr<T> &t)
189 refcount = t.refcount;
202 bool operator!=(T *t)
206 bool operator==(T *t)
210 T & operator[](unsigned int i)
217 assert((*refcount) > 0);
230 template <typename T>
234 Buffer(unsigned int size)
239 Buffer(const Buffer &buffer)
241 m_size = buffer.m_size;
242 data = new T[buffer.m_size];
243 memcpy(data, buffer.data, buffer.m_size);
245 Buffer(T *t, unsigned int size)
249 memcpy(data, t, size);
255 T & operator[](unsigned int i) const
259 T * operator*() const
263 unsigned int getSize() const
272 template <typename T>
276 SharedBuffer(unsigned int size)
280 refcount = new unsigned int;
283 SharedBuffer(const SharedBuffer &buffer)
285 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
286 m_size = buffer.m_size;
288 refcount = buffer.refcount;
291 SharedBuffer & operator=(const SharedBuffer & buffer)
293 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
297 m_size = buffer.m_size;
299 refcount = buffer.refcount;
306 SharedBuffer(T *t, unsigned int size)
310 memcpy(data, t, size);
311 refcount = new unsigned int;
317 SharedBuffer(const Buffer<T> &buffer)
319 m_size = buffer.m_size;
320 data = new T[buffer.getSize()];
321 memcpy(data, *buffer, buffer.getSize());
322 refcount = new unsigned int;
329 T & operator[](unsigned int i) const
333 T * operator*() const
337 unsigned int getSize() const
344 assert((*refcount) > 0);
354 unsigned int *refcount;
357 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
359 SharedBuffer<u8> b((u8*)string, strlen(string)+1);
364 class MutexedVariable
367 MutexedVariable(T value):
375 JMutexAutoLock lock(m_mutex);
381 JMutexAutoLock lock(m_mutex);
385 // You'll want to grab this in a SharedPtr
386 JMutexAutoLock * getLock()
388 return new JMutexAutoLock(m_mutex);
391 // You pretty surely want to grab the lock when accessing this
402 class IrrlichtWrapper;
407 TimeTaker(const char *name, u32 *result=NULL);
414 u32 stop(bool quiet=false);
425 // Calculates the borders of a "d-radius" cube
426 inline void getFacePositions(core::list<v3s16> &list, u16 d)
430 list.push_back(v3s16(0,0,0));
436 This is an optimized sequence of coordinates.
438 list.push_back(v3s16( 0, 1, 0)); // top
439 list.push_back(v3s16( 0, 0, 1)); // back
440 list.push_back(v3s16(-1, 0, 0)); // left
441 list.push_back(v3s16( 1, 0, 0)); // right
442 list.push_back(v3s16( 0, 0,-1)); // front
443 list.push_back(v3s16( 0,-1, 0)); // bottom
445 list.push_back(v3s16(-1, 0, 1)); // back left
446 list.push_back(v3s16( 1, 0, 1)); // back right
447 list.push_back(v3s16(-1, 0,-1)); // front left
448 list.push_back(v3s16( 1, 0,-1)); // front right
449 list.push_back(v3s16(-1,-1, 0)); // bottom left
450 list.push_back(v3s16( 1,-1, 0)); // bottom right
451 list.push_back(v3s16( 0,-1, 1)); // bottom back
452 list.push_back(v3s16( 0,-1,-1)); // bottom front
453 list.push_back(v3s16(-1, 1, 0)); // top left
454 list.push_back(v3s16( 1, 1, 0)); // top right
455 list.push_back(v3s16( 0, 1, 1)); // top back
456 list.push_back(v3s16( 0, 1,-1)); // top front
458 list.push_back(v3s16(-1, 1, 1)); // top back-left
459 list.push_back(v3s16( 1, 1, 1)); // top back-right
460 list.push_back(v3s16(-1, 1,-1)); // top front-left
461 list.push_back(v3s16( 1, 1,-1)); // top front-right
462 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
463 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
464 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
465 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
470 // Take blocks in all sides, starting from y=0 and going +-y
471 for(s16 y=0; y<=d-1; y++)
473 // Left and right side, including borders
474 for(s16 z=-d; z<=d; z++)
476 list.push_back(v3s16(d,y,z));
477 list.push_back(v3s16(-d,y,z));
480 list.push_back(v3s16(d,-y,z));
481 list.push_back(v3s16(-d,-y,z));
484 // Back and front side, excluding borders
485 for(s16 x=-d+1; x<=d-1; x++)
487 list.push_back(v3s16(x,y,d));
488 list.push_back(v3s16(x,y,-d));
491 list.push_back(v3s16(x,-y,d));
492 list.push_back(v3s16(x,-y,-d));
497 // Take the bottom and top face with borders
498 // -d<x<d, y=+-d, -d<z<d
499 for(s16 x=-d; x<=d; x++)
500 for(s16 z=-d; z<=d; z++)
502 list.push_back(v3s16(x,-d,z));
503 list.push_back(v3s16(x,d,z));
507 class IndentationRaiser
510 IndentationRaiser(u16 *indentation)
512 m_indentation = indentation;
523 inline s16 getContainerPos(s16 p, s16 d)
525 return (p>=0 ? p : p-d+1) / d;
528 inline v2s16 getContainerPos(v2s16 p, s16 d)
531 getContainerPos(p.X, d),
532 getContainerPos(p.Y, d)
536 inline v3s16 getContainerPos(v3s16 p, s16 d)
539 getContainerPos(p.X, d),
540 getContainerPos(p.Y, d),
541 getContainerPos(p.Z, d)
545 inline v2s16 getContainerPos(v2s16 p, v2s16 d)
548 getContainerPos(p.X, d.X),
549 getContainerPos(p.Y, d.Y)
553 inline v3s16 getContainerPos(v3s16 p, v3s16 d)
556 getContainerPos(p.X, d.X),
557 getContainerPos(p.Y, d.Y),
558 getContainerPos(p.Z, d.Z)
562 inline bool isInArea(v3s16 p, s16 d)
565 p.X >= 0 && p.X < d &&
566 p.Y >= 0 && p.Y < d &&
571 inline bool isInArea(v2s16 p, s16 d)
574 p.X >= 0 && p.X < d &&
579 inline bool isInArea(v3s16 p, v3s16 d)
582 p.X >= 0 && p.X < d.X &&
583 p.Y >= 0 && p.Y < d.Y &&
584 p.Z >= 0 && p.Z < d.Z
588 inline s16 rangelim(s16 i, s16 min, s16 max)
597 inline s16 rangelim(s16 i, s16 max)
606 inline v3s16 arealim(v3s16 p, s16 d)
623 inline std::wstring narrow_to_wide(const std::string& mbs)
625 size_t wcl = mbs.size();
626 SharedBuffer<wchar_t> wcs(wcl+1);
627 size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
632 inline std::string wide_to_narrow(const std::wstring& wcs)
634 size_t mbl = wcs.size()*4;
635 SharedBuffer<char> mbs(mbl+1);
636 size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
645 See test.cpp for example cases.
646 wraps degrees to the range of -360...360
647 NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
649 inline float wrapDegrees(float f)
651 // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
657 // NOTE: This would be used for wrapping to 0...360
663 // 10, 0.5, -0.5, -0.5
668 inline std::string lowercase(const std::string &s)
671 for(size_t i=0; i<s.size(); i++)
674 if(c >= 'A' && c <= 'Z')
681 inline bool is_yes(const std::string &s)
683 std::string s2 = lowercase(trim(s));
684 if(s2 == "y" || s2 == "yes" || s2 == "true" || s2 == "1")
689 inline s32 stoi(const std::string &s, s32 min, s32 max)
691 s32 i = atoi(s.c_str());
699 inline s32 stoi(std::string s)
701 return atoi(s.c_str());
704 inline float stof(std::string s)
707 std::istringstream ss(s);
712 inline std::string itos(s32 i)
714 std::ostringstream o;
719 inline std::string ftos(float f)
721 std::ostringstream o;
727 A base class for simple background thread implementation
730 class SimpleThread : public JThread
744 virtual ~SimpleThread()
747 virtual void * Thread() = 0;
751 JMutexAutoLock lock(run_mutex);
754 void setRun(bool a_run)
756 JMutexAutoLock lock(run_mutex);
775 VALUETYPE_FLAG // Doesn't take any arguments
780 ValueSpec(ValueType a_type, const char *a_help=NULL)
793 void writeLines(std::ostream &os)
795 for(core::map<std::string, std::string>::Iterator
796 i = m_settings.getIterator();
797 i.atEnd() == false; i++)
799 std::string name = i.getNode()->getKey();
800 std::string value = i.getNode()->getValue();
801 os<<name<<" = "<<value<<"\n";
805 bool parseConfigLine(const std::string &line)
807 std::string trimmedline = trim(line);
810 if(trimmedline[0] == '#')
813 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
815 Strfnd sf(trim(line));
817 std::string name = sf.next("=");
823 std::string value = sf.next("\n");
826 /*dstream<<"Config name=\""<<name<<"\" value=\""
827 <<value<<"\""<<std::endl;*/
829 m_settings[name] = value;
834 // Returns false on EOF
835 bool parseConfigObject(std::istream &is)
841 NOTE: This function might be expanded to allow multi-line
845 std::getline(is, line);
846 //dstream<<"got line: \""<<line<<"\""<<std::endl;
848 return parseConfigLine(line);
852 Read configuration file
854 Returns true on success
856 bool readConfigFile(const char *filename)
858 std::ifstream is(filename);
859 if(is.good() == false)
861 dstream<<"Error opening configuration file \""
862 <<filename<<"\""<<std::endl;
866 dstream<<"Parsing configuration file: \""
867 <<filename<<"\""<<std::endl;
869 while(parseConfigObject(is));
875 Reads a configuration object from stream (usually a single line)
878 Preserves comments and empty lines.
880 Settings that were added to dst are also added to updated.
881 key of updated is setting name, value of updated is dummy.
885 bool getUpdatedConfigObject(std::istream &is,
886 core::list<std::string> &dst,
887 core::map<std::string, bool> &updated)
892 // NOTE: This function will be expanded to allow multi-line settings
894 std::getline(is, line);
896 std::string trimmedline = trim(line);
898 std::string line_end = "";
899 if(is.eof() == false)
903 if(trimmedline[0] == '#')
905 dst.push_back(line+line_end);
909 Strfnd sf(trim(line));
911 std::string name = sf.next("=");
916 dst.push_back(line+line_end);
920 std::string value = sf.next("\n");
923 if(m_settings.find(name))
925 std::string newvalue = m_settings[name];
927 if(newvalue != value)
929 dstream<<"Changing value of \""<<name<<"\" = \""
930 <<value<<"\" -> \""<<newvalue<<"\""
934 dst.push_back(name + " = " + newvalue + line_end);
936 updated[name] = true;
943 Updates configuration file
945 Returns true on success
947 bool updateConfigFile(const char *filename)
949 dstream<<"Updating configuration file: \""
950 <<filename<<"\""<<std::endl;
952 core::list<std::string> objects;
953 core::map<std::string, bool> updated;
955 // Read and modify stuff
957 std::ifstream is(filename);
958 if(is.good() == false)
960 dstream<<"Error opening configuration file"
962 <<filename<<"\""<<std::endl;
966 while(getUpdatedConfigObject(is, objects, updated));
971 std::ofstream os(filename);
972 if(os.good() == false)
974 dstream<<"Error opening configuration file"
976 <<filename<<"\""<<std::endl;
983 for(core::list<std::string>::Iterator
985 i != objects.end(); i++)
991 Write stuff that was not already in the file
993 for(core::map<std::string, std::string>::Iterator
994 i = m_settings.getIterator();
995 i.atEnd() == false; i++)
997 if(updated.find(i.getNode()->getKey()))
999 std::string name = i.getNode()->getKey();
1000 std::string value = i.getNode()->getValue();
1001 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
1003 os<<name<<" = "<<value<<"\n";
1011 NOTE: Types of allowed_options are ignored
1013 returns true on success
1015 bool parseCommandLine(int argc, char *argv[],
1016 core::map<std::string, ValueSpec> &allowed_options)
1023 std::string argname = argv[i];
1024 if(argname.substr(0, 2) != "--")
1026 dstream<<"Invalid command-line parameter \""
1027 <<argname<<"\": --<option> expected."<<std::endl;
1032 std::string name = argname.substr(2);
1034 core::map<std::string, ValueSpec>::Node *n;
1035 n = allowed_options.find(name);
1038 dstream<<"Unknown command-line parameter \""
1039 <<argname<<"\""<<std::endl;
1043 ValueType type = n->getValue().type;
1045 std::string value = "";
1047 if(type == VALUETYPE_FLAG)
1055 dstream<<"Invalid command-line parameter \""
1056 <<name<<"\": missing value"<<std::endl;
1064 dstream<<"Valid command-line parameter: \""
1065 <<name<<"\" = \""<<value<<"\""
1073 void set(std::string name, std::string value)
1075 m_settings[name] = value;
1078 void setDefault(std::string name, std::string value)
1080 m_defaults[name] = value;
1083 bool exists(std::string name)
1085 return (m_settings.find(name) || m_defaults.find(name));
1088 std::string get(std::string name)
1090 core::map<std::string, std::string>::Node *n;
1091 n = m_settings.find(name);
1094 n = m_defaults.find(name);
1097 throw SettingNotFoundException("Setting not found");
1101 return n->getValue();
1104 bool getBool(std::string name)
1106 return is_yes(get(name));
1109 bool getFlag(std::string name)
1113 return getBool(name);
1115 catch(SettingNotFoundException &e)
1122 bool getBoolAsk(std::string name, std::string question, bool def)
1124 // If it is in settings
1125 if(m_settings.find(name))
1126 return getBool(name);
1130 std::cout<<question<<" [y/N]: ";
1131 std::cin.getline(templine, 10);
1140 float getFloat(std::string name)
1142 return stof(get(name));
1145 u16 getU16(std::string name)
1147 return stoi(get(name), 0, 65535);
1150 u16 getU16Ask(std::string name, std::string question, u16 def)
1152 // If it is in settings
1153 if(m_settings.find(name))
1154 return getU16(name);
1158 std::cout<<question<<" ["<<def<<"]: ";
1159 std::cin.getline(templine, 10);
1165 return stoi(s, 0, 65535);
1168 s16 getS16(std::string name)
1170 return stoi(get(name), -32768, 32767);
1173 s32 getS32(std::string name)
1175 return stoi(get(name));
1178 v3f getV3F(std::string name)
1181 Strfnd f(get(name));
1183 value.X = stof(f.next(","));
1184 value.Y = stof(f.next(","));
1185 value.Z = stof(f.next(")"));
1189 void setS32(std::string name, s32 value)
1191 set(name, itos(value));
1194 void setFloat(std::string name, float value)
1196 set(name, ftos(value));
1199 void setV3F(std::string name, v3f value)
1201 std::ostringstream os;
1202 os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
1203 set(name, os.str());
1212 Settings & operator+=(Settings &other)
1217 for(core::map<std::string, std::string>::Iterator
1218 i = other.m_settings.getIterator();
1219 i.atEnd() == false; i++)
1221 m_settings.insert(i.getNode()->getKey(),
1222 i.getNode()->getValue());
1225 for(core::map<std::string, std::string>::Iterator
1226 i = other.m_defaults.getIterator();
1227 i.atEnd() == false; i++)
1229 m_defaults.insert(i.getNode()->getKey(),
1230 i.getNode()->getValue());
1235 Settings & operator=(Settings &other)
1247 core::map<std::string, std::string> m_settings;
1248 core::map<std::string, std::string> m_defaults;
1254 template<typename T>
1260 m_list.push_back(t);
1265 if(m_list.size() == 0)
1266 throw ItemNotFoundException("MutexedQueue: queue is empty");
1268 typename core::list<T>::Iterator begin = m_list.begin();
1270 m_list.erase(begin);
1276 return m_list.size();
1280 core::list<T> m_list;
1284 Thread-safe FIFO queue
1287 template<typename T>
1297 return m_list.size();
1301 JMutexAutoLock lock(m_mutex);
1302 m_list.push_back(t);
1304 T pop_front(u32 wait_time_max_ms=0)
1306 u32 wait_time_ms = 0;
1311 JMutexAutoLock lock(m_mutex);
1313 if(m_list.size() > 0)
1315 typename core::list<T>::Iterator begin = m_list.begin();
1317 m_list.erase(begin);
1321 if(wait_time_ms >= wait_time_max_ms)
1322 throw ItemNotFoundException("MutexedQueue: queue is empty");
1325 // Wait a while before trying again
1336 core::list<T> & getList()
1343 core::list<T> m_list;
1346 template<typename Caller, typename Data>
1354 template<typename Key, typename T, typename Caller, typename CallerData>
1360 core::list<CallerInfo<Caller, CallerData> > callers;
1363 template<typename Key, typename T, typename Caller, typename CallerData>
1364 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1368 template<typename Key, typename T, typename Caller, typename CallerData>
1376 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1380 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1391 ResultQueue<Key, T, Caller, CallerData> *dest;
1392 core::list<CallerInfo<Caller, CallerData> > callers;
1396 Quickhands for typical request-result queues.
1397 Used for distributing work between threads.
1400 template<typename Key, typename T, typename Caller, typename CallerData>
1406 return m_queue.size();
1409 void add(Key key, Caller caller, CallerData callerdata,
1410 ResultQueue<Key, T, Caller, CallerData> *dest)
1412 JMutexAutoLock lock(m_queue.getMutex());
1415 If the caller is already on the list, only update CallerData
1417 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1418 i = m_queue.getList().begin();
1419 i != m_queue.getList().end(); i++)
1421 GetRequest<Key, T, Caller, CallerData> &request = *i;
1423 if(request.key == key)
1425 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1426 i = request.callers.begin();
1427 i != request.callers.end(); i++)
1429 CallerInfo<Caller, CallerData> &ca = *i;
1430 if(ca.caller == caller)
1432 ca.data = callerdata;
1436 CallerInfo<Caller, CallerData> ca;
1438 ca.data = callerdata;
1439 request.callers.push_back(ca);
1445 Else add a new request to the queue
1448 GetRequest<Key, T, Caller, CallerData> request;
1450 CallerInfo<Caller, CallerData> ca;
1452 ca.data = callerdata;
1453 request.callers.push_back(ca);
1454 request.dest = dest;
1456 m_queue.getList().push_back(request);
1459 GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1461 return m_queue.pop_front(wait_if_empty);
1465 MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
1469 Pseudo-random (VC++ rand() sucks)
1472 void mysrand(unsigned seed);
1473 #define MYRAND_MAX 32767
1475 inline int myrand_range(int min, int max)
1482 return (myrand()%(max-min+1))+min;
1486 Some kind of a thing that stores attributes related to
1496 Attribute(const std::string &value):
1501 Attribute(float value)
1503 m_value = ftos(value);
1506 void set(const std::string &value)
1518 return is_yes(get());
1524 std::istringstream vis(get());
1531 return stoi(get(), 0, 65535);
1536 return stoi(get(), -32768, 32767);
1544 std::string m_value;
1547 class PointAttributeList
1549 struct PointWithAttr
1556 ~PointAttributeList()
1560 Attribute getNearAttr(v2s16 p)
1562 core::list<PointWithAttr>::Iterator
1563 nearest_i = m_points.end();
1564 s16 nearest_d = 32767;
1565 for(core::list<PointWithAttr>::Iterator
1566 i = m_points.begin();
1567 i != m_points.end(); i++)
1569 PointWithAttr &pwa = *i;
1570 s16 d = pwa.p.getDistanceFrom(p);
1578 if(nearest_i == m_points.end())
1581 return nearest_i->attr;
1584 Attribute getNearAttr(v3s16 p)
1586 return getNearAttr(v2s16(p.X, p.Z));
1591 return (m_points.size() == 0);
1595 Take all points in range, or at least the nearest point,
1596 and interpolate the values as floats
1598 float getInterpolatedFloat(v2s16 p);
1600 float getInterpolatedFloat(v3s16 p)
1602 return getInterpolatedFloat(v2s16(p.X, p.Z));
1605 void addPoint(v2s16 p, const Attribute &attr)
1607 PointWithAttr pattr;
1610 m_points.push_back(pattr);
1613 void addPoint(v3s16 p, const Attribute &attr)
1615 addPoint(v2s16(p.X, p.Z), attr);
1619 core::list<PointWithAttr> m_points;
1623 Basically just a wrapper to core::map<PointAttributeList*>
1626 class PointAttributeDatabase
1629 ~PointAttributeDatabase()
1631 for(core::map<std::string, PointAttributeList*>::Iterator
1632 i = m_lists.getIterator();
1633 i.atEnd() == false; i++)
1635 delete i.getNode()->getValue();
1639 PointAttributeList *getList(const std::string &name)
1641 PointAttributeList *list = NULL;
1643 core::map<std::string, PointAttributeList*>::Node *n;
1644 n = m_lists.find(name);
1648 list = new PointAttributeList();
1649 m_lists.insert(name, list);
1653 list = n->getValue();
1659 core::map<std::string, PointAttributeList*> m_lists;
1663 Miscellaneous functions
1666 bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range);
1669 Queue with unique values with fast checking of value existence
1672 template<typename Value>
1678 Does nothing if value is already queued.
1681 false: value already exists
1683 bool push_back(Value value)
1685 // Check if already exists
1686 if(m_map.find(value) != NULL)
1690 m_map.insert(value, 0);
1691 m_list.push_back(value);
1698 typename core::list<Value>::Iterator i = m_list.begin();
1700 m_map.remove(value);
1707 assert(m_list.size() == m_map.size());
1708 return m_list.size();
1712 core::map<Value, u8> m_map;
1713 core::list<Value> m_list;
1717 template<typename Key, typename Value>
1724 assert(m_mutex.IsInitialized());
1727 void set(const Key &name, const Value &value)
1729 JMutexAutoLock lock(m_mutex);
1731 m_values[name] = value;
1734 bool get(const Key &name, Value *result)
1736 JMutexAutoLock lock(m_mutex);
1738 typename core::map<Key, Value>::Node *n;
1739 n = m_values.find(name);
1744 *result = n->getValue();
1749 core::map<Key, Value> m_values;
1755 Generates ids for comparable values.
1756 Id=0 is reserved for "no value".
1759 - Returning value by id (very fast)
1760 - Returning id by value
1761 - Generating a new id for a value
1764 - Remove an id/value pair (is possible to implement but slow)
1766 template<typename T>
1767 class MutexedIdGenerator
1770 MutexedIdGenerator()
1773 assert(m_mutex.IsInitialized());
1776 // Returns true if found
1777 bool getValue(u32 id, T &value)
1781 JMutexAutoLock lock(m_mutex);
1782 if(m_id_to_value.size() < id)
1784 value = m_id_to_value[id-1];
1788 // If id exists for value, returns the id.
1789 // Otherwise generates an id for the value.
1790 u32 getId(const T &value)
1792 JMutexAutoLock lock(m_mutex);
1793 typename core::map<T, u32>::Node *n;
1794 n = m_value_to_id.find(value);
1796 return n->getValue();
1797 m_id_to_value.push_back(value);
1798 u32 new_id = m_id_to_value.size();
1799 m_value_to_id.insert(value, new_id);
1805 // Values are stored here at id-1 position (id 1 = [0])
1806 core::array<T> m_id_to_value;
1807 core::map<T, u32> m_value_to_id;
1811 Checks if a string contains only supplied characters
1813 inline bool string_allowed(const std::string &s, const std::string &allowed_chars)
1815 for(u32 i=0; i<s.size(); i++)
1817 bool confirmed = false;
1818 for(u32 j=0; j<allowed_chars.size(); j++)
1820 if(s[i] == allowed_chars[j])
1826 if(confirmed == false)