diff --git a/src/Components/Modules/Command.cpp b/src/Components/Modules/Command.cpp index b203f7d2..c4a0e4ff 100644 --- a/src/Components/Modules/Command.cpp +++ b/src/Components/Modules/Command.cpp @@ -121,7 +121,7 @@ namespace Components return; } - command.append("\n"); // Make sure it's terminated + command.push_back('\n'); // Make sure it's terminated assert(command.size() < Game::MAX_CMD_LINE); diff --git a/src/Components/Modules/MapRotation.cpp b/src/Components/Modules/MapRotation.cpp index 8ed6ad4a..de84131e 100644 --- a/src/Components/Modules/MapRotation.cpp +++ b/src/Components/Modules/MapRotation.cpp @@ -1,5 +1,6 @@ #include #include "MapRotation.hpp" +#include "Party.hpp" namespace Components { @@ -25,7 +26,7 @@ namespace Components void MapRotation::RotationData::addEntry(const std::string& key, const std::string& value) { - this->rotationEntries_.emplace_back(std::make_pair(key, value)); + this->rotationEntries_.emplace_back(key, value); } std::size_t MapRotation::RotationData::getEntriesSize() const noexcept @@ -36,7 +37,7 @@ namespace Components MapRotation::RotationData::rotationEntry& MapRotation::RotationData::getNextEntry() { const auto index = this->index_; - ++this->index_ %= this->rotationEntries_.size(); // Point index_ to the next entry + ++this->index_ %= this->rotationEntries_.size(); return this->rotationEntries_.at(index); } @@ -45,6 +46,19 @@ namespace Components return this->rotationEntries_.at(this->index_); } + void MapRotation::RotationData::setHandler(const std::string& key, const rotationCallback& callback) + { + this->rotationHandlers_[key] = callback; + } + + void MapRotation::RotationData::callHandler(const rotationEntry& entry) const + { + if (const auto itr = this->rotationHandlers_.find(entry.first); itr != this->rotationHandlers_.end()) + { + itr->second(entry.second); + } + } + void MapRotation::RotationData::parse(const std::string& data) { const auto tokens = Utils::String::Split(data, ' '); @@ -54,14 +68,12 @@ namespace Components const auto& key = tokens[i]; const auto& value = tokens[i + 1]; - if (key == "map"s || key == "gametype"s) + if (!this->containsHandler(key)) { - this->addEntry(key, value); - } - else - { - throw MapRotationParseError(); + throw MapRotationParseError(std::format("Invalid key {}", key)); } + + this->addEntry(key, value); } } @@ -78,6 +90,16 @@ namespace Components }); } + bool MapRotation::RotationData::containsHandler(const std::string& key) const + { + return this->rotationHandlers_.contains(key); + } + + void MapRotation::RotationData::clear() noexcept + { + this->rotationEntries_.clear(); + } + nlohmann::json MapRotation::RotationData::to_json() const { std::vector mapVector; @@ -97,8 +119,8 @@ namespace Components auto mapRotationJson = nlohmann::json { - {"maps", mapVector}, - {"gametypes", gametypeVector}, + { "maps", mapVector }, + { "gametypes", gametypeVector }, }; return mapRotationJson; @@ -183,7 +205,7 @@ namespace Components return false; } - if (Dvar::Var("party_enable").get() && Dvar::Var("party_host").get()) + if (Party::IsEnabled() && Dvar::Var("party_host").get()) { Logger::Warning(Game::CON_CHANNEL_SERVER, "Not performing map rotation as we are hosting a party!\n"); return false; @@ -212,6 +234,13 @@ namespace Components Game::Dvar_SetStringByName("g_gametype", gametype.data()); } + void MapRotation::ApplyExec(const std::string& name) + { + assert(!name.empty()); + Command::Execute(std::format("exec {}", name), false); + Command::Execute(std::format("exec game_settings/{}", name), false); + } + void MapRotation::RestartCurrentMap() { std::string svMapname = (*Game::sv_mapname)->current.string; @@ -234,21 +263,15 @@ namespace Components while (i < rotation.getEntriesSize()) { const auto& entry = rotation.getNextEntry(); + rotation.callHandler(entry); + Logger::Print("MapRotation: applying key '{}' with value '{}'\n", entry.first, entry.second); + if (entry.first == "map"s) { - Logger::Print("Loading new map: '{}'", entry.second); - ApplyMap(entry.second); - // Map was found so we exit the loop break; } - if (entry.first == "gametype"s) - { - Logger::Print("Applying new gametype: '{}'", entry.second); - ApplyGametype(entry.second); - } - ++i; } @@ -374,13 +397,15 @@ namespace Components AddMapRotationCommands(); Utils::Hook::Set(0x4152E8, SV_MapRotate_f); + DedicatedRotation.setHandler("map", ApplyMap); + DedicatedRotation.setHandler("gametype", ApplyGametype); + DedicatedRotation.setHandler("exec", ApplyExec); + Events::OnDvarInit(RegisterMapRotationDvars); } bool MapRotation::unitTest() { - RotationData rotation; - Logger::Debug("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"; @@ -395,6 +420,8 @@ namespace Components return false; } + DedicatedRotation.clear(); + const auto* mistake = "spdevmap mp_dome"; auto success = false; diff --git a/src/Components/Modules/MapRotation.hpp b/src/Components/Modules/MapRotation.hpp index 68e51b23..3acbd4f3 100644 --- a/src/Components/Modules/MapRotation.hpp +++ b/src/Components/Modules/MapRotation.hpp @@ -14,9 +14,27 @@ namespace Components bool unitTest() override; private: - struct MapRotationParseError : public std::exception + class MapRotationParseError : public std::runtime_error { - [[nodiscard]] const char* what() const noexcept override { return "Map Rotation Parse Error"; } + private: + static std::string fmt(const std::string& message) + { + std::string error = "Map Rotation Parse Error"; + + if (!message.empty()) + { + error.append(": "); + error.append(message); + } + + return error; + } + + public: + MapRotationParseError(const std::string& message) + : std::runtime_error(fmt(message)) + { + } }; class RotationData @@ -24,6 +42,8 @@ namespace Components public: using rotationEntry = std::pair; + using rotationCallback = std::function; + RotationData(); void randomize(); @@ -36,15 +56,22 @@ namespace Components rotationEntry& getNextEntry(); rotationEntry& peekNextEntry(); + void setHandler(const std::string& key, const rotationCallback& callback); + void callHandler(const rotationEntry& entry) const; + void parse(const std::string& data); [[nodiscard]] bool empty() const noexcept; [[nodiscard]] bool contains(const std::string& key, const std::string& value) const; + [[nodiscard]] bool containsHandler(const std::string& key) const; + + void clear() noexcept; [[nodiscard]] nlohmann::json to_json() const; private: std::vector rotationEntries_; + std::unordered_map rotationHandlers_; std::size_t index_; }; @@ -67,6 +94,7 @@ namespace Components static bool ShouldRotate(); static void ApplyMap(const std::string& map); static void ApplyGametype(const std::string& gametype); + static void ApplyExec(const std::string& name); static void RestartCurrentMap(); static void ApplyRotation(RotationData& rotation); static void ApplyMapRotationCurrent(const std::string& data); diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index be59087f..da4a65f3 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -316,11 +316,17 @@ namespace Components void Maps::GetBSPName(char* buffer, size_t size, const char* format, const char* mapname) { - if (!Utils::String::StartsWith(mapname, "mp_") && !Utils::String::StartsWith(mapname, "zm_")) + if (!Utils::String::StartsWith(mapname, "mp_")) { format = "maps/%s.d3dbsp"; } + // TODO: Remove this hack by using CoD4 version of the map + if (std::strcmp(mapname, "mp_shipment") == 0) + { + mapname = "mp_shipment_long"; + } + _snprintf_s(buffer, size, _TRUNCATE, format, mapname); } diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index 00c551a2..7ce68157 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -4,7 +4,7 @@ namespace Components { Utils::Signal Network::StartupSignal; // Packet interception - std::unordered_map Network::CL_Callbacks; + std::unordered_map Network::CL_Callbacks; Network::Address::Address() { @@ -283,7 +283,7 @@ namespace Components Utils::Hook::Call(0x414D40)(client, msg); } - void Network::OnClientPacket(const std::string& command, const NetworkCallback& callback) + void Network::OnClientPacket(const std::string& command, const networkCallback& callback) { CL_Callbacks[Utils::String::ToLower(command)] = callback; } diff --git a/src/Components/Modules/Network.hpp b/src/Components/Modules/Network.hpp index bd55a5cc..89e46bec 100644 --- a/src/Components/Modules/Network.hpp +++ b/src/Components/Modules/Network.hpp @@ -48,7 +48,7 @@ namespace Components typedef void(CallbackRaw)(); - using NetworkCallback = std::function; + using networkCallback = std::function; Network(); @@ -72,11 +72,11 @@ namespace Components static void BroadcastRange(unsigned int min, unsigned int max, const std::string& data); static void BroadcastAll(const std::string& data); - static void OnClientPacket(const std::string& command, const NetworkCallback& callback); + static void OnClientPacket(const std::string& command, const networkCallback& callback); private: static Utils::Signal StartupSignal; - static std::unordered_map CL_Callbacks; + static std::unordered_map CL_Callbacks; static void NetworkStart(); static void NetworkStartStub(); diff --git a/src/Components/Modules/Session.cpp b/src/Components/Modules/Session.cpp index 6058f334..77fbc22b 100644 --- a/src/Components/Modules/Session.cpp +++ b/src/Components/Modules/Session.cpp @@ -14,7 +14,7 @@ namespace Components Utils::Cryptography::ECC::Key Session::SignatureKey; - std::unordered_map Session::PacketHandlers; + std::unordered_map Session::PacketHandlers; std::queue> Session::SignatureQueue; @@ -61,7 +61,7 @@ namespace Components #endif } - void Session::Handle(const std::string& packet, const Network::NetworkCallback& callback) + void Session::Handle(const std::string& packet, const Network::networkCallback& callback) { #ifdef DISABLE_SESSION Network::OnClientPacket(packet, callback); diff --git a/src/Components/Modules/Session.hpp b/src/Components/Modules/Session.hpp index 181d9ce6..5a2cfbca 100644 --- a/src/Components/Modules/Session.hpp +++ b/src/Components/Modules/Session.hpp @@ -35,7 +35,7 @@ namespace Components void preDestroy() override; static void Send(const Network::Address& target, const std::string& command, const std::string& data = ""); - static void Handle(const std::string& packet, const Network::NetworkCallback& callback); + static void Handle(const std::string& packet, const Network::networkCallback& callback); private: static volatile bool Terminate; @@ -46,7 +46,7 @@ namespace Components static Utils::Cryptography::ECC::Key SignatureKey; - static std::unordered_map PacketHandlers; + static std::unordered_map PacketHandlers; static std::queue> SignatureQueue;