]> git.lizzy.rs Git - dragonfireclient.git/blob - src/utility.h
93fd9d4a7fe443ca38f04b57216356b6ddf95369
[dragonfireclient.git] / src / utility.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
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.
9
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.
14
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.
18 */
19
20 /*
21 (c) 2010 Perttu Ahola <celeron55@gmail.com>
22 */
23
24 #ifndef UTILITY_HEADER
25 #define UTILITY_HEADER
26
27 #include "common_irrlicht.h"
28 #include "debug.h"
29 #include "strfnd.h"
30 #include "exceptions.h"
31 #include <iostream>
32 #include <fstream>
33 #include <string>
34 #include <sstream>
35
36 extern const v3s16 g_26dirs[26];
37
38 inline void writeU32(u8 *data, u32 i)
39 {
40         data[0] = ((i>>24)&0xff);
41         data[1] = ((i>>16)&0xff);
42         data[2] = ((i>> 8)&0xff);
43         data[3] = ((i>> 0)&0xff);
44 }
45
46 inline void writeU16(u8 *data, u16 i)
47 {
48         data[0] = ((i>> 8)&0xff);
49         data[1] = ((i>> 0)&0xff);
50 }
51
52 inline void writeU8(u8 *data, u8 i)
53 {
54         data[0] = ((i>> 0)&0xff);
55 }
56
57 inline u32 readU32(u8 *data)
58 {
59         return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
60 }
61
62 inline u16 readU16(u8 *data)
63 {
64         return (data[0]<<8) | (data[1]<<0);
65 }
66
67 inline u8 readU8(u8 *data)
68 {
69         return (data[0]<<0);
70 }
71
72 // Signed variants of the above
73
74 inline void writeS32(u8 *data, s32 i){
75         writeU32(data, (u32)i);
76 }
77 inline s32 readS32(u8 *data){
78         return (s32)readU32(data);
79 }
80
81 inline void writeS16(u8 *data, s16 i){
82         writeU16(data, (u16)i);
83 }
84 inline s16 readS16(u8 *data){
85         return (s16)readU16(data);
86 }
87
88 inline void writeV3S32(u8 *data, v3s32 p)
89 {
90         writeS32(&data[0], p.X);
91         writeS32(&data[4], p.Y);
92         writeS32(&data[8], p.Z);
93 }
94
95 inline v3s32 readV3S32(u8 *data)
96 {
97         v3s32 p;
98         p.X = readS32(&data[0]);
99         p.Y = readS32(&data[4]);
100         p.Z = readS32(&data[8]);
101         return p;
102 }
103
104 inline void writeV2S16(u8 *data, v2s16 p)
105 {
106         writeS16(&data[0], p.X);
107         writeS16(&data[2], p.Y);
108 }
109
110 inline v2s16 readV2S16(u8 *data)
111 {
112         v2s16 p;
113         p.X = readS16(&data[0]);
114         p.Y = readS16(&data[2]);
115         return p;
116 }
117
118 inline void writeV2S32(u8 *data, v2s32 p)
119 {
120         writeS32(&data[0], p.X);
121         writeS32(&data[2], p.Y);
122 }
123
124 inline v2s32 readV2S32(u8 *data)
125 {
126         v2s32 p;
127         p.X = readS32(&data[0]);
128         p.Y = readS32(&data[2]);
129         return p;
130 }
131
132 inline void writeV3S16(u8 *data, v3s16 p)
133 {
134         writeS16(&data[0], p.X);
135         writeS16(&data[2], p.Y);
136         writeS16(&data[4], p.Z);
137 }
138
139 inline v3s16 readV3S16(u8 *data)
140 {
141         v3s16 p;
142         p.X = readS16(&data[0]);
143         p.Y = readS16(&data[2]);
144         p.Z = readS16(&data[4]);
145         return p;
146 }
147
148 /*
149         None of these are used at the moment
150 */
151
152 template <typename T>
153 class SharedPtr
154 {
155 public:
156         SharedPtr(T *t=NULL)
157         {
158                 refcount = new int;
159                 *refcount = 1;
160                 ptr = t;
161         }
162         SharedPtr(SharedPtr<T> &t)
163         {
164                 //*this = t;
165                 drop();
166                 refcount = t.refcount;
167                 (*refcount)++;
168                 ptr = t.ptr;
169         }
170         ~SharedPtr()
171         {
172                 drop();
173         }
174         SharedPtr<T> & operator=(T *t)
175         {
176                 drop();
177                 refcount = new int;
178                 *refcount = 1;
179                 ptr = t;
180                 return *this;
181         }
182         SharedPtr<T> & operator=(SharedPtr<T> &t)
183         {
184                 drop();
185                 refcount = t.refcount;
186                 (*refcount)++;
187                 ptr = t.ptr;
188                 return *this;
189         }
190         T* operator->()
191         {
192                 return ptr;
193         }
194         T & operator*()
195         {
196                 return *ptr;
197         }
198         bool operator!=(T *t)
199         {
200                 return ptr != t;
201         }
202         bool operator==(T *t)
203         {
204                 return ptr == t;
205         }
206 private:
207         void drop()
208         {
209                 assert((*refcount) > 0);
210                 (*refcount)--;
211                 if(*refcount == 0)
212                 {
213                         delete refcount;
214                         if(ptr != NULL)
215                                 delete ptr;
216                 }
217         }
218         T *ptr;
219         int *refcount;
220 };
221
222 template <typename T>
223 class Buffer
224 {
225 public:
226         Buffer(unsigned int size)
227         {
228                 m_size = size;
229                 data = new T[size];
230         }
231         Buffer(const Buffer &buffer)
232         {
233                 m_size = buffer.m_size;
234                 data = new T[buffer.m_size];
235                 memcpy(data, buffer.data, buffer.m_size);
236         }
237         Buffer(T *t, unsigned int size)
238         {
239                 m_size = size;
240                 data = new T[size];
241                 memcpy(data, t, size);
242         }
243         ~Buffer()
244         {
245                 delete[] data;
246         }
247         T & operator[](unsigned int i) const
248         {
249                 return data[i];
250         }
251         T * operator*() const
252         {
253                 return data;
254         }
255         unsigned int getSize() const
256         {
257                 return m_size;
258         }
259 private:
260         T *data;
261         unsigned int m_size;
262 };
263
264 template <typename T>
265 class SharedBuffer
266 {
267 public:
268         SharedBuffer(unsigned int size)
269         {
270                 m_size = size;
271                 data = new T[size];
272                 refcount = new unsigned int;
273                 (*refcount) = 1;
274         }
275         SharedBuffer(const SharedBuffer &buffer)
276         {
277                 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
278                 m_size = buffer.m_size;
279                 data = buffer.data;
280                 refcount = buffer.refcount;
281                 (*refcount)++;
282         }
283         SharedBuffer & operator=(const SharedBuffer & buffer)
284         {
285                 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
286                 if(this == &buffer)
287                         return *this;
288                 drop();
289                 m_size = buffer.m_size;
290                 data = buffer.data;
291                 refcount = buffer.refcount;
292                 (*refcount)++;
293                 return *this;
294         }
295         /*
296                 Copies whole buffer
297         */
298         SharedBuffer(T *t, unsigned int size)
299         {
300                 m_size = size;
301                 data = new T[size];
302                 memcpy(data, t, size);
303                 refcount = new unsigned int;
304                 (*refcount) = 1;
305         }
306         /*
307                 Copies whole buffer
308         */
309         SharedBuffer(const Buffer<T> &buffer)
310         {
311                 m_size = buffer.m_size;
312                 data = new T[buffer.getSize()];
313                 memcpy(data, *buffer, buffer.getSize());
314                 refcount = new unsigned int;
315                 (*refcount) = 1;
316         }
317         ~SharedBuffer()
318         {
319                 drop();
320         }
321         T & operator[](unsigned int i) const
322         {
323                 return data[i];
324         }
325         T * operator*() const
326         {
327                 return data;
328         }
329         unsigned int getSize() const
330         {
331                 return m_size;
332         }
333 private:
334         void drop()
335         {
336                 assert((*refcount) > 0);
337                 (*refcount)--;
338                 if(*refcount == 0)
339                 {
340                         delete[] data;
341                         delete refcount;
342                 }
343         }
344         T *data;
345         unsigned int m_size;
346         unsigned int *refcount;
347 };
348
349 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
350 {
351         SharedBuffer<u8> b((u8*)string, strlen(string)+1);
352         return b;
353 }
354
355 template<typename T>
356 class MutexedVariable
357 {
358 public:
359         MutexedVariable(T value):
360                 m_value(value)
361         {
362                 m_mutex.Init();
363         }
364
365         T get()
366         {
367                 JMutexAutoLock lock(m_mutex);
368                 return m_value;
369         }
370
371         void set(T value)
372         {
373                 JMutexAutoLock lock(m_mutex);
374                 m_value = value;
375         }
376         
377         // You'll want to grab this in a SharedPtr
378         JMutexAutoLock * getLock()
379         {
380                 return new JMutexAutoLock(m_mutex);
381         }
382         
383         // You pretty surely want to grab the lock when accessing this
384         T m_value;
385
386 private:
387         JMutex m_mutex;
388 };
389
390 /*
391         TimeTaker
392 */
393
394 class TimeTaker
395 {
396 public:
397         TimeTaker(const char *name, IrrlichtDevice *dev)
398         {
399                 m_name = name;
400                 m_dev = dev;
401                 m_time1 = m_dev->getTimer()->getRealTime();
402                 m_running = true;
403         }
404         ~TimeTaker()
405         {
406                 stop();
407         }
408         u32 stop(bool quiet=false)
409         {
410                 if(m_running)
411                 {
412                         u32 time2 = m_dev->getTimer()->getRealTime();
413                         u32 dtime = time2 - m_time1;
414                         if(quiet == false)
415                                 std::cout<<m_name<<" took "<<dtime<<"ms"<<std::endl;
416                         m_running = false;
417                         return dtime;
418                 }
419                 return 0;
420         }
421 private:
422         const char *m_name;
423         IrrlichtDevice *m_dev;
424         u32 m_time1;
425         bool m_running;
426 };
427
428 // Calculates the borders of a "d-radius" cube
429 inline void getFacePositions(core::list<v3s16> &list, u16 d)
430 {
431         if(d == 0)
432         {
433                 list.push_back(v3s16(0,0,0));
434                 return;
435         }
436         if(d == 1)
437         {
438                 /*
439                         This is an optimized sequence of coordinates.
440                 */
441                 list.push_back(v3s16( 0, 0, 1)); // back
442                 list.push_back(v3s16(-1, 0, 0)); // left
443                 list.push_back(v3s16( 1, 0, 0)); // right
444                 list.push_back(v3s16( 0, 0,-1)); // front
445                 list.push_back(v3s16( 0,-1, 0)); // bottom
446                 list.push_back(v3s16( 0, 1, 0)); // top
447                 // 6
448                 list.push_back(v3s16(-1, 0, 1)); // back left
449                 list.push_back(v3s16( 1, 0, 1)); // back right
450                 list.push_back(v3s16(-1, 0,-1)); // front left
451                 list.push_back(v3s16( 1, 0,-1)); // front right
452                 list.push_back(v3s16(-1,-1, 0)); // bottom left
453                 list.push_back(v3s16( 1,-1, 0)); // bottom right
454                 list.push_back(v3s16( 0,-1, 1)); // bottom back
455                 list.push_back(v3s16( 0,-1,-1)); // bottom front
456                 list.push_back(v3s16(-1, 1, 0)); // top left
457                 list.push_back(v3s16( 1, 1, 0)); // top right
458                 list.push_back(v3s16( 0, 1, 1)); // top back
459                 list.push_back(v3s16( 0, 1,-1)); // top front
460                 // 18
461                 list.push_back(v3s16(-1, 1, 1)); // top back-left
462                 list.push_back(v3s16( 1, 1, 1)); // top back-right
463                 list.push_back(v3s16(-1, 1,-1)); // top front-left
464                 list.push_back(v3s16( 1, 1,-1)); // top front-right
465                 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
466                 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
467                 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
468                 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
469                 // 26
470                 return;
471         }
472
473         // Take blocks in all sides, starting from y=0 and going +-y
474         for(s16 y=0; y<=d-1; y++)
475         {
476                 // Left and right side, including borders
477                 for(s16 z=-d; z<=d; z++)
478                 {
479                         list.push_back(v3s16(d,y,z));
480                         list.push_back(v3s16(-d,y,z));
481                         if(y != 0)
482                         {
483                                 list.push_back(v3s16(d,-y,z));
484                                 list.push_back(v3s16(-d,-y,z));
485                         }
486                 }
487                 // Back and front side, excluding borders
488                 for(s16 x=-d+1; x<=d-1; x++)
489                 {
490                         list.push_back(v3s16(x,y,d));
491                         list.push_back(v3s16(x,y,-d));
492                         if(y != 0)
493                         {
494                                 list.push_back(v3s16(x,-y,d));
495                                 list.push_back(v3s16(x,-y,-d));
496                         }
497                 }
498         }
499
500         // Take the bottom and top face with borders
501         // -d<x<d, y=+-d, -d<z<d
502         for(s16 x=-d; x<=d; x++)
503         for(s16 z=-d; z<=d; z++)
504         {
505                 list.push_back(v3s16(x,-d,z));
506                 list.push_back(v3s16(x,d,z));
507         }
508 }
509
510 class IndentationRaiser
511 {
512 public:
513         IndentationRaiser(u16 *indentation)
514         {
515                 m_indentation = indentation;
516                 (*m_indentation)++;
517         }
518         ~IndentationRaiser()
519         {
520                 (*m_indentation)--;
521         }
522 private:
523         u16 *m_indentation;
524 };
525
526 inline s16 getContainerPos(s16 p, s16 d)
527 {
528         return (p>=0 ? p : p-d+1) / d;
529 }
530
531 inline v2s16 getContainerPos(v2s16 p, s16 d)
532 {
533         return v2s16(
534                 getContainerPos(p.X, d),
535                 getContainerPos(p.Y, d)
536         );
537 }
538
539 inline v3s16 getContainerPos(v3s16 p, s16 d)
540 {
541         return v3s16(
542                 getContainerPos(p.X, d),
543                 getContainerPos(p.Y, d),
544                 getContainerPos(p.Z, d)
545         );
546 }
547
548 inline bool isInArea(v3s16 p, s16 d)
549 {
550         return (
551                 p.X >= 0 && p.X < d &&
552                 p.Y >= 0 && p.Y < d &&
553                 p.Z >= 0 && p.Z < d
554         );
555 }
556
557 inline bool isInArea(v2s16 p, s16 d)
558 {
559         return (
560                 p.X >= 0 && p.X < d &&
561                 p.Y >= 0 && p.Y < d
562         );
563 }
564
565 inline std::wstring narrow_to_wide(const std::string& mbs)
566 {
567         size_t wcl = mbs.size();
568         SharedBuffer<wchar_t> wcs(wcl+1);
569         size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
570         wcs[l] = 0;
571         return *wcs;
572 }
573
574 inline std::string wide_to_narrow(const std::wstring& wcs)
575 {
576         size_t mbl = wcs.size()*4;
577         SharedBuffer<char> mbs(mbl+1);
578         size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
579         if((int)l == -1)
580                 mbs[0] = 0;
581         else
582                 mbs[l] = 0;
583         return *mbs;
584 }
585
586 /*
587         See test.cpp for example cases.
588         wraps degrees to the range of -360...360
589         NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
590 */
591 inline float wrapDegrees(float f)
592 {
593         // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
594         // This results in
595         // 10, 720, -1, -361
596         int i = floor(f);
597         // 0, 2, 0, -1
598         int l = i / 360;
599         // NOTE: This would be used for wrapping to 0...360
600         // 0, 2, -1, -2
601         /*if(i < 0)
602                 l -= 1;*/
603         // 0, 720, 0, -360
604         int k = l * 360;
605         // 10, 0.5, -0.5, -0.5
606         f -= float(k);
607         return f;
608 }
609
610 inline std::string lowercase(std::string s)
611 {
612         for(size_t i=0; i<s.size(); i++)
613         {
614                 if(s[i] >= 'A' && s[i] <= 'Z')
615                         s[i] -= 'A' - 'a';
616         }
617         return s;
618 }
619
620 inline bool is_yes(std::string s)
621 {
622         s = lowercase(trim(s));
623         if(s == "y" || s == "yes" || s == "true")
624                 return true;
625         return false;
626 }
627
628 inline s32 stoi(std::string s, s32 min, s32 max)
629 {
630         s32 i = atoi(s.c_str());
631         if(i < min)
632                 i = min;
633         if(i > max)
634                 i = max;
635         return i;
636 }
637
638 inline s32 stoi(std::string s)
639 {
640         return atoi(s.c_str());
641 }
642
643 /*
644         Config stuff
645 */
646
647 class Settings
648 {
649 public:
650
651         // Returns false on EOF
652         bool parseConfigObject(std::istream &is)
653         {
654                 if(is.eof())
655                         return false;
656                 
657                 // NOTE: This function will be expanded to allow multi-line settings
658                 std::string line;
659                 std::getline(is, line);
660                 //dstream<<"got line: \""<<line<<"\""<<std::endl;
661
662                 std::string trimmedline = trim(line);
663                 
664                 // Ignore comments
665                 if(trimmedline[0] == '#')
666                         return true;
667
668                 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
669
670                 Strfnd sf(trim(line));
671
672                 std::string name = sf.next("=");
673                 name = trim(name);
674
675                 if(name == "")
676                         return true;
677                 
678                 std::string value = sf.next("\n");
679                 value = trim(value);
680
681                 dstream<<"Config name=\""<<name<<"\" value=\""
682                                 <<value<<"\""<<std::endl;
683                 
684                 m_settings[name] = value;
685                 
686                 return true;
687         }
688
689         // Returns true on success
690         bool readConfigFile(const char *filename)
691         {
692                 std::ifstream is(filename);
693                 if(is.good() == false)
694                 {
695                         dstream<<"Error opening configuration file: "
696                                         <<filename<<std::endl;
697                         return false;
698                 }
699
700                 dstream<<"Parsing configuration file: "
701                                 <<filename<<std::endl;
702                                 
703                 while(parseConfigObject(is));
704                 
705                 return true;
706         }
707
708         void set(std::string name, std::string value)
709         {
710                 m_settings[name] = value;
711         }
712
713         std::string get(std::string name)
714         {
715                 core::map<std::string, std::string>::Node *n;
716                 n = m_settings.find(name);
717                 if(n == NULL)
718                         throw SettingNotFoundException("Setting not found");
719
720                 return n->getValue();
721         }
722
723         bool getBool(std::string name)
724         {
725                 return is_yes(get(name));
726         }
727         
728         // Asks if empty
729         bool getBoolAsk(std::string name, std::string question, bool def)
730         {
731                 std::string s = get(name);
732                 if(s != "")
733                         return is_yes(s);
734                 
735                 char templine[10];
736                 std::cout<<question<<" [y/N]: ";
737                 std::cin.getline(templine, 10);
738                 s = templine;
739
740                 if(s == "")
741                         return def;
742
743                 return is_yes(s);
744         }
745
746         float getFloat(std::string name)
747         {
748                 float f;
749                 std::istringstream vis(get(name));
750                 vis>>f;
751                 return f;
752         }
753
754         u16 getU16(std::string name)
755         {
756                 return stoi(get(name), 0, 65535);
757         }
758
759         u16 getU16Ask(std::string name, std::string question, u16 def)
760         {
761                 std::string s = get(name);
762                 if(s != "")
763                         return stoi(s, 0, 65535);
764                 
765                 char templine[10];
766                 std::cout<<question<<" ["<<def<<"]: ";
767                 std::cin.getline(templine, 10);
768                 s = templine;
769
770                 if(s == "")
771                         return def;
772
773                 return stoi(s, 0, 65535);
774         }
775
776         s16 getS16(std::string name)
777         {
778                 return stoi(get(name), -32768, 32767);
779         }
780
781         s32 getS32(std::string name)
782         {
783                 return stoi(get(name));
784         }
785
786 private:
787         core::map<std::string, std::string> m_settings;
788 };
789
790 #endif
791