iw7-mod/src/client/component/patches.cpp

200 lines
6.1 KiB
C++
Raw Normal View History

2022-05-20 14:59:24 -04:00
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
2022-09-18 09:38:50 -04:00
#include "game/dvars.hpp"
2022-05-20 14:59:24 -04:00
2022-09-21 12:14:51 -04:00
#include "fastfiles.hpp"
#include "dvars.hpp"
2022-05-20 14:59:24 -04:00
#include <utils/hook.hpp>
#include <utils/string.hpp>
namespace patches
{
namespace
{
2022-09-21 12:14:51 -04:00
utils::hook::detour com_register_common_dvars_hook;
utils::hook::detour cg_set_client_dvar_from_server_hook;
utils::hook::detour live_get_map_index_hook;
utils::hook::detour content_do_we_have_content_pack_hook;
std::string get_login_username()
{
char username[UNLEN + 1];
DWORD username_len = UNLEN + 1;
if (!GetUserNameA(username, &username_len))
{
return "Unknown Soldier";
}
return std::string{ username, username_len - 1 };
}
game::dvar_t* name_dvar;
game::dvar_t* com_maxfps;
game::dvar_t* cg_fov;
game::dvar_t* cg_fovScale;
void com_register_common_dvars_stub()
{
name_dvar = game::Dvar_RegisterString("name", get_login_username().data(), game::DVAR_FLAG_SAVED, "Player name.");
com_maxfps = game::Dvar_RegisterInt("com_maxfps", 0, 0, 1000, game::DVAR_FLAG_SAVED, "Cap frames per second");
cg_fov = game::Dvar_RegisterFloat("cg_fov", 65.0f, 1.0f, 160.f, game::DVAR_FLAG_SAVED,
"The field of view angle in degrees");
cg_fovScale = game::Dvar_RegisterFloat("cg_fovScale", 1.0f, 0.1f, 2.0f, game::DVAR_FLAG_SAVED,
"Scale applied to the field of view");
*reinterpret_cast<game::dvar_t**>(0x6005758_b) = com_maxfps;
dvars::disable::re_register("com_maxfps");
dvars::disable::de_register("com_maxfps");
*reinterpret_cast<game::dvar_t**>(0x1FA6DA0_b) = cg_fov;
dvars::disable::re_register("cg_fov");
dvars::disable::de_register("cg_fov");
*reinterpret_cast<game::dvar_t**>(0x1FA6DB0_b) = cg_fovScale;
dvars::disable::re_register("cg_fovScale");
dvars::disable::de_register("cg_fovScale");
return com_register_common_dvars_hook.invoke<void>();
}
const char* live_get_local_client_name()
{
return game::Dvar_FindVar("name")->current.string;
}
2022-09-18 09:38:50 -04:00
void dvar_write_single_variable_stub(const game::dvar_t* dvar, int* user_data)
{
if ((dvar->flags & game::DVAR_FLAG_SAVED) != 0)
{
const char* val = game::Dvar_DisplayableLatchedValue(dvar);
auto h = *user_data;
auto dvar_name = dvars::dvar_get_name(dvar);
if (!dvar_name.empty())
{
game::FS_Printf(h, "seta %s \"%s\"\n", dvar_name.data(), val);
}
else
{
game::FS_Printf(h, "setcl %d \"%s\"\n", dvar->checksum, val);
}
}
}
2022-09-21 12:14:51 -04:00
void missing_content_error_stub(int, const char*)
{
game::Com_Error(game::ERR_DROP, utils::string::va("MISSING FILE\n%s.ff",
fastfiles::get_current_fastfile().data()));
}
const char* stored_mapname;
int live_get_map_index_stub(const char* map)
{
stored_mapname = map;
return live_get_map_index_hook.invoke<int>(map);
}
bool content_do_we_have_content_pack_stub(int index)
{
if (stored_mapname != nullptr && !fastfiles::exists(stored_mapname))
{
stored_mapname = nullptr;
return false;
}
return content_do_we_have_content_pack_hook.invoke<bool>(index);
}
void cg_set_client_dvar_from_server_stub(void* client_num, void* cgame_glob, const char* dvar_checksum, const char* value)
{
unsigned int checksum = static_cast<unsigned int>(atoi(dvar_checksum));
auto* dvar = game::Dvar_FindMalleableVar(checksum);
static unsigned int cg_fov_checksum = game::Dvar_GenerateChecksum("cg_fov");
static unsigned int cg_fovScale_checksum = game::Dvar_GenerateChecksum("cg_fovScale");
if (checksum == cg_fov_checksum ||
checksum == cg_fovScale_checksum)
{
return;
}
// register new dvar
if (!dvar)
{
game::Dvar_SetFromStringByChecksum(checksum, value, game::DvarSetSource::DVAR_SOURCE_EXTERNAL);
}
// only set if dvar has no flags or has external flag
else if (dvar->flags == game::DVAR_FLAG_NONE ||
(dvar->flags & game::DVAR_FLAG_EXTERNAL) != 0)
{
game::Dvar_SetFromStringFromSource(dvar, value, game::DvarSetSource::DVAR_SOURCE_EXTERNAL);
}
// original code
unsigned int index = 0;
auto result = utils::hook::invoke<__int64>(0xB7AC60_b, dvar, &index); // NetConstStrings_SV_GetNetworkDvarIndex
if (result)
{
std::string index_str = std::to_string(index);
return cg_set_client_dvar_from_server_hook.invoke<void>(client_num, cgame_glob, index_str.data(), value);
}
}
game::dvar_t* get_client_dvar(const char* name)
{
game::dvar_t* dvar = game::Dvar_FindVar(name);
if (!dvar)
{
static game::dvar_t dummy{ 0 };
dummy.checksum = game::Dvar_GenerateChecksum(name);
return &dummy;
}
return dvar;
}
bool get_client_dvar_checksum(game::dvar_t* dvar, unsigned int* checksum)
{
*checksum = dvar->checksum;
return true;
}
2022-05-20 14:59:24 -04:00
}
class component final : public component_interface
{
public:
void post_unpack() override
{
2022-09-21 12:14:51 -04:00
// register custom dvars
com_register_common_dvars_hook.create(0xBADF30_b, com_register_common_dvars_stub);
// get client name from dvar
utils::hook::jump(0xD32770_b, live_get_local_client_name);
2022-09-18 09:38:50 -04:00
// write better config
utils::hook::jump(0xBB2A50_b, dvar_write_single_variable_stub);
2022-09-21 12:14:51 -04:00
// show missing fastfiles
utils::hook::call(0x3BBD4B_b, missing_content_error_stub);
// show missing map
stored_mapname = nullptr;
live_get_map_index_hook.create(0xCE72C0_b, live_get_map_index_stub);
content_do_we_have_content_pack_hook.create(0xCE8550_b, content_do_we_have_content_pack_stub);
// make setclientdvar behave like older games
cg_set_client_dvar_from_server_hook.create(0x856D70_b, cg_set_client_dvar_from_server_stub);
utils::hook::call(0xB0A9BB_b, get_client_dvar_checksum); // setclientdvar
utils::hook::call(0xB0ACD7_b, get_client_dvar_checksum); // setclientdvars
utils::hook::call(0xB0A984_b, get_client_dvar); // setclientdvar
utils::hook::call(0xB0AC9F_b, get_client_dvar); // setclientdvars
utils::hook::set<uint8_t>(0xB0A9AC_b, 0xEB); // setclientdvar
utils::hook::set<uint8_t>(0xB0ACC8_b, 0xEB); // setclientdvars
// don't reset our fov
utils::hook::set<uint8_t>(0x8A6160_b, 0xC3);
2022-05-20 14:59:24 -04:00
}
};
}
REGISTER_COMPONENT(patches::component)