@@ -13,7 +13,7 @@ bool __fastcall PlayLayer_initH(gd::PlayLayer* self, uintptr_t, gd::GJGameLevel*
1313 bot->player1holding = false ;
1414 bot->player2holding = false ;
1515 bot->currentFrame = 0 ;
16-
16+ bot-> practiceCheckpoints . clear ();
1717 bot->queuedBtnP1 = None;
1818 bot->queuedBtnP2 = None;
1919
@@ -72,6 +72,8 @@ void __fastcall PlayLayer_updateH(gd::PlayLayer* self, uintptr_t, float dt) {
7272 {
7373 LevelFrameData frame = bot->levelFrames [bot->currentFrame ];
7474
75+ // std::cout << "alignment: " << bot->currentFrame << " :: " << frame.frame << "\n";
76+
7577 frame.player1 .applyToPlayer (self->m_pPlayer1 );
7678 frame.player2 .applyToPlayer (self->m_pPlayer2 );
7779
@@ -140,73 +142,79 @@ void __fastcall PauseLayer_customSetupH(gd::PauseLayer* self, uintptr_t) {
140142}
141143
142144void (__thiscall* GJBaseGameLayer_pushButtonO)(gd::GJBaseGameLayer*, int , bool );
143- void __fastcall GJBaseGameLayer_pushButtonH (gd::GJBaseGameLayer* self, uintptr_t , int button, bool player1 ) {
144- GJBaseGameLayer_pushButtonO (self, button, player1 );
145+ void __fastcall GJBaseGameLayer_pushButtonH (gd::GJBaseGameLayer* self, uintptr_t , int button, bool rightSide ) {
146+ GJBaseGameLayer_pushButtonO (self, button, rightSide );
145147
146148 auto bot = GatoBot::sharedState ();
147149
148150 if (bot->status == Recording && !MBO (bool , self, 0x39C )) {
149- if (player1) bot->queuedBtnP1 = Pressed;
150- else bot->queuedBtnP2 = Pressed;
151+ bool twoPlayer = MBO (bool , self->m_pLevelSettings , 0xFA );
152+
153+ if (MBO (bool , self, 0x2A9 ) && !rightSide && twoPlayer)
154+ bot->queuedBtnP2 = Pressed;
155+
156+ else bot->queuedBtnP1 = Pressed;
151157 }
152158}
153159
154160void (__thiscall* GJBaseGameLayer_releaseButtonO)(gd::GJBaseGameLayer*, int , bool );
155- void __fastcall GJBaseGameLayer_releaseButtonH (gd::GJBaseGameLayer* self, uintptr_t , int button, bool player1 ) {
156- GJBaseGameLayer_releaseButtonO (self, button, player1 );
161+ void __fastcall GJBaseGameLayer_releaseButtonH (gd::GJBaseGameLayer* self, uintptr_t , int button, bool rightSide ) {
162+ GJBaseGameLayer_releaseButtonO (self, button, rightSide );
157163
158164 auto bot = GatoBot::sharedState ();
159165
160166 if (bot->status == Recording && !MBO (bool , self, 0x39C )) {
161- if (player1) bot->queuedBtnP1 = Released;
162- else bot->queuedBtnP2 = Released;
167+ bool twoPlayer = MBO (bool , self->m_pLevelSettings , 0xFA );
168+
169+ if (MBO (bool , self, 0x2A9 ) && !rightSide && twoPlayer)
170+ bot->queuedBtnP2 = Released;
171+
172+ else bot->queuedBtnP1 = Released;
163173 }
164174}
165175
166- gd::GameObject* (__thiscall* PlayLayer_createCheckpointO )(gd::PlayLayer *);
167- gd::GameObject* __fastcall PlayLayer_createCheckpointH (gd::PlayLayer * self, uintptr_t ) {
168- auto ret = PlayLayer_createCheckpointO (self);
176+ void (__thiscall* UILayer_onCheckO )(gd::UILayer*, CCObject *);
177+ void __fastcall UILayer_onCheckH (gd::UILayer * self, uintptr_t , CCObject* pSender ) {
178+ UILayer_onCheckO (self, pSender );
169179
170- auto bot = GatoBot::sharedState ();
171- if (bot->status == Recording) {
172- auto player1 = PlayerData::fromPlayer (self->m_pPlayer1 );
173- auto player2 = PlayerData::fromPlayer (self->m_pPlayer2 );
180+ GatoBot::sharedState ()->handleCheckpoint (gd::PlayLayer::get ());
181+ }
174182
175- LevelFrameData frame = {bot->currentFrame , player1, player2};
176- CheckpointData checkpoint = {frame};
183+ void midhookFuckery () {
184+ GatoBot::sharedState ()->handleCheckpoint (gd::PlayLayer::get ());
185+ }
177186
178- bot->practiceCheckpoints .push_back (checkpoint);
187+ // midfunc moment
188+ void (*PlayerObject_tryPlaceCheckpointO)();
189+ __declspec (naked) void PlayerObject_tryPlaceCheckpointH() {
190+ __asm {
191+ call midhookFuckery;
192+ jmp PlayerObject_tryPlaceCheckpointO;
179193 }
194+ }
180195
181- return ret;
182- }
183-
184- void (__thiscall* PlayLayer_removePendingCheckpointO)(gd::PlayLayer*);
185- void __fastcall PlayLayer_removePendingCheckpointH (gd::PlayLayer* self, uintptr_t ) {
186- PlayLayer_removePendingCheckpointO (self);
196+ void (__thiscall* PlayLayer_removeLastCheckpointO)(gd::PlayLayer*);
197+ void __fastcall PlayLayer_removeLastCheckpointH (gd::PlayLayer* self, uintptr_t ) {
198+ PlayLayer_removeLastCheckpointO (self);
187199
188200 auto bot = GatoBot::sharedState ();
189201
190202 if (bot->practiceCheckpoints .size () > 0 )
191203 bot->practiceCheckpoints .pop_back ();
192204}
193205
194- float getTimeForPos (gd::PlayLayer* self) {
195- float ret;
196- float xPos = self->m_pPlayer1 ->getPositionX ();
197- __asm movss xmm1, xPos;
198- reinterpret_cast <void (__thiscall*)(gd::PlayLayer*, bool )>(gd::base + 0x208800 )(self, self->m_isTestMode ); // PlayLayer::timeForXPos2
199- __asm movss ret, xmm0; // return value
200-
201- return ret;
202- }
203-
204206void (__thiscall* PlayLayer_resetLevelO)(gd::PlayLayer*);
205207void __fastcall PlayLayer_resetLevelH (gd::PlayLayer* self, uintptr_t ) {
206- PlayLayer_resetLevelO (self);
207-
208208 auto bot = GatoBot::sharedState ();
209209
210+ // disable practice mode
211+ if (bot->status == Replaying || bot->status == Rendering && self->m_isPracticeMode ) {
212+ self->togglePracticeMode (false );
213+ bot->practiceCheckpoints .clear ();
214+ }
215+
216+ PlayLayer_resetLevelO (self);
217+
210218 if (bot->status == Recording) {
211219 if (bot->levelFrames .size () > 0 ) {
212220 // practice mode shenanigans
@@ -221,39 +229,52 @@ void __fastcall PlayLayer_resetLevelH(gd::PlayLayer* self, uintptr_t) {
221229 checkpoint.frame .player2 .applyToPlayer (self->m_pPlayer2 );
222230 }
223231 else bot->currentFrame = 0 ;
224-
232+
225233 // remove all clicks and frames after checkpoint
226234 if (self->m_isPracticeMode && bot->currentFrame > 0 ) {
227235 bot->levelFrames .resize (bot->currentFrame );
228- }
236+ }
229237 else {
230238 bot->levelFrames .clear ();
231239 }
232-
240+
233241 // jump?
234242 if (bot->levelFrames .back ().player1 .isHolding != MBO (bool , self->m_pPlayer1 , 0x611 )) {
235- if (MBO (bool , self->m_pPlayer1 , 0x611 )) bot->levelFrames .back ().player1 .action = Pressed;
236- else bot->levelFrames .back ().player1 .action = Released;
243+ if (MBO (bool , self->m_pPlayer1 , 0x611 )) {
244+ bot->levelFrames .back ().player1 .action = Pressed;
245+ bot->levelFrames .back ().player1 .isHolding = true ;
246+ }
247+ else {
248+ bot->levelFrames .back ().player1 .action = Released;
249+ bot->levelFrames .back ().player1 .isHolding = false ;
250+ }
237251 }
238252
239253 if (bot->levelFrames .back ().player2 .isHolding != MBO (bool , self->m_pPlayer2 , 0x611 )) {
240- if (MBO (bool , self->m_pPlayer2 , 0x611 )) bot->levelFrames .back ().player2 .action = Pressed;
241- else bot->levelFrames .back ().player2 .action = Released;
254+ if (MBO (bool , self->m_pPlayer2 , 0x611 )) {
255+ bot->levelFrames .back ().player2 .action = Pressed;
256+ bot->levelFrames .back ().player2 .isHolding = true ;
257+ }
258+ else {
259+ bot->levelFrames .back ().player2 .action = Released;
260+ bot->levelFrames .back ().player2 .isHolding = false ;
261+ }
242262 }
243263
244264 bot->queuedBtnP1 = None;
245265 bot->queuedBtnP2 = None;
246266 }
267+ }
247268
269+ if (bot->status == Recording || bot->status == Replaying)
248270 bot->setSongPitch (CCDirector::sharedDirector ()->getScheduler ()->getTimeScale ());
249- }
250271
251272 if (!self->m_isPracticeMode ) {
252273 bot->currentFrame = 0 ;
253274 bot->timeFromStart = 0 ;
254275
255276 // update music offset
256- bot->currentMusicOffset = getTimeForPos (self) + MBO (float , self->m_pLevelSettings , 0xFC ); // timeForXPos + songOffset
277+ bot->currentMusicOffset = bot-> getTimeForXPos (self) + MBO (float , self->m_pLevelSettings , 0xFC ); // timeForXPos + songOffset
257278 }
258279}
259280
@@ -304,7 +325,6 @@ void __fastcall CCScheduler_updateH(CCScheduler* self, uintptr_t, float dt) {
304325 }
305326
306327 if (bot->status == Rendering && !bot->gamePaused ) {
307-
308328 if (!bot->currentFrameHasData ) {
309329 float deltaTime = 1 .f / static_cast <float >(bot->settings .targetGameFPS ); // constant delta time
310330
@@ -314,7 +334,7 @@ void __fastcall CCScheduler_updateH(CCScheduler* self, uintptr_t, float dt) {
314334 if (fmod->isBackgroundMusicPlaying () && !pLayer->m_hasCompletedLevel ) {
315335 // what the fuck why are the args backwards
316336 auto channel = fmod->m_pGlobalChannel ;
317- int musicTime = static_cast <int >((getTimeForPos (pLayer) + MBO (float , pLayer->m_pLevelSettings , 0xFC )) * 1000 );
337+ int musicTime = static_cast <int >((bot-> getTimeForXPos (pLayer) + MBO (float , pLayer->m_pLevelSettings , 0xFC )) * 1000 );
318338 __asm {
319339 push 0x1 ;
320340 push musicTime;
@@ -399,18 +419,25 @@ void loadHooks() {
399419 reinterpret_cast <void **>(&GJBaseGameLayer_releaseButtonO)
400420 );
401421
402- // PlayLayer::createCheckpoint
422+ // UILayer::onCheck
423+ MH_CreateHook (
424+ reinterpret_cast <void *>(gd::base + 0x25fb60 ),
425+ reinterpret_cast <void *>(&UILayer_onCheckH),
426+ reinterpret_cast <void **>(&UILayer_onCheckO)
427+ );
428+
429+ // PlayLayer::tryPlaceCheckpoint (MIDHOOK)
403430 MH_CreateHook (
404- reinterpret_cast <void *>(gd::base + 0x20b050 ),
405- reinterpret_cast <void *>(&PlayLayer_createCheckpointH ),
406- reinterpret_cast <void **>(&PlayLayer_createCheckpointO )
431+ reinterpret_cast <void *>(gd::base + 0x20b487 ),
432+ reinterpret_cast <void *>(&PlayerObject_tryPlaceCheckpointH ),
433+ reinterpret_cast <void **>(&PlayerObject_tryPlaceCheckpointO )
407434 );
408435
409- // PlayLayer::removePendingCheckpoint
436+ // PlayLayer::removeLastCheckpoint
410437 MH_CreateHook (
411438 reinterpret_cast <void *>(gd::base + 0x20b830 ),
412- reinterpret_cast <void *>(&PlayLayer_removePendingCheckpointH ),
413- reinterpret_cast <void **>(&PlayLayer_removePendingCheckpointO )
439+ reinterpret_cast <void *>(&PlayLayer_removeLastCheckpointH ),
440+ reinterpret_cast <void **>(&PlayLayer_removeLastCheckpointO )
414441 );
415442
416443 // PlayLayer::resetLevel
0 commit comments