X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmain.cpp;h=e9b320af79d1db391faba7f89090d8b88c45c279;hb=d82d18bfb1a51e0f2f0a89999474e98890addf7e;hp=303004f0c6baf7cd8cb330ca768fcc7c147452fa;hpb=c42753338924bb29c61081c9f269772f89bcd808;p=minetest.git diff --git a/src/main.cpp b/src/main.cpp index 303004f0c..e9b320af7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,55 +17,77 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "irrlichttypes.h" // must be included before anything irrlicht, see comment in the file #include "irrlicht.h" // createDevice - -#include "mainmenumanager.h" #include "irrlichttypes_extrabloated.h" +#include "benchmark/benchmark.h" #include "chat_interface.h" #include "debug.h" #include "unittest/test.h" #include "server.h" #include "filesys.h" #include "version.h" -#include "guiMainMenu.h" -#include "game.h" +#include "client/game.h" #include "defaultsettings.h" #include "gettext.h" #include "log.h" -#include "quicktune.h" +#include "util/quicktune.h" #include "httpfetch.h" -#include "guiEngine.h" #include "gameparams.h" -#include "database.h" +#include "database/database.h" #include "config.h" +#include "player.h" #include "porting.h" +#include "network/socket.h" +#include "mapblock.h" #if USE_CURSES #include "terminal_chat_console.h" #endif #ifndef SERVER +#include "gui/guiMainMenu.h" #include "client/clientlauncher.h" +#include "gui/guiEngine.h" +#include "gui/mainmenumanager.h" #endif - #ifdef HAVE_TOUCHSCREENGUI - #include "touchscreengui.h" + #include "gui/touchscreengui.h" #endif -#if !defined(SERVER) && \ - (IRRLICHT_VERSION_MAJOR == 1) && \ - (IRRLICHT_VERSION_MINOR == 8) && \ - (IRRLICHT_VERSION_REVISION == 2) - #error "Irrlicht 1.8.2 is known to be broken - please update Irrlicht to version >= 1.8.3" +// for version information only +extern "C" { +#if USE_LUAJIT + #include +#else + #include +#endif +} + +#if !defined(__cpp_rtti) || !defined(__cpp_exceptions) +#error Minetest cannot be built without exceptions or RTTI +#endif + +#if defined(__MINGW32__) && !defined(__MINGW64__) && !defined(__clang__) && \ + (__GNUC__ < 11 || (__GNUC__ == 11 && __GNUC_MINOR__ < 1)) +// see e.g. https://github.com/minetest/minetest/issues/10137 +#warning ================================== +#warning 32-bit MinGW gcc before 11.1 has known issues with crashes on thread exit, you should upgrade. +#warning ================================== #endif #define DEBUGFILE "debug.txt" #define DEFAULT_SERVER_PORT 30000 +#define ENV_NO_COLOR "NO_COLOR" +#define ENV_CLICOLOR "CLICOLOR" +#define ENV_CLICOLOR_FORCE "CLICOLOR_FORCE" + typedef std::map OptionList; /********************************************************************** * Private functions **********************************************************************/ +static void get_env_opts(Settings &args); static bool get_cmdline_opts(int argc, char *argv[], Settings *cmd_args); static void set_allowed_options(OptionList *allowed_options); @@ -73,14 +95,15 @@ static void print_help(const OptionList &allowed_options); static void print_allowed_options(const OptionList &allowed_options); static void print_version(); static void print_worldspecs(const std::vector &worldspecs, - std::ostream &os); + std::ostream &os, bool print_name = true, bool print_path = true); static void print_modified_quicktune_values(); static void list_game_ids(); -static void list_worlds(); -static void setup_log_params(const Settings &cmd_args); +static void list_worlds(bool print_name, bool print_path); +static bool setup_log_params(const Settings &cmd_args); static bool create_userdata_path(); static bool init_common(const Settings &cmd_args, int argc, char *argv[]); +static void uninit_common(); static void startup_message(); static bool read_config_file(const Settings &cmd_args); static void init_log_streams(const Settings &cmd_args); @@ -100,6 +123,7 @@ static bool determine_subgame(GameParams *game_params); static bool run_dedicated_server(const GameParams &game_params, const Settings &cmd_args); static bool migrate_map_database(const GameParams &game_params, const Settings &cmd_args); +static bool recompress_map_database(const GameParams &game_params, const Settings &cmd_args, const Address &addr); /**********************************************************************/ @@ -117,6 +141,7 @@ int main(int argc, char *argv[]) g_logger.addOutputMaxLevel(&stderr_output, LL_ACTION); Settings cmd_args; + get_env_opts(cmd_args); bool cmd_args_ok = get_cmdline_opts(argc, argv, &cmd_args); if (!cmd_args_ok || cmd_args.getFlag("help") @@ -134,7 +159,8 @@ int main(int argc, char *argv[]) return 0; } - setup_log_params(cmd_args); + if (!setup_log_params(cmd_args)) + return 1; porting::signal_handler_init(); @@ -150,9 +176,6 @@ int main(int argc, char *argv[]) return 1; } - // Initialize debug stacks - DSTACK(FUNCTION_NAME); - // Debug handler BEGIN_DEBUG_EXCEPTION_HANDLER @@ -162,9 +185,19 @@ int main(int argc, char *argv[]) return 0; } - // List worlds if requested - if (cmd_args.exists("world") && cmd_args.get("world") == "list") { - list_worlds(); + // List worlds, world names, and world paths if requested + if (cmd_args.exists("worldlist")) { + if (cmd_args.get("worldlist") == "name") { + list_worlds(true, false); + } else if (cmd_args.get("worldlist") == "path") { + list_worlds(false, true); + } else if (cmd_args.get("worldlist") == "both") { + list_worlds(true, true); + } else { + errorstream << "Invalid --worldlist value: " + << cmd_args.get("worldlist") << std::endl; + return 1; + } return 0; } @@ -177,11 +210,30 @@ int main(int argc, char *argv[]) #ifndef __ANDROID__ // Run unit tests if (cmd_args.getFlag("run-unittests")) { +#if BUILD_UNITTESTS return run_tests(); +#else + errorstream << "Unittest support is not enabled in this binary. " + << "If you want to enable it, compile project with BUILD_UNITTESTS=1 flag." + << std::endl; + return 1; +#endif } + + // Run benchmarks + if (cmd_args.getFlag("run-benchmarks")) { +#if BUILD_BENCHMARKS + return run_benchmarks(); +#else + errorstream << "Benchmark support is not enabled in this binary. " + << "If you want to enable it, compile project with BUILD_BENCHMARKS=1 flag." + << std::endl; + return 1; #endif + } +#endif // __ANDROID__ - GameParams game_params; + GameStartData game_params; #ifdef SERVER porting::attachOrCreateConsole(); game_params.is_dedicated_server = true; @@ -197,15 +249,11 @@ int main(int argc, char *argv[]) sanity_check(!game_params.world_path.empty()); - infostream << "Using commanded world path [" - << game_params.world_path << "]" << std::endl; - if (game_params.is_dedicated_server) return run_dedicated_server(game_params, cmd_args) ? 0 : 1; #ifndef SERVER - ClientLauncher launcher; - retval = launcher.run(game_params, cmd_args) ? 0 : 1; + retval = ClientLauncher().run(game_params, cmd_args) ? 0 : 1; #else retval = 0; #endif @@ -216,9 +264,6 @@ int main(int argc, char *argv[]) print_modified_quicktune_values(); - // Stop httpfetch thread (if started) - httpfetch_cleanup(); - END_DEBUG_EXCEPTION_HANDLER return retval; @@ -230,6 +275,29 @@ int main(int argc, char *argv[]) *****************************************************************************/ +static void get_env_opts(Settings &args) +{ + // CLICOLOR is a de-facto standard option for colors + // CLICOLOR != 0: ANSI colors are supported (auto-detection, this is the default) + // CLICOLOR == 0: ANSI colors are NOT supported + const char *clicolor = std::getenv(ENV_CLICOLOR); + if (clicolor && std::string(clicolor) == "0") { + args.set("color", "never"); + } + // NO_COLOR only specifies that no color is allowed. + // Implemented according to + const char *no_color = std::getenv(ENV_NO_COLOR); + if (no_color && no_color[0]) { + args.set("color", "never"); + } + // CLICOLOR_FORCE is another option, which should turn on colors "no matter what". + const char *clicolor_force = std::getenv(ENV_CLICOLOR_FORCE); + if (clicolor_force && std::string(clicolor_force) != "0") { + // should ALWAYS have colors, so we ignore tty (no "auto") + args.set("color", "always"); + } +} + static bool get_cmdline_opts(int argc, char *argv[], Settings *cmd_args) { set_allowed_options(&allowed_options); @@ -251,14 +319,22 @@ static void set_allowed_options(OptionList *allowed_options) _("Set network port (UDP)")))); allowed_options->insert(std::make_pair("run-unittests", ValueSpec(VALUETYPE_FLAG, _("Run the unit tests and exit")))); + allowed_options->insert(std::make_pair("run-benchmarks", ValueSpec(VALUETYPE_FLAG, + _("Run the benchmarks and exit")))); allowed_options->insert(std::make_pair("map-dir", ValueSpec(VALUETYPE_STRING, _("Same as --world (deprecated)")))); allowed_options->insert(std::make_pair("world", ValueSpec(VALUETYPE_STRING, - _("Set world path (implies local game) ('list' lists all)")))); + _("Set world path (implies local game if used with option --go)")))); allowed_options->insert(std::make_pair("worldname", ValueSpec(VALUETYPE_STRING, - _("Set world by name (implies local game)")))); + _("Set world by name (implies local game if used with option --go)")))); + allowed_options->insert(std::make_pair("worldlist", ValueSpec(VALUETYPE_STRING, + _("Get list of worlds ('path' lists paths, " + "'name' lists names, 'both' lists both)")))); allowed_options->insert(std::make_pair("quiet", ValueSpec(VALUETYPE_FLAG, _("Print to console errors only")))); + allowed_options->insert(std::make_pair("color", ValueSpec(VALUETYPE_STRING, + _("Coloured logs ('always', 'never' or 'auto'), defaults to 'auto'" + )))); allowed_options->insert(std::make_pair("info", ValueSpec(VALUETYPE_FLAG, _("Print more information to console")))); allowed_options->insert(std::make_pair("verbose", ValueSpec(VALUETYPE_FLAG, @@ -273,11 +349,15 @@ static void set_allowed_options(OptionList *allowed_options) _("Migrate from current map backend to another (Only works when using minetestserver or with --server)")))); allowed_options->insert(std::make_pair("migrate-players", ValueSpec(VALUETYPE_STRING, _("Migrate from current players backend to another (Only works when using minetestserver or with --server)")))); + allowed_options->insert(std::make_pair("migrate-auth", ValueSpec(VALUETYPE_STRING, + _("Migrate from current auth backend to another (Only works when using minetestserver or with --server)")))); + allowed_options->insert(std::make_pair("migrate-mod-storage", ValueSpec(VALUETYPE_STRING, + _("Migrate from current mod storage backend to another (Only works when using minetestserver or with --server)")))); allowed_options->insert(std::make_pair("terminal", ValueSpec(VALUETYPE_FLAG, _("Feature an interactive terminal (Only works when using minetestserver or with --server)")))); + allowed_options->insert(std::make_pair("recompress", ValueSpec(VALUETYPE_FLAG, + _("Recompress the blocks of the given map database.")))); #ifndef SERVER - allowed_options->insert(std::make_pair("videomodes", ValueSpec(VALUETYPE_FLAG, - _("Show available video modes")))); allowed_options->insert(std::make_pair("speedtests", ValueSpec(VALUETYPE_FLAG, _("Run speed tests")))); allowed_options->insert(std::make_pair("address", ValueSpec(VALUETYPE_STRING, @@ -290,6 +370,8 @@ static void set_allowed_options(OptionList *allowed_options) _("Set player name")))); allowed_options->insert(std::make_pair("password", ValueSpec(VALUETYPE_STRING, _("Set password")))); + allowed_options->insert(std::make_pair("password-file", ValueSpec(VALUETYPE_STRING, + _("Set password from contents of file")))); allowed_options->insert(std::make_pair("go", ValueSpec(VALUETYPE_FLAG, _("Disable main menu")))); allowed_options->insert(std::make_pair("console", ValueSpec(VALUETYPE_FLAG, @@ -324,11 +406,16 @@ static void print_allowed_options(const OptionList &allowed_options) static void print_version() { std::cout << PROJECT_NAME_C " " << g_version_hash - << " (" << porting::getPlatformName() << ")" << std::endl; + << " (" << porting::getPlatformName() << ")" << std::endl; #ifndef SERVER - std::cout << "Using Irrlicht " << IRRLICHT_SDK_VERSION << std::endl; + std::cout << "Using Irrlicht " IRRLICHT_SDK_VERSION << std::endl; #endif - std::cout << "Build info: " << g_build_info << std::endl; +#if USE_LUAJIT + std::cout << "Using " << LUAJIT_VERSION << std::endl; +#else + std::cout << "Using " << LUA_RELEASE << std::endl; +#endif + std::cout << g_build_info << std::endl; } static void list_game_ids() @@ -338,24 +425,26 @@ static void list_game_ids() std::cout << gameid < worldspecs = getAvailableWorlds(); - print_worldspecs(worldspecs, std::cout); + print_worldspecs(worldspecs, std::cout, print_name, print_path); } static void print_worldspecs(const std::vector &worldspecs, - std::ostream &os) + std::ostream &os, bool print_name, bool print_path) { for (const WorldSpec &worldspec : worldspecs) { std::string name = worldspec.name; std::string path = worldspec.path; - if (name.find(' ') != std::string::npos) - name = std::string("'") + name + "'"; - path = std::string("'") + path + "'"; - name = padStringRight(name, 14); - os << " " << name << " " << path << std::endl; + if (print_name && print_path) { + os << "\t" << name << "\t\t" << path << std::endl; + } else if (print_name) { + os << "\t" << name << std::endl; + } else if (print_path) { + os << "\t" << path << std::endl; + } } } @@ -376,7 +465,7 @@ static void print_modified_quicktune_values() } } -static void setup_log_params(const Settings &cmd_args) +static bool setup_log_params(const Settings &cmd_args) { // Quiet mode, print errors only if (cmd_args.getFlag("quiet")) { @@ -384,12 +473,28 @@ static void setup_log_params(const Settings &cmd_args) g_logger.addOutputMaxLevel(&stderr_output, LL_ERROR); } - // If trace is enabled, enable logging of certain things - if (cmd_args.getFlag("trace")) { - dstream << _("Enabling trace level debug output") << std::endl; - g_logger.setTraceEnabled(true); - dout_con_ptr = &verbosestream; // This is somewhat old - socket_enable_debug_output = true; // Sockets doesn't use log.h + // Coloured log messages (see log.h) + std::string color_mode; + if (cmd_args.exists("color")) { + color_mode = cmd_args.get("color"); +#if !defined(_WIN32) + } else { + char *color_mode_env = getenv("MT_LOGCOLOR"); + if (color_mode_env) + color_mode = color_mode_env; +#endif + } + if (!color_mode.empty()) { + if (color_mode == "auto") { + Logger::color_mode = LOG_COLOR_AUTO; + } else if (color_mode == "always") { + Logger::color_mode = LOG_COLOR_ALWAYS; + } else if (color_mode == "never") { + Logger::color_mode = LOG_COLOR_NEVER; + } else { + errorstream << "Invalid color mode: " << color_mode << std::endl; + return false; + } } // In certain cases, output info level on stderr @@ -400,6 +505,14 @@ static void setup_log_params(const Settings &cmd_args) // In certain cases, output verbose level on stderr if (cmd_args.getFlag("verbose") || cmd_args.getFlag("trace")) g_logger.addOutput(&stderr_output, LL_VERBOSE); + + if (cmd_args.getFlag("trace")) { + dstream << _("Enabling trace level debug output") << std::endl; + g_logger.addOutput(&stderr_output, LL_TRACE); + socket_enable_debug_output = true; + } + + return true; } static bool create_userdata_path() @@ -412,10 +525,9 @@ static bool create_userdata_path() } else { success = true; } - porting::copyAssets(); #else // Create user data directory - success = fs::CreateDir(porting::path_user); + success = fs::CreateAllDirs(porting::path_user); #endif return success; @@ -424,11 +536,15 @@ static bool create_userdata_path() static bool init_common(const Settings &cmd_args, int argc, char *argv[]) { startup_message(); - set_default_settings(g_settings); + set_default_settings(); - // Initialize sockets sockets_init(); - atexit(sockets_cleanup); + + // Initialize g_settings + Settings::createLayer(SL_GLOBAL); + + // Set cleanup callback(s) to run at process exit + atexit(uninit_common); if (!read_config_file(cmd_args)) return false; @@ -448,6 +564,17 @@ static bool init_common(const Settings &cmd_args, int argc, char *argv[]) return true; } +static void uninit_common() +{ + httpfetch_cleanup(); + + sockets_cleanup(); + + // It'd actually be okay to leak these but we want to please valgrind... + for (int i = 0; i < (int)SL_TOTAL_COUNT; i++) + delete Settings::getLayer((SettingsLayer)i); +} + static void startup_message() { infostream << PROJECT_NAME << " " << _("with") @@ -459,7 +586,7 @@ static void startup_message() static bool read_config_file(const Settings &cmd_args) { // Path of configuration file in use - sanity_check(g_settings_path == ""); // Sanity check + sanity_check(g_settings_path.empty()); // Sanity check if (cmd_args.exists("config")) { bool r = g_settings->readConfigFile(cmd_args.get("config").c_str()); @@ -501,11 +628,8 @@ static bool read_config_file(const Settings &cmd_args) static void init_log_streams(const Settings &cmd_args) { -#if RUN_IN_PLACE - std::string log_filename = DEBUGFILE; -#else std::string log_filename = porting::path_user + DIR_DELIM + DEBUGFILE; -#endif + if (cmd_args.exists("logfile")) log_filename = cmd_args.get("logfile"); @@ -517,7 +641,7 @@ static void init_log_streams(const Settings &cmd_args) warningstream << "Deprecated use of debug_log_level with an " "integer value; please update your configuration." << std::endl; static const char *lev_name[] = - {"", "error", "action", "info", "verbose"}; + {"", "error", "action", "info", "verbose", "trace"}; int lev_i = atoi(conf_loglev.c_str()); if (lev_i < 0 || lev_i >= (int)ARRLEN(lev_name)) { warningstream << "Supplied invalid debug_log_level!" @@ -536,9 +660,8 @@ static void init_log_streams(const Settings &cmd_args) "using maximum." << std::endl; } - verbosestream << "log_filename = " << log_filename << std::endl; - - file_log_output.open(log_filename); + file_log_output.setFile(log_filename, + g_settings->getU64("debug_log_size_max") * 1000000); g_logger.addOutputMaxLevel(&file_log_output, log_level); } @@ -558,10 +681,14 @@ static bool game_configure(GameParams *game_params, const Settings &cmd_args) static void game_configure_port(GameParams *game_params, const Settings &cmd_args) { - if (cmd_args.exists("port")) + if (cmd_args.exists("port")) { game_params->socket_port = cmd_args.getU16("port"); - else - game_params->socket_port = g_settings->getU16("port"); + } else { + if (game_params->is_dedicated_server) + game_params->socket_port = g_settings->getU16("port"); + else + game_params->socket_port = g_settings->getU16("remote_port"); + } if (game_params->socket_port == 0) game_params->socket_port = DEFAULT_SERVER_PORT; @@ -642,8 +769,6 @@ static bool auto_select_world(GameParams *game_params) // No world was specified; try to select it automatically // Get information about available worlds - verbosestream << _("Determining world path") << std::endl; - std::vector worldspecs = getAvailableWorlds(); std::string world_path; @@ -664,11 +789,11 @@ static bool auto_select_world(GameParams *game_params) // This is the ultimate default world path world_path = porting::path_user + DIR_DELIM + "worlds" + DIR_DELIM + "world"; - infostream << "Creating default world at [" + infostream << "Using default world at [" << world_path << "]" << std::endl; } - assert(world_path != ""); // Post-condition + assert(!world_path.empty()); // Post-condition game_params->world_path = world_path; return true; } @@ -724,9 +849,8 @@ static bool determine_subgame(GameParams *game_params) { SubgameSpec gamespec; - assert(game_params->world_path != ""); // Pre-condition + assert(!game_params->world_path.empty()); // Pre-condition - verbosestream << _("Determining gameid/gamespec") << std::endl; // If world doesn't exist if (!game_params->world_path.empty() && !getWorldExists(game_params->world_path)) { @@ -738,7 +862,7 @@ static bool determine_subgame(GameParams *game_params) gamespec = findSubgame(g_settings->get("default_game")); infostream << "Using default gameid [" << gamespec.id << "]" << std::endl; if (!gamespec.isValid()) { - errorstream << "Subgame specified in default_game [" + errorstream << "Game specified in default_game [" << g_settings->get("default_game") << "] is invalid." << std::endl; return false; @@ -763,7 +887,7 @@ static bool determine_subgame(GameParams *game_params) } if (!gamespec.isValid()) { - errorstream << "Subgame [" << gamespec.id << "] could not be found." + errorstream << "Game [" << gamespec.id << "] could not be found." << std::endl; return false; } @@ -778,8 +902,6 @@ static bool determine_subgame(GameParams *game_params) *****************************************************************************/ static bool run_dedicated_server(const GameParams &game_params, const Settings &cmd_args) { - DSTACK("Dedicated server branch"); - verbosestream << _("Using world path") << " [" << game_params.world_path << "]" << std::endl; verbosestream << _("Using gameid") << " [" @@ -806,13 +928,22 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings & return false; } - // Database migration + // Database migration/compression if (cmd_args.exists("migrate")) return migrate_map_database(game_params, cmd_args); if (cmd_args.exists("migrate-players")) return ServerEnvironment::migratePlayersDatabase(game_params, cmd_args); + if (cmd_args.exists("migrate-auth")) + return ServerEnvironment::migrateAuthDatabase(game_params, cmd_args); + + if (cmd_args.exists("migrate-mod-storage")) + return Server::migrateModStorageDatabase(game_params, cmd_args); + + if (cmd_args.getFlag("recompress")) + return recompress_map_database(game_params, cmd_args, bind_addr); + if (cmd_args.exists("terminal")) { #if USE_CURSES bool name_ok = true; @@ -842,13 +973,13 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings & try { // Create server Server server(game_params.world_path, game_params.game_spec, - false, bind_addr.isIPv6(), true, &iface); + false, bind_addr, true, &iface); g_term_console.setup(&iface, &kill, admin_nick); g_term_console.start(); - server.start(bind_addr); + server.start(); // Run server dedicated_server_loop(server, kill); } catch (const ModError &e) { @@ -876,8 +1007,8 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings & try { // Create server Server server(game_params.world_path, game_params.game_spec, false, - bind_addr.isIPv6(), true); - server.start(bind_addr); + bind_addr, true); + server.start(); // Run server bool &kill = *porting::signal_handler_killstatus(); @@ -962,3 +1093,69 @@ static bool migrate_map_database(const GameParams &game_params, const Settings & return true; } + +static bool recompress_map_database(const GameParams &game_params, const Settings &cmd_args, const Address &addr) +{ + Settings world_mt; + const std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt"; + + if (!world_mt.readConfigFile(world_mt_path.c_str())) { + errorstream << "Cannot read world.mt at " << world_mt_path << std::endl; + return false; + } + const std::string &backend = world_mt.get("backend"); + Server server(game_params.world_path, game_params.game_spec, false, addr, false); + MapDatabase *db = ServerMap::createDatabase(backend, game_params.world_path, world_mt); + + u32 count = 0; + u64 last_update_time = 0; + bool &kill = *porting::signal_handler_killstatus(); + const u8 serialize_as_ver = SER_FMT_VER_HIGHEST_WRITE; + + // This is ok because the server doesn't actually run + std::vector blocks; + db->listAllLoadableBlocks(blocks); + db->beginSave(); + std::istringstream iss(std::ios_base::binary); + std::ostringstream oss(std::ios_base::binary); + for (auto it = blocks.begin(); it != blocks.end(); ++it) { + if (kill) return false; + + std::string data; + db->loadBlock(*it, &data); + if (data.empty()) { + errorstream << "Failed to load block " << PP(*it) << std::endl; + return false; + } + + iss.str(data); + iss.clear(); + + { + MapBlock mb(nullptr, v3s16(0,0,0), &server); + u8 ver = readU8(iss); + mb.deSerialize(iss, ver, true); + + oss.str(""); + oss.clear(); + writeU8(oss, serialize_as_ver); + mb.serialize(oss, serialize_as_ver, true, -1); + } + + db->saveBlock(*it, oss.str()); + + count++; + if (count % 0xFF == 0 && porting::getTimeS() - last_update_time >= 1) { + std::cerr << " Recompressed " << count << " blocks, " + << (100.0f * count / blocks.size()) << "% completed.\r"; + db->endSave(); + db->beginSave(); + last_update_time = porting::getTimeS(); + } + } + std::cerr << std::endl; + db->endSave(); + + actionstream << "Done, " << count << " blocks were recompressed." << std::endl; + return true; +}