[VisionFile] Move zone patch here

This commit is contained in:
Diavolo 2022-07-23 22:16:26 +02:00
parent b52142bbb1
commit 034abfe235
No known key found for this signature in database
GPG Key ID: FA77F074E98D98A5
9 changed files with 124 additions and 125 deletions

View File

@ -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<BOOL(char*)>(0x444810)(a1);
return Utils::Hook::Call<BOOL(const char*)>(0x444810)(classname); // IsDynClassname
}
void QuickPatch::CL_KeyEvent_OnEscape()

View File

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

View File

@ -2,76 +2,104 @@
namespace Components
{
const char* VisionFile::DvarExceptions[] =
std::vector<std::string> VisionFile::DvarExceptions =
{
"r_pretess",
};
void VisionFile::ApplyExemptDvar(const std::string& dvarName, const char* buffer, const std::string& fileName)
std::unordered_map<std::string, std::string> 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
}
}

View File

@ -8,12 +8,12 @@ namespace Components
VisionFile();
private:
static const char* DvarExceptions[];
static std::vector<std::string> DvarExceptions;
static std::unordered_map<std::string, std::string> 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();
};
}

View File

@ -4,12 +4,12 @@
namespace Components
{
int Zones::ZoneVersion;
int Zones::EntitiesVersion;
int Zones::FxEffectIndex;
char* Zones::FxEffectStrings[64];
static std::unordered_map<std::string, std::string> shellshock_replace_list = {
static std::unordered_map<std::string, std::string> 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<std::string, std::string> 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<WORD>(0x4CF7F0, 0xC3CC);

View File

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

View File

@ -995,7 +995,6 @@ namespace Game
MaterialShaderArgument *args;
};
/* 9045 */
struct visionSetVars_t
{
bool glowEnable;

View File

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

View File

@ -4,7 +4,7 @@ namespace Utils
{
namespace String
{
template <size_t Buffers, size_t MinBufferSize>
template <std::size_t Buffers, std::size_t MinBufferSize>
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<char>(this->size + 1);
if (this->buffer) Memory::GetAllocator()->free(this->buffer);
this->buffer = Memory::GetAllocator()->allocateArray<char>(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<std::string> 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);