Custom vision file parser (#249)
This commit is contained in:
parent
060abd6251
commit
769ff3fd5e
@ -31,8 +31,8 @@ namespace Components
|
||||
|
||||
Loader::Register(new Flags());
|
||||
Loader::Register(new Singleton());
|
||||
Loader::Register(new Exception()); // install our exception handler as early as posssible to get better debug dumps from startup crashes
|
||||
|
||||
// Install our exception handler as early as posssible to get better debug dumps from startup crashes
|
||||
Loader::Register(new Exception());
|
||||
Loader::Register(new Auth());
|
||||
Loader::Register(new Bans());
|
||||
Loader::Register(new Bots());
|
||||
@ -104,6 +104,7 @@ namespace Components
|
||||
Loader::Register(new Movement());
|
||||
Loader::Register(new Elevators());
|
||||
Loader::Register(new ClientCommand());
|
||||
Loader::Register(new VisionFile());
|
||||
Loader::Register(new ScriptExtension());
|
||||
Loader::Register(new Branding());
|
||||
Loader::Register(new Debug());
|
||||
|
@ -134,6 +134,7 @@ namespace Components
|
||||
#include "Modules/Movement.hpp"
|
||||
#include "Modules/Elevators.hpp"
|
||||
#include "Modules/ClientCommand.hpp"
|
||||
#include "Modules/VisionFile.hpp"
|
||||
#include "Modules/Gamepad.hpp"
|
||||
#include "Modules/ScriptExtension.hpp"
|
||||
#include "Modules/Branding.hpp"
|
||||
|
111
src/Components/Modules/VisionFile.cpp
Normal file
111
src/Components/Modules/VisionFile.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#include <STDInclude.hpp>
|
||||
|
||||
namespace Components
|
||||
{
|
||||
const char* VisionFile::DvarExceptions[] =
|
||||
{
|
||||
"r_pretess",
|
||||
};
|
||||
|
||||
void VisionFile::ApplyExemptDvar(const std::string& dvarName, const char* buffer, const std::string& fileName)
|
||||
{
|
||||
for (std::size_t i = 0; i < std::extent_v<decltype(DvarExceptions)>; ++i)
|
||||
{
|
||||
if (dvarName == DvarExceptions[i])
|
||||
{
|
||||
const auto* dvar = Game::Dvar_FindVar(dvarName.data());
|
||||
|
||||
assert(dvar != nullptr);
|
||||
|
||||
const auto* currentVal = Game::Dvar_DisplayableValue(dvar);
|
||||
const auto* parsedValue = Game::Com_ParseOnLine(&buffer);
|
||||
|
||||
if (std::strcmp(parsedValue, currentVal) == 0)
|
||||
{
|
||||
// The dvar is already set to the value we want
|
||||
return;
|
||||
}
|
||||
|
||||
Game::Dvar_SetFromStringFromSource(dvar, parsedValue, Game::DvarSetSource::DVAR_SOURCE_INTERNAL);
|
||||
Logger::Print("Overriding '{}' from '{}'\n", dvarName, fileName);
|
||||
|
||||
// Successfully found and tried to apply the string value to the dvar
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Game::Com_PrintWarning(Game::conChannel_t::CON_CHANNEL_SYSTEM,
|
||||
"WARNING: unknown dvar \'%s\' in file \'%s\'\n", dvarName.data(), fileName.data());
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
for (std::size_t i = 0; i < 21; ++i)
|
||||
{
|
||||
// Must be case insensitive comparison
|
||||
if (key == Utils::String::ToLower(Game::visionDefFields[i].name))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Dvar not found in visionDefFields, let's try to see if it's a 'patched' dvar
|
||||
ApplyExemptDvar(key, buffer, fileName);
|
||||
}
|
||||
|
||||
bool VisionFile::LoadVisionSettingsFromBuffer(const char* buffer, const char* fileName, Game::visionSetVars_t* settings)
|
||||
{
|
||||
assert(settings != nullptr);
|
||||
assert(fileName != nullptr);
|
||||
|
||||
Game::Com_BeginParseSession(fileName);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
Game::Com_EndParseSession();
|
||||
return true;
|
||||
}
|
||||
|
||||
__declspec(naked) bool VisionFile::LoadVisionSettingsFromBuffer_Stub()
|
||||
{
|
||||
// No need for push/pop ad guards, I have checked :)
|
||||
__asm
|
||||
{
|
||||
push [esp + 0x8] // settings
|
||||
push ebx // filename
|
||||
push [esp + 0xC] // buffer
|
||||
call VisionFile::LoadVisionSettingsFromBuffer
|
||||
add esp, 0xC
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
VisionFile::VisionFile()
|
||||
{
|
||||
AssertSize(Game::visField_t, 12);
|
||||
|
||||
// Place hook in LoadVisionFile function
|
||||
Utils::Hook(0x59A98A, LoadVisionSettingsFromBuffer_Stub, HOOK_CALL).install()->quick();
|
||||
}
|
||||
}
|
19
src/Components/Modules/VisionFile.hpp
Normal file
19
src/Components/Modules/VisionFile.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
namespace Components
|
||||
{
|
||||
class VisionFile : public Component
|
||||
{
|
||||
public:
|
||||
VisionFile();
|
||||
|
||||
private:
|
||||
static const char* DvarExceptions[];
|
||||
|
||||
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 LoadVisionSettingsFromBuffer(const char* buffer, const char* fileName, Game::visionSetVars_t* settings);
|
||||
static bool LoadVisionSettingsFromBuffer_Stub();
|
||||
};
|
||||
}
|
@ -95,7 +95,7 @@ namespace Components
|
||||
|
||||
void ZoneBuilder::Zone::Zone::build()
|
||||
{
|
||||
if(!this->dataMap.isValid())
|
||||
if (!this->dataMap.isValid())
|
||||
{
|
||||
Logger::Print("Unable to load CSV for '{}'!\n", this->zoneName);
|
||||
return;
|
||||
@ -111,7 +111,7 @@ namespace Components
|
||||
Logger::Print("Saving...\n");
|
||||
this->saveData();
|
||||
|
||||
if(this->buffer.hasBlock())
|
||||
if (this->buffer.hasBlock())
|
||||
{
|
||||
Logger::Error(Game::ERR_FATAL, "Non-popped blocks left!\n");
|
||||
}
|
||||
@ -267,7 +267,7 @@ namespace Components
|
||||
const char* assetName = Game::DB_GetXAssetName(asset);
|
||||
if (assetName[0] == ',') ++assetName;
|
||||
|
||||
if(this->getAssetName(type, assetName) == name)
|
||||
if (this->getAssetName(type, assetName) == name)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
@ -336,7 +336,7 @@ namespace Components
|
||||
if (assetIndex == -1) // nested asset
|
||||
{
|
||||
// already written. find alias and store in ptr
|
||||
if(this->hasAlias(asset))
|
||||
if (this->hasAlias(asset))
|
||||
{
|
||||
header.data = reinterpret_cast<void*>(this->getAlias(asset));
|
||||
}
|
||||
@ -1054,7 +1054,7 @@ namespace Components
|
||||
AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader, const std::string&, bool* restrict)
|
||||
{
|
||||
//if (*static_cast<int*>(Game::DB_XAssetPool[type].data) == 0)
|
||||
if(Game::g_poolSize[type] == 0)
|
||||
if (Game::g_poolSize[type] == 0)
|
||||
{
|
||||
*restrict = true;
|
||||
}
|
||||
@ -1070,9 +1070,9 @@ namespace Components
|
||||
{
|
||||
int result = Utils::Hook::Call<int(Game::dvar_t*, Game::DvarValue)>(0x642FC0)(dvar, value);
|
||||
|
||||
if(result)
|
||||
if (result)
|
||||
{
|
||||
if(std::string(value.string) != dvar->current.string)
|
||||
if (std::string(value.string) != dvar->current.string)
|
||||
{
|
||||
dvar->current.string = value.string;
|
||||
Game::FS_Restart(0, 0);
|
||||
@ -1517,7 +1517,7 @@ namespace Components
|
||||
{
|
||||
*i = Utils::String::VA("images/%s", i->data());
|
||||
|
||||
if(FileSystem::File(*i).exists())
|
||||
if (FileSystem::File(*i).exists())
|
||||
{
|
||||
i = images.erase(i);
|
||||
continue;
|
||||
@ -1552,7 +1552,7 @@ namespace Components
|
||||
unsigned int integer = 0x80000000;
|
||||
Utils::RotLeft(integer, 1);
|
||||
|
||||
if(integer != 1)
|
||||
if (integer != 1)
|
||||
{
|
||||
printf("Error\n");
|
||||
printf("Bit shifting failed: %X\n", integer);
|
||||
|
@ -78,6 +78,8 @@ namespace Game
|
||||
Com_PrintMessage_t Com_PrintMessage = Com_PrintMessage_t(0x4AA830);
|
||||
Com_EndParseSession_t Com_EndParseSession = Com_EndParseSession_t(0x4B80B0);
|
||||
Com_BeginParseSession_t Com_BeginParseSession = Com_BeginParseSession_t(0x4AAB80);
|
||||
Com_ParseOnLine_t Com_ParseOnLine = Com_ParseOnLine_t(0x4C0350);
|
||||
Com_SkipRestOfLine_t Com_SkipRestOfLine = Com_SkipRestOfLine_t(0x4B8300);
|
||||
Com_SetSpaceDelimited_t Com_SetSpaceDelimited = Com_SetSpaceDelimited_t(0x4FC710);
|
||||
Com_Parse_t Com_Parse = Com_Parse_t(0x474D60);
|
||||
Com_MatchToken_t Com_MatchToken = Com_MatchToken_t(0x447130);
|
||||
@ -128,6 +130,7 @@ namespace Game
|
||||
Dvar_InfoString_Big_t Dvar_InfoString_Big = Dvar_InfoString_Big_t(0x4D98A0);
|
||||
Dvar_SetCommand_t Dvar_SetCommand = Dvar_SetCommand_t(0x4EE430);
|
||||
Dvar_DisplayableValue_t Dvar_DisplayableValue = Dvar_DisplayableValue_t(0x4B5530);
|
||||
Dvar_Reset_t Dvar_Reset = Dvar_Reset_t(0x4FEFD0);
|
||||
|
||||
Encode_Init_t Encode_Init = Encode_Init_t(0x462AB0);
|
||||
|
||||
@ -535,6 +538,8 @@ namespace Game
|
||||
|
||||
FxElemField* s_elemFields = reinterpret_cast<FxElemField*>(0x73B848);
|
||||
|
||||
visField_t* visionDefFields = reinterpret_cast<visField_t*>(0x7982F0); // Count 21
|
||||
|
||||
infoParm_t* infoParams = reinterpret_cast<infoParm_t*>(0x79D260); // Count 0x1E
|
||||
|
||||
XZone* g_zones = reinterpret_cast<XZone*>(0x14C0F80);
|
||||
@ -1639,8 +1644,8 @@ namespace Game
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax,[esp+0x4]
|
||||
mov ebx,0x569950
|
||||
mov eax, [esp+0x4]
|
||||
mov ebx, 0x569950
|
||||
call ebx
|
||||
retn
|
||||
}
|
||||
@ -1680,6 +1685,48 @@ namespace Game
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto Dvar_SetFromStringFromSource_Func = 0x648580;
|
||||
__declspec(naked) void Dvar_SetFromStringFromSource(const dvar_t* /*dvar*/, const char* /*string*/, DvarSetSource /*source*/)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
|
||||
mov esi, [esp + 0x20 + 0x4] // dvar
|
||||
mov eax, [esp + 0x20 + 0x8] // string
|
||||
push [esp + 0x20 + 0xC] // source
|
||||
call Dvar_SetFromStringFromSource_Func
|
||||
add esp, 0x4
|
||||
|
||||
popad
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto ApplyTokenToField_Func = 0x59A760;
|
||||
__declspec(naked) bool ApplyTokenToField(unsigned int /*fieldNum*/, const char* /*token*/, visionSetVars_t* /*settings*/)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push eax
|
||||
pushad
|
||||
|
||||
mov eax, [esp + 0x24 + 0x4] // fieldNum
|
||||
mov ecx, [esp + 0x24 + 0x8] // token
|
||||
push [esp + 0x24 + 0xC] // settings
|
||||
call ApplyTokenToField_Func
|
||||
add esp, 0x4
|
||||
|
||||
movzx eax, al // Zero extend eax
|
||||
mov [esp + 0x20], eax
|
||||
popad
|
||||
pop eax
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto SV_BotUserMove_Addr = 0x626E50;
|
||||
__declspec(naked) void SV_BotUserMove(client_t* /*client*/)
|
||||
{
|
||||
|
@ -169,6 +169,12 @@ namespace Game
|
||||
typedef void(__cdecl * Com_BeginParseSession_t)(const char* filename);
|
||||
extern Com_BeginParseSession_t Com_BeginParseSession;
|
||||
|
||||
typedef char*(__cdecl * Com_ParseOnLine_t)(const char** data_p);
|
||||
extern Com_ParseOnLine_t Com_ParseOnLine;
|
||||
|
||||
typedef void(__cdecl * Com_SkipRestOfLine_t)(const char** data);
|
||||
extern Com_SkipRestOfLine_t Com_SkipRestOfLine;
|
||||
|
||||
typedef void(__cdecl * Com_SetSpaceDelimited_t)(int);
|
||||
extern Com_SetSpaceDelimited_t Com_SetSpaceDelimited;
|
||||
|
||||
@ -325,6 +331,9 @@ namespace Game
|
||||
typedef const char*(__cdecl * Dvar_DisplayableValue_t)(const dvar_t* dvar);
|
||||
extern Dvar_DisplayableValue_t Dvar_DisplayableValue;
|
||||
|
||||
typedef void(__cdecl * Dvar_Reset_t)(const dvar_t* dvar, DvarSetSource setSource);
|
||||
extern Dvar_Reset_t Dvar_Reset;
|
||||
|
||||
typedef bool(__cdecl * Encode_Init_t)(const char* );
|
||||
extern Encode_Init_t Encode_Init;
|
||||
|
||||
@ -1177,6 +1186,8 @@ namespace Game
|
||||
|
||||
extern FxElemField* s_elemFields;
|
||||
|
||||
extern visField_t* visionDefFields;
|
||||
|
||||
extern infoParm_t* infoParams;
|
||||
|
||||
extern XZone* g_zones;
|
||||
@ -1339,4 +1350,7 @@ namespace Game
|
||||
void AimAssist_UpdateAdsLerp(const AimInput* input);
|
||||
|
||||
void Dvar_SetVariant(dvar_t* var, DvarValue value, DvarSetSource source);
|
||||
void Dvar_SetFromStringFromSource(const dvar_t* dvar, const char* string, DvarSetSource source);
|
||||
|
||||
bool ApplyTokenToField(unsigned int fieldNum, const char* token, visionSetVars_t* settings);
|
||||
}
|
||||
|
@ -1014,6 +1014,7 @@ namespace Game
|
||||
{
|
||||
const char* name;
|
||||
int offset;
|
||||
// 0 is for int, 1 is for float, otherwise it's a vector
|
||||
int fieldType;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user