Files
ReshadePluginsCore/Starfield/dllmain.cpp

292 lines
10 KiB
C++
Raw Normal View History

#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;
}