292 lines
10 KiB
C++
292 lines
10 KiB
C++
|
|
#include "Memory.hpp";
|
||
|
|
#include "Maths.hpp";
|
||
|
|
#include "ObfuscateString.h"
|
||
|
|
#include <string>
|
||
|
|
#include <spdlog/spdlog.h>
|
||
|
|
#include <spdlog/sinks/basic_file_sink.h>
|
||
|
|
#include <safetyhook.hpp>
|
||
|
|
|
||
|
|
// Constants
|
||
|
|
const std::string PLUGIN_NAME = "Starfield";
|
||
|
|
const std::string PLUGIN_LOG = "Starfield.log";
|
||
|
|
const std::string gameExecutable = "Starfield.exe";
|
||
|
|
|
||
|
|
// Logger
|
||
|
|
std::shared_ptr<spdlog::logger> logger;
|
||
|
|
|
||
|
|
// Screen informations
|
||
|
|
static int screenWidth = GetSystemMetrics(SM_CXSCREEN);
|
||
|
|
static int screenHeight = GetSystemMetrics(SM_CYSCREEN);
|
||
|
|
static float aspectRatio = (float)screenWidth / screenHeight;
|
||
|
|
|
||
|
|
// Plugin states
|
||
|
|
static bool AOBScanDone = false;
|
||
|
|
static bool g_fix_enabled = false;
|
||
|
|
static bool g_dialog_fov_fix_enabled = false;
|
||
|
|
static bool g_weapon_fov_fix_enabled = false;
|
||
|
|
static bool g_HUD_fix_enabled = false;
|
||
|
|
static bool g_photomode_fix_enabled = false;
|
||
|
|
static int g_AdditionalDialogFOVValue = 0;
|
||
|
|
static int g_AdditionalWeaponFOVValue = 0;
|
||
|
|
static float g_HUDXValue = 0;
|
||
|
|
static float g_HUDYValue = 0;
|
||
|
|
|
||
|
|
// Shared values
|
||
|
|
static float g_Dialog_FOV_In = 0;
|
||
|
|
static float g_Dialog_FOV_Out = 0;
|
||
|
|
static float g_Weapon_FOV_In = 0;
|
||
|
|
static float g_Weapon_FOV_Out = 0;
|
||
|
|
|
||
|
|
// AOB Scan pointers
|
||
|
|
static uint8_t* DialogFOVAddress = nullptr;
|
||
|
|
static uint8_t* WeaponFOVAddress = nullptr;
|
||
|
|
static uint8_t* HUDAddress = nullptr;
|
||
|
|
static uint8_t* PhotomodeAddress = nullptr;
|
||
|
|
|
||
|
|
// Hooking
|
||
|
|
static SafetyHookMid DialogFOVHook{};
|
||
|
|
static SafetyHookMid WeaponFOVHook{};
|
||
|
|
static SafetyHookMid HUDHook{};
|
||
|
|
|
||
|
|
// Prototypes
|
||
|
|
static void DialogFOVFixEnabled(bool fix_enabled);
|
||
|
|
static void WeaponFOVFixEnabled(bool fix_enabled);
|
||
|
|
static void HUDFixEnabled(bool fix_enabled);
|
||
|
|
static void PhotomodeFixEnabled(bool fix_enabled);
|
||
|
|
|
||
|
|
extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled)
|
||
|
|
{
|
||
|
|
g_fix_enabled = enabled;
|
||
|
|
if (g_fix_enabled && !AOBScanDone) {
|
||
|
|
logger->info("--------------- AOB scan started ---------------");
|
||
|
|
// === AOB Scans ===
|
||
|
|
if (!DialogFOVAddress) {
|
||
|
|
constexpr auto DialogFOVPattern = make_obfuscated<0x4A>("E9 ?? ?? ?? ?? 49 ?? ?? E8 ?? ?? ?? ?? 84 ?? 0F 84 ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 89");
|
||
|
|
DialogFOVAddress = Memory::aob_scan(gameExecutable, DialogFOVPattern.decrypt(), PAGE_EXECUTE_READ);
|
||
|
|
if (DialogFOVAddress)
|
||
|
|
{
|
||
|
|
logger->info("Dialog FOV signature found at address: 0x{:X}.", reinterpret_cast<uintptr_t>(DialogFOVAddress));
|
||
|
|
}
|
||
|
|
else logger->warn("Dialog FOV signature not found. Maybe the game was updated.");
|
||
|
|
}
|
||
|
|
if (!WeaponFOVAddress) {
|
||
|
|
constexpr auto WeaponFOVPattern = make_obfuscated<0x4A>("C5 FA ?? ?? ?? ?? ?? ?? 80 3D ?? ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 74");
|
||
|
|
WeaponFOVAddress = Memory::aob_scan(gameExecutable, WeaponFOVPattern.decrypt(), PAGE_EXECUTE_READ);
|
||
|
|
if (WeaponFOVAddress)
|
||
|
|
{
|
||
|
|
logger->info("Weapon FOV signature found at address: 0x{:X}.", reinterpret_cast<uintptr_t>(WeaponFOVAddress));
|
||
|
|
}
|
||
|
|
else logger->warn("Weapon FOV signature not found. Maybe the game was updated.");
|
||
|
|
}
|
||
|
|
if (!HUDAddress) {
|
||
|
|
constexpr auto HUDPattern = make_obfuscated<0x4A>("C4 61 ?? ?? ?? ?? ?? ?? ?? C4 61 ?? ?? ?? ?? ?? ?? ?? 45 ?? ?? 74");
|
||
|
|
HUDAddress = Memory::aob_scan(gameExecutable, HUDPattern.decrypt(), PAGE_EXECUTE_READ);
|
||
|
|
if (HUDAddress)
|
||
|
|
{
|
||
|
|
logger->info("HUD safe zone signature found at address: 0x{:X}.", reinterpret_cast<uintptr_t>(HUDAddress));
|
||
|
|
HUDAddress += 0x12;
|
||
|
|
}
|
||
|
|
else logger->warn("HUD safe zone signature not found. Maybe the game was updated.");
|
||
|
|
}
|
||
|
|
if (!PhotomodeAddress) {
|
||
|
|
constexpr auto PhotomodePattern = make_obfuscated<0x4A>("74 ?? 0F BA ?? ?? 89 87 ?? ?? ?? ?? C6 87 ?? ?? ?? ?? ?? E8");
|
||
|
|
PhotomodeAddress = Memory::aob_scan(gameExecutable, PhotomodePattern.decrypt(), PAGE_EXECUTE_READ);
|
||
|
|
if (PhotomodeAddress)
|
||
|
|
{
|
||
|
|
logger->info("Photo mode signature found at address: 0x{:X}.", reinterpret_cast<uintptr_t>(PhotomodeAddress));
|
||
|
|
}
|
||
|
|
else logger->warn("Photo mode signature not found. Maybe the game was updated.");
|
||
|
|
if (DialogFOVAddress && WeaponFOVAddress && HUDAddress && PhotomodeAddress) {
|
||
|
|
logger->info("All AOB signatures found. Ready to patch...");
|
||
|
|
logger->info("--------------- AOB scan finished ---------------");
|
||
|
|
AOBScanDone = true;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
logger->warn("Some AOB signatures could not be found. Fixes may be partially unavailable.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// === Activer ou désactiver les patchs ===
|
||
|
|
if (DialogFOVAddress && WeaponFOVAddress && HUDAddress && PhotomodeAddress)
|
||
|
|
{
|
||
|
|
if (g_fix_enabled)
|
||
|
|
{
|
||
|
|
DialogFOVFixEnabled(g_dialog_fov_fix_enabled);
|
||
|
|
WeaponFOVFixEnabled(g_weapon_fov_fix_enabled);
|
||
|
|
HUDFixEnabled(g_HUD_fix_enabled);
|
||
|
|
PhotomodeFixEnabled(g_photomode_fix_enabled);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
DialogFOVFixEnabled(false);
|
||
|
|
WeaponFOVFixEnabled(false);
|
||
|
|
HUDFixEnabled(false);
|
||
|
|
PhotomodeFixEnabled(false);
|
||
|
|
logger->info("All fixes disabled.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Setters for Reshade addon call
|
||
|
|
extern "C" __declspec(dllexport) void SetDialogFOVFixEnabled(bool enabled, bool init)
|
||
|
|
{
|
||
|
|
g_dialog_fov_fix_enabled = enabled;
|
||
|
|
if (!init) DialogFOVFixEnabled(g_dialog_fov_fix_enabled);
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C" __declspec(dllexport) void SetWeaponFOVFixEnabled(bool enabled, bool init)
|
||
|
|
{
|
||
|
|
g_weapon_fov_fix_enabled = enabled;
|
||
|
|
if (!init) WeaponFOVFixEnabled(g_weapon_fov_fix_enabled);
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C" __declspec(dllexport) void SetHUDFixEnabled(bool enabled, bool init)
|
||
|
|
{
|
||
|
|
g_HUD_fix_enabled = enabled;
|
||
|
|
if (!init) HUDFixEnabled(g_HUD_fix_enabled);
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C" __declspec(dllexport) void SetPhotoModeFixEnabled(bool enabled, bool init)
|
||
|
|
{
|
||
|
|
g_photomode_fix_enabled = enabled;
|
||
|
|
if (!init) PhotomodeFixEnabled(g_photomode_fix_enabled);
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C" __declspec(dllexport) void SetDialogFOV(int fov)
|
||
|
|
{
|
||
|
|
g_AdditionalDialogFOVValue = fov;
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C" __declspec(dllexport) void SetWeaponFOV(int fov)
|
||
|
|
{
|
||
|
|
g_AdditionalWeaponFOVValue = fov;
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C" __declspec(dllexport) void SetHUDX(int HUDX)
|
||
|
|
{
|
||
|
|
g_HUDXValue = HUDX;
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C" __declspec(dllexport) void SetHUDY(int HUDY)
|
||
|
|
{
|
||
|
|
g_HUDYValue = HUDY;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Getters for Reshade addon call
|
||
|
|
extern "C" __declspec(dllexport) float GetDialogFOVIn() {
|
||
|
|
return g_Dialog_FOV_In;
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C" __declspec(dllexport) float GetDialogFOVOut() {
|
||
|
|
return g_Dialog_FOV_Out;
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C" __declspec(dllexport) float GetWeaponFOVIn() {
|
||
|
|
return g_Weapon_FOV_In;
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C" __declspec(dllexport) float GetWeaponFOVOut() {
|
||
|
|
return g_Weapon_FOV_Out;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Assembly code injections functions
|
||
|
|
static void DialogFOVFixEnabled(bool fix_enabled) {
|
||
|
|
if (g_fix_enabled && fix_enabled && DialogFOVAddress != nullptr) {
|
||
|
|
if (!DialogFOVHook) { // Hook only once
|
||
|
|
DialogFOVHook = safetyhook::create_mid(DialogFOVAddress,
|
||
|
|
[](SafetyHookContext& ctx) {
|
||
|
|
g_Dialog_FOV_In = ctx.xmm6.f32[0];
|
||
|
|
g_Dialog_FOV_Out = ctx.xmm6.f32[0] += (g_dialog_fov_fix_enabled ? g_AdditionalDialogFOVValue : 0); // World FOV
|
||
|
|
});
|
||
|
|
}
|
||
|
|
else DialogFOVHook.enable();
|
||
|
|
logger->info("FOV fix enabled");
|
||
|
|
}
|
||
|
|
if (!fix_enabled && DialogFOVHook) {
|
||
|
|
DialogFOVHook.disable();
|
||
|
|
logger->info("FOV fix disabled");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void WeaponFOVFixEnabled(bool fix_enabled) {
|
||
|
|
if (g_fix_enabled && fix_enabled && WeaponFOVAddress != nullptr) {
|
||
|
|
if (!WeaponFOVHook) {
|
||
|
|
WeaponFOVHook = safetyhook::create_mid(WeaponFOVAddress,
|
||
|
|
[](SafetyHookContext& ctx) {
|
||
|
|
g_Weapon_FOV_In = ctx.xmm0.f32[0];
|
||
|
|
g_Weapon_FOV_Out = ctx.xmm0.f32[0] += (g_weapon_fov_fix_enabled ? g_AdditionalWeaponFOVValue : 0);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
else WeaponFOVHook.enable();
|
||
|
|
logger->info("Weapon FOV fix enabled");
|
||
|
|
}
|
||
|
|
if (!fix_enabled && WeaponFOVHook) {
|
||
|
|
WeaponFOVHook.disable();
|
||
|
|
logger->info("Weapon FOV fix disabled");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void HUDFixEnabled(bool fix_enabled) {
|
||
|
|
if (g_fix_enabled && fix_enabled && HUDAddress) {
|
||
|
|
if (!HUDHook) {
|
||
|
|
HUDHook = safetyhook::create_mid(HUDAddress,
|
||
|
|
[](SafetyHookContext& ctx) {
|
||
|
|
int safeZoneX = (screenWidth / 2) * (g_HUDXValue / 100);
|
||
|
|
int safeZoneY = (screenHeight / 2) * (g_HUDYValue / 100);
|
||
|
|
ctx.r9 = *reinterpret_cast<uint32_t*>(&safeZoneX); // X axis
|
||
|
|
ctx.r8 = *reinterpret_cast<uint32_t*>(&safeZoneY); // Y axis
|
||
|
|
});
|
||
|
|
}
|
||
|
|
else HUDHook.enable();
|
||
|
|
logger->info("HUD fix enabled");
|
||
|
|
}
|
||
|
|
if (!fix_enabled && HUDHook) {
|
||
|
|
HUDHook.disable();
|
||
|
|
logger->info("HUD fix disabled");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void PhotomodeFixEnabled(bool fix_enabled) {
|
||
|
|
if (g_fix_enabled && fix_enabled && PhotomodeAddress != nullptr) {
|
||
|
|
Memory::PatchBytes(PhotomodeAddress, "\xEB", 1); // je ==> jmp
|
||
|
|
logger->info("Photomode fix enabled");
|
||
|
|
}
|
||
|
|
if (!fix_enabled && PhotomodeAddress) {
|
||
|
|
Memory::RestoreBytes(PhotomodeAddress);
|
||
|
|
logger->info("Photomode fix disabled");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// spdlog init with specific format
|
||
|
|
static void InitializeLogger()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
logger = spdlog::basic_logger_mt("Fixlib", PLUGIN_LOG, true);
|
||
|
|
spdlog::set_default_logger(logger);
|
||
|
|
// Format : [YYYY-MM-DD HH:MM:SS] [INFO] message
|
||
|
|
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S] [%^%l%$] %v");
|
||
|
|
spdlog::set_level(spdlog::level::debug);
|
||
|
|
logger->flush_on(spdlog::level::debug); // Flush automatically
|
||
|
|
}
|
||
|
|
catch (const spdlog::spdlog_ex& ex)
|
||
|
|
{
|
||
|
|
std::string plugin_error_message = "Could not open " + PLUGIN_LOG;
|
||
|
|
MessageBoxA(nullptr, plugin_error_message.c_str(), "Logger Error", MB_ICONERROR | MB_OK);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Entry point
|
||
|
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID)
|
||
|
|
{
|
||
|
|
if (reason == DLL_PROCESS_ATTACH)
|
||
|
|
{
|
||
|
|
InitializeLogger();
|
||
|
|
logger->info("Plugin {} loaded.", PLUGIN_NAME);
|
||
|
|
}
|
||
|
|
else if (reason == DLL_PROCESS_DETACH)
|
||
|
|
{
|
||
|
|
logger->info("Plugin {} unloaded.", PLUGIN_NAME);
|
||
|
|
spdlog::drop_all();
|
||
|
|
}
|
||
|
|
return TRUE;
|
||
|
|
}
|