LCOV - code coverage report
Current view: top level - src - main.cpp (source / functions) Hit Total Coverage
Test: report Lines: 229 462 49.6 %
Date: 2015-07-11 18:23:49 Functions: 25 34 73.5 %

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

Generated by: LCOV version 1.11