Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor config string handling to allocate multiple areas, allocate… #87

Merged
merged 6 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Components/Loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "Modules/ClientCommand.hpp"
#include "Modules/ConnectProtocol.hpp"
#include "Modules/Console.hpp"
#include "Modules/ConfigStrings.hpp"
#include "Modules/D3D9Ex.hpp"
#include "Modules/Debug.hpp"
#include "Modules/Discord.hpp"
Expand All @@ -32,6 +33,7 @@
#include "Modules/MapRotation.hpp"
#include "Modules/Materials.hpp"
#include "Modules/ModList.hpp"
#include "Modules/ModelCache.hpp"
#include "Modules/ModelSurfs.hpp"
#include "Modules/NetworkDebug.hpp"
#include "Modules/News.hpp"
Expand Down Expand Up @@ -110,6 +112,8 @@ namespace Components
Register(new UIScript());
Register(new ZoneBuilder());

Register(new ConfigStrings()); // Needs to be there early !! Before modelcache & weapons

Register(new ArenaLength());
Register(new AssetHandler());
Register(new Bans());
Expand Down Expand Up @@ -144,6 +148,7 @@ namespace Components
Register(new Materials());
Register(new Menus());
Register(new ModList());
Register(new ModelCache());
Register(new ModelSurfs());
Register(new NetworkDebug());
Register(new News());
Expand Down
2 changes: 1 addition & 1 deletion src/Components/Modules/AssetHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ namespace Components
Game::ReallocateAssetPool(Game::ASSET_TYPE_VERTEXSHADER, ZoneBuilder::IsEnabled() ? 0x2000 : 3072);
Game::ReallocateAssetPool(Game::ASSET_TYPE_MATERIAL, 8192 * 2);
Game::ReallocateAssetPool(Game::ASSET_TYPE_VERTEXDECL, ZoneBuilder::IsEnabled() ? 0x400 : 196);
Game::ReallocateAssetPool(Game::ASSET_TYPE_WEAPON, WEAPON_LIMIT);
Game::ReallocateAssetPool(Game::ASSET_TYPE_WEAPON, Weapon::WEAPON_LIMIT);
Game::ReallocateAssetPool(Game::ASSET_TYPE_STRINGTABLE, 800);
Game::ReallocateAssetPool(Game::ASSET_TYPE_IMPACT_FX, 8);

Expand Down
6 changes: 3 additions & 3 deletions src/Components/Modules/ClientCommand.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <STDInclude.hpp>
#include "ClientCommand.hpp"

#include "Weapon.hpp"
#include "ModelCache.hpp"

#include "GSC/Script.hpp"

Expand Down Expand Up @@ -384,9 +384,9 @@ namespace Components
Game::XModel* model = nullptr;
if (ent->model)
{
if (Components::Weapon::GModelIndexHasBeenReallocated)
if (Components::ModelCache::modelsHaveBeenReallocated)
{
model = Components::Weapon::cached_models_reallocated[ent->model];
model = Components::ModelCache::cached_models_reallocated[ent->model];
}
else
{
Expand Down
305 changes: 305 additions & 0 deletions src/Components/Modules/ConfigStrings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
#include <STDInclude.hpp>
#include "ConfigStrings.hpp"

namespace Components
{
// Patch game state
// The structure below is our own implementation of the gameState_t structure
static struct ReallocatedGameState_t
{
int stringOffsets[ConfigStrings::MAX_CONFIGSTRINGS];
char stringData[131072]; // MAX_GAMESTATE_CHARS
int dataCount;
} cl_gameState{};

static short sv_configStrings[ConfigStrings::MAX_CONFIGSTRINGS]{};

// New mapping (extra data)
constexpr auto EXTRA_WEAPONS_FIRST = ConfigStrings::BASEGAME_MAX_CONFIGSTRINGS;
constexpr auto EXTRA_WEAPONS_LAST = EXTRA_WEAPONS_FIRST + Weapon::ADDED_WEAPONS - 1;

constexpr auto EXTRA_MODELCACHE_FIRST = EXTRA_WEAPONS_LAST + 1;
constexpr auto EXTRA_MODELCACHE_LAST = EXTRA_MODELCACHE_FIRST + ModelCache::ADDITIONAL_GMODELS;

constexpr auto RUMBLE_FIRST = EXTRA_MODELCACHE_LAST + 1;
constexpr auto RUMBLE_LAST = RUMBLE_FIRST + 31; // TODO

void ConfigStrings::PatchConfigStrings()
{
// bump clientstate fields
Utils::Hook::Set<DWORD>(0x4347A7, MAX_CONFIGSTRINGS);
Utils::Hook::Set<DWORD>(0x4982F4, MAX_CONFIGSTRINGS);
Utils::Hook::Set<DWORD>(0x4F88B6, MAX_CONFIGSTRINGS); // Save file
Utils::Hook::Set<DWORD>(0x5A1FA7, MAX_CONFIGSTRINGS);
Utils::Hook::Set<DWORD>(0x5A210D, MAX_CONFIGSTRINGS); // Game state
Utils::Hook::Set<DWORD>(0x5A840E, MAX_CONFIGSTRINGS);
Utils::Hook::Set<DWORD>(0x5A853C, MAX_CONFIGSTRINGS);
Utils::Hook::Set<DWORD>(0x5AC392, MAX_CONFIGSTRINGS);
Utils::Hook::Set<DWORD>(0x5AC3F5, MAX_CONFIGSTRINGS);
Utils::Hook::Set<DWORD>(0x5AC542, MAX_CONFIGSTRINGS); // Game state
Utils::Hook::Set<DWORD>(0x5EADF0, MAX_CONFIGSTRINGS);
Utils::Hook::Set<DWORD>(0x625388, MAX_CONFIGSTRINGS);
Utils::Hook::Set<DWORD>(0x625516, MAX_CONFIGSTRINGS);

Utils::Hook::Set(0x405B72, sv_configStrings);
Utils::Hook::Set(0x468508, sv_configStrings);
Utils::Hook::Set(0x47FD7C, sv_configStrings);
Utils::Hook::Set(0x49830E, sv_configStrings);
Utils::Hook::Set(0x498371, sv_configStrings);
Utils::Hook::Set(0x4983D5, sv_configStrings);
Utils::Hook::Set(0x4A74AD, sv_configStrings);
Utils::Hook::Set(0x4BAE7C, sv_configStrings);
Utils::Hook::Set(0x4BAEC3, sv_configStrings);
Utils::Hook::Set(0x6252F5, sv_configStrings);
Utils::Hook::Set(0x625372, sv_configStrings);
Utils::Hook::Set(0x6253D3, sv_configStrings);
Utils::Hook::Set(0x625480, sv_configStrings);
Utils::Hook::Set(0x6254CB, sv_configStrings);

// TODO: Check if all of these actually mark the end of the array
// Only 2 actually mark the end, the rest is header data or so
Utils::Hook::Set(0x405B8F, &sv_configStrings[ARRAYSIZE(sv_configStrings)]);
Utils::Hook::Set(0x4A74C9, &sv_configStrings[ARRAYSIZE(sv_configStrings)]);

Utils::Hook(0x405BBE, ConfigStrings::SV_ClearConfigStrings, HOOK_CALL).install()->quick();
Utils::Hook(0x593CA4, ConfigStrings::CG_ParseConfigStrings, HOOK_CALL).install()->quick();

// Weapon
Utils::Hook(0x4BD52D, ConfigStrings::CL_GetWeaponConfigString, HOOK_CALL).install()->quick();
Utils::Hook(0x45D19E , ConfigStrings::SV_SetWeaponConfigString, HOOK_CALL).install()->quick();

// Cached Models
Utils::Hook(0x589908, ConfigStrings::CL_GetCachedModelConfigString, HOOK_CALL).install()->quick();
Utils::Hook(0x450A30, ConfigStrings::CL_GetCachedModelConfigString, HOOK_CALL).install()->quick();
Utils::Hook(0x4503F6, ConfigStrings::CL_GetCachedModelConfigString, HOOK_CALL).install()->quick();
Utils::Hook(0x4504A0, ConfigStrings::CL_GetCachedModelConfigString, HOOK_CALL).install()->quick();
Utils::Hook(0x450A30, ConfigStrings::CL_GetCachedModelConfigString, HOOK_CALL).install()->quick();

Utils::Hook(0x44F217, ConfigStrings::SV_GetCachedModelConfigStringConst, HOOK_CALL).install()->quick();
Utils::Hook(0X418F93, ConfigStrings::SV_GetCachedModelConfigStringConst, HOOK_CALL).install()->quick();
Utils::Hook(0x497B0A, ConfigStrings::SV_GetCachedModelConfigStringConst, HOOK_CALL).install()->quick();
Utils::Hook(0x4F4493, ConfigStrings::SV_GetCachedModelConfigStringConst, HOOK_CALL).install()->quick();
Utils::Hook(0x5FC46D, ConfigStrings::SV_GetCachedModelConfigStringConst, HOOK_JUMP).install()->quick();

Utils::Hook(0x44F282, ConfigStrings::SV_SetCachedModelConfigString, HOOK_CALL).install()->quick();

Utils::Hook::Set<DWORD>(0x44A333, sizeof(cl_gameState));
Utils::Hook::Set<DWORD>(0x5A1F56, sizeof(cl_gameState));
Utils::Hook::Set<DWORD>(0x5A2043, sizeof(cl_gameState));

Utils::Hook::Set<DWORD>(0x5A2053, sizeof(cl_gameState.stringOffsets));
Utils::Hook::Set<DWORD>(0x5A2098, sizeof(cl_gameState.stringOffsets));
Utils::Hook::Set<DWORD>(0x5AC32C, sizeof(cl_gameState.stringOffsets));

Utils::Hook::Set(0x4235AC, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x434783, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x44A339, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x44ADB7, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5A1FE6, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5A2048, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5A205A, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5A2077, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5A2091, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5A20D7, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5A83FF, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5A84B0, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5A84E5, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5AC333, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5AC44A, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5AC4F3, &cl_gameState.stringOffsets);
Utils::Hook::Set(0x5AC57A, &cl_gameState.stringOffsets);

Utils::Hook::Set(0x4235B7, &cl_gameState.stringData);
Utils::Hook::Set(0x43478D, &cl_gameState.stringData);
Utils::Hook::Set(0x44ADBC, &cl_gameState.stringData);
Utils::Hook::Set(0x5A1FEF, &cl_gameState.stringData);
Utils::Hook::Set(0x5A20E6, &cl_gameState.stringData);
Utils::Hook::Set(0x5AC457, &cl_gameState.stringData);
Utils::Hook::Set(0x5AC502, &cl_gameState.stringData);
Utils::Hook::Set(0x5AC586, &cl_gameState.stringData);

Utils::Hook::Set(0x5A2071, &cl_gameState.dataCount);
Utils::Hook::Set(0x5A20CD, &cl_gameState.dataCount);
Utils::Hook::Set(0x5A20DC, &cl_gameState.dataCount);
Utils::Hook::Set(0x5A20F3, &cl_gameState.dataCount);
Utils::Hook::Set(0x5A2104, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC33F, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC43B, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC450, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC463, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC471, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC4C3, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC4E8, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC4F8, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC50F, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC528, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC56F, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC580, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC592, &cl_gameState.dataCount);
Utils::Hook::Set(0x5AC59F, &cl_gameState.dataCount);
}

void ConfigStrings::SV_SetConfigString(int index, const char* data, Game::ConfigString basegameLastPosition, int extendedFirstPosition)
{
if (index > basegameLastPosition)
{
// we jump straight to the reallocated part of the array
const auto relativeIndex = index - (basegameLastPosition + 1);
index = extendedFirstPosition + relativeIndex;
}

// This will go back to our reallocated game state anyway
return Game::SV_SetConfigstring(index, data);
}

void ConfigStrings::SV_SetWeaponConfigString(int index, const char* data)
{
SV_SetConfigString(index, data, Game::CS_WEAPONFILES_LAST, EXTRA_WEAPONS_FIRST);
}

void ConfigStrings::SV_SetCachedModelConfigString(int index, const char* data)
{
SV_SetConfigString(index, data, Game::CS_MODELS_LAST, EXTRA_MODELCACHE_FIRST);
}

unsigned int ConfigStrings::SV_GetConfigString(int index, Game::ConfigString basegameLastPosition, int extendedFirstPosition)
{
if (index > basegameLastPosition)
{
// It's out of range, because we're loading more weapons than the basegame has
// So we jump straight to the reallocated part of the array
const auto relativeIndex = index - (basegameLastPosition + 1);

index = extendedFirstPosition + relativeIndex;
}

// This will go back to our reallocated game state anyway
return Game::SV_GetConfigstringConst(index);
}

const char* ConfigStrings::CL_GetConfigString(int index, Game::ConfigString basegameLastPosition, int extendedFirstPosition)
{
if (index > basegameLastPosition)
{
// It's out of range, because we're loading more weapons than the basegame has
// So we jump straight to the reallocated part of the array
const auto relativeIndex = index - (basegameLastPosition + 1);

index = extendedFirstPosition + relativeIndex;
}

// This will go back to our reallocated game state anyway
return Game::CL_GetConfigString(index);
}

const char* ConfigStrings::CL_GetCachedModelConfigString(int index)
{
return CL_GetConfigString(index, Game::CS_MODELS_LAST, EXTRA_MODELCACHE_FIRST);
}

int ConfigStrings::SV_GetCachedModelConfigStringConst(int index)
{
return SV_GetConfigString(index, Game::CS_MODELS_LAST, EXTRA_MODELCACHE_FIRST);
}

const char* ConfigStrings::CL_GetWeaponConfigString(int index)
{
return CL_GetConfigString(index, Game::CS_WEAPONFILES_LAST, EXTRA_WEAPONS_FIRST);
}

int ConfigStrings::SV_GetWeaponConfigStringConst(int index)
{
return SV_GetConfigString(index, Game::CS_WEAPONFILES_LAST, EXTRA_WEAPONS_FIRST);
}

int ConfigStrings::CG_ParseExtraConfigStrings()
{
Command::ClientParams params;

if (params.size() <= 1)
return 0;

char* end;
const auto* input = params.get(1);
auto index = std::strtol(input, &end, 10);

if (input == end)
{
Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "{} is not a valid input\nUsage: {} <weapon index>\n",
input, params.get(0));
return 0;
}

// If it's one of our extra data
// bypass parsing and handle it ourselves!
if (index >= BASEGAME_MAX_CONFIGSTRINGS)
{
// Handle extra weapons
if (index >= EXTRA_WEAPONS_FIRST && index <= EXTRA_WEAPONS_LAST)
{
// Recompute weapon index
index = index - EXTRA_WEAPONS_FIRST + Weapon::BASEGAME_WEAPON_LIMIT;
Game::CG_SetupWeaponConfigString(0, index);
}
// Handle extra models
else if (index >= EXTRA_MODELCACHE_FIRST && index <= EXTRA_MODELCACHE_LAST)
{
const auto name = Game::CL_GetConfigString(index);

const auto R_RegisterModel = 0x50FA00;

index = index - EXTRA_MODELCACHE_FIRST + ModelCache::BASE_GMODEL_COUNT;
ModelCache::gameModels_reallocated[index] = Utils::Hook::Call<Game::XModel*(const char*)>(R_RegisterModel)(name);
}
else
{
// Unknown for now?
// Pass it to the game
return 0;
}

// We handled it
return 1;
}

// Pass it to the game
return 0;
}

__declspec(naked) void ConfigStrings::CG_ParseConfigStrings()
{
__asm
{
push eax
pushad

call ConfigStrings::CG_ParseExtraConfigStrings

mov[esp + 20h], eax
popad

pop eax

test eax, eax
jz continueParsing

retn

continueParsing :
push 592960h
retn
}
}

int ConfigStrings::SV_ClearConfigStrings(void* dest, int value, int size)
{
memset(Utils::Hook::Get<void*>(0x405B72), value, MAX_CONFIGSTRINGS * sizeof(uint16_t));
return Utils::Hook::Call<int(void*, int, int)>(0x4C98D0)(dest, value, size); // Com_Memset
}


ConfigStrings::ConfigStrings()
{
PatchConfigStrings();
}
}
Loading
Loading