diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index f4e31ad4..14e4e909 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -175,20 +175,20 @@ namespace Components } } - BOOL QuickPatch::IsDynClassnameStub(char* a1) + BOOL QuickPatch::IsDynClassnameStub(const char* classname) { - auto version = Zones::GetEntitiesZoneVersion(); + const auto version = Zones::Version(); if (version >= VERSION_LATEST_CODO) { for (auto i = 0; i < Game::spawnVars->numSpawnVars; i++) { char** kvPair = Game::spawnVars->spawnVars[i]; - auto key = kvPair[0]; - auto val = kvPair[1]; + const auto* key = kvPair[0]; + const auto* val = kvPair[1]; - bool isSpecOps = strncmp(key, "script_specialops", 17) == 0; - bool isSpecOpsOnly = val[0] == '1' && val[1] == '\0'; + auto isSpecOps = std::strncmp(key, "script_specialops", 17) == 0; + auto isSpecOpsOnly = (val[0] == '1') && (val[1] == '\0'); if (isSpecOps && isSpecOpsOnly) { @@ -199,8 +199,7 @@ namespace Components } } - // Passthrough to the game's own IsDynClassname - return Utils::Hook::Call(0x444810)(a1); + return Utils::Hook::Call(0x444810)(classname); // IsDynClassname } void QuickPatch::CL_KeyEvent_OnEscape() diff --git a/src/Components/Modules/QuickPatch.hpp b/src/Components/Modules/QuickPatch.hpp index b5cc5d9f..52fa8c46 100644 --- a/src/Components/Modules/QuickPatch.hpp +++ b/src/Components/Modules/QuickPatch.hpp @@ -23,7 +23,7 @@ namespace Components static void ClientEventsFireWeaponStub(); static void ClientEventsFireWeaponMeleeStub(); - static BOOL IsDynClassnameStub(char* a1); + static BOOL IsDynClassnameStub(const char* classname); static void CL_KeyEvent_OnEscape(); static void CL_KeyEvent_ConsoleEscape_Stub(); diff --git a/src/Components/Modules/VisionFile.cpp b/src/Components/Modules/VisionFile.cpp index 463a9d01..1a1eb6da 100644 --- a/src/Components/Modules/VisionFile.cpp +++ b/src/Components/Modules/VisionFile.cpp @@ -2,76 +2,104 @@ namespace Components { - const char* VisionFile::DvarExceptions[] = + std::vector VisionFile::DvarExceptions = { "r_pretess", }; - void VisionFile::ApplyExemptDvar(const std::string& dvarName, const char* buffer, const std::string& fileName) + std::unordered_map VisionFile::VisionReplacements { - for (std::size_t i = 0; i < ARRAYSIZE(DvarExceptions); ++i) - { - if (dvarName == DvarExceptions[i]) - { - const auto* dvar = Game::Dvar_FindVar(dvarName.data()); - const auto* parsedValue = Game::Com_ParseOnLine(&buffer); + {"511", "r_glow"}, + {"516", "r_glowRadius0"}, + {"512", "r_glowBloomCutoff"}, + {"513", "r_glowBloomDesaturation"}, + {"514", "r_glowBloomIntensity0"}, + {"520", "r_filmEnable"}, + {"522", "r_filmContrast"}, + {"521", "r_filmBrightness"}, + {"523", "r_filmDesaturation"}, + {"524", "r_filmDesaturationDark"}, + {"525", "r_filmInvert"}, + {"526", "r_filmLightTint"}, + {"527", "r_filmMediumTint"}, + {"528", "r_filmDarkTint"}, + {"529", "r_primaryLightUseTweaks"}, + {"530", "r_primaryLightTweakDiffuseStrength"}, + {"531", "r_primaryLightTweakSpecularStrength"}, + }; - assert(dvar != nullptr); + bool VisionFile::ApplyExemptDvar(const char* dvarName, const char** buffer, const char* filename) + { + for (auto& exceptions : DvarExceptions) + { + if (!_stricmp(dvarName, exceptions.data())) + { + const auto* dvar = Game::Dvar_FindVar(dvarName); + const auto* parsedValue = Game::Com_ParseOnLine(buffer); + + assert(dvar); + assert(parsedValue); Game::Dvar_SetFromStringFromSource(dvar, parsedValue, Game::DvarSetSource::DVAR_SOURCE_INTERNAL); - Logger::Print("Overriding '{}' from '{}'\n", dvarName, fileName); + Logger::Print("Overriding '{}' from '{}'\n", dvar->name, filename); // Successfully found and tried to apply the string value to the dvar - return; + return true; } } - Game::Com_PrintWarning(Game::conChannel_t::CON_CHANNEL_SYSTEM, - "WARNING: unknown dvar \'%s\' in file \'%s\'\n", dvarName.data(), fileName.data()); + return false; } - // Gets the dvar name and value and attemps to apply it to the vision settings - void VisionFile::ApplyValueToSettings(const std::string& key, const char* buffer, - const std::string& fileName, Game::visionSetVars_t* settings) + bool VisionFile::LoadVisionSettingsFromBuffer(const char* buffer, const char* filename, Game::visionSetVars_t* settings) { - for (std::size_t i = 0; i < 21; ++i) + assert(settings); + + bool wasRead[21]{}; + Game::Com_BeginParseSession(filename); + + while (true) { - // Must be case insensitive comparison - if (key == Utils::String::ToLower(Game::visionDefFields[i].name)) + auto* token = Game::Com_Parse(&buffer); + + if (!*token) { - auto* const dvarValue = Game::Com_ParseOnLine(&buffer); - - if (!Game::ApplyTokenToField(i, dvarValue, settings)) - { - Game::Com_PrintWarning(Game::conChannel_t::CON_CHANNEL_SYSTEM, - "WARNING: malformed dvar \'%s\' in file \'%s\'\n", dvarValue, fileName.data()); - - // Failed to apply the value. Check that sscanf can actually parse the value - return; - } - - // Successfully found and applied the value to the settings - return; + break; } - } - // Dvar not found in visionDefFields, let's try to see if it's a 'patched' dvar - ApplyExemptDvar(key, buffer, fileName); - } + auto found = false; + auto fieldNum = 0; - bool VisionFile::LoadVisionSettingsFromBuffer(const char* buffer, const char* fileName, Game::visionSetVars_t* settings) - { - assert(settings != nullptr); - assert(fileName != nullptr); + const auto it = VisionReplacements.find(token); + for (fieldNum = 0; fieldNum < 21; ++fieldNum) + { + if (!wasRead[fieldNum] && !_stricmp((it == VisionReplacements.end()) ? token : it->second.data(), Game::visionDefFields[fieldNum].name)) + { + found = true; + break; + } + } - Game::Com_BeginParseSession(fileName); + if (!found) + { + if (!ApplyExemptDvar(token, &buffer, filename)) + { + Logger::Warning(Game::CON_CHANNEL_SYSTEM, "WARNING: unknown dvar '{}' in file '{}'\n", token, filename); + Game::Com_SkipRestOfLine(&buffer); + } + continue; + } - // Will split the buffer into tokens using the following delimiters: space, newlines (more?) - for (auto i = Game::Com_Parse(&buffer); *i != '\0'; i = Game::Com_Parse(&buffer)) - { - // Converting 'key' to lower case as it will be needed later - ApplyValueToSettings(Utils::String::ToLower(i), buffer, fileName, settings); - Game::Com_SkipRestOfLine(&buffer); + token = Game::Com_ParseOnLine(&buffer); + if (ApplyTokenToField(fieldNum, token, settings)) + { + wasRead[fieldNum] = true; + } + else + { + Logger::Warning(Game::CON_CHANNEL_SYSTEM, "WARNING: malformed dvar '{}' in file '{}'\n", token, filename); + Game::Com_SkipRestOfLine(&buffer); + } } Game::Com_EndParseSession(); @@ -80,15 +108,21 @@ namespace Components __declspec(naked) bool VisionFile::LoadVisionSettingsFromBuffer_Stub() { - // No need for push/pop ad guards, I have checked :) __asm { - push [esp + 0x8] // settings + push eax + pushad + + push [esp + 0x24 + 0x8] // settings push ebx // filename - push [esp + 0xC] // buffer - call VisionFile::LoadVisionSettingsFromBuffer + push [esp + 0x24 + 0xC] // buffer + call LoadVisionSettingsFromBuffer add esp, 0xC + mov [esp + 0x20], eax + popad + pop eax + ret } } diff --git a/src/Components/Modules/VisionFile.hpp b/src/Components/Modules/VisionFile.hpp index d9d379a9..8c43572e 100644 --- a/src/Components/Modules/VisionFile.hpp +++ b/src/Components/Modules/VisionFile.hpp @@ -8,12 +8,12 @@ namespace Components VisionFile(); private: - static const char* DvarExceptions[]; + static std::vector DvarExceptions; + static std::unordered_map VisionReplacements; - static void ApplyExemptDvar(const std::string& dvarName, const char* buffer, const std::string& fileName); - static void ApplyValueToSettings(const std::string& dvarName, const char* buffer, const std::string& fileName, Game::visionSetVars_t* settings); + static bool ApplyExemptDvar(const char* dvarName, const char** buffer, const char* filename); - static bool LoadVisionSettingsFromBuffer(const char* buffer, const char* fileName, Game::visionSetVars_t* settings); + static bool LoadVisionSettingsFromBuffer(const char* buffer, const char* filename, Game::visionSetVars_t* settings); static bool LoadVisionSettingsFromBuffer_Stub(); }; } diff --git a/src/Components/Modules/Zones.cpp b/src/Components/Modules/Zones.cpp index 1add1496..edcada03 100644 --- a/src/Components/Modules/Zones.cpp +++ b/src/Components/Modules/Zones.cpp @@ -4,12 +4,12 @@ namespace Components { int Zones::ZoneVersion; - int Zones::EntitiesVersion; int Zones::FxEffectIndex; char* Zones::FxEffectStrings[64]; - static std::unordered_map shellshock_replace_list = { + static std::unordered_map shellshock_replace_list = + { { "66","bg_shock_screenType" }, { "67","bg_shock_screenBlurBlendTime"}, { "68","bg_shock_screenBlurBlendFadeTime"}, @@ -41,26 +41,6 @@ namespace Components { "92","bg_shock_movement"} }; - static std::unordered_map vision_replace_list = { - { "511","r_glow" }, - { "516","r_glowRadius0" }, - { "512","r_glowBloomCutoff" }, - { "513","r_glowBloomDesaturation" }, - { "514","r_glowBloomIntensity0" }, - { "520","r_filmEnable" }, - { "522","r_filmContrast" }, - { "521","r_filmBrightness" }, - { "523","r_filmDesaturation" }, - { "524","r_filmDesaturationDark" }, - { "525","r_filmInvert" }, - { "526","r_filmLightTint" }, - { "527","r_filmMediumTint" }, - { "528","r_filmDarkTint" }, - { "529","r_primaryLightUseTweaks" }, - { "530","r_primaryLightTweakDiffuseStrength" }, - { "531","r_primaryLightTweakSpecularStrength" }, - }; - Game::XAssetType currentAssetType = Game::XAssetType::ASSET_TYPE_INVALID; Game::XAssetType previousAssetType = Game::XAssetType::ASSET_TYPE_INVALID; @@ -2559,8 +2539,6 @@ namespace Components int Zones::LoadMapEnts(bool atStreamStart, Game::MapEnts* buffer, int size) { - EntitiesVersion = Zones::Version(); - if (Zones::Version() >= 446) { size /= 44; @@ -3487,18 +3465,6 @@ namespace Components Game::DB_PopStreamPos(); } - - char* Zones::ParseVision_Stub(const char** data_p) - { - auto token = Game::Com_Parse(data_p); - - if (vision_replace_list.find(token) != vision_replace_list.end()) - { - return vision_replace_list[token].data(); - } - - return token; - } char* Zones::ParseShellShock_Stub(const char** data_p) { @@ -3507,10 +3473,10 @@ namespace Components { return shellshock_replace_list[token].data(); } + return token; } - Zones::Zones() { Zones::ZoneVersion = 0; @@ -3682,10 +3648,6 @@ namespace Components Utils::Hook(0x4597DD, Zones::LoadStatement, HOOK_CALL).install()->quick(); Utils::Hook(0x471A39, Zones::LoadWindowImage, HOOK_JUMP).install()->quick(); - // Fix newer vision file - Utils::Hook(0x59A849, ParseVision_Stub, HOOK_CALL).install()->quick(); - Utils::Hook(0x59A8AD, ParseVision_Stub, HOOK_CALL).install()->quick(); - #ifdef DEBUG // Easy dirty disk debugging Utils::Hook::Set(0x4CF7F0, 0xC3CC); diff --git a/src/Components/Modules/Zones.hpp b/src/Components/Modules/Zones.hpp index 615bc450..5c4899b0 100644 --- a/src/Components/Modules/Zones.hpp +++ b/src/Components/Modules/Zones.hpp @@ -21,14 +21,11 @@ namespace Components static void SetVersion(int version); - static int Version() { return Zones::ZoneVersion; }; - - static int GetEntitiesZoneVersion() { return Zones::EntitiesVersion; }; + static int Version() { return Zones::ZoneVersion; } private: static int ZoneVersion; - static int EntitiesVersion; static int FxEffectIndex; static char* FxEffectStrings[64]; @@ -105,6 +102,5 @@ namespace Components static void LoadTracerDefFxEffect(); static void FixImageCategory(Game::GfxImage* image); static char* ParseShellShock_Stub(const char** data_p); - static char* ParseVision_Stub(const char** data_p); }; } diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 5b29df09..c57e84f6 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -995,7 +995,6 @@ namespace Game MaterialShaderArgument *args; }; - /* 9045 */ struct visionSetVars_t { bool glowEnable; diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 223334a7..55cd12a0 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -43,6 +43,14 @@ namespace Utils return text; } + bool Compare(const std::string& lhs, const std::string& rhs) + { + return std::ranges::equal(lhs, rhs, [](const unsigned char a, const unsigned char b) + { + return std::tolower(a) == std::tolower(b); + }); + } + std::string DumpHex(const std::string& data, const std::string& separator) { std::string result; @@ -106,18 +114,18 @@ namespace Utils return std::equal(needle.rbegin(), needle.rend(), haystack.rbegin()); } - int IsSpace(int c) + bool IsNumber(const std::string& str) { - if (c < -1) return 0; - return _isspace_l(c, nullptr); + return !str.empty() && std::find_if(str.begin(), + str.end(), [](unsigned char input) { return !std::isdigit(input); }) == str.end(); } // Trim from start std::string& LTrim(std::string& str) { - str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](int val) + str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](const unsigned char input) { - return !IsSpace(val); + return !std::isspace(input); })); return str; @@ -126,9 +134,9 @@ namespace Utils // Trim from end std::string& RTrim(std::string& str) { - str.erase(std::find_if(str.rbegin(), str.rend(), [](int val) + str.erase(std::find_if(str.rbegin(), str.rend(), [](const unsigned char input) { - return !IsSpace(val); + return !std::isspace(input); }).base(), str.end()); return str; diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index 90422c29..b6b376ba 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -4,7 +4,7 @@ namespace Utils { namespace String { - template + template class VAProvider { public: @@ -25,7 +25,7 @@ namespace Utils while (true) { - const auto res = _vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap); + const auto res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap); if (res > 0) break; // Success if (res == 0) return ""; // Error @@ -47,15 +47,15 @@ namespace Utils ~Entry() { - if (this->buffer) Utils::Memory::GetAllocator()->free(this->buffer); + if (this->buffer) Memory::GetAllocator()->free(this->buffer); this->size = 0; this->buffer = nullptr; } void allocate() { - if (this->buffer) Utils::Memory::GetAllocator()->free(this->buffer); - this->buffer = Utils::Memory::GetAllocator()->allocateArray(this->size + 1); + if (this->buffer) Memory::GetAllocator()->free(this->buffer); + this->buffer = Memory::GetAllocator()->allocateArray(this->size + 1); } void doubleSize() @@ -74,13 +74,14 @@ namespace Utils const char *VA(const char *fmt, ...); - int IsSpace(int c); std::string ToLower(std::string text); std::string ToUpper(std::string text); + bool Compare(const std::string& lhs, const std::string& rhs); std::vector Split(const std::string& str, char delim); void Replace(std::string& string, const std::string& find, const std::string& replace); bool StartsWith(const std::string& haystack, const std::string& needle); bool EndsWith(const std::string& haystack, const std::string& needle); + bool IsNumber(const std::string& str); std::string& LTrim(std::string& str); std::string& RTrim(std::string& str); @@ -94,7 +95,7 @@ namespace Utils std::string DumpHex(const std::string& data, const std::string& separator = " "); - std::string XOR(const std::string str, char value); + std::string XOR(std::string str, char value); std::string EncodeBase64(const char* input, const unsigned long inputSize); std::string EncodeBase64(const std::string& input);