[MapRotation]: Refactor (#916)

This commit is contained in:
Edo 2023-04-09 18:26:25 +02:00 committed by GitHub
parent 1f94353e1a
commit 9b1f49252e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 96 additions and 35 deletions

View File

@ -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);

View File

@ -1,5 +1,6 @@
#include <STDInclude.hpp>
#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<std::string> 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<bool>() && Dvar::Var("party_host").get<bool>())
if (Party::IsEnabled() && Dvar::Var("party_host").get<bool>())
{
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<void(*)()>(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;

View File

@ -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<std::string, std::string>;
using rotationCallback = std::function<void(const std::string&)>;
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<rotationEntry> rotationEntries_;
std::unordered_map<std::string, rotationCallback> 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);

View File

@ -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);
}

View File

@ -4,7 +4,7 @@ namespace Components
{
Utils::Signal<Network::CallbackRaw> Network::StartupSignal;
// Packet interception
std::unordered_map<std::string, Network::NetworkCallback> Network::CL_Callbacks;
std::unordered_map<std::string, Network::networkCallback> Network::CL_Callbacks;
Network::Address::Address()
{
@ -283,7 +283,7 @@ namespace Components
Utils::Hook::Call<void(Game::client_t*, Game::msg_t*)>(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;
}

View File

@ -48,7 +48,7 @@ namespace Components
typedef void(CallbackRaw)();
using NetworkCallback = std::function<void(Address&, const std::string&)>;
using networkCallback = std::function<void(Address&, const std::string&)>;
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<CallbackRaw> StartupSignal;
static std::unordered_map<std::string, NetworkCallback> CL_Callbacks;
static std::unordered_map<std::string, networkCallback> CL_Callbacks;
static void NetworkStart();
static void NetworkStartStub();

View File

@ -14,7 +14,7 @@ namespace Components
Utils::Cryptography::ECC::Key Session::SignatureKey;
std::unordered_map<std::string, Network::NetworkCallback> Session::PacketHandlers;
std::unordered_map<std::string, Network::networkCallback> Session::PacketHandlers;
std::queue<std::pair<Network::Address, std::string>> 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);

View File

@ -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<std::string, Network::NetworkCallback> PacketHandlers;
static std::unordered_map<std::string, Network::networkCallback> PacketHandlers;
static std::queue<std::pair<Network::Address, std::string>> SignatureQueue;