]> git.lizzy.rs Git - dragonfireclient.git/blob - src/utility.h
f7e726f87b389418420e5b7714197a40543b9cd5
[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 <iostream>
28 #include <fstream>
29 #include <string>
30 #include <sstream>
31 #include <jmutex.h>
32 #include <jmutexautolock.h>
33
34 #include "common_irrlicht.h"
35 #include "debug.h"
36 #include "strfnd.h"
37 #include "exceptions.h"
38
39 extern const v3s16 g_26dirs[26];
40
41 inline void writeU32(u8 *data, u32 i)
42 {
43         data[0] = ((i>>24)&0xff);
44         data[1] = ((i>>16)&0xff);
45         data[2] = ((i>> 8)&0xff);
46         data[3] = ((i>> 0)&0xff);
47 }
48
49 inline void writeU16(u8 *data, u16 i)
50 {
51         data[0] = ((i>> 8)&0xff);
52         data[1] = ((i>> 0)&0xff);
53 }
54
55 inline void writeU8(u8 *data, u8 i)
56 {
57         data[0] = ((i>> 0)&0xff);
58 }
59
60 inline u32 readU32(u8 *data)
61 {
62         return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
63 }
64
65 inline u16 readU16(u8 *data)
66 {
67         return (data[0]<<8) | (data[1]<<0);
68 }
69
70 inline u8 readU8(u8 *data)
71 {
72         return (data[0]<<0);
73 }
74
75 // Signed variants of the above
76
77 inline void writeS32(u8 *data, s32 i){
78         writeU32(data, (u32)i);
79 }
80 inline s32 readS32(u8 *data){
81         return (s32)readU32(data);
82 }
83
84 inline void writeS16(u8 *data, s16 i){
85         writeU16(data, (u16)i);
86 }
87 inline s16 readS16(u8 *data){
88         return (s16)readU16(data);
89 }
90
91 inline void writeV3S32(u8 *data, v3s32 p)
92 {
93         writeS32(&data[0], p.X);
94         writeS32(&data[4], p.Y);
95         writeS32(&data[8], p.Z);
96 }
97
98 inline v3s32 readV3S32(u8 *data)
99 {
100         v3s32 p;
101         p.X = readS32(&data[0]);
102         p.Y = readS32(&data[4]);
103         p.Z = readS32(&data[8]);
104         return p;
105 }
106
107 inline void writeV2S16(u8 *data, v2s16 p)
108 {
109         writeS16(&data[0], p.X);
110         writeS16(&data[2], p.Y);
111 }
112
113 inline v2s16 readV2S16(u8 *data)
114 {
115         v2s16 p;
116         p.X = readS16(&data[0]);
117         p.Y = readS16(&data[2]);
118         return p;
119 }
120
121 inline void writeV2S32(u8 *data, v2s32 p)
122 {
123         writeS32(&data[0], p.X);
124         writeS32(&data[2], p.Y);
125 }
126
127 inline v2s32 readV2S32(u8 *data)
128 {
129         v2s32 p;
130         p.X = readS32(&data[0]);
131         p.Y = readS32(&data[2]);
132         return p;
133 }
134
135 inline void writeV3S16(u8 *data, v3s16 p)
136 {
137         writeS16(&data[0], p.X);
138         writeS16(&data[2], p.Y);
139         writeS16(&data[4], p.Z);
140 }
141
142 inline v3s16 readV3S16(u8 *data)
143 {
144         v3s16 p;
145         p.X = readS16(&data[0]);
146         p.Y = readS16(&data[2]);
147         p.Z = readS16(&data[4]);
148         return p;
149 }
150
151 /*
152         None of these are used at the moment
153 */
154
155 template <typename T>
156 class SharedPtr
157 {
158 public:
159         SharedPtr(T *t=NULL)
160         {
161                 refcount = new int;
162                 *refcount = 1;
163                 ptr = t;
164         }
165         SharedPtr(SharedPtr<T> &t)
166         {
167                 //*this = t;
168                 drop();
169                 refcount = t.refcount;
170                 (*refcount)++;
171                 ptr = t.ptr;
172         }
173         ~SharedPtr()
174         {
175                 drop();
176         }
177         SharedPtr<T> & operator=(T *t)
178         {
179                 drop();
180                 refcount = new int;
181                 *refcount = 1;
182                 ptr = t;
183                 return *this;
184         }
185         SharedPtr<T> & operator=(SharedPtr<T> &t)
186         {
187                 drop();
188                 refcount = t.refcount;
189                 (*refcount)++;
190                 ptr = t.ptr;
191                 return *this;
192         }
193         T* operator->()
194         {
195                 return ptr;
196         }
197         T & operator*()
198         {
199                 return *ptr;
200         }
201         bool operator!=(T *t)
202         {
203                 return ptr != t;
204         }
205         bool operator==(T *t)
206         {
207                 return ptr == t;
208         }
209 private:
210         void drop()
211         {
212                 assert((*refcount) > 0);
213                 (*refcount)--;
214                 if(*refcount == 0)
215                 {
216                         delete refcount;
217                         if(ptr != NULL)
218                                 delete ptr;
219                 }
220         }
221         T *ptr;
222         int *refcount;
223 };
224
225 template <typename T>
226 class Buffer
227 {
228 public:
229         Buffer(unsigned int size)
230         {
231                 m_size = size;
232                 data = new T[size];
233         }
234         Buffer(const Buffer &buffer)
235         {
236                 m_size = buffer.m_size;
237                 data = new T[buffer.m_size];
238                 memcpy(data, buffer.data, buffer.m_size);
239         }
240         Buffer(T *t, unsigned int size)
241         {
242                 m_size = size;
243                 data = new T[size];
244                 memcpy(data, t, size);
245         }
246         ~Buffer()
247         {
248                 delete[] data;
249         }
250         T & operator[](unsigned int i) const
251         {
252                 return data[i];
253         }
254         T * operator*() const
255         {
256                 return data;
257         }
258         unsigned int getSize() const
259         {
260                 return m_size;
261         }
262 private:
263         T *data;
264         unsigned int m_size;
265 };
266
267 template <typename T>
268 class SharedBuffer
269 {
270 public:
271         SharedBuffer(unsigned int size)
272         {
273                 m_size = size;
274                 data = new T[size];
275                 refcount = new unsigned int;
276                 (*refcount) = 1;
277         }
278         SharedBuffer(const SharedBuffer &buffer)
279         {
280                 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
281                 m_size = buffer.m_size;
282                 data = buffer.data;
283                 refcount = buffer.refcount;
284                 (*refcount)++;
285         }
286         SharedBuffer & operator=(const SharedBuffer & buffer)
287         {
288                 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
289                 if(this == &buffer)
290                         return *this;
291                 drop();
292                 m_size = buffer.m_size;
293                 data = buffer.data;
294                 refcount = buffer.refcount;
295                 (*refcount)++;
296                 return *this;
297         }
298         /*
299                 Copies whole buffer
300         */
301         SharedBuffer(T *t, unsigned int size)
302         {
303                 m_size = size;
304                 data = new T[size];
305                 memcpy(data, t, size);
306                 refcount = new unsigned int;
307                 (*refcount) = 1;
308         }
309         /*
310                 Copies whole buffer
311         */
312         SharedBuffer(const Buffer<T> &buffer)
313         {
314                 m_size = buffer.m_size;
315                 data = new T[buffer.getSize()];
316                 memcpy(data, *buffer, buffer.getSize());
317                 refcount = new unsigned int;
318                 (*refcount) = 1;
319         }
320         ~SharedBuffer()
321         {
322                 drop();
323         }
324         T & operator[](unsigned int i) const
325         {
326                 return data[i];
327         }
328         T * operator*() const
329         {
330                 return data;
331         }
332         unsigned int getSize() const
333         {
334                 return m_size;
335         }
336 private:
337         void drop()
338         {
339                 assert((*refcount) > 0);
340                 (*refcount)--;
341                 if(*refcount == 0)
342                 {
343                         delete[] data;
344                         delete refcount;
345                 }
346         }
347         T *data;
348         unsigned int m_size;
349         unsigned int *refcount;
350 };
351
352 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
353 {
354         SharedBuffer<u8> b((u8*)string, strlen(string)+1);
355         return b;
356 }
357
358 template<typename T>
359 class MutexedVariable
360 {
361 public:
362         MutexedVariable(T value):
363                 m_value(value)
364         {
365                 m_mutex.Init();
366         }
367
368         T get()
369         {
370                 JMutexAutoLock lock(m_mutex);
371                 return m_value;
372         }
373
374         void set(T value)
375         {
376                 JMutexAutoLock lock(m_mutex);
377                 m_value = value;
378         }
379         
380         // You'll want to grab this in a SharedPtr
381         JMutexAutoLock * getLock()
382         {
383                 return new JMutexAutoLock(m_mutex);
384         }
385         
386         // You pretty surely want to grab the lock when accessing this
387         T m_value;
388
389 private:
390         JMutex m_mutex;
391 };
392
393 /*
394         TimeTaker
395 */
396
397 class TimeTaker
398 {
399 public:
400         TimeTaker(const char *name, IrrlichtDevice *dev, u32 *result=NULL)
401         {
402                 m_name = name;
403                 m_dev = dev;
404                 m_result = result;
405                 m_running = true;
406                 if(dev == NULL)
407                 {
408                         m_time1 = 0;
409                         return;
410                 }
411                 m_time1 = m_dev->getTimer()->getRealTime();
412         }
413         ~TimeTaker()
414         {
415                 stop();
416         }
417         u32 stop(bool quiet=false)
418         {
419                 if(m_running)
420                 {
421                         if(m_dev == NULL)
422                         {
423                                 /*if(quiet == false)
424                                         std::cout<<"Couldn't measure time for "<<m_name
425                                                         <<": dev==NULL"<<std::endl;*/
426                                 return 0;
427                         }
428                         u32 time2 = m_dev->getTimer()->getRealTime();
429                         u32 dtime = time2 - m_time1;
430                         if(m_result != NULL)
431                         {
432                                 (*m_result) += dtime;
433                         }
434                         else
435                         {
436                                 if(quiet == false)
437                                         std::cout<<m_name<<" took "<<dtime<<"ms"<<std::endl;
438                         }
439                         m_running = false;
440                         return dtime;
441                 }
442                 return 0;
443         }
444 private:
445         const char *m_name;
446         IrrlichtDevice *m_dev;
447         u32 m_time1;
448         bool m_running;
449         u32 *m_result;
450 };
451
452 // Calculates the borders of a "d-radius" cube
453 inline void getFacePositions(core::list<v3s16> &list, u16 d)
454 {
455         if(d == 0)
456         {
457                 list.push_back(v3s16(0,0,0));
458                 return;
459         }
460         if(d == 1)
461         {
462                 /*
463                         This is an optimized sequence of coordinates.
464                 */
465                 list.push_back(v3s16( 0, 1, 0)); // top
466                 list.push_back(v3s16( 0, 0, 1)); // back
467                 list.push_back(v3s16(-1, 0, 0)); // left
468                 list.push_back(v3s16( 1, 0, 0)); // right
469                 list.push_back(v3s16( 0, 0,-1)); // front
470                 list.push_back(v3s16( 0,-1, 0)); // bottom
471                 // 6
472                 list.push_back(v3s16(-1, 0, 1)); // back left
473                 list.push_back(v3s16( 1, 0, 1)); // back right
474                 list.push_back(v3s16(-1, 0,-1)); // front left
475                 list.push_back(v3s16( 1, 0,-1)); // front right
476                 list.push_back(v3s16(-1,-1, 0)); // bottom left
477                 list.push_back(v3s16( 1,-1, 0)); // bottom right
478                 list.push_back(v3s16( 0,-1, 1)); // bottom back
479                 list.push_back(v3s16( 0,-1,-1)); // bottom front
480                 list.push_back(v3s16(-1, 1, 0)); // top left
481                 list.push_back(v3s16( 1, 1, 0)); // top right
482                 list.push_back(v3s16( 0, 1, 1)); // top back
483                 list.push_back(v3s16( 0, 1,-1)); // top front
484                 // 18
485                 list.push_back(v3s16(-1, 1, 1)); // top back-left
486                 list.push_back(v3s16( 1, 1, 1)); // top back-right
487                 list.push_back(v3s16(-1, 1,-1)); // top front-left
488                 list.push_back(v3s16( 1, 1,-1)); // top front-right
489                 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
490                 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
491                 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
492                 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
493                 // 26
494                 return;
495         }
496
497         // Take blocks in all sides, starting from y=0 and going +-y
498         for(s16 y=0; y<=d-1; y++)
499         {
500                 // Left and right side, including borders
501                 for(s16 z=-d; z<=d; z++)
502                 {
503                         list.push_back(v3s16(d,y,z));
504                         list.push_back(v3s16(-d,y,z));
505                         if(y != 0)
506                         {
507                                 list.push_back(v3s16(d,-y,z));
508                                 list.push_back(v3s16(-d,-y,z));
509                         }
510                 }
511                 // Back and front side, excluding borders
512                 for(s16 x=-d+1; x<=d-1; x++)
513                 {
514                         list.push_back(v3s16(x,y,d));
515                         list.push_back(v3s16(x,y,-d));
516                         if(y != 0)
517                         {
518                                 list.push_back(v3s16(x,-y,d));
519                                 list.push_back(v3s16(x,-y,-d));
520                         }
521                 }
522         }
523
524         // Take the bottom and top face with borders
525         // -d<x<d, y=+-d, -d<z<d
526         for(s16 x=-d; x<=d; x++)
527         for(s16 z=-d; z<=d; z++)
528         {
529                 list.push_back(v3s16(x,-d,z));
530                 list.push_back(v3s16(x,d,z));
531         }
532 }
533
534 class IndentationRaiser
535 {
536 public:
537         IndentationRaiser(u16 *indentation)
538         {
539                 m_indentation = indentation;
540                 (*m_indentation)++;
541         }
542         ~IndentationRaiser()
543         {
544                 (*m_indentation)--;
545         }
546 private:
547         u16 *m_indentation;
548 };
549
550 inline s16 getContainerPos(s16 p, s16 d)
551 {
552         return (p>=0 ? p : p-d+1) / d;
553 }
554
555 inline v2s16 getContainerPos(v2s16 p, s16 d)
556 {
557         return v2s16(
558                 getContainerPos(p.X, d),
559                 getContainerPos(p.Y, d)
560         );
561 }
562
563 inline v3s16 getContainerPos(v3s16 p, s16 d)
564 {
565         return v3s16(
566                 getContainerPos(p.X, d),
567                 getContainerPos(p.Y, d),
568                 getContainerPos(p.Z, d)
569         );
570 }
571
572 inline bool isInArea(v3s16 p, s16 d)
573 {
574         return (
575                 p.X >= 0 && p.X < d &&
576                 p.Y >= 0 && p.Y < d &&
577                 p.Z >= 0 && p.Z < d
578         );
579 }
580
581 inline bool isInArea(v2s16 p, s16 d)
582 {
583         return (
584                 p.X >= 0 && p.X < d &&
585                 p.Y >= 0 && p.Y < d
586         );
587 }
588
589 inline std::wstring narrow_to_wide(const std::string& mbs)
590 {
591         size_t wcl = mbs.size();
592         SharedBuffer<wchar_t> wcs(wcl+1);
593         size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
594         wcs[l] = 0;
595         return *wcs;
596 }
597
598 inline std::string wide_to_narrow(const std::wstring& wcs)
599 {
600         size_t mbl = wcs.size()*4;
601         SharedBuffer<char> mbs(mbl+1);
602         size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
603         if((int)l == -1)
604                 mbs[0] = 0;
605         else
606                 mbs[l] = 0;
607         return *mbs;
608 }
609
610 /*
611         See test.cpp for example cases.
612         wraps degrees to the range of -360...360
613         NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
614 */
615 inline float wrapDegrees(float f)
616 {
617         // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
618         // This results in
619         // 10, 720, -1, -361
620         int i = floor(f);
621         // 0, 2, 0, -1
622         int l = i / 360;
623         // NOTE: This would be used for wrapping to 0...360
624         // 0, 2, -1, -2
625         /*if(i < 0)
626                 l -= 1;*/
627         // 0, 720, 0, -360
628         int k = l * 360;
629         // 10, 0.5, -0.5, -0.5
630         f -= float(k);
631         return f;
632 }
633
634 inline std::string lowercase(std::string s)
635 {
636         for(size_t i=0; i<s.size(); i++)
637         {
638                 if(s[i] >= 'A' && s[i] <= 'Z')
639                         s[i] -= 'A' - 'a';
640         }
641         return s;
642 }
643
644 inline bool is_yes(std::string s)
645 {
646         s = lowercase(trim(s));
647         if(s == "y" || s == "yes" || s == "true")
648                 return true;
649         return false;
650 }
651
652 inline s32 stoi(std::string s, s32 min, s32 max)
653 {
654         s32 i = atoi(s.c_str());
655         if(i < min)
656                 i = min;
657         if(i > max)
658                 i = max;
659         return i;
660 }
661
662 inline s32 stoi(std::string s)
663 {
664         return atoi(s.c_str());
665 }
666
667 /*
668         Config stuff
669 */
670
671 enum ValueType
672 {
673         VALUETYPE_STRING,
674         VALUETYPE_FLAG // Doesn't take any arguments
675 };
676
677 struct ValueSpec
678 {
679         ValueSpec(ValueType a_type, const char *a_help=NULL)
680         {
681                 type = a_type;
682                 help = a_help;
683         }
684         ValueType type;
685         const char *help;
686 };
687
688 class Settings
689 {
690 public:
691
692         // Returns false on EOF
693         bool parseConfigObject(std::istream &is)
694         {
695                 if(is.eof())
696                         return false;
697                 
698                 // NOTE: This function will be expanded to allow multi-line settings
699                 std::string line;
700                 std::getline(is, line);
701                 //dstream<<"got line: \""<<line<<"\""<<std::endl;
702
703                 std::string trimmedline = trim(line);
704                 
705                 // Ignore comments
706                 if(trimmedline[0] == '#')
707                         return true;
708
709                 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
710
711                 Strfnd sf(trim(line));
712
713                 std::string name = sf.next("=");
714                 name = trim(name);
715
716                 if(name == "")
717                         return true;
718                 
719                 std::string value = sf.next("\n");
720                 value = trim(value);
721
722                 dstream<<"Config name=\""<<name<<"\" value=\""
723                                 <<value<<"\""<<std::endl;
724                 
725                 m_settings[name] = value;
726                 
727                 return true;
728         }
729
730         /*
731                 Read configuration file
732
733                 Returns true on success
734         */
735         bool readConfigFile(const char *filename)
736         {
737                 std::ifstream is(filename);
738                 if(is.good() == false)
739                 {
740                         dstream<<"Error opening configuration file \""
741                                         <<filename<<"\""<<std::endl;
742                         return false;
743                 }
744
745                 dstream<<"Parsing configuration file: \""
746                                 <<filename<<"\""<<std::endl;
747                                 
748                 while(parseConfigObject(is));
749                 
750                 return true;
751         }
752
753         /*
754                 Reads a configuration object from stream (usually a single line)
755                 and adds it to dst.
756                 
757                 Preserves comments and empty lines.
758
759                 Settings that were added to dst are also added to updated.
760                 key of updated is setting name, value of updated is dummy.
761
762                 Returns false on EOF
763         */
764         bool getUpdatedConfigObject(std::istream &is,
765                         core::list<std::string> &dst,
766                         core::map<std::string, bool> &updated)
767         {
768                 if(is.eof())
769                         return false;
770                 
771                 // NOTE: This function will be expanded to allow multi-line settings
772                 std::string line;
773                 std::getline(is, line);
774
775                 std::string trimmedline = trim(line);
776
777                 std::string line_end = "";
778                 if(is.eof() == false)
779                         line_end = "\n";
780                 
781                 // Ignore comments
782                 if(trimmedline[0] == '#')
783                 {
784                         dst.push_back(line+line_end);
785                         return true;
786                 }
787
788                 Strfnd sf(trim(line));
789
790                 std::string name = sf.next("=");
791                 name = trim(name);
792
793                 if(name == "")
794                 {
795                         dst.push_back(line+line_end);
796                         return true;
797                 }
798                 
799                 std::string value = sf.next("\n");
800                 value = trim(value);
801                 
802                 if(m_settings.find(name))
803                 {
804                         std::string newvalue = m_settings[name];
805                         
806                         if(newvalue != value)
807                         {
808                                 dstream<<"Changing value of \""<<name<<"\" = \""
809                                                 <<value<<"\" -> \""<<newvalue<<"\""
810                                                 <<std::endl;
811                         }
812
813                         dst.push_back(name + " = " + newvalue + line_end);
814
815                         updated[name] = true;
816                 }
817                 
818                 return true;
819         }
820
821         /*
822                 Updates configuration file
823
824                 Returns true on success
825         */
826         bool updateConfigFile(const char *filename)
827         {
828                 dstream<<"Updating configuration file: \""
829                                 <<filename<<"\""<<std::endl;
830                 
831                 core::list<std::string> objects;
832                 core::map<std::string, bool> updated;
833                 
834                 // Read and modify stuff
835                 {
836                         std::ifstream is(filename);
837                         if(is.good() == false)
838                         {
839                                 dstream<<"Error opening configuration file"
840                                                 " for reading: \""
841                                                 <<filename<<"\""<<std::endl;
842                                 return false;
843                         }
844
845                         while(getUpdatedConfigObject(is, objects, updated));
846                 }
847                 
848                 // Write stuff back
849                 {
850                         std::ofstream os(filename);
851                         if(os.good() == false)
852                         {
853                                 dstream<<"Error opening configuration file"
854                                                 " for writing: \""
855                                                 <<filename<<"\""<<std::endl;
856                                 return false;
857                         }
858                         
859                         /*
860                                 Write updated stuff
861                         */
862                         for(core::list<std::string>::Iterator
863                                         i = objects.begin();
864                                         i != objects.end(); i++)
865                         {
866                                 os<<(*i);
867                         }
868
869                         /*
870                                 Write stuff that was not already in the file
871                         */
872                         for(core::map<std::string, std::string>::Iterator
873                                         i = m_settings.getIterator();
874                                         i.atEnd() == false; i++)
875                         {
876                                 if(updated.find(i.getNode()->getKey()))
877                                         continue;
878                                 std::string name = i.getNode()->getKey();
879                                 std::string value = i.getNode()->getValue();
880                                 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
881                                                 <<std::endl;
882                                 os<<name<<" = "<<value<<"\n";
883                         }
884                 }
885                 
886                 return true;
887         }
888
889         /*
890                 NOTE: Types of allowed_options are ignored
891
892                 returns true on success
893         */
894         bool parseCommandLine(int argc, char *argv[],
895                         core::map<std::string, ValueSpec> &allowed_options)
896         {
897                 int i=1;
898                 for(;;)
899                 {
900                         if(i >= argc)
901                                 break;
902                         std::string argname = argv[i];
903                         if(argname.substr(0, 2) != "--")
904                         {
905                                 dstream<<"Invalid command-line parameter \""
906                                                 <<argname<<"\": --<option> expected."<<std::endl;
907                                 return false;
908                         }
909                         i++;
910
911                         std::string name = argname.substr(2);
912
913                         core::map<std::string, ValueSpec>::Node *n;
914                         n = allowed_options.find(name);
915                         if(n == NULL)
916                         {
917                                 dstream<<"Unknown command-line parameter \""
918                                                 <<argname<<"\""<<std::endl;
919                                 return false;
920                         }
921
922                         ValueType type = n->getValue().type;
923
924                         std::string value = "";
925                         
926                         if(type == VALUETYPE_FLAG)
927                         {
928                                 value = "true";
929                         }
930                         else
931                         {
932                                 if(i >= argc)
933                                 {
934                                         dstream<<"Invalid command-line parameter \""
935                                                         <<name<<"\": missing value"<<std::endl;
936                                         return false;
937                                 }
938                                 value = argv[i];
939                                 i++;
940                         }
941                         
942
943                         dstream<<"Valid command-line parameter: \""
944                                         <<name<<"\" = \""<<value<<"\""
945                                         <<std::endl;
946                         set(name, value);
947                 }
948
949                 return true;
950         }
951
952         void set(std::string name, std::string value)
953         {
954                 m_settings[name] = value;
955         }
956
957         void setDefault(std::string name, std::string value)
958         {
959                 m_defaults[name] = value;
960         }
961
962         bool exists(std::string name)
963         {
964                 return (m_settings.find(name) || m_defaults.find(name));
965         }
966
967         std::string get(std::string name)
968         {
969                 core::map<std::string, std::string>::Node *n;
970                 n = m_settings.find(name);
971                 if(n == NULL)
972                 {
973                         n = m_defaults.find(name);
974                         if(n == NULL)
975                         {
976                                 throw SettingNotFoundException("Setting not found");
977                         }
978                 }
979
980                 return n->getValue();
981         }
982
983         bool getBool(std::string name)
984         {
985                 return is_yes(get(name));
986         }
987         
988         bool getFlag(std::string name)
989         {
990                 try
991                 {
992                         return getBool(name);
993                 }
994                 catch(SettingNotFoundException &e)
995                 {
996                         return false;
997                 }
998         }
999
1000         // Asks if empty
1001         bool getBoolAsk(std::string name, std::string question, bool def)
1002         {
1003                 std::string s = get(name);
1004                 if(s != "")
1005                         return is_yes(s);
1006                 
1007                 char templine[10];
1008                 std::cout<<question<<" [y/N]: ";
1009                 std::cin.getline(templine, 10);
1010                 s = templine;
1011
1012                 if(s == "")
1013                         return def;
1014
1015                 return is_yes(s);
1016         }
1017
1018         float getFloat(std::string name)
1019         {
1020                 float f;
1021                 std::istringstream vis(get(name));
1022                 vis>>f;
1023                 return f;
1024         }
1025
1026         u16 getU16(std::string name)
1027         {
1028                 return stoi(get(name), 0, 65535);
1029         }
1030
1031         u16 getU16Ask(std::string name, std::string question, u16 def)
1032         {
1033                 std::string s = get(name);
1034                 if(s != "")
1035                         return stoi(s, 0, 65535);
1036                 
1037                 char templine[10];
1038                 std::cout<<question<<" ["<<def<<"]: ";
1039                 std::cin.getline(templine, 10);
1040                 s = templine;
1041
1042                 if(s == "")
1043                         return def;
1044
1045                 return stoi(s, 0, 65535);
1046         }
1047
1048         s16 getS16(std::string name)
1049         {
1050                 return stoi(get(name), -32768, 32767);
1051         }
1052
1053         s32 getS32(std::string name)
1054         {
1055                 return stoi(get(name));
1056         }
1057
1058 private:
1059         core::map<std::string, std::string> m_settings;
1060         core::map<std::string, std::string> m_defaults;
1061 };
1062
1063 /*
1064         A thread-safe texture cache.
1065
1066         This is used so that irrlicht doesn't get called from many threads
1067 */
1068
1069 class TextureCache
1070 {
1071 public:
1072         TextureCache()
1073         {
1074                 m_mutex.Init();
1075                 assert(m_mutex.IsInitialized());
1076         }
1077         
1078         void set(std::string name, video::ITexture *texture)
1079         {
1080                 JMutexAutoLock lock(m_mutex);
1081
1082                 m_textures[name] = texture;
1083         }
1084         
1085         video::ITexture* get(std::string name)
1086         {
1087                 JMutexAutoLock lock(m_mutex);
1088
1089                 core::map<std::string, video::ITexture*>::Node *n;
1090                 n = m_textures.find(name);
1091
1092                 if(n != NULL)
1093                         return n->getValue();
1094
1095                 return NULL;
1096         }
1097
1098 private:
1099         core::map<std::string, video::ITexture*> m_textures;
1100         JMutex m_mutex;
1101 };
1102
1103 #endif
1104