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