88
99using namespace geode ::prelude;
1010
11- enum RecordingState {
12- NONE , RECORD , PLAYBACK
11+ enum MacroMode {
12+ MODE_DISABLED , MODE_CAPTURE , MODE_EXECUTE
1313};
1414
15- enum ErrorCode {
16- ERROR_NONE ,
17- KEY_NOT_FOUND_ERROR ,
18- KEY_INVALID_ERROR ,
19- CURL_FAILED_ERROR ,
20- INVALID_HWID_ERROR ,
21- UNKNOWN_ERROR ,
22- KEY_LINKED_DIFFERENT_COMPUTER_ERROR
15+ enum ValidationResult {
16+ RESULT_OK ,
17+ RESULT_KEY_MISSING ,
18+ RESULT_KEY_MALFORMED ,
19+ RESULT_NETWORK_FAILURE ,
20+ RESULT_DEVICE_MISMATCH ,
21+ RESULT_UNEXPECTED ,
22+ RESULT_DEVICE_CONFLICT
2323};
2424
25- class ToastyReplay {
25+ class ReplayEngine {
2626public:
27- RecordingState state = NONE ;
28- ErrorCode error = ERROR_NONE ;
29-
30- bool fmodified = false ;
31-
32- float extraTPS = 0 .f;
33-
34- bool disableRender = false ;
35- bool ignoreBypass = false ;
36- bool justLoaded = false ;
37- bool ignoreInput = false ;
38- bool frameAdvance = false ;
39- bool doAdvance = false ;
40- bool stepFrame = false ;
41- bool internalRenderer = false ;
42- bool prevFrameAdvance = false ;
43- bool frameAdvanceKeyPressed = false ;
44- bool speedHackAudio = true ;
45- bool ignoreManualInput = false ;
46- bool isReplayInput = false ;
27+ MacroMode engineMode = MODE_DISABLED ;
28+ ValidationResult validationStatus = RESULT_OK ;
29+
30+ bool dataModified = false ;
31+
32+ float tickAccumulator = 0 .f;
33+
34+ bool renderingDisabled = false ;
35+ bool bypassIgnored = false ;
36+ bool recentlyInitialized = false ;
37+ bool inputIgnored = false ;
38+ bool tickStepping = false ;
39+ bool pendingStep = false ;
40+ bool singleTickStep = false ;
41+ bool renderInternal = false ;
42+ bool priorTickStepping = false ;
43+ bool stepKeyActive = false ;
44+ bool audioPitchEnabled = true ;
45+ bool userInputIgnored = false ;
46+ bool macroInputActive = false ;
47+ bool protectedMode = false ;
48+ bool pathPreview = false ;
49+ bool collisionBypass = false ;
50+ bool collisionLimitActive = false ;
51+ float collisionThreshold = 0 .0f ;
52+
4753 bool safeMode = false ;
4854 bool showTrajectory = false ;
49- bool noclip = false ;
50- bool noclipAccuracyEnabled = false ;
51- float noclipAccuracyLimit = 0 .0f ;
52-
53- int noclipDeaths = 0 ;
54- int noclipTotalFrames = 0 ;
55-
56- bool seedEnabled = false ;
57- unsigned int seedValue = 1 ;
58- uintptr_t macroSeed = 0 ;
59-
60- int trajectoryLength = 312 ;
61-
62- double speed = 1 ;
63- double tps = 240 .f;
64- ReplayData* currentReplay = nullptr ;
65-
66- std::unordered_map<CheckpointObject*, CheckpointData> checkpoints;
67- int previousFrame = 0 ;
68- int respawnFrame = -1 ;
69- size_t playbackIndex = 0 ;
70- size_t frameFixIndex = 0 ;
71- bool ignoreRecordAction = false ;
72- bool restart = false ;
73- bool firstAttempt = false ;
74- bool frameFixes = false ;
75- bool inputFixes = false ;
76- int frameFixesLimit = 240 ;
77- int ignoreFrame = -1 ;
78- int ignoreJumpButton = -1 ;
79- int delayedFrameReleaseMain[2 ] = { -1 , -1 };
80- int delayedFrameInput[2 ] = { -1 , -1 };
81- int delayedFrameRelease[2 ][2 ] = { { -1 , -1 }, { -1 , -1 } };
82- bool heldButtons[6 ] = { false , false , false , false , false , false };
83- bool wasHolding[6 ] = { false , false , false , false , false , false };
84- bool addSideHoldingMembers[2 ] = { false , false };
85- bool ignoreStopDashing[2 ] = { false , false };
55+ bool trajectoryBothSides = false ;
8656 bool creatingTrajectory = false ;
87- int currentSession = 0 ;
88- int lastAutoSaveFrame = 0 ;
89-
90- std::vector<std::string> savedReplays;
91-
92- int keybind_frameAdvance = 0x56 ;
93- int keybind_speedhackAudio = 0 ;
94- int keybind_safeMode = 0 ;
95- int keybind_trajectory = 0 ;
96- int keybind_noclip = 0 ;
97- int keybind_seed = 0 ;
98-
99- void refreshReplays () {
100- savedReplays.clear ();
57+
58+ int bypassedCollisions = 0 ;
59+ int totalTickCount = 0 ;
60+
61+ bool rngLocked = false ;
62+ unsigned int rngSeedVal = 1 ;
63+ uintptr_t capturedRngState = 0 ;
64+
65+ int pathLength = 312 ;
66+
67+ double gameSpeed = 1 ;
68+ double tickRate = 240 .f;
69+ MacroSequence* activeMacro = nullptr ;
70+
71+ std::unordered_map<CheckpointObject*, RestorePoint> storedRestorePoints;
72+ int lastTickIndex = 0 ;
73+ int respawnTickIndex = -1 ;
74+ size_t executeIndex = 0 ;
75+ size_t correctionIndex = 0 ;
76+ bool captureIgnored = false ;
77+ bool levelRestarting = false ;
78+ bool initialRun = false ;
79+ bool positionCorrection = false ;
80+ bool inputCorrection = false ;
81+ int correctionInterval = 240 ;
82+ int skipTickIndex = -1 ;
83+ int skipActionTick = -1 ;
84+ int deferredReleaseA[2 ] = { -1 , -1 };
85+ int deferredInputTick[2 ] = { -1 , -1 };
86+ int deferredReleaseB[2 ][2 ] = { { -1 , -1 }, { -1 , -1 } };
87+ bool activeButtons[6 ] = { false , false , false , false , false , false };
88+ bool priorButtonState[6 ] = { false , false , false , false , false , false };
89+ bool lateralInputPending[2 ] = { false , false };
90+ bool dashCancelIgnored[2 ] = { false , false };
91+ bool simulatingPath = false ;
92+ int sessionCounter = 0 ;
93+ int lastSaveTick = 0 ;
94+
95+ std::vector<std::string> storedMacros;
96+
97+ int hotkey_tickStep = 0x56 ;
98+ int hotkey_audioPitch = 0 ;
99+ int hotkey_protected = 0 ;
100+ int hotkey_pathPreview = 0 ;
101+ int hotkey_collision = 0 ;
102+ int hotkey_rngLock = 0 ;
103+
104+ void reloadMacroList () {
105+ storedMacros.clear ();
101106 auto dir = geode::prelude::Mod::get ()->getSaveDir () / " replays" ;
102107 if (std::filesystem::exists (dir)) {
103108 for (auto & entry : std::filesystem::directory_iterator (dir)) {
104109 if (entry.is_regular_file () && entry.path ().extension () == " .gdr" ) {
105- savedReplays .push_back (entry.path ().stem ().string ());
110+ storedMacros .push_back (entry.path ().stem ().string ());
106111 }
107112 }
108113 }
109114 }
110115
111- void startRecording (GJGameLevel* level) {
112- state = RECORD ;
113- createNewReplay (level);
116+ void beginCapture (GJGameLevel* level) {
117+ engineMode = MODE_CAPTURE ;
118+ initializeMacro (level);
114119 }
115120
116- void createNewReplay (GJGameLevel* level) {
117- if (currentReplay ) delete currentReplay ;
118- currentReplay = new ReplayData ();
121+ void initializeMacro (GJGameLevel* level) {
122+ if (activeMacro ) delete activeMacro ;
123+ activeMacro = new MacroSequence ();
119124 if (level) {
120- currentReplay ->levelInfo .id = level->m_levelID ;
121- currentReplay ->levelInfo .name = level->m_levelName ;
122- currentReplay ->name = level->m_levelName ;
125+ activeMacro ->levelInfo .id = level->m_levelID ;
126+ activeMacro ->levelInfo .name = level->m_levelName ;
127+ activeMacro ->name = level->m_levelName ;
123128 }
124- currentReplay ->framerate = tps ;
129+ activeMacro ->framerate = tickRate ;
125130 }
126131
127- void startPlayback () {
128- if (!currentReplay || currentReplay ->inputs .empty ()) return ;
132+ void beginExecution () {
133+ if (!activeMacro || activeMacro ->inputs .empty ()) return ;
129134
130- state = PLAYBACK ;
131- playbackIndex = 0 ;
132- frameFixIndex = 0 ;
133- firstAttempt = true ;
134- respawnFrame = -1 ;
135+ engineMode = MODE_EXECUTE ;
136+ executeIndex = 0 ;
137+ correctionIndex = 0 ;
138+ initialRun = true ;
139+ respawnTickIndex = -1 ;
135140
136141 PlayLayer* pl = PlayLayer::get ();
137142 if (pl) {
@@ -142,17 +147,17 @@ class ToastyReplay {
142147 }
143148 }
144149
145- void stopPlayback () {
146- state = NONE ;
150+ void haltExecution () {
151+ engineMode = MODE_DISABLED ;
147152 }
148153
149154 static auto * get () {
150- static ToastyReplay* instance = new ToastyReplay ();
151- return instance ;
155+ static ReplayEngine* singleton = new ReplayEngine ();
156+ return singleton ;
152157 }
153158
154- void playSound (bool p2 , int button , bool down );
159+ void triggerAudio (bool secondPlayer , int actionType , bool pressed );
155160
156- void handleKeybinds ();
161+ void processHotkeys ();
157162};
158163#endif
0 commit comments