diff --git a/include/TConsole.h b/include/TConsole.h index 0f417e0..722cda9 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -59,6 +59,8 @@ private: void Command_Settings(const std::string& cmd, const std::vector& args); void Command_Clear(const std::string&, const std::vector& args); void Command_Version(const std::string& cmd, const std::vector& args); + void Command_ProtectMod(const std::string& cmd, const std::vector& args); + void Command_ReloadMods(const std::string& cmd, const std::vector& args); void Command_Say(const std::string& FullCommand); bool EnsureArgsCount(const std::vector& args, size_t n); @@ -77,6 +79,8 @@ private: { "clear", [this](const auto& a, const auto& b) { Command_Clear(a, b); } }, { "say", [this](const auto&, const auto&) { Command_Say(""); } }, // shouldn't actually be called { "version", [this](const auto& a, const auto& b) { Command_Version(a, b); } }, + { "protectmod", [this](const auto& a, const auto& b) { Command_ProtectMod(a, b); } }, + { "reloadmods", [this](const auto& a, const auto& b) { Command_ReloadMods(a, b); } }, }; std::unique_ptr mCommandline { nullptr }; diff --git a/include/TNetwork.h b/include/TNetwork.h index 28029db..81931d9 100644 --- a/include/TNetwork.h +++ b/include/TNetwork.h @@ -45,6 +45,8 @@ public: void SendToAll(TClient* c, const std::vector& Data, bool Self, bool Rel); void UpdatePlayer(TClient& Client); + TResourceManager& ResourceManager() const { return mResourceManager; } + private: void UDPServerMain(); void TCPServerMain(); diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 53798b3..d92733d 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -208,16 +208,18 @@ void TConsole::Command_Help(const std::string&, const std::vector& } static constexpr const char* sHelpString = R"( Commands: - help displays this help - exit shuts down the server - kick [reason] kicks specified player with an optional reason - list lists all players and info about them - say sends the message to all players in chat - lua [state id] switches to lua, optionally into a specific state id's lua - settings [command] sets or gets settings for the server, run `settings help` for more info - status how the server is doing and what it's up to - clear clears the console window - version displays the server version)"; + help displays this help + exit shuts down the server + kick [reason] kicks specified player with an optional reason + list lists all players and info about them + say sends the message to all players in chat + lua [state id] switches to lua, optionally into a specific state id's lua + settings [command] sets or gets settings for the server, run `settings help` for more info + status how the server is doing and what it's up to + clear clears the console window + version displays the server version + protectmod sets whether a mod is protected + reloadmods reloads all mods from the Resources Client folder)"; Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString)); } @@ -262,6 +264,32 @@ void TConsole::Command_Version(const std::string& cmd, const std::vector& args) { + if (!EnsureArgsCount(args, 2)) { + return; + } + + const auto& ModName = args.at(0); + const auto& Protect = args.at(1); + + for (auto mod : mLuaEngine->Network().ResourceManager().GetMods()) { + if (mod["file_name"].get() == ModName) { + mLuaEngine->Network().ResourceManager().SetProtected(ModName, Protect == "true"); + Application::Console().WriteRaw("Mod " + ModName + " is now " + (Protect == "true" ? "protected" : "unprotected")); + return; + } + } + + Application::Console().WriteRaw("Mod " + ModName + " not found."); +} +void TConsole::Command_ReloadMods(const std::string& cmd, const std::vector& args) { + if (!EnsureArgsCount(args, 0)) { + return; + } + + mLuaEngine->Network().ResourceManager().RefreshFiles(); + Application::Console().WriteRaw("Mods reloaded."); +} void TConsole::Command_Kick(const std::string&, const std::vector& args) { if (!EnsureArgsCount(args, 1, size_t(-1))) { diff --git a/src/TResourceManager.cpp b/src/TResourceManager.cpp index bacec3e..fd8126a 100644 --- a/src/TResourceManager.cpp +++ b/src/TResourceManager.cpp @@ -98,12 +98,11 @@ void TResourceManager::RefreshFiles() { dbEntry["exists"] = true; mMods.push_back(nlohmann::json { - { "file_name", std::filesystem::path(File).filename() }, - { "file_size", std::filesystem::file_size(File) }, - { "hash_algorithm", "sha256" }, - { "hash", dbEntry["hash"] }, - { "protected", dbEntry["protected"] } - }); + { "file_name", std::filesystem::path(File).filename() }, + { "file_size", std::filesystem::file_size(File) }, + { "hash_algorithm", "sha256" }, + { "hash", dbEntry["hash"] }, + { "protected", dbEntry["protected"] } }); beammp_debugf("Mod '{}' loaded from cache", File); @@ -170,8 +169,7 @@ void TResourceManager::RefreshFiles() { { "file_size", std::filesystem::file_size(File) }, { "hash_algorithm", "sha256" }, { "hash", result }, - { "protected", false } - }); + { "protected", false } }); modsDB[std::filesystem::path(File).filename().string()] = { { "lastwrite", entry.last_write_time().time_since_epoch().count() }, @@ -186,7 +184,7 @@ void TResourceManager::RefreshFiles() { } } - for (auto it = modsDB.begin(); it != modsDB.end(); ) { + for (auto it = modsDB.begin(); it != modsDB.end();) { if (!it.value().contains("exists")) { it = modsDB.erase(it); } else { @@ -205,3 +203,39 @@ void TResourceManager::RefreshFiles() { beammp_error("Failed to update mod DB: " + std::string(e.what())); } } + +void TResourceManager::SetProtected(const std::string& ModName, bool Protected) { + std::unique_lock Lock(mModsMutex); + + for (auto& mod : mMods) { + if (mod["file_name"].get() == ModName) { + mod["protected"] = Protected; + break; + } + } + + auto modsDBPath = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client/mods.json"; + + if (std::filesystem::exists(modsDBPath)) { + try { + nlohmann::json modsDB; + + std::fstream stream(modsDBPath); + + stream >> modsDB; + + if (modsDB.contains(ModName)) { + modsDB[ModName]["protected"] = Protected; + } + + stream.clear(); + stream.seekp(0, std::ios::beg); + + stream << modsDB.dump(4); + + stream.close(); + } catch (const std::exception& e) { + beammp_errorf("Failed to update mods.json: {}", e.what()); + } + } +}