diff --git a/SilentPatch/Common.cpp b/SilentPatch/Common.cpp index af76978..790cc80 100644 --- a/SilentPatch/Common.cpp +++ b/SilentPatch/Common.cpp @@ -98,5 +98,10 @@ namespace Common { { DelayedPatches::Func = std::move(func); } + + void III_VC_DelayedCommon( bool /*hasDebugMenu*/, const wchar_t* /*iniPath*/ ) + { + + } } } \ No newline at end of file diff --git a/SilentPatch/Common.h b/SilentPatch/Common.h index 5a953cf..3640eaa 100644 --- a/SilentPatch/Common.h +++ b/SilentPatch/Common.h @@ -4,6 +4,7 @@ namespace Common { namespace Patches { + void III_VC_DelayedCommon( bool hasDebugMenu, const wchar_t* iniPath ); void III_VC_Common(); void III_VC_SetDelayedPatchesFunc( void(*func)() ); } diff --git a/SilentPatchIII/SilentPatchIII.cpp b/SilentPatchIII/SilentPatchIII.cpp index 3ef7f78..88ffc2a 100644 --- a/SilentPatchIII/SilentPatchIII.cpp +++ b/SilentPatchIII/SilentPatchIII.cpp @@ -7,6 +7,11 @@ #include "Common_ddraw.h" #include +#include + +#include "debugmenu_public.h" + +#pragma comment(lib, "shlwapi.lib") struct PsGlobalType { @@ -44,6 +49,10 @@ struct RwV2d float y; /**< Y value */ }; +DebugMenuAPI gDebugMenuAPI; + +static HMODULE hDLLModule; + static void (*DrawRect)(const CRect&,const CRGBA&); static void (*SetScale)(float,float); @@ -426,6 +435,68 @@ namespace KeyboardInputFix } } +namespace Localization +{ + static int8_t forcedUnits = -1; // 0 - metric, 1 - imperial + + bool IsMetric_LocaleBased() + { + if ( forcedUnits != -1 ) return forcedUnits == 0; + + unsigned int LCData; + if ( GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_IMEASURE|LOCALE_RETURN_NUMBER, reinterpret_cast(&LCData), sizeof(LCData) / sizeof(TCHAR) ) != 0 ) + { + return LCData == 0; + } + + // If fails, default to metric. Hopefully never fails though + return true; + } + + static void (__thiscall* orgUpdateCompareFlag_IsMetric)(void* pThis, uint8_t flag); + void __fastcall UpdateCompareFlag_IsMetric(void* pThis, void*, uint8_t) + { + std::invoke( orgUpdateCompareFlag_IsMetric, pThis, IsMetric_LocaleBased() ); + } + + uint32_t PrefsLanguage_IsMetric() + { + return IsMetric_LocaleBased(); + } +} + +void InjectDelayedPatches_III_Common( bool bHasDebugMenu, const wchar_t* wcModulePath ) +{ + // Locale based metric/imperial system INI/debug menu + { + using namespace Localization; + + forcedUnits = static_cast(GetPrivateProfileIntW(L"SilentPatch", L"Units", -1, wcModulePath)); + if ( bHasDebugMenu ) + { + static const char * const str[] = { "Default", "Metric", "Imperial" }; + DebugMenuEntry *e = DebugMenuAddVar( "SilentPatch", "Forced units", &forcedUnits, nullptr, 1, -1, 1, str ); + DebugMenuEntrySetWrap(e, true); + } + } +} + +void InjectDelayedPatches_III_Common() +{ + std::unique_ptr Protect = ScopedUnprotect::UnprotectSectionOrFullModule( GetModuleHandle( nullptr ), ".text" ); + + // Obtain a path to the ASI + wchar_t wcModulePath[MAX_PATH]; + GetModuleFileNameW(hDLLModule, wcModulePath, _countof(wcModulePath) - 3); // Minus max required space for extension + PathRenameExtensionW(wcModulePath, L".ini"); + + const bool hasDebugMenu = DebugMenuLoad(); + + InjectDelayedPatches_III_Common( hasDebugMenu, wcModulePath ); + + Common::Patches::III_VC_DelayedCommon( hasDebugMenu, wcModulePath ); +} + void Patch_III_10(const RECT& desktop) { @@ -953,6 +1024,32 @@ void Patch_III_Common() InjectHook( simButtonCheckers, ClearSimButtonPressCheckers ); InjectHook( updatePads.get( 10 ), jmpDest, PATCH_JUMP ); } + + + // Locale based metric/imperial system + { + using namespace Localization; + + void* updateCompareFlag = get_pattern( "89 E9 6A 00 E8 ? ? ? ? 30 C0 83 C4 70 5D 5E 5B C2 04 00", 4 ); + + ReadCall( updateCompareFlag, orgUpdateCompareFlag_IsMetric ); + InjectHook( updateCompareFlag, UpdateCompareFlag_IsMetric ); + + // Stats + auto constructStatLine = pattern( "FF 24 9D ? ? ? ? 39 D0" ).get_one(); + + // push eax + // push edx + // call IsMetric_LocaleBased + // movzx ebx, al + // pop edx + // pop eax + // nop... + Patch( constructStatLine.get( -0xF ), { 0x50, 0x52 } ); + InjectHook( constructStatLine.get( -0xF + 2 ), PrefsLanguage_IsMetric, PATCH_CALL ); + Patch( constructStatLine.get( -0xF + 7 ), { 0x0F, 0xB6, 0xD8, 0x5A, 0x58 } ); + Nop( constructStatLine.get( -0xF + 12 ), 3 ); + } } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) @@ -962,6 +1059,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) if ( fdwReason == DLL_PROCESS_ATTACH ) { + hDLLModule = hinstDLL; + RECT desktop; GetWindowRect(GetDesktopWindow(), &desktop); sprintf_s(aNoDesktopMode, "Cannot find %dx%dx32 video mode", desktop.right, desktop.bottom); @@ -978,6 +1077,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) Patch_III_Common(); Common::Patches::III_VC_Common(); Common::Patches::DDraw_Common(); + + Common::Patches::III_VC_SetDelayedPatchesFunc( InjectDelayedPatches_III_Common ); } Common::Patches::FixRwcseg_Patterns(); diff --git a/SilentPatchIII/SilentPatchIII.vcxproj b/SilentPatchIII/SilentPatchIII.vcxproj index cf3a4a4..7047177 100644 --- a/SilentPatchIII/SilentPatchIII.vcxproj +++ b/SilentPatchIII/SilentPatchIII.vcxproj @@ -42,6 +42,7 @@ + diff --git a/SilentPatchIII/SilentPatchIII.vcxproj.filters b/SilentPatchIII/SilentPatchIII.vcxproj.filters index 3358c79..3f02ae8 100644 --- a/SilentPatchIII/SilentPatchIII.vcxproj.filters +++ b/SilentPatchIII/SilentPatchIII.vcxproj.filters @@ -74,6 +74,9 @@ Header Files\Utils + + Header Files + diff --git a/SilentPatchVC/SilentPatchVC.cpp b/SilentPatchVC/SilentPatchVC.cpp index 74aec71..80d47ec 100644 --- a/SilentPatchVC/SilentPatchVC.cpp +++ b/SilentPatchVC/SilentPatchVC.cpp @@ -8,6 +8,11 @@ #include "ModelInfoVC.h" #include +#include + +#include "debugmenu_public.h" + +#pragma comment(lib, "shlwapi.lib") struct RsGlobalType { @@ -23,6 +28,10 @@ struct RsGlobalType void* pad; }; +DebugMenuAPI gDebugMenuAPI; + +static HMODULE hDLLModule; + static const void* RosieAudioFix_JumpBack; static void (*PrintString)(float,float,const wchar_t*); @@ -298,6 +307,68 @@ namespace KeyboardInputFix } } +namespace Localization +{ + static int8_t forcedUnits = -1; // 0 - metric, 1 - imperial + + bool IsMetric_LocaleBased() + { + if ( forcedUnits != -1 ) return forcedUnits == 0; + + unsigned int LCData; + if ( GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_IMEASURE|LOCALE_RETURN_NUMBER, reinterpret_cast(&LCData), sizeof(LCData) / sizeof(TCHAR) ) != 0 ) + { + return LCData == 0; + } + + // If fails, default to metric. Hopefully never fails though + return true; + } + + static void (__thiscall* orgUpdateCompareFlag_IsMetric)(void* pThis, uint8_t flag); + void __fastcall UpdateCompareFlag_IsMetric(void* pThis, void*, uint8_t) + { + std::invoke( orgUpdateCompareFlag_IsMetric, pThis, IsMetric_LocaleBased() ); + } + + uint32_t PrefsLanguage_IsMetric() + { + return IsMetric_LocaleBased(); + } +} + +void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModulePath ) +{ + // Locale based metric/imperial system INI/debug menu + { + using namespace Localization; + + forcedUnits = static_cast(GetPrivateProfileIntW(L"SilentPatch", L"Units", -1, wcModulePath)); + if ( bHasDebugMenu ) + { + static const char * const str[] = { "Default", "Metric", "Imperial" }; + DebugMenuEntry *e = DebugMenuAddVar( "SilentPatch", "Forced units", &forcedUnits, nullptr, 1, -1, 1, str ); + DebugMenuEntrySetWrap(e, true); + } + } +} + +void InjectDelayedPatches_VC_Common() +{ + std::unique_ptr Protect = ScopedUnprotect::UnprotectSectionOrFullModule( GetModuleHandle( nullptr ), ".text" ); + + // Obtain a path to the ASI + wchar_t wcModulePath[MAX_PATH]; + GetModuleFileNameW(hDLLModule, wcModulePath, _countof(wcModulePath) - 3); // Minus max required space for extension + PathRenameExtensionW(wcModulePath, L".ini"); + + const bool hasDebugMenu = DebugMenuLoad(); + + InjectDelayedPatches_VC_Common( hasDebugMenu, wcModulePath ); + + Common::Patches::III_VC_DelayedCommon( hasDebugMenu, wcModulePath ); +} + void Patch_VC_10(const RECT& desktop) { using namespace Memory; @@ -779,6 +850,24 @@ void Patch_VC_Common() InjectHook( updatePads.get( 9 ), jmpDest, PATCH_JUMP ); } + + // Locale based metric/imperial system + { + using namespace Localization; + + void* updateCompareFlag = get_pattern( "89 D9 6A 00 E8 ? ? ? ? 30 C0 83 C4 70 5D 5F 5E 5B C2 04 00", 4 ); + + ReadCall( updateCompareFlag, orgUpdateCompareFlag_IsMetric ); + InjectHook( updateCompareFlag, UpdateCompareFlag_IsMetric ); + + // Stats + auto constructStatLine = pattern( "85 C0 74 11 83 E8 01 83 F8 03" ).get_one(); + + Nop( constructStatLine.get( -11 ), 1 ); + InjectHook( constructStatLine.get( -11 + 1 ), PrefsLanguage_IsMetric, PATCH_CALL ); + Nop( constructStatLine.get( -2 ), 2 ); + } + } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) @@ -788,6 +877,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) if ( fdwReason == DLL_PROCESS_ATTACH ) { + hDLLModule = hinstDLL; + RECT desktop; GetWindowRect(GetDesktopWindow(), &desktop); sprintf_s(aNoDesktopMode, "Cannot find %dx%dx32 video mode", desktop.right, desktop.bottom); @@ -807,6 +898,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) Patch_VC_Common(); Common::Patches::III_VC_Common(); Common::Patches::DDraw_Common(); + + Common::Patches::III_VC_SetDelayedPatchesFunc( InjectDelayedPatches_VC_Common ); } Common::Patches::FixRwcseg_Patterns(); diff --git a/SilentPatchVC/SilentPatchVC.vcxproj b/SilentPatchVC/SilentPatchVC.vcxproj index 18b3770..fcf478e 100644 --- a/SilentPatchVC/SilentPatchVC.vcxproj +++ b/SilentPatchVC/SilentPatchVC.vcxproj @@ -172,6 +172,7 @@ + diff --git a/SilentPatchVC/SilentPatchVC.vcxproj.filters b/SilentPatchVC/SilentPatchVC.vcxproj.filters index a7419f1..70466a5 100644 --- a/SilentPatchVC/SilentPatchVC.vcxproj.filters +++ b/SilentPatchVC/SilentPatchVC.vcxproj.filters @@ -51,6 +51,9 @@ Header Files\Utils + + Header Files +