[GSC]: Script aliases (#610)

This commit is contained in:
Edo 2022-11-29 14:18:10 +00:00 committed by GitHub
parent c3d6b20644
commit b195d96abb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 243 additions and 176 deletions

View File

@ -7,10 +7,10 @@ namespace Components
struct BotMovementInfo
{
int buttons; // Actions
int8_t forward;
int8_t right;
uint16_t weapon;
std::int32_t buttons; // Actions
std::int8_t forward;
std::int8_t right;
std::uint16_t weapon;
bool active;
};
@ -19,7 +19,7 @@ namespace Components
struct BotAction
{
std::string action;
int key;
std::int32_t key;
};
static const BotAction BotActions[] =
@ -47,7 +47,7 @@ namespace Components
static bool loadedNames = false; // Load file only once
const char* botName;
if (Bots::BotNames.empty() && !loadedNames)
if (BotNames.empty() && !loadedNames)
{
FileSystem::File bots("bots.txt");
loadedNames = true;
@ -59,20 +59,20 @@ namespace Components
for (auto& name : names)
{
Utils::String::Replace(name, "\r", "");
name = Utils::String::Trim(name);
Utils::String::Trim(name);
if (!name.empty())
{
Bots::BotNames.push_back(name);
BotNames.push_back(name);
}
}
}
}
if (!Bots::BotNames.empty())
if (!BotNames.empty())
{
botId %= Bots::BotNames.size();
botName = Bots::BotNames[botId++].data();
botId %= BotNames.size();
botName = BotNames[botId++].data();
}
else
{
@ -125,8 +125,7 @@ namespace Components
void Bots::AddMethods()
{
Script::AddMethod("IsBot", Bots::GScr_isTestClient); // Usage: self IsBot();
Script::AddMethod("IsTestClient", Bots::GScr_isTestClient); // Usage: self IsTestClient();
Script::AddMethMultiple(GScr_isTestClient, false, {"IsTestClient", "IsBot"}); // Usage: self IsTestClient();
Script::AddMethod("BotStop", [](Game::scr_entref_t entref) // Usage: <bot> BotStop();
{
@ -240,7 +239,8 @@ namespace Components
return;
}
Game::usercmd_s userCmd = {0};
Game::usercmd_s userCmd;
ZeroMemory(&userCmd, sizeof(Game::usercmd_s));
userCmd.serverTime = *Game::svs_time;
@ -260,7 +260,7 @@ namespace Components
pushad
push edi
call Bots::BotAiAction
call BotAiAction
add esp, 4
popad
@ -284,7 +284,7 @@ namespace Components
push [esp + 0x20 + 0x8]
push [esp + 0x20 + 0x8]
call Bots::G_SelectWeaponIndex
call G_SelectWeaponIndex
add esp, 0x8
popad
@ -307,12 +307,12 @@ namespace Components
Utils::Hook::Set<const char*>(0x48ADA6, "connect bot%d \"\\cg_predictItems\\1\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\rate\\5000\\name\\%s\\protocol\\%d\\checksum\\%d\\statver\\%d %u\\qport\\%d\"");
// Intercept sprintf for the connect string
Utils::Hook(0x48ADAB, Bots::BuildConnectString, HOOK_CALL).install()->quick();
Utils::Hook(0x48ADAB, BuildConnectString, HOOK_CALL).install()->quick();
Utils::Hook(0x627021, Bots::SV_BotUserMove_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x627241, Bots::SV_BotUserMove_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x627021, SV_BotUserMove_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x627241, SV_BotUserMove_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x441B80, Bots::G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick();
Utils::Hook(0x441B80, G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick();
// Reset BotMovementInfo.active when client is dropped
Events::OnClientDisconnect([](const int clientNum)
@ -365,10 +365,10 @@ namespace Components
Toast::Show("cardicon_headshot", "^2Success", Utils::String::VA("Spawning %d %s...", count, (count == 1 ? "bot" : "bots")), 3000);
Logger::Debug("Spawning {} {}", count, (count == 1 ? "bot" : "bots"));
Bots::Spawn(count);
Spawn(count);
});
Bots::AddMethods();
AddMethods();
// In case a loaded mod didn't call "BotStop" before the VM shutdown
Events::OnVMShutdown([]

View File

@ -318,7 +318,7 @@ namespace Components
return;
}
if (strncmp(BugName->current.string, "bug", 3) != 0)
if (std::strncmp(BugName->current.string, "bug", 3) != 0)
{
Game::Dvar_SetString(BugName, "bug0");
return;

View File

@ -229,7 +229,8 @@ namespace Components
// Don't perform any checks if name didn't change
if (name == lastValidName) return;
std::string saneName = TextRenderer::StripAllTextIcons(TextRenderer::StripColors(Utils::String::Trim(name)));
Utils::String::Trim(name);
std::string saneName = TextRenderer::StripAllTextIcons(TextRenderer::StripColors(name));
if (saneName.size() < 3 || (saneName[0] == '[' && saneName[1] == '{'))
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Username '{}' is invalid. It must at least be 3 characters long and not appear empty!\n", name);

View File

@ -3,8 +3,8 @@
namespace Components
{
std::unordered_map<std::string, Script::ScriptFunction> Script::CustomScrFunctions;
std::unordered_map<std::string, Script::ScriptMethod> Script::CustomScrMethods;
std::vector<Script::ScriptFunction> Script::CustomScrFunctions;
std::vector<Script::ScriptMethod> Script::CustomScrMethods;
std::string Script::ScriptName;
std::vector<std::string> Script::ScriptNameStack;
@ -278,43 +278,74 @@ namespace Components
Game::GScr_LoadGameTypeScript();
}
void Script::AddFunction(const std::string& name, Game::BuiltinFunction func, bool type)
void Script::AddFunction(const std::string& name, const Game::BuiltinFunction func, const bool type)
{
ScriptFunction toAdd;
toAdd.actionFunc = func;
toAdd.type = type;
toAdd.aliases.push_back({Utils::String::ToLower(name)});
CustomScrFunctions.insert_or_assign(Utils::String::ToLower(name), toAdd);
CustomScrFunctions.emplace_back(toAdd);
}
void Script::AddMethod(const std::string& name, Game::BuiltinMethod func, bool type)
void Script::AddMethod(const std::string& name, const Game::BuiltinMethod func, const bool type)
{
ScriptMethod toAdd;
toAdd.actionFunc = func;
toAdd.type = type;
toAdd.aliases.push_back({Utils::String::ToLower(name)});
CustomScrMethods.insert_or_assign(Utils::String::ToLower(name), toAdd);
CustomScrMethods.emplace_back(toAdd);
}
void Script::AddFuncMultiple(Game::BuiltinFunction func, bool type, scriptNames aliases)
{
ScriptFunction toAdd;
auto aliasesToAdd = Utils::String::ApplyToLower(aliases);
toAdd.actionFunc = func;
toAdd.type = type;
toAdd.aliases = std::move(aliasesToAdd);
CustomScrFunctions.emplace_back(toAdd);
}
void Script::AddMethMultiple(Game::BuiltinMethod func, bool type, scriptNames aliases)
{
ScriptMethod toAdd;
auto aliasesToAdd = Utils::String::ApplyToLower(aliases);
toAdd.actionFunc = func;
toAdd.type = type;
toAdd.aliases = std::move(aliasesToAdd);
CustomScrMethods.emplace_back(toAdd);
}
Game::BuiltinFunction Script::BuiltIn_GetFunctionStub(const char** pName, int* type)
{
if (pName != nullptr)
{
// If no function was found let's call game's function
if (const auto itr = CustomScrFunctions.find(Utils::String::ToLower(*pName)); itr != CustomScrFunctions.end())
const auto name = Utils::String::ToLower(*pName);
for (const auto& func : CustomScrFunctions)
{
*type = itr->second.type;
return itr->second.actionFunc;
}
if (std::ranges::find(func.aliases, name) != func.aliases.end())
{
*type = func.type;
return func.actionFunc;
}
}
}
else
{
for (const auto& [name, builtin] : CustomScrFunctions)
for (const auto& func : CustomScrFunctions)
{
Game::Scr_RegisterFunction(reinterpret_cast<int>(builtin.actionFunc), name.data());
const auto& name = func.aliases[0];
Game::Scr_RegisterFunction(reinterpret_cast<int>(func.actionFunc), name.data());
}
}
// If no function was found let's call game's function
return Utils::Hook::Call<Game::BuiltinFunction(const char**, int*)>(0x5FA2B0)(pName, type); // BuiltIn_GetFunction
}
@ -322,21 +353,26 @@ namespace Components
{
if (pName != nullptr)
{
// If no method was found let's call game's function
if (const auto itr = CustomScrMethods.find(Utils::String::ToLower(*pName)); itr != CustomScrMethods.end())
const auto name = Utils::String::ToLower(*pName);
for (const auto& meth : CustomScrMethods)
{
*type = itr->second.type;
return itr->second.actionFunc;
if (std::ranges::find(meth.aliases, name) != meth.aliases.end())
{
*type = meth.type;
return meth.actionFunc;
}
}
}
else
{
for (const auto& [name, builtin] : CustomScrMethods)
for (const auto& meth : CustomScrMethods)
{
Game::Scr_RegisterFunction(reinterpret_cast<int>(builtin.actionFunc), name.data());
const auto& name = meth.aliases[0];
Game::Scr_RegisterFunction(reinterpret_cast<int>(meth.actionFunc), name.data());
}
}
// If no method was found let's call game's function
return Utils::Hook::Call<Game::BuiltinMethod(const char**, int*)>(0x5FA360)(pName, type); // Player_GetMethod
}

View File

@ -7,9 +7,13 @@ namespace Components
public:
Script();
using scriptNames = std::vector<std::string>;
static void AddFunction(const std::string& name, Game::BuiltinFunction func, bool type = false);
static void AddMethod(const std::string& name, Game::BuiltinMethod func, bool type = false);
static void AddFuncMultiple(Game::BuiltinFunction func, bool type, scriptNames);
static void AddMethMultiple(Game::BuiltinMethod func, bool type, scriptNames);
static Game::client_t* GetClient(const Game::gentity_t* gentity);
static const char* GetCodePosForParam(int index);
@ -40,16 +44,18 @@ namespace Components
{
Game::BuiltinFunction actionFunc;
bool type;
scriptNames aliases;
};
struct ScriptMethod
{
Game::BuiltinMethod actionFunc;
bool type;
scriptNames aliases;
};
static std::unordered_map<std::string, ScriptFunction> CustomScrFunctions;
static std::unordered_map<std::string, ScriptMethod> CustomScrMethods;
static std::vector<ScriptFunction> CustomScrFunctions;
static std::vector<ScriptMethod> CustomScrMethods;
static std::string ScriptName;
static std::vector<std::string> ScriptNameStack;

View File

@ -273,30 +273,6 @@ namespace Components
});
}
void ScriptExtension::Scr_TableLookupIStringByRow()
{
if (Game::Scr_GetNumParam() < 3)
{
Game::Scr_Error("USAGE: tableLookupIStringByRow( filename, rowNum, returnValueColumnNum )\n");
return;
}
const auto* fileName = Game::Scr_GetString(0);
const auto rowNum = Game::Scr_GetInt(1);
const auto returnValueColumnNum = Game::Scr_GetInt(2);
const auto* table = Game::DB_FindXAssetHeader(Game::ASSET_TYPE_STRINGTABLE, fileName).stringTable;
if (table == nullptr)
{
Game::Scr_ParamError(0, Utils::String::VA("%s does not exist\n", fileName));
return;
}
const auto* value = Game::StringTable_GetColumnValueForRow(table, rowNum, returnValueColumnNum);
Game::Scr_AddIString(value);
}
void ScriptExtension::AddEntityFields()
{
AddEntityField("entityflags", Game::F_INT,
@ -330,16 +306,10 @@ namespace Components
AddEntityFields();
AddClientFields();
// Correct builtin function pointer
Utils::Hook::Set<Game::BuiltinFunction>(0x79A90C, Scr_TableLookupIStringByRow);
Utils::Hook(0x4EC721, GScr_AddFieldsForEntityStub, HOOK_CALL).install()->quick(); // GScr_AddFieldsForEntity
Utils::Hook(0x41BED2, Scr_SetObjectFieldStub, HOOK_CALL).install()->quick(); // SetEntityFieldValue
Utils::Hook(0x5FBF01, Scr_SetClientFieldStub, HOOK_CALL).install()->quick(); // Scr_SetObjectField
Utils::Hook(0x4FF413, Scr_GetEntityFieldStub, HOOK_CALL).install()->quick(); // Scr_GetObjectField
// Fix format string in Scr_RandomFloatRange
Utils::Hook::Set<const char*>(0x5F10C6, "Scr_RandomFloatRange parms: %f %f ");
}
}

View File

@ -27,6 +27,5 @@ namespace Components
static void AddMethods();
static void AddEntityFields();
static void AddClientFields();
static void Scr_TableLookupIStringByRow();
};
}

View File

@ -20,8 +20,38 @@ namespace Components
return &Game::g_hudelems[entref.entnum];
}
void ScriptPatches::Scr_TableLookupIStringByRow_Hk()
{
if (Game::Scr_GetNumParam() < 3)
{
Game::Scr_Error("USAGE: tableLookupIStringByRow( filename, rowNum, returnValueColumnNum )\n");
return;
}
const auto* fileName = Game::Scr_GetString(0);
const auto rowNum = Game::Scr_GetInt(1);
const auto returnValueColumnNum = Game::Scr_GetInt(2);
const auto* table = Game::DB_FindXAssetHeader(Game::ASSET_TYPE_STRINGTABLE, fileName).stringTable;
if (table == nullptr)
{
Game::Scr_ParamError(0, Utils::String::VA("%s does not exist\n", fileName));
return;
}
const auto* value = Game::StringTable_GetColumnValueForRow(table, rowNum, returnValueColumnNum);
Game::Scr_AddIString(value);
}
ScriptPatches::ScriptPatches()
{
// Fix format string in Scr_RandomFloatRange
Utils::Hook::Set<const char*>(0x5F10C6, "Scr_RandomFloatRange parms: %f %f ");
// Correct builtin function pointer
Utils::Hook::Set<Game::BuiltinFunction>(0x79A90C, Scr_TableLookupIStringByRow_Hk);
Script::AddMethod("ClearHudText", [](Game::scr_entref_t entref) -> void
{
auto* hud = HECmd_GetHudElem(entref);

View File

@ -9,5 +9,7 @@ namespace Components
private:
static Game::game_hudelem_s* HECmd_GetHudElem(Game::scr_entref_t entref);
static void Scr_TableLookupIStringByRow_Hk();
};
}

View File

@ -22,7 +22,7 @@ namespace Components
_vsnprintf_s(buf, _TRUNCATE, message, va);
va_end(va);
Logger::MessagePrint(channel, {buf});
MessagePrint(channel, {buf});
}
void Logger::MessagePrint(const int channel, const std::string& msg)
@ -42,14 +42,14 @@ namespace Components
return;
}
if (!Logger::IsConsoleReady())
if (!IsConsoleReady())
{
OutputDebugStringA(out.data());
}
if (!Game::Sys_IsMainThread())
{
Logger::EnqueueMessage(msg);
EnqueueMessage(msg);
}
else
{
@ -67,14 +67,14 @@ namespace Components
const auto out = std::format("^2{}\n", msg);
#endif
Logger::MessagePrint(Game::CON_CHANNEL_DONT_FILTER, out);
MessagePrint(Game::CON_CHANNEL_DONT_FILTER, out);
}
void Logger::PrintInternal(int channel, std::string_view fmt, std::format_args&& args)
{
const auto msg = std::vformat(fmt, args);
Logger::MessagePrint(channel, msg);
MessagePrint(channel, msg);
}
void Logger::ErrorInternal(const Game::errorParm_t error, const std::string_view fmt, std::format_args&& args)
@ -92,7 +92,7 @@ namespace Components
const auto msg = "^1Error: " + std::vformat(fmt, args);
++(*Game::com_errorPrintsCount);
Logger::MessagePrint(channel, msg);
MessagePrint(channel, msg);
if (*Game::cls_uiStarted != 0 && (*Game::com_fixedConsolePosition == 0))
{
@ -104,36 +104,36 @@ namespace Components
{
const auto msg = "^3" + std::vformat(fmt, args);
Logger::MessagePrint(channel, msg);
MessagePrint(channel, msg);
}
void Logger::Frame()
{
std::unique_lock _(Logger::MessageMutex);
std::unique_lock _(MessageMutex);
for (auto i = Logger::MessageQueue.begin(); i != Logger::MessageQueue.end();)
for (auto i = MessageQueue.begin(); i != MessageQueue.end();)
{
Game::Com_PrintMessage(Game::CON_CHANNEL_DONT_FILTER, i->data(), 0);
if (!Logger::IsConsoleReady())
if (!IsConsoleReady())
{
OutputDebugStringA(i->data());
}
i = Logger::MessageQueue.erase(i);
i = MessageQueue.erase(i);
}
}
void Logger::PipeOutput(const std::function<void(const std::string&)>& callback)
{
Logger::PipeCallback = callback;
PipeCallback = callback;
}
void Logger::PrintMessagePipe(const char* data)
{
if (Logger::PipeCallback)
if (PipeCallback)
{
Logger::PipeCallback(data);
PipeCallback(data);
}
}
@ -144,7 +144,7 @@ namespace Components
return;
}
for (const auto& addr : Logger::LoggingAddresses[gLog & 1])
for (const auto& addr : LoggingAddresses[gLog & 1])
{
Network::SendCommand(addr, "print", data);
}
@ -169,20 +169,20 @@ namespace Components
}
// Allow the network log to run even if logFile was not opened
Logger::NetworkLog(string, true);
NetworkLog(string, true);
}
__declspec(naked) void Logger::PrintMessage_Stub()
{
__asm
{
mov eax, Logger::PipeCallback
mov eax, PipeCallback
test eax, eax
jz returnPrint
pushad
push [esp + 28h]
call Logger::PrintMessagePipe
call PrintMessagePipe
add esp, 4h
popad
retn
@ -191,7 +191,7 @@ namespace Components
pushad
push 0
push [esp + 2Ch]
call Logger::NetworkLog
call NetworkLog
add esp, 8h
popad
@ -205,8 +205,8 @@ namespace Components
void Logger::EnqueueMessage(const std::string& message)
{
std::unique_lock _(Logger::MessageMutex);
Logger::MessageQueue.push_back(message);
std::unique_lock _(MessageMutex);
MessageQueue.push_back(message);
}
void Logger::RedirectOSPath(const char* file, char* folder)
@ -232,7 +232,7 @@ namespace Components
push [esp + 28h]
push [esp + 30h]
call Logger::RedirectOSPath
call RedirectOSPath
add esp, 8h
@ -256,9 +256,9 @@ namespace Components
Network::Address addr(params->get(1));
if (std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr) == Logger::LoggingAddresses[0].end())
if (std::find(LoggingAddresses[0].begin(), LoggingAddresses[0].end(), addr) == LoggingAddresses[0].end())
{
Logger::LoggingAddresses[0].push_back(addr);
LoggingAddresses[0].push_back(addr);
}
});
@ -267,37 +267,37 @@ namespace Components
if (params->size() < 2) return;
const auto num = atoi(params->get(1));
if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[0].size())
if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < LoggingAddresses[0].size())
{
auto addr = Logger::LoggingAddresses[0].begin() + num;
Logger::Print("Address {} removed\n", addr->getString());
Logger::LoggingAddresses[0].erase(addr);
Print("Address {} removed\n", addr->getString());
LoggingAddresses[0].erase(addr);
}
else
{
Network::Address addr(params->get(1));
const auto i = std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr);
if (i != Logger::LoggingAddresses[0].end())
const auto i = std::find(LoggingAddresses[0].begin(), LoggingAddresses[0].end(), addr);
if (i != LoggingAddresses[0].end())
{
Logger::LoggingAddresses[0].erase(i);
Logger::Print("Address {} removed\n", addr.getString());
LoggingAddresses[0].erase(i);
Print("Address {} removed\n", addr.getString());
}
else
{
Logger::Print("Address {} not found!\n", addr.getString());
Print("Address {} not found!\n", addr.getString());
}
}
});
Command::AddSV("log_list", [](Command::Params*)
Command::AddSV("log_list", []([[maybe_unused]] Command::Params* params)
{
Logger::Print("# ID: Address\n");
Logger::Print("-------------\n");
Print("# ID: Address\n");
Print("-------------\n");
for (unsigned int i = 0; i < Logger::LoggingAddresses[0].size(); ++i)
for (unsigned int i = 0; i < LoggingAddresses[0].size(); ++i)
{
Logger::Print("#{:03d}: {}\n", i, Logger::LoggingAddresses[0][i].getString());
Print("#{:03d}: {}\n", i, LoggingAddresses[0][i].getString());
}
});
@ -307,9 +307,9 @@ namespace Components
const Network::Address addr(params->get(1));
if (std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr) == Logger::LoggingAddresses[1].end())
if (std::find(LoggingAddresses[1].begin(), LoggingAddresses[1].end(), addr) == LoggingAddresses[1].end())
{
Logger::LoggingAddresses[1].push_back(addr);
LoggingAddresses[1].push_back(addr);
}
});
@ -318,37 +318,37 @@ namespace Components
if (params->size() < 2) return;
const auto num = std::atoi(params->get(1));
if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[1].size())
if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < LoggingAddresses[1].size())
{
const auto addr = Logger::LoggingAddresses[1].begin() + num;
Logger::Print("Address {} removed\n", addr->getString());
Logger::LoggingAddresses[1].erase(addr);
const auto addr = LoggingAddresses[1].begin() + num;
Print("Address {} removed\n", addr->getString());
LoggingAddresses[1].erase(addr);
}
else
{
const Network::Address addr(params->get(1));
const auto i = std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr);
if (i != Logger::LoggingAddresses[1].end())
const auto i = std::ranges::find(LoggingAddresses[1].begin(), LoggingAddresses[1].end(), addr);
if (i != LoggingAddresses[1].end())
{
Logger::LoggingAddresses[1].erase(i);
Logger::Print("Address {} removed\n", addr.getString());
LoggingAddresses[1].erase(i);
Print("Address {} removed\n", addr.getString());
}
else
{
Logger::Print("Address {} not found!\n", addr.getString());
Print("Address {} not found!\n", addr.getString());
}
}
});
Command::AddSV("g_log_list", [](Command::Params*)
{
Logger::Print("# ID: Address\n");
Logger::Print("-------------\n");
Print("# ID: Address\n");
Print("-------------\n");
for (std::size_t i = 0; i < Logger::LoggingAddresses[1].size(); ++i)
for (std::size_t i = 0; i < LoggingAddresses[1].size(); ++i)
{
Logger::Print("#{:03d}: {}\n", i, Logger::LoggingAddresses[1][i].getString());
Print("#{:03d}: {}\n", i, LoggingAddresses[1][i].getString());
}
});
}
@ -356,30 +356,28 @@ namespace Components
Logger::Logger()
{
Dvar::Register<bool>("iw4x_onelog", false, Game::DVAR_LATCH | Game::DVAR_ARCHIVE, "Only write the game log to the 'userraw' OS folder");
Utils::Hook(0x642139, Logger::BuildOSPath_Stub, HOOK_JUMP).install()->quick();
Utils::Hook(0x642139, BuildOSPath_Stub, HOOK_JUMP).install()->quick();
Logger::PipeOutput(nullptr);
Scheduler::Loop(Frame, Scheduler::Pipeline::SERVER);
Scheduler::Loop(Logger::Frame, Scheduler::Pipeline::SERVER);
Utils::Hook(Game::G_LogPrintf, Logger::G_LogPrintf_Hk, HOOK_JUMP).install()->quick();
Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessage_Stub, HOOK_JUMP).install()->quick();
Utils::Hook(Game::G_LogPrintf, G_LogPrintf_Hk, HOOK_JUMP).install()->quick();
Utils::Hook(Game::Com_PrintMessage, PrintMessage_Stub, HOOK_JUMP).install()->quick();
if (Loader::IsPerformingUnitTests())
{
Utils::Hook(Game::Com_Printf, Logger::Print_Stub, HOOK_JUMP).install()->quick();
Utils::Hook(Game::Com_Printf, Print_Stub, HOOK_JUMP).install()->quick();
}
Events::OnSVInit(Logger::AddServerCommands);
Events::OnSVInit(AddServerCommands);
}
Logger::~Logger()
{
Logger::LoggingAddresses[0].clear();
Logger::LoggingAddresses[1].clear();
LoggingAddresses[0].clear();
LoggingAddresses[1].clear();
std::unique_lock lock(Logger::MessageMutex);
Logger::MessageQueue.clear();
std::unique_lock lock(MessageMutex);
MessageQueue.clear();
lock.unlock();
// Flush the console log

View File

@ -59,7 +59,7 @@ namespace Components
for (auto& node : nodeList)
{
Utils::String::Replace(node, "\r", "");
node = Utils::String::Trim(node);
Utils::String::Trim(node);
Node::Add(node);
}
}

View File

@ -18,7 +18,7 @@ namespace Components
}
std::string readablePlayerName(buffer);
readablePlayerName = Utils::String::Trim(readablePlayerName);
Utils::String::Trim(readablePlayerName);
if (readablePlayerName.size() < 3)
{

View File

@ -127,8 +127,8 @@ namespace Components
Network::OnClientPacket("rcon", [](const Network::Address& address, [[maybe_unused]] const std::string& data)
{
std::string data_ = data;
Utils::String::Trim(data_);
const auto pos = data.find_first_of(' ');
if (pos == std::string::npos)
{

View File

@ -28,23 +28,24 @@
#pragma warning(disable: 4244)
#include <DbgHelp.h>
#include <sstream>
#include <fstream>
#include <cctype>
#include <regex>
#include <thread>
#include <future>
#include <unordered_map>
#include <queue>
#include <algorithm>
#include <limits>
#include <cctype>
#include <chrono>
#include <cmath>
#include <filesystem>
#include <optional>
#include <random>
#include <chrono>
#include <format>
#include <fstream>
#include <future>
#include <limits>
#include <optional>
#include <queue>
#include <random>
#include <ranges>
#include <regex>
#include <source_location>
#include <sstream>
#include <thread>
#include <unordered_map>
#pragma warning(pop)

View File

@ -145,9 +145,9 @@ namespace Utils::String
}
// Trim from both ends
std::string& Trim(std::string& str)
void Trim(std::string& str)
{
return LTrim(RTrim(str));
LTrim(RTrim(str));
}
std::string Convert(const std::wstring& wstr)

View File

@ -11,7 +11,7 @@ namespace Utils::String
VAProvider() : currentBuffer(0) {}
~VAProvider() = default;
const char* get(const char* format, va_list ap)
[[nodiscard]] const char* get(const char* format, va_list ap)
{
++this->currentBuffer %= ARRAYSIZE(this->stringPool);
auto entry = &this->stringPool[this->currentBuffer];
@ -82,37 +82,61 @@ namespace Utils::String
}
}
const char* VA(const char* fmt, ...);
[[nodiscard]] const char* VA(const char* fmt, ...);
std::string ToLower(const std::string& text);
std::string ToUpper(const std::string& text);
[[nodiscard]] std::string ToLower(const std::string& text);
[[nodiscard]] std::string ToUpper(const std::string& text);
bool Compare(const std::string& lhs, const std::string& rhs);
template <class OutputIter>
[[nodiscard]] OutputIter ApplyToLower(OutputIter container)
{
OutputIter result;
std::ranges::transform(container, std::back_inserter(result), [](const std::string& s) -> std::string
{
return ToLower(s);
});
std::vector<std::string> Split(const std::string& str, char delim);
return result;
}
template <class OutputIter>
[[nodiscard]] OutputIter ApplyToUpper(OutputIter container)
{
OutputIter result;
std::ranges::transform(container, std::back_inserter(result), [](const std::string& s) -> std::string
{
return ToUpper(s);
});
return result;
}
[[nodiscard]] bool Compare(const std::string& lhs, const std::string& rhs);
[[nodiscard]] std::vector<std::string> Split(const std::string& str, char delim);
void Replace(std::string& str, const std::string& from, const std::string& to);
bool StartsWith(const std::string& haystack, const std::string& needle);
bool EndsWith(const std::string& haystack, const std::string& needle);
[[nodiscard]] bool StartsWith(const std::string& haystack, const std::string& needle);
[[nodiscard]] bool EndsWith(const std::string& haystack, const std::string& needle);
bool IsNumber(const std::string& str);
[[nodiscard]] bool IsNumber(const std::string& str);
std::string& LTrim(std::string& str);
std::string& RTrim(std::string& str);
std::string& Trim(std::string& str);
void Trim(std::string& str);
std::string Convert(const std::wstring& wstr);
std::wstring Convert(const std::string& str);
[[nodiscard]] std::string Convert(const std::wstring& wstr);
[[nodiscard]] std::wstring Convert(const std::string& str);
std::string FormatTimeSpan(int milliseconds);
std::string FormatBandwidth(std::size_t bytes, int milliseconds);
[[nodiscard]] std::string FormatTimeSpan(int milliseconds);
[[nodiscard]] std::string FormatBandwidth(std::size_t bytes, int milliseconds);
std::string DumpHex(const std::string& data, const std::string& separator = " ");
[[nodiscard]] std::string DumpHex(const std::string& data, const std::string& separator = " ");
std::string XOR(std::string str, char value);
[[nodiscard]] std::string XOR(std::string str, char value);
std::string EncodeBase64(const char* input, unsigned long inputSize);
std::string EncodeBase64(const std::string& input);
[[nodiscard]] std::string EncodeBase64(const char* input, unsigned long inputSize);
[[nodiscard]] std::string EncodeBase64(const std::string& input);
std::string EncodeBase128(const std::string& input);
[[nodiscard]] std::string EncodeBase128(const std::string& input);
}