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