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];
39 inline void writeU32(u8 *data, u32 i)
41 data[0] = ((i>>24)&0xff);
42 data[1] = ((i>>16)&0xff);
43 data[2] = ((i>> 8)&0xff);
44 data[3] = ((i>> 0)&0xff);
47 inline void writeU16(u8 *data, u16 i)
49 data[0] = ((i>> 8)&0xff);
50 data[1] = ((i>> 0)&0xff);
53 inline void writeU8(u8 *data, u8 i)
55 data[0] = ((i>> 0)&0xff);
58 inline u32 readU32(u8 *data)
60 return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
63 inline u16 readU16(u8 *data)
65 return (data[0]<<8) | (data[1]<<0);
68 inline u8 readU8(u8 *data)
73 // Signed variants of the above
75 inline void writeS32(u8 *data, s32 i){
76 writeU32(data, (u32)i);
78 inline s32 readS32(u8 *data){
79 return (s32)readU32(data);
82 inline void writeS16(u8 *data, s16 i){
83 writeU16(data, (u16)i);
85 inline s16 readS16(u8 *data){
86 return (s16)readU16(data);
89 inline void writeV3S32(u8 *data, v3s32 p)
91 writeS32(&data[0], p.X);
92 writeS32(&data[4], p.Y);
93 writeS32(&data[8], p.Z);
96 inline v3s32 readV3S32(u8 *data)
99 p.X = readS32(&data[0]);
100 p.Y = readS32(&data[4]);
101 p.Z = readS32(&data[8]);
105 inline void writeV2S16(u8 *data, v2s16 p)
107 writeS16(&data[0], p.X);
108 writeS16(&data[2], p.Y);
111 inline v2s16 readV2S16(u8 *data)
114 p.X = readS16(&data[0]);
115 p.Y = readS16(&data[2]);
119 inline void writeV2S32(u8 *data, v2s32 p)
121 writeS32(&data[0], p.X);
122 writeS32(&data[2], p.Y);
125 inline v2s32 readV2S32(u8 *data)
128 p.X = readS32(&data[0]);
129 p.Y = readS32(&data[2]);
133 inline void writeV3S16(u8 *data, v3s16 p)
135 writeS16(&data[0], p.X);
136 writeS16(&data[2], p.Y);
137 writeS16(&data[4], p.Z);
140 inline v3s16 readV3S16(u8 *data)
143 p.X = readS16(&data[0]);
144 p.Y = readS16(&data[2]);
145 p.Z = readS16(&data[4]);
150 None of these are used at the moment
153 template <typename T>
163 SharedPtr(SharedPtr<T> &t)
167 refcount = t.refcount;
175 SharedPtr<T> & operator=(T *t)
183 SharedPtr<T> & operator=(SharedPtr<T> &t)
186 refcount = t.refcount;
199 bool operator!=(T *t)
203 bool operator==(T *t)
210 assert((*refcount) > 0);
223 template <typename T>
227 Buffer(unsigned int size)
232 Buffer(const Buffer &buffer)
234 m_size = buffer.m_size;
235 data = new T[buffer.m_size];
236 memcpy(data, buffer.data, buffer.m_size);
238 Buffer(T *t, unsigned int size)
242 memcpy(data, t, size);
248 T & operator[](unsigned int i) const
252 T * operator*() const
256 unsigned int getSize() const
265 template <typename T>
269 SharedBuffer(unsigned int size)
273 refcount = new unsigned int;
276 SharedBuffer(const SharedBuffer &buffer)
278 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
279 m_size = buffer.m_size;
281 refcount = buffer.refcount;
284 SharedBuffer & operator=(const SharedBuffer & buffer)
286 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
290 m_size = buffer.m_size;
292 refcount = buffer.refcount;
299 SharedBuffer(T *t, unsigned int size)
303 memcpy(data, t, size);
304 refcount = new unsigned int;
310 SharedBuffer(const Buffer<T> &buffer)
312 m_size = buffer.m_size;
313 data = new T[buffer.getSize()];
314 memcpy(data, *buffer, buffer.getSize());
315 refcount = new unsigned int;
322 T & operator[](unsigned int i) const
326 T * operator*() const
330 unsigned int getSize() const
337 assert((*refcount) > 0);
347 unsigned int *refcount;
350 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
352 SharedBuffer<u8> b((u8*)string, strlen(string)+1);
357 class MutexedVariable
360 MutexedVariable(T value):
368 JMutexAutoLock lock(m_mutex);
374 JMutexAutoLock lock(m_mutex);
378 // You'll want to grab this in a SharedPtr
379 JMutexAutoLock * getLock()
381 return new JMutexAutoLock(m_mutex);
384 // You pretty surely want to grab the lock when accessing this
395 class IrrlichtWrapper;
400 TimeTaker(const char *name, u32 *result=NULL);
407 u32 stop(bool quiet=false);
416 // Calculates the borders of a "d-radius" cube
417 inline void getFacePositions(core::list<v3s16> &list, u16 d)
421 list.push_back(v3s16(0,0,0));
427 This is an optimized sequence of coordinates.
429 list.push_back(v3s16( 0, 1, 0)); // top
430 list.push_back(v3s16( 0, 0, 1)); // back
431 list.push_back(v3s16(-1, 0, 0)); // left
432 list.push_back(v3s16( 1, 0, 0)); // right
433 list.push_back(v3s16( 0, 0,-1)); // front
434 list.push_back(v3s16( 0,-1, 0)); // bottom
436 list.push_back(v3s16(-1, 0, 1)); // back left
437 list.push_back(v3s16( 1, 0, 1)); // back right
438 list.push_back(v3s16(-1, 0,-1)); // front left
439 list.push_back(v3s16( 1, 0,-1)); // front right
440 list.push_back(v3s16(-1,-1, 0)); // bottom left
441 list.push_back(v3s16( 1,-1, 0)); // bottom right
442 list.push_back(v3s16( 0,-1, 1)); // bottom back
443 list.push_back(v3s16( 0,-1,-1)); // bottom front
444 list.push_back(v3s16(-1, 1, 0)); // top left
445 list.push_back(v3s16( 1, 1, 0)); // top right
446 list.push_back(v3s16( 0, 1, 1)); // top back
447 list.push_back(v3s16( 0, 1,-1)); // top front
449 list.push_back(v3s16(-1, 1, 1)); // top back-left
450 list.push_back(v3s16( 1, 1, 1)); // top back-right
451 list.push_back(v3s16(-1, 1,-1)); // top front-left
452 list.push_back(v3s16( 1, 1,-1)); // top front-right
453 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
454 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
455 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
456 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
461 // Take blocks in all sides, starting from y=0 and going +-y
462 for(s16 y=0; y<=d-1; y++)
464 // Left and right side, including borders
465 for(s16 z=-d; z<=d; z++)
467 list.push_back(v3s16(d,y,z));
468 list.push_back(v3s16(-d,y,z));
471 list.push_back(v3s16(d,-y,z));
472 list.push_back(v3s16(-d,-y,z));
475 // Back and front side, excluding borders
476 for(s16 x=-d+1; x<=d-1; x++)
478 list.push_back(v3s16(x,y,d));
479 list.push_back(v3s16(x,y,-d));
482 list.push_back(v3s16(x,-y,d));
483 list.push_back(v3s16(x,-y,-d));
488 // Take the bottom and top face with borders
489 // -d<x<d, y=+-d, -d<z<d
490 for(s16 x=-d; x<=d; x++)
491 for(s16 z=-d; z<=d; z++)
493 list.push_back(v3s16(x,-d,z));
494 list.push_back(v3s16(x,d,z));
498 class IndentationRaiser
501 IndentationRaiser(u16 *indentation)
503 m_indentation = indentation;
514 inline s16 getContainerPos(s16 p, s16 d)
516 return (p>=0 ? p : p-d+1) / d;
519 inline v2s16 getContainerPos(v2s16 p, s16 d)
522 getContainerPos(p.X, d),
523 getContainerPos(p.Y, d)
527 inline v3s16 getContainerPos(v3s16 p, s16 d)
530 getContainerPos(p.X, d),
531 getContainerPos(p.Y, d),
532 getContainerPos(p.Z, d)
536 inline bool isInArea(v3s16 p, s16 d)
539 p.X >= 0 && p.X < d &&
540 p.Y >= 0 && p.Y < d &&
545 inline bool isInArea(v2s16 p, s16 d)
548 p.X >= 0 && p.X < d &&
553 inline s16 rangelim(s16 i, s16 min, s16 max)
562 inline s16 rangelim(s16 i, s16 max)
571 inline v3s16 arealim(v3s16 p, s16 d)
588 inline std::wstring narrow_to_wide(const std::string& mbs)
590 size_t wcl = mbs.size();
591 SharedBuffer<wchar_t> wcs(wcl+1);
592 size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
597 inline std::string wide_to_narrow(const std::wstring& wcs)
599 size_t mbl = wcs.size()*4;
600 SharedBuffer<char> mbs(mbl+1);
601 size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
610 See test.cpp for example cases.
611 wraps degrees to the range of -360...360
612 NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
614 inline float wrapDegrees(float f)
616 // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
622 // NOTE: This would be used for wrapping to 0...360
628 // 10, 0.5, -0.5, -0.5
633 inline std::string lowercase(const std::string &s)
636 for(size_t i=0; i<s.size(); i++)
639 if(c >= 'A' && c <= 'Z')
646 inline bool is_yes(const std::string &s)
648 std::string s2 = lowercase(trim(s));
649 if(s2 == "y" || s2 == "yes" || s2 == "true" || s2 == "1")
654 inline s32 stoi(const std::string &s, s32 min, s32 max)
656 s32 i = atoi(s.c_str());
664 inline s32 stoi(std::string s)
666 return atoi(s.c_str());
669 inline std::string itos(s32 i)
671 std::ostringstream o;
676 inline std::string ftos(float f)
678 std::ostringstream o;
684 A base class for simple background thread implementation
687 class SimpleThread : public JThread
701 virtual ~SimpleThread()
704 virtual void * Thread() = 0;
708 JMutexAutoLock lock(run_mutex);
711 void setRun(bool a_run)
713 JMutexAutoLock lock(run_mutex);
732 VALUETYPE_FLAG // Doesn't take any arguments
737 ValueSpec(ValueType a_type, const char *a_help=NULL)
750 // Returns false on EOF
751 bool parseConfigObject(std::istream &is)
756 // NOTE: This function will be expanded to allow multi-line settings
758 std::getline(is, line);
759 //dstream<<"got line: \""<<line<<"\""<<std::endl;
761 std::string trimmedline = trim(line);
764 if(trimmedline[0] == '#')
767 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
769 Strfnd sf(trim(line));
771 std::string name = sf.next("=");
777 std::string value = sf.next("\n");
780 dstream<<"Config name=\""<<name<<"\" value=\""
781 <<value<<"\""<<std::endl;
783 m_settings[name] = value;
789 Read configuration file
791 Returns true on success
793 bool readConfigFile(const char *filename)
795 std::ifstream is(filename);
796 if(is.good() == false)
798 dstream<<"Error opening configuration file \""
799 <<filename<<"\""<<std::endl;
803 dstream<<"Parsing configuration file: \""
804 <<filename<<"\""<<std::endl;
806 while(parseConfigObject(is));
812 Reads a configuration object from stream (usually a single line)
815 Preserves comments and empty lines.
817 Settings that were added to dst are also added to updated.
818 key of updated is setting name, value of updated is dummy.
822 bool getUpdatedConfigObject(std::istream &is,
823 core::list<std::string> &dst,
824 core::map<std::string, bool> &updated)
829 // NOTE: This function will be expanded to allow multi-line settings
831 std::getline(is, line);
833 std::string trimmedline = trim(line);
835 std::string line_end = "";
836 if(is.eof() == false)
840 if(trimmedline[0] == '#')
842 dst.push_back(line+line_end);
846 Strfnd sf(trim(line));
848 std::string name = sf.next("=");
853 dst.push_back(line+line_end);
857 std::string value = sf.next("\n");
860 if(m_settings.find(name))
862 std::string newvalue = m_settings[name];
864 if(newvalue != value)
866 dstream<<"Changing value of \""<<name<<"\" = \""
867 <<value<<"\" -> \""<<newvalue<<"\""
871 dst.push_back(name + " = " + newvalue + line_end);
873 updated[name] = true;
880 Updates configuration file
882 Returns true on success
884 bool updateConfigFile(const char *filename)
886 dstream<<"Updating configuration file: \""
887 <<filename<<"\""<<std::endl;
889 core::list<std::string> objects;
890 core::map<std::string, bool> updated;
892 // Read and modify stuff
894 std::ifstream is(filename);
895 if(is.good() == false)
897 dstream<<"Error opening configuration file"
899 <<filename<<"\""<<std::endl;
903 while(getUpdatedConfigObject(is, objects, updated));
908 std::ofstream os(filename);
909 if(os.good() == false)
911 dstream<<"Error opening configuration file"
913 <<filename<<"\""<<std::endl;
920 for(core::list<std::string>::Iterator
922 i != objects.end(); i++)
928 Write stuff that was not already in the file
930 for(core::map<std::string, std::string>::Iterator
931 i = m_settings.getIterator();
932 i.atEnd() == false; i++)
934 if(updated.find(i.getNode()->getKey()))
936 std::string name = i.getNode()->getKey();
937 std::string value = i.getNode()->getValue();
938 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
940 os<<name<<" = "<<value<<"\n";
948 NOTE: Types of allowed_options are ignored
950 returns true on success
952 bool parseCommandLine(int argc, char *argv[],
953 core::map<std::string, ValueSpec> &allowed_options)
960 std::string argname = argv[i];
961 if(argname.substr(0, 2) != "--")
963 dstream<<"Invalid command-line parameter \""
964 <<argname<<"\": --<option> expected."<<std::endl;
969 std::string name = argname.substr(2);
971 core::map<std::string, ValueSpec>::Node *n;
972 n = allowed_options.find(name);
975 dstream<<"Unknown command-line parameter \""
976 <<argname<<"\""<<std::endl;
980 ValueType type = n->getValue().type;
982 std::string value = "";
984 if(type == VALUETYPE_FLAG)
992 dstream<<"Invalid command-line parameter \""
993 <<name<<"\": missing value"<<std::endl;
1001 dstream<<"Valid command-line parameter: \""
1002 <<name<<"\" = \""<<value<<"\""
1010 void set(std::string name, std::string value)
1012 m_settings[name] = value;
1015 void setDefault(std::string name, std::string value)
1017 m_defaults[name] = value;
1020 bool exists(std::string name)
1022 return (m_settings.find(name) || m_defaults.find(name));
1025 std::string get(std::string name)
1027 core::map<std::string, std::string>::Node *n;
1028 n = m_settings.find(name);
1031 n = m_defaults.find(name);
1034 throw SettingNotFoundException("Setting not found");
1038 return n->getValue();
1041 bool getBool(std::string name)
1043 return is_yes(get(name));
1046 bool getFlag(std::string name)
1050 return getBool(name);
1052 catch(SettingNotFoundException &e)
1059 bool getBoolAsk(std::string name, std::string question, bool def)
1061 // If it is in settings
1062 if(m_settings.find(name))
1063 return getBool(name);
1067 std::cout<<question<<" [y/N]: ";
1068 std::cin.getline(templine, 10);
1077 float getFloat(std::string name)
1080 std::istringstream vis(get(name));
1085 u16 getU16(std::string name)
1087 return stoi(get(name), 0, 65535);
1090 u16 getU16Ask(std::string name, std::string question, u16 def)
1092 // If it is in settings
1093 if(m_settings.find(name))
1094 return getU16(name);
1098 std::cout<<question<<" ["<<def<<"]: ";
1099 std::cin.getline(templine, 10);
1105 return stoi(s, 0, 65535);
1108 s16 getS16(std::string name)
1110 return stoi(get(name), -32768, 32767);
1113 s32 getS32(std::string name)
1115 return stoi(get(name));
1124 Settings & operator+=(Settings &other)
1129 for(core::map<std::string, std::string>::Iterator
1130 i = other.m_settings.getIterator();
1131 i.atEnd() == false; i++)
1133 m_settings.insert(i.getNode()->getKey(),
1134 i.getNode()->getValue());
1137 for(core::map<std::string, std::string>::Iterator
1138 i = other.m_defaults.getIterator();
1139 i.atEnd() == false; i++)
1141 m_defaults.insert(i.getNode()->getKey(),
1142 i.getNode()->getValue());
1147 Settings & operator=(Settings &other)
1159 core::map<std::string, std::string> m_settings;
1160 core::map<std::string, std::string> m_defaults;
1166 template<typename T>
1172 m_list.push_back(t);
1177 if(m_list.size() == 0)
1178 throw ItemNotFoundException("MutexedQueue: queue is empty");
1180 typename core::list<T>::Iterator begin = m_list.begin();
1182 m_list.erase(begin);
1188 return m_list.size();
1192 core::list<T> m_list;
1196 Thread-safe FIFO queue
1199 template<typename T>
1209 return m_list.size();
1213 JMutexAutoLock lock(m_mutex);
1214 m_list.push_back(t);
1216 T pop_front(u32 wait_time_max_ms=0)
1218 u32 wait_time_ms = 0;
1223 JMutexAutoLock lock(m_mutex);
1225 if(m_list.size() > 0)
1227 typename core::list<T>::Iterator begin = m_list.begin();
1229 m_list.erase(begin);
1233 if(wait_time_ms >= wait_time_max_ms)
1234 throw ItemNotFoundException("MutexedQueue: queue is empty");
1237 // Wait a while before trying again
1248 core::list<T> & getList()
1255 core::list<T> m_list;
1258 template<typename Caller, typename Data>
1266 template<typename Key, typename T, typename Caller, typename CallerData>
1272 core::list<CallerInfo<Caller, CallerData> > callers;
1275 template<typename Key, typename T, typename Caller, typename CallerData>
1276 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1280 template<typename Key, typename T, typename Caller, typename CallerData>
1288 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1292 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1303 ResultQueue<Key, T, Caller, CallerData> *dest;
1304 core::list<CallerInfo<Caller, CallerData> > callers;
1308 Quickhands for typical request-result queues.
1309 Used for distributing work between threads.
1312 template<typename Key, typename T, typename Caller, typename CallerData>
1318 return m_queue.size();
1321 void add(Key key, Caller caller, CallerData callerdata,
1322 ResultQueue<Key, T, Caller, CallerData> *dest)
1324 JMutexAutoLock lock(m_queue.getMutex());
1327 If the caller is already on the list, only update CallerData
1329 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1330 i = m_queue.getList().begin();
1331 i != m_queue.getList().end(); i++)
1333 GetRequest<Key, T, Caller, CallerData> &request = *i;
1335 if(request.key == key)
1337 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1338 i = request.callers.begin();
1339 i != request.callers.end(); i++)
1341 CallerInfo<Caller, CallerData> &ca = *i;
1342 if(ca.caller == caller)
1344 ca.data = callerdata;
1348 CallerInfo<Caller, CallerData> ca;
1350 ca.data = callerdata;
1351 request.callers.push_back(ca);
1357 Else add a new request to the queue
1360 GetRequest<Key, T, Caller, CallerData> request;
1362 CallerInfo<Caller, CallerData> ca;
1364 ca.data = callerdata;
1365 request.callers.push_back(ca);
1366 request.dest = dest;
1368 m_queue.getList().push_back(request);
1371 GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1373 return m_queue.pop_front(wait_if_empty);
1377 MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
1381 Pseudo-random (VC++ rand() sucks)
1384 void mysrand(unsigned seed);
1385 #define MYRAND_MAX 32767
1388 Some kind of a thing that stores attributes related to
1398 Attribute(const std::string &value):
1403 Attribute(float value)
1405 m_value = ftos(value);
1408 void set(const std::string &value)
1420 return is_yes(get());
1426 std::istringstream vis(get());
1433 return stoi(get(), 0, 65535);
1438 return stoi(get(), -32768, 32767);
1446 std::string m_value;
1449 class PointAttributeList
1451 struct PointWithAttr
1458 ~PointAttributeList()
1460 /*for(core::list<PointWithAttr>::Iterator
1461 i = m_points.begin();
1462 i != m_points.end(); i++)
1464 PointWithAttr &pwa = *i;
1469 Attribute getNearAttr(v3s16 p)
1471 core::list<PointWithAttr>::Iterator
1472 nearest_i = m_points.end();
1473 s16 nearest_d = 32767;
1474 for(core::list<PointWithAttr>::Iterator
1475 i = m_points.begin();
1476 i != m_points.end(); i++)
1478 PointWithAttr &pwa = *i;
1479 s16 d = pwa.p.getDistanceFrom(p);
1487 if(nearest_i == m_points.end())
1490 return nearest_i->attr;
1493 Attribute getNearAttr(v2s16 p)
1495 return getNearAttr(v3s16(p.X, 0, p.Y));
1500 return (m_points.size() == 0);
1504 Take all points in range, or at least the nearest point,
1505 and interpolate the values as floats
1507 float getInterpolatedFloat(v3s16 p);
1509 float getInterpolatedFloat(v2s16 p)
1511 return getInterpolatedFloat(v3s16(p.X, 0, p.Y));
1514 //float getInterpolatedFloat(v3s16 p, s32 range);
1515 /*float getInterpolatedFloat(v2s16 p, s32 range)
1517 return getInterpolatedFloat(v3s16(p.X, 0, p.Y), range);
1520 void addPoint(v3s16 p, const Attribute &attr)
1522 PointWithAttr pattr;
1525 m_points.push_back(pattr);
1528 void addPoint(v2s16 p, const Attribute &attr)
1530 addPoint(v3s16(p.X, 0, p.Y), attr);
1534 core::list<PointWithAttr> m_points;
1538 Basically just a wrapper to core::map<PointAttributeList*>
1541 class PointAttributeDatabase
1544 ~PointAttributeDatabase()
1546 for(core::map<std::string, PointAttributeList*>::Iterator
1547 i = m_lists.getIterator();
1548 i.atEnd() == false; i++)
1550 delete i.getNode()->getValue();
1554 PointAttributeList *getList(const std::string &name)
1556 PointAttributeList *list = NULL;
1558 core::map<std::string, PointAttributeList*>::Node *n;
1559 n = m_lists.find(name);
1563 list = new PointAttributeList();
1564 m_lists.insert(name, list);
1568 list = n->getValue();
1574 core::map<std::string, PointAttributeList*> m_lists;
1578 Miscellaneous functions
1581 bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range);
1584 Queue with unique values with fast checking of value existence
1587 template<typename Value>
1593 Does nothing if value is already queued.
1596 false: value already exists
1598 bool push_back(Value value)
1600 // Check if already exists
1601 if(m_map.find(value) != NULL)
1605 m_map.insert(value, 0);
1606 m_list.push_back(value);
1613 typename core::list<Value>::Iterator i = m_list.begin();
1615 m_map.remove(value);
1622 assert(m_list.size() == m_map.size());
1623 return m_list.size();
1627 core::map<Value, u8> m_map;
1628 core::list<Value> m_list;