Don't call curl_global_init twice
[oweals/minetest.git] / src / main.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 #ifdef NDEBUG
21         /*#ifdef _WIN32
22                 #pragma message ("Disabling unit tests")
23         #else
24                 #warning "Disabling unit tests"
25         #endif*/
26         // Disable unit tests
27         #define ENABLE_TESTS 0
28 #else
29         // Enable unit tests
30         #define ENABLE_TESTS 1
31 #endif
32
33 #ifdef _MSC_VER
34 #ifndef SERVER // Dedicated server isn't linked with Irrlicht
35         #pragma comment(lib, "Irrlicht.lib")
36         // This would get rid of the console window
37         //#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
38 #endif
39         #pragma comment(lib, "zlibwapi.lib")
40         #pragma comment(lib, "Shell32.lib")
41 #endif
42
43 #include "irrlicht.h" // createDevice
44
45 #include "main.h"
46 #include "mainmenumanager.h"
47 #include <iostream>
48 #include <fstream>
49 #include <locale.h>
50 #include "irrlichttypes_extrabloated.h"
51 #include "debug.h"
52 #include "test.h"
53 #include "clouds.h"
54 #include "server.h"
55 #include "constants.h"
56 #include "porting.h"
57 #include "gettime.h"
58 #include "guiMessageMenu.h"
59 #include "filesys.h"
60 #include "config.h"
61 #include "version.h"
62 #include "guiMainMenu.h"
63 #include "game.h"
64 #include "keycode.h"
65 #include "tile.h"
66 #include "chat.h"
67 #include "defaultsettings.h"
68 #include "gettext.h"
69 #include "settings.h"
70 #include "profiler.h"
71 #include "log.h"
72 #include "mods.h"
73 #if USE_FREETYPE
74 #include "xCGUITTFont.h"
75 #endif
76 #include "util/string.h"
77 #include "subgame.h"
78 #include "quicktune.h"
79 #include "serverlist.h"
80 #include "httpfetch.h"
81 #include "guiEngine.h"
82 #include "mapsector.h"
83
84 #include "database-sqlite3.h"
85 #ifdef USE_LEVELDB
86 #include "database-leveldb.h"
87 #endif
88
89 /*
90         Settings.
91         These are loaded from the config file.
92 */
93 Settings main_settings;
94 Settings *g_settings = &main_settings;
95 std::string g_settings_path;
96
97 // Global profiler
98 Profiler main_profiler;
99 Profiler *g_profiler = &main_profiler;
100
101 // Menu clouds are created later
102 Clouds *g_menuclouds = 0;
103 irr::scene::ISceneManager *g_menucloudsmgr = 0;
104
105 /*
106         Debug streams
107 */
108
109 // Connection
110 std::ostream *dout_con_ptr = &dummyout;
111 std::ostream *derr_con_ptr = &verbosestream;
112
113 // Server
114 std::ostream *dout_server_ptr = &infostream;
115 std::ostream *derr_server_ptr = &errorstream;
116
117 // Client
118 std::ostream *dout_client_ptr = &infostream;
119 std::ostream *derr_client_ptr = &errorstream;
120
121 #ifndef SERVER
122 /*
123         Random stuff
124 */
125
126 /* mainmenumanager.h */
127
128 gui::IGUIEnvironment* guienv = NULL;
129 gui::IGUIStaticText *guiroot = NULL;
130 MainMenuManager g_menumgr;
131
132 bool noMenuActive()
133 {
134         return (g_menumgr.menuCount() == 0);
135 }
136
137 // Passed to menus to allow disconnecting and exiting
138 MainGameCallback *g_gamecallback = NULL;
139 #endif
140
141 /*
142         gettime.h implementation
143 */
144
145 #ifdef SERVER
146
147 u32 getTimeMs()
148 {
149         /* Use imprecise system calls directly (from porting.h) */
150         return porting::getTime(PRECISION_MILLI);
151 }
152
153 u32 getTime(TimePrecision prec)
154 {
155         return porting::getTime(prec);
156 }
157
158 #else
159
160 // A small helper class
161 class TimeGetter
162 {
163 public:
164         virtual u32 getTime(TimePrecision prec) = 0;
165 };
166
167 // A precise irrlicht one
168 class IrrlichtTimeGetter: public TimeGetter
169 {
170 public:
171         IrrlichtTimeGetter(IrrlichtDevice *device):
172                 m_device(device)
173         {}
174         u32 getTime(TimePrecision prec)
175         {
176                 if (prec == PRECISION_MILLI) {
177                         if(m_device == NULL)
178                                 return 0;
179                         return m_device->getTimer()->getRealTime();
180                 } else {
181                         return porting::getTime(prec);
182                 }
183         }
184 private:
185         IrrlichtDevice *m_device;
186 };
187 // Not so precise one which works without irrlicht
188 class SimpleTimeGetter: public TimeGetter
189 {
190 public:
191         u32 getTime(TimePrecision prec)
192         {
193                 return porting::getTime(prec);
194         }
195 };
196
197 // A pointer to a global instance of the time getter
198 // TODO: why?
199 TimeGetter *g_timegetter = NULL;
200
201 u32 getTimeMs()
202 {
203         if(g_timegetter == NULL)
204                 return 0;
205         return g_timegetter->getTime(PRECISION_MILLI);
206 }
207
208 u32 getTime(TimePrecision prec) {
209         if (g_timegetter == NULL)
210                 return 0;
211         return g_timegetter->getTime(prec);
212 }
213 #endif
214
215 class StderrLogOutput: public ILogOutput
216 {
217 public:
218         /* line: Full line with timestamp, level and thread */
219         void printLog(const std::string &line)
220         {
221                 std::cerr<<line<<std::endl;
222         }
223 } main_stderr_log_out;
224
225 class DstreamNoStderrLogOutput: public ILogOutput
226 {
227 public:
228         /* line: Full line with timestamp, level and thread */
229         void printLog(const std::string &line)
230         {
231                 dstream_no_stderr<<line<<std::endl;
232         }
233 } main_dstream_no_stderr_log_out;
234
235 #ifndef SERVER
236
237 /*
238         Event handler for Irrlicht
239
240         NOTE: Everything possible should be moved out from here,
241               probably to InputHandler and the_game
242 */
243
244 class MyEventReceiver : public IEventReceiver
245 {
246 public:
247         // This is the one method that we have to implement
248         virtual bool OnEvent(const SEvent& event)
249         {
250                 /*
251                         React to nothing here if a menu is active
252                 */
253                 if(noMenuActive() == false)
254                 {
255                         return g_menumgr.preprocessEvent(event);
256                 }
257
258                 // Remember whether each key is down or up
259                 if(event.EventType == irr::EET_KEY_INPUT_EVENT)
260                 {
261                         if(event.KeyInput.PressedDown) {
262                                 keyIsDown.set(event.KeyInput);
263                                 keyWasDown.set(event.KeyInput);
264                         } else {
265                                 keyIsDown.unset(event.KeyInput);
266                         }
267                 }
268
269                 if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)
270                 {
271                         if(noMenuActive() == false)
272                         {
273                                 left_active = false;
274                                 middle_active = false;
275                                 right_active = false;
276                         }
277                         else
278                         {
279                                 left_active = event.MouseInput.isLeftPressed();
280                                 middle_active = event.MouseInput.isMiddlePressed();
281                                 right_active = event.MouseInput.isRightPressed();
282
283                                 if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
284                                 {
285                                         leftclicked = true;
286                                 }
287                                 if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
288                                 {
289                                         rightclicked = true;
290                                 }
291                                 if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
292                                 {
293                                         leftreleased = true;
294                                 }
295                                 if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)
296                                 {
297                                         rightreleased = true;
298                                 }
299                                 if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
300                                 {
301                                         mouse_wheel += event.MouseInput.Wheel;
302                                 }
303                         }
304                 }
305
306                 return false;
307         }
308
309         bool IsKeyDown(const KeyPress &keyCode) const
310         {
311                 return keyIsDown[keyCode];
312         }
313
314         // Checks whether a key was down and resets the state
315         bool WasKeyDown(const KeyPress &keyCode)
316         {
317                 bool b = keyWasDown[keyCode];
318                 if (b)
319                         keyWasDown.unset(keyCode);
320                 return b;
321         }
322
323         s32 getMouseWheel()
324         {
325                 s32 a = mouse_wheel;
326                 mouse_wheel = 0;
327                 return a;
328         }
329
330         void clearInput()
331         {
332                 keyIsDown.clear();
333                 keyWasDown.clear();
334
335                 leftclicked = false;
336                 rightclicked = false;
337                 leftreleased = false;
338                 rightreleased = false;
339
340                 left_active = false;
341                 middle_active = false;
342                 right_active = false;
343
344                 mouse_wheel = 0;
345         }
346
347         MyEventReceiver()
348         {
349                 clearInput();
350         }
351
352         bool leftclicked;
353         bool rightclicked;
354         bool leftreleased;
355         bool rightreleased;
356
357         bool left_active;
358         bool middle_active;
359         bool right_active;
360
361         s32 mouse_wheel;
362
363 private:
364         IrrlichtDevice *m_device;
365
366         // The current state of keys
367         KeyList keyIsDown;
368         // Whether a key has been pressed or not
369         KeyList keyWasDown;
370 };
371
372 /*
373         Separated input handler
374 */
375
376 class RealInputHandler : public InputHandler
377 {
378 public:
379         RealInputHandler(IrrlichtDevice *device, MyEventReceiver *receiver):
380                 m_device(device),
381                 m_receiver(receiver)
382         {
383         }
384         virtual bool isKeyDown(const KeyPress &keyCode)
385         {
386                 return m_receiver->IsKeyDown(keyCode);
387         }
388         virtual bool wasKeyDown(const KeyPress &keyCode)
389         {
390                 return m_receiver->WasKeyDown(keyCode);
391         }
392         virtual v2s32 getMousePos()
393         {
394                 return m_device->getCursorControl()->getPosition();
395         }
396         virtual void setMousePos(s32 x, s32 y)
397         {
398                 m_device->getCursorControl()->setPosition(x, y);
399         }
400
401         virtual bool getLeftState()
402         {
403                 return m_receiver->left_active;
404         }
405         virtual bool getRightState()
406         {
407                 return m_receiver->right_active;
408         }
409
410         virtual bool getLeftClicked()
411         {
412                 return m_receiver->leftclicked;
413         }
414         virtual bool getRightClicked()
415         {
416                 return m_receiver->rightclicked;
417         }
418         virtual void resetLeftClicked()
419         {
420                 m_receiver->leftclicked = false;
421         }
422         virtual void resetRightClicked()
423         {
424                 m_receiver->rightclicked = false;
425         }
426
427         virtual bool getLeftReleased()
428         {
429                 return m_receiver->leftreleased;
430         }
431         virtual bool getRightReleased()
432         {
433                 return m_receiver->rightreleased;
434         }
435         virtual void resetLeftReleased()
436         {
437                 m_receiver->leftreleased = false;
438         }
439         virtual void resetRightReleased()
440         {
441                 m_receiver->rightreleased = false;
442         }
443
444         virtual s32 getMouseWheel()
445         {
446                 return m_receiver->getMouseWheel();
447         }
448
449         void clear()
450         {
451                 m_receiver->clearInput();
452         }
453 private:
454         IrrlichtDevice *m_device;
455         MyEventReceiver *m_receiver;
456 };
457
458 class RandomInputHandler : public InputHandler
459 {
460 public:
461         RandomInputHandler()
462         {
463                 leftdown = false;
464                 rightdown = false;
465                 leftclicked = false;
466                 rightclicked = false;
467                 leftreleased = false;
468                 rightreleased = false;
469                 keydown.clear();
470         }
471         virtual bool isKeyDown(const KeyPress &keyCode)
472         {
473                 return keydown[keyCode];
474         }
475         virtual bool wasKeyDown(const KeyPress &keyCode)
476         {
477                 return false;
478         }
479         virtual v2s32 getMousePos()
480         {
481                 return mousepos;
482         }
483         virtual void setMousePos(s32 x, s32 y)
484         {
485                 mousepos = v2s32(x,y);
486         }
487
488         virtual bool getLeftState()
489         {
490                 return leftdown;
491         }
492         virtual bool getRightState()
493         {
494                 return rightdown;
495         }
496
497         virtual bool getLeftClicked()
498         {
499                 return leftclicked;
500         }
501         virtual bool getRightClicked()
502         {
503                 return rightclicked;
504         }
505         virtual void resetLeftClicked()
506         {
507                 leftclicked = false;
508         }
509         virtual void resetRightClicked()
510         {
511                 rightclicked = false;
512         }
513
514         virtual bool getLeftReleased()
515         {
516                 return leftreleased;
517         }
518         virtual bool getRightReleased()
519         {
520                 return rightreleased;
521         }
522         virtual void resetLeftReleased()
523         {
524                 leftreleased = false;
525         }
526         virtual void resetRightReleased()
527         {
528                 rightreleased = false;
529         }
530
531         virtual s32 getMouseWheel()
532         {
533                 return 0;
534         }
535
536         virtual void step(float dtime)
537         {
538                 {
539                         static float counter1 = 0;
540                         counter1 -= dtime;
541                         if(counter1 < 0.0)
542                         {
543                                 counter1 = 0.1*Rand(1, 40);
544                                 keydown.toggle(getKeySetting("keymap_jump"));
545                         }
546                 }
547                 {
548                         static float counter1 = 0;
549                         counter1 -= dtime;
550                         if(counter1 < 0.0)
551                         {
552                                 counter1 = 0.1*Rand(1, 40);
553                                 keydown.toggle(getKeySetting("keymap_special1"));
554                         }
555                 }
556                 {
557                         static float counter1 = 0;
558                         counter1 -= dtime;
559                         if(counter1 < 0.0)
560                         {
561                                 counter1 = 0.1*Rand(1, 40);
562                                 keydown.toggle(getKeySetting("keymap_forward"));
563                         }
564                 }
565                 {
566                         static float counter1 = 0;
567                         counter1 -= dtime;
568                         if(counter1 < 0.0)
569                         {
570                                 counter1 = 0.1*Rand(1, 40);
571                                 keydown.toggle(getKeySetting("keymap_left"));
572                         }
573                 }
574                 {
575                         static float counter1 = 0;
576                         counter1 -= dtime;
577                         if(counter1 < 0.0)
578                         {
579                                 counter1 = 0.1*Rand(1, 20);
580                                 mousespeed = v2s32(Rand(-20,20), Rand(-15,20));
581                         }
582                 }
583                 {
584                         static float counter1 = 0;
585                         counter1 -= dtime;
586                         if(counter1 < 0.0)
587                         {
588                                 counter1 = 0.1*Rand(1, 30);
589                                 leftdown = !leftdown;
590                                 if(leftdown)
591                                         leftclicked = true;
592                                 if(!leftdown)
593                                         leftreleased = true;
594                         }
595                 }
596                 {
597                         static float counter1 = 0;
598                         counter1 -= dtime;
599                         if(counter1 < 0.0)
600                         {
601                                 counter1 = 0.1*Rand(1, 15);
602                                 rightdown = !rightdown;
603                                 if(rightdown)
604                                         rightclicked = true;
605                                 if(!rightdown)
606                                         rightreleased = true;
607                         }
608                 }
609                 mousepos += mousespeed;
610         }
611
612         s32 Rand(s32 min, s32 max)
613         {
614                 return (myrand()%(max-min+1))+min;
615         }
616 private:
617         KeyList keydown;
618         v2s32 mousepos;
619         v2s32 mousespeed;
620         bool leftdown;
621         bool rightdown;
622         bool leftclicked;
623         bool rightclicked;
624         bool leftreleased;
625         bool rightreleased;
626 };
627
628 #endif // !SERVER
629
630 // These are defined global so that they're not optimized too much.
631 // Can't change them to volatile.
632 s16 temp16;
633 f32 tempf;
634 v3f tempv3f1;
635 v3f tempv3f2;
636 std::string tempstring;
637 std::string tempstring2;
638
639 void SpeedTests()
640 {
641         {
642                 infostream<<"The following test should take around 20ms."<<std::endl;
643                 TimeTaker timer("Testing std::string speed");
644                 const u32 jj = 10000;
645                 for(u32 j=0; j<jj; j++)
646                 {
647                         tempstring = "";
648                         tempstring2 = "";
649                         const u32 ii = 10;
650                         for(u32 i=0; i<ii; i++){
651                                 tempstring2 += "asd";
652                         }
653                         for(u32 i=0; i<ii+1; i++){
654                                 tempstring += "asd";
655                                 if(tempstring == tempstring2)
656                                         break;
657                         }
658                 }
659         }
660
661         infostream<<"All of the following tests should take around 100ms each."
662                         <<std::endl;
663
664         {
665                 TimeTaker timer("Testing floating-point conversion speed");
666                 tempf = 0.001;
667                 for(u32 i=0; i<4000000; i++){
668                         temp16 += tempf;
669                         tempf += 0.001;
670                 }
671         }
672
673         {
674                 TimeTaker timer("Testing floating-point vector speed");
675
676                 tempv3f1 = v3f(1,2,3);
677                 tempv3f2 = v3f(4,5,6);
678                 for(u32 i=0; i<10000000; i++){
679                         tempf += tempv3f1.dotProduct(tempv3f2);
680                         tempv3f2 += v3f(7,8,9);
681                 }
682         }
683
684         {
685                 TimeTaker timer("Testing std::map speed");
686
687                 std::map<v2s16, f32> map1;
688                 tempf = -324;
689                 const s16 ii=300;
690                 for(s16 y=0; y<ii; y++){
691                         for(s16 x=0; x<ii; x++){
692                                 map1[v2s16(x,y)] =  tempf;
693                                 tempf += 1;
694                         }
695                 }
696                 for(s16 y=ii-1; y>=0; y--){
697                         for(s16 x=0; x<ii; x++){
698                                 tempf = map1[v2s16(x,y)];
699                         }
700                 }
701         }
702
703         {
704                 infostream<<"Around 5000/ms should do well here."<<std::endl;
705                 TimeTaker timer("Testing mutex speed");
706
707                 JMutex m;
708                 u32 n = 0;
709                 u32 i = 0;
710                 do{
711                         n += 10000;
712                         for(; i<n; i++){
713                                 m.Lock();
714                                 m.Unlock();
715                         }
716                 }
717                 // Do at least 10ms
718                 while(timer.getTimerTime() < 10);
719
720                 u32 dtime = timer.stop();
721                 u32 per_ms = n / dtime;
722                 infostream<<"Done. "<<dtime<<"ms, "
723                                 <<per_ms<<"/ms"<<std::endl;
724         }
725 }
726
727 static void print_worldspecs(const std::vector<WorldSpec> &worldspecs,
728                 std::ostream &os)
729 {
730         for(u32 i=0; i<worldspecs.size(); i++){
731                 std::string name = worldspecs[i].name;
732                 std::string path = worldspecs[i].path;
733                 if(name.find(" ") != std::string::npos)
734                         name = std::string("'") + name + "'";
735                 path = std::string("'") + path + "'";
736                 name = padStringRight(name, 14);
737                 os<<"  "<<name<<" "<<path<<std::endl;
738         }
739 }
740
741 int main(int argc, char *argv[])
742 {
743         int retval = 0;
744
745         /*
746                 Initialization
747         */
748
749         log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION);
750         log_add_output_all_levs(&main_dstream_no_stderr_log_out);
751
752         log_register_thread("main");
753         /*
754                 Parse command line
755         */
756
757         // List all allowed options
758         std::map<std::string, ValueSpec> allowed_options;
759         allowed_options.insert(std::make_pair("help", ValueSpec(VALUETYPE_FLAG,
760                         _("Show allowed options"))));
761         allowed_options.insert(std::make_pair("version", ValueSpec(VALUETYPE_FLAG,
762                         _("Show version information"))));
763         allowed_options.insert(std::make_pair("config", ValueSpec(VALUETYPE_STRING,
764                         _("Load configuration from specified file"))));
765         allowed_options.insert(std::make_pair("port", ValueSpec(VALUETYPE_STRING,
766                         _("Set network port (UDP)"))));
767         allowed_options.insert(std::make_pair("disable-unittests", ValueSpec(VALUETYPE_FLAG,
768                         _("Disable unit tests"))));
769         allowed_options.insert(std::make_pair("enable-unittests", ValueSpec(VALUETYPE_FLAG,
770                         _("Enable unit tests"))));
771         allowed_options.insert(std::make_pair("map-dir", ValueSpec(VALUETYPE_STRING,
772                         _("Same as --world (deprecated)"))));
773         allowed_options.insert(std::make_pair("world", ValueSpec(VALUETYPE_STRING,
774                         _("Set world path (implies local game) ('list' lists all)"))));
775         allowed_options.insert(std::make_pair("worldname", ValueSpec(VALUETYPE_STRING,
776                         _("Set world by name (implies local game)"))));
777         allowed_options.insert(std::make_pair("info", ValueSpec(VALUETYPE_FLAG,
778                         _("Print more information to console"))));
779         allowed_options.insert(std::make_pair("verbose",  ValueSpec(VALUETYPE_FLAG,
780                         _("Print even more information to console"))));
781         allowed_options.insert(std::make_pair("trace", ValueSpec(VALUETYPE_FLAG,
782                         _("Print enormous amounts of information to log and console"))));
783         allowed_options.insert(std::make_pair("logfile", ValueSpec(VALUETYPE_STRING,
784                         _("Set logfile path ('' = no logging)"))));
785         allowed_options.insert(std::make_pair("gameid", ValueSpec(VALUETYPE_STRING,
786                         _("Set gameid (\"--gameid list\" prints available ones)"))));
787         allowed_options.insert(std::make_pair("migrate", ValueSpec(VALUETYPE_STRING,
788                         _("Migrate from current map backend to another (Only works when using minetestserver or with --server)"))));
789 #ifndef SERVER
790         allowed_options.insert(std::make_pair("videomodes", ValueSpec(VALUETYPE_FLAG,
791                         _("Show available video modes"))));
792         allowed_options.insert(std::make_pair("speedtests", ValueSpec(VALUETYPE_FLAG,
793                         _("Run speed tests"))));
794         allowed_options.insert(std::make_pair("address", ValueSpec(VALUETYPE_STRING,
795                         _("Address to connect to. ('' = local game)"))));
796         allowed_options.insert(std::make_pair("random-input", ValueSpec(VALUETYPE_FLAG,
797                         _("Enable random user input, for testing"))));
798         allowed_options.insert(std::make_pair("server", ValueSpec(VALUETYPE_FLAG,
799                         _("Run dedicated server"))));
800         allowed_options.insert(std::make_pair("name", ValueSpec(VALUETYPE_STRING,
801                         _("Set player name"))));
802         allowed_options.insert(std::make_pair("password", ValueSpec(VALUETYPE_STRING,
803                         _("Set password"))));
804         allowed_options.insert(std::make_pair("go", ValueSpec(VALUETYPE_FLAG,
805                         _("Disable main menu"))));
806 #endif
807
808         Settings cmd_args;
809
810         bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);
811
812         if(ret == false || cmd_args.getFlag("help") || cmd_args.exists("nonopt1"))
813         {
814                 dstream<<_("Allowed options:")<<std::endl;
815                 for(std::map<std::string, ValueSpec>::iterator
816                                 i = allowed_options.begin();
817                                 i != allowed_options.end(); ++i)
818                 {
819                         std::ostringstream os1(std::ios::binary);
820                         os1<<"  --"<<i->first;
821                         if(i->second.type == VALUETYPE_FLAG)
822                                 {}
823                         else
824                                 os1<<_(" <value>");
825                         dstream<<padStringRight(os1.str(), 24);
826
827                         if(i->second.help != NULL)
828                                 dstream<<i->second.help;
829                         dstream<<std::endl;
830                 }
831
832                 return cmd_args.getFlag("help") ? 0 : 1;
833         }
834
835         if(cmd_args.getFlag("version"))
836         {
837 #ifdef SERVER
838                 dstream<<"minetestserver "<<minetest_version_hash<<std::endl;
839 #else
840                 dstream<<"Minetest "<<minetest_version_hash<<std::endl;
841                 dstream<<"Using Irrlicht "<<IRRLICHT_SDK_VERSION<<std::endl;
842 #endif
843                 dstream<<"Build info: "<<minetest_build_info<<std::endl;
844                 return 0;
845         }
846
847         /*
848                 Low-level initialization
849         */
850
851         // If trace is enabled, enable logging of certain things
852         if(cmd_args.getFlag("trace")){
853                 dstream<<_("Enabling trace level debug output")<<std::endl;
854                 log_trace_level_enabled = true;
855                 dout_con_ptr = &verbosestream; // this is somewhat old crap
856                 socket_enable_debug_output = true; // socket doesn't use log.h
857         }
858         // In certain cases, output info level on stderr
859         if(cmd_args.getFlag("info") || cmd_args.getFlag("verbose") ||
860                         cmd_args.getFlag("trace") || cmd_args.getFlag("speedtests"))
861                 log_add_output(&main_stderr_log_out, LMT_INFO);
862         // In certain cases, output verbose level on stderr
863         if(cmd_args.getFlag("verbose") || cmd_args.getFlag("trace"))
864                 log_add_output(&main_stderr_log_out, LMT_VERBOSE);
865
866         porting::signal_handler_init();
867         bool &kill = *porting::signal_handler_killstatus();
868
869         porting::initializePaths();
870
871         // Create user data directory
872         fs::CreateDir(porting::path_user);
873
874         infostream<<"path_share = "<<porting::path_share<<std::endl;
875         infostream<<"path_user  = "<<porting::path_user<<std::endl;
876
877         // Initialize debug stacks
878         debug_stacks_init();
879         DSTACK(__FUNCTION_NAME);
880
881         // Debug handler
882         BEGIN_DEBUG_EXCEPTION_HANDLER
883
884         // List gameids if requested
885         if(cmd_args.exists("gameid") && cmd_args.get("gameid") == "list")
886         {
887                 std::set<std::string> gameids = getAvailableGameIds();
888                 for(std::set<std::string>::const_iterator i = gameids.begin();
889                                 i != gameids.end(); i++)
890                         dstream<<(*i)<<std::endl;
891                 return 0;
892         }
893
894         // List worlds if requested
895         if(cmd_args.exists("world") && cmd_args.get("world") == "list"){
896                 dstream<<_("Available worlds:")<<std::endl;
897                 std::vector<WorldSpec> worldspecs = getAvailableWorlds();
898                 print_worldspecs(worldspecs, dstream);
899                 return 0;
900         }
901
902         // Print startup message
903         infostream<<PROJECT_NAME<<
904                         " "<<_("with")<<" SER_FMT_VER_HIGHEST_READ="<<(int)SER_FMT_VER_HIGHEST_READ
905                         <<", "<<minetest_build_info
906                         <<std::endl;
907
908         /*
909                 Basic initialization
910         */
911
912         // Initialize default settings
913         set_default_settings(g_settings);
914
915         // Initialize sockets
916         sockets_init();
917         atexit(sockets_cleanup);
918
919         /*
920                 Read config file
921         */
922
923         // Path of configuration file in use
924         g_settings_path = "";
925
926         if(cmd_args.exists("config"))
927         {
928                 bool r = g_settings->readConfigFile(cmd_args.get("config").c_str());
929                 if(r == false)
930                 {
931                         errorstream<<"Could not read configuration from \""
932                                         <<cmd_args.get("config")<<"\""<<std::endl;
933                         return 1;
934                 }
935                 g_settings_path = cmd_args.get("config");
936         }
937         else
938         {
939                 std::vector<std::string> filenames;
940                 filenames.push_back(porting::path_user +
941                                 DIR_DELIM + "minetest.conf");
942                 // Legacy configuration file location
943                 filenames.push_back(porting::path_user +
944                                 DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
945 #if RUN_IN_PLACE
946                 // Try also from a lower level (to aid having the same configuration
947                 // for many RUN_IN_PLACE installs)
948                 filenames.push_back(porting::path_user +
949                                 DIR_DELIM + ".." + DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
950 #endif
951
952                 for(u32 i=0; i<filenames.size(); i++)
953                 {
954                         bool r = g_settings->readConfigFile(filenames[i].c_str());
955                         if(r)
956                         {
957                                 g_settings_path = filenames[i];
958                                 break;
959                         }
960                 }
961
962                 // If no path found, use the first one (menu creates the file)
963                 if(g_settings_path == "")
964                         g_settings_path = filenames[0];
965         }
966
967         // Initialize debug streams
968 #define DEBUGFILE "debug.txt"
969 #if RUN_IN_PLACE
970         std::string logfile = DEBUGFILE;
971 #else
972         std::string logfile = porting::path_user+DIR_DELIM+DEBUGFILE;
973 #endif
974         if(cmd_args.exists("logfile"))
975                 logfile = cmd_args.get("logfile");
976
977         log_remove_output(&main_dstream_no_stderr_log_out);
978         int loglevel = g_settings->getS32("debug_log_level");
979
980         if (loglevel == 0) //no logging
981                 logfile = "";
982         else if (loglevel > 0 && loglevel <= LMT_NUM_VALUES)
983                 log_add_output_maxlev(&main_dstream_no_stderr_log_out, (LogMessageLevel)(loglevel - 1));
984
985         if(logfile != "")
986                 debugstreams_init(false, logfile.c_str());
987         else
988                 debugstreams_init(false, NULL);
989
990         infostream<<"logfile    = "<<logfile<<std::endl;
991
992         // Initialize random seed
993         srand(time(0));
994         mysrand(time(0));
995
996         // Initialize HTTP fetcher
997         httpfetch_init(g_settings->getS32("curl_parallel_limit"));
998
999         /*
1000                 Run unit tests
1001         */
1002
1003         if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)
1004                         || cmd_args.getFlag("enable-unittests") == true)
1005         {
1006                 run_tests();
1007         }
1008 #ifdef _MSC_VER
1009         init_gettext((porting::path_share + DIR_DELIM + "locale").c_str(),g_settings->get("language"),argc,argv);
1010 #else
1011         init_gettext((porting::path_share + DIR_DELIM + "locale").c_str(),g_settings->get("language"));
1012 #endif
1013
1014         /*
1015                 Game parameters
1016         */
1017
1018         // Port
1019         u16 port = 30000;
1020         if(cmd_args.exists("port"))
1021                 port = cmd_args.getU16("port");
1022         else if(g_settings->exists("port"))
1023                 port = g_settings->getU16("port");
1024         if(port == 0)
1025                 port = 30000;
1026
1027         // World directory
1028         std::string commanded_world = "";
1029         if(cmd_args.exists("world"))
1030                 commanded_world = cmd_args.get("world");
1031         else if(cmd_args.exists("map-dir"))
1032                 commanded_world = cmd_args.get("map-dir");
1033         else if(cmd_args.exists("nonopt0")) // First nameless argument
1034                 commanded_world = cmd_args.get("nonopt0");
1035         else if(g_settings->exists("map-dir"))
1036                 commanded_world = g_settings->get("map-dir");
1037
1038         // World name
1039         std::string commanded_worldname = "";
1040         if(cmd_args.exists("worldname"))
1041                 commanded_worldname = cmd_args.get("worldname");
1042
1043         // Strip world.mt from commanded_world
1044         {
1045                 std::string worldmt = "world.mt";
1046                 if(commanded_world.size() > worldmt.size() &&
1047                                 commanded_world.substr(commanded_world.size()-worldmt.size())
1048                                 == worldmt){
1049                         dstream<<_("Supplied world.mt file - stripping it off.")<<std::endl;
1050                         commanded_world = commanded_world.substr(
1051                                         0, commanded_world.size()-worldmt.size());
1052                 }
1053         }
1054
1055         // If a world name was specified, convert it to a path
1056         if(commanded_worldname != ""){
1057                 // Get information about available worlds
1058                 std::vector<WorldSpec> worldspecs = getAvailableWorlds();
1059                 bool found = false;
1060                 for(u32 i=0; i<worldspecs.size(); i++){
1061                         std::string name = worldspecs[i].name;
1062                         if(name == commanded_worldname){
1063                                 if(commanded_world != ""){
1064                                         dstream<<_("--worldname takes precedence over previously "
1065                                                         "selected world.")<<std::endl;
1066                                 }
1067                                 commanded_world = worldspecs[i].path;
1068                                 found = true;
1069                                 break;
1070                         }
1071                 }
1072                 if(!found){
1073                         dstream<<_("World")<<" '"<<commanded_worldname<<_("' not "
1074                                         "available. Available worlds:")<<std::endl;
1075                         print_worldspecs(worldspecs, dstream);
1076                         return 1;
1077                 }
1078         }
1079
1080         // Gamespec
1081         SubgameSpec commanded_gamespec;
1082         if(cmd_args.exists("gameid")){
1083                 std::string gameid = cmd_args.get("gameid");
1084                 commanded_gamespec = findSubgame(gameid);
1085                 if(!commanded_gamespec.isValid()){
1086                         errorstream<<"Game \""<<gameid<<"\" not found"<<std::endl;
1087                         return 1;
1088                 }
1089         }
1090
1091
1092         /*
1093                 Run dedicated server if asked to or no other option
1094         */
1095 #ifdef SERVER
1096         bool run_dedicated_server = true;
1097 #else
1098         bool run_dedicated_server = cmd_args.getFlag("server");
1099 #endif
1100         g_settings->set("server_dedicated", run_dedicated_server ? "true" : "false");
1101         if(run_dedicated_server)
1102         {
1103                 DSTACK("Dedicated server branch");
1104                 // Create time getter if built with Irrlicht
1105 #ifndef SERVER
1106                 g_timegetter = new SimpleTimeGetter();
1107 #endif
1108
1109                 // World directory
1110                 std::string world_path;
1111                 verbosestream<<_("Determining world path")<<std::endl;
1112                 bool is_legacy_world = false;
1113                 // If a world was commanded, use it
1114                 if(commanded_world != ""){
1115                         world_path = commanded_world;
1116                         infostream<<"Using commanded world path ["<<world_path<<"]"
1117                                         <<std::endl;
1118                 }
1119                 // No world was specified; try to select it automatically
1120                 else
1121                 {
1122                         // Get information about available worlds
1123                         std::vector<WorldSpec> worldspecs = getAvailableWorlds();
1124                         // If a world name was specified, select it
1125                         if(commanded_worldname != ""){
1126                                 world_path = "";
1127                                 for(u32 i=0; i<worldspecs.size(); i++){
1128                                         std::string name = worldspecs[i].name;
1129                                         if(name == commanded_worldname){
1130                                                 world_path = worldspecs[i].path;
1131                                                 break;
1132                                         }
1133                                 }
1134                                 if(world_path == ""){
1135                                         dstream<<_("World")<<" '"<<commanded_worldname<<"' "<<_("not "
1136                                                         "available. Available worlds:")<<std::endl;
1137                                         print_worldspecs(worldspecs, dstream);
1138                                         return 1;
1139                                 }
1140                         }
1141                         // If there is only a single world, use it
1142                         if(worldspecs.size() == 1){
1143                                 world_path = worldspecs[0].path;
1144                                 dstream<<_("Automatically selecting world at")<<" ["
1145                                                 <<world_path<<"]"<<std::endl;
1146                         // If there are multiple worlds, list them
1147                         } else if(worldspecs.size() > 1){
1148                                 dstream<<_("Multiple worlds are available.")<<std::endl;
1149                                 dstream<<_("Please select one using --worldname <name>"
1150                                                 " or --world <path>")<<std::endl;
1151                                 print_worldspecs(worldspecs, dstream);
1152                                 return 1;
1153                         // If there are no worlds, automatically create a new one
1154                         } else {
1155                                 // This is the ultimate default world path
1156                                 world_path = porting::path_user + DIR_DELIM + "worlds" +
1157                                                 DIR_DELIM + "world";
1158                                 infostream<<"Creating default world at ["
1159                                                 <<world_path<<"]"<<std::endl;
1160                         }
1161                 }
1162
1163                 if(world_path == ""){
1164                         errorstream<<"No world path specified or found."<<std::endl;
1165                         return 1;
1166                 }
1167                 verbosestream<<_("Using world path")<<" ["<<world_path<<"]"<<std::endl;
1168
1169                 // We need a gamespec.
1170                 SubgameSpec gamespec;
1171                 verbosestream<<_("Determining gameid/gamespec")<<std::endl;
1172                 // If world doesn't exist
1173                 if(!getWorldExists(world_path))
1174                 {
1175                         // Try to take gamespec from command line
1176                         if(commanded_gamespec.isValid()){
1177                                 gamespec = commanded_gamespec;
1178                                 infostream<<"Using commanded gameid ["<<gamespec.id<<"]"<<std::endl;
1179                         }
1180                         // Otherwise we will be using "minetest"
1181                         else{
1182                                 gamespec = findSubgame(g_settings->get("default_game"));
1183                                 infostream<<"Using default gameid ["<<gamespec.id<<"]"<<std::endl;
1184                         }
1185                 }
1186                 // World exists
1187                 else
1188                 {
1189                         std::string world_gameid = getWorldGameId(world_path, is_legacy_world);
1190                         // If commanded to use a gameid, do so
1191                         if(commanded_gamespec.isValid()){
1192                                 gamespec = commanded_gamespec;
1193                                 if(commanded_gamespec.id != world_gameid){
1194                                         errorstream<<"WARNING: Using commanded gameid ["
1195                                                         <<gamespec.id<<"]"<<" instead of world gameid ["
1196                                                         <<world_gameid<<"]"<<std::endl;
1197                                 }
1198                         } else{
1199                                 // If world contains an embedded game, use it;
1200                                 // Otherwise find world from local system.
1201                                 gamespec = findWorldSubgame(world_path);
1202                                 infostream<<"Using world gameid ["<<gamespec.id<<"]"<<std::endl;
1203                         }
1204                 }
1205                 if(!gamespec.isValid()){
1206                         errorstream<<"Subgame ["<<gamespec.id<<"] could not be found."
1207                                         <<std::endl;
1208                         return 1;
1209                 }
1210                 verbosestream<<_("Using gameid")<<" ["<<gamespec.id<<"]"<<std::endl;
1211
1212                 // Create server
1213                 Server server(world_path, gamespec, false);
1214
1215                 // Database migration
1216                 if (cmd_args.exists("migrate")) {
1217                         std::string migrate_to = cmd_args.get("migrate");
1218                         Settings world_mt;
1219                         bool success = world_mt.readConfigFile((world_path + DIR_DELIM + "world.mt").c_str());
1220                         if (!success) {
1221                                 errorstream << "Cannot read world.mt" << std::endl;
1222                                 return 1;
1223                         }
1224                         if (!world_mt.exists("backend")) {
1225                                 errorstream << "Please specify your current backend in world.mt file:"
1226                                         << std::endl << "       backend = {sqlite3|leveldb|dummy}" << std::endl;
1227                                 return 1;
1228                         }
1229                         std::string backend = world_mt.get("backend");
1230                         Database *new_db;
1231                         if (backend == migrate_to) {
1232                                 errorstream << "Cannot migrate: new backend is same as the old one" << std::endl;
1233                                 return 1;
1234                         }
1235                         if (migrate_to == "sqlite3")
1236                                 new_db = new Database_SQLite3(&(ServerMap&)server.getMap(), world_path);
1237                         #if USE_LEVELDB
1238                         else if (migrate_to == "leveldb")
1239                                 new_db = new Database_LevelDB(&(ServerMap&)server.getMap(), world_path);
1240                         #endif
1241                         else {
1242                                 errorstream << "Migration to " << migrate_to << " is not supported" << std::endl;
1243                                 return 1;
1244                         }
1245
1246                         std::list<v3s16> blocks;
1247                         ServerMap &old_map = ((ServerMap&)server.getMap());
1248                         old_map.listAllLoadableBlocks(blocks);
1249                         int count = 0;
1250                         new_db->beginSave();
1251                         for (std::list<v3s16>::iterator i = blocks.begin(); i != blocks.end(); ++i) {
1252                                 MapBlock *block = old_map.loadBlock(*i);
1253                                 new_db->saveBlock(block);
1254                                 MapSector *sector = old_map.getSectorNoGenerate(v2s16(i->X, i->Z));
1255                                 sector->deleteBlock(block);
1256                                 ++count;
1257                                 if (count % 500 == 0)
1258                                         actionstream << "Migrated " << count << " blocks "
1259                                                 << (100.0 * count / blocks.size()) << "% completed" << std::endl;
1260                         }
1261                         new_db->endSave();
1262
1263                         actionstream << "Successfully migrated " << count << " blocks" << std::endl;
1264                         world_mt.set("backend", migrate_to);
1265                         if(!world_mt.updateConfigFile((world_path + DIR_DELIM + "world.mt").c_str()))
1266                                 errorstream<<"Failed to update world.mt!"<<std::endl;
1267                         else
1268                                 actionstream<<"world.mt updated"<<std::endl;
1269
1270                         return 0;
1271                 }
1272
1273                 server.start(port);
1274
1275                 // Run server
1276                 dedicated_server_loop(server, kill);
1277
1278                 return 0;
1279         }
1280
1281 #ifndef SERVER // Exclude from dedicated server build
1282
1283         /*
1284                 More parameters
1285         */
1286
1287         std::string address = g_settings->get("address");
1288         if(commanded_world != "")
1289                 address = "";
1290         else if(cmd_args.exists("address"))
1291                 address = cmd_args.get("address");
1292
1293         std::string playername = g_settings->get("name");
1294         if(cmd_args.exists("name"))
1295                 playername = cmd_args.get("name");
1296
1297         bool skip_main_menu = cmd_args.getFlag("go");
1298
1299         /*
1300                 Device initialization
1301         */
1302
1303         // Resolution selection
1304
1305         bool fullscreen = g_settings->getBool("fullscreen");
1306         u16 screenW = g_settings->getU16("screenW");
1307         u16 screenH = g_settings->getU16("screenH");
1308
1309         // bpp, fsaa, vsync
1310
1311         bool vsync = g_settings->getBool("vsync");
1312         u16 bits = g_settings->getU16("fullscreen_bpp");
1313         u16 fsaa = g_settings->getU16("fsaa");
1314
1315         // Determine driver
1316
1317         video::E_DRIVER_TYPE driverType;
1318
1319         std::string driverstring = g_settings->get("video_driver");
1320
1321         if(driverstring == "null")
1322                 driverType = video::EDT_NULL;
1323         else if(driverstring == "software")
1324                 driverType = video::EDT_SOFTWARE;
1325         else if(driverstring == "burningsvideo")
1326                 driverType = video::EDT_BURNINGSVIDEO;
1327         else if(driverstring == "direct3d8")
1328                 driverType = video::EDT_DIRECT3D8;
1329         else if(driverstring == "direct3d9")
1330                 driverType = video::EDT_DIRECT3D9;
1331         else if(driverstring == "opengl")
1332                 driverType = video::EDT_OPENGL;
1333 #ifdef _IRR_COMPILE_WITH_OGLES1_
1334         else if(driverstring == "ogles1")
1335                 driverType = video::EDT_OGLES1;
1336 #endif
1337 #ifdef _IRR_COMPILE_WITH_OGLES2_
1338         else if(driverstring == "ogles2")
1339                 driverType = video::EDT_OGLES2;
1340 #endif
1341         else
1342         {
1343                 errorstream<<"WARNING: Invalid video_driver specified; defaulting "
1344                                 "to opengl"<<std::endl;
1345                 driverType = video::EDT_OPENGL;
1346         }
1347
1348         /*
1349                 List video modes if requested
1350         */
1351
1352         MyEventReceiver receiver;
1353
1354         if(cmd_args.getFlag("videomodes")){
1355                 IrrlichtDevice *nulldevice;
1356
1357                 SIrrlichtCreationParameters params = SIrrlichtCreationParameters();
1358                 params.DriverType    = video::EDT_NULL;
1359                 params.WindowSize    = core::dimension2d<u32>(640, 480);
1360                 params.Bits          = 24;
1361                 params.AntiAlias     = fsaa;
1362                 params.Fullscreen    = false;
1363                 params.Stencilbuffer = false;
1364                 params.Vsync         = vsync;
1365                 params.EventReceiver = &receiver;
1366                 params.HighPrecisionFPU = g_settings->getBool("high_precision_fpu");
1367
1368                 nulldevice = createDeviceEx(params);
1369
1370                 if(nulldevice == 0)
1371                         return 1;
1372
1373                 dstream<<_("Available video modes (WxHxD):")<<std::endl;
1374
1375                 video::IVideoModeList *videomode_list =
1376                                 nulldevice->getVideoModeList();
1377
1378                 if(videomode_list == 0){
1379                         nulldevice->drop();
1380                         return 1;
1381                 }
1382
1383                 s32 videomode_count = videomode_list->getVideoModeCount();
1384                 core::dimension2d<u32> videomode_res;
1385                 s32 videomode_depth;
1386                 for (s32 i = 0; i < videomode_count; ++i){
1387                         videomode_res = videomode_list->getVideoModeResolution(i);
1388                         videomode_depth = videomode_list->getVideoModeDepth(i);
1389                         dstream<<videomode_res.Width<<"x"<<videomode_res.Height
1390                                         <<"x"<<videomode_depth<<std::endl;
1391                 }
1392
1393                 dstream<<_("Active video mode (WxHxD):")<<std::endl;
1394                 videomode_res = videomode_list->getDesktopResolution();
1395                 videomode_depth = videomode_list->getDesktopDepth();
1396                 dstream<<videomode_res.Width<<"x"<<videomode_res.Height
1397                                 <<"x"<<videomode_depth<<std::endl;
1398
1399                 nulldevice->drop();
1400
1401                 return 0;
1402         }
1403
1404         /*
1405                 Create device and exit if creation failed
1406         */
1407
1408         IrrlichtDevice *device;
1409
1410         SIrrlichtCreationParameters params = SIrrlichtCreationParameters();
1411         params.DriverType    = driverType;
1412         params.WindowSize    = core::dimension2d<u32>(screenW, screenH);
1413         params.Bits          = bits;
1414         params.AntiAlias     = fsaa;
1415         params.Fullscreen    = fullscreen;
1416         params.Stencilbuffer = false;
1417         params.Vsync         = vsync;
1418         params.EventReceiver = &receiver;
1419         params.HighPrecisionFPU = g_settings->getBool("high_precision_fpu");
1420
1421         device = createDeviceEx(params);
1422
1423         if (device == 0)
1424                 return 1; // could not create selected driver.
1425
1426         /*
1427                 Continue initialization
1428         */
1429
1430         video::IVideoDriver* driver = device->getVideoDriver();
1431
1432         /*
1433                 This changes the minimum allowed number of vertices in a VBO.
1434                 Default is 500.
1435         */
1436         //driver->setMinHardwareBufferVertexCount(50);
1437
1438         // Create time getter
1439         g_timegetter = new IrrlichtTimeGetter(device);
1440
1441         // Create game callback for menus
1442         g_gamecallback = new MainGameCallback(device);
1443
1444         /*
1445                 Speed tests (done after irrlicht is loaded to get timer)
1446         */
1447         if(cmd_args.getFlag("speedtests"))
1448         {
1449                 dstream<<"Running speed tests"<<std::endl;
1450                 SpeedTests();
1451                 device->drop();
1452                 return 0;
1453         }
1454
1455         device->setResizable(true);
1456
1457         bool random_input = g_settings->getBool("random_input")
1458                         || cmd_args.getFlag("random-input");
1459         InputHandler *input = NULL;
1460         if(random_input)
1461                 input = new RandomInputHandler();
1462         else
1463                 input = new RealInputHandler(device, &receiver);
1464
1465         scene::ISceneManager* smgr = device->getSceneManager();
1466
1467         guienv = device->getGUIEnvironment();
1468         gui::IGUISkin* skin = guienv->getSkin();
1469         std::string font_path = g_settings->get("font_path");
1470         gui::IGUIFont *font;
1471         #if USE_FREETYPE
1472         bool use_freetype = g_settings->getBool("freetype");
1473         if (use_freetype) {
1474                 std::string fallback;
1475                 if (is_yes(gettext("needs_fallback_font")))
1476                         fallback = "fallback_";
1477                 u16 font_size = g_settings->getU16(fallback + "font_size");
1478                 font_path = g_settings->get(fallback + "font_path");
1479                 u32 font_shadow = g_settings->getU16(fallback + "font_shadow");
1480                 font = gui::CGUITTFont::createTTFont(guienv, font_path.c_str(), font_size, true, true, font_shadow);
1481         } else {
1482                 font = guienv->getFont(font_path.c_str());
1483         }
1484         #else
1485         font = guienv->getFont(font_path.c_str());
1486         #endif
1487         if(font)
1488                 skin->setFont(font);
1489         else
1490                 errorstream<<"WARNING: Font file was not found."
1491                                 " Using default font."<<std::endl;
1492         // If font was not found, this will get us one
1493         font = skin->getFont();
1494         assert(font);
1495
1496         u32 text_height = font->getDimension(L"Hello, world!").Height;
1497         infostream<<"text_height="<<text_height<<std::endl;
1498
1499         //skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,0,0,0));
1500         skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,255,255,255));
1501         //skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(0,0,0,0));
1502         //skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(0,0,0,0));
1503         skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0));
1504         skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0));
1505         skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255,70,100,50));
1506         skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255,255,255,255));
1507
1508 #if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
1509         // Irrlicht 1.8 input colours
1510         skin->setColor(gui::EGDC_EDITABLE, video::SColor(255,128,128,128));
1511         skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255,96,134,49));
1512 #endif
1513
1514
1515         // Create the menu clouds
1516         if (!g_menucloudsmgr)
1517                 g_menucloudsmgr = smgr->createNewSceneManager();
1518         if (!g_menuclouds)
1519                 g_menuclouds = new Clouds(g_menucloudsmgr->getRootSceneNode(),
1520                         g_menucloudsmgr, -1, rand(), 100);
1521         g_menuclouds->update(v2f(0, 0), video::SColor(255,200,200,255));
1522         scene::ICameraSceneNode* camera;
1523         camera = g_menucloudsmgr->addCameraSceneNode(0,
1524                                 v3f(0,0,0), v3f(0, 60, 100));
1525         camera->setFarValue(10000);
1526
1527         /*
1528                 GUI stuff
1529         */
1530
1531         ChatBackend chat_backend;
1532
1533         /*
1534                 If an error occurs, this is set to something and the
1535                 menu-game loop is restarted. It is then displayed before
1536                 the menu.
1537         */
1538         std::wstring error_message = L"";
1539
1540         // The password entered during the menu screen,
1541         std::string password;
1542
1543         bool first_loop = true;
1544
1545         /*
1546                 Menu-game loop
1547         */
1548         while(device->run() && kill == false)
1549         {
1550                 // Set the window caption
1551                 wchar_t* text = wgettext("Main Menu");
1552                 device->setWindowCaption((std::wstring(L"Minetest [")+text+L"]").c_str());
1553                 delete[] text;
1554
1555                 // This is used for catching disconnects
1556                 try
1557                 {
1558
1559                         /*
1560                                 Clear everything from the GUIEnvironment
1561                         */
1562                         guienv->clear();
1563
1564                         /*
1565                                 We need some kind of a root node to be able to add
1566                                 custom gui elements directly on the screen.
1567                                 Otherwise they won't be automatically drawn.
1568                         */
1569                         guiroot = guienv->addStaticText(L"",
1570                                         core::rect<s32>(0, 0, 10000, 10000));
1571
1572                         SubgameSpec gamespec;
1573                         WorldSpec worldspec;
1574                         bool simple_singleplayer_mode = false;
1575
1576                         // These are set up based on the menu and other things
1577                         std::string current_playername = "inv£lid";
1578                         std::string current_password = "";
1579                         std::string current_address = "does-not-exist";
1580                         int current_port = 0;
1581
1582                         /*
1583                                 Out-of-game menu loop.
1584
1585                                 Loop quits when menu returns proper parameters.
1586                         */
1587                         while(kill == false)
1588                         {
1589                                 // If skip_main_menu, only go through here once
1590                                 if(skip_main_menu && !first_loop){
1591                                         kill = true;
1592                                         break;
1593                                 }
1594                                 first_loop = false;
1595
1596                                 // Cursor can be non-visible when coming from the game
1597                                 device->getCursorControl()->setVisible(true);
1598                                 // Some stuff are left to scene manager when coming from the game
1599                                 // (map at least?)
1600                                 smgr->clear();
1601
1602                                 // Initialize menu data
1603                                 MainMenuData menudata;
1604                                 menudata.address = address;
1605                                 menudata.name = playername;
1606                                 menudata.port = itos(port);
1607                                 menudata.errormessage = wide_to_narrow(error_message);
1608                                 error_message = L"";
1609                                 if(cmd_args.exists("password"))
1610                                         menudata.password = cmd_args.get("password");
1611
1612                                 driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
1613
1614                                 menudata.enable_public = g_settings->getBool("server_announce");
1615
1616                                 std::vector<WorldSpec> worldspecs = getAvailableWorlds();
1617
1618                                 // If a world was commanded, append and select it
1619                                 if(commanded_world != ""){
1620
1621                                         std::string gameid = getWorldGameId(commanded_world, true);
1622                                         std::string name = _("[--world parameter]");
1623                                         if(gameid == ""){
1624                                                 gameid = g_settings->get("default_game");
1625                                                 name += " [new]";
1626                                         }
1627                                         //TODO find within worldspecs and set config
1628                                 }
1629
1630                                 if(skip_main_menu == false)
1631                                 {
1632                                         video::IVideoDriver* driver = device->getVideoDriver();
1633
1634                                         infostream<<"Waiting for other menus"<<std::endl;
1635                                         while(device->run() && kill == false)
1636                                         {
1637                                                 if(noMenuActive())
1638                                                         break;
1639                                                 driver->beginScene(true, true,
1640                                                                 video::SColor(255,128,128,128));
1641                                                 guienv->drawAll();
1642                                                 driver->endScene();
1643                                                 // On some computers framerate doesn't seem to be
1644                                                 // automatically limited
1645                                                 sleep_ms(25);
1646                                         }
1647                                         infostream<<"Waited for other menus"<<std::endl;
1648
1649                                         GUIEngine* temp = new GUIEngine(device, guiroot, &g_menumgr,smgr,&menudata,kill);
1650
1651                                         delete temp;
1652                                         //once finished you'll never end up here
1653                                         smgr->clear();
1654                                 }
1655
1656                                 if(menudata.errormessage != ""){
1657                                         error_message = narrow_to_wide(menudata.errormessage);
1658                                         continue;
1659                                 }
1660
1661                                 //update worldspecs (necessary as new world may have been created)
1662                                 worldspecs = getAvailableWorlds();
1663
1664                                 if (menudata.name == "")
1665                                         menudata.name = std::string("Guest") + itos(myrand_range(1000,9999));
1666                                 else
1667                                         playername = menudata.name;
1668
1669                                 password = translatePassword(playername, narrow_to_wide(menudata.password));
1670                                 //infostream<<"Main: password hash: '"<<password<<"'"<<std::endl;
1671
1672                                 address = menudata.address;
1673                                 int newport = stoi(menudata.port);
1674                                 if(newport != 0)
1675                                         port = newport;
1676
1677                                 simple_singleplayer_mode = menudata.simple_singleplayer_mode;
1678
1679                                 // Save settings
1680                                 g_settings->set("name", playername);
1681
1682                                 if((menudata.selected_world >= 0) &&
1683                                                 (menudata.selected_world < (int)worldspecs.size()))
1684                                         g_settings->set("selected_world_path",
1685                                                         worldspecs[menudata.selected_world].path);
1686
1687                                 // Break out of menu-game loop to shut down cleanly
1688                                 if(device->run() == false || kill == true)
1689                                         break;
1690
1691                                 current_playername = playername;
1692                                 current_password = password;
1693                                 current_address = address;
1694                                 current_port = port;
1695
1696                                 // If using simple singleplayer mode, override
1697                                 if(simple_singleplayer_mode){
1698                                         current_playername = "singleplayer";
1699                                         current_password = "";
1700                                         current_address = "";
1701                                         current_port = myrand_range(49152, 65535);
1702                                 }
1703                                 else if (address != "")
1704                                 {
1705                                         ServerListSpec server;
1706                                         server["name"] = menudata.servername;
1707                                         server["address"] = menudata.address;
1708                                         server["port"] = menudata.port;
1709                                         server["description"] = menudata.serverdescription;
1710                                         ServerList::insert(server);
1711                                 }
1712
1713                                 // Set world path to selected one
1714                                 if ((menudata.selected_world >= 0) &&
1715                                         (menudata.selected_world < (int)worldspecs.size())) {
1716                                         worldspec = worldspecs[menudata.selected_world];
1717                                         infostream<<"Selected world: "<<worldspec.name
1718                                                         <<" ["<<worldspec.path<<"]"<<std::endl;
1719                                 }
1720
1721                                 // If local game
1722                                 if(current_address == "")
1723                                 {
1724                                         if(menudata.selected_world == -1){
1725                                                 error_message = wgettext("No world selected and no address "
1726                                                                 "provided. Nothing to do.");
1727                                                 errorstream<<wide_to_narrow(error_message)<<std::endl;
1728                                                 continue;
1729                                         }
1730                                         // Load gamespec for required game
1731                                         gamespec = findWorldSubgame(worldspec.path);
1732                                         if(!gamespec.isValid() && !commanded_gamespec.isValid()){
1733                                                 error_message = wgettext("Could not find or load game \"")
1734                                                                 + narrow_to_wide(worldspec.gameid) + L"\"";
1735                                                 errorstream<<wide_to_narrow(error_message)<<std::endl;
1736                                                 continue;
1737                                         }
1738                                         if(commanded_gamespec.isValid() &&
1739                                                         commanded_gamespec.id != worldspec.gameid){
1740                                                 errorstream<<"WARNING: Overriding gamespec from \""
1741                                                                 <<worldspec.gameid<<"\" to \""
1742                                                                 <<commanded_gamespec.id<<"\""<<std::endl;
1743                                                 gamespec = commanded_gamespec;
1744                                         }
1745
1746                                         if(!gamespec.isValid()){
1747                                                 error_message = wgettext("Invalid gamespec.");
1748                                                 error_message += L" (world_gameid="
1749                                                                 +narrow_to_wide(worldspec.gameid)+L")";
1750                                                 errorstream<<wide_to_narrow(error_message)<<std::endl;
1751                                                 continue;
1752                                         }
1753                                 }
1754
1755                                 // Continue to game
1756                                 break;
1757                         }
1758
1759                         // Break out of menu-game loop to shut down cleanly
1760                         if(device->run() == false || kill == true) {
1761                                 if(g_settings_path != "") {
1762                                         g_settings->updateConfigFile(
1763                                                 g_settings_path.c_str());
1764                                 }
1765                                 break;
1766                         }
1767
1768                         /*
1769                                 Run game
1770                         */
1771                         the_game(
1772                                 kill,
1773                                 random_input,
1774                                 input,
1775                                 device,
1776                                 font,
1777                                 worldspec.path,
1778                                 current_playername,
1779                                 current_password,
1780                                 current_address,
1781                                 current_port,
1782                                 error_message,
1783                                 chat_backend,
1784                                 gamespec,
1785                                 simple_singleplayer_mode
1786                         );
1787                         smgr->clear();
1788
1789                 } //try
1790                 catch(con::PeerNotFoundException &e)
1791                 {
1792                         error_message = wgettext("Connection error (timed out?)");
1793                         errorstream<<wide_to_narrow(error_message)<<std::endl;
1794                 }
1795 #ifdef NDEBUG
1796                 catch(std::exception &e)
1797                 {
1798                         std::string narrow_message = "Some exception: \"";
1799                         narrow_message += e.what();
1800                         narrow_message += "\"";
1801                         errorstream<<narrow_message<<std::endl;
1802                         error_message = narrow_to_wide(narrow_message);
1803                 }
1804 #endif
1805
1806                 // If no main menu, show error and exit
1807                 if(skip_main_menu)
1808                 {
1809                         if(error_message != L""){
1810                                 verbosestream<<"error_message = "
1811                                                 <<wide_to_narrow(error_message)<<std::endl;
1812                                 retval = 1;
1813                         }
1814                         break;
1815                 }
1816         } // Menu-game loop
1817
1818
1819         g_menuclouds->drop();
1820         g_menucloudsmgr->drop();
1821
1822         delete input;
1823
1824         /*
1825                 In the end, delete the Irrlicht device.
1826         */
1827         device->drop();
1828
1829 #if USE_FREETYPE
1830         if (use_freetype)
1831                 font->drop();
1832 #endif
1833
1834 #endif // !SERVER
1835
1836         // Update configuration file
1837         if(g_settings_path != "")
1838                 g_settings->updateConfigFile(g_settings_path.c_str());
1839
1840         // Print modified quicktune values
1841         {
1842                 bool header_printed = false;
1843                 std::vector<std::string> names = getQuicktuneNames();
1844                 for(u32 i=0; i<names.size(); i++){
1845                         QuicktuneValue val = getQuicktuneValue(names[i]);
1846                         if(!val.modified)
1847                                 continue;
1848                         if(!header_printed){
1849                                 dstream<<"Modified quicktune values:"<<std::endl;
1850                                 header_printed = true;
1851                         }
1852                         dstream<<names[i]<<" = "<<val.getString()<<std::endl;
1853                 }
1854         }
1855
1856         // Stop httpfetch thread (if started)
1857         httpfetch_cleanup();
1858
1859         END_DEBUG_EXCEPTION_HANDLER(errorstream)
1860
1861         debugstreams_deinit();
1862
1863         return retval;
1864 }
1865
1866 //END
1867