Replace std::list by std::vector into ServerMap::listAllLoadableBlocks ServerMap...
[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 "irrlichttypes_extrabloated.h"
48 #include "debug.h"
49 #include "test.h"
50 #include "server.h"
51 #include "filesys.h"
52 #include "version.h"
53 #include "guiMainMenu.h"
54 #include "game.h"
55 #include "defaultsettings.h"
56 #include "gettext.h"
57 #include "profiler.h"
58 #include "log.h"
59 #include "quicktune.h"
60 #include "httpfetch.h"
61 #include "guiEngine.h"
62 #include "mapsector.h"
63 #include "fontengine.h"
64 #include "gameparams.h"
65 #ifndef SERVER
66 #include "client/clientlauncher.h"
67 #endif
68
69 #include "database-sqlite3.h"
70 #ifdef USE_LEVELDB
71 #include "database-leveldb.h"
72 #endif
73
74 #if USE_REDIS
75 #include "database-redis.h"
76 #endif
77
78 #ifdef HAVE_TOUCHSCREENGUI
79 #include "touchscreengui.h"
80 #endif
81
82 /*
83         Settings.
84         These are loaded from the config file.
85 */
86 static Settings main_settings;
87 Settings *g_settings = &main_settings;
88 std::string g_settings_path;
89
90 // Global profiler
91 Profiler main_profiler;
92 Profiler *g_profiler = &main_profiler;
93
94 // Menu clouds are created later
95 Clouds *g_menuclouds = 0;
96 irr::scene::ISceneManager *g_menucloudsmgr = 0;
97
98 /*
99         Debug streams
100 */
101
102 // Connection
103 std::ostream *dout_con_ptr = &dummyout;
104 std::ostream *derr_con_ptr = &verbosestream;
105
106 // Server
107 std::ostream *dout_server_ptr = &infostream;
108 std::ostream *derr_server_ptr = &errorstream;
109
110 // Client
111 std::ostream *dout_client_ptr = &infostream;
112 std::ostream *derr_client_ptr = &errorstream;
113
114 #define DEBUGFILE "debug.txt"
115 #define DEFAULT_SERVER_PORT 30000
116
117 typedef std::map<std::string, ValueSpec> OptionList;
118
119 /**********************************************************************
120  * Private functions
121  **********************************************************************/
122
123 static bool get_cmdline_opts(int argc, char *argv[], Settings *cmd_args);
124 static void set_allowed_options(OptionList *allowed_options);
125
126 static void print_help(const OptionList &allowed_options);
127 static void print_allowed_options(const OptionList &allowed_options);
128 static void print_version();
129 static void print_worldspecs(const std::vector<WorldSpec> &worldspecs,
130                                                          std::ostream &os);
131 static void print_modified_quicktune_values();
132
133 static void list_game_ids();
134 static void list_worlds();
135 static void setup_log_params(const Settings &cmd_args);
136 static bool create_userdata_path();
137 static bool init_common(int *log_level, const Settings &cmd_args, int argc, char *argv[]);
138 static void startup_message();
139 static bool read_config_file(const Settings &cmd_args);
140 static void init_debug_streams(int *log_level, const Settings &cmd_args);
141
142 static bool game_configure(GameParams *game_params, const Settings &cmd_args);
143 static void game_configure_port(GameParams *game_params, const Settings &cmd_args);
144
145 static bool game_configure_world(GameParams *game_params, const Settings &cmd_args);
146 static bool get_world_from_cmdline(GameParams *game_params, const Settings &cmd_args);
147 static bool get_world_from_config(GameParams *game_params, const Settings &cmd_args);
148 static bool auto_select_world(GameParams *game_params);
149 static std::string get_clean_world_path(const std::string &path);
150
151 static bool game_configure_subgame(GameParams *game_params, const Settings &cmd_args);
152 static bool get_game_from_cmdline(GameParams *game_params, const Settings &cmd_args);
153 static bool determine_subgame(GameParams *game_params);
154
155 static bool run_dedicated_server(const GameParams &game_params, const Settings &cmd_args);
156 static bool migrate_database(const GameParams &game_params, const Settings &cmd_args,
157                 Server *server);
158
159 /**********************************************************************/
160
161 #ifndef SERVER
162 /*
163         Random stuff
164 */
165
166 /* mainmenumanager.h */
167
168 gui::IGUIEnvironment* guienv = NULL;
169 gui::IGUIStaticText *guiroot = NULL;
170 MainMenuManager g_menumgr;
171
172 bool noMenuActive()
173 {
174         return (g_menumgr.menuCount() == 0);
175 }
176
177 // Passed to menus to allow disconnecting and exiting
178 MainGameCallback *g_gamecallback = NULL;
179 #endif
180
181 /*
182         gettime.h implementation
183 */
184
185 #ifdef SERVER
186
187 u32 getTimeMs()
188 {
189         /* Use imprecise system calls directly (from porting.h) */
190         return porting::getTime(PRECISION_MILLI);
191 }
192
193 u32 getTime(TimePrecision prec)
194 {
195         return porting::getTime(prec);
196 }
197
198 #endif
199
200 class StderrLogOutput: public ILogOutput
201 {
202 public:
203         /* line: Full line with timestamp, level and thread */
204         void printLog(const std::string &line)
205         {
206                 std::cerr << line << std::endl;
207         }
208 } main_stderr_log_out;
209
210 class DstreamNoStderrLogOutput: public ILogOutput
211 {
212 public:
213         /* line: Full line with timestamp, level and thread */
214         void printLog(const std::string &line)
215         {
216                 dstream_no_stderr << line << std::endl;
217         }
218 } main_dstream_no_stderr_log_out;
219
220 static OptionList allowed_options;
221
222 int main(int argc, char *argv[])
223 {
224         int retval;
225
226         debug_set_exception_handler();
227
228         log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION);
229         log_add_output_all_levs(&main_dstream_no_stderr_log_out);
230
231         log_register_thread("main");
232
233         Settings cmd_args;
234         bool cmd_args_ok = get_cmdline_opts(argc, argv, &cmd_args);
235         if (!cmd_args_ok
236                         || cmd_args.getFlag("help")
237                         || cmd_args.exists("nonopt1")) {
238                 print_help(allowed_options);
239                 return cmd_args_ok ? 0 : 1;
240         }
241
242         if (cmd_args.getFlag("version")) {
243                 print_version();
244                 return 0;
245         }
246
247         setup_log_params(cmd_args);
248
249         porting::signal_handler_init();
250         porting::initializePaths();
251
252         if (!create_userdata_path()) {
253                 errorstream << "Cannot create user data directory" << std::endl;
254                 return 1;
255         }
256
257         // Initialize debug stacks
258         debug_stacks_init();
259         DSTACK(__FUNCTION_NAME);
260
261         // Debug handler
262         BEGIN_DEBUG_EXCEPTION_HANDLER
263
264         // List gameids if requested
265         if (cmd_args.exists("gameid") && cmd_args.get("gameid") == "list") {
266                 list_game_ids();
267                 return 0;
268         }
269
270         // List worlds if requested
271         if (cmd_args.exists("world") && cmd_args.get("world") == "list") {
272                 list_worlds();
273                 return 0;
274         }
275
276         GameParams game_params;
277         if (!init_common(&game_params.log_level, cmd_args, argc, argv))
278                 return 1;
279
280 #ifndef __ANDROID__
281         // Run unit tests
282         if ((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)
283                         || cmd_args.getFlag("enable-unittests") == true) {
284                 run_tests();
285         }
286 #endif
287
288 #ifdef SERVER
289         game_params.is_dedicated_server = true;
290 #else
291         game_params.is_dedicated_server = cmd_args.getFlag("server");
292 #endif
293
294         if (!game_configure(&game_params, cmd_args))
295                 return 1;
296
297         assert(game_params.world_path != "");
298
299         infostream << "Using commanded world path ["
300                    << game_params.world_path << "]" << std::endl;
301
302         //Run dedicated server if asked to or no other option
303         g_settings->set("server_dedicated",
304                         game_params.is_dedicated_server ? "true" : "false");
305
306         if (game_params.is_dedicated_server)
307                 return run_dedicated_server(game_params, cmd_args) ? 0 : 1;
308
309 #ifndef SERVER
310         ClientLauncher launcher;
311         retval = launcher.run(game_params, cmd_args) ? 0 : 1;
312 #else
313         retval = 0;
314 #endif
315
316         // Update configuration file
317         if (g_settings_path != "")
318                 g_settings->updateConfigFile(g_settings_path.c_str());
319
320         print_modified_quicktune_values();
321
322         // Stop httpfetch thread (if started)
323         httpfetch_cleanup();
324
325         END_DEBUG_EXCEPTION_HANDLER(errorstream)
326
327         return retval;
328 }
329
330
331 /*****************************************************************************
332  * Startup / Init
333  *****************************************************************************/
334
335
336 static bool get_cmdline_opts(int argc, char *argv[], Settings *cmd_args)
337 {
338         set_allowed_options(&allowed_options);
339
340         return cmd_args->parseCommandLine(argc, argv, allowed_options);
341 }
342
343 static void set_allowed_options(OptionList *allowed_options)
344 {
345         allowed_options->clear();
346
347         allowed_options->insert(std::make_pair("help", ValueSpec(VALUETYPE_FLAG,
348                         _("Show allowed options"))));
349         allowed_options->insert(std::make_pair("version", ValueSpec(VALUETYPE_FLAG,
350                         _("Show version information"))));
351         allowed_options->insert(std::make_pair("config", ValueSpec(VALUETYPE_STRING,
352                         _("Load configuration from specified file"))));
353         allowed_options->insert(std::make_pair("port", ValueSpec(VALUETYPE_STRING,
354                         _("Set network port (UDP)"))));
355         allowed_options->insert(std::make_pair("disable-unittests", ValueSpec(VALUETYPE_FLAG,
356                         _("Disable unit tests"))));
357         allowed_options->insert(std::make_pair("enable-unittests", ValueSpec(VALUETYPE_FLAG,
358                         _("Enable unit tests"))));
359         allowed_options->insert(std::make_pair("map-dir", ValueSpec(VALUETYPE_STRING,
360                         _("Same as --world (deprecated)"))));
361         allowed_options->insert(std::make_pair("world", ValueSpec(VALUETYPE_STRING,
362                         _("Set world path (implies local game) ('list' lists all)"))));
363         allowed_options->insert(std::make_pair("worldname", ValueSpec(VALUETYPE_STRING,
364                         _("Set world by name (implies local game)"))));
365         allowed_options->insert(std::make_pair("quiet", ValueSpec(VALUETYPE_FLAG,
366                         _("Print to console errors only"))));
367         allowed_options->insert(std::make_pair("info", ValueSpec(VALUETYPE_FLAG,
368                         _("Print more information to console"))));
369         allowed_options->insert(std::make_pair("verbose",  ValueSpec(VALUETYPE_FLAG,
370                         _("Print even more information to console"))));
371         allowed_options->insert(std::make_pair("trace", ValueSpec(VALUETYPE_FLAG,
372                         _("Print enormous amounts of information to log and console"))));
373         allowed_options->insert(std::make_pair("logfile", ValueSpec(VALUETYPE_STRING,
374                         _("Set logfile path ('' = no logging)"))));
375         allowed_options->insert(std::make_pair("gameid", ValueSpec(VALUETYPE_STRING,
376                         _("Set gameid (\"--gameid list\" prints available ones)"))));
377         allowed_options->insert(std::make_pair("migrate", ValueSpec(VALUETYPE_STRING,
378                         _("Migrate from current map backend to another (Only works when using minetestserver or with --server)"))));
379 #ifndef SERVER
380         allowed_options->insert(std::make_pair("videomodes", ValueSpec(VALUETYPE_FLAG,
381                         _("Show available video modes"))));
382         allowed_options->insert(std::make_pair("speedtests", ValueSpec(VALUETYPE_FLAG,
383                         _("Run speed tests"))));
384         allowed_options->insert(std::make_pair("address", ValueSpec(VALUETYPE_STRING,
385                         _("Address to connect to. ('' = local game)"))));
386         allowed_options->insert(std::make_pair("random-input", ValueSpec(VALUETYPE_FLAG,
387                         _("Enable random user input, for testing"))));
388         allowed_options->insert(std::make_pair("server", ValueSpec(VALUETYPE_FLAG,
389                         _("Run dedicated server"))));
390         allowed_options->insert(std::make_pair("name", ValueSpec(VALUETYPE_STRING,
391                         _("Set player name"))));
392         allowed_options->insert(std::make_pair("password", ValueSpec(VALUETYPE_STRING,
393                         _("Set password"))));
394         allowed_options->insert(std::make_pair("go", ValueSpec(VALUETYPE_FLAG,
395                         _("Disable main menu"))));
396 #endif
397
398 }
399
400 static void print_help(const OptionList &allowed_options)
401 {
402         dstream << _("Allowed options:") << std::endl;
403         print_allowed_options(allowed_options);
404 }
405
406 static void print_allowed_options(const OptionList &allowed_options)
407 {
408         for (OptionList::const_iterator i = allowed_options.begin();
409                         i != allowed_options.end(); ++i) {
410                 std::ostringstream os1(std::ios::binary);
411                 os1 << "  --" << i->first;
412                 if (i->second.type != VALUETYPE_FLAG)
413                         os1 << _(" <value>");
414
415                 dstream << padStringRight(os1.str(), 24);
416
417                 if (i->second.help != NULL)
418                         dstream << i->second.help;
419
420                 dstream << std::endl;
421         }
422 }
423
424 static void print_version()
425 {
426 #ifdef SERVER
427         dstream << "minetestserver " << minetest_version_hash << std::endl;
428 #else
429         dstream << "Minetest " << minetest_version_hash << std::endl;
430         dstream << "Using Irrlicht " << IRRLICHT_SDK_VERSION << std::endl;
431 #endif
432         dstream << "Build info: " << minetest_build_info << std::endl;
433 }
434
435 static void list_game_ids()
436 {
437         std::set<std::string> gameids = getAvailableGameIds();
438         for (std::set<std::string>::const_iterator i = gameids.begin();
439                         i != gameids.end(); i++)
440                 dstream << (*i) <<std::endl;
441 }
442
443 static void list_worlds()
444 {
445         dstream << _("Available worlds:") << std::endl;
446         std::vector<WorldSpec> worldspecs = getAvailableWorlds();
447         print_worldspecs(worldspecs, dstream);
448 }
449
450 static void print_worldspecs(const std::vector<WorldSpec> &worldspecs,
451                                                          std::ostream &os)
452 {
453         for (size_t i = 0; i < worldspecs.size(); i++) {
454                 std::string name = worldspecs[i].name;
455                 std::string path = worldspecs[i].path;
456                 if (name.find(" ") != std::string::npos)
457                         name = std::string("'") + name + "'";
458                 path = std::string("'") + path + "'";
459                 name = padStringRight(name, 14);
460                 os << "  " << name << " " << path << std::endl;
461         }
462 }
463
464 static void print_modified_quicktune_values()
465 {
466         bool header_printed = false;
467         std::vector<std::string> names = getQuicktuneNames();
468
469         for (u32 i = 0; i < names.size(); i++) {
470                 QuicktuneValue val = getQuicktuneValue(names[i]);
471                 if (!val.modified)
472                         continue;
473                 if (!header_printed) {
474                         dstream << "Modified quicktune values:" << std::endl;
475                         header_printed = true;
476                 }
477                 dstream << names[i] << " = " << val.getString() << std::endl;
478         }
479 }
480
481 static void setup_log_params(const Settings &cmd_args)
482 {
483         // Quiet mode, print errors only
484         if (cmd_args.getFlag("quiet")) {
485                 log_remove_output(&main_stderr_log_out);
486                 log_add_output_maxlev(&main_stderr_log_out, LMT_ERROR);
487         }
488
489         // If trace is enabled, enable logging of certain things
490         if (cmd_args.getFlag("trace")) {
491                 dstream << _("Enabling trace level debug output") << std::endl;
492                 log_trace_level_enabled = true;
493                 dout_con_ptr = &verbosestream; // this is somewhat old crap
494                 socket_enable_debug_output = true; // socket doesn't use log.h
495         }
496
497         // In certain cases, output info level on stderr
498         if (cmd_args.getFlag("info") || cmd_args.getFlag("verbose") ||
499                         cmd_args.getFlag("trace") || cmd_args.getFlag("speedtests"))
500                 log_add_output(&main_stderr_log_out, LMT_INFO);
501
502         // In certain cases, output verbose level on stderr
503         if (cmd_args.getFlag("verbose") || cmd_args.getFlag("trace"))
504                 log_add_output(&main_stderr_log_out, LMT_VERBOSE);
505 }
506
507 static bool create_userdata_path()
508 {
509         bool success;
510
511 #ifdef __ANDROID__
512         porting::initAndroid();
513
514         porting::setExternalStorageDir(porting::jnienv);
515         if (!fs::PathExists(porting::path_user)) {
516                 success = fs::CreateDir(porting::path_user);
517         } else {
518                 success = true;
519         }
520         porting::copyAssets();
521 #else
522         // Create user data directory
523         success = fs::CreateDir(porting::path_user);
524 #endif
525
526         infostream << "path_share = " << porting::path_share << std::endl;
527         infostream << "path_user  = " << porting::path_user << std::endl;
528
529         return success;
530 }
531
532 static bool init_common(int *log_level, const Settings &cmd_args, int argc, char *argv[])
533 {
534         startup_message();
535         set_default_settings(g_settings);
536
537         // Initialize sockets
538         sockets_init();
539         atexit(sockets_cleanup);
540
541         if (!read_config_file(cmd_args))
542                 return false;
543
544         init_debug_streams(log_level, cmd_args);
545
546         // Initialize random seed
547         srand(time(0));
548         mysrand(time(0));
549
550         // Initialize HTTP fetcher
551         httpfetch_init(g_settings->getS32("curl_parallel_limit"));
552
553 #ifdef _MSC_VER
554         init_gettext((porting::path_share + DIR_DELIM + "locale").c_str(),
555                 g_settings->get("language"), argc, argv);
556 #else
557         init_gettext((porting::path_share + DIR_DELIM + "locale").c_str(),
558                 g_settings->get("language"));
559 #endif
560
561         return true;
562 }
563
564 static void startup_message()
565 {
566         infostream << PROJECT_NAME << " " << _("with")
567                    << " SER_FMT_VER_HIGHEST_READ="
568                << (int)SER_FMT_VER_HIGHEST_READ << ", "
569                << minetest_build_info << std::endl;
570 }
571
572 static bool read_config_file(const Settings &cmd_args)
573 {
574         // Path of configuration file in use
575         assert(g_settings_path == "");  // Sanity check
576
577         if (cmd_args.exists("config")) {
578                 bool r = g_settings->readConfigFile(cmd_args.get("config").c_str());
579                 if (!r) {
580                         errorstream << "Could not read configuration from \""
581                                     << cmd_args.get("config") << "\"" << std::endl;
582                         return false;
583                 }
584                 g_settings_path = cmd_args.get("config");
585         } else {
586                 std::vector<std::string> filenames;
587                 filenames.push_back(porting::path_user + DIR_DELIM + "minetest.conf");
588                 // Legacy configuration file location
589                 filenames.push_back(porting::path_user +
590                                 DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
591
592 #if RUN_IN_PLACE
593                 // Try also from a lower level (to aid having the same configuration
594                 // for many RUN_IN_PLACE installs)
595                 filenames.push_back(porting::path_user +
596                                 DIR_DELIM + ".." + DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
597 #endif
598
599                 for (size_t i = 0; i < filenames.size(); i++) {
600                         bool r = g_settings->readConfigFile(filenames[i].c_str());
601                         if (r) {
602                                 g_settings_path = filenames[i];
603                                 break;
604                         }
605                 }
606
607                 // If no path found, use the first one (menu creates the file)
608                 if (g_settings_path == "")
609                         g_settings_path = filenames[0];
610         }
611
612         return true;
613 }
614
615 static void init_debug_streams(int *log_level, const Settings &cmd_args)
616 {
617 #if RUN_IN_PLACE
618         std::string logfile = DEBUGFILE;
619 #else
620         std::string logfile = porting::path_user + DIR_DELIM + DEBUGFILE;
621 #endif
622         if (cmd_args.exists("logfile"))
623                 logfile = cmd_args.get("logfile");
624
625         log_remove_output(&main_dstream_no_stderr_log_out);
626         *log_level = g_settings->getS32("debug_log_level");
627
628         if (*log_level == 0) //no logging
629                 logfile = "";
630         if (*log_level < 0) {
631                 dstream << "WARNING: Supplied debug_log_level < 0; Using 0" << std::endl;
632                 *log_level = 0;
633         } else if (*log_level > LMT_NUM_VALUES) {
634                 dstream << "WARNING: Supplied debug_log_level > " << LMT_NUM_VALUES
635                         << "; Using " << LMT_NUM_VALUES << std::endl;
636                 *log_level = LMT_NUM_VALUES;
637         }
638
639         log_add_output_maxlev(&main_dstream_no_stderr_log_out,
640                         (LogMessageLevel)(*log_level - 1));
641
642         debugstreams_init(false, logfile == "" ? NULL : logfile.c_str());
643
644         infostream << "logfile = " << logfile << std::endl;
645
646         atexit(debugstreams_deinit);
647 }
648
649 static bool game_configure(GameParams *game_params, const Settings &cmd_args)
650 {
651         game_configure_port(game_params, cmd_args);
652
653         if (!game_configure_world(game_params, cmd_args)) {
654                 errorstream << "No world path specified or found." << std::endl;
655                 return false;
656         }
657
658         game_configure_subgame(game_params, cmd_args);
659
660         return true;
661 }
662
663 static void game_configure_port(GameParams *game_params, const Settings &cmd_args)
664 {
665         if (cmd_args.exists("port"))
666                 game_params->socket_port = cmd_args.getU16("port");
667         else
668                 game_params->socket_port = g_settings->getU16("port");
669
670         if (game_params->socket_port == 0)
671                 game_params->socket_port = DEFAULT_SERVER_PORT;
672 }
673
674 static bool game_configure_world(GameParams *game_params, const Settings &cmd_args)
675 {
676         if (get_world_from_cmdline(game_params, cmd_args))
677                 return true;
678         if (get_world_from_config(game_params, cmd_args))
679                 return true;
680
681         return auto_select_world(game_params);
682 }
683
684 static bool get_world_from_cmdline(GameParams *game_params, const Settings &cmd_args)
685 {
686         std::string commanded_world = "";
687
688         // World name
689         std::string commanded_worldname = "";
690         if (cmd_args.exists("worldname"))
691                 commanded_worldname = cmd_args.get("worldname");
692
693         // If a world name was specified, convert it to a path
694         if (commanded_worldname != "") {
695                 // Get information about available worlds
696                 std::vector<WorldSpec> worldspecs = getAvailableWorlds();
697                 bool found = false;
698                 for (u32 i = 0; i < worldspecs.size(); i++) {
699                         std::string name = worldspecs[i].name;
700                         if (name == commanded_worldname) {
701                                 dstream << _("Using world specified by --worldname on the "
702                                         "command line") << std::endl;
703                                 commanded_world = worldspecs[i].path;
704                                 found = true;
705                                 break;
706                         }
707                 }
708                 if (!found) {
709                         dstream << _("World") << " '" << commanded_worldname
710                                 << _("' not available. Available worlds:") << std::endl;
711                         print_worldspecs(worldspecs, dstream);
712                         return false;
713                 }
714
715                 game_params->world_path = get_clean_world_path(commanded_world);
716                 return commanded_world != "";
717         }
718
719         if (cmd_args.exists("world"))
720                 commanded_world = cmd_args.get("world");
721         else if (cmd_args.exists("map-dir"))
722                 commanded_world = cmd_args.get("map-dir");
723         else if (cmd_args.exists("nonopt0")) // First nameless argument
724                 commanded_world = cmd_args.get("nonopt0");
725
726         game_params->world_path = get_clean_world_path(commanded_world);
727         return commanded_world != "";
728 }
729
730 static bool get_world_from_config(GameParams *game_params, const Settings &cmd_args)
731 {
732         // World directory
733         std::string commanded_world = "";
734
735         if (g_settings->exists("map-dir"))
736                 commanded_world = g_settings->get("map-dir");
737
738         game_params->world_path = get_clean_world_path(commanded_world);
739
740         return commanded_world != "";
741 }
742
743 static bool auto_select_world(GameParams *game_params)
744 {
745         // No world was specified; try to select it automatically
746         // Get information about available worlds
747
748         verbosestream << _("Determining world path") << std::endl;
749
750         std::vector<WorldSpec> worldspecs = getAvailableWorlds();
751         std::string world_path;
752
753         // If there is only a single world, use it
754         if (worldspecs.size() == 1) {
755                 world_path = worldspecs[0].path;
756                 dstream <<_("Automatically selecting world at") << " ["
757                         << world_path << "]" << std::endl;
758         // If there are multiple worlds, list them
759         } else if (worldspecs.size() > 1 && game_params->is_dedicated_server) {
760                 dstream << _("Multiple worlds are available.") << std::endl;
761                 dstream << _("Please select one using --worldname <name>"
762                                 " or --world <path>") << std::endl;
763                 print_worldspecs(worldspecs, dstream);
764                 return false;
765         // If there are no worlds, automatically create a new one
766         } else {
767                 // This is the ultimate default world path
768                 world_path = porting::path_user + DIR_DELIM + "worlds" +
769                                 DIR_DELIM + "world";
770                 infostream << "Creating default world at ["
771                            << world_path << "]" << std::endl;
772         }
773
774         assert(world_path != "");
775         game_params->world_path = world_path;
776         return true;
777 }
778
779 static std::string get_clean_world_path(const std::string &path)
780 {
781         const std::string worldmt = "world.mt";
782         std::string clean_path;
783
784         if (path.size() > worldmt.size()
785                         && path.substr(path.size() - worldmt.size()) == worldmt) {
786                 dstream << _("Supplied world.mt file - stripping it off.") << std::endl;
787                 clean_path = path.substr(0, path.size() - worldmt.size());
788         } else {
789                 clean_path = path;
790         }
791         return path;
792 }
793
794
795 static bool game_configure_subgame(GameParams *game_params, const Settings &cmd_args)
796 {
797         bool success;
798
799         success = get_game_from_cmdline(game_params, cmd_args);
800         if (!success)
801                 success = determine_subgame(game_params);
802
803         return success;
804 }
805
806 static bool get_game_from_cmdline(GameParams *game_params, const Settings &cmd_args)
807 {
808         SubgameSpec commanded_gamespec;
809
810         if (cmd_args.exists("gameid")) {
811                 std::string gameid = cmd_args.get("gameid");
812                 commanded_gamespec = findSubgame(gameid);
813                 if (!commanded_gamespec.isValid()) {
814                         errorstream << "Game \"" << gameid << "\" not found" << std::endl;
815                         return false;
816                 }
817                 dstream << _("Using game specified by --gameid on the command line")
818                         << std::endl;
819                 game_params->game_spec = commanded_gamespec;
820                 return true;
821         }
822
823         return false;
824 }
825
826 static bool determine_subgame(GameParams *game_params)
827 {
828         SubgameSpec gamespec;
829
830         assert(game_params->world_path != "");  // pre-condition
831
832         verbosestream << _("Determining gameid/gamespec") << std::endl;
833         // If world doesn't exist
834         if (game_params->world_path != ""
835                         && !getWorldExists(game_params->world_path)) {
836                 // Try to take gamespec from command line
837                 if (game_params->game_spec.isValid()) {
838                         gamespec = game_params->game_spec;
839                         infostream << "Using commanded gameid [" << gamespec.id << "]" << std::endl;
840                 } else { // Otherwise we will be using "minetest"
841                         gamespec = findSubgame(g_settings->get("default_game"));
842                         infostream << "Using default gameid [" << gamespec.id << "]" << std::endl;
843                         if (!gamespec.isValid()) {
844                                 errorstream << "Subgame specified in default_game ["
845                                             << g_settings->get("default_game")
846                                             << "] is invalid." << std::endl;
847                                 return false;
848                         }
849                 }
850         } else { // World exists
851                 std::string world_gameid = getWorldGameId(game_params->world_path, false);
852                 // If commanded to use a gameid, do so
853                 if (game_params->game_spec.isValid()) {
854                         gamespec = game_params->game_spec;
855                         if (game_params->game_spec.id != world_gameid) {
856                                 errorstream << "WARNING: Using commanded gameid ["
857                                             << gamespec.id << "]" << " instead of world gameid ["
858                                             << world_gameid << "]" << std::endl;
859                         }
860                 } else {
861                         // If world contains an embedded game, use it;
862                         // Otherwise find world from local system.
863                         gamespec = findWorldSubgame(game_params->world_path);
864                         infostream << "Using world gameid [" << gamespec.id << "]" << std::endl;
865                 }
866         }
867
868         if (!gamespec.isValid()) {
869                 errorstream << "Subgame [" << gamespec.id << "] could not be found."
870                             << std::endl;
871                 return false;
872         }
873
874         game_params->game_spec = gamespec;
875         return true;
876 }
877
878
879 /*****************************************************************************
880  * Dedicated server
881  *****************************************************************************/
882 static bool run_dedicated_server(const GameParams &game_params, const Settings &cmd_args)
883 {
884         DSTACK("Dedicated server branch");
885
886         verbosestream << _("Using world path") << " ["
887                       << game_params.world_path << "]" << std::endl;
888         verbosestream << _("Using gameid") << " ["
889                       << game_params.game_spec.id << "]" << std::endl;
890
891         // Bind address
892         std::string bind_str = g_settings->get("bind_address");
893         Address bind_addr(0, 0, 0, 0, game_params.socket_port);
894
895         if (g_settings->getBool("ipv6_server")) {
896                 bind_addr.setAddress((IPv6AddressBytes*) NULL);
897         }
898         try {
899                 bind_addr.Resolve(bind_str.c_str());
900         } catch (ResolveError &e) {
901                 infostream << "Resolving bind address \"" << bind_str
902                            << "\" failed: " << e.what()
903                            << " -- Listening on all addresses." << std::endl;
904         }
905         if (bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) {
906                 errorstream << "Unable to listen on "
907                             << bind_addr.serializeString()
908                             << L" because IPv6 is disabled" << std::endl;
909                 return false;
910         }
911
912         // Create server
913         Server server(game_params.world_path,
914                         game_params.game_spec, false, bind_addr.isIPv6());
915
916         // Database migration
917         if (cmd_args.exists("migrate"))
918                 return migrate_database(game_params, cmd_args, &server);
919
920         server.start(bind_addr);
921
922         // Run server
923         bool &kill = *porting::signal_handler_killstatus();
924         dedicated_server_loop(server, kill);
925
926         return true;
927 }
928
929 static bool migrate_database(const GameParams &game_params, const Settings &cmd_args,
930                 Server *server)
931 {
932         Settings world_mt;
933         bool success = world_mt.readConfigFile((game_params.world_path
934                         + DIR_DELIM + "world.mt").c_str());
935         if (!success) {
936                 errorstream << "Cannot read world.mt" << std::endl;
937                 return false;
938         }
939
940         if (!world_mt.exists("backend")) {
941                 errorstream << "Please specify your current backend in world.mt file:"
942                             << std::endl << "   backend = {sqlite3|leveldb|redis|dummy}"
943                             << std::endl;
944                 return false;
945         }
946
947         std::string backend = world_mt.get("backend");
948         Database *new_db;
949         std::string migrate_to = cmd_args.get("migrate");
950
951         if (backend == migrate_to) {
952                 errorstream << "Cannot migrate: new backend is same as the old one"
953                             << std::endl;
954                 return false;
955         }
956
957         if (migrate_to == "sqlite3")
958                 new_db = new Database_SQLite3(&(ServerMap&)server->getMap(),
959                                 game_params.world_path);
960 #if USE_LEVELDB
961         else if (migrate_to == "leveldb")
962                 new_db = new Database_LevelDB(&(ServerMap&)server->getMap(),
963                                 game_params.world_path);
964 #endif
965 #if USE_REDIS
966         else if (migrate_to == "redis")
967                 new_db = new Database_Redis(&(ServerMap&)server->getMap(),
968                                 game_params.world_path);
969 #endif
970         else {
971                 errorstream << "Migration to " << migrate_to << " is not supported"
972                             << std::endl;
973                 return false;
974         }
975
976         std::vector<v3s16> blocks;
977         ServerMap &old_map = ((ServerMap&)server->getMap());
978         old_map.listAllLoadableBlocks(blocks);
979         int count = 0;
980         new_db->beginSave();
981         for (std::vector<v3s16>::iterator i = blocks.begin(); i != blocks.end(); i++) {
982                 MapBlock *block = old_map.loadBlock(*i);
983                 if (!block) {
984                         errorstream << "Failed to load block " << PP(*i) << ", skipping it.";
985                 }
986                 else {
987                         old_map.saveBlock(block, new_db);
988                         MapSector *sector = old_map.getSectorNoGenerate(v2s16(i->X, i->Z));
989                         sector->deleteBlock(block);
990                 }
991                 ++count;
992                 if (count % 500 == 0)
993                    actionstream << "Migrated " << count << " blocks "
994                            << (100.0 * count / blocks.size()) << "% completed" << std::endl;
995         }
996         new_db->endSave();
997         delete new_db;
998
999         actionstream << "Successfully migrated " << count << " blocks" << std::endl;
1000         world_mt.set("backend", migrate_to);
1001         if (!world_mt.updateConfigFile(
1002                                 (game_params.world_path+ DIR_DELIM + "world.mt").c_str()))
1003                 errorstream << "Failed to update world.mt!" << std::endl;
1004         else
1005                 actionstream << "world.mt updated" << std::endl;
1006
1007         return true;
1008 }