Files
iw6-mod/src/client/component/ultrawide.cpp
T
2026-09-09 21:14:45 +02:00

165 lines
5.0 KiB
C++

#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include <utils/hook.hpp>
namespace ultrawide
{
namespace
{
game::dvar_t* r_aspectRatio;
game::dvar_t* dvar_register_aspect_ratio(const char* name, const char**, int default_index, unsigned int flags,
const char* description)
{
static const char* values[] =
{
"auto",
"standard",
"wide 16:10",
"wide 16:9",
"custom",
nullptr
};
// register custom aspect ratio dvar
dvars::r_aspectRatioCustom = game::Dvar_RegisterFloat("r_aspectRatioCustom", 16.0f / 9.0f, 4.0f / 3.0f,
63.0f / 9.0f, flags,
"Screen aspect ratio. Divide width by height to get the aspect ratio value. For example: 21 / 9 = 2,33");
// register r_aspectRatio dvar
r_aspectRatio = game::Dvar_RegisterEnum(name, values, default_index, flags, description);
return r_aspectRatio;
}
struct wnd_struct
{
char pad[0x1C];
float aspect_ratio;
};
float hud_aspect_ratio = 1.77778f;
float hud_aspect_ratio_inv = -1.77778f;
void ultrawide_patch(wnd_struct* wnd)
{
if (r_aspectRatio != nullptr
&& r_aspectRatio->current.integer == 4 && dvars::r_aspectRatioCustom != nullptr)
{
hud_aspect_ratio = dvars::r_aspectRatioCustom->current.value;
hud_aspect_ratio_inv = -hud_aspect_ratio;
if (wnd)
{
wnd->aspect_ratio = hud_aspect_ratio;
}
}
}
auto ultrawide_spawn_window_stub_mp = utils::hook::assemble([](utils::hook::assembler& a)
{
a.call_aligned(0x1405E5E70); // og - setup hwnd struct
a.lea(rcx, ptr(rsp, 0x0A0));
a.call_aligned(ultrawide_patch);
a.mov(edi, ptr(rsp, 0x0B0)); // mov edi, [rsp+0B0h]
a.jmp(0x1405E6903);
});
auto ultrawide_menu_stub_01_mp = utils::hook::assemble([](utils::hook::assembler& a)
{
a.push(eax);
a.mov(eax, dword_ptr(reinterpret_cast<int64_t>(&hud_aspect_ratio)));
a.movd(xmm5, eax);
a.divss(xmm0, xmm5); // divss xmm0, cs:FLOAT_1_77778 // -> custom aspect ratio
a.subss(xmm1, xmm0); // subss xmm1, xmm0
a.movaps(xmm0, xmm3); // movaps xmm0, xmm3
a.mov(eax, dword_ptr(reinterpret_cast<int64_t>(&hud_aspect_ratio_inv)));
a.movd(xmm5, eax);
a.mulss(xmm0, xmm5); // mulss xmm0, cs:dword_14083D47C // -1.77778 // -> left menu offset
a.pop(eax);
a.jmp(0x1402008D2);
});
auto ultrawide_menu_stub_02_mp = utils::hook::assemble([](utils::hook::assembler& a)
{
a.push(eax);
a.mov(eax, dword_ptr(reinterpret_cast<int64_t>(&hud_aspect_ratio)));
a.movd(xmm5, eax);
a.mulss(xmm0, xmm5); // mulss xmm0, cs:FLOAT_1_77778 // -> custom aspect ratio
a.mulss(xmm0, xmm1); // mulss xmm0, xmm1
a.pop(eax);
a.jmp(0x1402008FF);
});
auto ultrawide_hud_stub_mp = utils::hook::assemble([](utils::hook::assembler& a)
{
a.push(eax);
a.mov(eax, dword_ptr(reinterpret_cast<int64_t>(&hud_aspect_ratio)));
a.movd(xmm5, eax);
a.divss(xmm6, xmm5); // divss xmm6, cs:FLOAT_1_77778
a.mulss(xmm6, xmm3); // mulss xmm6, xmm3
a.pop(eax);
a.jmp(0x1402F704F);
});
}
class component final : public component_interface
{
public:
void post_unpack() override
{
// ultrawide patches
utils::hook::call(0x1405DCF58, dvar_register_aspect_ratio);
// register r_aspectRatioCustom
utils::hook::jump(0x1405E68F7, ultrawide_spawn_window_stub_mp, true);
// apply general aspect ratio
utils::hook::jump(0x1402008BB, ultrawide_menu_stub_01_mp, true);
// fix menu aspect ratio and left offset
utils::hook::jump(0x1402008F3, ultrawide_menu_stub_02_mp, true);
// fix menu aspect ratio right offset
utils::hook::jump(0x1402F7043, ultrawide_hud_stub_mp, true); // fix aspect ratio for loadscreen and general in-game hud
// safeArea_adjusted dvars :: disable resets (in-game hud padding)
utils::hook::nop(0x1402D4FB2, 5); // safeArea_adjusted_horizontal
utils::hook::nop(0x1402F7375, 5); // safeArea_adjusted_horizontal
utils::hook::nop(0x1402D4FD9, 5);
utils::hook::set<uint8_t>(0x1402D4FD9, 0xC3);
// safeArea_adjusted_vertical :: return instead of jumping to Dvar_SetFloat
utils::hook::nop(0x1402F7384, 5); // safeArea_adjusted_vertical
// safeArea_ dvars :: remove cheat protection + add saved flag
utils::hook::set<uint8_t>(0x1402F6EBF + 4, 0x1);
// register safeArea_horizontal (mov dword ptr [rsp+20h], 4)
utils::hook::set<uint8_t>(0x1402F6EF7 + 4, 0x1);
// register safeArea_vertical (mov dword ptr [rsp+20h], 4)
utils::hook::set<uint8_t>(0x1402F6F27 + 5, 0x0);
utils::hook::set<uint8_t>(0x1402F6F27 + 4, 0x1);
// register safeArea_adjusted_horizontal (mov dword ptr [rsp+20h], 2000h)
utils::hook::set<uint8_t>(0x1402F6F57 + 5, 0x0);
utils::hook::set<uint8_t>(0x1402F6F57 + 4, 0x1);
// register safeArea_adjusted_vertical (mov dword ptr [rsp+20h], 2000h)
}
};
}
REGISTER_COMPONENT(ultrawide::component)