From 3ce03d1c2a63d261c83f5962cd13212697f19472 Mon Sep 17 00:00:00 2001 From: Hugues Ross Date: Tue, 28 Jul 2020 13:16:57 -0400 Subject: Sanitize world directory names on create. Keep original name separate (#9432) Blacklisted characters are replaced by '_' in the path. The display name is stored in world.mt, and duplicate file names are resolved by adding an incrementing suffix (_1, _2, _3, etc). --- src/server.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/server.cpp') diff --git a/src/server.cpp b/src/server.cpp index fe2bb3840..53ee8c444 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -356,8 +356,13 @@ void Server::init() infostream << "- game: " << m_gamespec.path << std::endl; // Create world if it doesn't exist - if (!loadGameConfAndInitWorld(m_path_world, m_gamespec)) - throw ServerError("Failed to initialize world"); + try { + loadGameConfAndInitWorld(m_path_world, + fs::GetFilenameFromPath(m_path_world.c_str()), + m_gamespec, false); + } catch (const BaseException &e) { + throw ServerError(std::string("Failed to initialize world: ") + e.what()); + } // Create emerge manager m_emerge = new EmergeManager(this); -- cgit v1.2.3 From 98faeac5a7b382e5d7ce0474bf7d52fc5975a23c Mon Sep 17 00:00:00 2001 From: DS Date: Thu, 20 Aug 2020 22:25:29 +0200 Subject: Load media from subfolders (#9065) --- doc/lua_api.txt | 24 +++++++++++++-------- .../mods/basenodes/textures/default_grass_side.png | Bin 796 -> 0 bytes .../textures/dirt_with_grass/default_grass.png | Bin 0 -> 829 bytes .../dirt_with_grass/default_grass_side.png | Bin 0 -> 796 bytes .../basenodes/textures/dirt_with_grass/info.txt | 3 +++ src/server.cpp | 16 +++++++++----- src/server/mods.cpp | 10 ++++----- src/unittest/test_servermodmanager.cpp | 2 -- 8 files changed, 34 insertions(+), 21 deletions(-) delete mode 100644 games/devtest/mods/basenodes/textures/default_grass_side.png create mode 100644 games/devtest/mods/basenodes/textures/dirt_with_grass/default_grass.png create mode 100644 games/devtest/mods/basenodes/textures/dirt_with_grass/default_grass_side.png create mode 100644 games/devtest/mods/basenodes/textures/dirt_with_grass/info.txt (limited to 'src/server.cpp') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 49fbe0d94..9770ae4a9 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -152,7 +152,11 @@ Mod directory structure │   ├── models │   ├── textures │   │   ├── modname_stuff.png - │   │   └── modname_something_else.png + │   │   ├── modname_something_else.png + │   │   ├── subfolder_foo + │   │   │ ├── modname_more_stuff.png + │   │   │ └── another_subfolder + │   │   └── bar_subfolder │   ├── sounds │   ├── media │   ├── locale @@ -221,18 +225,20 @@ registered callbacks. `minetest.settings` can be used to read custom or existing settings at load time, if necessary. (See [`Settings`]) -### `models` - -Models for entities or meshnodes. - -### `textures`, `sounds`, `media` +### `textures`, `sounds`, `media`, `models`, `locale` Media files (textures, sounds, whatever) that will be transferred to the -client and will be available for use by the mod. +client and will be available for use by the mod and translation files for +the clients (see [Translations]). -### `locale` +It is suggested to use the folders for the purpous they are thought for, +eg. put textures into `textures`, translation files into `locale`, +models for entities or meshnodes into `models` et cetera. -Translation files for the clients. (See [Translations]) +These folders and subfolders can contain subfolders. +Subfolders with names starting with `_` or `.` are ignored. +If a subfolder contains a media file with the same name as a media file +in one of its parents, the parent's file is used. Naming conventions ------------------ diff --git a/games/devtest/mods/basenodes/textures/default_grass_side.png b/games/devtest/mods/basenodes/textures/default_grass_side.png deleted file mode 100644 index 04770b6f6..000000000 Binary files a/games/devtest/mods/basenodes/textures/default_grass_side.png and /dev/null differ diff --git a/games/devtest/mods/basenodes/textures/dirt_with_grass/default_grass.png b/games/devtest/mods/basenodes/textures/dirt_with_grass/default_grass.png new file mode 100644 index 000000000..29fde6b26 Binary files /dev/null and b/games/devtest/mods/basenodes/textures/dirt_with_grass/default_grass.png differ diff --git a/games/devtest/mods/basenodes/textures/dirt_with_grass/default_grass_side.png b/games/devtest/mods/basenodes/textures/dirt_with_grass/default_grass_side.png new file mode 100644 index 000000000..04770b6f6 Binary files /dev/null and b/games/devtest/mods/basenodes/textures/dirt_with_grass/default_grass_side.png differ diff --git a/games/devtest/mods/basenodes/textures/dirt_with_grass/info.txt b/games/devtest/mods/basenodes/textures/dirt_with_grass/info.txt new file mode 100644 index 000000000..8db21ed9c --- /dev/null +++ b/games/devtest/mods/basenodes/textures/dirt_with_grass/info.txt @@ -0,0 +1,3 @@ +This is for testing loading textures from subfolders. +If it works correctly, the default_grass_side.png file in this folder is used but +default_grass.png is not overwritten by the file in this folder. diff --git a/src/server.cpp b/src/server.cpp index 53ee8c444..ef36aedca 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2494,19 +2494,25 @@ void Server::fillMediaCache() // Collect all media file paths std::vector paths; - m_modmgr->getModsMediaPaths(paths); - fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures"); + // The paths are ordered in descending priority fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server"); + fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures"); + m_modmgr->getModsMediaPaths(paths); // Collect media file information from paths into cache for (const std::string &mediapath : paths) { std::vector dirlist = fs::GetDirListing(mediapath); for (const fs::DirListNode &dln : dirlist) { - if (dln.dir) // Ignore dirs + if (dln.dir) // Ignore dirs (already in paths) continue; + + const std::string &filename = dln.name; + if (m_media.find(filename) != m_media.end()) // Do not override + continue; + std::string filepath = mediapath; - filepath.append(DIR_DELIM).append(dln.name); - addMediaFile(dln.name, filepath); + filepath.append(DIR_DELIM).append(filename); + addMediaFile(filename, filepath); } } diff --git a/src/server/mods.cpp b/src/server/mods.cpp index 6ac530739..cf1467648 100644 --- a/src/server/mods.cpp +++ b/src/server/mods.cpp @@ -99,10 +99,10 @@ void ServerModManager::getModNames(std::vector &modlist) const void ServerModManager::getModsMediaPaths(std::vector &paths) const { for (const ModSpec &spec : m_sorted_mods) { - paths.push_back(spec.path + DIR_DELIM + "textures"); - paths.push_back(spec.path + DIR_DELIM + "sounds"); - paths.push_back(spec.path + DIR_DELIM + "media"); - paths.push_back(spec.path + DIR_DELIM + "models"); - paths.push_back(spec.path + DIR_DELIM + "locale"); + fs::GetRecursiveDirs(paths, spec.path + DIR_DELIM + "textures"); + fs::GetRecursiveDirs(paths, spec.path + DIR_DELIM + "sounds"); + fs::GetRecursiveDirs(paths, spec.path + DIR_DELIM + "media"); + fs::GetRecursiveDirs(paths, spec.path + DIR_DELIM + "models"); + fs::GetRecursiveDirs(paths, spec.path + DIR_DELIM + "locale"); } } diff --git a/src/unittest/test_servermodmanager.cpp b/src/unittest/test_servermodmanager.cpp index 799936757..e3edb0c32 100644 --- a/src/unittest/test_servermodmanager.cpp +++ b/src/unittest/test_servermodmanager.cpp @@ -169,6 +169,4 @@ void TestServerModManager::testGetModMediaPaths() std::vector result; sm.getModsMediaPaths(result); UASSERTEQ(bool, result.empty(), false); - // We should have 5 folders for each mod (textures, media, locale, model, sounds) - UASSERTEQ(unsigned long, result.size() % 5, 0); } -- cgit v1.2.3 From f27cf4777933f06f85fa2f013d56ca0a2cf1d588 Mon Sep 17 00:00:00 2001 From: Desour Date: Sun, 23 Aug 2020 19:44:25 +0200 Subject: Properly handle mod-errors in on_shutdown --- src/client/game.cpp | 3 ++- src/server.cpp | 17 +++++++++++++++-- src/server.h | 7 ++++++- 3 files changed, 23 insertions(+), 4 deletions(-) (limited to 'src/server.cpp') diff --git a/src/client/game.cpp b/src/client/game.cpp index 0d3a0ca15..920383aaf 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1300,7 +1300,8 @@ bool Game::createSingleplayerServer(const std::string &map_dir, return false; } - server = new Server(map_dir, gamespec, simple_singleplayer_mode, bind_addr, false); + server = new Server(map_dir, gamespec, simple_singleplayer_mode, bind_addr, + false, nullptr, error_message); server->start(); return true; diff --git a/src/server.cpp b/src/server.cpp index ef36aedca..7b3978462 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -213,7 +213,8 @@ Server::Server( bool simple_singleplayer_mode, Address bind_addr, bool dedicated, - ChatInterface *iface + ChatInterface *iface, + std::string *on_shutdown_errmsg ): m_bind_addr(bind_addr), m_path_world(path_world), @@ -232,6 +233,7 @@ Server::Server( m_thread(new ServerThread(this)), m_clients(m_con), m_admin_chat(iface), + m_on_shutdown_errmsg(on_shutdown_errmsg), m_modchannel_mgr(new ModChannelMgr()) { if (m_path_world.empty()) @@ -314,7 +316,18 @@ Server::~Server() // Execute script shutdown hooks infostream << "Executing shutdown hooks" << std::endl; - m_script->on_shutdown(); + try { + m_script->on_shutdown(); + } catch (ModError &e) { + errorstream << "ModError: " << e.what() << std::endl; + if (m_on_shutdown_errmsg) { + if (m_on_shutdown_errmsg->empty()) { + *m_on_shutdown_errmsg = std::string("ModError: ") + e.what(); + } else { + *m_on_shutdown_errmsg += std::string("\nModError: ") + e.what(); + } + } + } infostream << "Server: Saving environment metadata" << std::endl; m_env->saveMeta(); diff --git a/src/server.h b/src/server.h index f44716531..be6f60abc 100644 --- a/src/server.h +++ b/src/server.h @@ -131,7 +131,8 @@ public: bool simple_singleplayer_mode, Address bind_addr, bool dedicated, - ChatInterface *iface = nullptr + ChatInterface *iface = nullptr, + std::string *on_shutdown_errmsg = nullptr ); ~Server(); DISABLE_CLASS_COPY(Server); @@ -596,6 +597,10 @@ private: ChatInterface *m_admin_chat; std::string m_admin_nick; + // if a mod-error occurs in the on_shutdown callback, the error message will + // be written into this + std::string *const m_on_shutdown_errmsg; + /* Map edit event queue. Automatically receives all map edits. The constructor of this class registers us to receive them through -- cgit v1.2.3 From 9ec75d77651c333eca3c5b46a3a56c8353fed464 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Wed, 16 Sep 2020 14:51:11 +0100 Subject: Clean up server-side translations, remove global variable (#10075) --- src/client/client.cpp | 9 ++------ src/filesys.cpp | 15 +++++++++++++ src/filesys.h | 2 ++ src/script/lua_api/l_env.cpp | 6 ++--- src/server.cpp | 53 ++++++++++++++++++-------------------------- src/server.h | 7 ++++-- src/serverlist.cpp | 10 +-------- src/translation.cpp | 8 ------- src/translation.h | 5 ----- 9 files changed, 50 insertions(+), 65 deletions(-) (limited to 'src/server.cpp') diff --git a/src/client/client.cpp b/src/client/client.cpp index 745cce900..d6e529c40 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -238,18 +238,13 @@ void Client::scanModSubfolder(const std::string &mod_name, const std::string &mo infostream << "Client::scanModSubfolder(): Loading \"" << real_path << "\" as \"" << vfs_path << "\"." << std::endl; - std::ifstream is(real_path, std::ios::binary | std::ios::ate); - if(!is.good()) { + std::string contents; + if (!fs::ReadFile(real_path, contents)) { errorstream << "Client::scanModSubfolder(): Can't read file \"" << real_path << "\"." << std::endl; continue; } - auto size = is.tellg(); - std::string contents(size, '\0'); - is.seekg(0); - is.read(&contents[0], size); - infostream << " size: " << size << " bytes" << std::endl; m_mod_vfs.emplace(vfs_path, contents); } } diff --git a/src/filesys.cpp b/src/filesys.cpp index 0bc351669..2470b1b64 100644 --- a/src/filesys.cpp +++ b/src/filesys.cpp @@ -750,6 +750,21 @@ bool safeWriteToFile(const std::string &path, const std::string &content) return true; } +bool ReadFile(const std::string &path, std::string &out) +{ + std::ifstream is(path, std::ios::binary | std::ios::ate); + if (!is.good()) { + return false; + } + + auto size = is.tellg(); + out.resize(size); + is.seekg(0); + is.read(&out[0], size); + + return true; +} + bool Rename(const std::string &from, const std::string &to) { return rename(from.c_str(), to.c_str()) == 0; diff --git a/src/filesys.h b/src/filesys.h index 09f129aa3..b2c800c55 100644 --- a/src/filesys.h +++ b/src/filesys.h @@ -128,6 +128,8 @@ const char *GetFilenameFromPath(const char *path); bool safeWriteToFile(const std::string &path, const std::string &content); +bool ReadFile(const std::string &path, std::string &out); + bool Rename(const std::string &from, const std::string &to); } // namespace fs diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index b2bc8c5f6..138e88ae8 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -1340,9 +1340,9 @@ int ModApiEnvMod::l_get_translated_string(lua_State * L) GET_ENV_PTR; std::string lang_code = luaL_checkstring(L, 1); std::string string = luaL_checkstring(L, 2); - getServer(L)->loadTranslationLanguage(lang_code); - string = wide_to_utf8(translate_string(utf8_to_wide(string), - &(*g_server_translations)[lang_code])); + + auto *translations = getServer(L)->getTranslationLanguage(lang_code); + string = wide_to_utf8(translate_string(utf8_to_wide(string), translations)); lua_pushstring(L, string.c_str()); return 1; } diff --git a/src/server.cpp b/src/server.cpp index 7b3978462..b8a99f6ae 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2451,31 +2451,14 @@ bool Server::addMediaFile(const std::string &filename, // Ok, attempt to load the file and add to cache // Read data - std::ifstream fis(filepath.c_str(), std::ios_base::binary); - if (!fis.good()) { - errorstream << "Server::addMediaFile(): Could not open \"" - << filename << "\" for reading" << std::endl; - return false; - } std::string filedata; - bool bad = false; - for (;;) { - char buf[1024]; - fis.read(buf, sizeof(buf)); - std::streamsize len = fis.gcount(); - filedata.append(buf, len); - if (fis.eof()) - break; - if (!fis.good()) { - bad = true; - break; - } - } - if (bad) { - errorstream << "Server::addMediaFile(): Failed to read \"" - << filename << "\"" << std::endl; + if (!fs::ReadFile(filepath, filedata)) { + errorstream << "Server::addMediaFile(): Failed to open \"" + << filename << "\" for reading" << std::endl; return false; - } else if (filedata.empty()) { + } + + if (filedata.empty()) { errorstream << "Server::addMediaFile(): Empty file \"" << filepath << "\"" << std::endl; return false; @@ -3890,19 +3873,27 @@ void Server::broadcastModChannelMessage(const std::string &channel, } } -void Server::loadTranslationLanguage(const std::string &lang_code) +Translations *Server::getTranslationLanguage(const std::string &lang_code) { - if (g_server_translations->count(lang_code)) - return; // Already loaded + if (lang_code.empty()) + return nullptr; + + auto it = server_translations.find(lang_code); + if (it != server_translations.end()) + return &it->second; // Already loaded + + // [] will create an entry + auto *translations = &server_translations[lang_code]; std::string suffix = "." + lang_code + ".tr"; for (const auto &i : m_media) { if (str_ends_with(i.first, suffix)) { - std::ifstream t(i.second.path); - std::string data((std::istreambuf_iterator(t)), - std::istreambuf_iterator()); - - (*g_server_translations)[lang_code].loadTranslation(data); + std::string data; + if (fs::ReadFile(i.second.path, data)) { + translations->loadTranslation(data); + } } } + + return translations; } diff --git a/src/server.h b/src/server.h index be6f60abc..258d75eaf 100644 --- a/src/server.h +++ b/src/server.h @@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "serverenvironment.h" #include "clientiface.h" #include "chatmessage.h" +#include "translation.h" #include #include #include @@ -343,8 +344,8 @@ public: // Send block to specific player only bool SendBlock(session_t peer_id, const v3s16 &blockpos); - // Load translations for a language - void loadTranslationLanguage(const std::string &lang_code); + // Get or load translations for a language + Translations *getTranslationLanguage(const std::string &lang_code); // Bind address Address m_bind_addr; @@ -557,6 +558,8 @@ private: // Mods std::unique_ptr m_modmgr; + std::unordered_map server_translations; + /* Threads */ diff --git a/src/serverlist.cpp b/src/serverlist.cpp index 2f6ab2e61..c7fe2d888 100644 --- a/src/serverlist.cpp +++ b/src/serverlist.cpp @@ -52,15 +52,7 @@ std::vector getLocal() { std::string path = ServerList::getFilePath(); std::string liststring; - if (fs::PathExists(path)) { - std::ifstream istream(path.c_str()); - if (istream.is_open()) { - std::ostringstream ostream; - ostream << istream.rdbuf(); - liststring = ostream.str(); - istream.close(); - } - } + fs::ReadFile(path, liststring); return deSerialize(liststring); } diff --git a/src/translation.cpp b/src/translation.cpp index 8bbaee0a3..82e813a5d 100644 --- a/src/translation.cpp +++ b/src/translation.cpp @@ -29,14 +29,6 @@ Translations client_translations; Translations *g_client_translations = &client_translations; #endif -// Per language server translations -std::unordered_map server_translations; -std::unordered_map *g_server_translations = &server_translations; - -Translations::~Translations() -{ - clear(); -} void Translations::clear() { diff --git a/src/translation.h b/src/translation.h index 71423b15e..f1a336fca 100644 --- a/src/translation.h +++ b/src/translation.h @@ -23,7 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include class Translations; -extern std::unordered_map *g_server_translations; #ifndef SERVER extern Translations *g_client_translations; #endif @@ -31,10 +30,6 @@ extern Translations *g_client_translations; class Translations { public: - Translations() = default; - - ~Translations(); - void loadTranslation(const std::string &data); void clear(); const std::wstring &getTranslation( -- cgit v1.2.3 From c6e3050357e8378ad15e7fa7a9aa80f3936fbc2d Mon Sep 17 00:00:00 2001 From: Buckaroo Banzai <39065740+BuckarooBanzay@users.noreply.github.com> Date: Fri, 25 Sep 2020 18:52:42 +0200 Subject: Correct erroneous reported max lag with prometheus (#10427) Co-authored-by: BuckarooBanzay --- src/server.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/server.cpp') diff --git a/src/server.cpp b/src/server.cpp index b8a99f6ae..456edfeb8 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -653,7 +653,12 @@ void Server::AsyncRunStep(bool initial_step) } m_clients.step(dtime); - m_lag_gauge->increment((m_lag_gauge->get() > dtime ? -1 : 1) * dtime/100); + // increase/decrease lag gauge gradually + if (m_lag_gauge->get() > dtime) { + m_lag_gauge->decrement(dtime/100); + } else { + m_lag_gauge->increment(dtime/100); + } #if USE_CURL // send masterserver announce { -- cgit v1.2.3 From 09af0c5946c7082fc82563faf0ad9ef144fb9a06 Mon Sep 17 00:00:00 2001 From: luk3yx Date: Sun, 27 Sep 2020 01:31:54 +1200 Subject: Remove null bytes from TOCLIENT_BLOCKDATA (#10433) --- src/server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/server.cpp') diff --git a/src/server.cpp b/src/server.cpp index 456edfeb8..d40ff259f 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2338,7 +2338,7 @@ void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver, block->serializeNetworkSpecific(os); std::string s = os.str(); - NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id); + NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + s.size(), peer_id); pkt << block->getPos(); pkt.putRawString(s.c_str(), s.size()); -- cgit v1.2.3 From 947466ab28129fd69e6630974c6c4e901f2bebc6 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Sun, 20 Sep 2020 13:12:55 +0200 Subject: (se)SerializeString: Include max length in the name This commit clarifies the maximal length of the serialized strings. It will avoid accidental use of serializeString() when a larger string can be expected. Removes unused Wide String serialization functions --- src/client/content_cao.cpp | 12 +++---- src/content_nodemeta.cpp | 18 +++++------ src/database/database-leveldb.cpp | 16 +++++----- src/itemdef.cpp | 52 +++++++++++++++--------------- src/mapblock.cpp | 4 +-- src/mapgen/mg_schematic.cpp | 4 +-- src/nameidmapping.cpp | 4 +-- src/network/clientpackethandler.cpp | 8 ++--- src/nodedef.cpp | 40 +++++++++++------------ src/nodemetadata.cpp | 8 ++--- src/object_properties.cpp | 28 ++++++++--------- src/particles.cpp | 4 +-- src/server.cpp | 4 +-- src/server/luaentity_sao.cpp | 28 ++++++++--------- src/server/player_sao.cpp | 16 +++++----- src/server/serveractiveobject.cpp | 2 +- src/server/unit_sao.cpp | 6 ++-- src/sound.h | 4 +-- src/staticobject.cpp | 4 +-- src/tool.cpp | 8 ++--- src/unittest/test_serialization.cpp | 50 +++++++++++++---------------- src/util/serialize.cpp | 63 +++++-------------------------------- src/util/serialize.h | 8 ++--- 23 files changed, 168 insertions(+), 223 deletions(-) (limited to 'src/server.cpp') diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 599139aa3..71a9d4b54 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -371,7 +371,7 @@ void GenericCAO::processInitData(const std::string &data) } // PROTOCOL_VERSION >= 37 - m_name = deSerializeString(is); + m_name = deSerializeString16(is); m_is_player = readU8(is); m_id = readU16(is); m_position = readV3F32(is); @@ -381,7 +381,7 @@ void GenericCAO::processInitData(const std::string &data) const u8 num_messages = readU8(is); for (int i = 0; i < num_messages; i++) { - std::string message = deSerializeLongString(is); + std::string message = deSerializeString32(is); processMessage(message); } @@ -1657,7 +1657,7 @@ void GenericCAO::processMessage(const std::string &data) rot_translator.update(m_rotation, false, update_interval); updateNodePos(); } else if (cmd == AO_CMD_SET_TEXTURE_MOD) { - std::string mod = deSerializeString(is); + std::string mod = deSerializeString16(is); // immediately reset a engine issued texture modifier if a mod sends a different one if (m_reset_textures_timer > 0) { @@ -1735,7 +1735,7 @@ void GenericCAO::processMessage(const std::string &data) m_animation_speed = readF32(is); updateAnimationSpeed(); } else if (cmd == AO_CMD_SET_BONE_POSITION) { - std::string bone = deSerializeString(is); + std::string bone = deSerializeString16(is); v3f position = readV3F32(is); v3f rotation = readV3F32(is); m_bone_position[bone] = core::vector2d(position, rotation); @@ -1743,7 +1743,7 @@ void GenericCAO::processMessage(const std::string &data) // updateBonePosition(); now called every step } else if (cmd == AO_CMD_ATTACH_TO) { u16 parent_id = readS16(is); - std::string bone = deSerializeString(is); + std::string bone = deSerializeString16(is); v3f position = readV3F32(is); v3f rotation = readV3F32(is); @@ -1793,7 +1793,7 @@ void GenericCAO::processMessage(const std::string &data) int armor_groups_size = readU16(is); for(int i=0; igetInventory()->deSerialize(is); - deSerializeLongString(is); // m_text - deSerializeString(is); // m_owner + deSerializeString32(is); // m_text + deSerializeString16(is); // m_owner - meta->setString("infotext",deSerializeString(is)); - meta->setString("formspec",deSerializeString(is)); + meta->setString("infotext",deSerializeString16(is)); + meta->setString("formspec",deSerializeString16(is)); readU8(is); // m_allow_text_input readU8(is); // m_allow_removal readU8(is); // m_enforce_owner int num_vars = readU32(is); for(int i=0; isetString(name, var); } return false; } else if(id == NODEMETA_SIGN) // SignNodeMetadata { - meta->setString("text", deSerializeString(is)); + meta->setString("text", deSerializeString16(is)); //meta->setString("infotext","\"${text}\""); meta->setString("infotext", std::string("\"") + meta->getString("text") + "\""); @@ -87,7 +87,7 @@ static bool content_nodemeta_deserialize_legacy_body( } else if(id == NODEMETA_LOCKABLE_CHEST) // LockingChestNodeMetadata { - meta->setString("owner", deSerializeString(is)); + meta->setString("owner", deSerializeString16(is)); meta->getInventory()->deSerialize(is); // Rename inventory list "0" to "main" @@ -138,7 +138,7 @@ static bool content_nodemeta_deserialize_legacy_meta( s16 id = readS16(is); // Read data - std::string data = deSerializeString(is); + std::string data = deSerializeString16(is); std::istringstream tmp_is(data, std::ios::binary); return content_nodemeta_deserialize_legacy_body(tmp_is, id, meta); } diff --git a/src/database/database-leveldb.cpp b/src/database/database-leveldb.cpp index 1976ae13d..73cd63f6d 100644 --- a/src/database/database-leveldb.cpp +++ b/src/database/database-leveldb.cpp @@ -145,8 +145,8 @@ void PlayerDatabaseLevelDB::savePlayer(RemotePlayer *player) StringMap stringvars = sao->getMeta().getStrings(); writeU32(os, stringvars.size()); for (const auto &it : stringvars) { - os << serializeString(it.first); - os << serializeLongString(it.second); + os << serializeString16(it.first); + os << serializeString32(it.second); } player->inventory.serialize(os); @@ -183,8 +183,8 @@ bool PlayerDatabaseLevelDB::loadPlayer(RemotePlayer *player, PlayerSAO *sao) u32 attribute_count = readU32(is); for (u32 i = 0; i < attribute_count; i++) { - std::string name = deSerializeString(is); - std::string value = deSerializeLongString(is); + std::string name = deSerializeString16(is); + std::string value = deSerializeString32(is); sao->getMeta().setString(name, value); } sao->getMeta().setModified(false); @@ -247,13 +247,13 @@ bool AuthDatabaseLevelDB::getAuth(const std::string &name, AuthEntry &res) res.id = 1; res.name = name; - res.password = deSerializeString(is); + res.password = deSerializeString16(is); u16 privilege_count = readU16(is); res.privileges.clear(); res.privileges.reserve(privilege_count); for (u16 i = 0; i < privilege_count; i++) { - res.privileges.push_back(deSerializeString(is)); + res.privileges.push_back(deSerializeString16(is)); } res.last_login = readS64(is); @@ -264,14 +264,14 @@ bool AuthDatabaseLevelDB::saveAuth(const AuthEntry &authEntry) { std::ostringstream os; writeU8(os, 1); - os << serializeString(authEntry.password); + os << serializeString16(authEntry.password); size_t privilege_count = authEntry.privileges.size(); FATAL_ERROR_IF(privilege_count > U16_MAX, "Unsupported number of privileges"); writeU16(os, privilege_count); for (const std::string &privilege : authEntry.privileges) { - os << serializeString(privilege); + os << serializeString16(privilege); } writeS64(os, authEntry.last_login); diff --git a/src/itemdef.cpp b/src/itemdef.cpp index 8e0492827..df20bdf15 100644 --- a/src/itemdef.cpp +++ b/src/itemdef.cpp @@ -128,10 +128,10 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const u8 version = 6; writeU8(os, version); writeU8(os, type); - os << serializeString(name); - os << serializeString(description); - os << serializeString(inventory_image); - os << serializeString(wield_image); + os << serializeString16(name); + os << serializeString16(description); + os << serializeString16(inventory_image); + os << serializeString16(wield_image); writeV3F32(os, wield_scale); writeS16(os, stack_max); writeU8(os, usable); @@ -143,25 +143,25 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const tool_capabilities->serialize(tmp_os, protocol_version); tool_capabilities_s = tmp_os.str(); } - os << serializeString(tool_capabilities_s); + os << serializeString16(tool_capabilities_s); writeU16(os, groups.size()); for (const auto &group : groups) { - os << serializeString(group.first); + os << serializeString16(group.first); writeS16(os, group.second); } - os << serializeString(node_placement_prediction); + os << serializeString16(node_placement_prediction); // Version from ContentFeatures::serialize to keep in sync sound_place.serialize(os, CONTENTFEATURES_VERSION); sound_place_failed.serialize(os, CONTENTFEATURES_VERSION); writeF32(os, range); - os << serializeString(palette_image); + os << serializeString16(palette_image); writeARGB8(os, color); - os << serializeString(inventory_overlay); - os << serializeString(wield_overlay); + os << serializeString16(inventory_overlay); + os << serializeString16(wield_overlay); } void ItemDefinition::deSerialize(std::istream &is) @@ -175,16 +175,16 @@ void ItemDefinition::deSerialize(std::istream &is) throw SerializationError("unsupported ItemDefinition version"); type = (enum ItemType)readU8(is); - name = deSerializeString(is); - description = deSerializeString(is); - inventory_image = deSerializeString(is); - wield_image = deSerializeString(is); + name = deSerializeString16(is); + description = deSerializeString16(is); + inventory_image = deSerializeString16(is); + wield_image = deSerializeString16(is); wield_scale = readV3F32(is); stack_max = readS16(is); usable = readU8(is); liquids_pointable = readU8(is); - std::string tool_capabilities_s = deSerializeString(is); + std::string tool_capabilities_s = deSerializeString16(is); if (!tool_capabilities_s.empty()) { std::istringstream tmp_is(tool_capabilities_s, std::ios::binary); tool_capabilities = new ToolCapabilities; @@ -194,22 +194,22 @@ void ItemDefinition::deSerialize(std::istream &is) groups.clear(); u32 groups_size = readU16(is); for(u32 i=0; iserialize(tmp_os, protocol_version); - os << serializeString(tmp_os.str()); + os << serializeString16(tmp_os.str()); } writeU16(os, m_aliases.size()); for (const auto &it : m_aliases) { - os << serializeString(it.first); - os << serializeString(it.second); + os << serializeString16(it.first); + os << serializeString16(it.second); } } void deSerialize(std::istream &is) @@ -543,7 +543,7 @@ public: for(u16 i=0; iidef()); } else { - //std::string data = deSerializeLongString(is); + //std::string data = deSerializeString32(is); std::ostringstream oss(std::ios_base::binary); decompressZlib(is, oss); std::istringstream iss(oss.str(), std::ios_base::binary); diff --git a/src/mapgen/mg_schematic.cpp b/src/mapgen/mg_schematic.cpp index ba102d997..dfd414709 100644 --- a/src/mapgen/mg_schematic.cpp +++ b/src/mapgen/mg_schematic.cpp @@ -314,7 +314,7 @@ bool Schematic::deserializeFromMts(std::istream *is, //// Read node names u16 nidmapcount = readU16(ss); for (int i = 0; i != nidmapcount; i++) { - std::string name = deSerializeString(ss); + std::string name = deSerializeString16(ss); // Instances of "ignore" from v1 are converted to air (and instances // are fixed to have MTSCHEM_PROB_NEVER later on). @@ -372,7 +372,7 @@ bool Schematic::serializeToMts(std::ostream *os, writeU16(ss, names.size()); // name count for (size_t i = 0; i != names.size(); i++) - ss << serializeString(names[i]); // node names + ss << serializeString16(names[i]); // node names // compressed bulk node data MapNode::serializeBulk(ss, SER_FMT_VER_HIGHEST_WRITE, diff --git a/src/nameidmapping.cpp b/src/nameidmapping.cpp index bd5bb1fc8..05cfae069 100644 --- a/src/nameidmapping.cpp +++ b/src/nameidmapping.cpp @@ -27,7 +27,7 @@ void NameIdMapping::serialize(std::ostream &os) const writeU16(os, m_id_to_name.size()); for (const auto &i : m_id_to_name) { writeU16(os, i.first); - os << serializeString(i.second); + os << serializeString16(i.second); } } @@ -41,7 +41,7 @@ void NameIdMapping::deSerialize(std::istream &is) m_name_to_id.clear(); for (u32 i = 0; i < count; i++) { u16 id = readU16(is); - std::string name = deSerializeString(is); + std::string name = deSerializeString16(is); m_id_to_name[id] = name; m_name_to_id[name] = id; } diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 8d87ff8f2..5683564a0 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -497,7 +497,7 @@ void Client::handleCommand_ActiveObjectMessages(NetworkPacket* pkt) if (!is.good()) break; - std::string message = deSerializeString(is); + std::string message = deSerializeString16(is); // Pass on to the environment m_env.processActiveObjectMessage(id, message); @@ -994,7 +994,7 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) p.minsize = readF32(is); p.maxsize = readF32(is); p.collisiondetection = readU8(is); - p.texture = deSerializeLongString(is); + p.texture = deSerializeString32(is); server_id = readU32(is); @@ -1207,11 +1207,11 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt) SkyboxParams skybox; skybox.bgcolor = video::SColor(readARGB8(is)); - skybox.type = std::string(deSerializeString(is)); + skybox.type = std::string(deSerializeString16(is)); u16 count = readU16(is); for (size_t i = 0; i < count; i++) - skybox.textures.emplace_back(deSerializeString(is)); + skybox.textures.emplace_back(deSerializeString16(is)); skybox.clouds = true; try { diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 392f5eb98..3a5934cf3 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -207,7 +207,7 @@ void TileDef::serialize(std::ostream &os, u16 protocol_version) const u8 version = 6; writeU8(os, version); - os << serializeString(name); + os << serializeString16(name); animation.serialize(os, version); bool has_scale = scale > 0; u16 flags = 0; @@ -241,7 +241,7 @@ void TileDef::deSerialize(std::istream &is, u8 contentfeatures_version, int version = readU8(is); if (version < 6) throw SerializationError("unsupported TileDef version"); - name = deSerializeString(is); + name = deSerializeString16(is); animation.deSerialize(is, version); u16 flags = readU16(is); backface_culling = flags & TILE_FLAG_BACKFACE_CULLING; @@ -416,10 +416,10 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const writeU8(os, version); // general - os << serializeString(name); + os << serializeString16(name); writeU16(os, groups.size()); for (const auto &group : groups) { - os << serializeString(group.first); + os << serializeString16(group.first); writeS16(os, group.second); } writeU8(os, param_type); @@ -427,7 +427,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const // visual writeU8(os, drawtype); - os << serializeString(mesh); + os << serializeString16(mesh); writeF32(os, visual_scale); writeU8(os, 6); for (const TileDef &td : tiledef) @@ -442,7 +442,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const writeU8(os, color.getRed()); writeU8(os, color.getGreen()); writeU8(os, color.getBlue()); - os << serializeString(palette_name); + os << serializeString16(palette_name); writeU8(os, waving); writeU8(os, connect_sides); writeU16(os, connects_to_ids.size()); @@ -470,8 +470,8 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const // liquid writeU8(os, liquid_type); - os << serializeString(liquid_alternative_flowing); - os << serializeString(liquid_alternative_source); + os << serializeString16(liquid_alternative_flowing); + os << serializeString16(liquid_alternative_source); writeU8(os, liquid_viscosity); writeU8(os, liquid_renewable); writeU8(os, liquid_range); @@ -492,7 +492,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const writeU8(os, legacy_facedir_simple); writeU8(os, legacy_wallmounted); - os << serializeString(node_dig_prediction); + os << serializeString16(node_dig_prediction); writeU8(os, leveled_max); } @@ -519,11 +519,11 @@ void ContentFeatures::deSerialize(std::istream &is) throw SerializationError("unsupported ContentFeatures version"); // general - name = deSerializeString(is); + name = deSerializeString16(is); groups.clear(); u32 groups_size = readU16(is); for (u32 i = 0; i < groups_size; i++) { - std::string name = deSerializeString(is); + std::string name = deSerializeString16(is); int value = readS16(is); groups[name] = value; } @@ -532,7 +532,7 @@ void ContentFeatures::deSerialize(std::istream &is) // visual drawtype = (enum NodeDrawType) readU8(is); - mesh = deSerializeString(is); + mesh = deSerializeString16(is); visual_scale = readF32(is); if (readU8(is) != 6) throw SerializationError("unsupported tile count"); @@ -548,7 +548,7 @@ void ContentFeatures::deSerialize(std::istream &is) color.setRed(readU8(is)); color.setGreen(readU8(is)); color.setBlue(readU8(is)); - palette_name = deSerializeString(is); + palette_name = deSerializeString16(is); waving = readU8(is); connect_sides = readU8(is); u16 connects_to_size = readU16(is); @@ -578,8 +578,8 @@ void ContentFeatures::deSerialize(std::istream &is) // liquid liquid_type = (enum LiquidType) readU8(is); - liquid_alternative_flowing = deSerializeString(is); - liquid_alternative_source = deSerializeString(is); + liquid_alternative_flowing = deSerializeString16(is); + liquid_alternative_source = deSerializeString16(is); liquid_viscosity = readU8(is); liquid_renewable = readU8(is); liquid_range = readU8(is); @@ -601,7 +601,7 @@ void ContentFeatures::deSerialize(std::istream &is) legacy_wallmounted = readU8(is); try { - node_dig_prediction = deSerializeString(is); + node_dig_prediction = deSerializeString16(is); u8 tmp_leveled_max = readU8(is); if (is.eof()) /* readU8 doesn't throw exceptions so we have to do this */ throw SerializationError(""); @@ -1472,7 +1472,7 @@ void NodeDefManager::serialize(std::ostream &os, u16 protocol_version) const // strict version incompatibilities std::ostringstream wrapper_os(std::ios::binary); f->serialize(wrapper_os, protocol_version); - os2<= 2) writeU8(os, (priv) ? 1 : 0); } @@ -63,8 +63,8 @@ void NodeMetadata::deSerialize(std::istream &is, u8 version) clear(); int num_vars = readU32(is); for(int i=0; i= 2) { if (readU8(is) == 1) diff --git a/src/object_properties.cpp b/src/object_properties.cpp index 8d51bcbfa..c31c667e7 100644 --- a/src/object_properties.cpp +++ b/src/object_properties.cpp @@ -84,11 +84,11 @@ void ObjectProperties::serialize(std::ostream &os) const writeV3F32(os, selectionbox.MinEdge); writeV3F32(os, selectionbox.MaxEdge); writeU8(os, pointable); - os << serializeString(visual); + os << serializeString16(visual); writeV3F32(os, visual_size); writeU16(os, textures.size()); for (const std::string &texture : textures) { - os << serializeString(texture); + os << serializeString16(texture); } writeV2S16(os, spritediv); writeV2S16(os, initial_sprite_basepos); @@ -96,7 +96,7 @@ void ObjectProperties::serialize(std::ostream &os) const writeU8(os, makes_footstep_sound); writeF32(os, automatic_rotate); // Added in protocol version 14 - os << serializeString(mesh); + os << serializeString16(mesh); writeU16(os, colors.size()); for (video::SColor color : colors) { writeARGB8(os, color); @@ -106,17 +106,17 @@ void ObjectProperties::serialize(std::ostream &os) const writeU8(os, automatic_face_movement_dir); writeF32(os, automatic_face_movement_dir_offset); writeU8(os, backface_culling); - os << serializeString(nametag); + os << serializeString16(nametag); writeARGB8(os, nametag_color); writeF32(os, automatic_face_movement_max_rotation_per_sec); - os << serializeString(infotext); - os << serializeString(wield_item); + os << serializeString16(infotext); + os << serializeString16(wield_item); writeS8(os, glow); writeU16(os, breath_max); writeF32(os, eye_height); writeF32(os, zoom_fov); writeU8(os, use_texture_alpha); - os << serializeString(damage_texture_modifier); + os << serializeString16(damage_texture_modifier); writeU8(os, shaded); // Add stuff only at the bottom. @@ -137,19 +137,19 @@ void ObjectProperties::deSerialize(std::istream &is) selectionbox.MinEdge = readV3F32(is); selectionbox.MaxEdge = readV3F32(is); pointable = readU8(is); - visual = deSerializeString(is); + visual = deSerializeString16(is); visual_size = readV3F32(is); textures.clear(); u32 texture_count = readU16(is); for (u32 i = 0; i < texture_count; i++){ - textures.push_back(deSerializeString(is)); + textures.push_back(deSerializeString16(is)); } spritediv = readV2S16(is); initial_sprite_basepos = readV2S16(is); is_visible = readU8(is); makes_footstep_sound = readU8(is); automatic_rotate = readF32(is); - mesh = deSerializeString(is); + mesh = deSerializeString16(is); colors.clear(); u32 color_count = readU16(is); for (u32 i = 0; i < color_count; i++){ @@ -160,18 +160,18 @@ void ObjectProperties::deSerialize(std::istream &is) automatic_face_movement_dir = readU8(is); automatic_face_movement_dir_offset = readF32(is); backface_culling = readU8(is); - nametag = deSerializeString(is); + nametag = deSerializeString16(is); nametag_color = readARGB8(is); automatic_face_movement_max_rotation_per_sec = readF32(is); - infotext = deSerializeString(is); - wield_item = deSerializeString(is); + infotext = deSerializeString16(is); + wield_item = deSerializeString16(is); glow = readS8(is); breath_max = readU16(is); eye_height = readF32(is); zoom_fov = readF32(is); use_texture_alpha = readU8(is); try { - damage_texture_modifier = deSerializeString(is); + damage_texture_modifier = deSerializeString16(is); u8 tmp = readU8(is); if (is.eof()) throw SerializationError(""); diff --git a/src/particles.cpp b/src/particles.cpp index fd81238dc..14c987958 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -28,7 +28,7 @@ void ParticleParameters::serialize(std::ostream &os, u16 protocol_ver) const writeF32(os, expirationtime); writeF32(os, size); writeU8(os, collisiondetection); - os << serializeLongString(texture); + os << serializeString32(texture); writeU8(os, vertical); writeU8(os, collision_removal); animation.serialize(os, 6); /* NOT the protocol ver */ @@ -47,7 +47,7 @@ void ParticleParameters::deSerialize(std::istream &is, u16 protocol_ver) expirationtime = readF32(is); size = readF32(is); collisiondetection = readU8(is); - texture = deSerializeLongString(is); + texture = deSerializeString32(is); vertical = readU8(is); collision_removal = readU8(is); animation.deSerialize(is, 6); /* NOT the protocol ver */ diff --git a/src/server.cpp b/src/server.cpp index d40ff259f..982f904f4 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -802,7 +802,7 @@ void Server::AsyncRunStep(bool initial_step) // u16 id // std::string data buffer.append(idbuf, sizeof(idbuf)); - buffer.append(serializeString(aom.datastring)); + buffer.append(serializeString16(aom.datastring)); } } /* @@ -1993,7 +1993,7 @@ void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersa writeU8((u8*)buf, type); data.append(buf, 1); - data.append(serializeLongString( + data.append(serializeString32( obj->getClientInitializationData(client->net_proto_version))); // Add to known objects diff --git a/src/server/luaentity_sao.cpp b/src/server/luaentity_sao.cpp index d504c42ca..f20914f7f 100644 --- a/src/server/luaentity_sao.cpp +++ b/src/server/luaentity_sao.cpp @@ -42,8 +42,8 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, const std::string &d u8 version2 = 0; u8 version = readU8(is); - name = deSerializeString(is); - state = deSerializeLongString(is); + name = deSerializeString16(is); + state = deSerializeString32(is); if (version < 1) break; @@ -225,7 +225,7 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) // PROTOCOL_VERSION >= 37 writeU8(os, 1); // version - os << serializeString(""); // name + os << serializeString16(""); // name writeU8(os, 0); // is_player writeU16(os, getId()); //id writeV3F32(os, m_base_position); @@ -233,26 +233,26 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) writeU16(os, m_hp); std::ostringstream msg_os(std::ios::binary); - msg_os << serializeLongString(getPropertyPacket()); // message 1 - msg_os << serializeLongString(generateUpdateArmorGroupsCommand()); // 2 - msg_os << serializeLongString(generateUpdateAnimationCommand()); // 3 + msg_os << serializeString32(getPropertyPacket()); // message 1 + msg_os << serializeString32(generateUpdateArmorGroupsCommand()); // 2 + msg_os << serializeString32(generateUpdateAnimationCommand()); // 3 for (const auto &bone_pos : m_bone_position) { - msg_os << serializeLongString(generateUpdateBonePositionCommand( + msg_os << serializeString32(generateUpdateBonePositionCommand( bone_pos.first, bone_pos.second.X, bone_pos.second.Y)); // m_bone_position.size } - msg_os << serializeLongString(generateUpdateAttachmentCommand()); // 4 + msg_os << serializeString32(generateUpdateAttachmentCommand()); // 4 int message_count = 4 + m_bone_position.size(); for (const auto &id : getAttachmentChildIds()) { if (ServerActiveObject *obj = m_env->getActiveObject(id)) { message_count++; - msg_os << serializeLongString(obj->generateUpdateInfantCommand( + msg_os << serializeString32(obj->generateUpdateInfantCommand( id, protocol_version)); } } - msg_os << serializeLongString(generateSetTextureModCommand()); + msg_os << serializeString32(generateSetTextureModCommand()); message_count++; writeU8(os, message_count); @@ -270,14 +270,14 @@ void LuaEntitySAO::getStaticData(std::string *result) const // version must be 1 to keep backwards-compatibility. See version2 writeU8(os, 1); // name - os<getScriptIface()-> luaentity_GetStaticdata(m_id); - os<= 15 writeU8(os, 1); // version - os << serializeString(m_player->getName()); // name + os << serializeString16(m_player->getName()); // name writeU8(os, 1); // is_player writeS16(os, getId()); // id writeV3F32(os, m_base_position); @@ -117,22 +117,22 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version) writeU16(os, getHP()); std::ostringstream msg_os(std::ios::binary); - msg_os << serializeLongString(getPropertyPacket()); // message 1 - msg_os << serializeLongString(generateUpdateArmorGroupsCommand()); // 2 - msg_os << serializeLongString(generateUpdateAnimationCommand()); // 3 + msg_os << serializeString32(getPropertyPacket()); // message 1 + msg_os << serializeString32(generateUpdateArmorGroupsCommand()); // 2 + msg_os << serializeString32(generateUpdateAnimationCommand()); // 3 for (const auto &bone_pos : m_bone_position) { - msg_os << serializeLongString(generateUpdateBonePositionCommand( + msg_os << serializeString32(generateUpdateBonePositionCommand( bone_pos.first, bone_pos.second.X, bone_pos.second.Y)); // m_bone_position.size } - msg_os << serializeLongString(generateUpdateAttachmentCommand()); // 4 - msg_os << serializeLongString(generateUpdatePhysicsOverrideCommand()); // 5 + msg_os << serializeString32(generateUpdateAttachmentCommand()); // 4 + msg_os << serializeString32(generateUpdatePhysicsOverrideCommand()); // 5 int message_count = 5 + m_bone_position.size(); for (const auto &id : getAttachmentChildIds()) { if (ServerActiveObject *obj = m_env->getActiveObject(id)) { message_count++; - msg_os << serializeLongString(obj->generateUpdateInfantCommand( + msg_os << serializeString32(obj->generateUpdateInfantCommand( id, protocol_version)); } } diff --git a/src/server/serveractiveobject.cpp b/src/server/serveractiveobject.cpp index 3341dc008..8cb59b2d6 100644 --- a/src/server/serveractiveobject.cpp +++ b/src/server/serveractiveobject.cpp @@ -61,7 +61,7 @@ std::string ServerActiveObject::generateUpdateInfantCommand(u16 infant_id, u16 p // Clients since 4aa9a66 so no longer need this data // Version 38 is the first bump after that commit. // See also: ClientEnvironment::addActiveObject - os << serializeLongString(getClientInitializationData(protocol_version)); + os << serializeString32(getClientInitializationData(protocol_version)); } return os.str(); } diff --git a/src/server/unit_sao.cpp b/src/server/unit_sao.cpp index ef0e87f2c..d906e885e 100644 --- a/src/server/unit_sao.cpp +++ b/src/server/unit_sao.cpp @@ -242,7 +242,7 @@ std::string UnitSAO::generateUpdateAttachmentCommand() const writeU8(os, AO_CMD_ATTACH_TO); // parameters writeS16(os, m_attachment_parent_id); - os << serializeString(m_attachment_bone); + os << serializeString16(m_attachment_bone); writeV3F32(os, m_attachment_position); writeV3F32(os, m_attachment_rotation); return os.str(); @@ -255,7 +255,7 @@ std::string UnitSAO::generateUpdateBonePositionCommand( // command writeU8(os, AO_CMD_SET_BONE_POSITION); // parameters - os << serializeString(bone); + os << serializeString16(bone); writeV3F32(os, position); writeV3F32(os, rotation); return os.str(); @@ -291,7 +291,7 @@ std::string UnitSAO::generateUpdateArmorGroupsCommand() const writeU8(os, AO_CMD_UPDATE_ARMOR_GROUPS); writeU16(os, m_armor_groups.size()); for (const auto &armor_group : m_armor_groups) { - os << serializeString(armor_group.first); + os << serializeString16(armor_group.first); writeS16(os, armor_group.second); } return os.str(); diff --git a/src/sound.h b/src/sound.h index 6cbd55e8f..6f7b0a1af 100644 --- a/src/sound.h +++ b/src/sound.h @@ -39,7 +39,7 @@ struct SimpleSoundSpec // keep in sync with item definitions void serialize(std::ostream &os, u8 cf_version) const { - os << serializeString(name); + os << serializeString16(name); writeF32(os, gain); writeF32(os, pitch); writeF32(os, fade); @@ -49,7 +49,7 @@ struct SimpleSoundSpec void deSerialize(std::istream &is, u8 cf_version) { - name = deSerializeString(is); + name = deSerializeString16(is); gain = readF32(is); pitch = readF32(is); fade = readF32(is); diff --git a/src/staticobject.cpp b/src/staticobject.cpp index 5ccb7baf5..86e455b9f 100644 --- a/src/staticobject.cpp +++ b/src/staticobject.cpp @@ -35,7 +35,7 @@ void StaticObject::serialize(std::ostream &os) // pos writeV3F1000(os, pos); // data - os<uses); writeS16(os, cap->maxlevel); writeU32(os, cap->times.size()); @@ -79,7 +79,7 @@ void ToolCapabilities::serialize(std::ostream &os, u16 protocol_version) const writeU32(os, damageGroups.size()); for (const auto &damageGroup : damageGroups) { - os << serializeString(damageGroup.first); + os << serializeString16(damageGroup.first); writeS16(os, damageGroup.second); } @@ -98,7 +98,7 @@ void ToolCapabilities::deSerialize(std::istream &is) groupcaps.clear(); u32 groupcaps_size = readU32(is); for (u32 i = 0; i < groupcaps_size; i++) { - std::string name = deSerializeString(is); + std::string name = deSerializeString16(is); ToolGroupCap cap; cap.uses = readS16(is); cap.maxlevel = readS16(is); @@ -113,7 +113,7 @@ void ToolCapabilities::deSerialize(std::istream &is) u32 damage_groups_size = readU32(is); for (u32 i = 0; i < damage_groups_size; i++) { - std::string name = deSerializeString(is); + std::string name = deSerializeString16(is); s16 rating = readS16(is); damageGroups[name] = rating; } diff --git a/src/unittest/test_serialization.cpp b/src/unittest/test_serialization.cpp index d72bf0d4c..660d77d02 100644 --- a/src/unittest/test_serialization.cpp +++ b/src/unittest/test_serialization.cpp @@ -44,7 +44,7 @@ public: std::wstring teststring2_w; std::string teststring2_w_encoded; - static const u8 test_serialized_data[12 * 13 - 8]; + static const u8 test_serialized_data[12 * 11 - 2]; }; static TestSerialization g_test_instance; @@ -91,21 +91,21 @@ void TestSerialization::buildTestStrings() void TestSerialization::testSerializeString() { // Test blank string - UASSERT(serializeString("") == mkstr("\0\0")); + UASSERT(serializeString16("") == mkstr("\0\0")); // Test basic string - UASSERT(serializeString("Hello world!") == mkstr("\0\14Hello world!")); + UASSERT(serializeString16("Hello world!") == mkstr("\0\14Hello world!")); // Test character range - UASSERT(serializeString(teststring2) == mkstr("\1\0") + teststring2); + UASSERT(serializeString16(teststring2) == mkstr("\1\0") + teststring2); } void TestSerialization::testDeSerializeString() { // Test deserialize { - std::istringstream is(serializeString(teststring2), std::ios::binary); - UASSERT(deSerializeString(is) == teststring2); + std::istringstream is(serializeString16(teststring2), std::ios::binary); + UASSERT(deSerializeString16(is) == teststring2); UASSERT(!is.eof()); is.get(); UASSERT(is.eof()); @@ -114,34 +114,34 @@ void TestSerialization::testDeSerializeString() // Test deserialize an incomplete length specifier { std::istringstream is(mkstr("\x53"), std::ios::binary); - EXCEPTION_CHECK(SerializationError, deSerializeString(is)); + EXCEPTION_CHECK(SerializationError, deSerializeString16(is)); } // Test deserialize a string with incomplete data { std::istringstream is(mkstr("\x00\x55 abcdefg"), std::ios::binary); - EXCEPTION_CHECK(SerializationError, deSerializeString(is)); + EXCEPTION_CHECK(SerializationError, deSerializeString16(is)); } } void TestSerialization::testSerializeLongString() { // Test blank string - UASSERT(serializeLongString("") == mkstr("\0\0\0\0")); + UASSERT(serializeString32("") == mkstr("\0\0\0\0")); // Test basic string - UASSERT(serializeLongString("Hello world!") == mkstr("\0\0\0\14Hello world!")); + UASSERT(serializeString32("Hello world!") == mkstr("\0\0\0\14Hello world!")); // Test character range - UASSERT(serializeLongString(teststring2) == mkstr("\0\0\1\0") + teststring2); + UASSERT(serializeString32(teststring2) == mkstr("\0\0\1\0") + teststring2); } void TestSerialization::testDeSerializeLongString() { // Test deserialize { - std::istringstream is(serializeLongString(teststring2), std::ios::binary); - UASSERT(deSerializeLongString(is) == teststring2); + std::istringstream is(serializeString32(teststring2), std::ios::binary); + UASSERT(deSerializeString32(is) == teststring2); UASSERT(!is.eof()); is.get(); UASSERT(is.eof()); @@ -150,19 +150,19 @@ void TestSerialization::testDeSerializeLongString() // Test deserialize an incomplete length specifier { std::istringstream is(mkstr("\x53"), std::ios::binary); - EXCEPTION_CHECK(SerializationError, deSerializeLongString(is)); + EXCEPTION_CHECK(SerializationError, deSerializeString32(is)); } // Test deserialize a string with incomplete data { std::istringstream is(mkstr("\x00\x00\x00\x05 abc"), std::ios::binary); - EXCEPTION_CHECK(SerializationError, deSerializeLongString(is)); + EXCEPTION_CHECK(SerializationError, deSerializeString32(is)); } // Test deserialize a string with a length too large { std::istringstream is(mkstr("\xFF\xFF\xFF\xFF blah"), std::ios::binary); - EXCEPTION_CHECK(SerializationError, deSerializeLongString(is)); + EXCEPTION_CHECK(SerializationError, deSerializeString32(is)); } } @@ -235,19 +235,17 @@ void TestSerialization::testStreamRead() UASSERT(readF1000(is) == F1000_MIN); UASSERT(readF1000(is) == F1000_MAX); - UASSERT(deSerializeString(is) == "foobar!"); + UASSERT(deSerializeString16(is) == "foobar!"); UASSERT(readV2S16(is) == v2s16(500, 500)); UASSERT(readV3S16(is) == v3s16(4207, 604, -30)); UASSERT(readV2S32(is) == v2s32(1920, 1080)); UASSERT(readV3S32(is) == v3s32(-400, 6400054, 290549855)); - UASSERT(deSerializeWideString(is) == L"\x02~woof~\x5455"); - UASSERT(readV3F1000(is) == v3f(500, 10024.2f, -192.54f)); UASSERT(readARGB8(is) == video::SColor(255, 128, 50, 128)); - UASSERT(deSerializeLongString(is) == "some longer string here"); + UASSERT(deSerializeString32(is) == "some longer string here"); UASSERT(is.rdbuf()->in_avail() == 2); UASSERT(readU16(is) == 0xF00D); @@ -275,7 +273,7 @@ void TestSerialization::testStreamWrite() writeF1000(os, F1000_MIN); writeF1000(os, F1000_MAX); - os << serializeString("foobar!"); + os << serializeString16("foobar!"); data = os.str(); UASSERT(data.size() < sizeof(test_serialized_data)); @@ -286,12 +284,10 @@ void TestSerialization::testStreamWrite() writeV2S32(os, v2s32(1920, 1080)); writeV3S32(os, v3s32(-400, 6400054, 290549855)); - os << serializeWideString(L"\x02~woof~\x5455"); - writeV3F1000(os, v3f(500, 10024.2f, -192.54f)); writeARGB8(os, video::SColor(255, 128, 50, 128)); - os << serializeLongString("some longer string here"); + os << serializeString32("some longer string here"); writeU16(os, 0xF00D); @@ -384,7 +380,7 @@ void TestSerialization::testFloatFormat() UASSERT(test_single(i)); } -const u8 TestSerialization::test_serialized_data[12 * 13 - 8] = { +const u8 TestSerialization::test_serialized_data[12 * 11 - 2] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x80, 0x75, 0x30, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd5, 0x00, 0x00, 0xd1, 0x1e, 0xee, 0x1e, @@ -392,9 +388,7 @@ const u8 TestSerialization::test_serialized_data[12 * 13 - 8] = { 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x21, 0x01, 0xf4, 0x01, 0xf4, 0x10, 0x6f, 0x02, 0x5c, 0xff, 0xe2, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x04, 0x38, 0xff, 0xff, 0xfe, 0x70, 0x00, 0x61, 0xa8, 0x36, 0x11, 0x51, 0x70, - 0x5f, 0x00, 0x08, 0x00, - 0x02, 0x00, 0x7e, 0x00, 'w', 0x00, 'o', 0x00, 'o', 0x00, 'f', 0x00, // \x02~woof~\x5455 - 0x7e, 0x54, 0x55, 0x00, 0x07, 0xa1, 0x20, 0x00, 0x98, 0xf5, 0x08, 0xff, + 0x5f, 0x00, 0x07, 0xa1, 0x20, 0x00, 0x98, 0xf5, 0x08, 0xff, 0xfd, 0x0f, 0xe4, 0xff, 0x80, 0x32, 0x80, 0x00, 0x00, 0x00, 0x17, 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x68, 0x65, 0x72, 0x65, 0xF0, 0x0D, diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp index fd5cbda21..d770101f2 100644 --- a/src/util/serialize.cpp +++ b/src/util/serialize.cpp @@ -35,13 +35,13 @@ FloatType g_serialize_f32_type = FLOATTYPE_UNKNOWN; //// String //// -std::string serializeString(const std::string &plain) +std::string serializeString16(const std::string &plain) { std::string s; char buf[2]; if (plain.size() > STRING_MAX_LEN) - throw SerializationError("String too long for serializeString"); + throw SerializationError("String too long for serializeString16"); s.reserve(2 + plain.size()); writeU16((u8 *)&buf[0], plain.size()); @@ -51,14 +51,14 @@ std::string serializeString(const std::string &plain) return s; } -std::string deSerializeString(std::istream &is) +std::string deSerializeString16(std::istream &is) { std::string s; char buf[2]; is.read(buf, 2); if (is.gcount() != 2) - throw SerializationError("deSerializeString: size not read"); + throw SerializationError("deSerializeString16: size not read"); u16 s_size = readU16((u8 *)buf); if (s_size == 0) @@ -67,66 +67,17 @@ std::string deSerializeString(std::istream &is) s.resize(s_size); is.read(&s[0], s_size); if (is.gcount() != s_size) - throw SerializationError("deSerializeString: couldn't read all chars"); + throw SerializationError("deSerializeString16: couldn't read all chars"); return s; } -//// -//// Wide String -//// - -std::string serializeWideString(const std::wstring &plain) -{ - std::string s; - char buf[2]; - - if (plain.size() > WIDE_STRING_MAX_LEN) - throw SerializationError("String too long for serializeWideString"); - s.reserve(2 + 2 * plain.size()); - - writeU16((u8 *)buf, plain.size()); - s.append(buf, 2); - - for (wchar_t i : plain) { - writeU16((u8 *)buf, i); - s.append(buf, 2); - } - return s; -} - -std::wstring deSerializeWideString(std::istream &is) -{ - std::wstring s; - char buf[2]; - - is.read(buf, 2); - if (is.gcount() != 2) - throw SerializationError("deSerializeWideString: size not read"); - - u16 s_size = readU16((u8 *)buf); - if (s_size == 0) - return s; - - s.reserve(s_size); - for (u32 i = 0; i < s_size; i++) { - is.read(&buf[0], 2); - if (is.gcount() != 2) { - throw SerializationError( - "deSerializeWideString: couldn't read all chars"); - } - - wchar_t c16 = readU16((u8 *)buf); - s.append(&c16, 1); - } - return s; -} //// //// Long String //// -std::string serializeLongString(const std::string &plain) +std::string serializeString32(const std::string &plain) { std::string s; char buf[4]; @@ -141,7 +92,7 @@ std::string serializeLongString(const std::string &plain) return s; } -std::string deSerializeLongString(std::istream &is) +std::string deSerializeString32(std::istream &is) { std::string s; char buf[4]; diff --git a/src/util/serialize.h b/src/util/serialize.h index a988a8f78..b3ec28eab 100644 --- a/src/util/serialize.h +++ b/src/util/serialize.h @@ -440,16 +440,16 @@ MAKE_STREAM_WRITE_FXN(video::SColor, ARGB8, 4); //// // Creates a string with the length as the first two bytes -std::string serializeString(const std::string &plain); +std::string serializeString16(const std::string &plain); // Reads a string with the length as the first two bytes -std::string deSerializeString(std::istream &is); +std::string deSerializeString16(std::istream &is); // Creates a string with the length as the first four bytes -std::string serializeLongString(const std::string &plain); +std::string serializeString32(const std::string &plain); // Reads a string with the length as the first four bytes -std::string deSerializeLongString(std::istream &is); +std::string deSerializeString32(std::istream &is); // Creates a string encoded in JSON format (almost equivalent to a C string literal) std::string serializeJsonString(const std::string &plain); -- cgit v1.2.3 From 81c66d6efb9fb0ab8a03b40e2bc22aa49eff9a04 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Rollo Date: Sun, 4 Oct 2020 15:24:29 +0200 Subject: Minimap as HUD element with API control Features: * Define Minimap available modes (surface/radar, scale) from Lua, using player:set_minimap_modes() * New HUD elements for displaying minimap with custom size and placing * New minimap mode for displaying a texture instead of the map --- doc/lua_api.txt | 33 ++++- src/client/client.cpp | 1 + src/client/client.h | 1 + src/client/game.cpp | 75 +++++------- src/client/hud.cpp | 30 ++++- src/client/hud.h | 2 + src/client/mapblock_mesh.cpp | 2 +- src/client/minimap.cpp | 237 +++++++++++++++++++++++++++--------- src/client/minimap.h | 41 ++++--- src/hud.cpp | 1 + src/hud.h | 13 +- src/network/clientopcodes.cpp | 1 + src/network/clientpackethandler.cpp | 46 ++++++- src/network/networkprotocol.h | 14 ++- src/network/serveropcodes.cpp | 1 + src/script/lua_api/l_minimap.cpp | 24 ++-- src/script/lua_api/l_object.cpp | 62 ++++++++++ src/script/lua_api/l_object.h | 3 + src/server.cpp | 17 +++ src/server.h | 12 ++ 20 files changed, 471 insertions(+), 145 deletions(-) (limited to 'src/server.cpp') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 77fb4a654..9e9af20da 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1484,6 +1484,15 @@ Displays an image oriented or translated according to current heading direction. If translation is chosen, texture is repeated horizontally to fill the whole element. +### `minimap` + +Displays a minimap on the HUD. + +* `size`: Size of the minimap to display. Minimap should be a square to avoid + distortion. +* `alignment`: The alignment of the minimap. +* `offset`: offset in pixels from position. + Representations of simple things ================================ @@ -6366,6 +6375,27 @@ object you are working with still exists. * `hud_set_hotbar_selected_image(texturename)` * sets image for selected item of hotbar * `hud_get_hotbar_selected_image`: returns texturename +* `set_minimap_modes({mode, mode, ...}, selected_mode)` + * Overrides the available minimap modes (and toggle order), and changes the + selected mode. + * `mode` is a table consisting of up to four fields: + * `type`: Available type: + * `off`: Minimap off + * `surface`: Minimap in surface mode + * `radar`: Minimap in radar mode + * `texture`: Texture to be displayed instead of terrain map + (texture is centered around 0,0 and can be scaled). + Texture size is limited to 512 x 512 pixel. + * `label`: Optional label to display on minimap mode toggle + The translation must be handled within the mod. + * `size`: Sidelength or diameter, in number of nodes, of the terrain + displayed in minimap + * `texture`: Only for texture type, name of the texture to display + * `scale`: Only for texture type, scale of the texture map in nodes per + pixel (for example a `scale` of 2 means each pixel represents a 2x2 + nodes square) + * `selected_mode` is the mode index to be selected after modes have been changed + (0 is the first mode). * `set_sky(parameters)` * `parameters` is a table with the following optional fields: * `base_color`: ColorSpec, changes fog in "skybox" and "plain". @@ -8047,7 +8077,8 @@ Used by `Player:hud_add`. Returned by `Player:hud_get`. { hud_elem_type = "image", -- See HUD element types - -- Type of element, can be "image", "text", "statbar", "inventory" or "compass" + -- Type of element, can be "image", "text", "statbar", "inventory", + -- "compass" or "minimap" position = {x=0.5, y=0.5}, -- Left corner position of element diff --git a/src/client/client.cpp b/src/client/client.cpp index d6e529c40..7fafe0da9 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -129,6 +129,7 @@ Client::Client( if (g_settings->getBool("enable_minimap")) { m_minimap = new Minimap(this); } + m_cache_save_interval = g_settings->getU16("server_map_save_interval"); } diff --git a/src/client/client.h b/src/client/client.h index 733634db1..8f4aac6e3 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -223,6 +223,7 @@ public: void handleCommand_CSMRestrictionFlags(NetworkPacket *pkt); void handleCommand_PlayerSpeed(NetworkPacket *pkt); void handleCommand_MediaPush(NetworkPacket *pkt); + void handleCommand_MinimapModes(NetworkPacket *pkt); void ProcessData(NetworkPacket *pkt); diff --git a/src/client/game.cpp b/src/client/game.cpp index 366464467..54e0c9f20 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1416,11 +1416,9 @@ bool Game::createClient(const GameStartData &start_data) } mapper = client->getMinimap(); - if (mapper) { - mapper->setMinimapMode(MINIMAP_MODE_OFF); - if (client->modsLoaded()) - client->getScript()->on_minimap_ready(mapper); - } + + if (mapper && client->modsLoaded()) + client->getScript()->on_minimap_ready(mapper); return true; } @@ -2222,52 +2220,37 @@ void Game::toggleMinimap(bool shift_pressed) if (!mapper || !m_game_ui->m_flags.show_hud || !g_settings->getBool("enable_minimap")) return; - if (shift_pressed) { + if (shift_pressed) mapper->toggleMinimapShape(); - return; - } + else + mapper->nextMode(); + + // TODO: When legacy minimap is deprecated, keep only HUD minimap stuff here + // Not so satisying code to keep compatibility with old fixed mode system + // --> u32 hud_flags = client->getEnv().getLocalPlayer()->hud_flags; - MinimapMode mode = MINIMAP_MODE_OFF; - if (hud_flags & HUD_FLAG_MINIMAP_VISIBLE) { - mode = mapper->getMinimapMode(); - mode = (MinimapMode)((int)mode + 1); - // If radar is disabled and in, or switching to, radar mode - if (!(hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE) && mode > 3) - mode = MINIMAP_MODE_OFF; - } + if (!(hud_flags & HUD_FLAG_MINIMAP_VISIBLE)) { + m_game_ui->m_flags.show_minimap = false; + } else { - m_game_ui->m_flags.show_minimap = true; - switch (mode) { - case MINIMAP_MODE_SURFACEx1: - m_game_ui->showTranslatedStatusText("Minimap in surface mode, Zoom x1"); - break; - case MINIMAP_MODE_SURFACEx2: - m_game_ui->showTranslatedStatusText("Minimap in surface mode, Zoom x2"); - break; - case MINIMAP_MODE_SURFACEx4: - m_game_ui->showTranslatedStatusText("Minimap in surface mode, Zoom x4"); - break; - case MINIMAP_MODE_RADARx1: - m_game_ui->showTranslatedStatusText("Minimap in radar mode, Zoom x1"); - break; - case MINIMAP_MODE_RADARx2: - m_game_ui->showTranslatedStatusText("Minimap in radar mode, Zoom x2"); - break; - case MINIMAP_MODE_RADARx4: - m_game_ui->showTranslatedStatusText("Minimap in radar mode, Zoom x4"); - break; - default: - mode = MINIMAP_MODE_OFF; - m_game_ui->m_flags.show_minimap = false; - if (hud_flags & HUD_FLAG_MINIMAP_VISIBLE) - m_game_ui->showTranslatedStatusText("Minimap hidden"); - else - m_game_ui->showTranslatedStatusText("Minimap currently disabled by game or mod"); - } + // If radar is disabled, try to find a non radar mode or fall back to 0 + if (!(hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE)) + while (mapper->getModeIndex() && + mapper->getModeDef().type == MINIMAP_TYPE_RADAR) + mapper->nextMode(); - mapper->setMinimapMode(mode); + m_game_ui->m_flags.show_minimap = mapper->getModeDef().type != + MINIMAP_TYPE_OFF; + } + // <-- + // End of 'not so satifying code' + if ((hud_flags & HUD_FLAG_MINIMAP_VISIBLE) || + (hud && hud->hasElementOfType(HUD_ELEM_MINIMAP))) + m_game_ui->showStatusText(utf8_to_wide(mapper->getModeDef().label)); + else + m_game_ui->showTranslatedStatusText("Minimap currently disabled by game or mod"); } void Game::toggleFog() @@ -3954,7 +3937,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, /* Update minimap pos and rotation */ - if (mapper && m_game_ui->m_flags.show_minimap && m_game_ui->m_flags.show_hud) { + if (mapper && m_game_ui->m_flags.show_hud) { mapper->setPos(floatToInt(player->getPosition(), BS)); mapper->setAngle(player->getYaw()); } diff --git a/src/client/hud.cpp b/src/client/hud.cpp index d3038230c..f6497fe25 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mesh.h" #include "wieldmesh.h" #include "client/renderingengine.h" +#include "client/minimap.h" #ifdef HAVE_TOUCHSCREENGUI #include "gui/touchscreengui.h" @@ -297,6 +298,18 @@ void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount, } } +bool Hud::hasElementOfType(HudElementType type) +{ + for (size_t i = 0; i != player->maxHudId(); i++) { + HudElement *e = player->getHud(i); + if (!e) + continue; + if (e->type == type) + return true; + } + return false; +} + // Calculates screen position of waypoint. Returns true if waypoint is visible (in front of the player), else false. bool Hud::calculateScreenPos(const v3s16 &camera_offset, HudElement *e, v2s32 *pos) { @@ -491,7 +504,22 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) default: break; } - + break; } + case HUD_ELEM_MINIMAP: { + if (e->size.X <= 0 || e->size.Y <= 0) + break; + if (!client->getMinimap()) + break; + // Draw a minimap of size "size" + v2s32 dstsize(e->size.X * m_scale_factor, + e->size.Y * m_scale_factor); + // (no percent size as minimap would likely be anamorphosed) + v2s32 offset((e->align.X - 1.0) * dstsize.X / 2, + (e->align.Y - 1.0) * dstsize.Y / 2); + core::rect rect(0, 0, dstsize.X, dstsize.Y); + rect += pos + offset + v2s32(e->offset.X * m_scale_factor, + e->offset.Y * m_scale_factor); + client->getMinimap()->drawMinimap(rect); break; } default: infostream << "Hud::drawLuaElements: ignoring drawform " << e->type << diff --git a/src/client/hud.h b/src/client/hud.h index cf83cb16e..d46545d71 100644 --- a/src/client/hud.h +++ b/src/client/hud.h @@ -81,6 +81,8 @@ public: m_selected_face_normal = face_normal; } + bool hasElementOfType(HudElementType type); + void drawLuaElements(const v3s16 &camera_offset); private: diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 2f96ca61f..b59679523 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -1044,7 +1044,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): m_use_tangent_vertices = data->m_use_tangent_vertices; m_enable_vbo = g_settings->getBool("enable_vbo"); - if (g_settings->getBool("enable_minimap")) { + if (data->m_client->getMinimap()) { m_minimap_mapblock = new MinimapMapblock; m_minimap_mapblock->getMinimapNodes( &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE); diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index 68770ec19..6bae408b4 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "shader.h" #include "mapblock.h" #include "client/renderingengine.h" - +#include "gettext.h" //// //// MinimapUpdateThread @@ -108,8 +108,11 @@ void MinimapUpdateThread::doUpdate() } } - if (data->map_invalidated && data->mode != MINIMAP_MODE_OFF) { - getMap(data->pos, data->map_size, data->scan_height); + + if (data->map_invalidated && ( + data->mode.type == MINIMAP_TYPE_RADAR || + data->mode.type == MINIMAP_TYPE_SURFACE)) { + getMap(data->pos, data->mode.map_size, data->mode.scan_height); data->map_invalidated = false; } } @@ -181,19 +184,26 @@ Minimap::Minimap(Client *client) this->m_ndef = client->getNodeDefManager(); m_angle = 0.f; + m_current_mode_index = 0; // Initialize static settings m_enable_shaders = g_settings->getBool("enable_shaders"); m_surface_mode_scan_height = g_settings->getBool("minimap_double_scan_height") ? 256 : 128; + // Initialize minimap modes + addMode(MINIMAP_TYPE_OFF); + addMode(MINIMAP_TYPE_SURFACE, 256); + addMode(MINIMAP_TYPE_SURFACE, 128); + addMode(MINIMAP_TYPE_SURFACE, 64); + addMode(MINIMAP_TYPE_RADAR, 512); + addMode(MINIMAP_TYPE_RADAR, 256); + addMode(MINIMAP_TYPE_RADAR, 128); + // Initialize minimap data data = new MinimapData; - data->mode = MINIMAP_MODE_OFF; - data->is_radar = false; - data->map_invalidated = true; - data->texture = NULL; - data->heightmap_texture = NULL; + data->map_invalidated = true; + data->minimap_shape_round = g_settings->getBool("minimap_shape_round"); // Get round minimap textures @@ -215,6 +225,8 @@ Minimap::Minimap(Client *client) // Create object marker texture data->object_marker_red = m_tsrc->getTexture("object_marker_red.png"); + setModeIndex(0); + // Create mesh buffer for minimap m_meshbuffer = getMinimapMeshBuffer(); @@ -280,29 +292,101 @@ MinimapShape Minimap::getMinimapShape() return MINIMAP_SHAPE_SQUARE; } -void Minimap::setMinimapMode(MinimapMode mode) +void Minimap::setModeIndex(size_t index) { - static const MinimapModeDef modedefs[MINIMAP_MODE_COUNT] = { - {false, 0, 0}, - {false, m_surface_mode_scan_height, 256}, - {false, m_surface_mode_scan_height, 128}, - {false, m_surface_mode_scan_height, 64}, - {true, 32, 128}, - {true, 32, 64}, - {true, 32, 32} - }; - - if (mode >= MINIMAP_MODE_COUNT) - return; - MutexAutoLock lock(m_mutex); - data->is_radar = modedefs[mode].is_radar; - data->scan_height = modedefs[mode].scan_height; - data->map_size = modedefs[mode].map_size; - data->mode = mode; + if (index < m_modes.size()) { + data->mode = m_modes[index]; + m_current_mode_index = index; + } else { + data->mode = MinimapModeDef{MINIMAP_TYPE_OFF, N_("Minimap hidden"), 0, 0, ""}; + m_current_mode_index = 0; + } + + data->map_invalidated = true; - m_minimap_update_thread->deferUpdate(); + if (m_minimap_update_thread) + m_minimap_update_thread->deferUpdate(); +} + +void Minimap::addMode(MinimapModeDef mode) +{ + // Check validity + if (mode.type == MINIMAP_TYPE_TEXTURE) { + if (mode.texture.empty()) + return; + if (mode.scale < 1) + mode.scale = 1; + } + + int zoom = -1; + + // Build a default standard label + if (mode.label == "") { + switch (mode.type) { + case MINIMAP_TYPE_OFF: + mode.label = N_("Minimap hidden"); + break; + case MINIMAP_TYPE_SURFACE: + mode.label = N_("Minimap in surface mode, Zoom x%d"); + if (mode.map_size > 0) + zoom = 256 / mode.map_size; + break; + case MINIMAP_TYPE_RADAR: + mode.label = N_("Minimap in radar mode, Zoom x%d"); + if (mode.map_size > 0) + zoom = 512 / mode.map_size; + break; + case MINIMAP_TYPE_TEXTURE: + mode.label = N_("Minimap in texture mode"); + break; + default: + break; + } + } + + if (zoom >= 0) { + char label_buf[1024]; + porting::mt_snprintf(label_buf, sizeof(label_buf), + mode.label.c_str(), zoom); + mode.label = label_buf; + } + + m_modes.push_back(mode); +} + +void Minimap::addMode(MinimapType type, u16 size, std::string label, + std::string texture, u16 scale) +{ + MinimapModeDef mode; + mode.type = type; + mode.label = label; + mode.map_size = size; + mode.texture = texture; + mode.scale = scale; + switch (type) { + case MINIMAP_TYPE_SURFACE: + mode.scan_height = m_surface_mode_scan_height; + break; + case MINIMAP_TYPE_RADAR: + mode.scan_height = 32; + break; + default: + mode.scan_height = 0; + } + addMode(mode); +} + +void Minimap::nextMode() +{ + if (m_modes.empty()) + return; + m_current_mode_index++; + if (m_current_mode_index >= m_modes.size()) + m_current_mode_index = 0; + + setModeIndex(m_current_mode_index); } void Minimap::setPos(v3s16 pos) @@ -331,16 +415,16 @@ void Minimap::setAngle(f32 angle) void Minimap::blitMinimapPixelsToImageRadar(video::IImage *map_image) { video::SColor c(240, 0, 0, 0); - for (s16 x = 0; x < data->map_size; x++) - for (s16 z = 0; z < data->map_size; z++) { - MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->map_size]; + for (s16 x = 0; x < data->mode.map_size; x++) + for (s16 z = 0; z < data->mode.map_size; z++) { + MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->mode.map_size]; if (mmpixel->air_count > 0) c.setGreen(core::clamp(core::round32(32 + mmpixel->air_count * 8), 0, 255)); else c.setGreen(0); - map_image->setPixel(x, data->map_size - z - 1, c); + map_image->setPixel(x, data->mode.map_size - z - 1, c); } } @@ -349,9 +433,9 @@ void Minimap::blitMinimapPixelsToImageSurface( { // This variable creation/destruction has a 1% cost on rendering minimap video::SColor tilecolor; - for (s16 x = 0; x < data->map_size; x++) - for (s16 z = 0; z < data->map_size; z++) { - MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->map_size]; + for (s16 x = 0; x < data->mode.map_size; x++) + for (s16 z = 0; z < data->mode.map_size; z++) { + MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->mode.map_size]; const ContentFeatures &f = m_ndef->get(mmpixel->n); const TileDef *tile = &f.tiledef[0]; @@ -367,10 +451,10 @@ void Minimap::blitMinimapPixelsToImageSurface( tilecolor.setBlue(tilecolor.getBlue() * f.minimap_color.getBlue() / 255); tilecolor.setAlpha(240); - map_image->setPixel(x, data->map_size - z - 1, tilecolor); + map_image->setPixel(x, data->mode.map_size - z - 1, tilecolor); u32 h = mmpixel->height; - heightmap_image->setPixel(x,data->map_size - z - 1, + heightmap_image->setPixel(x,data->mode.map_size - z - 1, video::SColor(255, h, h, h)); } } @@ -378,21 +462,46 @@ void Minimap::blitMinimapPixelsToImageSurface( video::ITexture *Minimap::getMinimapTexture() { // update minimap textures when new scan is ready - if (data->map_invalidated) + if (data->map_invalidated && data->mode.type != MINIMAP_TYPE_TEXTURE) return data->texture; // create minimap and heightmap images in memory - core::dimension2d dim(data->map_size, data->map_size); + core::dimension2d dim(data->mode.map_size, data->mode.map_size); video::IImage *map_image = driver->createImage(video::ECF_A8R8G8B8, dim); video::IImage *heightmap_image = driver->createImage(video::ECF_A8R8G8B8, dim); video::IImage *minimap_image = driver->createImage(video::ECF_A8R8G8B8, core::dimension2d(MINIMAP_MAX_SX, MINIMAP_MAX_SY)); // Blit MinimapPixels to images - if (data->is_radar) - blitMinimapPixelsToImageRadar(map_image); - else + switch(data->mode.type) { + case MINIMAP_TYPE_OFF: + break; + case MINIMAP_TYPE_SURFACE: blitMinimapPixelsToImageSurface(map_image, heightmap_image); + break; + case MINIMAP_TYPE_RADAR: + blitMinimapPixelsToImageRadar(map_image); + break; + case MINIMAP_TYPE_TEXTURE: + // Want to use texture source, to : 1 find texture, 2 cache it + video::ITexture* texture = m_tsrc->getTexture(data->mode.texture); + video::IImage* image = driver->createImageFromData( + texture->getColorFormat(), texture->getSize(), texture->lock(), true, false); + texture->unlock(); + + auto dim = image->getDimension(); + + map_image->fill(video::SColor(255, 0, 0, 0)); + + image->copyTo(map_image, + irr::core::vector2d { + ((data->mode.map_size - (static_cast(dim.Width))) >> 1) + - data->pos.X / data->mode.scale, + ((data->mode.map_size - (static_cast(dim.Height))) >> 1) + + data->pos.Z / data->mode.scale + }); + image->drop(); + } map_image->copyToScaling(minimap_image); map_image->drop(); @@ -461,21 +570,31 @@ scene::SMeshBuffer *Minimap::getMinimapMeshBuffer() void Minimap::drawMinimap() { + // Non hud managed minimap drawing (legacy minimap) + v2u32 screensize = RenderingEngine::get_instance()->getWindowSize(); + const u32 size = 0.25 * screensize.Y; + + drawMinimap(core::rect( + screensize.X - size - 10, 10, + screensize.X - 10, size + 10)); +} + +void Minimap::drawMinimap(core::rect rect) { + video::ITexture *minimap_texture = getMinimapTexture(); if (!minimap_texture) return; + if (data->mode.type == MINIMAP_TYPE_OFF) + return; + updateActiveMarkers(); - v2u32 screensize = RenderingEngine::get_instance()->getWindowSize(); - const u32 size = 0.25 * screensize.Y; core::rect oldViewPort = driver->getViewPort(); core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION); core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW); - driver->setViewPort(core::rect( - screensize.X - size - 10, 10, - screensize.X - 10, size + 10)); + driver->setViewPort(rect); driver->setTransform(video::ETS_PROJECTION, core::matrix4()); driver->setTransform(video::ETS_VIEW, core::matrix4()); @@ -488,7 +607,7 @@ void Minimap::drawMinimap() material.TextureLayer[0].Texture = minimap_texture; material.TextureLayer[1].Texture = data->heightmap_texture; - if (m_enable_shaders && !data->is_radar) { + if (m_enable_shaders && data->mode.type == MINIMAP_TYPE_SURFACE) { u16 sid = m_shdrsrc->getShader("minimap_shader", 1, 1); material.MaterialType = m_shdrsrc->getShaderInfo(sid).material; } else { @@ -529,14 +648,14 @@ void Minimap::drawMinimap() driver->setViewPort(oldViewPort); // Draw player markers - v2s32 s_pos(screensize.X - size - 10, 10); + v2s32 s_pos(rect.UpperLeftCorner.X, rect.UpperLeftCorner.Y); core::dimension2di imgsize(data->object_marker_red->getOriginalSize()); core::rect img_rect(0, 0, imgsize.Width, imgsize.Height); static const video::SColor col(255, 255, 255, 255); static const video::SColor c[4] = {col, col, col, col}; f32 sin_angle = std::sin(m_angle * core::DEGTORAD); f32 cos_angle = std::cos(m_angle * core::DEGTORAD); - s32 marker_size2 = 0.025 * (float)size; + s32 marker_size2 = 0.025 * (float)rect.getWidth();; for (std::list::const_iterator i = m_active_markers.begin(); i != m_active_markers.end(); ++i) { @@ -547,8 +666,8 @@ void Minimap::drawMinimap() posf.X = t1; posf.Y = t2; } - posf.X = (posf.X + 0.5) * (float)size; - posf.Y = (posf.Y + 0.5) * (float)size; + posf.X = (posf.X + 0.5) * (float)rect.getWidth(); + posf.Y = (posf.Y + 0.5) * (float)rect.getHeight(); core::rect dest_rect( s_pos.X + posf.X - marker_size2, s_pos.Y + posf.Y - marker_size2, @@ -571,16 +690,16 @@ void Minimap::updateActiveMarkers() for (Nametag *nametag : nametags) { v3s16 pos = floatToInt(nametag->parent_node->getAbsolutePosition() + intToFloat(client->getCamera()->getOffset(), BS), BS); - pos -= data->pos - v3s16(data->map_size / 2, - data->scan_height / 2, - data->map_size / 2); - if (pos.X < 0 || pos.X > data->map_size || - pos.Y < 0 || pos.Y > data->scan_height || - pos.Z < 0 || pos.Z > data->map_size) { + pos -= data->pos - v3s16(data->mode.map_size / 2, + data->mode.scan_height / 2, + data->mode.map_size / 2); + if (pos.X < 0 || pos.X > data->mode.map_size || + pos.Y < 0 || pos.Y > data->mode.scan_height || + pos.Z < 0 || pos.Z > data->mode.map_size) { continue; } - pos.X = ((float)pos.X / data->map_size) * MINIMAP_MAX_SX; - pos.Z = ((float)pos.Z / data->map_size) * MINIMAP_MAX_SY; + pos.X = ((float)pos.X / data->mode.map_size) * MINIMAP_MAX_SX; + pos.Z = ((float)pos.Z / data->mode.map_size) * MINIMAP_MAX_SY; const video::SColor &mask_col = minimap_mask->getPixel(pos.X, pos.Z); if (!mask_col.getAlpha()) { continue; diff --git a/src/client/minimap.h b/src/client/minimap.h index 258d5330d..11374b116 100644 --- a/src/client/minimap.h +++ b/src/client/minimap.h @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once +#include "../hud.h" #include "irrlichttypes_extrabloated.h" #include "util/thread.h" #include "voxel.h" @@ -33,26 +34,18 @@ class IShaderSource; #define MINIMAP_MAX_SX 512 #define MINIMAP_MAX_SY 512 -enum MinimapMode { - MINIMAP_MODE_OFF, - MINIMAP_MODE_SURFACEx1, - MINIMAP_MODE_SURFACEx2, - MINIMAP_MODE_SURFACEx4, - MINIMAP_MODE_RADARx1, - MINIMAP_MODE_RADARx2, - MINIMAP_MODE_RADARx4, - MINIMAP_MODE_COUNT, -}; - enum MinimapShape { MINIMAP_SHAPE_SQUARE, MINIMAP_SHAPE_ROUND, }; struct MinimapModeDef { - bool is_radar; + MinimapType type; + std::string label; u16 scan_height; u16 map_size; + std::string texture; + u16 scale; }; struct MinimapPixel { @@ -69,12 +62,9 @@ struct MinimapMapblock { }; struct MinimapData { - bool is_radar; - MinimapMode mode; + MinimapModeDef mode; v3s16 pos; v3s16 old_pos; - u16 scan_height; - u16 map_size; MinimapPixel minimap_scan[MINIMAP_MAX_SX * MINIMAP_MAX_SY]; bool map_invalidated; bool minimap_shape_round; @@ -127,12 +117,22 @@ public: v3s16 getPos() const { return data->pos; } void setAngle(f32 angle); f32 getAngle() const { return m_angle; } - void setMinimapMode(MinimapMode mode); - MinimapMode getMinimapMode() const { return data->mode; } void toggleMinimapShape(); void setMinimapShape(MinimapShape shape); MinimapShape getMinimapShape(); + void clearModes() { m_modes.clear(); }; + void addMode(MinimapModeDef mode); + void addMode(MinimapType type, u16 size = 0, std::string label = "", + std::string texture = "", u16 scale = 1); + + void setModeIndex(size_t index); + size_t getModeIndex() const { return m_current_mode_index; }; + size_t getMaxModeIndex() const { return m_modes.size() - 1; }; + void nextMode(); + + void setModesFromString(std::string modes_string); + MinimapModeDef getModeDef() const { return data->mode; } video::ITexture *getMinimapTexture(); @@ -144,6 +144,7 @@ public: void updateActiveMarkers(); void drawMinimap(); + void drawMinimap(core::rect rect); video::IVideoDriver *driver; Client* client; @@ -153,9 +154,11 @@ private: ITextureSource *m_tsrc; IShaderSource *m_shdrsrc; const NodeDefManager *m_ndef; - MinimapUpdateThread *m_minimap_update_thread; + MinimapUpdateThread *m_minimap_update_thread = nullptr; scene::SMeshBuffer *m_meshbuffer; bool m_enable_shaders; + std::vector m_modes; + size_t m_current_mode_index; u16 m_surface_mode_scan_height; f32 m_angle; std::mutex m_mutex; diff --git a/src/hud.cpp b/src/hud.cpp index 175701342..1791e04df 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -29,6 +29,7 @@ const struct EnumString es_HudElementType[] = {HUD_ELEM_WAYPOINT, "waypoint"}, {HUD_ELEM_IMAGE_WAYPOINT, "image_waypoint"}, {HUD_ELEM_COMPASS, "compass"}, + {HUD_ELEM_MINIMAP, "minimap"}, {0, NULL}, }; diff --git a/src/hud.h b/src/hud.h index 0a6993c1b..a0613ae98 100644 --- a/src/hud.h +++ b/src/hud.h @@ -51,7 +51,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #define HUD_HOTBAR_ITEMCOUNT_DEFAULT 8 #define HUD_HOTBAR_ITEMCOUNT_MAX 32 - #define HOTBAR_IMAGE_SIZE 48 enum HudElementType { @@ -61,7 +60,8 @@ enum HudElementType { HUD_ELEM_INVENTORY = 3, HUD_ELEM_WAYPOINT = 4, HUD_ELEM_IMAGE_WAYPOINT = 5, - HUD_ELEM_COMPASS = 6 + HUD_ELEM_COMPASS = 6, + HUD_ELEM_MINIMAP = 7 }; enum HudElementStat { @@ -108,3 +108,12 @@ extern const EnumString es_HudElementType[]; extern const EnumString es_HudElementStat[]; extern const EnumString es_HudBuiltinElement[]; +// Minimap stuff + +enum MinimapType { + MINIMAP_TYPE_OFF, + MINIMAP_TYPE_SURFACE, + MINIMAP_TYPE_RADAR, + MINIMAP_TYPE_TEXTURE, +}; + diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp index f812a08a1..55cfdd4dc 100644 --- a/src/network/clientopcodes.cpp +++ b/src/network/clientopcodes.cpp @@ -122,6 +122,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] = null_command_handler, { "TOCLIENT_SRP_BYTES_S_B", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_SrpBytesSandB }, // 0x60 { "TOCLIENT_FORMSPEC_PREPEND", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FormspecPrepend }, // 0x61, + { "TOCLIENT_MINIMAP_MODES", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_MinimapModes }, // 0x62, }; const static ServerCommandFactory null_command_factory = { "TOSERVER_NULL", 0, false }; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 5683564a0..65db02300 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1164,15 +1164,24 @@ void Client::handleCommand_HudSetFlags(NetworkPacket* pkt) m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE); bool m_minimap_radar_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE); + // Not so satisying code to keep compatibility with old fixed mode system + // --> + // Hide minimap if it has been disabled by the server if (m_minimap && m_minimap_disabled_by_server && was_minimap_visible) // defers a minimap update, therefore only call it if really // needed, by checking that minimap was visible before - m_minimap->setMinimapMode(MINIMAP_MODE_OFF); - - // Switch to surface mode if radar disabled by server - if (m_minimap && m_minimap_radar_disabled_by_server && was_minimap_radar_visible) - m_minimap->setMinimapMode(MINIMAP_MODE_SURFACEx1); + m_minimap->setModeIndex(0); + + // If radar has been disabled, try to find a non radar mode or fall back to 0 + if (m_minimap && m_minimap_radar_disabled_by_server + && was_minimap_radar_visible) { + while (m_minimap->getModeIndex() > 0 && + m_minimap->getModeDef().type == MINIMAP_TYPE_RADAR) + m_minimap->nextMode(); + } + // <-- + // End of 'not so satifying code' } void Client::handleCommand_HudSetParam(NetworkPacket* pkt) @@ -1611,3 +1620,30 @@ void Client::handleCommand_ModChannelSignal(NetworkPacket *pkt) if (valid_signal) m_script->on_modchannel_signal(channel, signal); } + +void Client::handleCommand_MinimapModes(NetworkPacket *pkt) +{ + u16 count; // modes + u16 mode; // wanted current mode index after change + + *pkt >> count >> mode; + + if (m_minimap) + m_minimap->clearModes(); + + for (size_t index = 0; index < count; index++) { + u16 type; + std::string label; + u16 size; + std::string texture; + u16 scale; + + *pkt >> type >> label >> size >> texture >> scale; + + if (m_minimap) + m_minimap->addMode(MinimapType(type), size, label, texture, scale); + } + + if (m_minimap) + m_minimap->setModeIndex(mode); +} diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 05600cda9..666e75e45 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -204,6 +204,7 @@ with this program; if not, write to the Free Software Foundation, Inc., PROTOCOL VERSION 39: Updated set_sky packet Adds new sun, moon and stars packets + Minimap modes */ #define LATEST_PROTOCOL_VERSION 39 @@ -764,7 +765,18 @@ enum ToClientCommand u8[len] formspec */ - TOCLIENT_NUM_MSG_TYPES = 0x62, + TOCLIENT_MINIMAP_MODES = 0x62, + /* + u16 count // modes + u16 mode // wanted current mode index after change + for each mode + u16 type + std::string label + u16 size + std::string extra + */ + + TOCLIENT_NUM_MSG_TYPES = 0x63, }; enum ToServerCommand diff --git a/src/network/serveropcodes.cpp b/src/network/serveropcodes.cpp index 2fc3197c2..aea5d7174 100644 --- a/src/network/serveropcodes.cpp +++ b/src/network/serveropcodes.cpp @@ -221,4 +221,5 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] = null_command_factory, // 0x5f { "TOSERVER_SRP_BYTES_S_B", 0, true }, // 0x60 { "TOCLIENT_FORMSPEC_PREPEND", 0, true }, // 0x61 + { "TOCLIENT_MINIMAP_MODES", 0, true }, // 0x62 }; diff --git a/src/script/lua_api/l_minimap.cpp b/src/script/lua_api/l_minimap.cpp index 5fba76eb8..3bbb6e5e3 100644 --- a/src/script/lua_api/l_minimap.cpp +++ b/src/script/lua_api/l_minimap.cpp @@ -89,7 +89,7 @@ int LuaMinimap::l_get_mode(lua_State *L) LuaMinimap *ref = checkobject(L, 1); Minimap *m = getobject(ref); - lua_pushinteger(L, m->getMinimapMode()); + lua_pushinteger(L, m->getModeIndex()); return 1; } @@ -98,13 +98,11 @@ int LuaMinimap::l_set_mode(lua_State *L) LuaMinimap *ref = checkobject(L, 1); Minimap *m = getobject(ref); - s32 mode = lua_tointeger(L, 2); - if (mode < MINIMAP_MODE_OFF || - mode >= MINIMAP_MODE_COUNT) { + u32 mode = lua_tointeger(L, 2); + if (mode >= m->getMaxModeIndex()) return 0; - } - m->setMinimapMode((MinimapMode) mode); + m->setModeIndex(mode); return 1; } @@ -140,8 +138,11 @@ int LuaMinimap::l_show(lua_State *L) LuaMinimap *ref = checkobject(L, 1); Minimap *m = getobject(ref); - if (m->getMinimapMode() == MINIMAP_MODE_OFF) - m->setMinimapMode(MINIMAP_MODE_SURFACEx1); + // This is not very adapted to new minimap mode management. Btw, tried + // to do something compatible. + + if (m->getModeIndex() == 0 && m->getMaxModeIndex() > 0) + m->setModeIndex(1); client->showMinimap(true); return 1; @@ -155,8 +156,11 @@ int LuaMinimap::l_hide(lua_State *L) LuaMinimap *ref = checkobject(L, 1); Minimap *m = getobject(ref); - if (m->getMinimapMode() != MINIMAP_MODE_OFF) - m->setMinimapMode(MINIMAP_MODE_OFF); + // This is not very adapted to new minimap mode management. Btw, tried + // to do something compatible. + + if (m->getModeIndex() != 0) + m->setModeIndex(0); client->showMinimap(false); return 1; diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index fead4e849..57ed7e2cd 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -2199,6 +2199,67 @@ int ObjectRef::l_get_day_night_ratio(lua_State *L) return 1; } +// set_minimap_modes(self, modes, modeindex) +int ObjectRef::l_set_minimap_modes(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + // Arg 1 should be a player + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (player == NULL) + return 0; + + // Arg 2 should be a table (of tables) + if (!lua_istable(L, 2)) { + return 0; + } + + // Arg 3 should be a number + s16 wantedmode = lua_tonumber(L, 3); + + std::vector modes; + + lua_pushnil(L); + while (lua_next(L, 2) != 0) { + /* key is at index -2, value is at index -1 */ + if (lua_istable(L, -1)) { + bool ok = true; + MinimapMode mode; + std::string type = getstringfield_default(L, -1, "type", ""); + if (type == "off") + mode.type = MINIMAP_TYPE_OFF; + else if (type == "surface") + mode.type = MINIMAP_TYPE_SURFACE; + else if (type == "radar") + mode.type = MINIMAP_TYPE_RADAR; + else if (type == "texture") { + mode.type = MINIMAP_TYPE_TEXTURE; + mode.texture = getstringfield_default(L, -1, "texture", ""); + mode.scale = getintfield_default(L, -1, "scale", 1); + } else { + warningstream << "Minimap mode of unknown type \"" << type.c_str() + << "\" ignored.\n" << std::endl; + ok = false; + } + + if (ok) { + mode.label = getstringfield_default(L, -1, "label", ""); + // Size is limited to 512. Performance gets poor if size too large, and + // segfaults have been experienced. + mode.size = rangelim(getintfield_default(L, -1, "size", 0), 1, 512); + modes.push_back(mode); + } + } + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(L, 1); + } + lua_pop(L, 1); // Remove key + + getServer(L)->SendMinimapModes(player->getPeerId(), modes, wantedmode); + return 0; +} + ObjectRef::ObjectRef(ServerActiveObject *object): m_object(object) { @@ -2359,5 +2420,6 @@ luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, set_eye_offset), luamethod(ObjectRef, get_eye_offset), luamethod(ObjectRef, send_mapblock), + luamethod(ObjectRef, set_minimap_modes), {0,0} }; diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index 126719b1f..ca03dfa2e 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -377,4 +377,7 @@ private: // send_mapblock(pos) static int l_send_mapblock(lua_State *L); + + // set_minimap_modes(self, modes, wanted_mode) + static int l_set_minimap_modes(lua_State *L); }; diff --git a/src/server.cpp b/src/server.cpp index 982f904f4..8f6257afe 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2662,6 +2662,23 @@ void Server::sendRequestedMedia(session_t peer_id, } } +void Server::SendMinimapModes(session_t peer_id, + std::vector &modes, size_t wanted_mode) +{ + RemotePlayer *player = m_env->getPlayer(peer_id); + assert(player); + if (player->getPeerId() == PEER_ID_INEXISTENT) + return; + + NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id); + pkt << (u16)modes.size() << (u16)wanted_mode; + + for (auto &mode : modes) + pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale; + + Send(&pkt); +} + void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id) { NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id); diff --git a/src/server.h b/src/server.h index 258d75eaf..4b3ac5cf7 100644 --- a/src/server.h +++ b/src/server.h @@ -118,6 +118,14 @@ struct ServerPlayingSound std::unordered_set clients; // peer ids }; +struct MinimapMode { + MinimapType type = MINIMAP_TYPE_OFF; + std::string label; + u16 size = 0; + std::string texture; + u16 scale = 1; +}; + class Server : public con::PeerHandler, public MapEventReceiver, public IGameDef { @@ -331,6 +339,10 @@ public: void SendPlayerSpeed(session_t peer_id, const v3f &added_vel); void SendPlayerFov(session_t peer_id); + void SendMinimapModes(session_t peer_id, + std::vector &modes, + size_t wanted_mode); + void sendDetachedInventories(session_t peer_id, bool incremental); virtual bool registerModStorage(ModMetadata *storage); -- cgit v1.2.3