22
33#include < nfd.h>
44
5- #undef snprintf
6- #include < json.hpp>
5+ using namespace nlohmann ; // json
76
8- void GatoBot::toggleReplay (float newSPF, float speed) {
7+ // for sorting
8+ bool compareFramesForPrac (const LevelFrameData& a, const LevelFrameData& b) {
9+ return a.frame < b.frame ;
10+ }
11+
12+ bool compareMHevents (const json& a, const json& b) {
13+ return a[" frame" ] < b[" frame" ];
14+ }
15+
16+ // toggle
17+ void GatoBot::toggleReplay (int FPS , float speed) {
918 if (status == Replaying) {
1019 status = Disabled;
1120
@@ -16,15 +25,16 @@ void GatoBot::toggleReplay(float newSPF, float speed) {
1625 setSongPitch (1 );
1726 }
1827 else {
19- if (newSPF > 0 && speed > 0 ) {
28+ if (FPS > 0 && speed > 0 ) {
2029 auto dir = CCDirector::sharedDirector ();
2130
31+ float newSPF = 1 .f / (FPS * speed);
2232 lastSPF = dir->getAnimationInterval ();
2333
2434 settings.targetSPF = newSPF;
2535 settings.targetSpeed = speed;
36+ settings.targetFPS = FPS ;
2637
27- // Speedhack (Classic Mode)
2838 dir->setAnimationInterval (newSPF);
2939 dir->getScheduler ()->setTimeScale (speed);
3040 }
@@ -35,11 +45,6 @@ void GatoBot::toggleReplay(float newSPF, float speed) {
3545 updateStatusLabel ();
3646}
3747
38- // for sorting
39- bool compareFramesForPrac (const LevelFrameData& a, const LevelFrameData& b) {
40- return a.frame < b.frame ;
41- }
42-
4348// split
4449std::vector<std::string> _splitString (std::string stringData, char * delimiter) {
4550 size_t index = 0 ;
@@ -66,8 +71,7 @@ std::vector<std::string> _splitString(std::string stringData, char* delimiter) {
6671void GatoBot::loadNewReplay () {
6772 // get file path
6873 nfdchar_t *outPath = NULL ;
69- // nfdresult_t res = NFD_OpenDialog({"gatobot,mhr.json"}, nullptr, &outPath);
70- nfdresult_t res = NFD_OpenDialog ({" gatobot" }, nullptr , &outPath);
74+ nfdresult_t res = NFD_OpenDialog ({" gatobot,mhr.json" }, nullptr , &outPath);
7175
7276 if (res != NFD_OKAY ) {
7377 free (outPath);
@@ -86,15 +90,29 @@ void GatoBot::loadNewReplay() {
8690 ReplayType rType = ReplayType::GatoBotR;
8791
8892 // MH replay
89- // if(strstr(outPath, "mhr.json") != NULL) rType = ReplayType::MegaHack;
93+ if (strstr (outPath, " mhr.json" ) != NULL ) rType = ReplayType::MegaHack;
9094
9195 free (outPath);
9296
9397 if (data.length () > 0 ) {
94- loadReplay (data, rType);
95- auto alert = gd::FLAlertLayer::create (nullptr , " Success" , " OK" , nullptr , " Replay loaded!" );
96- alert->m_pTargetLayer = (CCNode*)botMenu;
97- alert->show ();
98+ auto ret = loadReplay (data, rType);
99+
100+ if (ret == Success) {
101+ auto alert = gd::FLAlertLayer::create (nullptr , " Success" , " OK" , nullptr , " Replay loaded!" );
102+ alert->m_pTargetLayer = (CCNode*)botMenu;
103+ alert->show ();
104+ }
105+ if (ret == MissingFrames) {
106+ auto alert = gd::FLAlertLayer::create (nullptr , " Warning" , " OK" , nullptr , 360 , " This replay seems to have missing frames.\n <cy>Make sure the Mega Hack replay is recorded with the \" Frame Fixes\" accuracy.</c>" );
107+ alert->m_pTargetLayer = (CCNode*)botMenu;
108+ alert->show ();
109+ }
110+ if (ret == Failed) {
111+ // error
112+ auto alert = gd::FLAlertLayer::create (nullptr , " Error" , " OK" , nullptr , " Failed to load replay!" );
113+ alert->m_pTargetLayer = (CCNode*)botMenu;
114+ alert->show ();
115+ }
98116 }
99117 else {
100118 // error
@@ -104,7 +122,9 @@ void GatoBot::loadNewReplay() {
104122 }
105123}
106124
107- void GatoBot::loadReplay (std::string replayDataCompressed, ReplayType rType = ReplayType::GatoBotR) {
125+ ReplayLoadStatus GatoBot::loadReplay (std::string replayDataCompressed, ReplayType rType = ReplayType::GatoBotR) {
126+ ReplayLoadStatus retCode = Success;
127+
108128 // remove currently loaded frames
109129 levelFrames.clear ();
110130
@@ -139,68 +159,58 @@ void GatoBot::loadReplay(std::string replayDataCompressed, ReplayType rType = Re
139159 }
140160 // parse MegaHack replay
141161 if (rType == ReplayType::MegaHack) {
142- using namespace nlohmann ;
143-
144162 json data = json::parse (replayData);
145163
146164 auto events = data[" events" ];
147165
148- bool isHolding = false ;
149- int curF = 0 ;
166+ // sort just in case
167+ std::sort (events.begin (), events.end (), compareMHevents);
168+
169+ // allocate (ig?)
170+ levelFrames.resize (events.back ()[" frame" ] + 1 );
150171
172+ // apply to frames
151173 for (json::iterator it = events.begin (); it != events.end (); it++) {
152- // - parse event
153174 const auto item = it.value ();
175+ const int curFrame = item[" frame" ];
154176
155- item[" frame" ].get_to (curF);
156-
157- // player data
158- PlayerData pData;
177+ if (!item.contains (" p2" )) {
178+ auto pData = PlayerData::fromJson (item);
159179
160- item[" x" ].get_to (pData.position .x );
161- item[" y" ].get_to (pData.position .y );
162- item[" a" ].get_to (pData.yVel );
180+ const auto oldData = levelFrames[curFrame].player1 ;
163181
164- // click
165- if (item.contains (" down" )) {
166- item[" down" ].get_to (isHolding);
182+ if (oldData.action != None)
183+ pData.action = oldData.action ;
167184
168- pData.action = isHolding ? ButtonType::Pressed : ButtonType::Released;
169-
170- pData.isHolding = isHolding;
185+ levelFrames[curFrame].player1 = pData;
171186 }
172187 else {
173- pData.action = ButtonType::None;
174- }
188+ auto pData = PlayerData::fromJson (item);
175189
176- // new frame
177- if (curF + 1 > levelFrames.size ()) {
178- LevelFrameData frame;
179- frame.frame = curF;
190+ const auto oldData = levelFrames[curFrame].player2 ;
180191
181- if (item. contains ( " p2 " ))
182- frame. player2 = pData ;
192+ if (oldData. action != None)
193+ pData. action = oldData. action ;
183194
184- else frame.player1 = pData;
185-
186- levelFrames.push_back (frame);
195+ levelFrames[curFrame].player2 = pData;
187196 }
188- else {
189- LevelFrameData frame = levelFrames[curF];
190197
191- if (item.contains (" p2" )) {
192- frame.player2 = pData;
193- }
194-
195- else frame.player1 = pData;
198+ levelFrames[curFrame].frame = curFrame;
199+ }
196200
197- levelFrames[curF] = frame;
201+ // warning if not frame fixes accuracy
202+ for (size_t i = 0 ; i < levelFrames.size (); i++) {
203+ if (levelFrames[i].frame != i) {
204+ retCode = MissingFrames;
205+ break ;
198206 }
199207 }
200208 }
201209
202210 // sort clicks if some shit went wrong and they got shuffled
203211 std::sort (levelFrames.begin (), levelFrames.end (), compareFramesForPrac);
212+
213+ return retCode;
204214}
205215
206216LevelFrameData GatoBot::frameFromString (std::string frameData) {
@@ -245,4 +255,20 @@ LevelFrameData GatoBot::frameFromString(std::string frameData) {
245255void PlayerData::applyToPlayer (gd::PlayerObject* player) {
246256 MBO (CCPoint, player, 0x67C ) = position;
247257 MBO (double , player, 0x628 ) = yVel;
258+ }
259+
260+ PlayerData PlayerData::fromJson (json jsonData) {
261+ PlayerData data;
262+
263+ data.position = CCPoint (
264+ jsonData[" x" ], jsonData[" y" ]
265+ );
266+
267+ data.yVel = jsonData[" a" ];
268+
269+ if (jsonData.contains (" down" )) {
270+ data.action = jsonData[" down" ] ? Pressed : Released;
271+ }
272+
273+ return data;
248274}
0 commit comments