5
5
#define _WIN32_WINNT 0x0601
6
6
7
7
#include < windows.h>
8
+ #include " Utils/HookEach.hpp"
8
9
#include " Utils/MemoryMgr.h"
9
10
#include " Utils/Trampoline.h"
10
11
#include " Utils/Patterns.h"
@@ -27,22 +28,36 @@ namespace ForcedMinigameFPS
27
28
}
28
29
}
29
30
30
- static void (*orgSetMinigameFPSCap)(int cap);
31
-
32
31
template <bool force>
33
- static void SetMinigameFPSCap_ForcedFPS ( int cap )
32
+ struct MinigameFPSCap
34
33
{
35
- orgSetMinigameFPSCap ( cap );
36
- if constexpr ( force )
34
+ template <std::size_t Index>
35
+ static inline void (*orgSetMinigameFPSCap)(int cap);
36
+
37
+ static void ToggleFPSCap ()
37
38
{
38
- userFPSCap_ForMinigame = 0 ;
39
+ if constexpr (force)
40
+ {
41
+ userFPSCap_ForMinigame = 0 ;
42
+ }
43
+ else
44
+ {
45
+ userFPSCap_ForMinigame = userFPSCap;
46
+ }
47
+ minigameFPSForced = force;
39
48
}
40
- else
49
+
50
+ template <std::size_t Index>
51
+ static void SetMinigameFPSCap_ForcedFPS ( int cap )
41
52
{
42
- userFPSCap_ForMinigame = userFPSCap;
53
+ orgSetMinigameFPSCap<Index>( cap );
54
+ ToggleFPSCap ();
43
55
}
44
- minigameFPSForced = force;
45
- }
56
+
57
+ HOOK_EACH_INIT_CTR (M2, 0 , orgSetMinigameFPSCap, SetMinigameFPSCap_ForcedFPS);
58
+ HOOK_EACH_INIT_CTR (VF5, 1 , orgSetMinigameFPSCap, SetMinigameFPSCap_ForcedFPS);
59
+ HOOK_EACH_INIT_CTR (Karaoke, 2 , orgSetMinigameFPSCap, SetMinigameFPSCap_ForcedFPS);
60
+ };
46
61
};
47
62
48
63
@@ -51,118 +66,197 @@ void OnInitializeHook()
51
66
std::unique_ptr<ScopedUnprotect::Unprotect> Protect = ScopedUnprotect::UnprotectSectionOrFullModule ( GetModuleHandle ( nullptr ), " .text" );
52
67
53
68
using namespace Memory ;
54
- using namespace hook ;
69
+ using namespace hook ::txn ;
55
70
56
71
57
72
// Make frame limiter busy loop so it's more accurate
73
+ try
58
74
{
59
75
auto oneUsCompare = get_pattern ( " 48 2B C8 48 81 F9 E8 03 00 00" , 10 );
60
76
Patch<uint8_t >( oneUsCompare, 0xEB ); // jl -> jmp
61
77
}
78
+ TXN_CATCH ();
62
79
63
80
64
81
// Uncap minigames which did not need to be capped
82
+
83
+ // Mahjong
84
+ try
65
85
{
66
- void * noppedFpsCalls[] = {
67
- // Mahjong
68
- get_pattern ( " 8D 48 3C E8 ? ? ? ? 33 C9" , 3 ),
69
- get_pattern ( " E8 ? ? ? ? 90 49 8B CE 4C 8D 5C 24 ? 49 8B 5B 30" ),
70
-
71
- // Oicho Kabu
72
- get_pattern ( " B9 ? ? ? ? E8 ? ? ? ? 33 C0 48 89 83 00 07 00 00" , 5 ),
73
- get_pattern ( " E8 ? ? ? ? 90 89 2D" ),
74
-
75
- // Cee-lo/chinchiro
76
- get_pattern ( " E8 ? ? ? ? 90 48 8B 8B ? ? ? ? 48 85 C9 74 16" ),
77
- get_pattern ( " B9 ? ? ? ? E8 ? ? ? ? 90 48 8D 4C 24 48" , 5 ),
78
-
79
- // Tougijyo (Colliseum) menu
80
- get_pattern ( " 8D 4B 3C E8 ? ? ? ? 48 8D 05" , 3 ),
81
- get_pattern ( " 33 C9 E8 ? ? ? ? 90 33 D2" , 2 ),
82
-
83
- // Batting center
84
- get_pattern ( " 8D 4D 3C E8 ? ? ? ? 49 8B 46 28" , 3 ),
85
- get_pattern ( " 33 C9 E8 ? ? ? ? 48 8B 87 B0 00 00 00" , 2 ),
86
- get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8B CB 48 8B 5C 24 78" , 2 ),
87
-
88
- // Blackjack
89
- get_pattern ( " 8D 4B 3C E8 ? ? ? ? 48 8B CF" , 3 ),
90
- // The other one is below
91
-
92
- // Poker
93
- get_pattern ( " 8D 4B 3C E8 ? ? ? ? B9 40 01 00 00" , 3 ),
94
- // The other one is below
95
-
96
- // Hanafuda/Koi-Koi
97
- get_pattern ( " 8D 4E 3C E8 ? ? ? ? 89 B3 80 00 00 00" , 3 ),
98
- get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8B 5C 24 68" , 2 ),
99
-
100
- // Unknown baseball game
101
- get_pattern ( " 8D 4B 3C E8 ? ? ? ? 48 8B 46 28" , 3 ),
102
- get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8B 43 28" , 2 ),
103
-
104
- // Unknown baseball game #2
105
- get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8D 93 1C 03 00 00" , 2 ),
106
- get_pattern ( " 48 89 91 50 03 00 00 B9 ? ? ? ? E8 ?" , 12 ),
107
-
108
- // Darts
109
- get_pattern ( " B9 ? ? ? ? E8 ? ? ? ? 48 8D 05 ? ? ? ? 48 89 44 24 58" , 5 ),
110
- get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8D 8E 30 08 00 00" , 2 )
111
- };
112
-
113
- for ( void * addr : noppedFpsCalls )
114
- {
115
- Nop ( addr, 5 );
116
- }
86
+ auto ctor = get_pattern ( " 8D 48 3C E8 ? ? ? ? 33 C9" , 3 );
87
+ auto dtor = get_pattern ( " E8 ? ? ? ? 90 49 8B CE 4C 8D 5C 24 ? 49 8B 5B 30" );
88
+
89
+ Nop (ctor, 5 );
90
+ Nop (dtor, 5 );
91
+ }
92
+ TXN_CATCH ();
93
+
94
+ // Oicho Kabu
95
+ try
96
+ {
97
+ auto ctor = get_pattern ( " B9 ? ? ? ? E8 ? ? ? ? 33 C0 48 89 83 00 07 00 00" , 5 );
98
+ auto dtor = get_pattern ( " E8 ? ? ? ? 90 89 2D" );
99
+
100
+ Nop (ctor, 5 );
101
+ Nop (dtor, 5 );
102
+ }
103
+ TXN_CATCH ();
104
+
105
+ // Cee-lo/chinchiro
106
+ try
107
+ {
108
+ auto ctor = get_pattern ( " E8 ? ? ? ? 90 48 8B 8B ? ? ? ? 48 85 C9 74 16" );
109
+ auto dtor = get_pattern ( " B9 ? ? ? ? E8 ? ? ? ? 90 48 8D 4C 24 48" , 5 );
110
+
111
+ Nop (ctor, 5 );
112
+ Nop (dtor, 5 );
113
+ }
114
+ TXN_CATCH ();
115
+
116
+ // Tougijyo (Colliseum) menu
117
+ try
118
+ {
119
+ auto ctor = get_pattern ( " 8D 4B 3C E8 ? ? ? ? 48 8D 05" , 3 );
120
+ auto dtor = get_pattern ( " 33 C9 E8 ? ? ? ? 90 33 D2" , 2 );
121
+
122
+ Nop (ctor, 5 );
123
+ Nop (dtor, 5 );
124
+ }
125
+ TXN_CATCH ();
126
+
127
+ // Batting center
128
+ try
129
+ {
130
+ auto ctor1 = get_pattern ( " 8D 4D 3C E8 ? ? ? ? 49 8B 46 28" , 3 );
131
+ auto ctor2 = get_pattern ( " 33 C9 E8 ? ? ? ? 48 8B 87 B0 00 00 00" , 2 );
132
+ auto dtor = get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8B CB 48 8B 5C 24 78" , 2 );
133
+
134
+ Nop (ctor1, 5 );
135
+ Nop (ctor2, 5 );
136
+ Nop (dtor, 5 );
137
+ }
138
+ TXN_CATCH ();
117
139
118
- // Blackjack and poker dtors
119
- pattern ( " 33 C9 E8 ? ? ? ? 90 48 8B CB 48 8B 5C 24 40" ).count (2 ).for_each_result ( [] ( pattern_match match ) {
140
+ // Poker & Blackjack
141
+ try
142
+ {
143
+ auto blackjack_ctor = get_pattern ( " 8D 4B 3C E8 ? ? ? ? 48 8B CF" , 3 );
144
+ auto poker_ctor = get_pattern ( " 8D 4B 3C E8 ? ? ? ? B9 40 01 00 00" , 3 );
145
+ auto dtors = pattern ( " 33 C9 E8 ? ? ? ? 90 48 8B CB 48 8B 5C 24 40" ).count (2 );
146
+
147
+ Nop (blackjack_ctor, 5 );
148
+ Nop (poker_ctor, 5 );
149
+
150
+ dtors.for_each_result ( [] ( pattern_match match ) {
120
151
Nop ( match.get <void >( 2 ), 5 );
121
152
} );
122
153
}
154
+ TXN_CATCH ();
155
+
156
+ // Hanafuda/Koi-Koi
157
+ try
158
+ {
159
+ auto ctor = get_pattern ( " 8D 4E 3C E8 ? ? ? ? 89 B3 80 00 00 00" , 3 );
160
+ auto dtor = get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8B 5C 24 68" , 2 );
161
+
162
+ Nop (ctor, 5 );
163
+ Nop (dtor, 5 );
164
+ }
165
+ TXN_CATCH ();
166
+
167
+ // Unknown baseball game
168
+ try
169
+ {
170
+ auto ctor = get_pattern ( " 8D 4B 3C E8 ? ? ? ? 48 8B 46 28" , 3 );
171
+ auto dtor = get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8B 43 28" , 2 );
172
+
173
+ Nop (ctor, 5 );
174
+ Nop (dtor, 5 );
175
+ }
176
+ TXN_CATCH ();
177
+
178
+ // Unknown baseball game #2
179
+ try
180
+ {
181
+ auto ctor = get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8D 93 1C 03 00 00" , 2 );
182
+ auto dtor = get_pattern ( " 48 89 91 50 03 00 00 B9 ? ? ? ? E8" , 12 );
183
+
184
+ Nop (ctor, 5 );
185
+ Nop (dtor, 5 );
186
+ }
187
+ TXN_CATCH ();
188
+
189
+ // Darts
190
+ try
191
+ {
192
+ auto ctor = get_pattern ( " B9 ? ? ? ? E8 ? ? ? ? 48 8D 05 ? ? ? ? 48 89 44 24 58" , 5 );
193
+ auto dtor = get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8D 8E 30 08 00 00" , 2 );
194
+
195
+ Nop (ctor, 5 );
196
+ Nop (dtor, 5 );
197
+ }
198
+ TXN_CATCH ();
123
199
124
200
125
201
// Cap Toylets to 30FPS
202
+ try
126
203
{
127
204
auto toyletsFpsCap = get_pattern ( " B9 ? ? ? ? E8 ? ? ? ? B9 07 00 00 00" , 1 );
128
205
Patch<int32_t >( toyletsFpsCap, 30 );
129
206
}
207
+ TXN_CATCH ();
130
208
131
209
132
210
// Force 60FPS cap on arcade games even if 30FPS is selected in options
211
+ try
133
212
{
134
213
using namespace ForcedMinigameFPS ;
135
214
136
215
Trampoline* trampoline = Trampoline::MakeTrampoline ( GetModuleHandle ( nullptr ) );
137
216
138
- auto enableCapTrampoline = trampoline->Jump (SetMinigameFPSCap_ForcedFPS<true >);
139
- auto disableCapTrampoline = trampoline->Jump (SetMinigameFPSCap_ForcedFPS<false >);
140
-
141
217
auto setFPSCap = get_pattern ( " EB 02 33 C9 E8 ? ? ? ? 4C 8B 05" , 4 );
142
218
auto tickUserFPSCheck = get_pattern ( " 48 8B 15 ? ? ? ? 85 D2" , 3 );
143
219
144
- auto enableArcadeFPSCap_m2 = get_pattern ( " E8 ? ? ? ? 44 88 64 24 40" );
145
- auto disableArcadeFPSCap_m2 = get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8D 8B 00 03 00 00" , 2 );
220
+ auto TrampolineInterceptCall = [trampoline](auto address, auto && func, auto && hook)
221
+ {
222
+ InterceptCall (address, func, trampoline->Jump (hook));
223
+ };
146
224
147
- auto enableArcadeFPSCap_vf5 = get_pattern ( " 41 8D 4E 3C E8 " , 4 );
148
- auto disableArcadeFPSCap_vf5 = get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8B 8B 10 03 00 00 " , 2 );
225
+ TrampolineInterceptCall (setFPSCap, orgSetUserFPSCap, SetUserFPSCap_ForcedFPS );
226
+ WriteOffsetValue (tickUserFPSCheck, &userFPSCap_ForMinigame); // This comes from the Trampoline memory!
149
227
150
- auto enableFPSCap_Karaoke = get_pattern ( " 41 8D 4C 24 3C E8 ? ? ? ? B2 01" , 5 );
151
- auto disableFPSCap_Karaoke = get_pattern ( " 33 C9 E8 ? ? ? ? 90 41 B8 ? ? ? ? 48 8D 54 24 ? 48 8B CB E8 ? ? ? ? 90 4C 8B C0" , 2 );
228
+ // M2 games
229
+ try
230
+ {
231
+ std::array<void *, 1 > enableCap { get_pattern ( " E8 ? ? ? ? 44 88 64 24 40" ) };
232
+ std::array<void *, 1 > disableCap { get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8D 8B 00 03 00 00" , 2 ) };
152
233
153
- ReadCall ( setFPSCap, orgSetUserFPSCap );
154
- InjectHook ( setFPSCap, trampoline->Jump (SetUserFPSCap_ForcedFPS) );
234
+ MinigameFPSCap<true >::HookEach_M2 (enableCap, TrampolineInterceptCall);
235
+ MinigameFPSCap<false >::HookEach_M2 (disableCap, TrampolineInterceptCall);
236
+ }
237
+ TXN_CATCH ();
155
238
156
- ReadCall ( enableArcadeFPSCap_m2, orgSetMinigameFPSCap );
157
- InjectHook ( enableArcadeFPSCap_m2, enableCapTrampoline );
158
- InjectHook ( disableArcadeFPSCap_m2, disableCapTrampoline );
239
+ // VF5
240
+ try
241
+ {
242
+ std::array<void *, 1 > enableCap { get_pattern ( " 41 8D 4E 3C E8" , 4 ) };
243
+ std::array<void *, 1 > disableCap { get_pattern ( " 33 C9 E8 ? ? ? ? 90 48 8B 8B 10 03 00 00" , 2 ) };
159
244
160
- InjectHook ( enableArcadeFPSCap_vf5, enableCapTrampoline );
161
- InjectHook ( disableArcadeFPSCap_vf5, disableCapTrampoline );
245
+ MinigameFPSCap<true >::HookEach_VF5 (enableCap, TrampolineInterceptCall);
246
+ MinigameFPSCap<false >::HookEach_VF5 (disableCap, TrampolineInterceptCall);
247
+ }
248
+ TXN_CATCH ();
162
249
163
- InjectHook (enableFPSCap_Karaoke, enableCapTrampoline);
164
- InjectHook (disableFPSCap_Karaoke, disableCapTrampoline);
250
+ // Karaoke
251
+ try
252
+ {
253
+ std::array<void *, 1 > enableCap { get_pattern ( " 41 8D 4C 24 3C E8 ? ? ? ? B2 01" , 5 ) };
254
+ std::array<void *, 1 > disableCap { get_pattern ( " 33 C9 E8 ? ? ? ? 90 41 B8 ? ? ? ? 48 8D 54 24 ? 48 8B CB E8 ? ? ? ? 90 4C 8B C0" , 2 ) };
165
255
166
- WriteOffsetValue ( tickUserFPSCheck, &userFPSCap_ForMinigame ); // This comes from Trampoline memory!
256
+ MinigameFPSCap<true >::HookEach_Karaoke (enableCap, TrampolineInterceptCall);
257
+ MinigameFPSCap<false >::HookEach_Karaoke (disableCap, TrampolineInterceptCall);
258
+ }
259
+ TXN_CATCH ();
167
260
}
261
+ TXN_CATCH ();
168
262
}
0 commit comments