Files
ReshadePluginsAddon/DeathStranding2/dllmain.cpp

318 lines
16 KiB
C++
Raw Normal View History

2026-03-22 17:23:49 +01:00
#define IMGUI_DISABLE_INCLUDE_IMCONFIG_H
#define IMGUI_HAS_DOCK 1
#include "CommonHeaders.h"
#include "HotkeysManager.h"
#include "DirectX.h"
#include <thread>
2026-03-22 17:23:49 +01:00
// Constants
constexpr ULONGLONG DECIMA_ENGINE_INIT_DELAY = 6000; // Use to wait for Decima engine to be ready
2026-03-22 17:23:49 +01:00
// Screen informations
static int screenHeight = GetSystemMetrics(SM_CYSCREEN);
// Core game dll functions declarations
typedef void (*SetBoolFn)(bool, bool);
typedef void (*SetFixesFn)(GameFixes, bool);
typedef void (*SetFloatFn)(GameSetting, float);
static HMODULE fixLib = nullptr;
static LONG g_coreInitialized = 0;
static SetBoolFn SetFixEnabled = nullptr;
static SetFixesFn SetFixes = nullptr;
static SetFloatFn SetValues = nullptr;
void SetFixesEnabled(GameFixes fix, bool value) { if (SetFixes) SetFixes(fix, value); }
static GetGameInfosStruct GetGameInfos = nullptr;
// Plugin variables for checkboxes and sliders
static bool fov_fix_enabled = false;
static bool ultrawide_fix_enabled = false;
2026-03-30 12:39:42 +02:00
static bool HUD_fix_enabled = false;
2026-03-22 22:52:31 +01:00
static bool camera_fix_enabled = false;
static bool DOF_fix_enabled = false;
static bool vignetting_fix_enabled = false;
2026-03-30 20:45:42 +02:00
static bool sharpening_fix_enabled = false;
2026-03-22 17:23:49 +01:00
static bool fix_enabled = false;
static int worldFOVvalue = 0;
2026-03-22 22:52:31 +01:00
static float cameraDistancevalue = 1.f;
2026-03-30 20:45:42 +02:00
static float sharpeningvalue = 1.f;
2026-03-30 12:39:42 +02:00
static int HUDvalue = 0;
static int triggerDelayMs = 2000; // Default delay between shortcuts
2026-03-22 17:23:49 +01:00
// Overlays popups
static bool popup_Informations = false;
static bool show_log_overlay = false;
static std::string log_content;
// Plugin settings
const std::string SETTINGS_FILE = "./pluginsettings.ini";
2026-03-31 21:07:57 +02:00
const char* FIX_VERSION = "1.0.4.1";
2026-03-30 20:45:42 +02:00
const char* FIX_INFORMATIONS = "This fix allows to:\n - Control FOV in game.\n - Control camera distance.\n - Enable ultrawide.\n - Control HUD scaling.\n - Disable depth of field in cutscenes.\n - Disable vignetting.\n - Control image sharpening.";
2026-03-22 17:23:49 +01:00
const char* DONATION_URL = "https://buymeacoffee.com/k4sh44";
// Scaling factor based on screen resolution
float scale = (float)screenHeight / 1200;
// Prepare arrays of checkboxes for ImGui
static FixToggle individualFixes[] = {
{ "FOV", &fov_fix_enabled, GameFixes::FOV },
{ "Depth of field", &DOF_fix_enabled, GameFixes::DOF },
{ "Vignetting", &vignetting_fix_enabled, GameFixes::Vignetting },
2026-03-30 20:45:42 +02:00
{ "Sharpening", &sharpening_fix_enabled, GameFixes::Sharpening, "This fix will override game setting."},
{ "Ultrawide", &ultrawide_fix_enabled, GameFixes::UltraWide, "This fix targets aspect ratios wider than 32:9.\n"
"It forces the engine to redraw the aspect by simulating shortcuts.\n"
2026-03-30 20:45:42 +02:00
"Use the slider below to fine tune the delay between simulated shortcuts.\n"
"Increase the delay on slower PCs, decrease it on faster ones."},
2026-03-30 20:45:42 +02:00
{ "HUD", &HUD_fix_enabled, GameFixes::HUD, "Use this fix to reposition HUD for ultrawide displays."},
2026-03-22 22:52:31 +01:00
{ "Camera", &camera_fix_enabled, GameFixes::Camera } };
2026-03-22 17:23:49 +01:00
// Prepare array of sliders for ImGui
2026-03-30 20:45:42 +02:00
static SliderFix2 sliders[5];
2026-03-22 17:23:49 +01:00
// Load and unload game core dll functions /!\ necessary
static void LoadFixDLL(reshade::api::effect_runtime* runtime) {
if (InterlockedCompareExchange(&g_coreInitialized, 1, 0) != 0)
return;
if (GetModuleHandleA("DeathStranding2Core.dll") == nullptr) {
fixLib = LoadLibraryA("DeathStranding2Core.dll");
if (!fixLib) {
MessageBoxA(nullptr, "Impossible to load game core dll", "Erreur", MB_OK);
return;
}
SetFixEnabled = (SetBoolFn)GetProcAddress(fixLib, "SetFixEnabled");
SetFixes = (SetFixesFn)GetProcAddress(fixLib, "SetFixesEnabled");
SetValues = (SetFloatFn)GetProcAddress(fixLib, "SetValues");
GetGameInfos = (GetGameInfosStruct)GetProcAddress(fixLib, "GetGameInfos");
// Apply initial values loaded from settings
if (SetValues) {
SetValues(GameSetting::FOV, worldFOVvalue);
2026-03-30 12:39:42 +02:00
SetValues(GameSetting::HUD, HUDvalue);
2026-03-22 22:52:31 +01:00
SetValues(GameSetting::CameraDistance, cameraDistancevalue);
2026-03-30 20:45:42 +02:00
SetValues(GameSetting::Sharpening, sharpeningvalue);
2026-03-22 17:23:49 +01:00
}
if (SetFixEnabled) SetFixEnabled(fix_enabled, true);
if (SetFixes) {
SetFixes(GameFixes::FOV, fov_fix_enabled);
2026-03-30 12:39:42 +02:00
SetFixes(GameFixes::HUD, HUD_fix_enabled);
2026-03-22 22:52:31 +01:00
SetFixes(GameFixes::Camera, camera_fix_enabled);
SetFixes(GameFixes::DOF, DOF_fix_enabled);
SetFixes(GameFixes::Vignetting, vignetting_fix_enabled);
2026-03-30 20:45:42 +02:00
SetFixes(GameFixes::Sharpening, sharpening_fix_enabled);
2026-03-22 17:23:49 +01:00
}
sliders[0] = { "In game additional FOV", "##FOVValue", SliderType::Int, &worldFOVvalue, -20, 50, GameSetting::FOV, SetValues };
2026-03-30 12:39:42 +02:00
sliders[1] = { "HUD scaling", "##HUDValue", SliderType::Int, &HUDvalue, -20, 40, GameSetting::HUD, SetValues };
2026-03-30 20:45:42 +02:00
sliders[2] = { "Sharpening value", "##SharpeningValue", SliderType::Float, &sharpeningvalue, 0, 1.5, GameSetting::Sharpening, SetValues, "%.1f" };
sliders[3] = { "Camera distance", "##CamValue", SliderType::Float, &cameraDistancevalue, 0, 5, GameSetting::CameraDistance, SetValues, "%.1f",
2026-03-22 22:52:31 +01:00
"Value is a multiplier.\nFinal value reported below is in meters."};
2026-03-30 20:45:42 +02:00
sliders[4] = { "Ultrawide enforce delay", "##AltEnterValue", SliderType::Int, &triggerDelayMs, 1000, 5000, GameSetting::Threshold, SetValues, "",
"This value is a delay in ms between the simulated shortcuts to enforce aspect ratio on launch." };
2026-03-22 17:23:49 +01:00
}
}
// Settings functions
static void SaveSettings() {
ini::IniFile pluginIniFile;
pluginIniFile["1#General fix"].setComment(std::vector<std::string>{ "The following sections are saved by plugin",
"You should not need to modify them",
" ",
"Controls if fix mod (globally) is enabled" });
pluginIniFile["1#General fix"]["Enabled"] = fix_enabled;
pluginIniFile["1#General fix"]["TriggerDelayMs"] = triggerDelayMs;
2026-03-22 17:23:49 +01:00
pluginIniFile["2#Individual fix"].setComment("Controls each fix individually");
pluginIniFile["2#Individual fix"]["FOV"] = fov_fix_enabled;
pluginIniFile["2#Individual fix"]["UltraWide"] = ultrawide_fix_enabled;
2026-03-30 12:39:42 +02:00
pluginIniFile["2#Individual fix"]["HUD"] = HUD_fix_enabled;
2026-03-22 22:52:31 +01:00
pluginIniFile["2#Individual fix"]["Camera"] = camera_fix_enabled;
pluginIniFile["2#Individual fix"]["DOF"] = DOF_fix_enabled;
pluginIniFile["2#Individual fix"]["Vignetting"] = vignetting_fix_enabled;
2026-03-30 20:45:42 +02:00
pluginIniFile["2#Individual fix"]["Sharpening"] = sharpening_fix_enabled;
2026-03-22 17:23:49 +01:00
pluginIniFile["3#Fixes tuning"].setComment("Individual fix fine tune");
pluginIniFile["3#Fixes tuning"]["World FOV"] = worldFOVvalue;
2026-03-30 12:39:42 +02:00
pluginIniFile["3#Fixes tuning"]["HUD scaling"] = HUDvalue;
2026-03-22 22:52:31 +01:00
pluginIniFile["3#Fixes tuning"]["Camera distance"] = cameraDistancevalue;
2026-03-30 20:45:42 +02:00
pluginIniFile["3#Fixes tuning"]["Sharpening value"] = sharpeningvalue;
2026-03-22 17:23:49 +01:00
pluginIniFile.save(SETTINGS_FILE);
}
static void LoadSettings() {
ini::IniFile pluginIniFile;
try {
pluginIniFile.load(SETTINGS_FILE);
fix_enabled = pluginIniFile["1#General fix"]["Enabled"].as<bool>();
triggerDelayMs = pluginIniFile["1#General fix"]["TriggerDelayMs"].as<int>();
2026-03-22 17:23:49 +01:00
fov_fix_enabled = pluginIniFile["2#Individual fix"]["FOV"].as<bool>();
ultrawide_fix_enabled = pluginIniFile["2#Individual fix"]["UltraWide"].as<bool>();
2026-03-30 12:39:42 +02:00
HUD_fix_enabled = pluginIniFile["2#Individual fix"]["HUD"].as<bool>();
2026-03-22 22:52:31 +01:00
camera_fix_enabled = pluginIniFile["2#Individual fix"]["Camera"].as<bool>();
DOF_fix_enabled = pluginIniFile["2#Individual fix"]["DOF"].as<bool>();
vignetting_fix_enabled = pluginIniFile["2#Individual fix"]["Vignetting"].as<bool>();
2026-03-30 20:45:42 +02:00
sharpening_fix_enabled = pluginIniFile["2#Individual fix"]["Sharpening"].as<bool>();
2026-03-22 17:23:49 +01:00
worldFOVvalue = pluginIniFile["3#Fixes tuning"]["World FOV"].as<int>();
2026-03-30 12:39:42 +02:00
HUDvalue = pluginIniFile["3#Fixes tuning"]["HUD scaling"].as<int>();
2026-03-22 22:52:31 +01:00
cameraDistancevalue = pluginIniFile["3#Fixes tuning"]["Camera distance"].as<float>();
2026-03-30 20:45:42 +02:00
sharpeningvalue = pluginIniFile["3#Fixes tuning"]["Sharpening value"].as<float>();
2026-03-22 17:23:49 +01:00
}
catch (const std::exception& e) {}
}
// Read plugin log file
void read_log_file(const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open()) {
log_content = "Impossible to open file : " + filename;
return;
}
std::ostringstream ss;
ss << file.rdbuf();
log_content = ss.str();
}
// Initialize ImGui widgets for Reshade
static void on_overlay_draw(reshade::api::effect_runtime* runtime) {
ImGui::SetNextWindowSize(ImVec2(350 * scale, 150 * scale), ImGuiCond_Once);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.84f, 0.12f, 0.51f, 1.0f)); // pink
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.84f, 0.12f, 0.51f, 1.0f)); // pink
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.84f, 0.2f, 0.51f, 1.0f)); // pink
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 1.f, 1.f, 1.f)); // white
if (ImGui::Button("Like my work ? Consider donation")) ShellExecuteA(NULL, "open", DONATION_URL, NULL, NULL, SW_SHOWNORMAL); // Donation
ImGui::PopStyleColor(4); // Restore color
ImGui::SameLine();
if (ImGui::Button("Fix informations")) popup_Informations = true; // Fix information
ImGui::SameLine();
if (ImGui::Button("View logs")) {
read_log_file("DeathStranding2.log");
show_log_overlay = true; // Fix information
}
if (popup_Informations) {
ImGui::Begin("Informations", &popup_Informations, ImGuiWindowFlags_AlwaysAutoResize);
ImGui::Text("Version : %s", FIX_VERSION);
ImGui::Text(FIX_INFORMATIONS);
ImGui::End();
}
if (show_log_overlay) {
ImGui::Begin("Game log", &show_log_overlay, ImGuiWindowFlags_AlwaysAutoResize);
ImGui::TextUnformatted(log_content.c_str());
ImGui::End();
}
if (ImGui::BeginTabBar("MainTabs")) {
if (ImGui::BeginTabItem("Fixes")) {
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(10 * scale, 10 * scale));
if (ImGui::BeginTable("FixesTable", 2, ImGuiTableFlags_SizingStretchSame)) {
ImGui::TableSetupColumn("LeftFix", ImGuiTableColumnFlags_WidthStretch, 0.4f);
ImGui::TableSetupColumn("RightFix", ImGuiTableColumnFlags_WidthStretch, 0.6f);
ImGui::TableNextRow();
// Drawing a left column with slider and general fix
ImGui::TableSetColumnIndex(0);
if (ImGui::CollapsingHeader("Enable fixes", ImGuiTreeNodeFlags_DefaultOpen))
if (ImGui::Checkbox("Fix enabled", &fix_enabled)) {
if (SetFixEnabled) SetFixEnabled(fix_enabled, false);
SaveSettings();
}
// Individual fixes
ImGui::TableSetColumnIndex(1);
if (ImGui::CollapsingHeader("Individual fixes", ImGuiTreeNodeFlags_DefaultOpen)) {
if (ImGui::BeginTable("IndividualFixesTable", 2, ImGuiTableFlags_SizingStretchSame)) {
ImGui::TableSetupColumn("IndFix1", ImGuiTableColumnFlags_WidthStretch, 0.4f);
ImGui::TableSetupColumn("IndFix2", ImGuiTableColumnFlags_WidthStretch, 0.6f);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
2026-03-30 20:45:42 +02:00
for (int i = 0; i < 4; ++i) DrawFixCheckbox(individualFixes[i]);
ImGui::TableSetColumnIndex(1);
2026-03-30 20:45:42 +02:00
for (int i = 4; i < IM_ARRAYSIZE(individualFixes); ++i) DrawFixCheckbox(individualFixes[i]);
2026-03-22 17:23:49 +01:00
ImGui::EndTable();
}
}
ImGui::EndTable();
}
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 2);
if (ImGui::BeginTable("FixesSliders", 2, ImGuiTableFlags_SizingStretchSame)) {
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
2026-03-30 20:45:42 +02:00
for (int i = 0; i < 3; ++i) DrawSlider2(sliders[i], 200);
2026-03-22 22:52:31 +01:00
ImGui::TableSetColumnIndex(1);
2026-03-30 20:45:42 +02:00
for (int i = 3; i < 5; ++i) DrawSlider2(sliders[i], 200);
2026-03-22 17:23:49 +01:00
ImGui::EndTable();
}
ImGui::PopStyleVar();
ImGui::EndTabItem();
}
// Fix status
if (ImGui::CollapsingHeader("Fix informations", ImGuiTreeNodeFlags_DefaultOpen)) {
if (GetGameInfos) {
GameInfos infos{};
GetGameInfos(&infos);
ImGui::Text("Screen width: %d, height: %d, aspect ratio: %.2f", infos.screenWidth, infos.screenHeight, infos.aspectRatio);
ImGui::TextColored(ImColor(48, 179, 25), "FOV In: %.2f, Out: %.2f", infos.FOVIn, infos.FOVOut);
2026-03-22 22:52:31 +01:00
ImGui::TextColored(ImColor(48, 179, 25), "Camera distance In: %.2f, Out: %.2f", infos.cameraIn, infos.cameraOut);
2026-03-22 17:23:49 +01:00
}
}
}
ImGui::PopStyleVar();
}
static std::atomic<bool> g_Started{ false };
static std::atomic<bool> g_Done{ false };
static void on_present(reshade::api::command_queue* queue, reshade::api::swapchain* swapchain,
const reshade::api::rect*, const reshade::api::rect*, uint32_t, const reshade::api::rect*) {
if (!ultrawide_fix_enabled || g_Done || !SetFixes || g_Started.exchange(true)) return;
void* hwnd = swapchain->get_hwnd(); // Retrieve DX12 swapchain
HWND hwnd_local = reinterpret_cast<HWND>(hwnd);
bool exclusive = IsExclusiveFullscreen(swapchain); // Retrieve display mode (fullscreen or exclusive fullscreen)
SetFixes(GameFixes::UltraWide, ultrawide_fix_enabled);
SetFixes(GameFixes::None, false);
std::thread([hwnd_local, exclusive]() {
std::this_thread::sleep_for(std::chrono::milliseconds(DECIMA_ENGINE_INIT_DELAY)); // Wait for Decima engine to be ready
if (!exclusive) {
SimulateAltEnter(); // 1st Alt+Enter
std::this_thread::sleep_for(std::chrono::milliseconds(triggerDelayMs)); // Give enough time to swapchain rebuild
SimulateAltEnter(); // 2nd Alt+Enter
}
else {
SimulateAltTab(); // Simulate ALT+Tab
std::this_thread::sleep_for(std::chrono::milliseconds(triggerDelayMs));
ShowWindow(hwnd_local, SW_RESTORE); // Restore game window
}
g_Done = true;
}).detach();
}
2026-03-22 17:23:49 +01:00
// Main dll intrance
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
if (!reshade::register_addon(hinstDLL))
return FALSE;
LoadSettings();
reshade::register_overlay("Death Stranding 2: On The Beach", &on_overlay_draw);
reshade::register_event<reshade::addon_event::present>(&on_present);
2026-03-22 17:23:49 +01:00
reshade::register_event<reshade::addon_event::init_effect_runtime>(&LoadFixDLL);
break;
case DLL_PROCESS_DETACH:
reshade::unregister_overlay("Death Stranding 2: On The Beach", &on_overlay_draw);
reshade::unregister_event<reshade::addon_event::present>(&on_present);
2026-03-22 17:23:49 +01:00
reshade::unregister_event<reshade::addon_event::init_effect_runtime>(&LoadFixDLL);
reshade::unregister_addon(hinstDLL);
break;
}
return TRUE;
}