11#include "dllmain.h"
22#include "../../external/inih/ini.c"
3+ #include <stdio.h>
4+ #include <stdarg.h>
5+ #include <psapi.h>
36
47typedef struct {
58 float fps ;
@@ -8,6 +11,8 @@ typedef struct {
811 int ScreenHeight ;
912 int EnableCursorClip ;
1013 int CursorClipHotkey ;
14+ int EnableLogging ;
15+ int EnableBorderless ;
1116} config ;
1217config configFile ;
1318
@@ -25,7 +30,7 @@ static int handler(void *Settings, const char *section, const char *name, const
2530 config * modconfig = (config * )Settings ;
2631 if (MATCH ("Settings" , "fps" )) {
2732 modconfig -> fps = atof (value );
28- }
33+ }
2934 if (MATCH ("Settings" , "UseCustomScreenDimensions" )) {
3035 modconfig -> UseCustomScreenDimensions = atoi (value );
3136 } else if (MATCH ("Settings" , "ScreenWidth" )) {
@@ -36,57 +41,136 @@ static int handler(void *Settings, const char *section, const char *name, const
3641 modconfig -> EnableCursorClip = atoi (value );
3742 } else if (MATCH ("Settings" , "CursorClipHotkey" )) {
3843 modconfig -> CursorClipHotkey = strtol (value , NULL , 16 );
44+ } else if (MATCH ("Settings" , "EnableLogging" )) {
45+ modconfig -> EnableLogging = atoi (value );
46+ } else if (MATCH ("Settings" , "EnableBorderless" )) {
47+ modconfig -> EnableBorderless = atoi (value );
3948 } else
4049 return 0 ;
4150 return 1 ;
4251}
4352
4453float readFile () {
45- return ini_parse ("FPSconfig.ini" , handler , & configFile ) < 0 ? 1000 : configFile .fps ; // will set framerate limit to 1000 if the ini file is missing
54+ // Initialize config with default values
55+ configFile .EnableLogging = 0 ; // Default logging off
56+ configFile .fps = 1000 ; // Default FPS limit
57+ configFile .EnableBorderless = 1 ; // Default borderless enabled
58+
59+ // Parse INI file, which will override defaults if present
60+ if (ini_parse ("FPSconfig.ini" , handler , & configFile ) < 0 ) {
61+ return configFile .fps ; // Return default if file is missing
62+ }
63+ return configFile .fps ;
4664}
4765
48- void setFps (float rFPS ) {
66+ FILE * logFile = NULL ;
67+
68+ void log_init () {
69+ if (!configFile .EnableLogging ) return ;
70+ logFile = fopen ("DS3DebugFPS_log.txt" , "w" );
71+ if (logFile ) {
72+ fprintf (logFile , "[INFO] Log started\n" );
73+ fflush (logFile );
74+ }
75+ fclose (logFile );
76+ logFile = fopen ("DS3DebugFPS_log.txt" , "a" );
77+ }
78+ void log_close () {
79+ if (!configFile .EnableLogging ) return ;
80+ if (logFile ) fclose (logFile );
81+ }
82+ void log_print (const char * fmt , ...) {
83+ if (!configFile .EnableLogging || !logFile ) return ;
84+ va_list args ;
85+ va_start (args , fmt );
86+ vfprintf (logFile , fmt , args );
87+ fprintf (logFile , "\n" );
88+ fflush (logFile );
89+ va_end (args );
90+ }
4991
92+ void setFps (float rFPS ) {
93+ log_print ("[INFO] setFps called with rFPS = %f" , rFPS );
5094 // Find Process
5195 DWORD PID ;
5296 HWND hWnd = FindWindowA (NULL , "DARK SOULS III" );
97+ log_print ("[INFO] FindWindowA returned HWND = %p" , hWnd );
5398 GetWindowThreadProcessId (hWnd , & PID );
99+ log_print ("[INFO] GetWindowThreadProcessId returned PID = %lu" , PID );
54100 HANDLE pHandle = OpenProcess (PROCESS_ALL_ACCESS , FALSE, PID );
101+ log_print ("[INFO] OpenProcess returned HANDLE = %p" , pHandle );
55102
56103 // Skip Intros
57104 unsigned char SkipIntro [20 ] = {0x48 , 0x31 , 0xC0 , 0x48 , 0x89 , 0x02 , 0x49 , 0x89 , 0x04 , 0x24 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 };
58105 NtWriteVirtualMemory (pHandle , (LPVOID )0x140BF66AE , SkipIntro , 20 , 0 );
59106
60- // Borderless
61- if (configFile .UseCustomScreenDimensions != 1 ) {
62- final .right = GetSystemMetrics (SM_CXSCREEN );
63- final .bottom = GetSystemMetrics (SM_CYSCREEN );
64- } else {
65- final .right = configFile .ScreenWidth ;
66- final .bottom = configFile .ScreenHeight ;
107+ // Borderless window mode (if enabled)
108+ if (configFile .EnableBorderless ) {
109+ log_print ("[INFO] Applying borderless window mode" );
110+ if (configFile .UseCustomScreenDimensions != 1 ) {
111+ final .right = GetSystemMetrics (SM_CXSCREEN );
112+ final .bottom = GetSystemMetrics (SM_CYSCREEN );
113+ } else {
114+ final .right = configFile .ScreenWidth ;
115+ final .bottom = configFile .ScreenHeight ;
116+ }
117+ final .left = 0 ;
118+ final .top = 0 ;
119+ SetWindowLong (hWnd , GWL_STYLE , WS_POPUP | WS_VISIBLE );
120+ AdjustWindowRect (& final , GetWindowLong (hWnd , GWL_STYLE ), FALSE);
121+ SetWindowLong (hWnd , GWL_EXSTYLE , (GetWindowLong (hWnd , GWL_EXSTYLE ) | WS_EX_TOPMOST ));
122+ MoveWindow (hWnd , final .left , final .top , final .right - final .left , final .bottom - final .top , TRUE);
123+ log_print ("[INFO] Borderless window mode applied successfully" );
67124 }
68- final .left = 0 ;
69- final .top = 0 ;
70- SetWindowLong (hWnd , GWL_STYLE , WS_POPUP | WS_VISIBLE );
71- AdjustWindowRect (& final , GetWindowLong (hWnd , GWL_STYLE ), FALSE);
72- SetWindowLong (hWnd , GWL_EXSTYLE , (GetWindowLong (hWnd , GWL_EXSTYLE ) | WS_EX_TOPMOST ));
73- MoveWindow (hWnd , final .left , final .top , final .right - final .left , final .bottom - final .top , TRUE);
74-
75- SprjFlipper = (DWORD64 )GetModuleHandle ("darksoulsiii.exe" ) + 0x489DD10 ;
76125
77- // GRAPHICS -> GFX
78- NtReadVirtualMemory ( pHandle , ( LPVOID ) SprjFlipper , & SprjFlipper , sizeof ( SprjFlipper ), NULL );
126+ HMODULE hModule = GetModuleHandleA ( "darksoulsiii.exe" );
127+ log_print ( "[SCAN] Module base address: 0x%p" , hModule );
79128
80- // Debug FPS | デバッグFPS
81- NtWriteVirtualMemory (pHandle , (LPVOID )(SprjFlipper + 0x354 ), & rFPS , sizeof (DWORD ), NULL );
129+ BYTE sprjFlipperPattern1 [] = { 0x50 , 0x60 , 0x3E , 0x08 , 0xF4 , 0x7F , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
130+ BYTE sprjFlipperPattern2 [] = { 0x50 , 0x60 , 0x3E , 0x08 , 0xF3 , 0x7F , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
131+ const char * sprjFlipperMask = "xx??xxxxxxxxxxxx" ;
82132
83- // Use Debug FPS | デバッグFPSを利用するか
84- NtWriteVirtualMemory (pHandle , (LPVOID )(SprjFlipper + 0x358 ), & useDebug , sizeof (char ), NULL );
133+ HMODULE scanModule = GetModuleHandleA ("darksoulsiii.exe" );
134+ MODULEINFO moduleInfo ;
135+ if (GetModuleInformation (pHandle , scanModule , & moduleInfo , sizeof (moduleInfo ))) {
136+ BYTE * moduleBase = (BYTE * )moduleInfo .lpBaseOfDll ;
137+ DWORD moduleSize = moduleInfo .SizeOfImage ;
138+ size_t patternLen = strlen (sprjFlipperMask );
139+ int foundCount = 0 ;
140+ for (DWORD i = 0 ; i <= moduleSize - patternLen ; ++ i ) {
141+ BOOL found1 = TRUE, found2 = TRUE;
142+ for (size_t j = 0 ; j < patternLen ; ++ j ) {
143+ if (sprjFlipperMask [j ] == 'x' ) {
144+ if (sprjFlipperPattern1 [j ] != moduleBase [i + j ]) found1 = FALSE;
145+ if (sprjFlipperPattern2 [j ] != moduleBase [i + j ]) found2 = FALSE;
146+ }
147+ }
148+ if (found1 || found2 ) {
149+ foundCount ++ ;
150+ DWORD64 matchAddr = (DWORD64 )(moduleBase + i );
151+ log_print ("[SCAN] Pattern %s match at: 0x%llx" , found1 ? "F4" : "F3" , matchAddr );
152+ DWORD64 realSprjFlipper = 0 ;
153+ NtReadVirtualMemory (pHandle , (LPVOID )matchAddr , & realSprjFlipper , sizeof (realSprjFlipper ), NULL );
154+ log_print ("[PATCH] Read pointer at match: 0x%llx" , realSprjFlipper );
155+ NtWriteVirtualMemory (pHandle , (LPVOID )(realSprjFlipper + 0x354 ), & rFPS , sizeof (DWORD ), NULL );
156+ log_print ("[PATCH] Patched rFPS at: 0x%llx" , realSprjFlipper + 0x354 );
157+ NtWriteVirtualMemory (pHandle , (LPVOID )(realSprjFlipper + 0x358 ), & useDebug , sizeof (char ), NULL );
158+ log_print ("[PATCH] Patched useDebug at: 0x%llx" , realSprjFlipper + 0x358 );
159+ break ;
160+ }
161+ }
162+ if (foundCount == 0 ) {
163+ log_print ("[SCAN] No matching patterns found in module." );
164+ } else {
165+ log_print ("[SCAN] Successfully patched FPS and useDebug values." );
166+ }
167+ } else {
168+ log_print ("[SCAN] Failed to get module information for scan." );
169+ }
85170
86171 if (configFile .EnableCursorClip != 0 ) {
87-
88- // createthread for an asynchronous loop
89172 HANDLE thread = CreateThread (NULL , 0 , (void * )containCursor , & hWnd , 0 , NULL );
173+ log_print ("[INFO] Cursor clip thread created." );
90174 }
91175}
92176
@@ -99,6 +183,8 @@ BOOL WINAPI DllMain(HINSTANCE baseaddr, DWORD reason, BOOL isstatic) {
99183 while (BaseFileName -- > FullFilePath )
100184 if (* BaseFileName == L'\\' )
101185 break ;
186+ readFile ();
187+ log_init ();
102188 case DLL_THREAD_ATTACH :
103189 break ;
104190 }
@@ -131,3 +217,6 @@ importD3D(FARPROC D3DAssemble_, DebugSetMute_, D3DCompile_, D3DCompressShaders_,
131217 setFps (readFile ());
132218 }
133219}
220+
221+ // Dummy atexit implementation for -nostartfiles builds
222+ int atexit (void (* func )(void )) { return 0 ; }
0 commit comments