@@ -40,6 +40,7 @@ namespace {
4040 using WidgetProxyBindFn = void (__thiscall*)(void *, void *);
4141 using WidgetProxySetVisibleFn = void (__thiscall*)(void *, bool );
4242 using WidgetProxySetEnabledFn = void (__thiscall*)(void *, bool );
43+ using WidgetProxySetTextHAlignFn = void (__thiscall*)(void *, int , const char *);
4344 using TextLabelCtorFn = void (__thiscall*)(void *);
4445 using TextLabelDtorFn = void (__thiscall*)(void *);
4546 using TextLabelSetTextFn = void (__thiscall*)(void *, const void *);
@@ -77,6 +78,7 @@ namespace {
7778 constexpr char kWidgetProxyBindExportName [] = " ?Bind@WidgetProxy@UI@@IAEXPAVWidget@2@@Z" ;
7879 constexpr char kWidgetProxySetVisibleExportName [] = " ?SetVisible@WidgetProxy@UI@@UAEX_N@Z" ;
7980 constexpr char kWidgetProxySetEnabledExportName [] = " ?SetEnabled@WidgetProxy@UI@@UAEX_N@Z" ;
81+ constexpr char kWidgetProxySetTextHAlignExportName [] = " ?SetTextHAlign@WidgetProxy@UI@@QAEXW4HAlign@RenderProxy@@PBD@Z" ;
8082 constexpr char kTextLabelCtorExportName [] = " ??0TextLabel@UI@@QAE@XZ" ;
8183 constexpr char kTextLabelDtorExportName [] = " ??1TextLabel@UI@@UAE@XZ" ;
8284 constexpr char kTextLabelSetTextExportName [] = " ?SetText@TextLabel@UI@@QAEXABVLocString@@@Z" ;
@@ -102,11 +104,13 @@ namespace {
102104 constexpr char kTextLabelWidgetTypeName [] = " TextLabel" ;
103105 constexpr char kTimerPresentationDonorName [] = " txtInfo" ;
104106
105- constexpr float kTimerLabelPositionX = 0 .30260f ;
106- constexpr float kTimerLabelPositionY = 0 . 00000f ;
107- constexpr float kTimerLabelSizeX = 0 .39480f ;
107+ constexpr float kTimerLabelPositionX = 0 .47500f ;
108+ constexpr float kTimerLabelPositionY = - 0 . 02000f ;
109+ constexpr float kTimerLabelSizeX = 0 .14000f ;
108110 constexpr float kTimerLabelSizeY = 0 .12600f ;
109111
112+ constexpr int kRenderProxyHAlignLeft = 0 ;
113+
110114 constexpr std::size_t kOpaqueTextLabelStorageSize = 8192u ;
111115 constexpr std::size_t kLocStringStorageSize = 256u ;
112116
@@ -128,6 +132,7 @@ namespace {
128132 WidgetProxyBindFn g_widgetProxyBind = nullptr ;
129133 WidgetProxySetVisibleFn g_widgetProxySetVisible = nullptr ;
130134 WidgetProxySetEnabledFn g_widgetProxySetEnabled = nullptr ;
135+ WidgetProxySetTextHAlignFn g_widgetProxySetTextHAlign = nullptr ;
131136 TextLabelCtorFn g_textLabelCtor = nullptr ;
132137 TextLabelDtorFn g_textLabelDtor = nullptr ;
133138 TextLabelSetTextFn g_textLabelSetText = nullptr ;
@@ -170,18 +175,9 @@ namespace {
170175 bool g_lastUiLabelVisible = false ;
171176 bool g_uiLabelTextInitialized = false ;
172177
173- template <typename T>
174- T ResolveExport (HMODULE module , const char * exportName) {
175- if ((module == nullptr ) || (exportName == nullptr )) {
176- return nullptr ;
177- }
178-
179- return reinterpret_cast <T>(GetProcAddress (module , exportName));
180- }
181-
182178 template <typename T>
183179 bool ResolveRequiredExport (HMODULE module , const char * moduleName, const char * exportName, T& outFunction) {
184- outFunction = ResolveExport<T>(module , exportName);
180+ outFunction = ModSDK::Memory:: ResolveExport<T>(module , exportName);
185181 if (outFunction != nullptr ) {
186182 return true ;
187183 }
@@ -226,7 +222,7 @@ namespace {
226222 }
227223
228224 bool InstallExportHook (HMODULE module , const char * exportName, void * detour, void ** originalFunction, const char * hookDisplayName) {
229- void * target = ResolveExport<void *>(module , exportName);
225+ void * target = ModSDK::Memory:: ResolveExport<void *>(module , exportName);
230226 if (target == nullptr ) {
231227 char message[256 ] = {};
232228 std::snprintf (message, sizeof (message), " Match Timer failed to resolve %s" , hookDisplayName);
@@ -268,7 +264,7 @@ namespace {
268264 if (milliseconds > 0u ) {
269265 char message[96 ] = {};
270266 std::snprintf (message, sizeof (message), " Match Timer captured game time %.3f seconds" , gameTimeSeconds);
271- LogOnce (g_loggedTimeCapture, CoHModSDKLogLevel_Info , message);
267+ LogOnce (g_loggedTimeCapture, CoHModSDKLogLevel_Debug , message);
272268 }
273269 }
274270 }
@@ -342,7 +338,7 @@ namespace {
342338 ZeroWidgetField (g_timerLabelRaw, hitAreaOffset);
343339 LogOnce (
344340 g_loggedTimerLabelDetach,
345- CoHModSDKLogLevel_Info ,
341+ CoHModSDKLogLevel_Debug ,
346342 " Match Timer detached shared presentation state from the native Taskbar timer label before unload"
347343 );
348344 }
@@ -393,7 +389,6 @@ namespace {
393389 }
394390
395391 void * widget = nullptr ;
396- #if defined(_M_IX86)
397392 void * createFunction = g_widgetFactoryCreateAddress;
398393 __asm {
399394 mov edi, widgetTypeName
@@ -402,9 +397,6 @@ namespace {
402397 call eax
403398 mov widget, eax
404399 }
405- #else
406- (void )widgetTypeName;
407- #endif
408400 return widget;
409401 }
410402
@@ -438,7 +430,6 @@ namespace {
438430 return false ;
439431 }
440432
441- #if defined(_M_IX86)
442433 void * addRenderChildFunction = g_addRenderChildAddress;
443434 __asm {
444435 mov edi, parentRenderObject
@@ -448,12 +439,6 @@ namespace {
448439 call eax
449440 }
450441 return true ;
451- #else
452- (void )parentRenderObject;
453- (void )childWidget;
454- (void )insertionIndex;
455- return false ;
456- #endif
457442 }
458443
459444 bool AttachRenderChild (void * parentWidget, void * childWidget) {
@@ -554,6 +539,11 @@ namespace {
554539 g_textLabelSetMultiline (g_timerLabelProxyStorage.data (), false );
555540 }
556541
542+ if (g_widgetProxySetTextHAlign != nullptr ) {
543+ // Anchor the changing digits against the right edge of the fixed label box.
544+ g_widgetProxySetTextHAlign (g_timerLabelProxyStorage.data (), kRenderProxyHAlignLeft , nullptr );
545+ }
546+
557547 ApplyTimerLabelVisibility (false );
558548 LogOnce (g_loggedTimerLabelBound, CoHModSDKLogLevel_Info, " Match Timer bound the native Taskbar timer label" );
559549 return true ;
@@ -690,7 +680,7 @@ namespace {
690680 g_uiLabelTextInitialized = true ;
691681 g_lastUiLabelVisible = true ;
692682 g_lastUiLabelSeconds = totalSeconds;
693- LogOnce (g_loggedTimerLabelUpdated, CoHModSDKLogLevel_Info , " Match Timer updated the native Taskbar timer label" );
683+ LogOnce (g_loggedTimerLabelUpdated, CoHModSDKLogLevel_Debug , " Match Timer updated the native Taskbar timer label" );
694684 }
695685
696686 void __fastcall HookedWorldSimulate (void * world, void *) {
@@ -708,7 +698,6 @@ namespace {
708698 g_matchActive.store (true , std::memory_order_relaxed);
709699 g_gameOver.store (false , std::memory_order_relaxed);
710700 RefreshCachedMatchTime (simManager);
711- LogOnce (g_loggedWorldSimulate, CoHModSDKLogLevel_Info, " Match Timer World::Simulate hook is active" );
712701 }
713702
714703 void __fastcall HookedClearGameTicks (void * simManager, void *) {
@@ -728,8 +717,6 @@ namespace {
728717 }
729718
730719 void __fastcall HookedScreenManagerDraw (void * screenManager, void *, float deltaSeconds) {
731- LogOnce (g_loggedUiDrawHook, CoHModSDKLogLevel_Info, " Match Timer UI::ScreenManager::Draw hook is active" );
732-
733720 const bool shouldShow = ShouldShowTimer ();
734721 if (EnsureTaskbarTimerLabel (screenManager)) {
735722 ApplyTimerLabelVisibility (shouldShow);
@@ -779,8 +766,8 @@ namespace {
779766 return ShowAndLogError (" Match Timer failed to load SimEngine.dll" );
780767 }
781768
782- g_getGameTime = ResolveExport<SimManagerGetGameTimeFn>(simEngineModule, kGetGameTimeExportName );
783- g_getWorldSimManager = ResolveExport<WorldGetSimManagerFn>(simEngineModule, kWorldGetSimManagerExportName );
769+ g_getGameTime = ModSDK::Memory:: ResolveExport<SimManagerGetGameTimeFn>(simEngineModule, kGetGameTimeExportName );
770+ g_getWorldSimManager = ModSDK::Memory:: ResolveExport<WorldGetSimManagerFn>(simEngineModule, kWorldGetSimManagerExportName );
784771 if ((g_getGameTime == nullptr ) || (g_getWorldSimManager == nullptr )) {
785772 return ShowAndLogError (" Match Timer failed to resolve SimManager timer exports" );
786773 }
@@ -812,7 +799,6 @@ namespace {
812799 return false ;
813800 }
814801
815- ModSDK::Runtime::LogInfo (" Match Timer hooked SimEngine timer exports" );
816802 return true ;
817803 }
818804
@@ -839,6 +825,7 @@ namespace {
839825 ResolveRequiredExport (userInterfaceModule, kUserInterfaceModuleName , kWidgetProxyBindExportName , g_widgetProxyBind) &&
840826 ResolveRequiredExport (userInterfaceModule, kUserInterfaceModuleName , kWidgetProxySetVisibleExportName , g_widgetProxySetVisible) &&
841827 ResolveRequiredExport (userInterfaceModule, kUserInterfaceModuleName , kWidgetProxySetEnabledExportName , g_widgetProxySetEnabled) &&
828+ ResolveRequiredExport (userInterfaceModule, kUserInterfaceModuleName , kWidgetProxySetTextHAlignExportName , g_widgetProxySetTextHAlign) &&
842829 ResolveRequiredExport (userInterfaceModule, kUserInterfaceModuleName , kTextLabelCtorExportName , g_textLabelCtor) &&
843830 ResolveRequiredExport (userInterfaceModule, kUserInterfaceModuleName , kTextLabelDtorExportName , g_textLabelDtor) &&
844831 ResolveRequiredExport (userInterfaceModule, kUserInterfaceModuleName , kTextLabelSetTextExportName , g_textLabelSetText) &&
@@ -851,8 +838,8 @@ namespace {
851838 return false ;
852839 }
853840
854- g_textLabelSetAutoSize = ResolveExport<TextLabelSetAutoSizeFn>(userInterfaceModule, kTextLabelSetAutoSizeExportName );
855- g_textLabelSetMultiline = ResolveExport<TextLabelSetMultilineFn>(userInterfaceModule, kTextLabelSetMultilineExportName );
841+ g_textLabelSetAutoSize = ModSDK::Memory:: ResolveExport<TextLabelSetAutoSizeFn>(userInterfaceModule, kTextLabelSetAutoSizeExportName );
842+ g_textLabelSetMultiline = ModSDK::Memory:: ResolveExport<TextLabelSetMultilineFn>(userInterfaceModule, kTextLabelSetMultilineExportName );
856843
857844 const std::uintptr_t userInterfaceBase = reinterpret_cast <std::uintptr_t >(userInterfaceModule);
858845 g_widgetFactoryCreateAddress = reinterpret_cast <void *>(userInterfaceBase + kWidgetFactoryCreateRva );
@@ -887,7 +874,6 @@ namespace {
887874 return false ;
888875 }
889876
890- LogOnce (g_loggedUiHooksInstalled, CoHModSDKLogLevel_Info, " Match Timer hooked UI::ScreenManager::Draw for a native Taskbar timer" );
891877 return true ;
892878 }
893879
0 commit comments