[GSC]: Script aliases (#610)
This commit is contained in:
parent
c3d6b20644
commit
b195d96abb
@ -7,10 +7,10 @@ namespace Components
|
|||||||
|
|
||||||
struct BotMovementInfo
|
struct BotMovementInfo
|
||||||
{
|
{
|
||||||
int buttons; // Actions
|
std::int32_t buttons; // Actions
|
||||||
int8_t forward;
|
std::int8_t forward;
|
||||||
int8_t right;
|
std::int8_t right;
|
||||||
uint16_t weapon;
|
std::uint16_t weapon;
|
||||||
bool active;
|
bool active;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ namespace Components
|
|||||||
struct BotAction
|
struct BotAction
|
||||||
{
|
{
|
||||||
std::string action;
|
std::string action;
|
||||||
int key;
|
std::int32_t key;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const BotAction BotActions[] =
|
static const BotAction BotActions[] =
|
||||||
@ -47,7 +47,7 @@ namespace Components
|
|||||||
static bool loadedNames = false; // Load file only once
|
static bool loadedNames = false; // Load file only once
|
||||||
const char* botName;
|
const char* botName;
|
||||||
|
|
||||||
if (Bots::BotNames.empty() && !loadedNames)
|
if (BotNames.empty() && !loadedNames)
|
||||||
{
|
{
|
||||||
FileSystem::File bots("bots.txt");
|
FileSystem::File bots("bots.txt");
|
||||||
loadedNames = true;
|
loadedNames = true;
|
||||||
@ -59,20 +59,20 @@ namespace Components
|
|||||||
for (auto& name : names)
|
for (auto& name : names)
|
||||||
{
|
{
|
||||||
Utils::String::Replace(name, "\r", "");
|
Utils::String::Replace(name, "\r", "");
|
||||||
name = Utils::String::Trim(name);
|
Utils::String::Trim(name);
|
||||||
|
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
{
|
{
|
||||||
Bots::BotNames.push_back(name);
|
BotNames.push_back(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Bots::BotNames.empty())
|
if (!BotNames.empty())
|
||||||
{
|
{
|
||||||
botId %= Bots::BotNames.size();
|
botId %= BotNames.size();
|
||||||
botName = Bots::BotNames[botId++].data();
|
botName = BotNames[botId++].data();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -125,8 +125,7 @@ namespace Components
|
|||||||
|
|
||||||
void Bots::AddMethods()
|
void Bots::AddMethods()
|
||||||
{
|
{
|
||||||
Script::AddMethod("IsBot", Bots::GScr_isTestClient); // Usage: self IsBot();
|
Script::AddMethMultiple(GScr_isTestClient, false, {"IsTestClient", "IsBot"}); // Usage: self IsTestClient();
|
||||||
Script::AddMethod("IsTestClient", Bots::GScr_isTestClient); // Usage: self IsTestClient();
|
|
||||||
|
|
||||||
Script::AddMethod("BotStop", [](Game::scr_entref_t entref) // Usage: <bot> BotStop();
|
Script::AddMethod("BotStop", [](Game::scr_entref_t entref) // Usage: <bot> BotStop();
|
||||||
{
|
{
|
||||||
@ -240,7 +239,8 @@ namespace Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::usercmd_s userCmd = {0};
|
Game::usercmd_s userCmd;
|
||||||
|
ZeroMemory(&userCmd, sizeof(Game::usercmd_s));
|
||||||
|
|
||||||
userCmd.serverTime = *Game::svs_time;
|
userCmd.serverTime = *Game::svs_time;
|
||||||
|
|
||||||
@ -260,7 +260,7 @@ namespace Components
|
|||||||
pushad
|
pushad
|
||||||
|
|
||||||
push edi
|
push edi
|
||||||
call Bots::BotAiAction
|
call BotAiAction
|
||||||
add esp, 4
|
add esp, 4
|
||||||
|
|
||||||
popad
|
popad
|
||||||
@ -284,7 +284,7 @@ namespace Components
|
|||||||
|
|
||||||
push [esp + 0x20 + 0x8]
|
push [esp + 0x20 + 0x8]
|
||||||
push [esp + 0x20 + 0x8]
|
push [esp + 0x20 + 0x8]
|
||||||
call Bots::G_SelectWeaponIndex
|
call G_SelectWeaponIndex
|
||||||
add esp, 0x8
|
add esp, 0x8
|
||||||
|
|
||||||
popad
|
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\"");
|
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
|
// 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(0x627021, SV_BotUserMove_Hk, HOOK_CALL).install()->quick();
|
||||||
Utils::Hook(0x627241, Bots::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
|
// Reset BotMovementInfo.active when client is dropped
|
||||||
Events::OnClientDisconnect([](const int clientNum)
|
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);
|
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"));
|
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
|
// In case a loaded mod didn't call "BotStop" before the VM shutdown
|
||||||
Events::OnVMShutdown([]
|
Events::OnVMShutdown([]
|
||||||
|
@ -318,7 +318,7 @@ namespace Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(BugName->current.string, "bug", 3) != 0)
|
if (std::strncmp(BugName->current.string, "bug", 3) != 0)
|
||||||
{
|
{
|
||||||
Game::Dvar_SetString(BugName, "bug0");
|
Game::Dvar_SetString(BugName, "bug0");
|
||||||
return;
|
return;
|
||||||
|
@ -229,7 +229,8 @@ namespace Components
|
|||||||
// Don't perform any checks if name didn't change
|
// Don't perform any checks if name didn't change
|
||||||
if (name == lastValidName) return;
|
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] == '{'))
|
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);
|
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Username '{}' is invalid. It must at least be 3 characters long and not appear empty!\n", name);
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::unordered_map<std::string, Script::ScriptFunction> Script::CustomScrFunctions;
|
std::vector<Script::ScriptFunction> Script::CustomScrFunctions;
|
||||||
std::unordered_map<std::string, Script::ScriptMethod> Script::CustomScrMethods;
|
std::vector<Script::ScriptMethod> Script::CustomScrMethods;
|
||||||
|
|
||||||
std::string Script::ScriptName;
|
std::string Script::ScriptName;
|
||||||
std::vector<std::string> Script::ScriptNameStack;
|
std::vector<std::string> Script::ScriptNameStack;
|
||||||
@ -278,43 +278,74 @@ namespace Components
|
|||||||
Game::GScr_LoadGameTypeScript();
|
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;
|
ScriptFunction toAdd;
|
||||||
toAdd.actionFunc = func;
|
toAdd.actionFunc = func;
|
||||||
toAdd.type = type;
|
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;
|
ScriptMethod toAdd;
|
||||||
toAdd.actionFunc = func;
|
toAdd.actionFunc = func;
|
||||||
toAdd.type = type;
|
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)
|
Game::BuiltinFunction Script::BuiltIn_GetFunctionStub(const char** pName, int* type)
|
||||||
{
|
{
|
||||||
if (pName != nullptr)
|
if (pName != nullptr)
|
||||||
{
|
{
|
||||||
// If no function was found let's call game's function
|
const auto name = Utils::String::ToLower(*pName);
|
||||||
if (const auto itr = CustomScrFunctions.find(Utils::String::ToLower(*pName)); itr != CustomScrFunctions.end())
|
for (const auto& func : CustomScrFunctions)
|
||||||
{
|
{
|
||||||
*type = itr->second.type;
|
if (std::ranges::find(func.aliases, name) != func.aliases.end())
|
||||||
return itr->second.actionFunc;
|
{
|
||||||
}
|
*type = func.type;
|
||||||
|
return func.actionFunc;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
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
|
return Utils::Hook::Call<Game::BuiltinFunction(const char**, int*)>(0x5FA2B0)(pName, type); // BuiltIn_GetFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,21 +353,26 @@ namespace Components
|
|||||||
{
|
{
|
||||||
if (pName != nullptr)
|
if (pName != nullptr)
|
||||||
{
|
{
|
||||||
// If no method was found let's call game's function
|
const auto name = Utils::String::ToLower(*pName);
|
||||||
if (const auto itr = CustomScrMethods.find(Utils::String::ToLower(*pName)); itr != CustomScrMethods.end())
|
for (const auto& meth : CustomScrMethods)
|
||||||
{
|
{
|
||||||
*type = itr->second.type;
|
if (std::ranges::find(meth.aliases, name) != meth.aliases.end())
|
||||||
return itr->second.actionFunc;
|
{
|
||||||
|
*type = meth.type;
|
||||||
|
return meth.actionFunc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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
|
return Utils::Hook::Call<Game::BuiltinMethod(const char**, int*)>(0x5FA360)(pName, type); // Player_GetMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,9 +7,13 @@ namespace Components
|
|||||||
public:
|
public:
|
||||||
Script();
|
Script();
|
||||||
|
|
||||||
|
using scriptNames = std::vector<std::string>;
|
||||||
static void AddFunction(const std::string& name, Game::BuiltinFunction func, bool type = false);
|
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 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 Game::client_t* GetClient(const Game::gentity_t* gentity);
|
||||||
|
|
||||||
static const char* GetCodePosForParam(int index);
|
static const char* GetCodePosForParam(int index);
|
||||||
@ -40,16 +44,18 @@ namespace Components
|
|||||||
{
|
{
|
||||||
Game::BuiltinFunction actionFunc;
|
Game::BuiltinFunction actionFunc;
|
||||||
bool type;
|
bool type;
|
||||||
|
scriptNames aliases;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ScriptMethod
|
struct ScriptMethod
|
||||||
{
|
{
|
||||||
Game::BuiltinMethod actionFunc;
|
Game::BuiltinMethod actionFunc;
|
||||||
bool type;
|
bool type;
|
||||||
|
scriptNames aliases;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::unordered_map<std::string, ScriptFunction> CustomScrFunctions;
|
static std::vector<ScriptFunction> CustomScrFunctions;
|
||||||
static std::unordered_map<std::string, ScriptMethod> CustomScrMethods;
|
static std::vector<ScriptMethod> CustomScrMethods;
|
||||||
|
|
||||||
static std::string ScriptName;
|
static std::string ScriptName;
|
||||||
static std::vector<std::string> ScriptNameStack;
|
static std::vector<std::string> ScriptNameStack;
|
||||||
|
@ -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()
|
void ScriptExtension::AddEntityFields()
|
||||||
{
|
{
|
||||||
AddEntityField("entityflags", Game::F_INT,
|
AddEntityField("entityflags", Game::F_INT,
|
||||||
@ -330,16 +306,10 @@ namespace Components
|
|||||||
AddEntityFields();
|
AddEntityFields();
|
||||||
AddClientFields();
|
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(0x4EC721, GScr_AddFieldsForEntityStub, HOOK_CALL).install()->quick(); // GScr_AddFieldsForEntity
|
||||||
|
|
||||||
Utils::Hook(0x41BED2, Scr_SetObjectFieldStub, HOOK_CALL).install()->quick(); // SetEntityFieldValue
|
Utils::Hook(0x41BED2, Scr_SetObjectFieldStub, HOOK_CALL).install()->quick(); // SetEntityFieldValue
|
||||||
Utils::Hook(0x5FBF01, Scr_SetClientFieldStub, HOOK_CALL).install()->quick(); // Scr_SetObjectField
|
Utils::Hook(0x5FBF01, Scr_SetClientFieldStub, HOOK_CALL).install()->quick(); // Scr_SetObjectField
|
||||||
Utils::Hook(0x4FF413, Scr_GetEntityFieldStub, HOOK_CALL).install()->quick(); // Scr_GetObjectField
|
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 ");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,5 @@ namespace Components
|
|||||||
static void AddMethods();
|
static void AddMethods();
|
||||||
static void AddEntityFields();
|
static void AddEntityFields();
|
||||||
static void AddClientFields();
|
static void AddClientFields();
|
||||||
static void Scr_TableLookupIStringByRow();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,38 @@ namespace Components
|
|||||||
return &Game::g_hudelems[entref.entnum];
|
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()
|
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
|
Script::AddMethod("ClearHudText", [](Game::scr_entref_t entref) -> void
|
||||||
{
|
{
|
||||||
auto* hud = HECmd_GetHudElem(entref);
|
auto* hud = HECmd_GetHudElem(entref);
|
||||||
|
@ -9,5 +9,7 @@ namespace Components
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static Game::game_hudelem_s* HECmd_GetHudElem(Game::scr_entref_t entref);
|
static Game::game_hudelem_s* HECmd_GetHudElem(Game::scr_entref_t entref);
|
||||||
|
|
||||||
|
static void Scr_TableLookupIStringByRow_Hk();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ namespace Components
|
|||||||
_vsnprintf_s(buf, _TRUNCATE, message, va);
|
_vsnprintf_s(buf, _TRUNCATE, message, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
|
||||||
Logger::MessagePrint(channel, {buf});
|
MessagePrint(channel, {buf});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::MessagePrint(const int channel, const std::string& msg)
|
void Logger::MessagePrint(const int channel, const std::string& msg)
|
||||||
@ -42,14 +42,14 @@ namespace Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Logger::IsConsoleReady())
|
if (!IsConsoleReady())
|
||||||
{
|
{
|
||||||
OutputDebugStringA(out.data());
|
OutputDebugStringA(out.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Game::Sys_IsMainThread())
|
if (!Game::Sys_IsMainThread())
|
||||||
{
|
{
|
||||||
Logger::EnqueueMessage(msg);
|
EnqueueMessage(msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -67,14 +67,14 @@ namespace Components
|
|||||||
const auto out = std::format("^2{}\n", msg);
|
const auto out = std::format("^2{}\n", msg);
|
||||||
#endif
|
#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)
|
void Logger::PrintInternal(int channel, std::string_view fmt, std::format_args&& args)
|
||||||
{
|
{
|
||||||
const auto msg = std::vformat(fmt, 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)
|
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);
|
const auto msg = "^1Error: " + std::vformat(fmt, args);
|
||||||
|
|
||||||
++(*Game::com_errorPrintsCount);
|
++(*Game::com_errorPrintsCount);
|
||||||
Logger::MessagePrint(channel, msg);
|
MessagePrint(channel, msg);
|
||||||
|
|
||||||
if (*Game::cls_uiStarted != 0 && (*Game::com_fixedConsolePosition == 0))
|
if (*Game::cls_uiStarted != 0 && (*Game::com_fixedConsolePosition == 0))
|
||||||
{
|
{
|
||||||
@ -104,36 +104,36 @@ namespace Components
|
|||||||
{
|
{
|
||||||
const auto msg = "^3" + std::vformat(fmt, args);
|
const auto msg = "^3" + std::vformat(fmt, args);
|
||||||
|
|
||||||
Logger::MessagePrint(channel, msg);
|
MessagePrint(channel, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::Frame()
|
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);
|
Game::Com_PrintMessage(Game::CON_CHANNEL_DONT_FILTER, i->data(), 0);
|
||||||
|
|
||||||
if (!Logger::IsConsoleReady())
|
if (!IsConsoleReady())
|
||||||
{
|
{
|
||||||
OutputDebugStringA(i->data());
|
OutputDebugStringA(i->data());
|
||||||
}
|
}
|
||||||
|
|
||||||
i = Logger::MessageQueue.erase(i);
|
i = MessageQueue.erase(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::PipeOutput(const std::function<void(const std::string&)>& callback)
|
void Logger::PipeOutput(const std::function<void(const std::string&)>& callback)
|
||||||
{
|
{
|
||||||
Logger::PipeCallback = callback;
|
PipeCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::PrintMessagePipe(const char* data)
|
void Logger::PrintMessagePipe(const char* data)
|
||||||
{
|
{
|
||||||
if (Logger::PipeCallback)
|
if (PipeCallback)
|
||||||
{
|
{
|
||||||
Logger::PipeCallback(data);
|
PipeCallback(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ namespace Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& addr : Logger::LoggingAddresses[gLog & 1])
|
for (const auto& addr : LoggingAddresses[gLog & 1])
|
||||||
{
|
{
|
||||||
Network::SendCommand(addr, "print", data);
|
Network::SendCommand(addr, "print", data);
|
||||||
}
|
}
|
||||||
@ -169,20 +169,20 @@ namespace Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allow the network log to run even if logFile was not opened
|
// 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()
|
__declspec(naked) void Logger::PrintMessage_Stub()
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov eax, Logger::PipeCallback
|
mov eax, PipeCallback
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jz returnPrint
|
jz returnPrint
|
||||||
|
|
||||||
pushad
|
pushad
|
||||||
push [esp + 28h]
|
push [esp + 28h]
|
||||||
call Logger::PrintMessagePipe
|
call PrintMessagePipe
|
||||||
add esp, 4h
|
add esp, 4h
|
||||||
popad
|
popad
|
||||||
retn
|
retn
|
||||||
@ -191,7 +191,7 @@ namespace Components
|
|||||||
pushad
|
pushad
|
||||||
push 0
|
push 0
|
||||||
push [esp + 2Ch]
|
push [esp + 2Ch]
|
||||||
call Logger::NetworkLog
|
call NetworkLog
|
||||||
add esp, 8h
|
add esp, 8h
|
||||||
popad
|
popad
|
||||||
|
|
||||||
@ -205,8 +205,8 @@ namespace Components
|
|||||||
|
|
||||||
void Logger::EnqueueMessage(const std::string& message)
|
void Logger::EnqueueMessage(const std::string& message)
|
||||||
{
|
{
|
||||||
std::unique_lock _(Logger::MessageMutex);
|
std::unique_lock _(MessageMutex);
|
||||||
Logger::MessageQueue.push_back(message);
|
MessageQueue.push_back(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::RedirectOSPath(const char* file, char* folder)
|
void Logger::RedirectOSPath(const char* file, char* folder)
|
||||||
@ -232,7 +232,7 @@ namespace Components
|
|||||||
push [esp + 28h]
|
push [esp + 28h]
|
||||||
push [esp + 30h]
|
push [esp + 30h]
|
||||||
|
|
||||||
call Logger::RedirectOSPath
|
call RedirectOSPath
|
||||||
|
|
||||||
add esp, 8h
|
add esp, 8h
|
||||||
|
|
||||||
@ -256,9 +256,9 @@ namespace Components
|
|||||||
|
|
||||||
Network::Address addr(params->get(1));
|
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;
|
if (params->size() < 2) return;
|
||||||
|
|
||||||
const auto num = atoi(params->get(1));
|
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;
|
auto addr = Logger::LoggingAddresses[0].begin() + num;
|
||||||
Logger::Print("Address {} removed\n", addr->getString());
|
Print("Address {} removed\n", addr->getString());
|
||||||
Logger::LoggingAddresses[0].erase(addr);
|
LoggingAddresses[0].erase(addr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Network::Address addr(params->get(1));
|
Network::Address addr(params->get(1));
|
||||||
|
|
||||||
const auto i = std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr);
|
const auto i = std::find(LoggingAddresses[0].begin(), LoggingAddresses[0].end(), addr);
|
||||||
if (i != Logger::LoggingAddresses[0].end())
|
if (i != LoggingAddresses[0].end())
|
||||||
{
|
{
|
||||||
Logger::LoggingAddresses[0].erase(i);
|
LoggingAddresses[0].erase(i);
|
||||||
Logger::Print("Address {} removed\n", addr.getString());
|
Print("Address {} removed\n", addr.getString());
|
||||||
}
|
}
|
||||||
else
|
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");
|
Print("# ID: Address\n");
|
||||||
Logger::Print("-------------\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));
|
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;
|
if (params->size() < 2) return;
|
||||||
|
|
||||||
const auto num = std::atoi(params->get(1));
|
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;
|
const auto addr = LoggingAddresses[1].begin() + num;
|
||||||
Logger::Print("Address {} removed\n", addr->getString());
|
Print("Address {} removed\n", addr->getString());
|
||||||
Logger::LoggingAddresses[1].erase(addr);
|
LoggingAddresses[1].erase(addr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const Network::Address addr(params->get(1));
|
const Network::Address addr(params->get(1));
|
||||||
|
|
||||||
const auto i = std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr);
|
const auto i = std::ranges::find(LoggingAddresses[1].begin(), LoggingAddresses[1].end(), addr);
|
||||||
if (i != Logger::LoggingAddresses[1].end())
|
if (i != LoggingAddresses[1].end())
|
||||||
{
|
{
|
||||||
Logger::LoggingAddresses[1].erase(i);
|
LoggingAddresses[1].erase(i);
|
||||||
Logger::Print("Address {} removed\n", addr.getString());
|
Print("Address {} removed\n", addr.getString());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Address {} not found!\n", addr.getString());
|
Print("Address {} not found!\n", addr.getString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Command::AddSV("g_log_list", [](Command::Params*)
|
Command::AddSV("g_log_list", [](Command::Params*)
|
||||||
{
|
{
|
||||||
Logger::Print("# ID: Address\n");
|
Print("# ID: Address\n");
|
||||||
Logger::Print("-------------\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()
|
Logger::Logger()
|
||||||
{
|
{
|
||||||
Dvar::Register<bool>("iw4x_onelog", false, Game::DVAR_LATCH | Game::DVAR_ARCHIVE, "Only write the game log to the 'userraw' OS folder");
|
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, G_LogPrintf_Hk, HOOK_JUMP).install()->quick();
|
||||||
|
Utils::Hook(Game::Com_PrintMessage, PrintMessage_Stub, HOOK_JUMP).install()->quick();
|
||||||
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();
|
|
||||||
|
|
||||||
if (Loader::IsPerformingUnitTests())
|
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::~Logger()
|
||||||
{
|
{
|
||||||
Logger::LoggingAddresses[0].clear();
|
LoggingAddresses[0].clear();
|
||||||
Logger::LoggingAddresses[1].clear();
|
LoggingAddresses[1].clear();
|
||||||
|
|
||||||
std::unique_lock lock(Logger::MessageMutex);
|
std::unique_lock lock(MessageMutex);
|
||||||
Logger::MessageQueue.clear();
|
MessageQueue.clear();
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
// Flush the console log
|
// Flush the console log
|
||||||
|
@ -59,7 +59,7 @@ namespace Components
|
|||||||
for (auto& node : nodeList)
|
for (auto& node : nodeList)
|
||||||
{
|
{
|
||||||
Utils::String::Replace(node, "\r", "");
|
Utils::String::Replace(node, "\r", "");
|
||||||
node = Utils::String::Trim(node);
|
Utils::String::Trim(node);
|
||||||
Node::Add(node);
|
Node::Add(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string readablePlayerName(buffer);
|
std::string readablePlayerName(buffer);
|
||||||
readablePlayerName = Utils::String::Trim(readablePlayerName);
|
Utils::String::Trim(readablePlayerName);
|
||||||
|
|
||||||
if (readablePlayerName.size() < 3)
|
if (readablePlayerName.size() < 3)
|
||||||
{
|
{
|
||||||
|
@ -127,8 +127,8 @@ namespace Components
|
|||||||
Network::OnClientPacket("rcon", [](const Network::Address& address, [[maybe_unused]] const std::string& data)
|
Network::OnClientPacket("rcon", [](const Network::Address& address, [[maybe_unused]] const std::string& data)
|
||||||
{
|
{
|
||||||
std::string data_ = data;
|
std::string data_ = data;
|
||||||
|
|
||||||
Utils::String::Trim(data_);
|
Utils::String::Trim(data_);
|
||||||
|
|
||||||
const auto pos = data.find_first_of(' ');
|
const auto pos = data.find_first_of(' ');
|
||||||
if (pos == std::string::npos)
|
if (pos == std::string::npos)
|
||||||
{
|
{
|
||||||
|
@ -28,23 +28,24 @@
|
|||||||
#pragma warning(disable: 4244)
|
#pragma warning(disable: 4244)
|
||||||
#include <DbgHelp.h>
|
#include <DbgHelp.h>
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <cctype>
|
|
||||||
#include <regex>
|
|
||||||
#include <thread>
|
|
||||||
#include <future>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <queue>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <cctype>
|
||||||
|
#include <chrono>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <optional>
|
|
||||||
#include <random>
|
|
||||||
#include <chrono>
|
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <fstream>
|
||||||
|
#include <future>
|
||||||
|
#include <limits>
|
||||||
|
#include <optional>
|
||||||
|
#include <queue>
|
||||||
|
#include <random>
|
||||||
|
#include <ranges>
|
||||||
|
#include <regex>
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
|
#include <sstream>
|
||||||
|
#include <thread>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
@ -145,9 +145,9 @@ namespace Utils::String
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trim from both ends
|
// 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)
|
std::string Convert(const std::wstring& wstr)
|
||||||
|
@ -11,7 +11,7 @@ namespace Utils::String
|
|||||||
VAProvider() : currentBuffer(0) {}
|
VAProvider() : currentBuffer(0) {}
|
||||||
~VAProvider() = default;
|
~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);
|
++this->currentBuffer %= ARRAYSIZE(this->stringPool);
|
||||||
auto entry = &this->stringPool[this->currentBuffer];
|
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);
|
[[nodiscard]] std::string ToLower(const std::string& text);
|
||||||
std::string ToUpper(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);
|
void Replace(std::string& str, const std::string& from, const std::string& to);
|
||||||
|
|
||||||
bool StartsWith(const std::string& haystack, const std::string& needle);
|
[[nodiscard]] bool StartsWith(const std::string& haystack, const std::string& needle);
|
||||||
bool EndsWith(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& LTrim(std::string& str);
|
||||||
std::string& RTrim(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);
|
[[nodiscard]] std::string Convert(const std::wstring& wstr);
|
||||||
std::wstring Convert(const std::string& str);
|
[[nodiscard]] std::wstring Convert(const std::string& str);
|
||||||
|
|
||||||
std::string FormatTimeSpan(int milliseconds);
|
[[nodiscard]] std::string FormatTimeSpan(int milliseconds);
|
||||||
std::string FormatBandwidth(std::size_t bytes, 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);
|
[[nodiscard]] std::string EncodeBase64(const char* input, unsigned long inputSize);
|
||||||
std::string EncodeBase64(const std::string& input);
|
[[nodiscard]] std::string EncodeBase64(const std::string& input);
|
||||||
|
|
||||||
std::string EncodeBase128(const std::string& input);
|
[[nodiscard]] std::string EncodeBase128(const std::string& input);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user