[MapRotation] Allow people to circumvent 1024 dvar character limit

This commit is contained in:
Diavolo 2022-06-13 17:32:45 +02:00
parent 020201ab1f
commit bf4ae7f116
No known key found for this signature in database
GPG Key ID: FA77F074E98D98A5
7 changed files with 130 additions and 37 deletions

View File

@ -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::milliseconds>(std::chrono::high_resolution_clock::now() - startTime).count();
Logger::Print("Test done ({}ms): {}\n\n", duration, (testRes ? "Success" : "Error"));
result &= testRes;

View File

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

View File

@ -89,21 +89,21 @@ namespace Components
std::vector<std::string> idVector;
std::vector<std::string> 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 },

View File

@ -113,19 +113,19 @@ namespace Components
void Logger::Frame()
{
std::lock_guard<std::mutex> _(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<int*>(0x1AD8F28))

View File

@ -61,6 +61,33 @@ namespace Components
}
}
json11::Json MapRotation::RotationData::to_json() const
{
std::vector<std::string> mapVector;
std::vector<std::string> 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<bool>())
@ -92,6 +119,31 @@ namespace Components
loaded = true;
}
void MapRotation::AddMapRotationCommands()
{
Command::Add("AddMap", [](Command::Params* params)
{
if (params->size() < 2)
{
Logger::Print("{} <map name> : 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("{} <gametype> : 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<bool>())
@ -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<void(*)()>(0x4152E8, SV_MapRotate_f);
SVRandomMapRotation = Dvar::Register<bool>("sv_randomMapRotation", false,
@ -196,4 +249,38 @@ namespace Components
SVDontRotate = Dvar::Register<bool>("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;
}
}

View File

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

View File

@ -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::milliseconds>(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;
}
}