From bf4ae7f1169ef1f8bb643ad7715162549ed1e70f Mon Sep 17 00:00:00 2001 From: Diavolo Date: Mon, 13 Jun 2022 17:32:45 +0200 Subject: [PATCH] [MapRotation] Allow people to circumvent 1024 dvar character limit --- src/Components/Loader.cpp | 8 +-- src/Components/Loader.hpp | 4 +- src/Components/Modules/Bans.cpp | 10 +-- src/Components/Modules/Logger.cpp | 19 +++-- src/Components/Modules/MapRotation.cpp | 99 ++++++++++++++++++++++++-- src/Components/Modules/MapRotation.hpp | 8 +++ src/Components/Modules/QuickPatch.cpp | 19 +++-- 7 files changed, 130 insertions(+), 37 deletions(-) diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 73d1388d..2bd38300 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -175,13 +175,13 @@ namespace Components Logger::Print("Performing unit tests for components:\n"); - for (auto component : Loader::Components) + for (const auto component : Loader::Components) { -#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) - Logger::Print("Testing '{}'...\n", component->getName()); +#if defined(FORCE_UNIT_TESTS) + Logger::Debug("Testing '{}'...\n", component->getName()); #endif auto startTime = std::chrono::high_resolution_clock::now(); - bool testRes = component->unitTest(); + auto testRes = component->unitTest(); auto duration = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime).count(); Logger::Print("Test done ({}ms): {}\n\n", duration, (testRes ? "Success" : "Error")); result &= testRes; diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 36f03585..842021de 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -5,8 +5,8 @@ namespace Components class Component { public: - Component() {} - virtual ~Component() {} + Component() = default; + virtual ~Component() = default; #if defined(DEBUG) || defined(FORCE_UNIT_TESTS) virtual std::string getName() diff --git a/src/Components/Modules/Bans.cpp b/src/Components/Modules/Bans.cpp index c76054d6..cf13ed16 100644 --- a/src/Components/Modules/Bans.cpp +++ b/src/Components/Modules/Bans.cpp @@ -89,21 +89,21 @@ namespace Components std::vector idVector; std::vector ipVector; - for (auto& idEntry : list->idList) + for (const auto& idEntry : list->idList) { - idVector.push_back(Utils::String::VA("%llX", idEntry.bits)); + idVector.emplace_back(Utils::String::VA("%llX", idEntry.bits)); } - for (auto& ipEntry : list->ipList) + for (const auto& ipEntry : list->ipList) { - ipVector.push_back(Utils::String::VA("%u.%u.%u.%u", + ipVector.emplace_back(Utils::String::VA("%u.%u.%u.%u", ipEntry.bytes[0] & 0xFF, ipEntry.bytes[1] & 0xFF, ipEntry.bytes[2] & 0xFF, ipEntry.bytes[3] & 0xFF)); } - json11::Json bans = json11::Json::object + const json11::Json bans = json11::Json::object { { "ip", ipVector }, { "id", idVector }, diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index f62f6604..98382d14 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -113,19 +113,19 @@ namespace Components void Logger::Frame() { - std::lock_guard _(Logger::MessageMutex); + std::unique_lock _(Logger::MessageMutex); - for (std::size_t i = 0; i < Logger::MessageQueue.size(); ++i) + for (auto i = Logger::MessageQueue.begin(); i != Logger::MessageQueue.end();) { - Game::Com_PrintMessage(Game::CON_CHANNEL_DONT_FILTER, Logger::MessageQueue[i].data(), 0); + Game::Com_PrintMessage(Game::CON_CHANNEL_DONT_FILTER, i->data(), 0); if (!Logger::IsConsoleReady()) { - OutputDebugStringA(Logger::MessageQueue[i].data()); + OutputDebugStringA(i->data()); } - } - Logger::MessageQueue.clear(); + i = Logger::MessageQueue.erase(i); + } } void Logger::PipeOutput(void(*callback)(const std::string&)) @@ -203,9 +203,8 @@ namespace Components void Logger::EnqueueMessage(const std::string& message) { - Logger::MessageMutex.lock(); + std::unique_lock _(Logger::MessageMutex); Logger::MessageQueue.push_back(message); - Logger::MessageMutex.unlock(); } void Logger::RedirectOSPath(const char* file, char* folder) @@ -375,9 +374,9 @@ namespace Components Logger::LoggingAddresses[0].clear(); Logger::LoggingAddresses[1].clear(); - Logger::MessageMutex.lock(); + std::unique_lock lock(Logger::MessageMutex); Logger::MessageQueue.clear(); - Logger::MessageMutex.unlock(); + lock.unlock(); // Flush the console log if (const auto logfile = *reinterpret_cast(0x1AD8F28)) diff --git a/src/Components/Modules/MapRotation.cpp b/src/Components/Modules/MapRotation.cpp index d77bf96a..e7fe38c0 100644 --- a/src/Components/Modules/MapRotation.cpp +++ b/src/Components/Modules/MapRotation.cpp @@ -61,6 +61,33 @@ namespace Components } } + json11::Json MapRotation::RotationData::to_json() const + { + std::vector mapVector; + std::vector gametypeVector; + + for (const auto& [key, val] : this->rotationEntries_) + { + if (key == "map") + { + mapVector.emplace_back(val); + } + else if (key == "gametype") + { + gametypeVector.emplace_back(val); + } + } + + + json11::Json mapRotationJson = json11::Json::object + { + {"maps", mapVector}, + {"gametypes", gametypeVector}, + }; + + return mapRotationJson; + } + void MapRotation::LoadRotation(const std::string& data) { static auto loaded = false; @@ -77,10 +104,10 @@ namespace Components } catch (const std::exception& ex) { - Logger::Print(Game::CON_CHANNEL_SERVER, "%s: sv_mapRotation contains invalid data!\n", ex.what()); + Logger::Print(Game::CON_CHANNEL_SERVER, "{}: sv_mapRotation contains invalid data!\n", ex.what()); } - Logger::Print(Game::CON_CHANNEL_SERVER, "DedicatedRotation size after parsing is '%u'\n", DedicatedRotation.getEntriesSize()); + Logger::DebugInfo("DedicatedRotation size after parsing is '{}'\n", DedicatedRotation.getEntriesSize()); // Shuffles values if (SVRandomMapRotation.get()) @@ -92,6 +119,31 @@ namespace Components loaded = true; } + void MapRotation::AddMapRotationCommands() + { + Command::Add("AddMap", [](Command::Params* params) + { + if (params->size() < 2) + { + Logger::Print("{} : add a map to the map rotation\n", params->get(0)); + return; + } + + DedicatedRotation.addEntry("map", params->get(1)); + }); + + Command::Add("AddGametype", [](Command::Params* params) + { + if (params->size() < 2) + { + Logger::Print("{} : add a game mode to the map rotation\n", params->get(0)); + return; + } + + DedicatedRotation.addEntry("gametype", params->get(1)); + }); + } + bool MapRotation::ShouldRotate() { if (!Dedicated::IsEnabled() && SVDontRotate.get()) @@ -132,7 +184,7 @@ namespace Components void MapRotation::ApplyMapRotation() { - // Continue to apply gamemode until a map is found + // Continue to apply gametype until a map is found auto foundMap = false; std::size_t i = 0; @@ -142,15 +194,15 @@ namespace Components if (entry.first == "map") { - Logger::Print("Loading new map: '%s'\n", entry.second.data()); + Logger::DebugInfo("Loading new map: '{}'\n", entry.second); Command::Execute(Utils::String::VA("map %s", entry.second.data()), true); // Map was found so we exit the loop foundMap = true; } - else if (entry.first == "gamemode") + else if (entry.first == "gametype") { - Logger::Print("Applying new gametype: '%s'\n", entry.second.data()); + Logger::DebugInfo("Applying new gametype: '{}'\n", entry.second); Dvar::Var("g_gametype").set(entry.second); } @@ -189,6 +241,7 @@ namespace Components MapRotation::MapRotation() { + AddMapRotationCommands(); Utils::Hook::Set(0x4152E8, SV_MapRotate_f); SVRandomMapRotation = Dvar::Register("sv_randomMapRotation", false, @@ -196,4 +249,38 @@ namespace Components SVDontRotate = Dvar::Register("sv_dontRotate", false, Game::dvar_flag::DVAR_NONE, "Do not perform map rotation"); } + + bool MapRotation::unitTest() + { + RotationData rotation; + + Logger::DebugInfo("Testing map rotation parsing..."); + + const auto* normal = "map mp_highrise map mp_terminal map mp_firingrange map mp_trailerpark gametype dm map mp_shipment_long"; + + try + { + DedicatedRotation.parse(normal); + } + catch (const std::exception& ex) + { + Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}: parsing of 'normal' failed", ex.what()); + return false; + } + + const auto* mistake = "spdevmap mp_dome"; + auto success = false; + + try + { + DedicatedRotation.parse(mistake); + } + catch (const std::exception& ex) + { + Logger::Debug("{}: parsing of 'normal' failed as expected", ex.what()); + success = true; + } + + return success; + } } diff --git a/src/Components/Modules/MapRotation.hpp b/src/Components/Modules/MapRotation.hpp index 420b5a4a..bf9a1cca 100644 --- a/src/Components/Modules/MapRotation.hpp +++ b/src/Components/Modules/MapRotation.hpp @@ -7,6 +7,8 @@ namespace Components public: MapRotation(); + bool unitTest() override; + private: struct ParseRotationError : public std::exception { @@ -31,6 +33,9 @@ namespace Components void parse(const std::string& data); + // Json11 Implicit constructor + [[nodiscard]] json11::Json to_json() const; + private: std::vector rotationEntries_; @@ -49,6 +54,9 @@ namespace Components static void LoadRotation(const std::string& data); + // Use these commands before SV_MapRotate_f is called + static void AddMapRotationCommands(); + static bool ShouldRotate(); static void RestartCurrentMap(); static void ApplyMapRotation(); diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index 6b842af2..5c7260d1 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -731,9 +731,9 @@ namespace Components bool QuickPatch::unitTest() { uint32_t randIntCount = 4'000'000; - printf("Generating %d random integers...", randIntCount); + Logger::Debug("Generating %d random integers...", randIntCount); - auto startTime = std::chrono::high_resolution_clock::now(); + const auto startTime = std::chrono::high_resolution_clock::now(); for (uint32_t i = 0; i < randIntCount; ++i) { @@ -741,9 +741,9 @@ namespace Components } auto duration = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime).count(); - Logger::Print("took {}ms\n", duration); + Logger::Debug("took {}ms\n", duration); - printf("Testing ZLib compression..."); + Logger::Debug("Testing ZLib compression..."); std::string test = Utils::String::VA("%c", Utils::Cryptography::Rand::GenerateInt()); @@ -754,21 +754,20 @@ namespace Components if (test != decompressed) { - printf("Error\n"); - printf("Compressing %d bytes and decompressing failed!\n", test.size()); + Logger::PrintError(Game::CON_CHANNEL_ERROR, "Compressing {} bytes and decompressing failed!\n", test.size()); return false; } - auto size = test.size(); + const auto size = test.size(); for (unsigned int j = 0; j < size; ++j) { test.append(Utils::String::VA("%c", Utils::Cryptography::Rand::GenerateInt())); } } - printf("Success\n"); + Logger::Debug("Success"); - printf("Testing trimming..."); + Logger::Debug("Testing trimming..."); std::string trim1 = " 1 "; std::string trim2 = " 1"; std::string trim3 = "1 "; @@ -781,7 +780,7 @@ namespace Components if (trim2 != "1") return false; if (trim3 != "1") return false; - printf("Success\n"); + Logger::Debug("Success"); return true; } }