From 86ea0b5fbfb0083d229e3a6c1a40e32cfab1da47 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 01:57:29 +0300 Subject: [PATCH 001/211] update memebers --- mod.json | 17 +++++++------- src/macro.hpp | 18 +++++++-------- src/practice_fixes/player.cpp | 28 +++++++++++------------ src/renderer/renderer.cpp | 3 ++- src/ui/autoclicker_settings_layer.hpp | 8 +++---- src/ui/autosave_settings_layer.hpp | 2 +- src/ui/record_layer.cpp | 32 +++++++++++++-------------- src/ui/render_settings_layer.cpp | 18 +++++++-------- 8 files changed, 64 insertions(+), 62 deletions(-) diff --git a/mod.json b/mod.json index ed86b668..18add9a6 100644 --- a/mod.json +++ b/mod.json @@ -1,22 +1,23 @@ { - "geode": "4.4.0", + "geode": "4.6.2", "gd": { "win": "2.2074", - "android": "2.2074" + "mac": "2.2074", + "android": "2.2074", + "ios": "2.2074" }, "version": "2.4.1", "id": "zilko.xdbot", "name": "xdBot", "developer": "Zilko", "description": "Best Free Bot fr", - "dependencies": [ - { - "id": "geode.custom-keybinds", - "version": ">=v1.10.0", + "dependencies": { + "geode.custom-keybinds": { + "version": ">=1.10.4", "importance": "required", - "platforms": ["win"] + "platforms": ["win", "mac"] } - ], + }, "settings": { "button-setting": { "type": "custom:button", diff --git a/src/macro.hpp b/src/macro.hpp index 0859e495..ad52bf3d 100644 --- a/src/macro.hpp +++ b/src/macro.hpp @@ -109,7 +109,7 @@ struct PlayerData { DashRingObject* m_dashRing; double m_slopeStartTime; bool m_justPlacedStreak; - GameObject* m_maybeLastGroundObject; + CCNode* m_maybeLastGroundObject; cocos2d::CCDictionary* m_collisionLogTop; cocos2d::CCDictionary* m_collisionLogBottom; cocos2d::CCDictionary* m_collisionLogLeft; @@ -177,8 +177,8 @@ struct PlayerData { double m_lastSpiderFlipTime; bool m_unkBool5; bool m_maybeIsVehicleGlowing; - bool m_gv0096; - bool m_gv0100; + bool m_switchWaveTrailColor; + bool m_practiceDeathEffect; double m_accelerationOrSpeed; double m_snapDistance; bool m_ringJumpRelated; @@ -259,7 +259,7 @@ struct PlayerData { cocos2d::CCArray* m_touchingRings; GameObject* m_lastActivatedPortal; bool m_hasEverJumped; - bool m_ringOrStreakRelated; + bool m_hasEverHitRing; cocos2d::CCPoint m_position; bool m_isSecondPlayer; bool m_unkA99; @@ -268,9 +268,9 @@ struct PlayerData { float m_unkAAC; float m_unkAngle1; float m_yVelocityRelated3; - bool m_gamevar0060; + bool m_defaultMiniIcon; bool m_swapColors; - bool m_gamevar0062; + bool m_switchDashFireColor; int m_followRelated; float m_unk838; int m_stateOnGround; @@ -323,9 +323,9 @@ struct PlayerData { bool m_isOutOfBounds; float m_fallStartY; bool m_disablePlayerSqueeze; - bool m_robotHasRun3; - bool m_robotHasRun2; - bool m_item20; + bool m_robotAnimation1Enabled; + bool m_robotAnimation2Enabled; + bool m_spiderAnimationEnabled; bool m_ignoreDamage; bool m_enable22Changes; }; diff --git a/src/practice_fixes/player.cpp b/src/practice_fixes/player.cpp index cc279ffb..b782bbbe 100644 --- a/src/practice_fixes/player.cpp +++ b/src/practice_fixes/player.cpp @@ -106,8 +106,8 @@ PlayerData PlayerPracticeFixes::saveData(PlayerObject* player) { data.m_lastSpiderFlipTime = player->m_lastSpiderFlipTime; data.m_unkBool5 = player->m_unkBool5; data.m_maybeIsVehicleGlowing = player->m_maybeIsVehicleGlowing; - data.m_gv0096 = player->m_gv0096; - data.m_gv0100 = player->m_gv0100; + data.m_switchWaveTrailColor = player->m_switchWaveTrailColor; + data.m_practiceDeathEffect = player->m_practiceDeathEffect; data.m_accelerationOrSpeed = player->m_accelerationOrSpeed; data.m_snapDistance = player->m_snapDistance; data.m_ringJumpRelated = player->m_ringJumpRelated; @@ -188,7 +188,7 @@ PlayerData PlayerPracticeFixes::saveData(PlayerObject* player) { data.m_touchingRings = player->m_touchingRings; data.m_lastActivatedPortal = player->m_lastActivatedPortal; data.m_hasEverJumped = player->m_hasEverJumped; - data.m_ringOrStreakRelated = player->m_ringOrStreakRelated; + data.m_hasEverHitRing = player->m_hasEverHitRing; data.m_position = player->m_position; data.m_isSecondPlayer = player->m_isSecondPlayer; data.m_unkA99 = player->m_unkA99; @@ -197,9 +197,9 @@ PlayerData PlayerPracticeFixes::saveData(PlayerObject* player) { data.m_unkAAC = player->m_unkAAC; data.m_unkAngle1 = player->m_unkAngle1; data.m_yVelocityRelated3 = player->m_yVelocityRelated3; - data.m_gamevar0060 = player->m_gamevar0060; + data.m_defaultMiniIcon = player->m_defaultMiniIcon; data.m_swapColors = player->m_swapColors; - data.m_gamevar0062 = player->m_gamevar0062; + data.m_switchDashFireColor = player->m_switchDashFireColor; data.m_followRelated = player->m_followRelated; data.m_unk838 = player->m_unk838; data.m_stateOnGround = player->m_stateOnGround; @@ -252,9 +252,9 @@ PlayerData PlayerPracticeFixes::saveData(PlayerObject* player) { data.m_isOutOfBounds = player->m_isOutOfBounds; data.m_fallStartY = player->m_fallStartY; data.m_disablePlayerSqueeze = player->m_disablePlayerSqueeze; - data.m_robotHasRun3 = player->m_robotHasRun3; - data.m_robotHasRun2 = player->m_robotHasRun2; - data.m_item20 = player->m_item20; + data.m_robotAnimation1Enabled = player->m_robotAnimation1Enabled; + data.m_robotAnimation2Enabled = player->m_robotAnimation2Enabled; + data.m_spiderAnimationEnabled = player->m_spiderAnimationEnabled; data.m_ignoreDamage = player->m_ignoreDamage; data.m_enable22Changes = player->m_enable22Changes; return data; @@ -444,7 +444,7 @@ void PlayerPracticeFixes::applyData(PlayerObject* player, PlayerData data, bool player->m_touchingRings = data.m_touchingRings; player->m_lastActivatedPortal = data.m_lastActivatedPortal; player->m_hasEverJumped = data.m_hasEverJumped; - player->m_ringOrStreakRelated = data.m_ringOrStreakRelated; + player->m_hasEverHitRing = data.m_hasEverHitRing; player->m_position = data.m_position; player->m_isSecondPlayer = data.m_isSecondPlayer; player->m_unkA99 = data.m_unkA99; @@ -453,9 +453,9 @@ void PlayerPracticeFixes::applyData(PlayerObject* player, PlayerData data, bool player->m_unkAAC = data.m_unkAAC; player->m_unkAngle1 = data.m_unkAngle1; player->m_yVelocityRelated3 = data.m_yVelocityRelated3; - player->m_gamevar0060 = data.m_gamevar0060; + player->m_defaultMiniIcon = data.m_defaultMiniIcon; player->m_swapColors = data.m_swapColors; - player->m_gamevar0062 = data.m_gamevar0062; + player->m_switchDashFireColor = data.m_switchDashFireColor; player->m_followRelated = data.m_followRelated; player->m_unk838 = data.m_unk838; player->m_stateOnGround = data.m_stateOnGround; @@ -507,9 +507,9 @@ void PlayerPracticeFixes::applyData(PlayerObject* player, PlayerData data, bool player->m_isOutOfBounds = data.m_isOutOfBounds; player->m_fallStartY = data.m_fallStartY; player->m_disablePlayerSqueeze = data.m_disablePlayerSqueeze; - player->m_robotHasRun3 = data.m_robotHasRun3; - player->m_robotHasRun2 = data.m_robotHasRun2; - player->m_item20 = data.m_item20; + player->m_robotAnimation1Enabled = data.m_robotAnimation1Enabled; + player->m_robotAnimation2Enabled = data.m_robotAnimation2Enabled; + player->m_spiderAnimationEnabled = data.m_spiderAnimationEnabled; player->m_ignoreDamage = data.m_ignoreDamage; player->m_enable22Changes = data.m_enable22Changes; diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 311d556a..e7e38d47 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -84,8 +84,9 @@ class $modify(FMODAudioEngine) { if (path != "playSound_01.ogg" || !Global::get().renderer.recordingAudio) return FMODAudioEngine::playEffect(path, speed, p2, volume); - } + return 0; + } }; class $modify(GJBaseGameLayer) { diff --git a/src/ui/autoclicker_settings_layer.hpp b/src/ui/autoclicker_settings_layer.hpp index 8d0e8329..5fc84dd6 100644 --- a/src/ui/autoclicker_settings_layer.hpp +++ b/src/ui/autoclicker_settings_layer.hpp @@ -192,7 +192,7 @@ class AutoclickerLayer : public geode::Popup<>, public TextInputDelegate { holdLbl->setOpacity(g.autoclickerP1 ? 86 : 23); holdInput->getBGSprite()->setOpacity(g.autoclickerP1 ? 90 : 30); holdInput->setEnabled(g.autoclickerP1); - holdInput->getInputNode()->m_placeholderLabel->setOpacity(g.autoclickerP1 ? 255 : 100); + holdInput->getInputNode()->m_textLabel->setOpacity(g.autoclickerP1 ? 255 : 100); if (!g.autoclickerP1) { holdInput->getInputNode()->detachWithIME(); holdInput->getInputNode()->onClickTrackNode(false); @@ -203,7 +203,7 @@ class AutoclickerLayer : public geode::Popup<>, public TextInputDelegate { holdLbl2->setOpacity(g.autoclickerP2 ? 86 : 23); holdInput2->getBGSprite()->setOpacity(g.autoclickerP2 ? 90 : 30); holdInput2->setEnabled(g.autoclickerP2); - holdInput2->getInputNode()->m_placeholderLabel->setOpacity(g.autoclickerP2 ? 255 : 100); + holdInput2->getInputNode()->m_textLabel->setOpacity(g.autoclickerP2 ? 255 : 100); if (!g.autoclickerP2) { holdInput2->getInputNode()->detachWithIME(); holdInput2->getInputNode()->onClickTrackNode(false); @@ -214,7 +214,7 @@ class AutoclickerLayer : public geode::Popup<>, public TextInputDelegate { releaseLbl->setOpacity(g.autoclickerP1 ? 86 : 23); releaseInput->getBGSprite()->setOpacity(g.autoclickerP1 ? 90 : 30); releaseInput->setEnabled(g.autoclickerP1); - releaseInput->getInputNode()->m_placeholderLabel->setOpacity(g.autoclickerP1 ? 255 : 100); + releaseInput->getInputNode()->m_textLabel->setOpacity(g.autoclickerP1 ? 255 : 100); if (!g.autoclickerP1) { releaseInput->getInputNode()->detachWithIME(); releaseInput->getInputNode()->onClickTrackNode(false); @@ -225,7 +225,7 @@ class AutoclickerLayer : public geode::Popup<>, public TextInputDelegate { releaseLbl2->setOpacity(g.autoclickerP2 ? 86 : 23); releaseInput2->getBGSprite()->setOpacity(g.autoclickerP2 ? 90 : 30); releaseInput2->setEnabled(g.autoclickerP2); - releaseInput2->getInputNode()->m_placeholderLabel->setOpacity(g.autoclickerP2 ? 255 : 100); + releaseInput2->getInputNode()->m_textLabel->setOpacity(g.autoclickerP2 ? 255 : 100); if (!g.autoclickerP2) { releaseInput2->getInputNode()->detachWithIME(); releaseInput2->getInputNode()->onClickTrackNode(false); diff --git a/src/ui/autosave_settings_layer.hpp b/src/ui/autosave_settings_layer.hpp index 7faf510f..b9f7c3dc 100644 --- a/src/ui/autosave_settings_layer.hpp +++ b/src/ui/autosave_settings_layer.hpp @@ -128,7 +128,7 @@ class AutoSaveLayer : public geode::Popup<>, public TextInputDelegate { intervalLbl2->setOpacity(g.autosaveIntervalEnabled ? 255 : 100); intervalInput->getBGSprite()->setOpacity(g.autosaveIntervalEnabled ? 90 : 30); intervalInput->setEnabled(g.autosaveIntervalEnabled); - intervalInput->getInputNode()->m_placeholderLabel->setOpacity(g.autosaveIntervalEnabled ? 255 : 100); + intervalInput->getInputNode()->m_textLabel->setOpacity(g.autosaveIntervalEnabled ? 255 : 100); if (!g.autosaveIntervalEnabled) { intervalInput->getInputNode()->detachWithIME(); intervalInput->getInputNode()->onClickTrackNode(false); diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index edb1d6d4..76c63029 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -765,7 +765,7 @@ bool RecordLayer::setup() { widthInput = CCTextInputNode::create(150, 30, "Width", "chatFont.fnt"); widthInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); widthInput->ignoreAnchorPointForPosition(true); - widthInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); + widthInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); widthInput->setPosition(ccp(-157, -31)); widthInput->setMaxLabelScale(0.7f); widthInput->setMouseEnabled(true); @@ -780,7 +780,7 @@ bool RecordLayer::setup() { heightInput = CCTextInputNode::create(150, 30, "Height", "chatFont.fnt"); heightInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); heightInput->ignoreAnchorPointForPosition(true); - heightInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); + heightInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); heightInput->setPosition(ccp(-72.5, -31)); heightInput->setMaxLabelScale(0.7f); heightInput->setMouseEnabled(true); @@ -795,7 +795,7 @@ bool RecordLayer::setup() { bitrateInput = CCTextInputNode::create(150, 30, "br", "chatFont.fnt"); bitrateInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); bitrateInput->ignoreAnchorPointForPosition(true); - bitrateInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); + bitrateInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); bitrateInput->setPosition(ccp(-185.5, -59)); bitrateInput->setMaxLabelScale(0.7f); bitrateInput->setMouseEnabled(true); @@ -838,7 +838,7 @@ bool RecordLayer::setup() { codecInput = CCTextInputNode::create(150, 30, "Codec", "chatFont.fnt"); codecInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); codecInput->ignoreAnchorPointForPosition(true); - codecInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); + codecInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); codecInput->setPosition(ccp(-70.5, -62)); codecInput->setMouseEnabled(true); codecInput->setTouchEnabled(true); @@ -853,8 +853,8 @@ bool RecordLayer::setup() { fpsInput = CCTextInputNode::create(150, 30, "FPS", "chatFont.fnt"); fpsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); fpsInput->ignoreAnchorPointForPosition(true); - fpsInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); - fpsInput->m_placeholderLabel->setScale(0.6); + fpsInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + fpsInput->m_textLabel->setScale(0.6); fpsInput->setPosition(ccp(-133, -59)); fpsInput->setMaxLabelScale(0.7f); fpsInput->setMouseEnabled(true); @@ -1076,8 +1076,8 @@ void RecordLayer::loadSetting(RecordSetting sett, float yPos) { speedhackInput->setPosition(ccp(127.5, yPos)); speedhackInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); speedhackInput->ignoreAnchorPointForPosition(true); - speedhackInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); - speedhackInput->m_placeholderLabel->setScale(0.6); + speedhackInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + speedhackInput->m_textLabel->setScale(0.6); speedhackInput->setMaxLabelScale(0.7f); speedhackInput->setMouseEnabled(true); speedhackInput->setTouchEnabled(true); @@ -1108,8 +1108,8 @@ void RecordLayer::loadSetting(RecordSetting sett, float yPos) { tpsInput->setPosition(ccp(133.5, yPos)); tpsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); tpsInput->ignoreAnchorPointForPosition(true); - tpsInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); - tpsInput->m_placeholderLabel->setScale(0.6); + tpsInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + tpsInput->m_textLabel->setScale(0.6); tpsInput->setMaxLabelScale(0.7f); tpsInput->setMouseEnabled(true); tpsInput->setTouchEnabled(true); @@ -1140,8 +1140,8 @@ void RecordLayer::loadSetting(RecordSetting sett, float yPos) { seedInput->setPosition(ccp(109.5, yPos)); seedInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); seedInput->ignoreAnchorPointForPosition(true); - seedInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); - seedInput->m_placeholderLabel->setScale(0.6); + seedInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + seedInput->m_textLabel->setScale(0.6); seedInput->setMaxLabelScale(0.7f); seedInput->setMouseEnabled(true); seedInput->setTouchEnabled(true); @@ -1172,8 +1172,8 @@ void RecordLayer::loadSetting(RecordSetting sett, float yPos) { respawnInput->setPosition(ccp(127.5, yPos)); respawnInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); respawnInput->ignoreAnchorPointForPosition(true); - respawnInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); - respawnInput->m_placeholderLabel->setScale(0.6); + respawnInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + respawnInput->m_textLabel->setScale(0.6); respawnInput->setMaxLabelScale(0.7f); respawnInput->setMouseEnabled(true); respawnInput->setTouchEnabled(true); @@ -1249,7 +1249,7 @@ void RecordLayer::updateTPS() { tpsInput->setID(""); tpsBg->setOpacity(75); tpsToggle->setEnabled(true); - tpsInput->m_placeholderLabel->setOpacity(255); + tpsInput->m_textLabel->setOpacity(255); tpsInput->detachWithIME(); tpsInput->onClickTrackNode(false); @@ -1265,7 +1265,7 @@ void RecordLayer::updateTPS() { tpsInput->setID("disabled-input"_spr); tpsBg->setOpacity(30); tpsToggle->setEnabled(false); - tpsInput->m_placeholderLabel->setOpacity(120); + tpsInput->m_textLabel->setOpacity(120); tpsInput->detachWithIME(); tpsInput->onClickTrackNode(false); diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index 3eb47f7b..6974d7a7 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -129,7 +129,7 @@ bool RenderSettingsLayer::setup() { argsInput = CCTextInputNode::create(150, 30, "args", "chatFont.fnt"); argsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); argsInput->ignoreAnchorPointForPosition(true); - argsInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); + argsInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); argsInput->setPosition(ccp(25, 86)); argsInput->setLabelPlaceholderColor(ccc3(163, 135, 121)); argsInput->setMouseEnabled(true); @@ -165,7 +165,7 @@ bool RenderSettingsLayer::setup() { audioArgsInput = CCTextInputNode::create(150, 30, "audio args", "chatFont.fnt"); audioArgsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); audioArgsInput->ignoreAnchorPointForPosition(true); - audioArgsInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); + audioArgsInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); audioArgsInput->setPosition(ccp(18, 53)); audioArgsInput->setLabelPlaceholderColor(ccc3(163, 135, 121)); audioArgsInput->setMouseEnabled(true); @@ -199,7 +199,7 @@ bool RenderSettingsLayer::setup() { videoArgsInput = CCTextInputNode::create(150, 30, "video args", "chatFont.fnt"); videoArgsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); videoArgsInput->ignoreAnchorPointForPosition(true); - videoArgsInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); + videoArgsInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); videoArgsInput->setPosition({19, 22}); videoArgsInput->setLabelPlaceholderColor(ccc3(163, 135, 121)); videoArgsInput->setMouseEnabled(true); @@ -229,7 +229,7 @@ bool RenderSettingsLayer::setup() { secondsInput = CCTextInputNode::create(150, 30, "sec", "chatFont.fnt"); secondsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); secondsInput->ignoreAnchorPointForPosition(true); - secondsInput->m_placeholderLabel->setAnchorPoint({ 0.5f, 0.5f }); + secondsInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); secondsInput->setPosition(ccp(50, -8)); secondsInput->setLabelPlaceholderColor(ccc3(163, 135, 121)); secondsInput->setMouseEnabled(true); @@ -467,22 +467,22 @@ bool RenderSettingsLayer::setup() { menu->addChild(btn); if (usingApi) { - argsInput->m_placeholderLabel->setOpacity(100); - audioArgsInput->m_placeholderLabel->setOpacity(100); + argsInput->m_textLabel->setOpacity(100); + audioArgsInput->m_textLabel->setOpacity(100); argsInput->setID("disabled-input"_spr); audioArgsInput->setID("disabled-input"_spr); extensionInput->setEnabled(false); - extensionInput->getInputNode()->m_placeholderLabel->setOpacity(100); + extensionInput->getInputNode()->m_textLabel->setOpacity(100); extensionInput->getBGSprite()->setOpacity(40); fadeOutInput->setEnabled(false); - fadeOutInput->getInputNode()->m_placeholderLabel->setOpacity(100); + fadeOutInput->getInputNode()->m_textLabel->setOpacity(100); fadeOutInput->getBGSprite()->setOpacity(40); fadeInInput->setEnabled(false); - fadeInInput->getInputNode()->m_placeholderLabel->setOpacity(100); + fadeInInput->getInputNode()->m_textLabel->setOpacity(100); fadeInInput->getBGSprite()->setOpacity(40); onlySongToggle->setCascadeOpacityEnabled(true); From 00afbcea8db0776d84c08c309dd2bec06cf43d45 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 01:59:38 +0300 Subject: [PATCH 002/211] macos and ios action --- .github/workflows/multi-platform.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/multi-platform.yml b/.github/workflows/multi-platform.yml index ef3d0807..53a960cd 100644 --- a/.github/workflows/multi-platform.yml +++ b/.github/workflows/multi-platform.yml @@ -15,6 +15,9 @@ jobs: - name: Windows os: windows-latest build-type: RelWithDebInfo + + - name: macOS + os: macos-latest - name: Android32 os: ubuntu-latest @@ -23,6 +26,10 @@ jobs: - name: Android64 os: ubuntu-latest target: Android64 + + - name: iOS + os: macos-latest + target: iOS name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} From d03e73e3ae61264b6b449c0e59f3bba6def5de58 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:02:14 +0300 Subject: [PATCH 003/211] jailOS support --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16f99a66..27c06891 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,11 @@ cmake_minimum_required(VERSION 3.21) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") +if ("${CMAKE_SYSTEM_NAME}" STREQUAL "iOS" OR IOS) + set(CMAKE_OSX_ARCHITECTURES "arm64") +else() + set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") +endif() set(CMAKE_CXX_VISIBILITY_PRESET hidden) project(xdBot2 VERSION 1.0.0) @@ -46,4 +50,4 @@ endif() add_subdirectory($ENV{GEODE_SDK} ${CMAKE_CURRENT_BINARY_DIR}/geode) -setup_geode_mod(${PROJECT_NAME}) \ No newline at end of file +setup_geode_mod(${PROJECT_NAME}) From 3e3e8e5cc40035e05f75b5b058255c3b55d2edba Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:07:41 +0300 Subject: [PATCH 004/211] i hope this will fix it --- src/keybinds.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index ca9f968b..62503035 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -67,6 +67,7 @@ namespace keybinds { using namespace keybinds; +#if !defined(GEODE_IS_IOS) && !defined(GEODE_IS_MACOS) void onKeybind(bool down, ActionID id) { #ifdef GEODE_IS_WINDOWS @@ -137,6 +138,7 @@ void onKeybind(bool down, ActionID id) { } #endif +#endif } From adf0304a6b6afe6ea267eaf8d3f46227506e40fb Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:10:16 +0300 Subject: [PATCH 005/211] oops --- src/keybinds.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 62503035..f1b6c7d1 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -138,9 +138,8 @@ void onKeybind(bool down, ActionID id) { } #endif -#endif - } +#endif $execute{ From 46b7b3c70dbf1ae4c93d8b42f8d66b6b5b0fe02f Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:13:14 +0300 Subject: [PATCH 006/211] alright lets see this --- src/keybinds.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index f1b6c7d1..f97d27d1 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -55,19 +55,8 @@ class $modify(CCKeyboardDispatcher) { } }; -#ifdef GEODE_IS_ANDROID - -namespace keybinds { - - struct ActionID {}; - -}; - -#endif - using namespace keybinds; -#if !defined(GEODE_IS_IOS) && !defined(GEODE_IS_MACOS) void onKeybind(bool down, ActionID id) { #ifdef GEODE_IS_WINDOWS @@ -138,8 +127,8 @@ void onKeybind(bool down, ActionID id) { } #endif + } -#endif $execute{ From 872a8e82364d2b37eec4cc3e2a2fc99eb6e85fdd Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:18:38 +0300 Subject: [PATCH 007/211] ok --- src/keybinds.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index f97d27d1..8bc60e27 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -55,10 +55,21 @@ class $modify(CCKeyboardDispatcher) { } }; +#ifdef GEODE_IS_MOBILE + +namespace keybinds { + + struct ActionID {}; + +}; + +#endif + using namespace keybinds; void onKeybind(bool down, ActionID id) { #ifdef GEODE_IS_WINDOWS +#ifdef GEODE_IS_MACOS auto& g = Global::get(); @@ -127,8 +138,8 @@ void onKeybind(bool down, ActionID id) { } #endif - } +#endif $execute{ From 0f45ddf6f03504a41367f86fb5cd85be9e513728 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:19:40 +0300 Subject: [PATCH 008/211] oopsss --- src/keybinds.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 8bc60e27..a8e0bf80 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -144,6 +144,7 @@ void onKeybind(bool down, ActionID id) { $execute{ #ifdef GEODE_IS_WINDOWS + #ifdef GEODE_IS_MACOS BindManager * bm = BindManager::get(); @@ -235,3 +236,4 @@ void onKeybind(bool down, ActionID id) { #endif } +#endif From 42a720e5fd0994ee3a36d20a3acdce0dffd0db1f Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:25:58 +0300 Subject: [PATCH 009/211] asdklasdlkasdlk --- src/keybinds.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index a8e0bf80..c4a8a870 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -1,4 +1,3 @@ - #include "includes.hpp" #include "ui/record_layer.hpp" #include "ui/game_ui.hpp" @@ -67,6 +66,7 @@ namespace keybinds { using namespace keybinds; +#if !defined(GEODE_IS_IOS) && !defined(GEODE_IS_MACOS) void onKeybind(bool down, ActionID id) { #ifdef GEODE_IS_WINDOWS #ifdef GEODE_IS_MACOS @@ -143,8 +143,8 @@ void onKeybind(bool down, ActionID id) { $execute{ - #ifdef GEODE_IS_WINDOWS - #ifdef GEODE_IS_MACOS +#ifdef GEODE_IS_WINDOWS +#ifdef GEODE_IS_MACOS BindManager * bm = BindManager::get(); @@ -234,6 +234,7 @@ void onKeybind(bool down, ActionID id) { }, InvokeBindFilter(nullptr, (""_spr) + keybindIDs[i])); } - #endif -} #endif +#endif + +} From ee7019de7d04d55be542bdc8324d22bd0b0b60ae Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:28:27 +0300 Subject: [PATCH 010/211] aldalsdajlsdj --- src/keybinds.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index c4a8a870..078dccea 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -68,8 +68,7 @@ using namespace keybinds; #if !defined(GEODE_IS_IOS) && !defined(GEODE_IS_MACOS) void onKeybind(bool down, ActionID id) { -#ifdef GEODE_IS_WINDOWS -#ifdef GEODE_IS_MACOS +#if defined(GEODE_IS_WINDOWS) || defined(GEODE_IS_MACOS) auto& g = Global::get(); @@ -137,9 +136,9 @@ void onKeybind(bool down, ActionID id) { } } -#endif +#endif // GEODE_IS_WINDOWS || GEODE_IS_MACOS } -#endif +#endif // !GEODE_IS_IOS && !GEODE_IS_MACOS $execute{ From 945eb85392db8ac46cafa34d51f43803d44f5e0d Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:32:36 +0300 Subject: [PATCH 011/211] o --- src/utils/utils.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 1a647fc3..201530ed 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -25,6 +25,7 @@ std::string Utils::narrow(const wchar_t* str) { return result; #else +#if !defined (GEODE_IS_IOS) && !defined (GEODE_IS_MACOS) int size = WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr); if (size <= 0) { return ""; @@ -41,6 +42,7 @@ std::string Utils::narrow(const wchar_t* str) { return result; #endif +#endif } std::wstring Utils::widen(const char* str) { From 68f4718796d3938900076eb566d087bf1e3146a4 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:34:44 +0300 Subject: [PATCH 012/211] w --- src/utils/utils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 201530ed..a0c2275b 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -58,7 +58,7 @@ std::wstring Utils::widen(const char* str) { return result; #else - +#if !defined (GEODE_IS_IOS) && !defined (GEODE_IS_MACOS) if (str == nullptr) { return L"Widen Error"; } @@ -82,6 +82,7 @@ std::wstring Utils::widen(const char* str) { delete[] buffer; return result; +#endif #endif } From 68d4071575c568b83fcf8db2cd2f882a94b95f8c Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:45:23 +0300 Subject: [PATCH 013/211] idk at this point --- src/keybinds.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 078dccea..fb40a79c 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -64,10 +64,8 @@ namespace keybinds { #endif -using namespace keybinds; - -#if !defined(GEODE_IS_IOS) && !defined(GEODE_IS_MACOS) -void onKeybind(bool down, ActionID id) { +#if !defined(GEODE_IS_IOS) +void onKeybind(bool down, keybinds::ActionID id) { #if defined(GEODE_IS_WINDOWS) || defined(GEODE_IS_MACOS) auto& g = Global::get(); From d1f4243a4a5444ceefe47430bb96547f1d43c9e6 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 02:48:08 +0300 Subject: [PATCH 014/211] a --- src/keybinds.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index fb40a79c..91b1914b 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -11,10 +11,12 @@ #include #ifdef GEODE_IS_WINDOWS +#ifdef GEODE_IS_MACOS #include #include +#endif #endif const std::vector keybindIDs = { @@ -64,6 +66,11 @@ namespace keybinds { #endif +#if defined (GEODE_IS_WINDOWS) && defined (GEODE_IS_MACOS) +using namespace keybinds; + +#endif + #if !defined(GEODE_IS_IOS) void onKeybind(bool down, keybinds::ActionID id) { #if defined(GEODE_IS_WINDOWS) || defined(GEODE_IS_MACOS) From 96a8d4afe46e43f6e500451d2805f77d4ff07e0d Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 04:20:20 +0300 Subject: [PATCH 015/211] waaa --- src/keybinds.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 91b1914b..6e7657ca 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -10,13 +10,11 @@ #include #include -#ifdef GEODE_IS_WINDOWS -#ifdef GEODE_IS_MACOS +#if defined(GEODE_IS_WINDOWS) && defined(GEODE_IS_MACOS) #include #include -#endif #endif const std::vector keybindIDs = { @@ -69,10 +67,7 @@ namespace keybinds { #if defined (GEODE_IS_WINDOWS) && defined (GEODE_IS_MACOS) using namespace keybinds; -#endif - -#if !defined(GEODE_IS_IOS) -void onKeybind(bool down, keybinds::ActionID id) { +void onKeybind(bool down, ActionID id) { #if defined(GEODE_IS_WINDOWS) || defined(GEODE_IS_MACOS) auto& g = Global::get(); From 6d10d68432835eb2515c4f1ada2f2778fe857c24 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 04:35:32 +0300 Subject: [PATCH 016/211] oo --- src/ui/button_edit_layer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/button_edit_layer.cpp b/src/ui/button_edit_layer.cpp index ed11ea97..990dd836 100644 --- a/src/ui/button_edit_layer.cpp +++ b/src/ui/button_edit_layer.cpp @@ -114,12 +114,12 @@ void ButtonEditLayer::updateSelectedLabels() { oss << std::fixed << std::setprecision(1) << scale; - scaleLbl->setString(std::format("Scale ({})", oss.str()).c_str()); + scaleLbl->setString(fmt::format("Scale ({})", oss.str()).c_str()); std::ostringstream oss2; oss2 << std::fixed << std::setprecision(1) << opacity; - opacityLbl->setString(std::format("Opacity ({})", oss2.str()).c_str()); + opacityLbl->setString(fmt::format("Opacity ({})", oss2.str()).c_str()); } void ButtonEditLayer::updateSelected(std::string selected) { From 770f7aab5b10a52dcafa5aaa001a2c2a005b70c6 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 05:22:35 +0300 Subject: [PATCH 017/211] hhhhhh --- src/renderer/renderer.cpp | 4 +++- src/renderer/renderer.hpp | 4 +++- src/ui/record_layer.cpp | 10 +++++++++- src/ui/record_layer.hpp | 2 ++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index e7e38d47..ab46383c 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -15,6 +15,7 @@ #include #include +#ifndef GEODE_IS_IOS class $modify(CCParticleSystemQuad) { static CCParticleSystemQuad* create(const char* v1, bool v2) { @@ -836,4 +837,5 @@ void Renderer::handleAudioRecording(PlayLayer* pl, int frame) { } else g.renderer.stopAudio(); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/renderer/renderer.hpp b/src/renderer/renderer.hpp index 9948e986..74023ea3 100644 --- a/src/renderer/renderer.hpp +++ b/src/renderer/renderer.hpp @@ -1,6 +1,7 @@ #include "../includes.hpp" #include "ffmpeg/events.hpp" +#ifndef GEODE_IS_IOS enum AudioMode { Off = 0, Song = 1, @@ -76,4 +77,5 @@ class Renderer { static bool toggle(); static bool shouldUseAPI(); bool tryPause(); -}; \ No newline at end of file +}; +#endif \ No newline at end of file diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 76c63029..91bf59bf 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -267,6 +267,10 @@ void RecordLayer::toggleRender(CCObject* btn) { static_cast(btn)->toggle(false); } +void RecordLayer::toggleRenderIOS(CCObject* btn) { + FLAlertLayer::create("Info", "Rendering on iOS is not supported yet!", "OK")->show(); +} + void RecordLayer::onEditMacro(CCObject*) { MacroEditLayer::open(); } @@ -919,12 +923,16 @@ bool RecordLayer::setup() { spriteOn2->setScale(0.74f); ButtonSprite* spriteOff2 = ButtonSprite::create("Start"); spriteOff2->setScale(0.74f); - + + #ifdef GEODE_IS_IOS + renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRenderIOS)); + #else renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRender)); renderToggle->toggle(g.renderer.recording || g.renderer.recordingAudio); renderToggle->setPosition(ccp(-65.5, -100)); menu->addChild(renderToggle); + #endif spr = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png"); spr->setScale(0.65f); diff --git a/src/ui/record_layer.hpp b/src/ui/record_layer.hpp index e7aef5a0..f4954bfa 100644 --- a/src/ui/record_layer.hpp +++ b/src/ui/record_layer.hpp @@ -115,6 +115,8 @@ class RecordLayer : public geode::Popup<>, public TextInputDelegate { void togglePlaying(CCObject*); void toggleRender(CCObject* btn); + + void toggleRenderIOS(CCObject* btn); void openPresets(CCObject*); From ffb65418cdc501a858510c0e8b8298023dbc6b6f Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 05:30:02 +0300 Subject: [PATCH 018/211] i hope i can sleep now --- src/main.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 272cf304..2fefcffb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -130,9 +130,10 @@ class $modify(PlayLayer) { auto& g = Global::get(); int frame = Global::getCurrentFrame(); - + #ifndef GEODE_IS_IOS if (!m_isPracticeMode) g.renderer.levelStartFrame = frame; + #endif if (g.restart && m_levelSettings->m_platformerMode && g.state != state::none) m_fields->delayedLevelRestart = frame + 2; @@ -208,7 +209,7 @@ class $modify(BGLHook, GJBaseGameLayer) { } Global::updateSeed(); - + #ifndef GEODE_IS_IOS bool rendering = g.renderer.recording || g.renderer.recordingAudio; if (g.state != state::none || rendering) { @@ -255,6 +256,7 @@ class $modify(BGLHook, GJBaseGameLayer) { handlePlaying(Global::getCurrentFrame()); } + #endif void handleRecording(int frame) { auto& g = Global::get(); @@ -458,8 +460,10 @@ class $modify(PauseLayer) { Loader::get()->queueInMainThread([] { auto& g = Global::get(); + #ifndef GEODE_IS_IOS if (g.renderer.recording) g.renderer.stop(); if (g.renderer.recordingAudio) g.renderer.stopAudio(); + #endif }); } @@ -470,8 +474,10 @@ class $modify(PauseLayer) { Loader::get()->queueInMainThread([] { auto& g = Global::get(); + #ifndef GEODE_IS_IOS if (g.renderer.recording) g.renderer.stop(); if (g.renderer.recordingAudio) g.renderer.stopAudio(); + #endif }); } From 9e638937ffa32ec8e4dbc5ac02d3a798f6c60579 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 05:35:37 +0300 Subject: [PATCH 019/211] CAN I HAVE SOME SLEEP NOW --- src/includes.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/includes.hpp b/src/includes.hpp index db9501e0..5fbe11e8 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -82,7 +82,9 @@ class Global { geode::Popup<>* layer = nullptr; Macro macro; + #ifndef GEODE_IS_IOS Renderer renderer; + #endif state state = none; std::unordered_map checkpoints; From 520ea256241ecfb99a430e186a36cad845bc1966 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 05:40:25 +0300 Subject: [PATCH 020/211] Update main.cpp --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 2fefcffb..25a148ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -60,8 +60,9 @@ class $modify(PlayLayer) { void pauseGame(bool b1) { Global::updateKeybinds(); - + #ifndef GEODE_IS_IOS if (!Global::get().renderer.tryPause()) return; + #endif auto& g = Global::get(); From f1bcb2c83c42b121015bff16b534420de4012355 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 05:54:53 +0300 Subject: [PATCH 021/211] Update main.cpp --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 25a148ff..5ec160fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,7 +62,7 @@ class $modify(PlayLayer) { Global::updateKeybinds(); #ifndef GEODE_IS_IOS if (!Global::get().renderer.tryPause()) return; - #endif + #else auto& g = Global::get(); @@ -109,6 +109,7 @@ class $modify(PlayLayer) { PlayLayer::pauseGame(b1); } +#endif bool init(GJGameLevel * level, bool b1, bool b2) { auto& g = Global::get(); From e9529656f9c34b8c0bb6a3edcaf9d9e792e00fa8 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 06:01:04 +0300 Subject: [PATCH 022/211] Update main.cpp --- src/main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5ec160fa..25a148ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,7 +62,7 @@ class $modify(PlayLayer) { Global::updateKeybinds(); #ifndef GEODE_IS_IOS if (!Global::get().renderer.tryPause()) return; - #else + #endif auto& g = Global::get(); @@ -109,7 +109,6 @@ class $modify(PlayLayer) { PlayLayer::pauseGame(b1); } -#endif bool init(GJGameLevel * level, bool b1, bool b2) { auto& g = Global::get(); From 4d65eba3f8a0a7335cbe1ed2f7de52ca4f740528 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 06:12:32 +0300 Subject: [PATCH 023/211] Update main.cpp --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 25a148ff..3337aacf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -219,7 +219,7 @@ class $modify(BGLHook, GJBaseGameLayer) { g.renderer.dontRender = false; g.renderer.dontRecordAudio = false; } - + #endif int frame = Global::getCurrentFrame(); if (frame > 2 && g.firstAttempt && g.macro.xdBotMacro) { g.firstAttempt = false; From 0b7a94f50aee7ce2b1c18485f5da354c9dd54064 Mon Sep 17 00:00:00 2001 From: Sergei Baigerov Date: Sun, 29 Jun 2025 11:35:47 +0800 Subject: [PATCH 024/211] fix if statement i hope --- src/main.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3337aacf..1ad972f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -210,16 +210,15 @@ class $modify(BGLHook, GJBaseGameLayer) { } Global::updateSeed(); - #ifndef GEODE_IS_IOS bool rendering = g.renderer.recording || g.renderer.recordingAudio; if (g.state != state::none || rendering) { - + #ifndef GEODE_IS_IOS if (!g.firstAttempt) { g.renderer.dontRender = false; g.renderer.dontRecordAudio = false; } - #endif + #endif int frame = Global::getCurrentFrame(); if (frame > 2 && g.firstAttempt && g.macro.xdBotMacro) { g.firstAttempt = false; From 24b85a1dc3cb4f4ec54113d7423ce04692394f01 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 14:57:54 +0300 Subject: [PATCH 025/211] Update main.cpp --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1ad972f8..28a1f22f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -212,13 +212,13 @@ class $modify(BGLHook, GJBaseGameLayer) { Global::updateSeed(); bool rendering = g.renderer.recording || g.renderer.recordingAudio; - if (g.state != state::none || rendering) { #ifndef GEODE_IS_IOS + if (g.state != state::none || rendering) { if (!g.firstAttempt) { g.renderer.dontRender = false; g.renderer.dontRecordAudio = false; } - #endif + #endif int frame = Global::getCurrentFrame(); if (frame > 2 && g.firstAttempt && g.macro.xdBotMacro) { g.firstAttempt = false; From 55b00cf891e6f012369f740dba02a8a179bfd43d Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:01:56 +0300 Subject: [PATCH 026/211] Update main.cpp --- src/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 28a1f22f..0699e774 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -212,13 +212,11 @@ class $modify(BGLHook, GJBaseGameLayer) { Global::updateSeed(); bool rendering = g.renderer.recording || g.renderer.recordingAudio; - #ifndef GEODE_IS_IOS if (g.state != state::none || rendering) { if (!g.firstAttempt) { g.renderer.dontRender = false; g.renderer.dontRecordAudio = false; } - #endif int frame = Global::getCurrentFrame(); if (frame > 2 && g.firstAttempt && g.macro.xdBotMacro) { g.firstAttempt = false; From 295db95d284f2d41bfd7dee529ee4cf46ed8ed9b Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:04:46 +0300 Subject: [PATCH 027/211] am i allowed to swear in commit messages on github --- src/main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0699e774..cfb24167 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -213,19 +213,22 @@ class $modify(BGLHook, GJBaseGameLayer) { bool rendering = g.renderer.recording || g.renderer.recordingAudio; if (g.state != state::none || rendering) { + #ifndef GEODE_IS_IOS if (!g.firstAttempt) { g.renderer.dontRender = false; g.renderer.dontRecordAudio = false; } + #endif int frame = Global::getCurrentFrame(); if (frame > 2 && g.firstAttempt && g.macro.xdBotMacro) { g.firstAttempt = false; - + #ifndef GEODE_IS_IOS if ((m_levelSettings->m_platformerMode || rendering) && !m_levelEndAnimationStarted) return pl->resetLevelFromStart(); else if (!m_levelEndAnimationStarted) return pl->resetLevel(); } + #endif if (g.previousFrame == frame && frame != 0 && g.macro.xdBotMacro) return GJBaseGameLayer::processCommands(dt); @@ -254,7 +257,6 @@ class $modify(BGLHook, GJBaseGameLayer) { handlePlaying(Global::getCurrentFrame()); } - #endif void handleRecording(int frame) { auto& g = Global::get(); From bfab870ea36b1685b37242525db058700b9e6b91 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:07:30 +0300 Subject: [PATCH 028/211] Update main.cpp --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index cfb24167..ddc80d69 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -210,10 +210,10 @@ class $modify(BGLHook, GJBaseGameLayer) { } Global::updateSeed(); + #ifndef GEODE_IS_IOS bool rendering = g.renderer.recording || g.renderer.recordingAudio; if (g.state != state::none || rendering) { - #ifndef GEODE_IS_IOS if (!g.firstAttempt) { g.renderer.dontRender = false; g.renderer.dontRecordAudio = false; From 9f8819dd05298ecb5974837891ebd2d613857bd6 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:15:43 +0300 Subject: [PATCH 029/211] ignore indentation --- src/main.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ddc80d69..1fe3c5b5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -243,12 +243,19 @@ class $modify(BGLHook, GJBaseGameLayer) { int frame = Global::getCurrentFrame(); g.previousFrame = frame; - if (g.macro.xdBotMacro && g.restart && !m_levelEndAnimationStarted) { - if ((m_levelSettings->m_platformerMode && g.state != state::none) || g.renderer.recording || g.renderer.recordingAudio) - return pl->resetLevelFromStart(); - else - return pl->resetLevel(); - } +if (g.macro.xdBotMacro && g.restart && !m_levelEndAnimationStarted) { + #ifndef GEODE_IS_IOS + if ((m_levelSettings->m_platformerMode && g.state != state::none || g.renderer.recordingAudio)) + return pl->resetLevelFromStart(); + else + return pl->resetLevel(); + #else + if (m_levelSettings->m_platformerMode && g.state != state::none) + return pl->resetLevelFromStart(); + else + return pl->resetLevel(); + #endif +} if (g.state == state::recording) handleRecording(frame); From c28ca1ff9536f4348158c21fbd19c30241598320 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:19:06 +0300 Subject: [PATCH 030/211] O --- src/main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1fe3c5b5..e8fabd44 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -224,14 +224,14 @@ class $modify(BGLHook, GJBaseGameLayer) { g.firstAttempt = false; #ifndef GEODE_IS_IOS if ((m_levelSettings->m_platformerMode || rendering) && !m_levelEndAnimationStarted) - return pl->resetLevelFromStart(); + return pl->resetLevelFromStart(); else if (!m_levelEndAnimationStarted) - return pl->resetLevel(); + return pl->resetLevel(); + #endif } - #endif if (g.previousFrame == frame && frame != 0 && g.macro.xdBotMacro) - return GJBaseGameLayer::processCommands(dt); + return GJBaseGameLayer::processCommands(dt); } From d0b684698d4c4393893c4f429dcc3089b8ca12d7 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:22:10 +0300 Subject: [PATCH 031/211] WHY DO THE MOST STUPIDIEST ERRORS HAPPEN ON IOS --- src/main.cpp | 333 +++++++++++++++++++++++++-------------------------- 1 file changed, 166 insertions(+), 167 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e8fabd44..566551cc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,70 +9,70 @@ #include $execute { - + geode::listenForSettingChanges("macro_accuracy", +[](std::string value) { auto& g = Global::get(); g.frameFixes = false; g.inputFixes = false; - + if (value == "Frame Fixes") g.frameFixes = true; if (value == "Input Fixes") g.inputFixes = true; }); - + geode::listenForSettingChanges("frame_fixes_limit", +[](int64_t value) { Global::get().frameFixesLimit = value; }); - + geode::listenForSettingChanges("lock_delta", +[](bool value) { Global::get().lockDelta = value; }); - + geode::listenForSettingChanges("auto_stop_playing", +[](bool value) { Global::get().stopPlaying = value; }); - + }; class $modify(PlayLayer) { - + struct Fields { int delayedLevelRestart = -1; }; - + void postUpdate(float dt) { PlayLayer::postUpdate(dt); auto& g = Global::get(); - + if (m_fields->delayedLevelRestart != -1 && m_fields->delayedLevelRestart >= Global::getCurrentFrame()) { m_fields->delayedLevelRestart = -1; resetLevelFromStart(); } - + } - + void onQuit() { if (Mod::get()->getSettingValue("disable_speedhack") && Global::get().speedhackEnabled) - Global::toggleSpeedhack(); - + Global::toggleSpeedhack(); + PlayLayer::onQuit(); } - + void pauseGame(bool b1) { Global::updateKeybinds(); #ifndef GEODE_IS_IOS if (!Global::get().renderer.tryPause()) return; #endif - + auto& g = Global::get(); - + if (!m_player1 || !m_player2) return PlayLayer::pauseGame(b1); - + if (g.state != state::recording) return PlayLayer::pauseGame(b1); - + g.ignoreRecordAction = true; int frame = Global::getCurrentFrame() + 1; - + if (m_player1->m_holdingButtons[1]) { handleButton(false, 1, false); g.macro.inputs.push_back(input(frame, 1, false, false)); @@ -87,7 +87,7 @@ class $modify(PlayLayer) { g.macro.inputs.push_back(input(frame, 3, false, false)); } } - + if (m_levelSettings->m_twoPlayerMode) { if (m_player2->m_holdingButtons[1]) { handleButton(false, 1, true); @@ -104,116 +104,117 @@ class $modify(PlayLayer) { } } } - + g.ignoreRecordAction = false; - + PlayLayer::pauseGame(b1); } - + bool init(GJGameLevel * level, bool b1, bool b2) { auto& g = Global::get(); g.firstAttempt = true; - + if (!PlayLayer::init(level, b1, b2)) return false; - + Global::updateKeybinds(); - + auto now = std::chrono::system_clock::now(); g.currentSession = std::chrono::duration_cast(now.time_since_epoch()).count(); g.lastAutoSaveFrame = 0; - + return true; } - + void resetLevel() { PlayLayer::resetLevel(); - + auto& g = Global::get(); - + int frame = Global::getCurrentFrame(); #ifndef GEODE_IS_IOS if (!m_isPracticeMode) - g.renderer.levelStartFrame = frame; + g.renderer.levelStartFrame = frame; #endif - + if (g.restart && m_levelSettings->m_platformerMode && g.state != state::none) - m_fields->delayedLevelRestart = frame + 2; - + m_fields->delayedLevelRestart = frame + 2; + Global::updateSeed(true); - + g.safeMode = false; - + if (g.layoutMode) - g.safeMode = true; - + g.safeMode = true; + g.currentAction = 0; g.currentFrameFix = 0; g.restart = false; - + if (g.state == state::recording) - Macro::updateInfo(this); - + Macro::updateInfo(this); + if ((!m_isPracticeMode || frame <= 1 || g.checkpoints.empty()) && g.state == state::recording) { g.macro.inputs.clear(); g.macro.frameFixes.clear(); g.checkpoints.clear(); - + g.macro.framerate = 240.f; if (g.layer) static_cast(g.layer)->updateTPS(); - + PlayerData p1Data = PlayerPracticeFixes::saveData(m_player1); PlayerData p2Data = PlayerPracticeFixes::saveData(m_player2); - + InputPracticeFixes::applyFixes(this, p1Data, p2Data, frame); Macro::resetVariables(); - + m_player1->m_holdingRight = false; m_player1->m_holdingLeft = false; m_player2->m_holdingRight = false; m_player2->m_holdingLeft = false; - + m_player1->m_holdingButtons[2] = false; m_player1->m_holdingButtons[3] = false; m_player2->m_holdingButtons[2] = false; m_player2->m_holdingButtons[3] = false; } - + if (!m_levelSettings->m_platformerMode || (!g.mod->getSavedValue("macro_always_practice_fixes") && g.state != state::recording)) return; - + g.ignoreRecordAction = true; for (int i = 0; i < 4; i++) { bool player2 = !(sidesButtons[i] > 2); bool rightKey = sidesButtons[i] == 5 || sidesButtons[i] == 2; if (g.heldButtons[sidesButtons[i]]) - handleButton(true, indexButton[sidesButtons[i]], player2); + handleButton(true, indexButton[sidesButtons[i]], player2); } g.ignoreRecordAction = false; } - + }; class $modify(BGLHook, GJBaseGameLayer) { - + struct Fields { bool macroInput = false; }; - + void processCommands(float dt) { auto& g = Global::get(); - PlayLayer* pl = PlayLayer::get(); - + if (!pl) { - // handlePlaying(Global::getCurrentFrame(true)); - // log::debug("{}", Global::getCurrentFrame(true)); return GJBaseGameLayer::processCommands(dt); } - + Global::updateSeed(); + + bool rendering = false; #ifndef GEODE_IS_IOS - bool rendering = g.renderer.recording || g.renderer.recordingAudio; - + rendering = g.renderer.recording || g.renderer.recordingAudio; + #endif + if (g.state != state::none || rendering) { + #ifndef GEODE_IS_IOS if (!g.firstAttempt) { g.renderer.dontRender = false; g.renderer.dontRecordAudio = false; @@ -224,81 +225,79 @@ class $modify(BGLHook, GJBaseGameLayer) { g.firstAttempt = false; #ifndef GEODE_IS_IOS if ((m_levelSettings->m_platformerMode || rendering) && !m_levelEndAnimationStarted) - return pl->resetLevelFromStart(); + return pl->resetLevelFromStart(); else if (!m_levelEndAnimationStarted) - return pl->resetLevel(); + return pl->resetLevel(); #endif } - + if (g.previousFrame == frame && frame != 0 && g.macro.xdBotMacro) - return GJBaseGameLayer::processCommands(dt); - + return GJBaseGameLayer::processCommands(dt); } - + GJBaseGameLayer::processCommands(dt); - + if (g.state == state::none) - return; - + return; + int frame = Global::getCurrentFrame(); g.previousFrame = frame; - -if (g.macro.xdBotMacro && g.restart && !m_levelEndAnimationStarted) { - #ifndef GEODE_IS_IOS - if ((m_levelSettings->m_platformerMode && g.state != state::none || g.renderer.recordingAudio)) - return pl->resetLevelFromStart(); - else - return pl->resetLevel(); - #else - if (m_levelSettings->m_platformerMode && g.state != state::none) - return pl->resetLevelFromStart(); - else - return pl->resetLevel(); - #endif -} - + + if (g.macro.xdBotMacro && g.restart && !m_levelEndAnimationStarted) { + #ifndef GEODE_IS_IOS + if ((m_levelSettings->m_platformerMode && g.state != state::none) || g.renderer.recordingAudio) + return pl->resetLevelFromStart(); + else + return pl->resetLevel(); + #else + if (m_levelSettings->m_platformerMode && g.state != state::none) + return pl->resetLevelFromStart(); + else + return pl->resetLevel(); + #endif + } + if (g.state == state::recording) - handleRecording(frame); - + handleRecording(frame); + if (g.state == state::playing) - handlePlaying(Global::getCurrentFrame()); - + handlePlaying(Global::getCurrentFrame()); } - + void handleRecording(int frame) { auto& g = Global::get(); - + if (g.ignoreFrame != -1) { if (g.ignoreFrame < frame) g.ignoreFrame = -1; } - + bool twoPlayers = m_levelSettings->m_twoPlayerMode; - + if (g.delayedFrameInput[0] == frame) { g.delayedFrameInput[0] = -1; // if ((g.heldButtons[0] && twoPlayers) || (!twoPlayers && (g.heldButtons[0] || g.heldButtons[3]))) - GJBaseGameLayer::handleButton(true, 1, true); + GJBaseGameLayer::handleButton(true, 1, true); } - + if (g.delayedFrameInput[1] == frame) { g.delayedFrameInput[1] = -1; // if ((g.heldButtons[3] && twoPlayers) || (!twoPlayers && (g.heldButtons[0] || g.heldButtons[3]))) - GJBaseGameLayer::handleButton(true, 1, false); + GJBaseGameLayer::handleButton(true, 1, false); } - + if (frame > g.ignoreJumpButton && g.ignoreJumpButton != -1) - g.ignoreJumpButton = -1; - + g.ignoreJumpButton = -1; + for (int x = 0; x < 2; x++) { if (g.delayedFrameReleaseMain[x] == frame) { bool player2 = x == 0; g.delayedFrameReleaseMain[x] = -1; GJBaseGameLayer::handleButton(false, 1, twoPlayers ? player2 : false); } - + if (!m_levelSettings->m_platformerMode) - continue; - + continue; + for (int y = 0; y < 2; y++) { if (g.delayedFrameRelease[x][y] == frame) { int button = y == 0 ? 2 : 3; @@ -308,163 +307,163 @@ if (g.macro.xdBotMacro && g.restart && !m_levelEndAnimationStarted) { } } } - + if (!g.frameFixes || g.macro.inputs.empty()) return; - + if (!g.macro.frameFixes.empty()) - if (1.f / Global::getTPS() * (frame - g.macro.frameFixes.back().frame) < 1.f / g.frameFixesLimit) - return; - + if (1.f / Global::getTPS() * (frame - g.macro.frameFixes.back().frame) < 1.f / g.frameFixesLimit) + return; + g.macro.recordFrameFix(frame, m_player1, m_player2); - + } - + void handlePlaying(int frame) { auto& g = Global::get(); if (m_levelEndAnimationStarted) return; - + if (m_player1->m_isDead) { m_player1->releaseAllButtons(); m_player2->releaseAllButtons(); return; } - + m_fields->macroInput = true; - + while (g.currentAction < g.macro.inputs.size() && frame >= g.macro.inputs[g.currentAction].frame) { auto input = g.macro.inputs[g.currentAction]; - + if (frame != g.respawnFrame) { if (Macro::flipControls()) - input.player2 = !input.player2; - + input.player2 = !input.player2; + GJBaseGameLayer::handleButton(input.down, input.button, input.player2); } - + g.currentAction++; g.safeMode = true; } - + g.respawnFrame = -1; m_fields->macroInput = false; - + if (g.currentAction == g.macro.inputs.size()) { if (g.stopPlaying) { Macro::togglePlaying(); Macro::resetState(true); - + return; } } - + if ((!g.frameFixes && !g.inputFixes) || !PlayLayer::get()) return; - + while (g.currentFrameFix < g.macro.frameFixes.size() && frame >= g.macro.frameFixes[g.currentFrameFix].frame) { auto& fix = g.macro.frameFixes[g.currentFrameFix]; - + PlayerObject* p1 = m_player1; PlayerObject* p2 = m_player2; - + cocos2d::CCPoint pos1 = p1->getPosition(); cocos2d::CCPoint pos2 = p2->getPosition(); - + if (fix.p1.pos.x != 0.f && fix.p1.pos.y != 0.f) - p1->setPosition(fix.p1.pos); - + p1->setPosition(fix.p1.pos); + if (fix.p1.rotate && fix.p1.rotation != 0.f) - p1->setRotation(fix.p1.rotation); - + p1->setRotation(fix.p1.rotation); + if (m_gameState.m_isDualMode) { if (fix.p2.pos.x != 0.f && fix.p2.pos.y != 0.f) - p2->setPosition(fix.p2.pos); - + p2->setPosition(fix.p2.pos); + if (fix.p2.rotate && fix.p2.rotation != 0.f) - p2->setRotation(fix.p2.rotation); + p2->setRotation(fix.p2.rotation); } - + g.currentFrameFix++; } - + } - + void handleButton(bool hold, int button, bool player2) { auto& g = Global::get(); - + if (g.p2mirror && m_gameState.m_isDualMode && !g.autoclicker) { GJBaseGameLayer::handleButton(g.mod->getSavedValue("p2_input_mirror_inverted") ? !hold : hold, button, !player2); } - + if (g.state == state::none) - return GJBaseGameLayer::handleButton(hold, button, player2); - + return GJBaseGameLayer::handleButton(hold, button, player2); + if (g.state == state::playing) { if (g.mod->getSavedValue("macro_ignore_inputs") && !m_fields->macroInput) - return; + return; else return GJBaseGameLayer::handleButton(hold, button, player2); - + } else if (g.ignoreFrame != -1 && hold) - return; - + return; + int frame = Global::getCurrentFrame(); - + if (frame >= 10 && hold) - Global::hasIncompatibleMods(); - + Global::hasIncompatibleMods(); + bool isDelayedInput = g.delayedFrameInput[(m_levelSettings->m_twoPlayerMode ? static_cast(!player2) : 0)] != -1; bool isDelayedRelease = g.delayedFrameReleaseMain[(m_levelSettings->m_twoPlayerMode ? static_cast(!player2) : 0)] != -1; - + if ((isDelayedInput || g.ignoreJumpButton == frame || isDelayedRelease) && button == 1) { if (g.ignoreJumpButton >= frame) - g.delayedFrameInput[(m_levelSettings->m_twoPlayerMode ? static_cast(!player2) : 0)] = g.ignoreJumpButton + 1; - + g.delayedFrameInput[(m_levelSettings->m_twoPlayerMode ? static_cast(!player2) : 0)] = g.ignoreJumpButton + 1; + return; } - + if (g.state != state::recording) return GJBaseGameLayer::handleButton(hold, button, player2); - + if (g.inputFixes) - g.macro.recordFrameFix(frame, m_player1, m_player2); - + g.macro.recordFrameFix(frame, m_player1, m_player2); + GJBaseGameLayer::handleButton(hold, button, player2); - + if (!m_levelSettings->m_twoPlayerMode) - player2 = false; - + player2 = false; + if (!g.ignoreRecordAction && !g.creatingTrajectory && !m_player1->m_isDead) { g.macro.recordAction(frame, button, player2, hold); if (g.p2mirror && m_gameState.m_isDualMode) - g.macro.recordAction(frame, button, !player2, g.mod->getSavedValue("p2_input_mirror_inverted") ? !hold : hold); + g.macro.recordAction(frame, button, !player2, g.mod->getSavedValue("p2_input_mirror_inverted") ? !hold : hold); } - + } }; class $modify(PauseLayer) { - + void onPracticeMode(CCObject * sender) { PauseLayer::onPracticeMode(sender); if (Global::get().state != state::none) PlayLayer::get()->resetLevel(); } - + void onNormalMode(CCObject * sender) { PauseLayer::onNormalMode(sender); auto& g = Global::get(); - + g.checkpoints.clear(); - + if (g.restart) { if (PlayLayer* pl = PlayLayer::get()) - pl->resetLevel(); + pl->resetLevel(); } - + } - + void onQuit(CCObject * sender) { PauseLayer::onQuit(sender); - + Macro::resetState(); - + Loader::get()->queueInMainThread([] { auto& g = Global::get(); #ifndef GEODE_IS_IOS @@ -473,10 +472,10 @@ class $modify(PauseLayer) { #endif }); } - + void goEdit() { PauseLayer::goEdit(); - + Macro::resetState(); Loader::get()->queueInMainThread([] { @@ -487,5 +486,5 @@ class $modify(PauseLayer) { #endif }); } - + }; From efe93184aa534cd66c9082476e9e05899c594e90 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:28:59 +0300 Subject: [PATCH 032/211] git broke xd --- src/hacks/frame_stepper.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/hacks/frame_stepper.cpp b/src/hacks/frame_stepper.cpp index 958c10e7..114b4965 100644 --- a/src/hacks/frame_stepper.cpp +++ b/src/hacks/frame_stepper.cpp @@ -72,7 +72,7 @@ class $modify(GJBaseGameLayer) { } auto& g = Global::get(); - + #ifndef GEODE_IS_IOS if (!g.renderer.recording && g.frameStepper) { if (g.stepFrameParticle != 0) g.stepFrameParticle--; @@ -89,6 +89,24 @@ class $modify(GJBaseGameLayer) { return; } } + #else + if (g.frameStepper) { + if (g.stepFrameParticle != 0) + g.stepFrameParticle--; + + if (Macro::shouldStep()) { + g.stepFrame = false; + + GJBaseGameLayer::update(1.f / Global::getTPS()); + + return; + } + else { + g.safeMode = true; + return; + } + } + #endif GJBaseGameLayer::update(dt); } @@ -100,7 +118,15 @@ class $modify(CCParticleSystem) { virtual void update(float dt) { auto& g = Global::get(); if (!PlayLayer::get()) return CCParticleSystem::update(dt); - + #ifndef GEODE_IS_IOS + if (!g.renderer.recording && g.frameStepper) { + if (g.stepFrameParticle != 0) { + CCParticleSystem::update(dt); + } + else + return; + } + #else if (!g.renderer.recording && g.frameStepper) { if (g.stepFrameParticle != 0) { CCParticleSystem::update(dt); @@ -108,6 +134,7 @@ class $modify(CCParticleSystem) { else return; } + #endif CCParticleSystem::update(dt); } From 43a00badd6efbfb975943cf901402a76f1c5149d Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:29:14 +0300 Subject: [PATCH 033/211] git broke xd --- src/hacks/other.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hacks/other.cpp b/src/hacks/other.cpp index 0e38ca17..c1dd0279 100644 --- a/src/hacks/other.cpp +++ b/src/hacks/other.cpp @@ -22,13 +22,14 @@ class $modify(CCScheduler) { return CCScheduler::update(dt); } - + #ifndef GEODE_IS_IOS if (g.renderer.recording || g.renderer.recordingAudio) { if (g.currentPitch != 1.f) Global::updatePitch(1.f); return CCScheduler::update(dt); } + #endif float speedhack = 1.f; @@ -129,7 +130,9 @@ class $modify(PlayLayer) { Global::get().safeMode = true; if (getActionByTag(16)) { + #ifndef GEODE_IS_IOS if (Global::get().renderer.recordingAudio) Global::get().renderer.stopAudio(); + #endif if (g.mod->getSavedValue("respawn_time_enabled")) { stopActionByTag(16); @@ -289,4 +292,4 @@ class $modify(GameLevelOptionsLayer) { return ret; } -}; \ No newline at end of file +}; From 604ac8088bce82ec923e1c5892ac856af08f6f12 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:31:13 +0300 Subject: [PATCH 034/211] o i forgor --- src/hacks/frame_stepper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hacks/frame_stepper.cpp b/src/hacks/frame_stepper.cpp index 114b4965..b2b2ad84 100644 --- a/src/hacks/frame_stepper.cpp +++ b/src/hacks/frame_stepper.cpp @@ -127,7 +127,7 @@ class $modify(CCParticleSystem) { return; } #else - if (!g.renderer.recording && g.frameStepper) { + if (g.frameStepper) { if (g.stepFrameParticle != 0) { CCParticleSystem::update(dt); } From 1c56dd779c50b70e5729d9047a1f892c4dfcf493 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:36:11 +0300 Subject: [PATCH 035/211] o what --- src/ui/record_layer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 91bf59bf..80aba42a 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -259,6 +259,7 @@ void RecordLayer::togglePlaying(CCObject*) { this->updateTPS(); } +#ifndef GEODE_IS_IOS void RecordLayer::toggleRender(CCObject* btn) { if (!Renderer::toggle()) static_cast(btn)->toggle(true); @@ -266,10 +267,11 @@ void RecordLayer::toggleRender(CCObject* btn) { if (Global::get().renderer.recordingAudio) static_cast(btn)->toggle(false); } - +#else void RecordLayer::toggleRenderIOS(CCObject* btn) { FLAlertLayer::create("Info", "Rendering on iOS is not supported yet!", "OK")->show(); } +#endif void RecordLayer::onEditMacro(CCObject*) { MacroEditLayer::open(); @@ -1279,4 +1281,4 @@ void RecordLayer::updateTPS() { tpsInput->onClickTrackNode(false); tpsInput->m_cursor->setVisible(false); } -} \ No newline at end of file +} From e3073dc6745f91f3e7b7ad036f20e3cfa960c43f Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:38:49 +0300 Subject: [PATCH 036/211] Update render_settings_layer.cpp --- src/ui/render_settings_layer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index 6974d7a7..8d8dd882 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -84,8 +84,9 @@ void RenderSettingsLayer::onDefaults(CCObject*) { bool RenderSettingsLayer::setup() { setTitle("Render Settings"); - + #ifndef GEODE_IS_IOS bool usingApi = Renderer::shouldUseAPI(); + #endif cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; m_mainLayer->setPosition(m_mainLayer->getPosition() - offset); @@ -521,4 +522,4 @@ void RenderSettingsLayer::showInfoPopup(CCObject* obj) { msg.c_str(), "Ok" )->show(); -}; \ No newline at end of file +}; From cd32ceb676a03232c774dfa1ce6176dacc19553d Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:42:21 +0300 Subject: [PATCH 037/211] Update render_settings_layer.cpp --- src/ui/render_settings_layer.cpp | 34 +++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index 8d8dd882..d18b5798 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -116,7 +116,9 @@ bool RenderSettingsLayer::setup() { bg->setContentSize({ 392, 55 }); menu->addChild(bg); + #ifndef GEODE_IS_IOS if (usingApi) bg->setOpacity(40); + #endif CCLabelBMFont* lbl = CCLabelBMFont::create("Extra Args:", "bigFont.fnt"); lbl->setPosition(ccp(-105, 88)); @@ -125,7 +127,9 @@ bool RenderSettingsLayer::setup() { lbl->setScale(0.325); menu->addChild(lbl); + #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); + #endif argsInput = CCTextInputNode::create(150, 30, "args", "chatFont.fnt"); argsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); @@ -152,7 +156,9 @@ bool RenderSettingsLayer::setup() { bg->setContentSize({ 401, 55 }); menu->addChild(bg); + #ifndef GEODE_IS_IOS if (usingApi) bg->setOpacity(40); + #endif lbl = CCLabelBMFont::create("Audio Args:", "bigFont.fnt"); lbl->setPosition(ccp(-105, 55)); @@ -161,7 +167,9 @@ bool RenderSettingsLayer::setup() { lbl->setScale(0.325); menu->addChild(lbl); + #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); + #endif audioArgsInput = CCTextInputNode::create(150, 30, "audio args", "chatFont.fnt"); audioArgsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); @@ -257,7 +265,9 @@ bool RenderSettingsLayer::setup() { lbl->setScale(0.325); menu->addChild(lbl); + #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); + #endif onlySongToggle = CCMenuItemToggler::create( CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), @@ -276,7 +286,9 @@ bool RenderSettingsLayer::setup() { lbl->setScale(0.325); menu->addChild(lbl); + #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); + #endif recordAudioToggle = CCMenuItemToggler::create( CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), @@ -295,7 +307,9 @@ bool RenderSettingsLayer::setup() { lbl->setScale(0.325); menu->addChild(lbl); + #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); + #endif fadeInInput = TextInput::create(50.f, "s", "bigFont.fnt"); fadeInInput->setScale(0.5f); @@ -315,11 +329,13 @@ bool RenderSettingsLayer::setup() { toggle->setID("render_fade_in"); menu->addChild(toggle); + #ifndef GEODE_IS_IOS if (usingApi) { toggle->setCascadeOpacityEnabled(true); toggle->setEnabled(false); toggle->setOpacity(100); } + #endif lbl = CCLabelBMFont::create("Fade Out:", "bigFont.fnt"); lbl->setPosition(ccp(25, -58)); @@ -327,8 +343,10 @@ bool RenderSettingsLayer::setup() { lbl->setOpacity(200); lbl->setScale(0.325); menu->addChild(lbl); - + + #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); + #endif lbl = CCLabelBMFont::create("File Extension:", "bigFont.fnt"); lbl->setPosition(ccp(110, -5)); @@ -336,8 +354,10 @@ bool RenderSettingsLayer::setup() { lbl->setOpacity(200); lbl->setScale(0.3f); menu->addChild(lbl); - + + #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); + #endif extensionInput = TextInput::create(46.f, "", "chatFont.fnt"); extensionInput->setScale(0.8f); @@ -365,11 +385,13 @@ bool RenderSettingsLayer::setup() { toggle->setID("render_fade_out"); menu->addChild(toggle); + #ifndef GEODE_IS_IOS if (usingApi) { toggle->setCascadeOpacityEnabled(true); toggle->setEnabled(false); toggle->setOpacity(100); } + #endif lbl = CCLabelBMFont::create("Hide Endscreen:", "bigFont.fnt"); lbl->setPosition(ccp(-105, -83)); @@ -410,7 +432,9 @@ bool RenderSettingsLayer::setup() { lbl->setPosition({188, 42}); menu->addChild(lbl); + #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); + #endif sfxSlider = Slider::create( this, @@ -427,8 +451,10 @@ bool RenderSettingsLayer::setup() { lbl->setScale(0.475f); lbl->setPosition({188, 87}); menu->addChild(lbl); - + + #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); + #endif musicSlider = Slider::create( this, @@ -467,6 +493,7 @@ bool RenderSettingsLayer::setup() { btn->setTag(0); menu->addChild(btn); + #ifndef GEODE_IS_IOS if (usingApi) { argsInput->m_textLabel->setOpacity(100); audioArgsInput->m_textLabel->setOpacity(100); @@ -507,6 +534,7 @@ bool RenderSettingsLayer::setup() { return true; } +#endif void RenderSettingsLayer::onSlider(CCObject*) { Mod::get()->setSavedValue("render_sfx_volume", sfxSlider->getValue()); From f9f4a18fb06343fb02bb7201a27c9151d8b2f78b Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:43:57 +0300 Subject: [PATCH 038/211] Update render_settings_layer.cpp --- src/ui/render_settings_layer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index d18b5798..9d674e99 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -275,7 +275,9 @@ bool RenderSettingsLayer::setup() { this, menu_selector(RecordLayer::toggleSetting)); onlySongToggle->setPosition(ccp(0, -32)); onlySongToggle->setScale(0.555); + #ifndef GEODE_IS_IOS if (!usingApi) onlySongToggle->toggle(mod->getSavedValue("render_only_song")); + #endif onlySongToggle->setID("render_only_song"); menu->addChild(onlySongToggle); @@ -296,7 +298,9 @@ bool RenderSettingsLayer::setup() { this, menu_selector(RecordLayer::toggleSetting)); recordAudioToggle->setPosition(ccp(0, -58)); recordAudioToggle->setScale(0.555); + #ifndef GEODE_IS_IOS if (!usingApi) recordAudioToggle->toggle(mod->getSavedValue("render_record_audio")); + #endif recordAudioToggle->setID("render_record_audio"); menu->addChild(recordAudioToggle); @@ -325,7 +329,9 @@ bool RenderSettingsLayer::setup() { this, menu_selector(RecordLayer::toggleSetting)); toggle->setPosition(ccp(130, -32)); toggle->setScale(0.555); + #ifndef GEODE_IS_IOS if (!usingApi) toggle->toggle(mod->getSavedValue("render_fade_in")); + #endif toggle->setID("render_fade_in"); menu->addChild(toggle); @@ -381,7 +387,9 @@ bool RenderSettingsLayer::setup() { this, menu_selector(RecordLayer::toggleSetting)); toggle->setPosition(ccp(130, -58)); toggle->setScale(0.555); + #ifndef GEODE_IS_IOS if (!usingApi) toggle->toggle(mod->getSavedValue("render_fade_out")); + #endif toggle->setID("render_fade_out"); menu->addChild(toggle); From d4298ae0e91e0c4817ec5cbee90955cf084a1b20 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:46:39 +0300 Subject: [PATCH 039/211] Update render_settings_layer.cpp --- src/ui/render_settings_layer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index 9d674e99..0f2ecaf8 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -84,7 +84,7 @@ void RenderSettingsLayer::onDefaults(CCObject*) { bool RenderSettingsLayer::setup() { setTitle("Render Settings"); - #ifndef GEODE_IS_IOS +#ifndef GEODE_IS_IOS bool usingApi = Renderer::shouldUseAPI(); #endif From e59e650b51a8132efda7253e95013eefcd4abac5 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:50:38 +0300 Subject: [PATCH 040/211] Update render_settings_layer.cpp --- src/ui/render_settings_layer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index 0f2ecaf8..6075a960 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -84,9 +84,10 @@ void RenderSettingsLayer::onDefaults(CCObject*) { bool RenderSettingsLayer::setup() { setTitle("Render Settings"); + bool usingApi = false; #ifndef GEODE_IS_IOS - bool usingApi = Renderer::shouldUseAPI(); - #endif + usingApi = Renderer::shouldUseAPI(); +#endif cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; m_mainLayer->setPosition(m_mainLayer->getPosition() - offset); From 7147c905b841b3a2dadc3ab2356bd6d29171f0f8 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:53:48 +0300 Subject: [PATCH 041/211] Update render_settings_layer.cpp --- src/ui/render_settings_layer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index 6075a960..e6efd410 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -540,10 +540,10 @@ bool RenderSettingsLayer::setup() { musicSlider->m_groove->setOpacity(100); musicSlider->m_touchLogic->setOpacity(100); } +#endif return true; } -#endif void RenderSettingsLayer::onSlider(CCObject*) { Mod::get()->setSavedValue("render_sfx_volume", sfxSlider->getValue()); @@ -559,4 +559,4 @@ void RenderSettingsLayer::showInfoPopup(CCObject* obj) { msg.c_str(), "Ok" )->show(); -}; +} From 6a2244c08b20d1bc498ffae999e94c5a5855d9fd Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:58:31 +0300 Subject: [PATCH 042/211] Update game_ui.cpp --- src/ui/game_ui.cpp | 133 ++++++++++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 62 deletions(-) diff --git a/src/ui/game_ui.cpp b/src/ui/game_ui.cpp index d5ba0184..b344b279 100644 --- a/src/ui/game_ui.cpp +++ b/src/ui/game_ui.cpp @@ -4,27 +4,34 @@ #include class $modify(PlayLayer) { - + struct Fields { CCLabelBMFont* frameLabel = nullptr; }; - + void postUpdate(float dt) { PlayLayer::postUpdate(dt); auto& g = Global::get(); - - if (g.state != state::none && g.frameLabel && !g.renderer.recording) + + #ifndef GEODE_IS_IOS + if (g.state != state::none && g.frameLabel && !g.renderer.recording) { + m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); + } + #else + if (g.state != state::none && g.frameLabel && !g.renderer.recording) { m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); + } + #endif } - + bool init(GJGameLevel * level, bool b1, bool b2) { if (!PlayLayer::init(level, b1, b2)) return false; - + Interface::addLabels(this); Interface::addButtons(this); - + m_fields->frameLabel = static_cast(getChildByID("frame-label"_spr)); - + return true; } }; @@ -37,7 +44,7 @@ void Interface::addLabels(PlayLayer* pl) { lbl->setZOrder(300); lbl->setScale(0.625f); pl->addChild(lbl); - + lbl = CCLabelBMFont::create("", "chatFont.fnt"); lbl->setPosition({ 6.5f, 12 }); lbl->setAnchorPoint({ 0, 0.5 }); @@ -45,7 +52,7 @@ void Interface::addLabels(PlayLayer* pl) { lbl->setZOrder(300); lbl->setScale(0.625f); pl->addChild(lbl); - + lbl = CCLabelBMFont::create("Recording Audio", "bigFont.fnt"); lbl->setPosition(pl->getContentSize() / 2); lbl->setID("recording-audio-label"_spr); @@ -53,163 +60,165 @@ void Interface::addLabels(PlayLayer* pl) { lbl->setOpacity(75); lbl->setVisible(false); pl->addChild(lbl); - + Interface::updateLabels(); } void Interface::addButtons(PlayLayer* pl) { cocos2d::CCSize winSize = CCDirector::sharedDirector()->getWinSize(); - + CCMenu* menu = CCMenu::create(); menu->setZOrder(300); menu->setPosition({ 0, 0 }); menu->setID("button-menu"_spr); pl->addChild(menu); - + CCSprite* spr = CCSprite::createWithSpriteFrameName("GJ_arrow_02_001.png"); spr->setFlipX(true); - + CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(spr, pl, menu_selector(Interface::onFrameStepper)); btn->setAnchorPoint({ 0, 0 }); btn->setID("step-frame-btn"); CCSprite* sprite = btn->getChildByType(0); sprite->setPosition({ 0, 0 }); - + menu->addChild(btn); - + spr = CCSprite::createWithSpriteFrameName("GJ_deleteIcon_001.png"); - + btn = CCMenuItemSpriteExtra::create(spr, pl, menu_selector(Interface::onFrameStepperOff)); btn->setID("disable-stepper-btn"); btn->setAnchorPoint({ 0, 0 }); sprite = btn->getChildByType(0); sprite->setPosition({ 0, 0 }); - + menu->addChild(btn); - + spr = CCSprite::createWithSpriteFrameName("GJ_timeIcon_001.png"); - + btn = CCMenuItemSpriteExtra::create(spr, pl, menu_selector(Interface::onSpeedhack)); btn->setAnchorPoint({ 0, 0 }); btn->setID("speedhack-btn"); sprite = btn->getChildByType(0); sprite->setPosition({ 0, 0 }); - + menu->addChild(btn); - + Interface::updateButtons(); } void Interface::updateLabels() { PlayLayer* pl = PlayLayer::get(); auto& g = Global::get(); - + if (!pl) return; - + if (g.state == state::none || !g.frameLabel) - static_cast(pl->getChildByID("frame-label"_spr))->setString(""); - + static_cast(pl->getChildByID("frame-label"_spr))->setString(""); + CCLabelBMFont* label = typeinfo_cast(pl->getChildByID("state-label"_spr)); - + if (!label) return; - + if (g.mod->getSavedValue("macro_hide_labels")) - return label->setString(""); - + return label->setString(""); + state state = g.state; std::string labelText = state == state::none ? "" : "Playing"; if (state == state::recording) - labelText = "Recording"; - + labelText = "Recording"; + if (labelText == "Recording" && state == state::recording && g.mod->getSavedValue("macro_hide_recording_label")) - labelText = ""; - + labelText = ""; + if (labelText == "Playing" && state == state::playing && g.mod->getSavedValue("macro_hide_playing_label")) - labelText = ""; - + labelText = ""; + + #ifndef GEODE_IS_IOS if (g.renderer.recording && g.mod->getSavedValue("render_hide_labels")) { labelText = ""; if (CCLabelBMFont* lbl = typeinfo_cast(pl->getChildByID("frame-label"_spr))) - lbl->setString(""); + lbl->setString(""); } - + label->setString(labelText.c_str()); } +#endif void Interface::updateButtons() { PlayLayer* pl = PlayLayer::get(); if (!pl) return; - + CCNode* menu = pl->getChildByID("button-menu"_spr); if (!menu) return; - + auto& g = Global::get(); - -#ifdef GEODE_IS_WINDOWS + + #ifdef GEODE_IS_WINDOWS bool isWindows = true; -#else + #else bool isWindows = false; -#endif - + #endif + CCNode* disableStepperBtn = menu->getChildByID("disable-stepper-btn"); CCNode* stepFrameBtn = menu->getChildByID("step-frame-btn"); CCNode* speedhackBtn = menu->getChildByID("speedhack-btn"); - + disableStepperBtn->setPosition(ccp( g.mod->getSavedValue("button_off_pos_x"), g.mod->getSavedValue("button_off_pos_y") )); - + float scale = g.mod->getSavedValue("button_off_scale"); - + CCSprite* sprite = disableStepperBtn->getChildByType(0); sprite->setScale(scale); sprite->setOpacity(static_cast(g.mod->getSavedValue("button_off_opacity") * 255)); sprite->setAnchorPoint({ 0, 0 }); - + cocos2d::CCSize size = sprite->getContentSize(); disableStepperBtn->setContentSize({ size.width * scale, size.height * scale }); - + stepFrameBtn->setPosition(ccp( g.mod->getSavedValue("button_advance_frame_pos_x"), g.mod->getSavedValue("button_advance_frame_pos_y") )); - + scale = g.mod->getSavedValue("button_advance_frame_scale"); - + sprite = stepFrameBtn->getChildByType(0); sprite->setScale(scale); sprite->setOpacity(static_cast(g.mod->getSavedValue("button_advance_frame_opacity") * 255)); sprite->setAnchorPoint({ 0, 0 }); - + size = sprite->getContentSize(); speedhackBtn->setContentSize({ size.width * scale, size.height * scale }); - + speedhackBtn->setPosition(ccp( g.mod->getSavedValue("button_speedhack_pos_x"), g.mod->getSavedValue("button_speedhack_pos_y") )); - + scale = g.mod->getSavedValue("button_speedhack_scale"); - + sprite = speedhackBtn->getChildByType(0); sprite->setScale(scale); sprite->setOpacity(static_cast(g.mod->getSavedValue("button_speedhack_opacity") * 255)); sprite->setAnchorPoint({ 0, 0 }); - + size = sprite->getContentSize(); speedhackBtn->setContentSize({ size.width * scale, size.height * scale }); - + if ((g.state != state::recording && !g.mod->getSavedValue("macro_always_show_buttons")) || isWindows) { disableStepperBtn->setVisible(false); stepFrameBtn->setVisible(false); speedhackBtn->setVisible(false); - + return; } - + speedhackBtn->setVisible(!g.mod->getSavedValue("macro_hide_speedhack")); - + if (g.mod->getSavedValue("macro_hide_stepper")) { disableStepperBtn->setVisible(false); stepFrameBtn->setVisible(false); @@ -218,4 +227,4 @@ void Interface::updateButtons() { stepFrameBtn->setVisible(true); disableStepperBtn->setVisible(g.frameStepper); } -} \ No newline at end of file +} From 37ec2ce41201bc6cf007e8229e39673862935c76 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 16:00:37 +0300 Subject: [PATCH 043/211] Update game_ui.cpp --- src/ui/game_ui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/game_ui.cpp b/src/ui/game_ui.cpp index b344b279..0186acc7 100644 --- a/src/ui/game_ui.cpp +++ b/src/ui/game_ui.cpp @@ -18,7 +18,7 @@ class $modify(PlayLayer) { m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); } #else - if (g.state != state::none && g.frameLabel && !g.renderer.recording) { + if (g.state != state::none && g.frameLabel) { m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); } #endif From f86b64d058f009c6e84d623f25791642a79e2616 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 29 Jun 2025 16:03:46 +0300 Subject: [PATCH 044/211] Update game_ui.cpp --- src/ui/game_ui.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ui/game_ui.cpp b/src/ui/game_ui.cpp index 0186acc7..1f1f8467 100644 --- a/src/ui/game_ui.cpp +++ b/src/ui/game_ui.cpp @@ -114,36 +114,36 @@ void Interface::updateLabels() { if (!pl) return; if (g.state == state::none || !g.frameLabel) - static_cast(pl->getChildByID("frame-label"_spr))->setString(""); + static_cast(pl->getChildByID("frame-label"_spr))->setString(""); CCLabelBMFont* label = typeinfo_cast(pl->getChildByID("state-label"_spr)); if (!label) return; if (g.mod->getSavedValue("macro_hide_labels")) - return label->setString(""); + return label->setString(""); state state = g.state; std::string labelText = state == state::none ? "" : "Playing"; if (state == state::recording) - labelText = "Recording"; + labelText = "Recording"; if (labelText == "Recording" && state == state::recording && g.mod->getSavedValue("macro_hide_recording_label")) - labelText = ""; + labelText = ""; if (labelText == "Playing" && state == state::playing && g.mod->getSavedValue("macro_hide_playing_label")) - labelText = ""; + labelText = ""; - #ifndef GEODE_IS_IOS +#ifndef GEODE_IS_IOS if (g.renderer.recording && g.mod->getSavedValue("render_hide_labels")) { labelText = ""; if (CCLabelBMFont* lbl = typeinfo_cast(pl->getChildByID("frame-label"_spr))) - lbl->setString(""); + lbl->setString(""); } - +#endif + label->setString(labelText.c_str()); } -#endif void Interface::updateButtons() { PlayLayer* pl = PlayLayer::get(); From 23b7cbff239c735dd442a7794da0485917d0f1a1 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Mon, 30 Jun 2025 00:03:35 +0300 Subject: [PATCH 045/211] Update keybinds.cpp --- src/keybinds.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 6e7657ca..e3cc636a 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -142,9 +142,7 @@ void onKeybind(bool down, ActionID id) { $execute{ -#ifdef GEODE_IS_WINDOWS -#ifdef GEODE_IS_MACOS - +#if defined(GEODE_IS_WINDOWS) && defined(GEODE_IS_MACOS) BindManager * bm = BindManager::get(); bm->registerBindable({ @@ -234,6 +232,5 @@ void onKeybind(bool down, ActionID id) { } #endif -#endif } From 041d079564fead0d9b60265d6c611189b8d72178 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Mon, 30 Jun 2025 02:05:29 +0300 Subject: [PATCH 046/211] thank u jasmine --- src/includes.hpp | 6 ++++++ src/keybinds.cpp | 14 +++----------- src/ui/record_layer.hpp | 9 +++++++++ src/ui/render_settings_layer.hpp | 7 +++++++ 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/includes.hpp b/src/includes.hpp index 5fbe11e8..498d4c6c 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -45,6 +45,12 @@ const std::string buttonIDs[6] = { class Global { + #define DESELECT_INPUT(node) \ + if (node) { \ + node->onClickTrackNode(false); \ + node->setDelegate(nullptr); \ + } + Global() {} public: diff --git a/src/keybinds.cpp b/src/keybinds.cpp index e3cc636a..521c31e8 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -10,7 +10,7 @@ #include #include -#if defined(GEODE_IS_WINDOWS) && defined(GEODE_IS_MACOS) +#ifdef GEODE_IS_DESKTOP #include #include @@ -64,11 +64,10 @@ namespace keybinds { #endif -#if defined (GEODE_IS_WINDOWS) && defined (GEODE_IS_MACOS) +#ifdef GEODE_IS_DESKTOP using namespace keybinds; void onKeybind(bool down, ActionID id) { -#if defined(GEODE_IS_WINDOWS) || defined(GEODE_IS_MACOS) auto& g = Global::get(); @@ -135,14 +134,9 @@ void onKeybind(bool down, ActionID id) { static_cast(g.layer)->noclipToggle->toggle(g.mod->getSavedValue("macro_noclip")); } } - -#endif // GEODE_IS_WINDOWS || GEODE_IS_MACOS } -#endif // !GEODE_IS_IOS && !GEODE_IS_MACOS $execute{ - -#if defined(GEODE_IS_WINDOWS) && defined(GEODE_IS_MACOS) BindManager * bm = BindManager::get(); bm->registerBindable({ @@ -230,7 +224,5 @@ void onKeybind(bool down, ActionID id) { new EventListener([=](InvokeBindEvent* event) { onKeybind(event->isDown(), event->getID()); return ListenerResult::Propagate; }, InvokeBindFilter(nullptr, (""_spr) + keybindIDs[i])); } - -#endif - } +#endif diff --git a/src/ui/record_layer.hpp b/src/ui/record_layer.hpp index f4954bfa..271c4b61 100644 --- a/src/ui/record_layer.hpp +++ b/src/ui/record_layer.hpp @@ -76,6 +76,15 @@ class RecordLayer : public geode::Popup<>, public TextInputDelegate { bool setup() override; ~RecordLayer() override { + DESELECT_INPUT(widthInput) + DESELECT_INPUT(heightInput) + DESELECT_INPUT(bitrateInput) + DESELECT_INPUT(fpsInput) + DESELECT_INPUT(codecInput) + DESELECT_INPUT(seedInput) + DESELECT_INPUT(speedhackInput) + DESELECT_INPUT(respawnInput) + DESELECT_INPUT(tpsInput) cocos2d::CCTouchDispatcher::get()->unregisterForcePrio(this); Global::get().layer = nullptr; } diff --git a/src/ui/render_settings_layer.hpp b/src/ui/render_settings_layer.hpp index 712e0044..679b1955 100644 --- a/src/ui/render_settings_layer.hpp +++ b/src/ui/render_settings_layer.hpp @@ -28,6 +28,13 @@ class RenderSettingsLayer : public geode::Popup<>, public TextInputDelegate { public: +~RenderSettingsLayer() override { + DESELECT_INPUT(argsInput) + DESELECT_INPUT(audioArgsInput) + DESELECT_INPUT(secondsInput) + DESELECT_INPUT(videoArgsInput) + } + STATIC_CREATE(RenderSettingsLayer, 396, 277) void open(CCObject*) { From 629f80dc83e56302249ddb624fbb31f750d732b3 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:43:37 +0300 Subject: [PATCH 047/211] ifdef changes --- src/global.cpp | 6 +++--- src/ui/macro_editor.cpp | 2 +- src/ui/record_layer.cpp | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/global.cpp b/src/global.cpp index 6212c6ba..d8c932e4 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -3,7 +3,7 @@ #include -#ifdef GEODE_IS_WINDOWS +#ifdef GEODE_IS_DESKTOP #include #endif @@ -186,7 +186,7 @@ int Global::getCurrentFrame(bool editor) { } void Global::updateKeybinds() { -#ifdef GEODE_IS_WINDOWS +#ifdef GEODE_IS_DESKTOP auto& g = Global::get(); for (size_t i = 0; i < 6; i++) { @@ -435,7 +435,7 @@ PauseLayer* Global::getPauseLayer() { g.mod->setSavedValue("menu_pause_on_open", false); g.mod->setSavedValue("menu_show_cursor", true); - #ifdef GEODE_IS_ANDROID + #ifdef GEODE_IS_MOBILE g.mod->setSavedValue("menu_show_cursor", false); #endif diff --git a/src/ui/macro_editor.cpp b/src/ui/macro_editor.cpp index 9becb211..369eb898 100644 --- a/src/ui/macro_editor.cpp +++ b/src/ui/macro_editor.cpp @@ -29,7 +29,7 @@ class $modify(CCEGLView) { class $modify(FLAlertLayer) { -#ifdef GEODE_IS_ANDROID +#ifdef GEODE_IS_MOBILE virtual bool ccTouchBegan(cocos2d::CCTouch * touch, cocos2d::CCEvent * event) { if (!FLAlertLayer::ccTouchBegan(touch, event)) return false; diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 80aba42a..0a07e6a8 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -31,7 +31,7 @@ const std::vector> settings { { "Auto Safe Mode:", "macro_auto_safe_mode", InputType::None } }, { - #ifdef GEODE_IS_WINDOWS + #ifdef GEODE_IS_DESKTOP { "Force cursor on open:", "menu_show_cursor", InputType::None }, { "Button on pause menu:", "menu_show_button", InputType::None }, { "Pause on open:", "menu_pause_on_open", InputType::None }, @@ -67,7 +67,7 @@ class $modify(PauseLayer) { void customSetup() { PauseLayer::customSetup(); - #ifdef GEODE_IS_WINDOWS + #ifdef GEODE_IS_DESKTOP if (!Mod::get()->getSavedValue("menu_show_button")) return; @@ -147,7 +147,7 @@ RecordLayer* RecordLayer::openMenu(bool instant) { if (!pl->m_isPaused) pl->pauseGame(false); } -#ifdef GEODE_IS_WINDOWS +#ifdef GEODE_IS_DESKTOP else if (pl && g.mod->getSavedValue("menu_show_cursor")) { cursor = cocos2d::CCEGLView::sharedOpenGLView()->getShouldHideCursor(); cocos2d::CCEGLView::sharedOpenGLView()->showCursor(true); @@ -485,7 +485,7 @@ void RecordLayer::showKeybindsWarning() { } void RecordLayer::openKeybinds(CCObject*) { -#ifdef GEODE_IS_WINDOWS +#ifdef GEODE_IS_DESKTOP MoreOptionsLayer::create()->onKeybindings(nullptr); CCScene* scene = CCDirector::get()->getRunningScene(); @@ -723,7 +723,7 @@ bool RecordLayer::setup() { btn->setPosition(ccp(-176, 34)); menu->addChild(btn); -#ifdef GEODE_IS_WINDOWS +#ifdef GEODE_IS_DESKTOP btnSprite = ButtonSprite::create("Keybinds"); #else btnSprite = ButtonSprite::create("Buttons"); From c7a3cf707a606c946d1ebb7e57889b03cb9456fe Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:50:16 +0300 Subject: [PATCH 048/211] iOS render button --- src/ui/record_layer.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 0a07e6a8..4df263e7 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -921,13 +921,20 @@ bool RecordLayer::setup() { bg->setZOrder(29); menu->addChild(bg); + #ifdef GEODE_IS_IOS + ButtonSprite* spriteOn2 = ButtonSprite::create("N/A"); + spriteOn2->setScale(0.74f); + #else ButtonSprite* spriteOn2 = ButtonSprite::create("Stop"); spriteOn2->setScale(0.74f); ButtonSprite* spriteOff2 = ButtonSprite::create("Start"); spriteOff2->setScale(0.74f); + #endif #ifdef GEODE_IS_IOS - renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRenderIOS)); + renderToggle = CCMenuItemToggler::create(spriteOn2, this, menu_selector(RecordLayer::toggleRenderIOS)); + renderToggle->setPosition(ccp(-65.5, -100)); + menu->addChild(renderToggle); #else renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRender)); renderToggle->toggle(g.renderer.recording || g.renderer.recordingAudio); From 2d530f07cd6adb034bc89108171afc2878226093 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:51:42 +0300 Subject: [PATCH 049/211] revert geode is desktop ifdef --- src/ui/record_layer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 4df263e7..5d082cc9 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -31,7 +31,7 @@ const std::vector> settings { { "Auto Safe Mode:", "macro_auto_safe_mode", InputType::None } }, { - #ifdef GEODE_IS_DESKTOP + #ifdef GEODE_IS_WINDOWS { "Force cursor on open:", "menu_show_cursor", InputType::None }, { "Button on pause menu:", "menu_show_button", InputType::None }, { "Pause on open:", "menu_pause_on_open", InputType::None }, @@ -147,7 +147,7 @@ RecordLayer* RecordLayer::openMenu(bool instant) { if (!pl->m_isPaused) pl->pauseGame(false); } -#ifdef GEODE_IS_DESKTOP +#ifdef GEODE_IS_WINDOWS else if (pl && g.mod->getSavedValue("menu_show_cursor")) { cursor = cocos2d::CCEGLView::sharedOpenGLView()->getShouldHideCursor(); cocos2d::CCEGLView::sharedOpenGLView()->showCursor(true); From 006c681644dd829a569675d354257906cb167a5a Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:53:28 +0300 Subject: [PATCH 050/211] laflaksdlk --- src/ui/record_layer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 5d082cc9..9f3374b5 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -924,6 +924,8 @@ bool RecordLayer::setup() { #ifdef GEODE_IS_IOS ButtonSprite* spriteOn2 = ButtonSprite::create("N/A"); spriteOn2->setScale(0.74f); + ButtonSprite * spriteOff2 = ButtonSprite::create("N/A"); + spriteOff2 = ButtonSprite::create("N/A"); #else ButtonSprite* spriteOn2 = ButtonSprite::create("Stop"); spriteOn2->setScale(0.74f); @@ -932,7 +934,7 @@ bool RecordLayer::setup() { #endif #ifdef GEODE_IS_IOS - renderToggle = CCMenuItemToggler::create(spriteOn2, this, menu_selector(RecordLayer::toggleRenderIOS)); + renderToggle = CCMenuItemToggler::create(spriteOn2, spriteOff2, this, menu_selector(RecordLayer::toggleRenderIOS)); renderToggle->setPosition(ccp(-65.5, -100)); menu->addChild(renderToggle); #else From 61559d4c29e906c15a20f34ab9f930161dc301e4 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Mon, 30 Jun 2025 16:29:33 +0300 Subject: [PATCH 051/211] what the hell --- src/ui/record_layer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 9f3374b5..f6ea1d69 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -924,8 +924,8 @@ bool RecordLayer::setup() { #ifdef GEODE_IS_IOS ButtonSprite* spriteOn2 = ButtonSprite::create("N/A"); spriteOn2->setScale(0.74f); - ButtonSprite * spriteOff2 = ButtonSprite::create("N/A"); - spriteOff2 = ButtonSprite::create("N/A"); + ButtonSprite* spriteOff2 = ButtonSprite::create("N/A"); + spriteOff2->setScale(0.74f); #else ButtonSprite* spriteOn2 = ButtonSprite::create("Stop"); spriteOn2->setScale(0.74f); From ee5ea39792dfab7fcceaa41abd2896963b2c6b83 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 11 Jul 2025 22:28:23 +0300 Subject: [PATCH 052/211] stupid ios! --- mod.json | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/mod.json b/mod.json index 18add9a6..e7e59ecf 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "4.6.2", + "geode": "4.6.3", "gd": { "win": "2.2074", "mac": "2.2074", @@ -53,17 +53,32 @@ "macros_folder": { "name": "Macro Save Location", "type": "folder", - "default": "{gd_dir}/macros" + "default": { + "win": "{gd_dir}/macros", + "mac": "{gd_dir}/macros", + "android": "{gd_dir}/macros", + "ios: "{mod_save_dir}/macros" + } }, "autosaves_folder": { "name": "Auto Saves Location", "type": "folder", - "default": "{gd_dir}/autosaves" + "default": { + "win": "{gd_dir}/autosaves", + "mac": "{gd_dir}/autosaves", + "android": "{gd_dir}/autosaves", + "ios": "{mod_save_dir}/autosaves" + } }, "render_folder": { "name": "Render Save Location", "type": "folder", - "default": "{gd_dir}/renders" + "default": { + "win": "{gd_dir}/renders", + "mac": "{gd_dir}/renders", + "android": "{gd_dir}/renders", + "ios": "{mod_save_dir}/renders" + } }, "background_color": { "name": "Menu background color", From 1ec76a26b2fb6eb22fa44a919f9bc669973364c2 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 11 Jul 2025 22:28:56 +0300 Subject: [PATCH 053/211] =?UTF-8?q?im=20ido=C5=9Ft?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod.json b/mod.json index e7e59ecf..9d52a41d 100644 --- a/mod.json +++ b/mod.json @@ -57,7 +57,7 @@ "win": "{gd_dir}/macros", "mac": "{gd_dir}/macros", "android": "{gd_dir}/macros", - "ios: "{mod_save_dir}/macros" + "ios": "{mod_save_dir}/macros" } }, "autosaves_folder": { From 7f2e96a42a03c44e7e28418a47489c3878f3568d Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 11 Jul 2025 23:03:37 +0300 Subject: [PATCH 054/211] blehh --- mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod.json b/mod.json index 9d52a41d..1aef3d59 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "4.6.3", + "geode": "4.6.1", "gd": { "win": "2.2074", "mac": "2.2074", From 20347546a587d704659008fa0bd74c17c259b045 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 11 Jul 2025 23:14:52 +0300 Subject: [PATCH 055/211] welp --- mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod.json b/mod.json index 1aef3d59..9d52a41d 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "4.6.1", + "geode": "4.6.3", "gd": { "win": "2.2074", "mac": "2.2074", From 7819300cb81540ab8d5d755022dafd00cf6d1c3c Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sat, 14 Feb 2026 00:43:43 +0300 Subject: [PATCH 056/211] geode v5 (2.2081) --- CMakeLists.txt | 2 +- mod.json | 17 +- src/global.cpp | 57 +- src/hacks/autoclicker.cpp | 4 +- src/hacks/frame_stepper.cpp | 58 +- src/hacks/other.cpp | 20 +- src/includes.hpp | 8 +- src/keybinds.cpp | 408 +++---- src/main.cpp | 54 +- src/practice_fixes/player.cpp | 26 +- src/renderer/ffmpeg/events.hpp | 498 ++++---- src/renderer/renderer.cpp | 1556 ++++++++++++------------- src/renderer/renderer.hpp | 134 +-- src/ui/autoclicker_settings_layer.hpp | 7 +- src/ui/autosave_settings_layer.hpp | 7 +- src/ui/button_edit_layer.cpp | 3 +- src/ui/button_edit_layer.hpp | 6 +- src/ui/button_setting.cpp | 2 +- src/ui/clickbot_layer.cpp | 33 +- src/ui/clickbot_layer.hpp | 18 +- src/ui/game_ui.cpp | 26 +- src/ui/load_macro_layer.cpp | 466 ++++---- src/ui/load_macro_layer.hpp | 23 +- src/ui/macro_editor.cpp | 497 ++++---- src/ui/macro_editor.hpp | 6 +- src/ui/macro_info_layer.hpp | 7 +- src/ui/mirror_settings_layer.hpp | 7 +- src/ui/noclip_settings_layer.hpp | 7 +- src/ui/record_layer.cpp | 35 +- src/ui/record_layer.hpp | 6 +- src/ui/render_presets_layer.hpp | 7 +- src/ui/render_settings_layer.cpp | 651 +++++------ src/ui/render_settings_layer.hpp | 7 +- src/ui/save_macro_layer.hpp | 7 +- src/ui/trajectory_settings_layer.hpp | 231 ++-- src/utils/utils.cpp | 2 +- src/utils/utils.hpp | 2 +- 37 files changed, 2471 insertions(+), 2434 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 27c06891..5aa5d412 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.21) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) if ("${CMAKE_SYSTEM_NAME}" STREQUAL "iOS" OR IOS) set(CMAKE_OSX_ARCHITECTURES "arm64") diff --git a/mod.json b/mod.json index 9d52a41d..32861513 100644 --- a/mod.json +++ b/mod.json @@ -1,23 +1,16 @@ { - "geode": "4.6.3", + "geode": "5.0.0-alpha.2", "gd": { - "win": "2.2074", - "mac": "2.2074", - "android": "2.2074", - "ios": "2.2074" + "win": "2.2081", + "mac": "2.2081", + "android": "2.2081", + "ios": "2.2081" }, "version": "2.4.1", "id": "zilko.xdbot", "name": "xdBot", "developer": "Zilko", "description": "Best Free Bot fr", - "dependencies": { - "geode.custom-keybinds": { - "version": ">=1.10.4", - "importance": "required", - "platforms": ["win", "mac"] - } - }, "settings": { "button-setting": { "type": "custom:button", diff --git a/src/global.cpp b/src/global.cpp index d8c932e4..cb5dcf49 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -3,9 +3,9 @@ #include -#ifdef GEODE_IS_DESKTOP -#include -#endif +// #ifdef GEODE_IS_DESKTOP +// #include +// #endif #include @@ -185,25 +185,25 @@ int Global::getCurrentFrame(bool editor) { return frame; } -void Global::updateKeybinds() { -#ifdef GEODE_IS_DESKTOP +// void Global::updateKeybinds() { +// #ifdef GEODE_IS_DESKTOP - auto& g = Global::get(); - for (size_t i = 0; i < 6; i++) { - auto keys = keybinds::BindManager::get()->getBindsFor(buttonIDs[i]); - std::vector keysInts = {}; +// auto& g = Global::get(); +// for (size_t i = 0; i < 6; i++) { +// auto keys = keybinds::BindManager::get()->getBindsFor(buttonIDs[i]); +// std::vector keysInts = {}; - for (size_t j = 0; j < keys.size(); j++) { - keysInts.push_back(keys[j]->getHash()); - g.allKeybinds.insert(keys[j]->getHash()); - } +// for (size_t j = 0; j < keys.size(); j++) { +// keysInts.push_back(keys[j]->getHash()); +// g.allKeybinds.insert(keys[j]->getHash()); +// } - g.keybinds[i].clear(); - for (int k = 0; k < keysInts.size(); k++) - g.keybinds[i].push_back(keysInts[k]); - } -#endif -} +// g.keybinds[i].clear(); +// for (int k = 0; k < keysInts.size(); k++) +// g.keybinds[i].push_back(keysInts[k]); +// } +// #endif +// } void Global::updateSeed(bool isRestart) { @@ -333,16 +333,17 @@ void Global::frameStepperOff() { Interface::updateButtons(); } -PauseLayer* Global::getPauseLayer() { - CCArray* children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); - CCObject* child; - CCARRAY_FOREACH(children, child) { - if (PauseLayer* pauseLayer = typeinfo_cast(child)) - return pauseLayer; - } + PauseLayer* Global::getPauseLayer() { + auto children = CCDirector::sharedDirector() + ->getRunningScene() + ->getChildren(); - return nullptr; -} + for (auto child : CCArrayExt(children)) { + if (auto pauseLayer = typeinfo_cast(child)) + return pauseLayer; + } + return nullptr; + } $execute{ auto & g = Global::get(); diff --git a/src/hacks/autoclicker.cpp b/src/hacks/autoclicker.cpp index a9716184..59a940f8 100644 --- a/src/hacks/autoclicker.cpp +++ b/src/hacks/autoclicker.cpp @@ -11,8 +11,8 @@ class $modify(GJBaseGameLayer) { bool holding[2] = {false, false}; }; - void processCommands(float dt) { - GJBaseGameLayer::processCommands(dt); + void processCommands(float dt, bool isHalfTick, bool isLastTick) { + GJBaseGameLayer::processCommands(dt, isHalfTick, isLastTick); auto& g = Global::get(); diff --git a/src/hacks/frame_stepper.cpp b/src/hacks/frame_stepper.cpp index b2b2ad84..95d8c584 100644 --- a/src/hacks/frame_stepper.cpp +++ b/src/hacks/frame_stepper.cpp @@ -72,24 +72,24 @@ class $modify(GJBaseGameLayer) { } auto& g = Global::get(); - #ifndef GEODE_IS_IOS - if (!g.renderer.recording && g.frameStepper) { - if (g.stepFrameParticle != 0) - g.stepFrameParticle--; - - if (Macro::shouldStep()) { - g.stepFrame = false; - - GJBaseGameLayer::update(1.f / Global::getTPS()); - - return; - } - else { - g.safeMode = true; - return; - } - } - #else + // #ifndef GEODE_IS_IOS + // if (!g.renderer.recording && g.frameStepper) { + // if (g.stepFrameParticle != 0) + // g.stepFrameParticle--; + + // if (Macro::shouldStep()) { + // g.stepFrame = false; + + // GJBaseGameLayer::update(1.f / Global::getTPS()); + + // return; + // } + // else { + // g.safeMode = true; + // return; + // } + // } + // #else if (g.frameStepper) { if (g.stepFrameParticle != 0) g.stepFrameParticle--; @@ -106,7 +106,7 @@ class $modify(GJBaseGameLayer) { return; } } - #endif + // #endif GJBaseGameLayer::update(dt); } @@ -118,15 +118,15 @@ class $modify(CCParticleSystem) { virtual void update(float dt) { auto& g = Global::get(); if (!PlayLayer::get()) return CCParticleSystem::update(dt); - #ifndef GEODE_IS_IOS - if (!g.renderer.recording && g.frameStepper) { - if (g.stepFrameParticle != 0) { - CCParticleSystem::update(dt); - } - else - return; - } - #else + // #ifndef GEODE_IS_IOS + // if (!g.renderer.recording && g.frameStepper) { + // if (g.stepFrameParticle != 0) { + // CCParticleSystem::update(dt); + // } + // else + // return; + // } + // #else if (g.frameStepper) { if (g.stepFrameParticle != 0) { CCParticleSystem::update(dt); @@ -134,7 +134,7 @@ class $modify(CCParticleSystem) { else return; } - #endif + // #endif CCParticleSystem::update(dt); } diff --git a/src/hacks/other.cpp b/src/hacks/other.cpp index c1dd0279..8a9959c1 100644 --- a/src/hacks/other.cpp +++ b/src/hacks/other.cpp @@ -22,14 +22,14 @@ class $modify(CCScheduler) { return CCScheduler::update(dt); } - #ifndef GEODE_IS_IOS - if (g.renderer.recording || g.renderer.recordingAudio) { - if (g.currentPitch != 1.f) - Global::updatePitch(1.f); + // #ifndef GEODE_IS_IOS + // if (g.renderer.recording || g.renderer.recordingAudio) { + // if (g.currentPitch != 1.f) + // Global::updatePitch(1.f); - return CCScheduler::update(dt); - } - #endif + // return CCScheduler::update(dt); + // } + // #endif float speedhack = 1.f; @@ -130,9 +130,9 @@ class $modify(PlayLayer) { Global::get().safeMode = true; if (getActionByTag(16)) { - #ifndef GEODE_IS_IOS - if (Global::get().renderer.recordingAudio) Global::get().renderer.stopAudio(); - #endif + // #ifndef GEODE_IS_IOS + // if (Global::get().renderer.recordingAudio) Global::get().renderer.stopAudio(); + // #endif if (g.mod->getSavedValue("respawn_time_enabled")) { stopActionByTag(16); diff --git a/src/includes.hpp b/src/includes.hpp index 498d4c6c..f0fc761c 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -32,10 +32,10 @@ const std::string buttonIDs[6] = { "robtop.geometry-dash/move-right-p2" }; -#define STATIC_CREATE(class, width, height) \ +#define STATIC_CREATE(class) \ static class* create() { \ class* ret = new class(); \ - if (ret->initAnchored(width, height, Utils::getTexture().c_str())) { \ + if (ret->init()) { \ ret->autorelease(); \ return ret; \ } \ @@ -85,11 +85,11 @@ class Global { static PauseLayer* getPauseLayer(); Mod* mod = Mod::get(); - geode::Popup<>* layer = nullptr; + geode::Popup* layer = nullptr; Macro macro; #ifndef GEODE_IS_IOS - Renderer renderer; + // Renderer renderer; #endif state state = none; diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 521c31e8..f4dffe78 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -1,228 +1,228 @@ -#include "includes.hpp" -#include "ui/record_layer.hpp" -#include "ui/game_ui.hpp" -#include "ui/clickbot_layer.hpp" -#include "ui/macro_editor.hpp" -#include "ui/render_settings_layer.hpp" -#include "hacks/layout_mode.hpp" -#include "hacks/show_trajectory.hpp" +// #include "includes.hpp" +// #include "ui/record_layer.hpp" +// #include "ui/game_ui.hpp" +// #include "ui/clickbot_layer.hpp" +// #include "ui/macro_editor.hpp" +// #include "ui/render_settings_layer.hpp" +// #include "hacks/layout_mode.hpp" +// #include "hacks/show_trajectory.hpp" -#include -#include +// #include +// #include -#ifdef GEODE_IS_DESKTOP +// #ifdef GEODE_IS_DESKTOP -#include -#include +// #include +// #include -#endif +// #endif -const std::vector keybindIDs = { - "open_menu", "toggle_recording", "toggle_playing", - "toggle_speedhack", "toggle_frame_stepper", "step_frame", - "toggle_render", "toggle_noclip", "show_trajectory" -}; +// const std::vector keybindIDs = { +// "open_menu", "toggle_recording", "toggle_playing", +// "toggle_speedhack", "toggle_frame_stepper", "step_frame", +// "toggle_render", "toggle_noclip", "show_trajectory" +// }; -class $modify(CCKeyboardDispatcher) { - bool dispatchKeyboardMSG(enumKeyCodes key, bool isKeyDown, bool isKeyRepeat) { +// class $modify(CCKeyboardDispatcher) { +// bool dispatchKeyboardMSG(enumKeyCodes key, bool isKeyDown, bool isKeyRepeat) { - auto& g = Global::get(); +// auto& g = Global::get(); - int keyInt = static_cast(key); - if (g.allKeybinds.contains(keyInt) && !isKeyRepeat) { - for (size_t i = 0; i < 6; i++) { - if (std::find(g.keybinds[i].begin(), g.keybinds[i].end(), keyInt) != g.keybinds[i].end()) - g.heldButtons[i] = isKeyDown; - } - } +// int keyInt = static_cast(key); +// if (g.allKeybinds.contains(keyInt) && !isKeyRepeat) { +// for (size_t i = 0; i < 6; i++) { +// if (std::find(g.keybinds[i].begin(), g.keybinds[i].end(), keyInt) != g.keybinds[i].end()) +// g.heldButtons[i] = isKeyDown; +// } +// } - // if (key == enumKeyCodes::KEY_L && !isKeyRepeat && isKeyDown) { - // } +// // if (key == enumKeyCodes::KEY_L && !isKeyRepeat && isKeyDown) { +// // } - // if (key == enumKeyCodes::KEY_F && !isKeyRepeat && isKeyDown && PlayLayer::get()) { - // log::debug("POS DEBUG {}", PlayLayer::get()->m_player1->getPosition()); - // log::debug("POS2 DEBUG {}", PlayLayer::get()->m_player2->getPosition()); - // } +// // if (key == enumKeyCodes::KEY_F && !isKeyRepeat && isKeyDown && PlayLayer::get()) { +// // log::debug("POS DEBUG {}", PlayLayer::get()->m_player1->getPosition()); +// // log::debug("POS2 DEBUG {}", PlayLayer::get()->m_player2->getPosition()); +// // } - // if (key == enumKeyCodes::KEY_J && !isKeyRepeat && isKeyDown && PlayLayer::get()) { - // std::string str = ZipUtils::decompressString(PlayLayer::get()->m_level->m_levelString.c_str(), true, 0); - // log::debug("{}", str); - // } +// // if (key == enumKeyCodes::KEY_J && !isKeyRepeat && isKeyDown && PlayLayer::get()) { +// // std::string str = ZipUtils::decompressString(PlayLayer::get()->m_level->m_levelString.c_str(), true, 0); +// // log::debug("{}", str); +// // } - return CCKeyboardDispatcher::dispatchKeyboardMSG(key, isKeyDown, isKeyRepeat); - } -}; +// return CCKeyboardDispatcher::dispatchKeyboardMSG(key, isKeyDown, isKeyRepeat); +// } +// }; -#ifdef GEODE_IS_MOBILE +// #ifdef GEODE_IS_MOBILE -namespace keybinds { +// namespace keybinds { - struct ActionID {}; +// struct ActionID {}; -}; +// }; -#endif +// #endif -#ifdef GEODE_IS_DESKTOP -using namespace keybinds; +// #ifdef GEODE_IS_DESKTOP +// using namespace keybinds; -void onKeybind(bool down, ActionID id) { +// void onKeybind(bool down, ActionID id) { - auto& g = Global::get(); +// auto& g = Global::get(); - if (!down || (LevelEditorLayer::get() && !g.mod->getSettingValue("editor_keybinds")) || g.mod->getSettingValue("disable_keybinds")) - return; +// if (!down || (LevelEditorLayer::get() && !g.mod->getSettingValue("editor_keybinds")) || g.mod->getSettingValue("disable_keybinds")) +// return; - if (g.state != state::recording && g.mod->getSettingValue("recording_only_keybinds")) - return; +// if (g.state != state::recording && g.mod->getSettingValue("recording_only_keybinds")) +// return; - if (id == "open_menu"_spr) { - if (g.layer) { - static_cast(g.layer)->onClose(nullptr); - return; - } - - RecordLayer::openMenu(); - } - - if (id == "toggle_recording"_spr) - Macro::toggleRecording(); - - if (id == "toggle_playing"_spr) - Macro::togglePlaying(); - - if (id == "toggle_frame_stepper"_spr && PlayLayer::get()) - Global::toggleFrameStepper(); - - if (id == "step_frame"_spr) - Global::frameStep(); - - if (id == "toggle_speedhack"_spr) - Global::toggleSpeedhack(); - - if (id == "show_trajectory"_spr) { - g.mod->setSavedValue("macro_show_trajectory", !g.mod->getSavedValue("macro_show_trajectory")); - - if (g.layer) { - if (static_cast(g.layer)->trajectoryToggle) - static_cast(g.layer)->trajectoryToggle->toggle(g.mod->getSavedValue("macro_show_trajectory")); - } - - g.showTrajectory = g.mod->getSavedValue("macro_show_trajectory"); - if (!g.showTrajectory) ShowTrajectory::trajectoryOff(); - } - - if (id == "toggle_render"_spr && PlayLayer::get()) { - bool result = Renderer::toggle(); - - if (result && Global::get().renderer.recording) - Notification::create("Started Rendering", NotificationIcon::Info)->show(); - - if (g.layer) { - if (static_cast(g.layer)->renderToggle) - static_cast(g.layer)->renderToggle->toggle(Global::get().renderer.recording); - } - - } - - if (id == "toggle_noclip"_spr) { - g.mod->setSavedValue("macro_noclip", !g.mod->getSavedValue("macro_noclip")); - - if (g.layer) { - if (static_cast(g.layer)->noclipToggle) - static_cast(g.layer)->noclipToggle->toggle(g.mod->getSavedValue("macro_noclip")); - } - } -} - -$execute{ - BindManager * bm = BindManager::get(); - - bm->registerBindable({ - "open_menu"_spr, - "Open Menu", - "Open Menu.", - { Keybind::create(KEY_F, Modifier::Alt) }, - "xdBot", - false - }); - - bm->registerBindable({ - "toggle_recording"_spr, - "Record macro", - "Toggles recording.", - { Keybind::create(KEY_G, Modifier::Alt) }, - "xdBot", - false - }); - - bm->registerBindable({ - "toggle_playing"_spr, - "Play macro", - "Toggles playing.", - { Keybind::create(KEY_H, Modifier::Alt) }, - "xdBot", - false - }); - - bm->registerBindable({ - "toggle_speedhack"_spr, - "Speedhack", - "Toggles speedhack.", - { Keybind::create(KEY_S, Modifier::Alt) }, - "xdBot", - false - }); - - bm->registerBindable({ - "toggle_noclip"_spr, - "NoClip", - "Toggles NoClip.", - { Keybind::create(KEY_N, Modifier::Alt) }, - "xdBot", - false - }); - - bm->registerBindable({ - "toggle_frame_stepper"_spr, - "Toggle Frame Stepper", - "Toggles frame stepper..", - { Keybind::create(KEY_C, Modifier::Alt) }, - "xdBot", - false - }); - - bm->registerBindable({ - "step_frame"_spr, - "Advance frame", - "Advances one frame if frame stepper is on.", - { Keybind::create(KEY_V) }, - "xdBot" - }); - - bm->setRepeatOptionsFor("step_frame"_spr, { true, 10, 450 }); - - bm->registerBindable({ - "show_trajectory"_spr, - "Show Trajectory", - "Toggles Show Trajectory.", - { Keybind::create(KEY_T, Modifier::Alt) }, - "xdBot" - }); - - bm->registerBindable({ - "toggle_render"_spr, - "Render", - "Toggles rendering.", - { Keybind::create(KEY_P, Modifier::Alt) }, - "xdBot", - false - }); - - for (int i = 0; i < keybindIDs.size(); i++) { - new EventListener([=](InvokeBindEvent* event) { onKeybind(event->isDown(), event->getID()); return ListenerResult::Propagate; - }, InvokeBindFilter(nullptr, (""_spr) + keybindIDs[i])); - } -} -#endif +// if (id == "open_menu"_spr) { +// if (g.layer) { +// static_cast(g.layer)->onClose(nullptr); +// return; +// } + +// RecordLayer::openMenu(); +// } + +// if (id == "toggle_recording"_spr) +// Macro::toggleRecording(); + +// if (id == "toggle_playing"_spr) +// Macro::togglePlaying(); + +// if (id == "toggle_frame_stepper"_spr && PlayLayer::get()) +// Global::toggleFrameStepper(); + +// if (id == "step_frame"_spr) +// Global::frameStep(); + +// if (id == "toggle_speedhack"_spr) +// Global::toggleSpeedhack(); + +// if (id == "show_trajectory"_spr) { +// g.mod->setSavedValue("macro_show_trajectory", !g.mod->getSavedValue("macro_show_trajectory")); + +// if (g.layer) { +// if (static_cast(g.layer)->trajectoryToggle) +// static_cast(g.layer)->trajectoryToggle->toggle(g.mod->getSavedValue("macro_show_trajectory")); +// } + +// g.showTrajectory = g.mod->getSavedValue("macro_show_trajectory"); +// if (!g.showTrajectory) ShowTrajectory::trajectoryOff(); +// } + +// if (id == "toggle_render"_spr && PlayLayer::get()) { +// bool result = Renderer::toggle(); + +// if (result && Global::get().renderer.recording) +// Notification::create("Started Rendering", NotificationIcon::Info)->show(); + +// if (g.layer) { +// if (static_cast(g.layer)->renderToggle) +// static_cast(g.layer)->renderToggle->toggle(Global::get().renderer.recording); +// } + +// } + +// if (id == "toggle_noclip"_spr) { +// g.mod->setSavedValue("macro_noclip", !g.mod->getSavedValue("macro_noclip")); + +// if (g.layer) { +// if (static_cast(g.layer)->noclipToggle) +// static_cast(g.layer)->noclipToggle->toggle(g.mod->getSavedValue("macro_noclip")); +// } +// } +// } + +// $execute{ +// BindManager * bm = BindManager::get(); + +// bm->registerBindable({ +// "open_menu"_spr, +// "Open Menu", +// "Open Menu.", +// { Keybind::create(KEY_F, Modifier::Alt) }, +// "xdBot", +// false +// }); + +// bm->registerBindable({ +// "toggle_recording"_spr, +// "Record macro", +// "Toggles recording.", +// { Keybind::create(KEY_G, Modifier::Alt) }, +// "xdBot", +// false +// }); + +// bm->registerBindable({ +// "toggle_playing"_spr, +// "Play macro", +// "Toggles playing.", +// { Keybind::create(KEY_H, Modifier::Alt) }, +// "xdBot", +// false +// }); + +// bm->registerBindable({ +// "toggle_speedhack"_spr, +// "Speedhack", +// "Toggles speedhack.", +// { Keybind::create(KEY_S, Modifier::Alt) }, +// "xdBot", +// false +// }); + +// bm->registerBindable({ +// "toggle_noclip"_spr, +// "NoClip", +// "Toggles NoClip.", +// { Keybind::create(KEY_N, Modifier::Alt) }, +// "xdBot", +// false +// }); + +// bm->registerBindable({ +// "toggle_frame_stepper"_spr, +// "Toggle Frame Stepper", +// "Toggles frame stepper..", +// { Keybind::create(KEY_C, Modifier::Alt) }, +// "xdBot", +// false +// }); + +// bm->registerBindable({ +// "step_frame"_spr, +// "Advance frame", +// "Advances one frame if frame stepper is on.", +// { Keybind::create(KEY_V) }, +// "xdBot" +// }); + +// bm->setRepeatOptionsFor("step_frame"_spr, { true, 10, 450 }); + +// bm->registerBindable({ +// "show_trajectory"_spr, +// "Show Trajectory", +// "Toggles Show Trajectory.", +// { Keybind::create(KEY_T, Modifier::Alt) }, +// "xdBot" +// }); + +// bm->registerBindable({ +// "toggle_render"_spr, +// "Render", +// "Toggles rendering.", +// { Keybind::create(KEY_P, Modifier::Alt) }, +// "xdBot", +// false +// }); + +// for (int i = 0; i < keybindIDs.size(); i++) { +// new EventListener([=](InvokeBindEvent* event) { onKeybind(event->isDown(), event->getID()); return ListenerResult::Propagate; +// }, InvokeBindFilter(nullptr, (""_spr) + keybindIDs[i])); +// } +// } +// #endif diff --git a/src/main.cpp b/src/main.cpp index 566551cc..b48baafe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,7 +10,7 @@ $execute { - geode::listenForSettingChanges("macro_accuracy", +[](std::string value) { + geode::listenForSettingChanges("macro_accuracy", +[](std::string value) { auto& g = Global::get(); g.frameFixes = false; @@ -18,19 +18,19 @@ if (value == "Frame Fixes") g.frameFixes = true; if (value == "Input Fixes") g.inputFixes = true; - }); + }, Mod::get()); - geode::listenForSettingChanges("frame_fixes_limit", +[](int64_t value) { + geode::listenForSettingChanges("frame_fixes_limit", +[](int64_t value) { Global::get().frameFixesLimit = value; - }); + }, Mod::get()); - geode::listenForSettingChanges("lock_delta", +[](bool value) { + geode::listenForSettingChanges("lock_delta", +[](bool value) { Global::get().lockDelta = value; - }); + }, Mod::get()); - geode::listenForSettingChanges("auto_stop_playing", +[](bool value) { + geode::listenForSettingChanges("auto_stop_playing", +[](bool value) { Global::get().stopPlaying = value; - }); + }, Mod::get()); }; @@ -59,9 +59,9 @@ class $modify(PlayLayer) { } void pauseGame(bool b1) { - Global::updateKeybinds(); + // Global::updateKeybinds(); #ifndef GEODE_IS_IOS - if (!Global::get().renderer.tryPause()) return; + // if (!Global::get().renderer.tryPause()) return; #endif auto& g = Global::get(); @@ -116,7 +116,7 @@ class $modify(PlayLayer) { if (!PlayLayer::init(level, b1, b2)) return false; - Global::updateKeybinds(); + // Global::updateKeybinds(); auto now = std::chrono::system_clock::now(); g.currentSession = std::chrono::duration_cast(now.time_since_epoch()).count(); @@ -131,10 +131,10 @@ class $modify(PlayLayer) { auto& g = Global::get(); int frame = Global::getCurrentFrame(); - #ifndef GEODE_IS_IOS - if (!m_isPracticeMode) - g.renderer.levelStartFrame = frame; - #endif + // #ifndef GEODE_IS_IOS + // if (!m_isPracticeMode) + // g.renderer.levelStartFrame = frame; + // #endif if (g.restart && m_levelSettings->m_platformerMode && g.state != state::none) m_fields->delayedLevelRestart = frame + 2; @@ -198,26 +198,26 @@ class $modify(BGLHook, GJBaseGameLayer) { bool macroInput = false; }; - void processCommands(float dt) { + void processCommands(float dt, bool isHalfTick, bool isLastTick) { auto& g = Global::get(); PlayLayer* pl = PlayLayer::get(); if (!pl) { - return GJBaseGameLayer::processCommands(dt); + return GJBaseGameLayer::processCommands(dt, isHalfTick, isLastTick); } Global::updateSeed(); bool rendering = false; #ifndef GEODE_IS_IOS - rendering = g.renderer.recording || g.renderer.recordingAudio; + // rendering = g.renderer.recording || g.renderer.recordingAudio; #endif if (g.state != state::none || rendering) { #ifndef GEODE_IS_IOS if (!g.firstAttempt) { - g.renderer.dontRender = false; - g.renderer.dontRecordAudio = false; + // g.renderer.dontRender = false; + // g.renderer.dontRecordAudio = false; } #endif int frame = Global::getCurrentFrame(); @@ -232,10 +232,10 @@ class $modify(BGLHook, GJBaseGameLayer) { } if (g.previousFrame == frame && frame != 0 && g.macro.xdBotMacro) - return GJBaseGameLayer::processCommands(dt); + return GJBaseGameLayer::processCommands(dt, isHalfTick, isLastTick); } - GJBaseGameLayer::processCommands(dt); + GJBaseGameLayer::processCommands(dt, isHalfTick, isLastTick); if (g.state == state::none) return; @@ -245,7 +245,7 @@ class $modify(BGLHook, GJBaseGameLayer) { if (g.macro.xdBotMacro && g.restart && !m_levelEndAnimationStarted) { #ifndef GEODE_IS_IOS - if ((m_levelSettings->m_platformerMode && g.state != state::none) || g.renderer.recordingAudio) + if ((m_levelSettings->m_platformerMode && g.state != state::none) /*|| g.renderer.recordingAudio*/) return pl->resetLevelFromStart(); else return pl->resetLevel(); @@ -467,8 +467,8 @@ class $modify(PauseLayer) { Loader::get()->queueInMainThread([] { auto& g = Global::get(); #ifndef GEODE_IS_IOS - if (g.renderer.recording) g.renderer.stop(); - if (g.renderer.recordingAudio) g.renderer.stopAudio(); + // if (g.renderer.recording) g.renderer.stop(); + // if (g.renderer.recordingAudio) g.renderer.stopAudio(); #endif }); } @@ -481,8 +481,8 @@ class $modify(PauseLayer) { Loader::get()->queueInMainThread([] { auto& g = Global::get(); #ifndef GEODE_IS_IOS - if (g.renderer.recording) g.renderer.stop(); - if (g.renderer.recordingAudio) g.renderer.stopAudio(); + // if (g.renderer.recording) g.renderer.stop(); + // if (g.renderer.recordingAudio) g.renderer.stopAudio(); #endif }); } diff --git a/src/practice_fixes/player.cpp b/src/practice_fixes/player.cpp index b782bbbe..c589df3a 100644 --- a/src/practice_fixes/player.cpp +++ b/src/practice_fixes/player.cpp @@ -6,7 +6,7 @@ PlayerData PlayerPracticeFixes::saveData(PlayerObject* player) { #ifdef GEODE_IS_WINDOWS data.m_rotateObjectsRelated.insert(player->m_rotateObjectsRelated.begin(), player->m_rotateObjectsRelated.end()); - data.m_maybeRotatedObjectsMap.insert(player->m_maybeRotatedObjectsMap.begin(), player->m_maybeRotatedObjectsMap.end()); + // data.m_maybeRotatedObjectsMap.insert(player->m_maybeRotatedObjectsMap.begin(), player->m_maybeRotatedObjectsMap.end()); data.m_touchedRings.insert(player->m_touchedRings.begin(), player->m_touchedRings.end()); data.m_ringRelatedSet.insert(player->m_ringRelatedSet.begin(), player->m_ringRelatedSet.end()); data.m_jumpPadRelated.insert(player->m_jumpPadRelated.begin(), player->m_jumpPadRelated.end()); @@ -17,8 +17,8 @@ PlayerData PlayerPracticeFixes::saveData(PlayerObject* player) { #else - // data.m_jumpPadRelated = player->m_jumpPadRelated; - // data.m_holdingButtons = player->m_holdingButtons; + data.m_jumpPadRelated = player->m_jumpPadRelated; + data.m_holdingButtons = player->m_holdingButtons; #endif @@ -68,7 +68,7 @@ PlayerData PlayerPracticeFixes::saveData(PlayerObject* player) { data.m_isCollidingWithSlope = player->m_isCollidingWithSlope; data.m_isBallRotating = player->m_isBallRotating; data.m_unk669 = player->m_unk669; - data.m_currentSlope3 = player->m_currentSlope3; + // data.m_currentSlope3 = player->m_currentSlope3; data.m_currentSlope = player->m_currentSlope; data.unk_584 = player->unk_584; data.m_collidingWithSlopeId = player->m_collidingWithSlopeId; @@ -101,8 +101,8 @@ PlayerData PlayerPracticeFixes::saveData(PlayerObject* player) { data.m_lastJumpTime = player->m_lastJumpTime; data.m_lastFlipTime = player->m_lastFlipTime; data.m_flashTime = player->m_flashTime; - data.m_flashRelated = player->m_flashRelated; - data.m_flashRelated1 = player->m_flashRelated1; + // data.m_flashRelated = player->m_flashRelated; + // data.m_flashRelated1 = player->m_flashRelated1; data.m_lastSpiderFlipTime = player->m_lastSpiderFlipTime; data.m_unkBool5 = player->m_unkBool5; data.m_maybeIsVehicleGlowing = player->m_maybeIsVehicleGlowing; @@ -194,7 +194,6 @@ PlayerData PlayerPracticeFixes::saveData(PlayerObject* player) { data.m_unkA99 = player->m_unkA99; data.m_totalTime = player->m_totalTime; data.m_isBeingSpawnedByDualPortal = player->m_isBeingSpawnedByDualPortal; - data.m_unkAAC = player->m_unkAAC; data.m_unkAngle1 = player->m_unkAngle1; data.m_yVelocityRelated3 = player->m_yVelocityRelated3; data.m_defaultMiniIcon = player->m_defaultMiniIcon; @@ -273,7 +272,7 @@ void PlayerPracticeFixes::applyData(PlayerObject* player, PlayerData data, bool #ifdef GEODE_IS_WINDOWS player->m_rotateObjectsRelated.insert(data.m_rotateObjectsRelated.begin(), data.m_rotateObjectsRelated.end()); - player->m_maybeRotatedObjectsMap.insert(data.m_maybeRotatedObjectsMap.begin(), data.m_maybeRotatedObjectsMap.end()); + // player->m_maybeRotatedObjectsMap.insert(data.m_maybeRotatedObjectsMap.begin(), data.m_maybeRotatedObjectsMap.end()); player->m_touchedRings.insert(data.m_touchedRings.begin(), data.m_touchedRings.end()); player->m_ringRelatedSet.insert(data.m_ringRelatedSet.begin(), data.m_ringRelatedSet.end()); player->m_jumpPadRelated.insert(data.m_jumpPadRelated.begin(), data.m_jumpPadRelated.end()); @@ -286,8 +285,8 @@ void PlayerPracticeFixes::applyData(PlayerObject* player, PlayerData data, bool #else - // player->m_jumpPadRelated = data.m_jumpPadRelated; - // player->m_holdingButtons = data.m_holdingButtons; + player->m_jumpPadRelated = data.m_jumpPadRelated; + player->m_holdingButtons = data.m_holdingButtons; #endif @@ -305,7 +304,7 @@ void PlayerPracticeFixes::applyData(PlayerObject* player, PlayerData data, bool player->m_dashRing = data.m_dashRing; player->m_slopeStartTime = data.m_slopeStartTime; player->m_justPlacedStreak = data.m_justPlacedStreak; - player->m_maybeLastGroundObject = data.m_maybeLastGroundObject; + // player->m_maybeLastGroundObject = data.m_maybeLastGroundObject; player->m_collisionLogTop = data.m_collisionLogTop; player->m_collisionLogBottom = data.m_collisionLogBottom; player->m_collisionLogLeft = data.m_collisionLogLeft; @@ -335,7 +334,7 @@ void PlayerPracticeFixes::applyData(PlayerObject* player, PlayerData data, bool player->m_isCollidingWithSlope = data.m_isCollidingWithSlope; player->m_isBallRotating = data.m_isBallRotating; player->m_unk669 = data.m_unk669; - player->m_currentSlope3 = data.m_currentSlope3; + // player->m_currentSlope3 = data.m_currentSlope3; player->m_currentSlope = data.m_currentSlope; player->unk_584 = data.unk_584; player->m_collidingWithSlopeId = data.m_collidingWithSlopeId; @@ -450,7 +449,8 @@ void PlayerPracticeFixes::applyData(PlayerObject* player, PlayerData data, bool player->m_unkA99 = data.m_unkA99; player->m_totalTime = data.m_totalTime; player->m_isBeingSpawnedByDualPortal = data.m_isBeingSpawnedByDualPortal; - player->m_unkAAC = data.m_unkAAC; + // player->m_audioScale = data.m_audioScale; + player->m_unkAngle1 = data.m_unkAngle1; player->m_unkAngle1 = data.m_unkAngle1; player->m_yVelocityRelated3 = data.m_yVelocityRelated3; player->m_defaultMiniIcon = data.m_defaultMiniIcon; diff --git a/src/renderer/ffmpeg/events.hpp b/src/renderer/ffmpeg/events.hpp index 58585238..ccf0be3e 100644 --- a/src/renderer/ffmpeg/events.hpp +++ b/src/renderer/ffmpeg/events.hpp @@ -1,249 +1,249 @@ -#pragma once - -#include "render_settings.hpp" - -#include - -namespace ffmpeg::events { -namespace impl { -#define DEFAULT_RESULT_ERROR geode::Err("Event was not handled") - - class CreateRecorderEvent : public geode::Event { - public: - CreateRecorderEvent() {m_ptr = nullptr;} - void setPtr(void* ptr) {m_ptr = ptr;} - void* getPtr() const {return m_ptr;} - private: - void* m_ptr; - }; - - class DeleteRecorderEvent : public geode::Event { - public: - DeleteRecorderEvent(void* ptr) {m_ptr = ptr;} - void* getPtr() const {return m_ptr;} - private: - void* m_ptr; - }; - - class InitRecorderEvent : public geode::Event { - public: - InitRecorderEvent(void* ptr, const RenderSettings* settings) { - m_ptr = ptr; - m_renderSettings = settings; - } - - void setResult(geode::Result<>&& result) {m_result = std::move(result);} - geode::Result<> getResult() {return m_result;} - - void* getPtr() const {return m_ptr;} - - const RenderSettings& getRenderSettings() const {return *m_renderSettings;} - - private: - const RenderSettings* m_renderSettings; - void* m_ptr; - geode::Result<> m_result = DEFAULT_RESULT_ERROR; - }; - - class StopRecorderEvent : public geode::Event { - public: - StopRecorderEvent(void* ptr) {m_ptr = ptr;} - void* getPtr() const {return m_ptr;} - private: - void* m_ptr; - }; - - struct Dummy {}; - - class GetWriteFrameFunctionEvent : public geode::Event { - public: - using writeFrame_t = geode::Result<>(Dummy::*)(std::vector const&); - GetWriteFrameFunctionEvent() = default; - - void setFunction(writeFrame_t function) {m_function = function;} - writeFrame_t getFunction() const {return m_function;} - private: - writeFrame_t m_function; - }; - - class CodecRecorderEvent : public geode::Event { - public: - CodecRecorderEvent() = default; - - void setCodecs(std::vector&& codecs) {m_codecs = std::move(codecs);} - const std::vector& getCodecs() const {return m_codecs;} - private: - std::vector m_codecs; - }; - - class MixVideoAudioEvent : public geode::Event { - public: - MixVideoAudioEvent(const std::filesystem::path& videoFile, const std::filesystem::path& audioFile, const std::filesystem::path& outputMp4File) { - m_videoFile = &videoFile; - m_audioFile = &audioFile; - m_outputMp4File = &outputMp4File; - } - - void setResult(geode::Result<>&& result) {m_result = std::move(result);} - geode::Result<> getResult() {return m_result;} - - std::filesystem::path const& getVideoFile() const {return *m_videoFile;} - std::filesystem::path const& getAudioFile() const {return *m_audioFile;} - std::filesystem::path const& getOutputMp4File() const {return *m_outputMp4File;} - - private: - const std::filesystem::path* m_videoFile; - const std::filesystem::path* m_audioFile; - const std::filesystem::path* m_outputMp4File; - geode::Result<> m_result = DEFAULT_RESULT_ERROR; - }; - - class MixVideoRawEvent : public geode::Event { - public: - MixVideoRawEvent(const std::filesystem::path& videoFile, const std::vector& raw, const std::filesystem::path& outputMp4File) { - m_videoFile = &videoFile; - m_raw = &raw; - m_outputMp4File = &outputMp4File; - } - - void setResult(const geode::Result<>& result) {m_result = geode::Result(result);} - geode::Result<> getResult() {return m_result;} - - std::filesystem::path const& getVideoFile() const {return *m_videoFile;} - std::vector const& getRaw() const {return *m_raw;} - std::filesystem::path const& getOutputMp4File() const {return *m_outputMp4File;} - - private: - const std::filesystem::path* m_videoFile; - const std::vector* m_raw; - const std::filesystem::path* m_outputMp4File; - geode::Result<> m_result = DEFAULT_RESULT_ERROR; - }; -#undef DEFAULT_RESULT_ERROR -} - -class Recorder { -public: - Recorder() { - impl::CreateRecorderEvent createEvent; - createEvent.post(); - m_ptr = static_cast(createEvent.getPtr()); - } - - ~Recorder() { - impl::DeleteRecorderEvent deleteEvent(m_ptr); - deleteEvent.post(); - } - - bool isValid() const {return m_ptr != nullptr;} - - /** - * @brief Initializes the Recorder with the specified rendering settings. - * - * This function configures the recorder with the given render settings, - * allocates necessary resources, and prepares for video encoding. - * - * @param settings The rendering settings that define the output characteristics, - * including codec, bitrate, resolution, and pixel format. - * - * @return true if initialization is successful, false otherwise. - */ - geode::Result<> init(RenderSettings const& settings) { - impl::InitRecorderEvent initEvent(m_ptr, &settings); - initEvent.post(); - return initEvent.getResult(); - } - /** - * @brief Stops the recording process and finalizes the output file. - * - * This function ensures that all buffered frames are written to the output file, - * releases allocated resources, and properly closes the output file. - */ - void stop() { - impl::StopRecorderEvent(m_ptr).post(); - } - - /** - * @brief Writes a single video frame to the output. - * - * This function takes the frame data as a byte vector and encodes it - * to the output file. The frame data must match the expected format and - * dimensions defined during initialization. - * - * @param frameData A vector containing the raw frame data to be written. - * - * @return true if the frame is successfully written, false if there is an error. - * - * @warning Ensure that the frameData size matches the expected dimensions of the frame. - */ - geode::Result<> writeFrame(const std::vector& frameData) { - static auto writeFrame = []{ - impl::GetWriteFrameFunctionEvent event; - event.post(); - return event.getFunction(); - }(); - if (!writeFrame) return geode::Err("Failed to call writeFrame function."); - return std::invoke(writeFrame, m_ptr, frameData); - } - - /** - * @brief Retrieves a list of available codecs for video encoding. - * - * This function iterates through all available codecs in FFmpeg and - * returns a sorted vector of codec names. - * - * @return A vector representing the names of available codecs. - */ - static std::vector getAvailableCodecs() { - impl::CodecRecorderEvent codecEvent; - codecEvent.post(); - return codecEvent.getCodecs(); - } -private: - impl::Dummy* m_ptr = nullptr; -}; - -class AudioMixer { -public: - AudioMixer() = delete; - - /** - * @brief Mixes a video file and an audio file into a single MP4 output. - * - * This function takes an input video file and an audio file, and merges them into a single MP4 output file. - * The output MP4 file will have both the video and audio streams synchronized. - * - * @param videoFile The path to the input video file. - * @param audioFile The path to the input audio file. - * @param outputMp4File The path where the output MP4 file will be saved. - * - * @warning The audio file is expected to contain stereo (dual-channel) audio. Using other formats might lead to unexpected results. - * @warning The video file is expected to contain a single video stream. Only the first video stream will be copied. - */ - static geode::Result<> mixVideoAudio(std::filesystem::path const& videoFile, std::filesystem::path const& audioFile, std::filesystem::path const& outputMp4File) { - impl::MixVideoAudioEvent mixEvent(videoFile, audioFile, outputMp4File); - mixEvent.post(); - return mixEvent.getResult(); - } - - /** - * @brief Mixes a video file and raw audio data into a single MP4 output. - * - * This function takes an input video file and raw audio data (in the form of a vector of floating-point samples), - * and merges them into a single MP4 output file. - * - * @param videoFile The path to the input video file. - * @param raw A vector containing the raw audio data (floating-point samples). - * @param outputMp4File The path where the output MP4 file will be saved. - * - * @warning The raw audio data is expected to be stereo (dual-channel). Using mono or multi-channel audio might lead to issues. - * @warning The video file is expected to contain a single video stream. Only the first video stream will be copied. - */ - static geode::Result<> mixVideoRaw(std::filesystem::path const& videoFile, const std::vector& raw, std::filesystem::path const& outputMp4File) { - impl::MixVideoRawEvent mixEvent(videoFile, raw, outputMp4File); - mixEvent.post(); - return mixEvent.getResult(); - } -}; - -} \ No newline at end of file +// #pragma once + +// #include "render_settings.hpp" + +// #include + +// namespace ffmpeg::events { +// namespace impl { +// #define DEFAULT_RESULT_ERROR geode::Err("Event was not handled") + +// class CreateRecorderEvent : public geode::Event { +// public: +// CreateRecorderEvent() {m_ptr = nullptr;} +// void setPtr(void* ptr) {m_ptr = ptr;} +// void* getPtr() const {return m_ptr;} +// private: +// void* m_ptr; +// }; + +// class DeleteRecorderEvent : public geode::Event { +// public: +// DeleteRecorderEvent(void* ptr) {m_ptr = ptr;} +// void* getPtr() const {return m_ptr;} +// private: +// void* m_ptr; +// }; + +// class InitRecorderEvent : public geode::Event { +// public: +// InitRecorderEvent(void* ptr, const RenderSettings* settings) { +// m_ptr = ptr; +// m_renderSettings = settings; +// } + +// void setResult(geode::Result<>&& result) {m_result = std::move(result);} +// geode::Result<> getResult() {return m_result;} + +// void* getPtr() const {return m_ptr;} + +// const RenderSettings& getRenderSettings() const {return *m_renderSettings;} + +// private: +// const RenderSettings* m_renderSettings; +// void* m_ptr; +// geode::Result<> m_result = DEFAULT_RESULT_ERROR; +// }; + +// class StopRecorderEvent : public geode::Event { +// public: +// StopRecorderEvent(void* ptr) {m_ptr = ptr;} +// void* getPtr() const {return m_ptr;} +// private: +// void* m_ptr; +// }; + +// struct Dummy {}; + +// class GetWriteFrameFunctionEvent : public geode::Event { +// public: +// using writeFrame_t = geode::Result<>(Dummy::*)(std::vector const&); +// GetWriteFrameFunctionEvent() = default; + +// void setFunction(writeFrame_t function) {m_function = function;} +// writeFrame_t getFunction() const {return m_function;} +// private: +// writeFrame_t m_function; +// }; + +// class CodecRecorderEvent : public geode::Event { +// public: +// CodecRecorderEvent() = default; + +// void setCodecs(std::vector&& codecs) {m_codecs = std::move(codecs);} +// const std::vector& getCodecs() const {return m_codecs;} +// private: +// std::vector m_codecs; +// }; + +// class MixVideoAudioEvent : public geode::Event { +// public: +// MixVideoAudioEvent(const std::filesystem::path& videoFile, const std::filesystem::path& audioFile, const std::filesystem::path& outputMp4File) { +// m_videoFile = &videoFile; +// m_audioFile = &audioFile; +// m_outputMp4File = &outputMp4File; +// } + +// void setResult(geode::Result<>&& result) {m_result = std::move(result);} +// geode::Result<> getResult() {return m_result;} + +// std::filesystem::path const& getVideoFile() const {return *m_videoFile;} +// std::filesystem::path const& getAudioFile() const {return *m_audioFile;} +// std::filesystem::path const& getOutputMp4File() const {return *m_outputMp4File;} + +// private: +// const std::filesystem::path* m_videoFile; +// const std::filesystem::path* m_audioFile; +// const std::filesystem::path* m_outputMp4File; +// geode::Result<> m_result = DEFAULT_RESULT_ERROR; +// }; + +// class MixVideoRawEvent : public geode::Event { +// public: +// MixVideoRawEvent(const std::filesystem::path& videoFile, const std::vector& raw, const std::filesystem::path& outputMp4File) { +// m_videoFile = &videoFile; +// m_raw = &raw; +// m_outputMp4File = &outputMp4File; +// } + +// void setResult(const geode::Result<>& result) {m_result = geode::Result(result);} +// geode::Result<> getResult() {return m_result;} + +// std::filesystem::path const& getVideoFile() const {return *m_videoFile;} +// std::vector const& getRaw() const {return *m_raw;} +// std::filesystem::path const& getOutputMp4File() const {return *m_outputMp4File;} + +// private: +// const std::filesystem::path* m_videoFile; +// const std::vector* m_raw; +// const std::filesystem::path* m_outputMp4File; +// geode::Result<> m_result = DEFAULT_RESULT_ERROR; +// }; +// #undef DEFAULT_RESULT_ERROR +// } + +// class Recorder { +// public: +// Recorder() { +// impl::CreateRecorderEvent createEvent; +// createEvent.post(); +// m_ptr = static_cast(createEvent.getPtr()); +// } + +// ~Recorder() { +// impl::DeleteRecorderEvent deleteEvent(m_ptr); +// deleteEvent.post(); +// } + +// bool isValid() const {return m_ptr != nullptr;} + +// /** +// * @brief Initializes the Recorder with the specified rendering settings. +// * +// * This function configures the recorder with the given render settings, +// * allocates necessary resources, and prepares for video encoding. +// * +// * @param settings The rendering settings that define the output characteristics, +// * including codec, bitrate, resolution, and pixel format. +// * +// * @return true if initialization is successful, false otherwise. +// */ +// geode::Result<> init(RenderSettings const& settings) { +// impl::InitRecorderEvent initEvent(m_ptr, &settings); +// initEvent.post(); +// return initEvent.getResult(); +// } +// /** +// * @brief Stops the recording process and finalizes the output file. +// * +// * This function ensures that all buffered frames are written to the output file, +// * releases allocated resources, and properly closes the output file. +// */ +// void stop() { +// impl::StopRecorderEvent(m_ptr).post(); +// } + +// /** +// * @brief Writes a single video frame to the output. +// * +// * This function takes the frame data as a byte vector and encodes it +// * to the output file. The frame data must match the expected format and +// * dimensions defined during initialization. +// * +// * @param frameData A vector containing the raw frame data to be written. +// * +// * @return true if the frame is successfully written, false if there is an error. +// * +// * @warning Ensure that the frameData size matches the expected dimensions of the frame. +// */ +// geode::Result<> writeFrame(const std::vector& frameData) { +// static auto writeFrame = []{ +// impl::GetWriteFrameFunctionEvent event; +// event.post(); +// return event.getFunction(); +// }(); +// if (!writeFrame) return geode::Err("Failed to call writeFrame function."); +// return std::invoke(writeFrame, m_ptr, frameData); +// } + +// /** +// * @brief Retrieves a list of available codecs for video encoding. +// * +// * This function iterates through all available codecs in FFmpeg and +// * returns a sorted vector of codec names. +// * +// * @return A vector representing the names of available codecs. +// */ +// static std::vector getAvailableCodecs() { +// impl::CodecRecorderEvent codecEvent; +// codecEvent.post(); +// return codecEvent.getCodecs(); +// } +// private: +// impl::Dummy* m_ptr = nullptr; +// }; + +// class AudioMixer { +// public: +// AudioMixer() = delete; + +// /** +// * @brief Mixes a video file and an audio file into a single MP4 output. +// * +// * This function takes an input video file and an audio file, and merges them into a single MP4 output file. +// * The output MP4 file will have both the video and audio streams synchronized. +// * +// * @param videoFile The path to the input video file. +// * @param audioFile The path to the input audio file. +// * @param outputMp4File The path where the output MP4 file will be saved. +// * +// * @warning The audio file is expected to contain stereo (dual-channel) audio. Using other formats might lead to unexpected results. +// * @warning The video file is expected to contain a single video stream. Only the first video stream will be copied. +// */ +// static geode::Result<> mixVideoAudio(std::filesystem::path const& videoFile, std::filesystem::path const& audioFile, std::filesystem::path const& outputMp4File) { +// impl::MixVideoAudioEvent mixEvent(videoFile, audioFile, outputMp4File); +// mixEvent.post(); +// return mixEvent.getResult(); +// } + +// /** +// * @brief Mixes a video file and raw audio data into a single MP4 output. +// * +// * This function takes an input video file and raw audio data (in the form of a vector of floating-point samples), +// * and merges them into a single MP4 output file. +// * +// * @param videoFile The path to the input video file. +// * @param raw A vector containing the raw audio data (floating-point samples). +// * @param outputMp4File The path where the output MP4 file will be saved. +// * +// * @warning The raw audio data is expected to be stereo (dual-channel). Using mono or multi-channel audio might lead to issues. +// * @warning The video file is expected to contain a single video stream. Only the first video stream will be copied. +// */ +// static geode::Result<> mixVideoRaw(std::filesystem::path const& videoFile, const std::vector& raw, std::filesystem::path const& outputMp4File) { +// impl::MixVideoRawEvent mixEvent(videoFile, raw, outputMp4File); +// mixEvent.post(); +// return mixEvent.getResult(); +// } +// }; + +// } \ No newline at end of file diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index ab46383c..fe646cbb 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -1,841 +1,841 @@ -#include "../includes.hpp" -#include "../ui/game_ui.hpp" -#include "../utils/subprocess.hpp" +// #include "../includes.hpp" +// #include "../ui/game_ui.hpp" +// #include "../utils/subprocess.hpp" -#include -#include -#include -#include -#include -#include -#include -#include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include -#include -#include -#include +// #include +// #include +// #include -#ifndef GEODE_IS_IOS -class $modify(CCParticleSystemQuad) { +// #ifndef GEODE_IS_IOS +// class $modify(CCParticleSystemQuad) { - static CCParticleSystemQuad* create(const char* v1, bool v2) { - CCParticleSystemQuad* ret = CCParticleSystemQuad::create(v1, v2); - if (!Global::get().renderer.recording) return ret; +// static CCParticleSystemQuad* create(const char* v1, bool v2) { +// CCParticleSystemQuad* ret = CCParticleSystemQuad::create(v1, v2); +// if (!Global::get().renderer.recording) return ret; - if (std::string_view(v1) == "levelComplete01.plist" && Mod::get()->getSavedValue("render_hide_levelcomplete")) - ret->setVisible(false); +// if (std::string_view(v1) == "levelComplete01.plist" && Mod::get()->getSavedValue("render_hide_levelcomplete")) +// ret->setVisible(false); - return ret; - } +// return ret; +// } -}; +// }; -class $modify(CCCircleWave) { +// class $modify(CCCircleWave) { - static CCCircleWave* create(float v1, float v2, float v3, bool v4, bool v5) { - CCCircleWave* ret = CCCircleWave::create(v1, v2, v3, v4, v5); +// static CCCircleWave* create(float v1, float v2, float v3, bool v4, bool v5) { +// CCCircleWave* ret = CCCircleWave::create(v1, v2, v3, v4, v5); - if (!Global::get().renderer.recording || !PlayLayer::get()->m_levelEndAnimationStarted) return ret; +// if (!Global::get().renderer.recording || !PlayLayer::get()->m_levelEndAnimationStarted) return ret; - if (Mod::get()->getSavedValue("render_hide_levelcomplete")) - ret->setVisible(false); +// if (Mod::get()->getSavedValue("render_hide_levelcomplete")) +// ret->setVisible(false); - return ret; - } +// return ret; +// } -}; +// }; -class $modify(PlayLayer) { +// class $modify(PlayLayer) { - void showCompleteText() { - PlayLayer::showCompleteText(); - if (!Global::get().renderer.recording) return; +// void showCompleteText() { +// PlayLayer::showCompleteText(); +// if (!Global::get().renderer.recording) return; - if (m_levelEndAnimationStarted && Mod::get()->getSavedValue("render_hide_levelcomplete")) { - for (CCNode* node : CCArrayExt(getChildren())) { - CCSprite* spr = typeinfo_cast(node); - if (!spr) continue; - if (!isSpriteFrameName(spr, "GJ_levelComplete_001.png")) continue; - spr->setVisible(false); - } - } - } +// if (m_levelEndAnimationStarted && Mod::get()->getSavedValue("render_hide_levelcomplete")) { +// for (CCNode* node : CCArrayExt(getChildren())) { +// CCSprite* spr = typeinfo_cast(node); +// if (!spr) continue; +// if (!isSpriteFrameName(spr, "GJ_levelComplete_001.png")) continue; +// spr->setVisible(false); +// } +// } +// } -}; +// }; -class $modify(EndLevelLayer) { +// class $modify(EndLevelLayer) { - void customSetup() { - EndLevelLayer::customSetup(); +// void customSetup() { +// EndLevelLayer::customSetup(); - if (!PlayLayer::get()) return; - if (Global::get().renderer.recording && PlayLayer::get()->m_levelEndAnimationStarted && Mod::get()->getSavedValue("render_hide_endscreen")) { - Loader::get()->queueInMainThread([this] { - setVisible(false); - }); - } - } +// if (!PlayLayer::get()) return; +// if (Global::get().renderer.recording && PlayLayer::get()->m_levelEndAnimationStarted && Mod::get()->getSavedValue("render_hide_endscreen")) { +// Loader::get()->queueInMainThread([this] { +// setVisible(false); +// }); +// } +// } -}; +// }; -class $modify(FMODAudioEngine) { +// class $modify(FMODAudioEngine) { - int playEffect(gd::string path, float speed, float p2, float volume) { - if (path == "explode_11.ogg" && Global::get().renderer.recording) return 0; +// int playEffect(gd::string path, float speed, float p2, float volume) { +// if (path == "explode_11.ogg" && Global::get().renderer.recording) return 0; - if (path != "playSound_01.ogg" || !Global::get().renderer.recordingAudio) - return FMODAudioEngine::playEffect(path, speed, p2, volume); +// if (path != "playSound_01.ogg" || !Global::get().renderer.recordingAudio) +// return FMODAudioEngine::playEffect(path, speed, p2, volume); - return 0; - } -}; +// return 0; +// } +// }; -class $modify(GJBaseGameLayer) { - void update(float dt) { - GJBaseGameLayer::update(dt); - auto& g = Global::get(); +// class $modify(GJBaseGameLayer) { +// void update(float dt) { +// GJBaseGameLayer::update(dt); +// auto& g = Global::get(); - PlayLayer* pl = PlayLayer::get(); +// PlayLayer* pl = PlayLayer::get(); - if ((!g.renderer.recording && !g.renderer.recordingAudio) || !pl) return; +// if ((!g.renderer.recording && !g.renderer.recordingAudio) || !pl) return; - int frame = Global::getCurrentFrame(); +// int frame = Global::getCurrentFrame(); - if (g.renderer.recording && frame % static_cast(Global::getTPS() / g.renderer.fps) == 0) - return g.renderer.handleRecording(pl, frame); +// if (g.renderer.recording && frame % static_cast(Global::getTPS() / g.renderer.fps) == 0) +// return g.renderer.handleRecording(pl, frame); - if (g.renderer.recordingAudio && !g.renderer.startedAudio) { - return g.renderer.startAudio(pl); - } +// if (g.renderer.recordingAudio && !g.renderer.startedAudio) { +// return g.renderer.startAudio(pl); +// } - if (g.renderer.recordingAudio && frame % static_cast(Global::getTPS() / g.renderer.fps) == 0) - return g.renderer.handleAudioRecording(pl, frame); - } -}; +// if (g.renderer.recordingAudio && frame % static_cast(Global::getTPS() / g.renderer.fps) == 0) +// return g.renderer.handleAudioRecording(pl, frame); +// } +// }; -float leftOver = 0.f; +// float leftOver = 0.f; -class $modify(CCScheduler) { +// class $modify(CCScheduler) { - void update(float dt) { - Renderer& r = Global::get().renderer; - if (!r.recording) return CCScheduler::update(dt); +// void update(float dt) { +// Renderer& r = Global::get().renderer; +// if (!r.recording) return CCScheduler::update(dt); - r.changeRes(false); +// r.changeRes(false); - using namespace std::literals; +// using namespace std::literals; - float newDt = 1.f / Global::getTPS(); - - auto startTime = std::chrono::high_resolution_clock::now(); - int mult = static_cast((dt + leftOver) / newDt); - - for (int i = 0; i < mult; ++i) { - CCScheduler::update(newDt); - if (std::chrono::high_resolution_clock::now() - startTime > 33.333ms) { - mult = i + 1; - break; - } - } +// float newDt = 1.f / Global::getTPS(); + +// auto startTime = std::chrono::high_resolution_clock::now(); +// int mult = static_cast((dt + leftOver) / newDt); + +// for (int i = 0; i < mult; ++i) { +// CCScheduler::update(newDt); +// if (std::chrono::high_resolution_clock::now() - startTime > 33.333ms) { +// mult = i + 1; +// break; +// } +// } - leftOver += (dt - newDt * mult); +// leftOver += (dt - newDt * mult); - r.changeRes(true); - } +// r.changeRes(true); +// } -}; +// }; -bool Renderer::shouldUseAPI() { - #ifdef GEODE_IS_WINDOWS +// bool Renderer::shouldUseAPI() { +// #ifdef GEODE_IS_WINDOWS - bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); - std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); - bool foundExe = std::filesystem::exists(ffmpegPath) && ffmpegPath.filename().string() == "ffmpeg.exe"; +// bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); +// std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); +// bool foundExe = std::filesystem::exists(ffmpegPath) && ffmpegPath.filename().string() == "ffmpeg.exe"; - return !foundExe && foundApi; +// return !foundExe && foundApi; -#else +// #else - return true; +// return true; -#endif +// #endif -} +// } -bool Renderer::toggle() { - auto& g = Global::get(); - if (Loader::get()->isModLoaded("syzzi.click_between_frames")) { - FLAlertLayer::create("Render", "Disable CBF in Geode to render a level.", "OK")->show(); - return false; - } +// bool Renderer::toggle() { +// auto& g = Global::get(); +// if (Loader::get()->isModLoaded("syzzi.click_between_frames")) { +// FLAlertLayer::create("Render", "Disable CBF in Geode to render a level.", "OK")->show(); +// return false; +// } - bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); - std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); - bool foundExe = std::filesystem::exists(ffmpegPath) && ffmpegPath.filename().string() == "ffmpeg.exe"; +// bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); +// std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); +// bool foundExe = std::filesystem::exists(ffmpegPath) && ffmpegPath.filename().string() == "ffmpeg.exe"; - g.renderer.usingApi = Renderer::shouldUseAPI(); +// g.renderer.usingApi = Renderer::shouldUseAPI(); - if (g.renderer.recording || g.renderer.recordingAudio) { - g.renderer.recordingAudio ? g.renderer.stopAudio() : g.renderer.stop(Global::getCurrentFrame()); - } - else { +// if (g.renderer.recording || g.renderer.recordingAudio) { +// g.renderer.recordingAudio ? g.renderer.stopAudio() : g.renderer.stop(Global::getCurrentFrame()); +// } +// else { -#ifdef GEODE_IS_WINDOWS - if (!foundExe && !foundApi) { - geode::createQuickPopup( - "Error", - "FFmpeg not found, set the path to the .exe in mod settings or install FFmpeg API.\nOpen download link?", - "Cancel", "Yes", - [](auto, bool btn2) { - if (btn2) { - FLAlertLayer::create("Info", "Unzip the downloaded file and look for ffmpeg.exe in the 'bin' folder.", "Ok")->show(); - utils::web::openLinkInBrowser("https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-essentials.7z"); - } - } - ); - return false; - } - - g.renderer.ffmpegPath = ffmpegPath.string(); -#else - if (!foundApi) { - FLAlertLayer::create("Error", "FFmpeg API not found. Download it to render a level.", "Ok")->show(); - return false; - } -#endif - - if (!PlayLayer::get()) { - FLAlertLayer::create("Warning", "Open a level to start rendering it.", "Ok")->show(); - return false; - } - - std::filesystem::path path = Mod::get()->getSettingValue("render_folder"); - - if (std::filesystem::exists(path)) - g.renderer.start(); - else { - if (utils::file::createDirectoryAll(path).isOk()) - g.renderer.start(); - else { - FLAlertLayer::create("Error", "There was an error getting the renders folder. ID: 11", "Ok")->show(); - return false; - } - } - } - - Interface::updateLabels(); - - return true; -} - -void Renderer::start() { - PlayLayer* pl = PlayLayer::get(); - GameManager* gm = GameManager::sharedState(); - Mod* mod = Mod::get(); - fmod = FMODAudioEngine::sharedEngine(); - - fps = std::stoi(mod->getSavedValue("render_fps")); - codec = mod->getSavedValue("render_codec"); - bitrate = mod->getSavedValue("render_bitrate") + "M"; - extraArgs = mod->getSavedValue("render_args"); - videoArgs = mod->getSavedValue("render_video_args"); - extraAudioArgs = mod->getSavedValue("render_audio_args"); - SFXVolume = mod->getSavedValue("render_sfx_volume"); - musicVolume = mod->getSavedValue("render_music_volume"); - stopAfter = geode::utils::numFromString(mod->getSavedValue("render_seconds_after")).unwrapOr(0.f); - audioMode = AudioMode::Off; - std::string extension = mod->getSavedValue("render_file_extension"); - - if (mod->getSavedValue("render_only_song")) audioMode = AudioMode::Song; - if (mod->getSavedValue("render_record_audio")) audioMode = AudioMode::Record; - - auto now = std::chrono::system_clock::now(); - auto duration = now.time_since_epoch(); - auto timestamp = std::chrono::duration_cast(duration).count(); +// #ifdef GEODE_IS_WINDOWS +// if (!foundExe && !foundApi) { +// geode::createQuickPopup( +// "Error", +// "FFmpeg not found, set the path to the .exe in mod settings or install FFmpeg API.\nOpen download link?", +// "Cancel", "Yes", +// [](auto, bool btn2) { +// if (btn2) { +// FLAlertLayer::create("Info", "Unzip the downloaded file and look for ffmpeg.exe in the 'bin' folder.", "Ok")->show(); +// utils::web::openLinkInBrowser("https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-essentials.7z"); +// } +// } +// ); +// return false; +// } + +// g.renderer.ffmpegPath = ffmpegPath.string(); +// #else +// if (!foundApi) { +// FLAlertLayer::create("Error", "FFmpeg API not found. Download it to render a level.", "Ok")->show(); +// return false; +// } +// #endif + +// if (!PlayLayer::get()) { +// FLAlertLayer::create("Warning", "Open a level to start rendering it.", "Ok")->show(); +// return false; +// } + +// std::filesystem::path path = Mod::get()->getSettingValue("render_folder"); + +// if (std::filesystem::exists(path)) +// g.renderer.start(); +// else { +// if (utils::file::createDirectoryAll(path).isOk()) +// g.renderer.start(); +// else { +// FLAlertLayer::create("Error", "There was an error getting the renders folder. ID: 11", "Ok")->show(); +// return false; +// } +// } +// } + +// Interface::updateLabels(); + +// return true; +// } + +// void Renderer::start() { +// PlayLayer* pl = PlayLayer::get(); +// GameManager* gm = GameManager::sharedState(); +// Mod* mod = Mod::get(); +// fmod = FMODAudioEngine::sharedEngine(); + +// fps = std::stoi(mod->getSavedValue("render_fps")); +// codec = mod->getSavedValue("render_codec"); +// bitrate = mod->getSavedValue("render_bitrate") + "M"; +// extraArgs = mod->getSavedValue("render_args"); +// videoArgs = mod->getSavedValue("render_video_args"); +// extraAudioArgs = mod->getSavedValue("render_audio_args"); +// SFXVolume = mod->getSavedValue("render_sfx_volume"); +// musicVolume = mod->getSavedValue("render_music_volume"); +// stopAfter = geode::utils::numFromString(mod->getSavedValue("render_seconds_after")).unwrapOr(0.f); +// audioMode = AudioMode::Off; +// std::string extension = mod->getSavedValue("render_file_extension"); + +// if (mod->getSavedValue("render_only_song")) audioMode = AudioMode::Song; +// if (mod->getSavedValue("render_record_audio")) audioMode = AudioMode::Record; + +// auto now = std::chrono::system_clock::now(); +// auto duration = now.time_since_epoch(); +// auto timestamp = std::chrono::duration_cast(duration).count(); - std::string filename = fmt::format("render_{}_{}{}", std::string_view(pl->m_level->m_levelName), std::to_string(timestamp), extension); - std::string path = (Mod::get()->getSettingValue("render_folder") / filename).string(); - - width = std::stoi(mod->getSavedValue("render_width2")); - height = std::stoi(mod->getSavedValue("render_height")); - - if (width % 2 != 0) - width++; - if (height % 2 != 0) - height++; - - renderer.width = width; - renderer.height = height; - ogRes = cocos2d::CCEGLView::get()->getDesignResolutionSize(); - ogScaleX = cocos2d::CCEGLView::get()->m_fScaleX; - ogScaleY = cocos2d::CCEGLView::get()->m_fScaleY; - - dontRender = true; - recording = true; - frameHasData = false; - levelFinished = false; - startedAudio = false; - timeAfter = 0.f; - finishFrame = 0; - pauseAttempts = 0; - lastFrame_t = extra_t = 0; - - if (!pl->m_levelEndAnimationStarted && pl->m_isPaused) - Global::get().restart = true; - - if (Global::get().state != state::playing && !Global::get().macro.inputs.empty()) - Macro::togglePlaying(); - - std::string songFile = pl->m_level->getAudioFileName(); - if (pl->m_level->m_songID == 0) - songFile = cocos2d::CCFileUtils::sharedFileUtils()->fullPathForFilename(songFile.c_str(), false); - - float songOffset = pl->m_levelSettings->m_songOffset + (fmod->m_musicOffset / 1000.f) + (levelStartFrame / Global::getTPS()); - bool fadeIn = pl->m_levelSettings->m_fadeIn; - bool fadeOut = pl->m_levelSettings->m_fadeOut; - int bitrateApi = geode::utils::numFromString(mod->getSavedValue("render_bitrate")).unwrapOr(30) * 1000000; - - currentFrame.resize(width * height * 3, 0); - renderedFrames.clear(); - renderer.begin(); - changeRes(false); - - ffmpeg::RenderSettings settings; - settings.m_pixelFormat = ffmpeg::PixelFormat::RGB24; - settings.m_codec = codec; - settings.m_bitrate = bitrateApi; - settings.m_width = width; - settings.m_height = height; - settings.m_fps = fps; - settings.m_outputFile = path; - settings.m_colorspaceFilters = videoArgs; - - if (!Mod::get()->setSavedValue("first_render_", true)) { - FLAlertLayer::create( - "Warning", - "If you have a macro for the level, let it run to allow the level to render.", - "Ok" - )->show(); - } - - std::thread([&, path, songFile, songOffset, fadeIn, fadeOut, extension, bitrateApi, settings]() { - if (!codec.empty()) codec = "-c:v " + codec + " "; - if (!bitrate.empty()) bitrate = "-b:v " + bitrate + " "; - if (extraArgs.empty()) extraArgs = "-pix_fmt yuv420p"; - if (videoArgs.empty()) videoArgs = "colorspace=all=bt709:iall=bt470bg:fast=1"; - - float fadeInTime = geode::utils::numFromString(Mod::get()->getSavedValue("render_fade_in_time")).unwrapOr(0.f); - bool fadeInVideo = Mod::get()->getSavedValue("render_fade_in") && fadeInTime != 0.f; - float fadeOutTime = geode::utils::numFromString(Mod::get()->getSavedValue("render_fade_out_time")).unwrapOr(0.f); - bool fadeOutVideo = Mod::get()->getSavedValue("render_fade_out") && fadeOutTime != 0.f; - - std::string fadeArgs; - std::string command; - #ifdef GEODE_IS_WINDOWS - subprocess::Popen process; - #endif - - if (fadeInVideo) - fadeArgs = fmt::format(",fade=t=in:st=0:d={}", fadeInTime); - - if (usingApi) { - auto res = ffmpeg.init(settings); - if (res.isErr()) { - Loader::get()->queueInMainThread([] { - // std::string err = res.unwrapErr(); - FLAlertLayer::create("Error", "FFmpeg API failed to initialize: ", "Ok")->show(); - }); - - audioMode = AudioMode::Off; - return stop(); - } +// std::string filename = fmt::format("render_{}_{}{}", std::string_view(pl->m_level->m_levelName), std::to_string(timestamp), extension); +// std::string path = (Mod::get()->getSettingValue("render_folder") / filename).string(); + +// width = std::stoi(mod->getSavedValue("render_width2")); +// height = std::stoi(mod->getSavedValue("render_height")); + +// if (width % 2 != 0) +// width++; +// if (height % 2 != 0) +// height++; + +// renderer.width = width; +// renderer.height = height; +// ogRes = cocos2d::CCEGLView::get()->getDesignResolutionSize(); +// ogScaleX = cocos2d::CCEGLView::get()->m_fScaleX; +// ogScaleY = cocos2d::CCEGLView::get()->m_fScaleY; + +// dontRender = true; +// recording = true; +// frameHasData = false; +// levelFinished = false; +// startedAudio = false; +// timeAfter = 0.f; +// finishFrame = 0; +// pauseAttempts = 0; +// lastFrame_t = extra_t = 0; + +// if (!pl->m_levelEndAnimationStarted && pl->m_isPaused) +// Global::get().restart = true; + +// if (Global::get().state != state::playing && !Global::get().macro.inputs.empty()) +// Macro::togglePlaying(); + +// std::string songFile = pl->m_level->getAudioFileName(); +// if (pl->m_level->m_songID == 0) +// songFile = cocos2d::CCFileUtils::sharedFileUtils()->fullPathForFilename(songFile.c_str(), false); + +// float songOffset = pl->m_levelSettings->m_songOffset + (fmod->m_musicOffset / 1000.f) + (levelStartFrame / Global::getTPS()); +// bool fadeIn = pl->m_levelSettings->m_fadeIn; +// bool fadeOut = pl->m_levelSettings->m_fadeOut; +// int bitrateApi = geode::utils::numFromString(mod->getSavedValue("render_bitrate")).unwrapOr(30) * 1000000; + +// currentFrame.resize(width * height * 3, 0); +// renderedFrames.clear(); +// renderer.begin(); +// changeRes(false); + +// ffmpeg::RenderSettings settings; +// settings.m_pixelFormat = ffmpeg::PixelFormat::RGB24; +// settings.m_codec = codec; +// settings.m_bitrate = bitrateApi; +// settings.m_width = width; +// settings.m_height = height; +// settings.m_fps = fps; +// settings.m_outputFile = path; +// settings.m_colorspaceFilters = videoArgs; + +// if (!Mod::get()->setSavedValue("first_render_", true)) { +// FLAlertLayer::create( +// "Warning", +// "If you have a macro for the level, let it run to allow the level to render.", +// "Ok" +// )->show(); +// } + +// std::thread([&, path, songFile, songOffset, fadeIn, fadeOut, extension, bitrateApi, settings]() { +// if (!codec.empty()) codec = "-c:v " + codec + " "; +// if (!bitrate.empty()) bitrate = "-b:v " + bitrate + " "; +// if (extraArgs.empty()) extraArgs = "-pix_fmt yuv420p"; +// if (videoArgs.empty()) videoArgs = "colorspace=all=bt709:iall=bt470bg:fast=1"; + +// float fadeInTime = geode::utils::numFromString(Mod::get()->getSavedValue("render_fade_in_time")).unwrapOr(0.f); +// bool fadeInVideo = Mod::get()->getSavedValue("render_fade_in") && fadeInTime != 0.f; +// float fadeOutTime = geode::utils::numFromString(Mod::get()->getSavedValue("render_fade_out_time")).unwrapOr(0.f); +// bool fadeOutVideo = Mod::get()->getSavedValue("render_fade_out") && fadeOutTime != 0.f; + +// std::string fadeArgs; +// std::string command; +// #ifdef GEODE_IS_WINDOWS +// subprocess::Popen process; +// #endif + +// if (fadeInVideo) +// fadeArgs = fmt::format(",fade=t=in:st=0:d={}", fadeInTime); + +// if (usingApi) { +// auto res = ffmpeg.init(settings); +// if (res.isErr()) { +// Loader::get()->queueInMainThread([] { +// // std::string err = res.unwrapErr(); +// FLAlertLayer::create("Error", "FFmpeg API failed to initialize: ", "Ok")->show(); +// }); + +// audioMode = AudioMode::Off; +// return stop(); +// } - } else { - #ifdef GEODE_IS_WINDOWS - command = fmt::format( - "\"{}\" -y -f rawvideo -pix_fmt rgb24 -s {}x{} -r {} -i - {}{}{} -vf \"vflip,{}{}\" -an \"{}\" ", - ffmpegPath, - std::to_string(width), - std::to_string(height), - std::to_string(fps), - codec, - bitrate, - extraArgs, - videoArgs, - fadeArgs, - path - ); - - log::info("Executing: {}", command); - - process = subprocess::Popen(command); - #endif - } - - while (recording || pause || recordingAudio || frameHasData) { - lock.lock(); - if (frameHasData) { - const std::vector frame = currentFrame; - frameHasData = false; - lock.unlock(); - if (usingApi) { - auto res = ffmpeg.writeFrame(frame); - if (res.isErr()) { - Loader::get()->queueInMainThread([] { - FLAlertLayer::create("Error", "FFmpeg API failed: ", "Ok")->show(); - }); - - audioMode = AudioMode::Off; - stop(); - break; - } - } - #ifdef GEODE_IS_WINDOWS - else - process.m_stdin.write(frame.data(), frame.size()); - #endif - } - else lock.unlock(); - } - - if (usingApi) { - ffmpeg.stop(); - } - else { - #ifdef GEODE_IS_WINDOWS - if (process.close()) { - Loader::get()->queueInMainThread([] { - FLAlertLayer::create("Error", "There was an error saving the render. Wrong render Args.", "Ok")->show(); - }); - return; - } - #endif - } - - Loader::get()->queueInMainThread([] { - Notification::create("Saving Render...", NotificationIcon::Loading)->show(); - }); - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - if ((SFXVolume == 0.f && musicVolume == 0.f) || audioMode == AudioMode::Off || (audioMode == AudioMode::Song && !std::filesystem::exists(songFile)) || (audioMode == AudioMode::Record && !std::filesystem::exists("fmodoutput.wav"))) { - if (audioMode != AudioMode::Off) { - Loader::get()->queueInMainThread([] { - FLAlertLayer::create("Error", "Song File not found.", "Ok")->show(); - }); - - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - - Loader::get()->queueInMainThread([] { - Notification::create("Render Saved Without Audio", NotificationIcon::Success)->show(); - if (!Mod::get()->getSavedValue("render_hide_endscreen")) return; - if (PlayLayer* pl = PlayLayer::get()) - if (EndLevelLayer* layer = pl->getChildByType(0)) - layer->setVisible(true); - }); - - return; - } - - std::filesystem::path tempPath = std::filesystem::path(path).parent_path() / ("temp_" + std::filesystem::path(path).filename().string()); - std::filesystem::path tempPathAudio = (Mod::get()->getSaveDir() / "temp_audio_file.wav"); - - if (usingApi) { - std::string file = audioMode == AudioMode::Song ? songFile : "fmodoutput.wav"; - auto res = ffmpeg::events::AudioMixer::mixVideoAudio(path, file, tempPath); - log::debug("XD"); - if (res.isErr()) { - Loader::get()->queueInMainThread([] { - FLAlertLayer::create("Error", "FFmpeg failed to add audio: ", "Ok")->show(); - }); - return; - } - } - else { - #ifdef GEODE_IS_WINDOWS - - double totalTime = lastFrame_t; - if (fadeOutTime > totalTime) fadeOutTime = totalTime / 2; - float fadeOutStart = totalTime - fadeOutTime; - - if (fadeOutVideo) { - command = fmt::format("\"{}\" -i \"{}\" -vf \"fade=t=out:st={}:d={}\" {}{}-c:a copy \"{}\"", ffmpegPath, path, fadeOutStart, std::to_string(fadeOutTime), codec, bitrate, path + "_temp" + extension); - - log::info("Executing (Fade Out): {}", command); - process = subprocess::Popen(command); - if (!process.close()) { - std::error_code ec; - std::filesystem::remove(path, ec); - if (ec) log::warn("Failed to remove old render file."); - else { - ec.clear(); - std::filesystem::rename(path + "_temp" + extension, path, ec); - if (ec) log::warn("Failed to rename temp render file."); - } - } else log::debug("Fade Out Error xD"); - } - - if (audioMode == AudioMode::Record) { - command = fmt::format("\"{}\" -i \"fmodoutput.wav\" -acodec pcm_s16le -ar 44100 -ac 2 \"{}\"", - ffmpegPath, tempPathAudio - ); - - process = subprocess::Popen(command); // Fix ffmpeg not reading it - if (process.close()) { - Loader::get()->queueInMainThread([] { - FLAlertLayer::create("Error", "There was an error adding the song. ID: 140", "Ok")->show(); - }); - return; - } - } - - { - - std::string fadeInString; - if ((fadeIn && audioMode == AudioMode::Song) || fadeInVideo) - fadeInString = fmt::format(", afade=t=in:d={}", fadeInVideo ? std::to_string(fadeInTime) : "2"); - - std::string fadeOutString; - if ((fadeOut && audioMode == AudioMode::Song) || fadeOutVideo) - fadeOutString = fmt::format( - ", afade=t=out:d={}:st={}", - fadeOutVideo ? std::to_string(fadeOutTime) : "2", - fadeOutVideo ? fadeOutStart : totalTime - timeAfter - 3.5f - ); - - std::filesystem::path file = audioMode == AudioMode::Song ? songFile : tempPathAudio; - float offset = audioMode == AudioMode::Song ? songOffset : (isPlatformer ? 0.28f : 0.f); - - if (!extraAudioArgs.empty()) extraAudioArgs += " "; - - std::string volume = audioMode == AudioMode::Song ? fmt::format(",volume={:.2f}", musicVolume) : ""; - - command = fmt::format( - "\"{}\" -y -ss {} -i \"{}\" -i \"{}\" -t {} -c:v copy {} -filter:a \"[1:a]adelay=0|0{}{}{}\" \"{}\"", - ffmpegPath, - offset, - file, - path, - totalTime, - extraAudioArgs, - fadeInString, - fadeOutString, - volume, - tempPath - ); - - log::info("Executing (Audio): {}", command); - - auto process = subprocess::Popen(command); - if (process.close()) { - Loader::get()->queueInMainThread([] { - FLAlertLayer::create("Error", "There was an error adding the song. Wrong Audio Args.", "Ok")->show(); - }); - return; - } - } - - #endif - } - - std::error_code ec; - std::filesystem::remove(Utils::widen(path), ec); - if (ec) log::warn("Failed to remove old render file."); - else { - ec.clear(); - std::filesystem::rename(tempPath, Utils::widen(path), ec); - if (ec) log::warn("Failed to rename temp render file."); - } - - ec.clear(); - std::filesystem::remove(tempPathAudio, ec); - if (ec) log::warn("Failed to remove temp audio file."); - - ec.clear(); - std::filesystem::remove("fmodoutput.wav", ec); - if (ec) log::warn("Failed to remove fmod audio file."); - - Loader::get()->queueInMainThread([] { - Notification::create("Render Saved With Audio", NotificationIcon::Success)->show(); - }); +// } else { +// #ifdef GEODE_IS_WINDOWS +// command = fmt::format( +// "\"{}\" -y -f rawvideo -pix_fmt rgb24 -s {}x{} -r {} -i - {}{}{} -vf \"vflip,{}{}\" -an \"{}\" ", +// ffmpegPath, +// std::to_string(width), +// std::to_string(height), +// std::to_string(fps), +// codec, +// bitrate, +// extraArgs, +// videoArgs, +// fadeArgs, +// path +// ); + +// log::info("Executing: {}", command); + +// process = subprocess::Popen(command); +// #endif +// } + +// while (recording || pause || recordingAudio || frameHasData) { +// lock.lock(); +// if (frameHasData) { +// const std::vector frame = currentFrame; +// frameHasData = false; +// lock.unlock(); +// if (usingApi) { +// auto res = ffmpeg.writeFrame(frame); +// if (res.isErr()) { +// Loader::get()->queueInMainThread([] { +// FLAlertLayer::create("Error", "FFmpeg API failed: ", "Ok")->show(); +// }); + +// audioMode = AudioMode::Off; +// stop(); +// break; +// } +// } +// #ifdef GEODE_IS_WINDOWS +// else +// process.m_stdin.write(frame.data(), frame.size()); +// #endif +// } +// else lock.unlock(); +// } + +// if (usingApi) { +// ffmpeg.stop(); +// } +// else { +// #ifdef GEODE_IS_WINDOWS +// if (process.close()) { +// Loader::get()->queueInMainThread([] { +// FLAlertLayer::create("Error", "There was an error saving the render. Wrong render Args.", "Ok")->show(); +// }); +// return; +// } +// #endif +// } + +// Loader::get()->queueInMainThread([] { +// Notification::create("Saving Render...", NotificationIcon::Loading)->show(); +// }); +// std::this_thread::sleep_for(std::chrono::milliseconds(100)); + +// if ((SFXVolume == 0.f && musicVolume == 0.f) || audioMode == AudioMode::Off || (audioMode == AudioMode::Song && !std::filesystem::exists(songFile)) || (audioMode == AudioMode::Record && !std::filesystem::exists("fmodoutput.wav"))) { +// if (audioMode != AudioMode::Off) { +// Loader::get()->queueInMainThread([] { +// FLAlertLayer::create("Error", "Song File not found.", "Ok")->show(); +// }); + +// std::this_thread::sleep_for(std::chrono::milliseconds(100)); +// } + +// Loader::get()->queueInMainThread([] { +// Notification::create("Render Saved Without Audio", NotificationIcon::Success)->show(); +// if (!Mod::get()->getSavedValue("render_hide_endscreen")) return; +// if (PlayLayer* pl = PlayLayer::get()) +// if (EndLevelLayer* layer = pl->getChildByType(0)) +// layer->setVisible(true); +// }); + +// return; +// } + +// std::filesystem::path tempPath = std::filesystem::path(path).parent_path() / ("temp_" + std::filesystem::path(path).filename().string()); +// std::filesystem::path tempPathAudio = (Mod::get()->getSaveDir() / "temp_audio_file.wav"); + +// if (usingApi) { +// std::string file = audioMode == AudioMode::Song ? songFile : "fmodoutput.wav"; +// auto res = ffmpeg::events::AudioMixer::mixVideoAudio(path, file, tempPath); +// log::debug("XD"); +// if (res.isErr()) { +// Loader::get()->queueInMainThread([] { +// FLAlertLayer::create("Error", "FFmpeg failed to add audio: ", "Ok")->show(); +// }); +// return; +// } +// } +// else { +// #ifdef GEODE_IS_WINDOWS + +// double totalTime = lastFrame_t; +// if (fadeOutTime > totalTime) fadeOutTime = totalTime / 2; +// float fadeOutStart = totalTime - fadeOutTime; + +// if (fadeOutVideo) { +// command = fmt::format("\"{}\" -i \"{}\" -vf \"fade=t=out:st={}:d={}\" {}{}-c:a copy \"{}\"", ffmpegPath, path, fadeOutStart, std::to_string(fadeOutTime), codec, bitrate, path + "_temp" + extension); + +// log::info("Executing (Fade Out): {}", command); +// process = subprocess::Popen(command); +// if (!process.close()) { +// std::error_code ec; +// std::filesystem::remove(path, ec); +// if (ec) log::warn("Failed to remove old render file."); +// else { +// ec.clear(); +// std::filesystem::rename(path + "_temp" + extension, path, ec); +// if (ec) log::warn("Failed to rename temp render file."); +// } +// } else log::debug("Fade Out Error xD"); +// } + +// if (audioMode == AudioMode::Record) { +// command = fmt::format("\"{}\" -i \"fmodoutput.wav\" -acodec pcm_s16le -ar 44100 -ac 2 \"{}\"", +// ffmpegPath, tempPathAudio +// ); + +// process = subprocess::Popen(command); // Fix ffmpeg not reading it +// if (process.close()) { +// Loader::get()->queueInMainThread([] { +// FLAlertLayer::create("Error", "There was an error adding the song. ID: 140", "Ok")->show(); +// }); +// return; +// } +// } + +// { + +// std::string fadeInString; +// if ((fadeIn && audioMode == AudioMode::Song) || fadeInVideo) +// fadeInString = fmt::format(", afade=t=in:d={}", fadeInVideo ? std::to_string(fadeInTime) : "2"); + +// std::string fadeOutString; +// if ((fadeOut && audioMode == AudioMode::Song) || fadeOutVideo) +// fadeOutString = fmt::format( +// ", afade=t=out:d={}:st={}", +// fadeOutVideo ? std::to_string(fadeOutTime) : "2", +// fadeOutVideo ? fadeOutStart : totalTime - timeAfter - 3.5f +// ); + +// std::filesystem::path file = audioMode == AudioMode::Song ? songFile : tempPathAudio; +// float offset = audioMode == AudioMode::Song ? songOffset : (isPlatformer ? 0.28f : 0.f); + +// if (!extraAudioArgs.empty()) extraAudioArgs += " "; + +// std::string volume = audioMode == AudioMode::Song ? fmt::format(",volume={:.2f}", musicVolume) : ""; + +// command = fmt::format( +// "\"{}\" -y -ss {} -i \"{}\" -i \"{}\" -t {} -c:v copy {} -filter:a \"[1:a]adelay=0|0{}{}{}\" \"{}\"", +// ffmpegPath, +// offset, +// file, +// path, +// totalTime, +// extraAudioArgs, +// fadeInString, +// fadeOutString, +// volume, +// tempPath +// ); + +// log::info("Executing (Audio): {}", command); + +// auto process = subprocess::Popen(command); +// if (process.close()) { +// Loader::get()->queueInMainThread([] { +// FLAlertLayer::create("Error", "There was an error adding the song. Wrong Audio Args.", "Ok")->show(); +// }); +// return; +// } +// } + +// #endif +// } + +// std::error_code ec; +// std::filesystem::remove(Utils::widen(path), ec); +// if (ec) log::warn("Failed to remove old render file."); +// else { +// ec.clear(); +// std::filesystem::rename(tempPath, Utils::widen(path), ec); +// if (ec) log::warn("Failed to rename temp render file."); +// } + +// ec.clear(); +// std::filesystem::remove(tempPathAudio, ec); +// if (ec) log::warn("Failed to remove temp audio file."); + +// ec.clear(); +// std::filesystem::remove("fmodoutput.wav", ec); +// if (ec) log::warn("Failed to remove fmod audio file."); + +// Loader::get()->queueInMainThread([] { +// Notification::create("Render Saved With Audio", NotificationIcon::Success)->show(); +// }); - }).detach(); -} +// }).detach(); +// } -void Renderer::stop(int frame) { - renderedFrames.clear(); - finishFrame = Global::getCurrentFrame(); - pause = true; - recording = false; - timeAfter = 0.f; +// void Renderer::stop(int frame) { +// renderedFrames.clear(); +// finishFrame = Global::getCurrentFrame(); +// pause = true; +// recording = false; +// timeAfter = 0.f; - if (usingApi) audioMode = AudioMode::Off; +// if (usingApi) audioMode = AudioMode::Off; - if (PlayLayer* pl = PlayLayer::get()) { +// if (PlayLayer* pl = PlayLayer::get()) { - if (pl->m_isPaused && audioMode == AudioMode::Record) { - if (PauseLayer* layer = Global::getPauseLayer()) { - CCScene* scene = CCDirector::sharedDirector()->getRunningScene(); - if (RecordLayer* xdbot = scene->getChildByType(0)) - xdbot->onClose(nullptr); +// if (pl->m_isPaused && audioMode == AudioMode::Record) { +// if (PauseLayer* layer = Global::getPauseLayer()) { +// CCScene* scene = CCDirector::sharedDirector()->getRunningScene(); +// if (RecordLayer* xdbot = scene->getChildByType(0)) +// xdbot->onClose(nullptr); - layer->onResume(nullptr); - } - } - else if (pl->m_levelEndAnimationStarted) { - finishFrame = 0; - levelFinished = true; - } - - } else - audioMode = AudioMode::Off; - - if (audioMode == AudioMode::Record) { - recordingAudio = true; - dontRecordAudio = true; - Notification::create("Recording Audio...", NotificationIcon::Loading)->show(); - } - - pause = false; - changeRes(true); -} - -void Renderer::changeRes(bool og) { - cocos2d::CCEGLView* view = cocos2d::CCEGLView::get(); - cocos2d::CCSize res = {0, 0}; - float scaleX = 1.f; - float scaleY = 1.f; - - res = og ? ogRes : CCSize(320.f * (width / static_cast(height)), 320.f); - scaleX = og ? ogScaleX : (width / res.width); - scaleY = og ? ogScaleY : (height / res.height); - - if (res == CCSize(0, 0) && !og) return changeRes(true); +// layer->onResume(nullptr); +// } +// } +// else if (pl->m_levelEndAnimationStarted) { +// finishFrame = 0; +// levelFinished = true; +// } + +// } else +// audioMode = AudioMode::Off; + +// if (audioMode == AudioMode::Record) { +// recordingAudio = true; +// dontRecordAudio = true; +// Notification::create("Recording Audio...", NotificationIcon::Loading)->show(); +// } + +// pause = false; +// changeRes(true); +// } + +// void Renderer::changeRes(bool og) { +// cocos2d::CCEGLView* view = cocos2d::CCEGLView::get(); +// cocos2d::CCSize res = {0, 0}; +// float scaleX = 1.f; +// float scaleY = 1.f; + +// res = og ? ogRes : CCSize(320.f * (width / static_cast(height)), 320.f); +// scaleX = og ? ogScaleX : (width / res.width); +// scaleY = og ? ogScaleY : (height / res.height); + +// if (res == CCSize(0, 0) && !og) return changeRes(true); - CCDirector::sharedDirector()->m_obWinSizeInPoints = res; - view->setDesignResolutionSize(res.width, res.height, ResolutionPolicy::kResolutionExactFit); - view->m_fScaleX = scaleX; - view->m_fScaleY = scaleY; -} - -void MyRenderTexture::begin() { - if (Global::get().renderer.usingApi) { - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo); - - texture = new CCTexture2D(); - { - std::unique_ptr data(static_cast(malloc(width * height * 3)), free); - memset(data.get(), 0, width * height * 3); - texture->initWithData(data.get(), kCCTexture2DPixelFormat_RGB888, width, height, CCSize(static_cast(width), static_cast(height))); - } - - glGetIntegerv(GL_RENDERBUFFER_BINDING, &old_rbo); - - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture->getName(), 0); - - texture->setAliasTexParameters(); - - texture->autorelease(); - - glBindRenderbuffer(GL_RENDERBUFFER, old_rbo); - glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); -#ifdef GEODE_IS_WINDOWS - } else { - glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); - - texture = new CCTexture2D(); - { - auto data = malloc(width * height * 3); - memset(data, 0, width * height * 3); - texture->initWithData(data, kCCTexture2DPixelFormat_RGB888, width, height, CCSize(static_cast(width), static_cast(height))); - free(data); - } - - glGetIntegerv(GL_RENDERBUFFER_BINDING_EXT, &old_rbo); - - glGenFramebuffersEXT(1, &fbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture->getName(), 0); - - texture->setAliasTexParameters(); - - texture->autorelease(); - - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, old_rbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo); - } -#else - } -#endif -} - -void MyRenderTexture::capture(std::mutex& lock, std::vector& data, volatile bool& hasData) { - CCDirector* director = CCDirector::sharedDirector(); - PlayLayer* pl = PlayLayer::get(); - - if (Global::get().renderer.usingApi) { - glViewport(0, 0, width, height); - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - pl->visit(); - - glPixelStorei(GL_PACK_ALIGNMENT, 1); - lock.lock(); - hasData = true; - glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data.data()); - lock.unlock(); - - glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); - director->setViewport(); -#ifdef GEODE_IS_WINDOWS - } else { - glViewport(-1, 1.0, width, height); - glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); - - pl->visit(); - - glPixelStorei(GL_PACK_ALIGNMENT, 1); - lock.lock(); - hasData = true; - glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data.data()); - lock.unlock(); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo); - director->setViewport(); - } -#else - } -#endif -} - -void Renderer::captureFrame() { - while (frameHasData) {} - renderer.capture(lock, currentFrame, frameHasData); -} -int wa = 0; -void Renderer::handleRecording(PlayLayer* pl, int frame) { - if (!pl) stop(frame); - isPlatformer = pl->m_levelSettings->m_platformerMode; - if (dontRender || pl->m_player1->m_isDead) return; - - auto& g = Global::get(); - if (renderedFrames.contains(frame) && frame > 10) - return; - - renderedFrames.insert(frame); - - if (!pl->m_hasCompletedLevel || timeAfter < stopAfter) { - - float dt = 1.f / static_cast(fps); - if (pl->m_hasCompletedLevel) { - timeAfter += dt; - levelFinished = true; - } - - float time = pl->m_gameState.m_levelTime + extra_t - lastFrame_t; - if (time >= dt) { - extra_t = time - dt; - lastFrame_t = pl->m_gameState.m_levelTime; - - int correctMusicTime = static_cast((frame / static_cast(Global::getTPS()) + pl->m_levelSettings->m_songOffset) * 1000); - correctMusicTime += fmod->m_musicOffset; - - if (fmod->getMusicTimeMS(0) - correctMusicTime >= 110) - fmod->setMusicTimeMS(correctMusicTime, true, 0); - - captureFrame(); - } - } - else stop(frame); -} - -bool Renderer::tryPause() { - if (!recordingAudio) return true; - - pauseAttempts++; - - if (pauseAttempts > 5) { - pauseAttempts = 0; - stopAudio(); - return true; - } - - return false; -} - -void Renderer::startAudio(PlayLayer* pl) { - EndLevelLayer* endLevelLayer = pl->getChildByType(0); - if (dontRecordAudio) return; - - if (pl->m_levelEndAnimationStarted && endLevelLayer != nullptr) { - CCKeyboardDispatcher::get()->dispatchKeyboardMSG(enumKeyCodes::KEY_Space, true, false); - CCKeyboardDispatcher::get()->dispatchKeyboardMSG(enumKeyCodes::KEY_Space, false, false); - } - else if (!pl->m_levelEndAnimationStarted) { - - if (!pl->m_isPaused) - pl->pauseGame(false); - - if (Global::get().state != state::playing) - Macro::togglePlaying(); - - Global::get().restart = true; - - if (PauseLayer* layer = Global::getPauseLayer()) - layer->onResume(nullptr); - - auto fmod = FMODAudioEngine::sharedEngine(); - fmod->m_globalChannel->getVolume(&ogSFXVol); - fmod->m_backgroundMusicChannel->getVolume(&ogMusicVol); - - FMODAudioEngine::sharedEngine()->m_system->setOutput(FMOD_OUTPUTTYPE_WAVWRITER); - startedAudio = true; - pauseAttempts = 0; - if (CCNode* lbl = pl->getChildByID("recording-audio-label"_spr)) - lbl->setVisible(true); - } -} - -void Renderer::stopAudio() { - FMODAudioEngine::sharedEngine()->m_system->setOutput(FMOD_OUTPUTTYPE_AUTODETECT); - auto fmod = FMODAudioEngine::sharedEngine(); - fmod->m_globalChannel->setVolume(ogSFXVol); - fmod->m_backgroundMusicChannel->setVolume(ogMusicVol); - - recordingAudio = false; - if (PlayLayer* pl = PlayLayer::get()) - if (CCNode* lbl = pl->getChildByID("recording-audio-label"_spr)) - lbl->setVisible(false); -} - -void Renderer::handleAudioRecording(PlayLayer* pl, int frame) { - auto& g = Global::get(); +// CCDirector::sharedDirector()->m_obWinSizeInPoints = res; +// view->setDesignResolutionSize(res.width, res.height, ResolutionPolicy::kResolutionExactFit); +// view->m_fScaleX = scaleX; +// view->m_fScaleY = scaleY; +// } + +// void MyRenderTexture::begin() { +// if (Global::get().renderer.usingApi) { +// glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo); + +// texture = new CCTexture2D(); +// { +// std::unique_ptr data(static_cast(malloc(width * height * 3)), free); +// memset(data.get(), 0, width * height * 3); +// texture->initWithData(data.get(), kCCTexture2DPixelFormat_RGB888, width, height, CCSize(static_cast(width), static_cast(height))); +// } + +// glGetIntegerv(GL_RENDERBUFFER_BINDING, &old_rbo); + +// glGenFramebuffers(1, &fbo); +// glBindFramebuffer(GL_FRAMEBUFFER, fbo); + +// glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture->getName(), 0); + +// texture->setAliasTexParameters(); + +// texture->autorelease(); + +// glBindRenderbuffer(GL_RENDERBUFFER, old_rbo); +// glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); +// #ifdef GEODE_IS_WINDOWS +// } else { +// glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); + +// texture = new CCTexture2D(); +// { +// auto data = malloc(width * height * 3); +// memset(data, 0, width * height * 3); +// texture->initWithData(data, kCCTexture2DPixelFormat_RGB888, width, height, CCSize(static_cast(width), static_cast(height))); +// free(data); +// } + +// glGetIntegerv(GL_RENDERBUFFER_BINDING_EXT, &old_rbo); + +// glGenFramebuffersEXT(1, &fbo); +// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); + +// glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture->getName(), 0); + +// texture->setAliasTexParameters(); + +// texture->autorelease(); + +// glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, old_rbo); +// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo); +// } +// #else +// } +// #endif +// } + +// void MyRenderTexture::capture(std::mutex& lock, std::vector& data, volatile bool& hasData) { +// CCDirector* director = CCDirector::sharedDirector(); +// PlayLayer* pl = PlayLayer::get(); + +// if (Global::get().renderer.usingApi) { +// glViewport(0, 0, width, height); +// glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo); +// glBindFramebuffer(GL_FRAMEBUFFER, fbo); + +// pl->visit(); + +// glPixelStorei(GL_PACK_ALIGNMENT, 1); +// lock.lock(); +// hasData = true; +// glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data.data()); +// lock.unlock(); + +// glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); +// director->setViewport(); +// #ifdef GEODE_IS_WINDOWS +// } else { +// glViewport(-1, 1.0, width, height); +// glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); +// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); + +// pl->visit(); + +// glPixelStorei(GL_PACK_ALIGNMENT, 1); +// lock.lock(); +// hasData = true; +// glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data.data()); +// lock.unlock(); + +// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo); +// director->setViewport(); +// } +// #else +// } +// #endif +// } + +// void Renderer::captureFrame() { +// while (frameHasData) {} +// renderer.capture(lock, currentFrame, frameHasData); +// } +// int wa = 0; +// void Renderer::handleRecording(PlayLayer* pl, int frame) { +// if (!pl) stop(frame); +// isPlatformer = pl->m_levelSettings->m_platformerMode; +// if (dontRender || pl->m_player1->m_isDead) return; + +// auto& g = Global::get(); +// if (renderedFrames.contains(frame) && frame > 10) +// return; + +// renderedFrames.insert(frame); + +// if (!pl->m_hasCompletedLevel || timeAfter < stopAfter) { + +// float dt = 1.f / static_cast(fps); +// if (pl->m_hasCompletedLevel) { +// timeAfter += dt; +// levelFinished = true; +// } + +// float time = pl->m_gameState.m_levelTime + extra_t - lastFrame_t; +// if (time >= dt) { +// extra_t = time - dt; +// lastFrame_t = pl->m_gameState.m_levelTime; + +// int correctMusicTime = static_cast((frame / static_cast(Global::getTPS()) + pl->m_levelSettings->m_songOffset) * 1000); +// correctMusicTime += fmod->m_musicOffset; + +// if (fmod->getMusicTimeMS(0) - correctMusicTime >= 110) +// fmod->setMusicTimeMS(correctMusicTime, true, 0); + +// captureFrame(); +// } +// } +// else stop(frame); +// } + +// bool Renderer::tryPause() { +// if (!recordingAudio) return true; + +// pauseAttempts++; + +// if (pauseAttempts > 5) { +// pauseAttempts = 0; +// stopAudio(); +// return true; +// } + +// return false; +// } + +// void Renderer::startAudio(PlayLayer* pl) { +// EndLevelLayer* endLevelLayer = pl->getChildByType(0); +// if (dontRecordAudio) return; + +// if (pl->m_levelEndAnimationStarted && endLevelLayer != nullptr) { +// CCKeyboardDispatcher::get()->dispatchKeyboardMSG(enumKeyCodes::KEY_Space, true, false); +// CCKeyboardDispatcher::get()->dispatchKeyboardMSG(enumKeyCodes::KEY_Space, false, false); +// } +// else if (!pl->m_levelEndAnimationStarted) { + +// if (!pl->m_isPaused) +// pl->pauseGame(false); + +// if (Global::get().state != state::playing) +// Macro::togglePlaying(); + +// Global::get().restart = true; + +// if (PauseLayer* layer = Global::getPauseLayer()) +// layer->onResume(nullptr); + +// auto fmod = FMODAudioEngine::sharedEngine(); +// fmod->m_globalChannel->getVolume(&ogSFXVol); +// fmod->m_backgroundMusicChannel->getVolume(&ogMusicVol); + +// FMODAudioEngine::sharedEngine()->m_system->setOutput(FMOD_OUTPUTTYPE_WAVWRITER); +// startedAudio = true; +// pauseAttempts = 0; +// if (CCNode* lbl = pl->getChildByID("recording-audio-label"_spr)) +// lbl->setVisible(true); +// } +// } + +// void Renderer::stopAudio() { +// FMODAudioEngine::sharedEngine()->m_system->setOutput(FMOD_OUTPUTTYPE_AUTODETECT); +// auto fmod = FMODAudioEngine::sharedEngine(); +// fmod->m_globalChannel->setVolume(ogSFXVol); +// fmod->m_backgroundMusicChannel->setVolume(ogMusicVol); + +// recordingAudio = false; +// if (PlayLayer* pl = PlayLayer::get()) +// if (CCNode* lbl = pl->getChildByID("recording-audio-label"_spr)) +// lbl->setVisible(false); +// } + +// void Renderer::handleAudioRecording(PlayLayer* pl, int frame) { +// auto& g = Global::get(); - fmod->m_globalChannel->setVolume(SFXVolume); - fmod->m_backgroundMusicChannel->setVolume(musicVolume); - - if (!pl) { - g.renderer.stopAudio(); - return; - } - - if (finishFrame != 0 && frame >= finishFrame) { - g.renderer.stopAudio(); - return; - } - - if (!pl->m_hasCompletedLevel || timeAfter < stopAfter) { - float dt = 1.f / static_cast(fps); - if (pl->m_hasCompletedLevel) - timeAfter += dt; - } - else - g.renderer.stopAudio(); -} -#endif \ No newline at end of file +// fmod->m_globalChannel->setVolume(SFXVolume); +// fmod->m_backgroundMusicChannel->setVolume(musicVolume); + +// if (!pl) { +// g.renderer.stopAudio(); +// return; +// } + +// if (finishFrame != 0 && frame >= finishFrame) { +// g.renderer.stopAudio(); +// return; +// } + +// if (!pl->m_hasCompletedLevel || timeAfter < stopAfter) { +// float dt = 1.f / static_cast(fps); +// if (pl->m_hasCompletedLevel) +// timeAfter += dt; +// } +// else +// g.renderer.stopAudio(); +// } +// #endif \ No newline at end of file diff --git a/src/renderer/renderer.hpp b/src/renderer/renderer.hpp index 74023ea3..b6c2b5bf 100644 --- a/src/renderer/renderer.hpp +++ b/src/renderer/renderer.hpp @@ -1,81 +1,81 @@ -#include "../includes.hpp" -#include "ffmpeg/events.hpp" +// #include "../includes.hpp" +// #include "ffmpeg/events.hpp" -#ifndef GEODE_IS_IOS -enum AudioMode { - Off = 0, - Song = 1, - Record = 2 -}; +// #ifndef GEODE_IS_IOS +// enum AudioMode { +// Off = 0, +// Song = 1, +// Record = 2 +// }; -class MyRenderTexture { -public: - unsigned width, height; - int old_fbo, old_rbo; - unsigned fbo; - geode::prelude::CCTexture2D* texture = nullptr; - void begin(); - void capture(std::mutex& lock, std::vector& data, volatile bool& lul); -}; +// class MyRenderTexture { +// public: +// unsigned width, height; +// int old_fbo, old_rbo; +// unsigned fbo; +// geode::prelude::CCTexture2D* texture = nullptr; +// void begin(); +// void capture(std::mutex& lock, std::vector& data, volatile bool& lul); +// }; -class Renderer { -public: +// class Renderer { +// public: - Renderer() : width(1920), height(1080), fps(60) {} +// Renderer() : width(1920), height(1080), fps(60) {} - volatile bool frameHasData; - bool levelFinished = false; - bool recording = false; - bool pause = false; - int audioMode = 0; - float ogMusicVol; - float ogSFXVol; - float SFXVolume = 1.f; - float musicVolume = 1.f; +// volatile bool frameHasData; +// bool levelFinished = false; +// bool recording = false; +// bool pause = false; +// int audioMode = 0; +// float ogMusicVol; +// float ogSFXVol; +// float SFXVolume = 1.f; +// float musicVolume = 1.f; - bool usingApi = false; - bool dontRender = false; - bool dontRecordAudio = false; - bool recordingAudio = false; - bool startedAudio = false; - bool isPlatformer = false; - int finishFrame = 0; - int levelStartFrame = 0; +// bool usingApi = false; +// bool dontRender = false; +// bool dontRecordAudio = false; +// bool recordingAudio = false; +// bool startedAudio = false; +// bool isPlatformer = false; +// int finishFrame = 0; +// int levelStartFrame = 0; - float stopAfter = 3.f; - float timeAfter = 0.f; - unsigned width, height; - unsigned fps; - double lastFrame_t, extra_t; - int pauseAttempts = 0; +// float stopAfter = 3.f; +// float timeAfter = 0.f; +// unsigned width, height; +// unsigned fps; +// double lastFrame_t, extra_t; +// int pauseAttempts = 0; - MyRenderTexture renderer; - ffmpeg::events::Recorder ffmpeg; - std::vector currentFrame; - std::mutex lock; - std::string codec = "", bitrate = "12M", extraArgs = "", videoArgs = "", extraAudioArgs = "", path = ""; - std::string ffmpegPath = (geode::dirs::getGameDir() / "ffmpeg.exe").string(); - std::unordered_set renderedFrames; +// MyRenderTexture renderer; +// ffmpeg::events::Recorder ffmpeg; +// std::vector currentFrame; +// std::mutex lock; +// std::string codec = "", bitrate = "12M", extraArgs = "", videoArgs = "", extraAudioArgs = "", path = ""; +// std::string ffmpegPath = (geode::dirs::getGameDir() / "ffmpeg.exe").string(); +// std::unordered_set renderedFrames; - FMODAudioEngine* fmod = nullptr; - cocos2d::CCSize ogRes = {0, 0}; - float ogScaleX = 1.f; - float ogScaleY = 1.f; +// FMODAudioEngine* fmod = nullptr; +// cocos2d::CCSize ogRes = {0, 0}; +// float ogScaleX = 1.f; +// float ogScaleY = 1.f; - void captureFrame(); - void changeRes(bool og); +// void captureFrame(); +// void changeRes(bool og); - void start(); - void startAudio(PlayLayer* pl); +// void start(); +// void startAudio(PlayLayer* pl); - void stop(int frame = 0); - void stopAudio(); +// void stop(int frame = 0); +// void stopAudio(); - void handleRecording(PlayLayer* pl, int frame); - void handleAudioRecording(PlayLayer* pl, int frame); +// void handleRecording(PlayLayer* pl, int frame); +// void handleAudioRecording(PlayLayer* pl, int frame); - static bool toggle(); - static bool shouldUseAPI(); - bool tryPause(); -}; -#endif \ No newline at end of file +// static bool toggle(); +// static bool shouldUseAPI(); +// bool tryPause(); +// }; +// #endif \ No newline at end of file diff --git a/src/ui/autoclicker_settings_layer.hpp b/src/ui/autoclicker_settings_layer.hpp index 5fc84dd6..f11493b0 100644 --- a/src/ui/autoclicker_settings_layer.hpp +++ b/src/ui/autoclicker_settings_layer.hpp @@ -1,6 +1,6 @@ #include "../includes.hpp" -class AutoclickerLayer : public geode::Popup<>, public TextInputDelegate { +class AutoclickerLayer : public geode::Popup, public TextInputDelegate { private: @@ -23,7 +23,7 @@ class AutoclickerLayer : public geode::Popup<>, public TextInputDelegate { CCMenuItemToggler* toggleP1 = nullptr; CCMenuItemToggler* toggleP2 = nullptr; - STATIC_CREATE(AutoclickerLayer, 250, 240) + STATIC_CREATE(AutoclickerLayer) void textChanged(CCTextInputNode*) override { auto& g = Global::get(); @@ -45,7 +45,8 @@ class AutoclickerLayer : public geode::Popup<>, public TextInputDelegate { releaseLbl2->setString(fmt::format("{:.3f}s", dt * g.releaseFor2).c_str()); } - bool setup() override { + bool init() override { + if (!Popup::init(250, 240)) return false; setTitle("Autoclicker"); m_title->setScale(0.625f); m_title->setPositionY(224); diff --git a/src/ui/autosave_settings_layer.hpp b/src/ui/autosave_settings_layer.hpp index b9f7c3dc..aa6dc936 100644 --- a/src/ui/autosave_settings_layer.hpp +++ b/src/ui/autosave_settings_layer.hpp @@ -1,6 +1,6 @@ #include "../includes.hpp" -class AutoSaveLayer : public geode::Popup<>, public TextInputDelegate { +class AutoSaveLayer : public geode::Popup, public TextInputDelegate { private: @@ -11,7 +11,7 @@ class AutoSaveLayer : public geode::Popup<>, public TextInputDelegate { CCLabelBMFont* intervalLbl = nullptr; CCLabelBMFont* intervalLbl2 = nullptr; - STATIC_CREATE(AutoSaveLayer, 250, 190) + STATIC_CREATE(AutoSaveLayer) void textChanged(CCTextInputNode*) override { std::string str = intervalInput->getString(); @@ -21,7 +21,8 @@ class AutoSaveLayer : public geode::Popup<>, public TextInputDelegate { Mod::get()->setSavedValue("autosave_interval", str); } - bool setup() override { + bool init() override { + if (!Popup::init(250, 190)) return false; setTitle("AutoSave"); m_title->setScale(0.575f); m_title->setPositionY(171); diff --git a/src/ui/button_edit_layer.cpp b/src/ui/button_edit_layer.cpp index 990dd836..ae39a275 100644 --- a/src/ui/button_edit_layer.cpp +++ b/src/ui/button_edit_layer.cpp @@ -168,7 +168,8 @@ void ButtonEditLayer::updateOpacity(CCObject*) { updateSelectedLabels(); } -bool ButtonEditLayer::setup() { +bool ButtonEditLayer::init() { + if (!Popup::init(200, 131)) return false; mod = Mod::get(); cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; diff --git a/src/ui/button_edit_layer.hpp b/src/ui/button_edit_layer.hpp index 51fff266..384254d9 100644 --- a/src/ui/button_edit_layer.hpp +++ b/src/ui/button_edit_layer.hpp @@ -20,15 +20,15 @@ struct MovingButton { cocos2d::CCPoint offset = ccp(0, 0); }; -class ButtonEditLayer : public geode::Popup<> { +class ButtonEditLayer : public geode::Popup { private: - bool setup() override; + bool init() override; public: - STATIC_CREATE(ButtonEditLayer, 200, 131) + STATIC_CREATE(ButtonEditLayer) Mod* mod = nullptr; CCMenu* menu = nullptr; diff --git a/src/ui/button_setting.cpp b/src/ui/button_setting.cpp index 9a752f5b..ee9be7bc 100644 --- a/src/ui/button_setting.cpp +++ b/src/ui/button_setting.cpp @@ -75,7 +75,7 @@ class MyButtonSettingNodeV3 : public SettingNodeV3 { ret->autorelease(); return ret; } - CC_SAFE_DELETE(ret); + delete ret; return nullptr; } bool hasUncommittedChanges() const override { diff --git a/src/ui/clickbot_layer.cpp b/src/ui/clickbot_layer.cpp index bcd9096c..da7b940b 100644 --- a/src/ui/clickbot_layer.cpp +++ b/src/ui/clickbot_layer.cpp @@ -19,7 +19,8 @@ void ClickbotLayer::updateLabels() { } -bool ClickbotLayer::setup() { +bool ClickbotLayer::init() { + if (!Popup::init(432, 250)) return false; setTitle("ClickBot"); m_title->setPositionY(m_title->getPositionY() + 5); @@ -285,9 +286,9 @@ bool ClickbotLayer::setup() { return true; } -ClickSettingsLayer* ClickSettingsLayer::create(std::string button, geode::Popup<>* layer) { +ClickSettingsLayer* ClickSettingsLayer::create(std::string button, geode::Popup* layer) { ClickSettingsLayer* ret = new ClickSettingsLayer(); - if (ret->initAnchored(250, 173, button, layer, Utils::getTexture().c_str())) { + if (ret->init(button, layer)) { ret->autorelease(); return ret; } @@ -296,7 +297,8 @@ ClickSettingsLayer* ClickSettingsLayer::create(std::string button, geode::Popup< return nullptr; } -bool ClickSettingsLayer::setup(std::string button, geode::Popup<>* layer) { +bool ClickSettingsLayer::init(std::string button, geode::Popup* layer) { + if (!Popup::init(250, 173, Utils::getTexture().c_str())) return false; cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; m_mainLayer->setPosition(m_mainLayer->getPosition() - offset); m_closeBtn->setPosition(m_closeBtn->getPosition() + offset); @@ -402,18 +404,19 @@ void ClickSettingsLayer::onSelectFile(CCObject*) { textFilter.files = { "*.mp3", "*.ogg" }; fileOptions.filters.push_back(textFilter); - file::pick(file::PickMode::OpenFile, { Mod::get()->getResourcesDir(), { textFilter } }).listen([this](Result* res) { - if (res->isOk()) { - std::filesystem::path path = res->unwrapOrDefault(); - - filenameLabel->setString(path.filename().string().c_str()); - - settings.path = path; - saveSettings(); - - static_cast(clickbotLayer)->updateLabels(); + m_pickFuture = [](ClickSettingsLayer* self, file::FilePickOptions options) -> arc::Future { + auto res = co_await file::pick(file::PickMode::OpenFile, options); + if (res.isOk()) { + auto pathOpt = res.unwrapOrDefault(); + if (pathOpt) { + std::filesystem::path path = pathOpt.value(); + self->filenameLabel->setString(path.filename().string().c_str()); + self->settings.path = path; + self->saveSettings(); + static_cast(self->clickbotLayer)->updateLabels(); + } } - }); + }(this, { Mod::get()->getResourcesDir(), { textFilter } }); } void ClickSettingsLayer::onRestore(CCObject*) { diff --git a/src/ui/clickbot_layer.hpp b/src/ui/clickbot_layer.hpp index 198f2041..5cd91369 100644 --- a/src/ui/clickbot_layer.hpp +++ b/src/ui/clickbot_layer.hpp @@ -3,10 +3,11 @@ #include "../includes.hpp" #include "../hacks/clickbot.hpp" #include "record_layer.hpp" +#include const std::unordered_map buttons = { {1, ""} }; -class ClickSettingsLayer : public geode::Popup*> { +class ClickSettingsLayer : public geode::Popup { private: @@ -21,14 +22,15 @@ class ClickSettingsLayer : public geode::Popup*> { CCLabelBMFont* pitchLabel = nullptr; CCMenuItemToggler* disableToggle = nullptr; + std::optional> m_pickFuture; - bool setup(std::string button, geode::Popup<>* layer) override; + bool init(std::string button, geode::Popup* layer); public: - geode::Popup<>* clickbotLayer = nullptr; + geode::Popup* clickbotLayer = nullptr; - static ClickSettingsLayer* create(std::string button, geode::Popup<>* layer); + static ClickSettingsLayer* create(std::string button, geode::Popup* layer); void saveSettings() { matjson::Value data = matjson::Serialize::to_json(settings); @@ -74,7 +76,7 @@ class ClickSettingsLayer : public geode::Popup*> { }; -class ClickbotLayer : public geode::Popup<> { +class ClickbotLayer : public geode::Popup { Slider* volumeSlider = nullptr; Slider* pitchSlider = nullptr; @@ -84,11 +86,11 @@ class ClickbotLayer : public geode::Popup<> { private: - bool setup() override; + bool init() override; public: - STATIC_CREATE(ClickbotLayer, 432, 250) + STATIC_CREATE(ClickbotLayer) std::vector labels; @@ -98,7 +100,7 @@ class ClickbotLayer : public geode::Popup<> { void openClickSettings(CCObject* obj) { std::string id = static_cast(obj)->getID(); - ClickSettingsLayer::create(id, static_cast*>(this))->show(); + ClickSettingsLayer::create(id, static_cast(this))->show(); } void updateLabels(); diff --git a/src/ui/game_ui.cpp b/src/ui/game_ui.cpp index 1f1f8467..6a3993f8 100644 --- a/src/ui/game_ui.cpp +++ b/src/ui/game_ui.cpp @@ -13,15 +13,15 @@ class $modify(PlayLayer) { PlayLayer::postUpdate(dt); auto& g = Global::get(); - #ifndef GEODE_IS_IOS - if (g.state != state::none && g.frameLabel && !g.renderer.recording) { - m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); - } - #else + //#ifndef GEODE_IS_IOS + // if (g.state != state::none && g.frameLabel && !g.renderer.recording) { + // m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); + // } + // #else if (g.state != state::none && g.frameLabel) { m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); } - #endif + // #endif } bool init(GJGameLevel * level, bool b1, bool b2) { @@ -134,13 +134,13 @@ void Interface::updateLabels() { if (labelText == "Playing" && state == state::playing && g.mod->getSavedValue("macro_hide_playing_label")) labelText = ""; -#ifndef GEODE_IS_IOS - if (g.renderer.recording && g.mod->getSavedValue("render_hide_labels")) { - labelText = ""; - if (CCLabelBMFont* lbl = typeinfo_cast(pl->getChildByID("frame-label"_spr))) - lbl->setString(""); - } -#endif +// #ifndef GEODE_IS_IOS + // if (g.renderer.recording && g.mod->getSavedValue("render_hide_labels")) { + // labelText = ""; + // if (CCLabelBMFont* lbl = typeinfo_cast(pl->getChildByID("frame-label"_spr))) + // lbl->setString(""); + // } +// #endif label->setString(labelText.c_str()); } diff --git a/src/ui/load_macro_layer.cpp b/src/ui/load_macro_layer.cpp index aa2c49e6..8e3cfd52 100644 --- a/src/ui/load_macro_layer.cpp +++ b/src/ui/load_macro_layer.cpp @@ -8,38 +8,38 @@ class $modify(CCMenu) { virtual bool ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) { CCScene* scene = CCDirector::sharedDirector()->getRunningScene(); LoadMacroLayer* layer = scene->getChildByType(0); - - if (!layer) return CCMenu::ccTouchBegan(touch, event); - - cocos2d::CCPoint pos = touch->getLocation(); + + if (!layer) return CCMenu::ccTouchBegan(touch, event); + + cocos2d::CCPoint pos = touch->getLocation(); float yCenter = CCDirector::sharedDirector()->getWinSize().height / 2.f; - + if (pos.y > yCenter - 100) return CCMenu::ccTouchBegan(touch, event); - + for (MacroCell* cell : layer->allMacros) { if (cell->menu == this) - return false; + return false; } - + return CCMenu::ccTouchBegan(touch, event); } }; -void LoadMacroLayer::open(geode::Popup<>* layer, geode::Popup<>* layer2, bool autosaves) { +void LoadMacroLayer::open(geode::Popup* layer, geode::Popup* layer2, bool autosaves) { std::filesystem::path path = Mod::get()->getSettingValue("macros_folder"); - + if (!std::filesystem::exists(path)) { if (utils::file::createDirectoryAll(path).isErr()) - return FLAlertLayer::create("Error", "There was an error getting the folder. ID: 6", "Ok")->show(); + return FLAlertLayer::create("Error", "There was an error getting the folder. ID: 6", "Ok")->show(); } - + path = Mod::get()->getSettingValue("autosaves_folder"); - + if (!std::filesystem::exists(path)) { if (utils::file::createDirectoryAll(path).isErr()) - return FLAlertLayer::create("Error", "There was an error getting the folder. ID: 61", "Ok")->show(); + return FLAlertLayer::create("Error", "There was an error getting the folder. ID: 61", "Ok")->show(); } - + LoadMacroLayer* layerReal = create(layer, layer2, autosaves); layerReal->m_noElasticity = true; layerReal->show(); @@ -52,51 +52,51 @@ void LoadMacroLayer::textChanged(CCTextInputNode* node) { searchOff->setOpacity(184); } else - searchOff->setVisible(false); - + searchOff->setVisible(false); + reloadList(0); } void LoadMacroLayer::reloadList(int amount) { if (CCNode* scrollbar = m_buttonMenu->getChildByID("scrollbar")) - scrollbar->removeFromParentAndCleanup(true); - + scrollbar->removeFromParentAndCleanup(true); + if (CCNode* lbl = menu->getChildByID("no-macros-label")) - lbl->removeFromParentAndCleanup(true); - + lbl->removeFromParentAndCleanup(true); + CCNode* listLayer = m_buttonMenu->getChildByID("list-layer"); if (!listLayer) return; - + ListView* listView = listLayer->getChildByType(0); - + CCLayer* contentLayer = nullptr; contentLayer = typeinfo_cast(listView->m_tableView->getChildren()->objectAtIndex(0)); - + int childrenCount = 0; float posY = 0.f; if (contentLayer) { if (CCArray* children = contentLayer->getChildren()) - childrenCount = children->count(); - + childrenCount = children->count(); + posY = contentLayer->getPositionY(); } listLayer->removeFromParentAndCleanup(true); if (CCNode* bg = m_buttonMenu->getChildByID("background")) - bg->removeFromParentAndCleanup(true); - + bg->removeFromParentAndCleanup(true); + selectedMacros.clear(); allMacros.clear(); - + if (!isMerge) - selectAllToggle->toggle(false); - + selectAllToggle->toggle(false); + addList(childrenCount > 7 && amount != 0, posY + (35.f * amount)); } void LoadMacroLayer::deleteSelected(CCObject*) { int amount = selectedMacros.size(); if (amount < 1) return; - + geode::createQuickPopup( "Warning", "Are you sure you want to delete " + std::to_string(amount) + " " + (isAutosaves ? "autosave" : "macro") + "(s)?", @@ -104,35 +104,35 @@ void LoadMacroLayer::deleteSelected(CCObject*) { [this, amount](auto, bool btn2) { if (btn2) { for (size_t i = 0; i < this->selectedMacros.size(); i++) - this->selectedMacros[i]->deleteMacro(false); - + this->selectedMacros[i]->deleteMacro(false); + this->reloadList(amount); Notification::create("Macros Deleted", NotificationIcon::Success)->show(); } } ); - + } void LoadMacroLayer::onSelectAll(CCObject* obj) { bool on = !static_cast(obj)->isToggled(); - + for (size_t i = 0; i < allMacros.size(); i++) { CCMenuItemToggler* toggle = allMacros[i]->toggler; if (toggle->isToggled() == on) continue; - + toggle->toggle(on); allMacros[i]->selectMacro(false); } } -LoadMacroLayer* LoadMacroLayer::create(geode::Popup<>* layer, geode::Popup<>* layer2, bool autosaves) { +LoadMacroLayer* LoadMacroLayer::create(geode::Popup* layer, geode::Popup* layer2, bool autosaves) { LoadMacroLayer* ret = new LoadMacroLayer(); - if (ret->initAnchored(385, 291, layer, layer2, autosaves, Utils::getTexture().c_str())) { + if (ret->init(layer, layer2, autosaves)) { ret->autorelease(); return ret; } - + delete ret; return nullptr; } @@ -143,104 +143,109 @@ void LoadMacroLayer::onImportMacro(CCObject*) { textFilter.description = "Macro Files"; textFilter.files = { "*.gdr", "*.xd", "*.json" }; fileOptions.filters.push_back(textFilter); - - file::pick(file::PickMode::OpenFile, { dirs::getGameDir(), { textFilter } }).listen([this](Result* res) { - if (res->isOk()) { - std::filesystem::path path = res->unwrapOrDefault(); - + + m_importFuture = [](LoadMacroLayer* self, file::FilePickOptions options) -> arc::Future { + auto res = co_await file::pick(file::PickMode::OpenFile, options); + if (res.isOk()) { + auto pathOpt = res.unwrapOrDefault(); + if (!pathOpt) co_return; + std::filesystem::path path = pathOpt.value(); + auto& g = Global::get(); Macro tempMacro; - + if (path.extension() == ".xd") { tempMacro = Macro::XDtoGDR(path); - - if (tempMacro.description == "fail") - return FLAlertLayer::create("Error", "There was an error importing this macro. ID: 46", "Ok")->show(); - + + if (tempMacro.description == "fail") { + FLAlertLayer::create("Error", "There was an error importing this macro. ID: 46", "Ok")->show(); + co_return; + } } else { - + std::ifstream f(path, std::ios::binary); - + f.seekg(0, std::ios::end); size_t fileSize = f.tellg(); f.seekg(0, std::ios::beg); - + std::vector macroData(fileSize); - + f.read(reinterpret_cast(macroData.data()), fileSize); f.close(); - + tempMacro = Macro::importData(macroData); - + } - + bool xdMacro = path.extension() == ".xd"; - + int iterations = 0; - + std::string name = path.filename().string().substr(0, path.filename().string().find_last_of('.')); - + std::filesystem::path newPath = Mod::get()->getSettingValue("macros_folder") / name; - + std::string pathString = newPath.string(); - + while (std::filesystem::exists(pathString + ".gdr.json")) { iterations++; - + if (iterations > 1) { int length = 3 + std::to_string(iterations - 1).length(); pathString.erase(pathString.length() - length, length); } - + pathString += fmt::format(" ({})", std::to_string(iterations)); } - + pathString += ".gdr.json"; - + std::ofstream f2(Utils::widen(pathString), std::ios::binary); auto data = tempMacro.exportData(true); - + f2.write(reinterpret_cast(data.data()), data.size()); f2.close(); - - this->reloadList(0); - + + self->reloadList(0); + if (xdMacro) - FLAlertLayer::create("Warning", ".xd extension macros may not function correctly in this version.", "Ok")->show(); - + FLAlertLayer::create("Warning", ".xd extension macros may not function correctly in this version.", "Ok")->show(); + Notification::create("Macro Imported", NotificationIcon::Success)->show(); } - }); + }(this, { dirs::getGameDir(), { textFilter } }); } -bool LoadMacroLayer::setup(geode::Popup<>* layer, geode::Popup<>* layer2, bool autosaves) { - +bool LoadMacroLayer::init(geode::Popup* layer, geode::Popup* layer2, bool autosaves) { + if (!Popup::init(385, 291, Utils::getTexture().c_str())) return false; + #ifdef GEODE_IS_ANDROID invertSort = true; #endif - + menu = CCMenu::create(); menu->setZOrder(110); m_mainLayer->addChild(menu); - + Utils::setBackgroundColor(m_bgSprite); - + menuLayer = layer; mergeLayer = layer2; isAutosaves = autosaves; isMerge = mergeLayer != nullptr; - + setTitle(isMerge ? "Merge Macro" : "Load Macro"); m_title->setPositionY(m_title->getPositionY() + 5); - m_closeBtn->getNormalImage()->setScale(0.6f); - + m_closeBtn->getNormalImage()->setScale(0.6f); + cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; - m_mainLayer->setPosition(m_mainLayer->getPosition() - offset); - m_bgSprite->setPosition(m_bgSprite->getPosition() + offset); - m_closeBtn->setPosition(m_closeBtn->getPosition() + offset); - m_title->setPosition(m_title->getPosition() + offset); - + m_mainLayer->setPosition(m_mainLayer->getPosition() - offset); + m_bgSprite->setPosition(m_bgSprite->getPosition() + offset); + m_closeBtn->setPosition(m_closeBtn->getPosition() + offset); + m_title->setPosition(m_title->getPosition() + offset); + if (!isMerge) { CCSprite* icon = CCSprite::createWithSpriteFrameName("GJ_plusBtn_001.png"); icon->setScale(0.585f); @@ -250,14 +255,14 @@ bool LoadMacroLayer::setup(geode::Popup<>* layer, geode::Popup<>* layer2, bool a menu_selector(LoadMacroLayer::onImportMacro) ); btn->setPosition(ccp(165, -121)); - + menu->addChild(btn); - + searchInput = TextInput::create(235, "Search Macro", "bigFont.fnt"); searchInput->setPositionY(100); searchInput->setDelegate(this); menu->addChild(searchInput); - + CCSprite* emptyBtn = CCSprite::createWithSpriteFrameName("GJ_plainBtn_001.png"); emptyBtn->setScale(0.585f); CCSprite* folderIcon = CCSprite::createWithSpriteFrameName("folderIcon_001.png"); @@ -270,9 +275,9 @@ bool LoadMacroLayer::setup(geode::Popup<>* layer, geode::Popup<>* layer2, bool a menu_selector(LoadMacroLayer::openFolder) ); btn->setPosition(ccp(115, -121)); - + menu->addChild(btn); - + CCSprite* spr = CCSprite::createWithSpriteFrameName("GJ_trashBtn_001.png"); spr->setScale(0.585f); btn = CCMenuItemSpriteExtra::create( @@ -281,9 +286,9 @@ bool LoadMacroLayer::setup(geode::Popup<>* layer, geode::Popup<>* layer2, bool a menu_selector(LoadMacroLayer::deleteSelected) ); btn->setPosition(ccp(65, -121)); - + menu->addChild(btn); - + if (isAutosaves) { spr = CCSprite::createWithSpriteFrameName("GJ_optionsBtn_001.png"); spr->setScale(0.55f); @@ -293,44 +298,44 @@ bool LoadMacroLayer::setup(geode::Popup<>* layer, geode::Popup<>* layer2, bool a menu_selector(AutoSaveLayer::open) ); btn->setPosition(ccp(15, -121)); - + menu->addChild(btn); } } - + CCSprite* spr1 = CCSprite::create("GJ_button_01.png"); CCSprite* spr2 = CCSprite::createWithSpriteFrameName("GJ_sortIcon_001.png"); spr2->setPosition({20, 20}); spr1->addChild(spr2); - + CCSprite* spr3 = CCSprite::create("GJ_button_02.png"); CCSprite* spr4 = CCSprite::createWithSpriteFrameName("GJ_sortIcon_001.png"); spr4->setPosition({20, 20}); spr3->addChild(spr4); - + sortToggle = CCMenuItemToggler::create(spr1, spr3, this, menu_selector(LoadMacroLayer::updateSort)); sortToggle->setPosition({-145, 100}); sortToggle->setScale(0.55f); sortToggle->toggle(false); menu->addChild(sortToggle); - + CCSprite* spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); CCSprite* spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); - + selectAllToggle = CCMenuItemToggler::create(spriteOff, spriteOn, this, menu_selector(LoadMacroLayer::onSelectAll)); selectAllToggle->setScale(0.585f); selectAllToggle->setPosition({ -165, -121 }); - + if (!isMerge) - menu->addChild(selectAllToggle); - + menu->addChild(selectAllToggle); + CCLabelBMFont* lbl = CCLabelBMFont::create("Select all", "bigFont.fnt"); lbl->setScale(0.4f); lbl->setPosition({ -110, -121 }); - + if (!isMerge) - menu->addChild(lbl); - + menu->addChild(lbl); + CCSprite* spr = CCSprite::createWithSpriteFrameName("gj_findBtnOff_001.png"); spr->setScale(0.685f); searchOff = CCMenuItemSpriteExtra::create( @@ -341,50 +346,50 @@ bool LoadMacroLayer::setup(geode::Popup<>* layer, geode::Popup<>* layer2, bool a searchOff->setPosition(ccp(137, 100)); searchOff->setVisible(false); menu->addChild(searchOff); - + macroCountLbl = CCLabelBMFont::create("13 Macros", "chatFont.fnt"); macroCountLbl->setOpacity(108); macroCountLbl->setScale(0.55f); macroCountLbl->setAnchorPoint({1.f, 0.5f}); macroCountLbl->setPosition({180, 130}); menu->addChild(macroCountLbl); - + if (isMerge) { p1Toggle = CCMenuItemToggler::create(spriteOff, spriteOn, this, nullptr); p1Toggle->setID("p1-toggle"); p1Toggle->setScale(0.675f); p1Toggle->setPosition({ -23, -121 }); menu->addChild(p1Toggle); - + p2Toggle = CCMenuItemToggler::create(spriteOff, spriteOn, this, nullptr); p2Toggle->setID("p2-toggle"); p2Toggle->setScale(0.675f); p2Toggle->setPosition({ 98, -121 }); menu->addChild(p2Toggle); - + owToggle = CCMenuItemToggler::create(spriteOff, spriteOn, this, nullptr); owToggle->setID("ow-toggle"); owToggle->setScale(0.675f); owToggle->setPosition({ -166, -121 }); owToggle->toggle(true); menu->addChild(owToggle); - + lbl = CCLabelBMFont::create("Overwrite", "bigFont.fnt"); lbl->setPosition({ -111, -121 }); lbl->setScale(0.44f); menu->addChild(lbl); - + lbl = CCLabelBMFont::create("P1 only", "bigFont.fnt"); lbl->setPosition({ 21, -121 }); lbl->setScale(0.44f); menu->addChild(lbl); - + lbl = CCLabelBMFont::create("P2 only", "bigFont.fnt"); lbl->setPosition({ 144, -121 }); lbl->setScale(0.44f); menu->addChild(lbl); } - + addList(); return true; @@ -394,53 +399,53 @@ void LoadMacroLayer::clearSearch(CCObject*) { searchOff->setVisible(false); searchInput->setString(""); search = ""; - + reloadList(0); } void LoadMacroLayer::updateSort(CCObject*) { if (!sortToggle) return; - + invertSort = !sortToggle->isToggled(); - + #ifdef GEODE_IS_ANDROID invertSort = !invertSort; #endif - + reloadList(0); } void LoadMacroLayer::addList(bool refresh, float prevScroll) { cocos2d::CCSize winSize = cocos2d::CCDirector::sharedDirector()->getWinSize(); - + std::filesystem::path path = Mod::get()->getSettingValue(isAutosaves ? "autosaves_folder" : "macros_folder"); std::vector macros = file::readDirectory(path).unwrapOrDefault(); - + CCArray* cells = CCArray::create(); - + for (int i = invertSort ? macros.size() - 1 : 0; invertSort ? i >= 0 : i < macros.size(); invertSort ? --i : ++i) { - + if (macros[i].extension() != ".gdr" && macros[i].extension() != ".xd" && macros[i].extension() != ".json") continue; - + std::string name = macros[i].filename().string().substr(0, macros[i].filename().string().find_last_of('.')); - + if (macros[i].extension() == ".json") - name = name.substr(0, name.find_last_of('.')); - + name = name.substr(0, name.find_last_of('.')); + if (Utils::toLower(name).find(search) == std::string::npos && search != "") continue; - + std::time_t date; - -#ifdef GEODE_IS_WINDOWS + + #ifdef GEODE_IS_WINDOWS date = Utils::getFileCreationTime(macros[i]); -#endif - + #endif + MacroCell* cell = MacroCell::create(macros[i], name, date, menuLayer, mergeLayer, static_cast(this)); cells->addObject(cell); } - + macroCountLbl->setString(fmt::format("{} Macros", std::to_string(cells->count())).c_str()); - + if (cells->count() == 0) { CCLabelBMFont* lbl = CCLabelBMFont::create(isAutosaves ? "No Autosaves" : "No Macros", "bigFont.fnt"); lbl->setPosition(winSize / 2); @@ -449,46 +454,57 @@ void LoadMacroLayer::addList(bool refresh, float prevScroll) { lbl->setID("no-macros-label"); menu->addChild(lbl); } - + ListView* listView = ListView::create(cells, 35, 323, 180); CCNode* contentLayer = static_cast(listView->m_tableView->getChildren()->objectAtIndex(0)); - + if (refresh) - contentLayer->setPositionY(prevScroll); - + contentLayer->setPositionY(prevScroll); + cocos2d::ccColor3B color = Mod::get()->getSettingValue("background_color"); - - CCArray* children = contentLayer->getChildren(); - CCObject* child; + + auto children = contentLayer->getChildren(); + int it = 0; - - cocos2d::ccColor3B color1 = ccc3(std::max(0, color.r - 70), std::max(0, color.g - 70), std::max(0, color.b - 70)); - cocos2d::ccColor3B color2 = ccc3(std::max(0, color.r - 55), std::max(0, color.g - 55), std::max(0, color.b - 55)); - - CCARRAY_FOREACH(children, child) { - if (GenericListCell* cell = typeinfo_cast(child)) { - allMacros.push_back(static_cast(cell->getChildren()->objectAtIndex(2))); - + + cocos2d::ccColor3B color1 = ccc3( + std::max(0, color.r - 70), + std::max(0, color.g - 70), + std::max(0, color.b - 70) + ); + cocos2d::ccColor3B color2 = ccc3( + std::max(0, color.r - 55), + std::max(0, color.g - 55), + std::max(0, color.b - 55) + ); + + for (auto child : CCArrayExt(children)) { + if (auto cell = typeinfo_cast(child)) { + if (auto macroCell = typeinfo_cast(cell->getChildrenExt()[2])) { + allMacros.push_back(macroCell); + } + cocos2d::ccColor3B col = (it % 2 == 0) ? color1 : color2; it++; cell->m_backgroundLayer->setColor(col); } } - + + GJCommentListLayer* listLayer = GJCommentListLayer::create(listView, "Custom Labels", ccc4(255, 255, 255, 0), 323, 180, true); listLayer->setPosition((winSize / 2) - (listLayer->getContentSize() / 2) - CCPoint((it >= 5) ? 6 : 0, 0) + ccp(0, 1)); listLayer->setZOrder(1); listLayer->setID("list-layer"); listView->setPositionY(-12); m_buttonMenu->addChild(listLayer); - + listLayer->setUserObject("dont-correct-borders", cocos2d::CCBool::create(true)); - + CCSprite* topBorder = listLayer->getChildByType(1); CCSprite* bottomBorder = listLayer->getChildByType(0); CCSprite* rightBorder = listLayer->getChildByType(3); CCSprite* leftBorder = listLayer->getChildByType(2); - + if (color != ccc3(51, 68, 153)) { CCSprite* topSprite = CCSprite::create("GJ_commentTop2_001_White.png"_spr); CCSprite* bottomSprite = CCSprite::create("GJ_commentTop2_001_White.png"_spr); @@ -496,39 +512,39 @@ void LoadMacroLayer::addList(bool refresh, float prevScroll) { CCSprite* leftSprite = CCSprite::create("GJ_commentSide2_001_White.png"_spr); rightSprite->setScaleX(-1); bottomSprite->setScaleY(-1); - + topSprite->setColor(color); bottomSprite->setColor(color); rightSprite->setColor(color); leftSprite->setColor(color); - + topSprite->setAnchorPoint({ 0, 0 }); bottomSprite->setAnchorPoint({ 0, 1 }); rightSprite->setAnchorPoint({ 1, 0 }); leftSprite->setAnchorPoint({ 0, 0 }); - + topBorder->addChild(topSprite); bottomBorder->addChild(bottomSprite); rightBorder->addChild(rightSprite); leftBorder->addChild(leftSprite); } - + topBorder->setScaleX(0.945f); topBorder->setScaleY(1.f); topBorder->setPosition(ccp(161.25, 162.f)); - + bottomBorder->setScaleX(0.945f); bottomBorder->setScaleY(1.f); bottomBorder->setPosition({ 161.25, -7.f }); - + rightBorder->setScaleX(0.8f); rightBorder->setScaleY(5.9f); rightBorder->setPosition({ 328, -12 }); - + leftBorder->setScaleX(0.8f); leftBorder->setScaleY(5.6f); leftBorder->setPosition({ -5.45, -1 }); - + CCScale9Sprite* listBackground = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); listBackground->setScale(0.7f); listBackground->setColor({ 0,0,0 }); @@ -537,7 +553,7 @@ void LoadMacroLayer::addList(bool refresh, float prevScroll) { listBackground->setContentSize({ 461.1f, 255.1f }); listBackground->setID("background"); m_buttonMenu->addChild(listBackground); - + if (it >= 5) { Scrollbar* scrollbar = Scrollbar::create(listView->m_tableView); scrollbar->setPosition({ (winSize.width / 2) + (listLayer->getScaledContentSize().width / 2) + 4, winSize.height / 2 }); @@ -546,19 +562,19 @@ void LoadMacroLayer::addList(bool refresh, float prevScroll) { } } -MacroCell* MacroCell::create(std::filesystem::path path, std::string name, std::time_t date, geode::Popup<>* menuLayer, geode::Popup<>* mergeLayer, CCLayer* loadLayer) { +MacroCell* MacroCell::create(std::filesystem::path path, std::string name, std::time_t date, geode::Popup* menuLayer, geode::Popup* mergeLayer, CCLayer* loadLayer) { MacroCell* ret = new MacroCell(); if (!ret->init(path, name, date, menuLayer, mergeLayer, loadLayer)) { delete ret; return nullptr; } - + ret->autorelease(); return ret; } -bool MacroCell::init(std::filesystem::path path, std::string name, std::time_t date, geode::Popup<>* menuLayer, geode::Popup<>* mergeLayer, CCLayer* loadLayer) { - +bool MacroCell::init(std::filesystem::path path, std::string name, std::time_t date, geode::Popup* menuLayer, geode::Popup* mergeLayer, CCLayer* loadLayer) { + this->path = path; this->date = date; this->name = name; @@ -566,9 +582,9 @@ bool MacroCell::init(std::filesystem::path path, std::string name, std::time_t d this->mergeLayer = mergeLayer; this->loadLayer = loadLayer; this->isMerge = mergeLayer != nullptr; - + bool autosave = false; - + size_t pos = name.find('_'); if (pos != std::string::npos) { std::string firstPart = name.substr(0, pos); @@ -577,7 +593,7 @@ bool MacroCell::init(std::filesystem::path path, std::string name, std::time_t d pos = secondPart.find('_'); if (pos != std::string::npos) { std::string str = secondPart.substr(pos + 1); - + if (std::all_of(str.begin(), str.end(), ::isdigit)) { autosave = true; this->name = secondPart.substr(0, pos); @@ -585,46 +601,46 @@ bool MacroCell::init(std::filesystem::path path, std::string name, std::time_t d } } } - + menu = CCMenu::create(); menu->setPosition({0, 0}); addChild(menu); - + CCLabelBMFont* lbl = CCLabelBMFont::create(this->name.c_str(), "chatFont.fnt"); lbl->limitLabelWidth(194.f, 0.8f, 0.01f); lbl->setAnchorPoint({ 0, 0.5 }); lbl->updateLabel(); addChild(lbl); - + lbl->setPosition({ 10, 23 }); - -#ifdef GEODE_IS_WINDOWS + + #ifdef GEODE_IS_WINDOWS std::string subText = Utils::formatTime(date) + " | "; - + subText += autosave ? "Auto Save" : path.extension().string(); - + lbl = CCLabelBMFont::create(subText.c_str(), "chatFont.fnt"); -#else + #else std::string subText = autosave ? "Auto Save" : path.extension().string(); - + lbl = CCLabelBMFont::create(subText.c_str(), "chatFont.fnt"); -#endif - + #endif + lbl->setPosition({ 10, 9 }); lbl->setScale(0.55f); lbl->setSkewX(2); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setOpacity(80); addChild(lbl); - + std::string btnText = isMerge ? "Merge" : "Load"; - + ButtonSprite* spr = ButtonSprite::create(btnText.c_str()); spr->setScale(isMerge ? 0.5425f : 0.62f); CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroCell::onLoad)); btn->setPosition(ccp(isMerge ? 277.26f : 288.26f, 17.5f)); menu->addChild(btn); - + CCSprite* spr2 = CCSprite::createWithSpriteFrameName("GJ_trashBtn_001.png"); spr2->setScale(0.485f); btn = CCMenuItemSpriteExtra::create( @@ -633,20 +649,20 @@ bool MacroCell::init(std::filesystem::path path, std::string name, std::time_t d menu_selector(MacroCell::onDelete) ); btn->setPosition(ccp(246, 17.5f)); - + if (!isMerge) - menu->addChild(btn); - + menu->addChild(btn); + CCSprite* spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); CCSprite* spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); - + toggler = CCMenuItemToggler::create(spriteOff, spriteOn, this, menu_selector(MacroCell::onSelect)); toggler->setScale(0.485f); toggler->setPosition({ 220, 17.5 }); - + if (!isMerge) - menu->addChild(toggler); - + menu->addChild(toggler); + return true; } @@ -655,75 +671,75 @@ void MacroCell::handleLoad() { Macro newMacro; Macro oldMacro = g.macro; - + if (path.extension() == ".xd") { if (!Macro::loadXDFile(path)) { if (!isMerge) - return FLAlertLayer::create("Error", "There was an error loading this macro. ID: 45", "Ok")->show(); + return FLAlertLayer::create("Error", "There was an error loading this macro. ID: 45", "Ok")->show(); else - return; + return; } - + newMacro = g.macro; - + if (isMerge) - g.macro = oldMacro; + g.macro = oldMacro; } else { std::ifstream f(path.string(), std::ios::binary); - + f.seekg(0, std::ios::end); size_t fileSize = f.tellg(); f.seekg(0, std::ios::beg); - + std::vector macroData(fileSize); - + f.read(reinterpret_cast(macroData.data()), fileSize); f.close(); - + newMacro = Macro::importData(macroData); } - + if (isMerge) { bool players[2] = { true, true }; bool p1 = static_cast(loadLayer)->p1Toggle->isToggled(); bool p2 = static_cast(loadLayer)->p2Toggle->isToggled(); - + if (p1) - players[1] = false; + players[1] = false; else if (p2) - players[0] = false; - + players[0] = false; + if (mergeLayer) { typeinfo_cast(mergeLayer)->mergeMacro(newMacro.inputs, players, static_cast(loadLayer)->owToggle->isToggled()); loadLayer->keyBackClicked(); } - + return; } - + g.macro = newMacro; g.currentAction = 0; g.currentFrameFix = 0; g.restart = true; g.macro.canChangeFPS = false; - - g.macro.xdBotMacro = g.macro.botInfo.name == "xdBot"; - + + g.macro.xdBotMacro = g.macro.botInfo.name == "xdBot"; + loadLayer->keyBackClicked(); - + RecordLayer* newLayer = nullptr; - + if (RecordLayer* layer = typeinfo_cast(menuLayer)) { - layer->keyBackClicked(); + layer->onClose(nullptr); newLayer = RecordLayer::openMenu(true); } - + if (!newLayer) newLayer = g.layer != nullptr ? static_cast(g.layer) : nullptr; if (newLayer) newLayer->updateTPS(); - + if (!PlayLayer::get() && g.state != state::playing) - Macro::togglePlaying(); + Macro::togglePlaying(); else if (g.state == state::recording) { if (newLayer) { newLayer->recording->toggle(Global::get().state != state::recording); @@ -735,17 +751,17 @@ void MacroCell::handleLoad() { layer->onClose(nullptr); } } - + if (path.extension() == ".xd") - FLAlertLayer::create("Warning", ".xd extension macros may not function correctly in this version.", "Ok")->show(); - + FLAlertLayer::create("Warning", ".xd extension macros may not function correctly in this version.", "Ok")->show(); + Notification::create("Macro Loaded", NotificationIcon::Success)->show(); } void MacroCell::onLoad(CCObject*) { if (Global::get().macro.inputs.empty() || isMerge) - return handleLoad(); - + return handleLoad(); + geode::createQuickPopup( "Warning", "Replace the current " + std::to_string(Global::get().macro.inputs.size()) + " macro actions?", @@ -756,7 +772,7 @@ void MacroCell::onLoad(CCObject*) { } } ); - + } void MacroCell::onDelete(CCObject*) { @@ -794,16 +810,16 @@ void MacroCell::onSelect(CCObject*) { void MacroCell::selectMacro(bool single) { LoadMacroLayer* layer = static_cast(loadLayer); std::vector& selectedMacros = layer->selectedMacros; - + auto it = std::remove(selectedMacros.begin(), selectedMacros.end(), this); - + if (it != selectedMacros.end()) { selectedMacros.erase(it, selectedMacros.end()); if (single) layer->selectAllToggle->toggle(false); } else - selectedMacros.push_back(this); - + selectedMacros.push_back(this); + if (selectedMacros.size() == layer->allMacros.size() && single) - layer->selectAllToggle->toggle(true); + layer->selectAllToggle->toggle(true); } \ No newline at end of file diff --git a/src/ui/load_macro_layer.hpp b/src/ui/load_macro_layer.hpp index 0e10f59e..c21ca77e 100644 --- a/src/ui/load_macro_layer.hpp +++ b/src/ui/load_macro_layer.hpp @@ -5,14 +5,15 @@ #include #include #include +#include class MacroCell : public CCNode { std::string name; std::filesystem::path path; std::time_t date; - geode::Popup<>* menuLayer = nullptr; - geode::Popup<>* mergeLayer = nullptr; + geode::Popup* menuLayer = nullptr; + geode::Popup* mergeLayer = nullptr; CCLayer* loadLayer = nullptr; bool isMerge = false; @@ -22,9 +23,9 @@ class MacroCell : public CCNode { CCMenu* menu = nullptr; CCMenuItemToggler* toggler = nullptr; - static MacroCell* create(std::filesystem::path path, std::string name, std::time_t date, geode::Popup<>* menuLayer, geode::Popup<>* mergeLayer, CCLayer* loadLayer); + static MacroCell* create(std::filesystem::path path, std::string name, std::time_t date, geode::Popup* menuLayer, geode::Popup* mergeLayer, CCLayer* loadLayer); - bool init(std::filesystem::path path, std::string name, std::time_t date, geode::Popup<>* menuLayer, geode::Popup<>* mergeLayer, CCLayer* loadLayer); + bool init(std::filesystem::path path, std::string name, std::time_t date, geode::Popup* menuLayer, geode::Popup* mergeLayer, CCLayer* loadLayer); void onLoad(CCObject*); @@ -39,11 +40,11 @@ class MacroCell : public CCNode { void selectMacro(bool single); }; -class LoadMacroLayer : public geode::Popup*, geode::Popup<>*, bool>, public TextInputDelegate { +class LoadMacroLayer : public geode::Popup, TextInputDelegate { public: - geode::Popup<>* menuLayer = nullptr; - geode::Popup<>* mergeLayer = nullptr; + geode::Popup* menuLayer = nullptr; + geode::Popup* mergeLayer = nullptr; CCMenu* menu = nullptr; CCMenuItemToggler* selectAllToggle = nullptr; @@ -66,11 +67,13 @@ class LoadMacroLayer : public geode::Popup*, geode::Popup<>*, boo bool isMerge = false; bool invertSort = false; - static LoadMacroLayer* create(geode::Popup<>* layer, geode::Popup<>* layer2, bool autosaves); + std::optional> m_importFuture; - bool setup(geode::Popup<>* layer, geode::Popup<>* layer2, bool autosaves) override; + static LoadMacroLayer* create(geode::Popup* layer, geode::Popup* layer2, bool autosaves); - static void open(geode::Popup<>* layer, geode::Popup<>* layer2, bool autosaves = false); + bool init(geode::Popup* layer, geode::Popup* layer2, bool autosaves); + + static void open(geode::Popup* layer, geode::Popup* layer2, bool autosaves = false); void openFolder(CCObject*) { file::openFolder(Mod::get()->getSettingValue(isAutosaves ? "autosaves_folder" : "macros_folder")); diff --git a/src/ui/macro_editor.cpp b/src/ui/macro_editor.cpp index 369eb898..56dde1a8 100644 --- a/src/ui/macro_editor.cpp +++ b/src/ui/macro_editor.cpp @@ -11,15 +11,15 @@ MacroEditLayer* editLayer = nullptr; class $modify(CCEGLView) { void onGLFWMouseMoveCallBack(GLFWwindow* v1, double v2, double v3) { CCEGLView::onGLFWMouseMoveCallBack(v1, v2, v3); - + if (!editLayer) return; - + CCScene* scene = CCDirector::get()->getRunningScene(); if (MacroEditLayer* layer = scene->getChildByType(0)) - editLayer = layer; + editLayer = layer; else - return; - + return; + editLayer->updateHover(getMousePos()); } @@ -28,41 +28,41 @@ class $modify(CCEGLView) { #endif class $modify(FLAlertLayer) { - -#ifdef GEODE_IS_MOBILE - + + #ifdef GEODE_IS_MOBILE + virtual bool ccTouchBegan(cocos2d::CCTouch * touch, cocos2d::CCEvent * event) { if (!FLAlertLayer::ccTouchBegan(touch, event)) return false; MacroEditLayer* layer = typeinfo_cast(this); - + if (!layer) return true; - + layer->updateHover(touch->getLocation()); - + return true; } - + virtual void ccTouchMoved(cocos2d::CCTouch * touch, cocos2d::CCEvent * event) { FLAlertLayer::ccTouchMoved(touch, event); MacroEditLayer* layer = typeinfo_cast(this); - + if (!layer) return; - + layer->updateHover(touch->getLocation()); } - -#endif - + + #endif + virtual void ccTouchEnded(cocos2d::CCTouch * touch, cocos2d::CCEvent * event) { FLAlertLayer::ccTouchEnded(touch, event); MacroEditLayer* layer = typeinfo_cast(this); - + if (!layer) return; - + layer->selectInput(layer->hoveredInput); layer->updateHover(touch->getLocation()); } - + }; MacroEditLayer::~MacroEditLayer() { @@ -93,68 +93,69 @@ void MacroEditLayer::onClose(CCObject*) { void MacroEditLayer::updateHover(cocos2d::CCPoint pos) { if (pageInputs.empty()) return; - + cocos2d::CCSize center = CCDirector::sharedDirector()->getWinSize() / 2.f; - + float xMin = center.width - 91 - 95; float xMax = center.width - 91 + 95; - + float yMin = center.height - 87.5; float yMax = center.height + 87.5; - + if (pos.x < xMin || pos.x > xMax) return stopHovering(); if (pos.y < yMin || pos.y > yMax) return stopHovering(); - + for (int i = 1; i < 7; i++) { if (pos.y > yMax - (i * 29)) - return hoverInput(i - 1); + return hoverInput(i - 1); } - + stopHovering(); } -bool MacroEditLayer::setup() { +bool MacroEditLayer::init() { + if (!Popup::init(438, 247)) return false; Utils::setBackgroundColor(m_bgSprite); CCMenu* menu = CCMenu::create(); menu->setID("main-menu"); m_mainLayer->addChild(menu); - + selectedInputMenu = CCMenu::create(); selectedInputMenu->setID("selected-input-menu"); m_mainLayer->addChild(selectedInputMenu); - + CCLabelBMFont* lbl = CCLabelBMFont::create("Edit Macro", "goldFont.fnt"); lbl->setPosition({117, 104}); lbl->setScale(0.55f); menu->addChild(lbl); - + inputCountLbl = CCLabelBMFont::create("Inputs: 156", "chatFont.fnt"); inputCountLbl->setPosition({-187, 112}); inputCountLbl->setAnchorPoint({0, 0.5}); inputCountLbl->setOpacity(99); inputCountLbl->setScale(0.45f); menu->addChild(inputCountLbl); - + notSavedLabel = CCLabelBMFont::create("*", "chatFont.fnt"); notSavedLabel->setPosition({-3, 94}); notSavedLabel->setScale(0.7f); notSavedLabel->setOpacity(139); notSavedLabel->setVisible(false); menu->addChild(notSavedLabel); - + noInputsLabel1 = CCLabelBMFont::create("Empty", "bigFont.fnt"); noInputsLabel1->setOpacity(174); noInputsLabel1->setPositionX(-91); noInputsLabel1->setScale(0.85f); menu->addChild(noInputsLabel1); - + noInputsLabel2 = CCLabelBMFont::create("No Input", "bigFont.fnt"); noInputsLabel2->setOpacity(174); noInputsLabel2->setPositionX(117); noInputsLabel2->setScale(0.625f); menu->addChild(noInputsLabel2); - + hoveredBg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); hoveredBg->setColor({ 255, 255, 255 }); hoveredBg->setOpacity(44); @@ -164,7 +165,7 @@ bool MacroEditLayer::setup() { hoveredBg->setContentSize({ 471, 65 }); hoveredBg->setVisible(false); menu->addChild(hoveredBg); - + selectedBg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); selectedBg->setColor({ 232, 255, 0 }); selectedBg->setOpacity(44); @@ -173,7 +174,7 @@ bool MacroEditLayer::setup() { selectedBg->setAnchorPoint({ 0.5, 0.5 }); selectedBg->setContentSize({ 471, 65 }); menu->addChild(selectedBg); - + listBg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); listBg->setColor({ 0,0,0 }); listBg->setOpacity(78); @@ -181,7 +182,7 @@ bool MacroEditLayer::setup() { listBg->setAnchorPoint({ 0.5, 0.5 }); listBg->setContentSize({ 194, 209 }); menu->addChild(listBg); - + selectedInputBg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); selectedInputBg->setColor({ 0,0,0 }); selectedInputBg->setOpacity(78); @@ -189,56 +190,56 @@ bool MacroEditLayer::setup() { selectedInputBg->setAnchorPoint({ 0.5, 0.5 }); selectedInputBg->setContentSize({ 151, 167 }); menu->addChild(selectedInputBg); - + CCSprite* spr = CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"); spr->setScale(0.55f); pageLeftBtn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::switchPage)); pageLeftBtn->setID("left"); pageLeftBtn->setPositionX(-199); menu->addChild(pageLeftBtn); - + spr = CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"); spr->setFlipX(true); spr->setScale(0.55f); pageRightBtn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::switchPage)); pageRightBtn->setPositionX(17); menu->addChild(pageRightBtn); - + ButtonSprite* btnSpr = ButtonSprite::create("Apply"); btnSpr->setScale(0.5f); saveBtn = CCMenuItemSpriteExtra::create(btnSpr, this, menu_selector(MacroEditLayer::onSave)); saveBtn->setPosition({185, -99}); menu->addChild(saveBtn); - + btnSpr = ButtonSprite::create("Merge"); btnSpr->setScale(0.5f); CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(btnSpr, this, menu_selector(MacroEditLayer::onMerge)); btn->setPosition({72, -99}); menu->addChild(btn); - + btnSpr = ButtonSprite::create("Clear"); btnSpr->setScale(0.5f); btn = CCMenuItemSpriteExtra::create(btnSpr, this, menu_selector(MacroEditLayer::onClear)); btn->setPosition({128.5, -99}); menu->addChild(btn); - - spr = CCSprite::createWithSpriteFrameName("GJ_plusBtn_001.png"); + + spr = CCSprite::createWithSpriteFrameName("GJ_plusBtn_001.png"); spr->setScale(0.45f); btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::onAddInput)); btn->setPosition({23.5, -94}); menu->addChild(btn); - + spr = CCSprite::createWithSpriteFrameName("GJ_deleteSongBtn_001.png"); spr->setScale(0.55f); deleteBtn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::onRemoveInput)); deleteBtn->setPosition({23.5, -64}); menu->addChild(deleteBtn); - + lbl = CCLabelBMFont::create("Page", "bigFont.fnt"); lbl->setPosition({23.5, 108}); lbl->setScale(0.26f); menu->addChild(lbl); - + pageInput = TextInput::create(36, "0"); pageInput->getInputNode()->setAllowedChars("0123456789"); pageInput->getInputNode()->setMaxLabelLength(5); @@ -246,22 +247,22 @@ bool MacroEditLayer::setup() { pageInput->setPosition({23.5, 91}); pageInput->setScale(0.55f); menu->addChild(pageInput); - + float xPos = 57.f; float yPos = 44.5f; - + lbl = CCLabelBMFont::create("Selected Input", "bigFont.fnt"); lbl->setPosition({117, 73}); lbl->setOpacity(196); lbl->setScale(0.4f); menu->addChild(lbl); - + lbl = CCLabelBMFont::create("Frame: ", "bigFont.fnt"); lbl->setScale(0.375f); lbl->setAnchorPoint({0, 0.5}); lbl->setPosition({xPos, yPos}); selectedInputMenu->addChild(lbl); - + frameInput = TextInput::create(70, "236"); frameInput->setPosition({xPos + 91, yPos}); frameInput->setScale(0.625f); @@ -269,33 +270,33 @@ bool MacroEditLayer::setup() { frameInput->getInputNode()->setMaxLabelLength(8); frameInput->getInputNode()->setDelegate(this); selectedInputMenu->addChild(frameInput); - + spr = CCSprite::createWithSpriteFrameName("edit_leftBtn_001.png"); spr->setScale(0.55f); btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::switchFrame)); btn->setPosition({xPos + 62, yPos}); btn->setID("left"); selectedInputMenu->addChild(btn); - + spr = CCSprite::createWithSpriteFrameName("edit_rightBtn_001.png"); spr->setScale(0.55f); btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::switchFrame)); btn->setPosition({xPos + 120, yPos}); selectedInputMenu->addChild(btn); - + lbl = CCLabelBMFont::create("Button: ", "bigFont.fnt"); lbl->setAnchorPoint({0, 0.5}); lbl->setScale(0.375f); lbl->setPosition({xPos, yPos - 35}); selectedInputMenu->addChild(lbl); - + spr = CCSprite::createWithSpriteFrameName("edit_leftBtn_001.png"); spr->setScale(0.55f); btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::switchButton)); btn->setPosition({xPos + 62, yPos - 35}); btn->setID("left"); selectedInputMenu->addChild(btn); - + spr = CCSprite::createWithSpriteFrameName("edit_rightBtn_001.png"); spr->setScale(0.55f); btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::switchButton)); @@ -310,24 +311,24 @@ bool MacroEditLayer::setup() { bg->setAnchorPoint({ 0.5, 0.5 }); bg->setContentSize({ 140, 60 }); selectedInputMenu->addChild(bg); - + buttonLabel = CCLabelBMFont::create("Left", "bigFont.fnt"); buttonLabel->setScale(0.375f); buttonLabel->setPosition({xPos + 91, yPos - 35}); selectedInputMenu->addChild(buttonLabel); - + lbl = CCLabelBMFont::create("Action: ", "bigFont.fnt"); lbl->setAnchorPoint({0, 0.5}); lbl->setScale(0.375f); lbl->setPosition({xPos, yPos - 66}); selectedInputMenu->addChild(lbl); - + spr = CCSprite::createWithSpriteFrameName("edit_leftBtn_001.png"); spr->setScale(0.55f); btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::switchAction)); btn->setPosition({xPos + 62, yPos - 66}); selectedInputMenu->addChild(btn); - + spr = CCSprite::createWithSpriteFrameName("edit_rightBtn_001.png"); spr->setScale(0.55f); btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::switchAction)); @@ -342,30 +343,30 @@ bool MacroEditLayer::setup() { bg->setAnchorPoint({ 0.5, 0.5 }); bg->setContentSize({ 140, 60 }); selectedInputMenu->addChild(bg); - + actionLabel = CCLabelBMFont::create("Hold", "bigFont.fnt"); actionLabel->setScale(0.375f); actionLabel->setPosition({xPos + 91, yPos - 66}); selectedInputMenu->addChild(actionLabel); - + lbl = CCLabelBMFont::create("Player: ", "bigFont.fnt"); lbl->setAnchorPoint({0, 0.5}); lbl->setScale(0.375f); lbl->setPosition({xPos, yPos - 97}); selectedInputMenu->addChild(lbl); - + spr = CCSprite::createWithSpriteFrameName("edit_leftBtn_001.png"); spr->setScale(0.55f); btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::switchPlayer)); btn->setPosition({xPos + 62, yPos - 97}); selectedInputMenu->addChild(btn); - + spr = CCSprite::createWithSpriteFrameName("edit_rightBtn_001.png"); spr->setScale(0.55f); btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(MacroEditLayer::switchPlayer)); btn->setPosition({xPos + 120, yPos - 97}); selectedInputMenu->addChild(btn); - + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); bg->setColor({ 0,0,0 }); bg->setScale(0.3125f); @@ -374,12 +375,12 @@ bool MacroEditLayer::setup() { bg->setAnchorPoint({ 0.5, 0.5 }); bg->setContentSize({ 140, 60 }); selectedInputMenu->addChild(bg); - + playerLabel = CCLabelBMFont::create("One", "bigFont.fnt"); playerLabel->setScale(0.375f); playerLabel->setPosition({xPos + 91, yPos - 97}); selectedInputMenu->addChild(playerLabel); - + for (int i = 0; i < 7; i++) { CCLabelBMFont* lbl = CCLabelBMFont::create("_____________________", "chatFont.fnt"); lbl->setPosition(ccp(-91, 93.5 - (i * 29))); @@ -388,19 +389,19 @@ bool MacroEditLayer::setup() { menu->addChild(lbl); separators.push_back(lbl); } - + inputs = Global::get().macro.inputs; ogInputs = inputs; - + loadPage(1); - + hoveredInput = -2; selectInput(0); - + updateSaved(); - + editLayer = this; - + cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; m_mainLayer->setPosition(m_mainLayer->getPosition() - offset); m_closeBtn->setPosition(m_closeBtn->getPosition() + offset); @@ -411,118 +412,118 @@ bool MacroEditLayer::setup() { void MacroEditLayer::loadPage(int page) { currentPage = page; - + pageInput->setString(std::to_string(currentPage).c_str()); - + if (pageMenu) - pageMenu->removeFromParentAndCleanup(true); + pageMenu->removeFromParentAndCleanup(true); pageMenu = CCMenu::create(); pageMenu->setID("page-menu"); m_mainLayer->addChild(pageMenu); - + updatePageInputs(page); - + bool empty = pageInputs.empty(); - + noInputsLabel1->setVisible(empty); noInputsLabel2->setVisible(empty); - + selectedInputMenu->setVisible(!empty); - + bool disableArrows = inputs.size() <= 6; - + deleteBtn->getChildByType(0)->setOpacity(empty ? 130 : 255); deleteBtn->setEnabled(!empty); - + pageLeftBtn->getChildByType(0)->setOpacity((disableArrows && !empty) || inputs.empty() ? 130 : 255); pageLeftBtn->setEnabled(!((disableArrows && !empty) || inputs.empty())); - + disableArrows = disableArrows || (empty && !inputs.empty()); - + pageRightBtn->getChildByType(0)->setOpacity(disableArrows ? 130 : 255); pageRightBtn->setEnabled(!disableArrows); - + for (int i = 0; i < 7; i++) - separators[i]->setVisible(i <= pageInputs.size() && !empty); - + separators[i]->setVisible(i <= pageInputs.size() && !empty); + if (empty) { selectedBg->setVisible(false); hoveredBg->setVisible(false); - + selectedInput = -1; selectedInputIndex = -1; hoveredInput = -1; - + return; } - + if (selectedInput == -1) - selectInput(pageInputs.size() - 1); - + selectInput(pageInputs.size() - 1); + for (int i = 0; i < pageInputs.size(); i ++) { float height1 = 78.f - (i * 29.f); float height2 = 67.f - (i * 29.f); - + InputText inp = getInputText(pageInputs[i]); - + CCLabelBMFont* lbl = CCLabelBMFont::create("Frame", "chatFont.fnt"); lbl->setScale(0.525f); lbl->setOpacity(134); lbl->setPosition({-153, height1}); - + pageMenu->addChild(lbl); lbl = CCLabelBMFont::create(inp.frame.c_str(), "chatFont.fnt"); lbl->setScale(0.55f); lbl->setOpacity(218); lbl->setPosition({-153, height2}); - + pageMenu->addChild(lbl); - + lbl = CCLabelBMFont::create("Button", "chatFont.fnt"); lbl->setScale(0.525f); lbl->setOpacity(134); lbl->setPosition({-112, height1}); - + pageMenu->addChild(lbl); - + lbl = CCLabelBMFont::create(inp.button.c_str(), "chatFont.fnt"); lbl->setScale(0.55f); lbl->setOpacity(218); lbl->setPosition({-112, height2}); - + pageMenu->addChild(lbl); - + lbl = CCLabelBMFont::create("Action", "chatFont.fnt"); lbl->setScale(0.525f); lbl->setOpacity(134); lbl->setPosition({-69, height1}); - + pageMenu->addChild(lbl); - + lbl = CCLabelBMFont::create(inp.action.c_str(), "chatFont.fnt"); lbl->setScale(0.55f); lbl->setOpacity(218); lbl->setPosition({-69, height2}); - + pageMenu->addChild(lbl); - + lbl = CCLabelBMFont::create("Player", "chatFont.fnt"); lbl->setScale(0.525f); lbl->setOpacity(134); lbl->setPosition({-31, height1}); - + pageMenu->addChild(lbl); - + lbl = CCLabelBMFont::create(inp.player.c_str(), "chatFont.fnt"); lbl->setScale(0.55f); lbl->setOpacity(218); lbl->setPosition({-31, height2}); - + pageMenu->addChild(lbl); } - + } InputText MacroEditLayer::getInputText(input input) { @@ -532,47 +533,47 @@ InputText MacroEditLayer::getInputText(input input) { input.player2 ? "Two" : "One", input.down ? "Hold" : "Release" }; - + return ret; } void MacroEditLayer::textChanged(CCTextInputNode* input) { if (!input || !editLayer) return; - + std::string text = input->getString(); - + if (text == "") return; - + if (input == editLayer->pageInput->getInputNode()) { int page = std::stoi(text); - + if (page <= 0) return; - + editLayer->loadPage(page); editLayer->reSelectInput(); - + return; } - + if (input == editLayer->frameInput->getInputNode()) { int frame = std::stoi(text); - + editLayer->changeSelectedInputFrame(frame, false); - + return; } } void MacroEditLayer::updatePageInputs(int page) { - + if (!pageInputs.empty()) - pageInputs.clear(); - + pageInputs.clear(); + for (int i = 0; i < 6; i++) { int index = (page - 1) * 6 + i; - + if (index >= inputs.size()) break; - + pageInputs.push_back(inputs[index]); } } @@ -580,11 +581,11 @@ void MacroEditLayer::updatePageInputs(int page) { void MacroEditLayer::hoverInput(int input) { if (input == selectedInput) return stopHovering(); if (input >= pageInputs.size()) return stopHovering(); - + float y = 72.5f - (29 * input); hoveredBg->setPositionY(y); hoveredBg->setVisible(true); - + hoveredInput = input; } @@ -596,11 +597,11 @@ void MacroEditLayer::stopHovering() { void MacroEditLayer::updateLabels() { auto currentInput = inputs[selectedInputIndex]; InputText inp = getInputText(currentInput); - + frameInput->setString(inp.frame.c_str()); playerLabel->setString(inp.player.c_str()); buttonLabel->setString(inp.button.c_str()); - + actionLabel->setString(inp.action.c_str()); actionLabel->limitLabelWidth(33.f, 1.f, 0.01f); actionLabel->updateLabel(); @@ -608,19 +609,19 @@ void MacroEditLayer::updateLabels() { void MacroEditLayer::selectInput(int input) { if (hoveredInput == -1 || hoveredInput == selectedInput || selectedInput == input) return; - + if (hoveredInput == -2) - hoveredInput = -1; - + hoveredInput = -1; + if (pageInputs.empty()) return; - + if (input >= pageInputs.size()) - input = pageInputs.size() - 1; - + input = pageInputs.size() - 1; + float y = 72.5f - (29 * input); selectedBg->setPositionY(y); selectedBg->setVisible(true); - + selectedInput = input; selectedInputIndex = (currentPage - 1) * 6 + input; @@ -630,112 +631,112 @@ void MacroEditLayer::selectInput(int input) { void MacroEditLayer::reSelectInput() { int prevSelected = selectedInput; - + selectedInput = -1; selectedInputIndex = -1; hoveredInput = -2; - + selectInput(prevSelected); } int MacroEditLayer::getSum(CCObject* obj) { if (std::string_view(static_cast(obj)->getID()) == "left") - return -1; - + return -1; + return 1; } void MacroEditLayer::switchPage(CCObject* obj) { int sum = getSum(obj); - + currentPage += sum; - + int lastPage = inputs.size() / 6; bool empty = pageInputs.empty(); - + if (inputs.size() != lastPage * 6) - lastPage++; - + lastPage++; + if (currentPage == 0 || empty) { currentPage = lastPage; } else if (currentPage >= lastPage + 1) { currentPage = 1; } - + loadPage(currentPage); reSelectInput(); if (empty) - selectInput(5); + selectInput(5); } void MacroEditLayer::switchFrame(CCObject* obj) { auto input = inputs[selectedInputIndex]; int sum = getSum(obj); - + if (input.frame == 0 && sum == -1) return; - + changeSelectedInputFrame(input.frame + sum); } void MacroEditLayer::changeSelectedInputFrame(int frame, bool isArrow) { auto input = inputs[selectedInputIndex]; - + input.frame = frame; inputs.erase(inputs.begin() + selectedInputIndex); size_t addedAt = 0; - + for (size_t i = 0; i < inputs.size(); i++) { int currentFrame = inputs[i].frame; int nextFrame = i != inputs.size() - 1 ? inputs[i + 1].frame : -1; - + if ((selectedInputIndex == 0 && input.frame < currentFrame) || frame <= inputs[0].frame) { inputs.insert(inputs.begin(), input); - + addedAt = 0; - + break; } - + if (selectedInputIndex == inputs.size() && isArrow) { - + addedAt = selectedInputIndex; inputs.push_back(input); - + auto secLast = inputs.size() - 2; - + if (inputs[secLast].frame > input.frame) { auto inputCopy = inputs[secLast]; - + inputs.erase(inputs.begin() + secLast); inputs.push_back(inputCopy); - + addedAt = selectedInputIndex - 1; } - + break; } - + if ((input.frame > currentFrame && input.frame <= nextFrame) || nextFrame == -1) { - + inputs.insert(inputs.begin() + i + 1, input); addedAt = i + 1; - + break; } } - + int co = addedAt / 6; int newPage = co + 1; int newSelected = addedAt - co * 6; - + loadPage(newPage); - + selectedInput = newSelected; reSelectInput(); updateSaved(); @@ -743,14 +744,14 @@ void MacroEditLayer::changeSelectedInputFrame(int frame, bool isArrow) { void MacroEditLayer::switchButton(CCObject* obj) { int sum = getSum(obj); - + auto& input = inputs[selectedInputIndex]; input.button += sum; - + if (input.button == 0) input.button = 3; if (input.button == 4) input.button = 1; - + loadPage(currentPage); reSelectInput(); updateSaved(); @@ -758,9 +759,9 @@ void MacroEditLayer::switchButton(CCObject* obj) { void MacroEditLayer::switchAction(CCObject* obj) { auto& input = inputs[selectedInputIndex]; - + input.down = !input.down; - + loadPage(currentPage); reSelectInput(); updateSaved(); @@ -768,9 +769,9 @@ void MacroEditLayer::switchAction(CCObject* obj) { void MacroEditLayer::switchPlayer(CCObject* obj) { auto& input = inputs[selectedInputIndex]; - + input.player2 = !input.player2; - + loadPage(currentPage); reSelectInput(); updateSaved(); @@ -778,23 +779,23 @@ void MacroEditLayer::switchPlayer(CCObject* obj) { void MacroEditLayer::flashSelected() { if (!selectedBg->isVisible()) return; - + CCTintTo* tintTo = CCTintTo::create(0.05f, 247, 255, 140); CCTintTo* tintFrom = CCTintTo::create(0.35f, 232, 255, 0); - + CCFadeTo* fadeTo = CCFadeTo::create(0.05f, 100); CCFadeTo* fadeFrom = CCFadeTo::create(0.35f, 44); - + CCSequence* colorSeq = CCSequence::create(tintTo, tintFrom, nullptr); CCSequence* opacitySeq = CCSequence::create(fadeTo, fadeFrom, nullptr); - + CCSpawn* spawn = CCSpawn::create(colorSeq, opacitySeq, nullptr); - + selectedBg->runAction(spawn); - + tintTo = CCTintTo::create(0.05f, 20, 20, 20); tintFrom = CCTintTo::create(0.35f, 0, 0, 0); - + selectedInputBg->runAction(CCSequence::create(tintTo, tintFrom, nullptr)); } @@ -802,42 +803,42 @@ void MacroEditLayer::onAddInput(CCObject*) { if (inputs.empty()) { inputs.push_back({1, 1, false, true}); loadPage(1); - + hoveredInput = -2; selectInput(0); - + return updateSaved(); } - + if (pageInputs.empty()) { int lastPage = inputs.size() / 6; - + if (inputs.size() != lastPage * 6) - lastPage++; - + lastPage++; + loadPage(lastPage); - + if (pageInputs.empty()) return updateSaved(); - + hoveredInput = -2; selectInput(pageInputs.size() - 1); } - + auto input = inputs[selectedInputIndex]; input.frame++; - + inputs.insert(inputs.begin() + (selectedInputIndex + 1), input); - + if (selectedInput == 5) { loadPage(currentPage + 1); - + hoveredInput = -2; selectInput(0); flashSelected(); - + return updateSaved(); } - + hoveredInput = -2; loadPage(currentPage); selectInput(selectedInput + 1); @@ -846,21 +847,21 @@ void MacroEditLayer::onAddInput(CCObject*) { void MacroEditLayer::onRemoveInput(CCObject*) { if (inputs.empty() || pageInputs.empty() || selectedInput == -1) return; - + inputs.erase(inputs.begin() + selectedInputIndex); - + loadPage(currentPage); reSelectInput(); - + while (pageInputs.empty() && currentPage != 1) { loadPage(currentPage - 1); selectedInput != 5 ? selectInput(5) : reSelectInput(); } - + if (inputs.empty()) { CCTintTo* tintTo = CCTintTo::create(0.05f, 20, 20, 20); CCTintTo* tintFrom = CCTintTo::create(0.35f, 0, 0, 0); - + selectedInputBg->runAction(CCSequence::create(tintTo, tintFrom, nullptr)); listBg->runAction(CCSequence::create(tintTo, tintFrom, nullptr)); } @@ -870,45 +871,45 @@ void MacroEditLayer::onRemoveInput(CCObject*) { void MacroEditLayer::onSave(CCObject*) { std::string extension = Global::get().macro.frameFixes.empty() || inputs.empty() ? "." : " \nAll Frame Fixes will be removed."; - + geode::createQuickPopup( "Apply", "Apply changes to current macro?" + extension, "Cancel", "Yes", [this](auto, bool btn2) { if (!btn2) return; - + auto& g = Global::get(); g.macro.frameFixes.clear(); g.macro.inputs = this->inputs; - + this->saved = true; - + onClose(nullptr); - - CCArray* children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); - CCObject* child; - CCARRAY_FOREACH(children, child) { + + auto children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); + + for (auto child : CCArrayExt(children)) { if (RecordLayer* layer = typeinfo_cast(child)) { - layer->keyBackClicked(); + layer->onClose(nullptr); break; } } - + RecordLayer::openMenu(true); MacroEditLayer::open(true); - + Loader::get()->queueInMainThread([] { - CCArray* children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); - CCObject* child; - CCARRAY_FOREACH(children, child) { + auto children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); + + for (auto child : CCArrayExt(children)) { if (MacroEditLayer* layer = typeinfo_cast(child)) { editLayer = layer; break; } } }); - + Notification::create("Applied", NotificationIcon::Success)->show(); } ); @@ -918,7 +919,7 @@ void MacroEditLayer::toggleSaveButton(bool toggle) { ButtonSprite* btnSpr = saveBtn->getChildByType(0); CCScale9Sprite* spr = btnSpr->getChildByType(0); CCLabelBMFont* lbl = btnSpr->getChildByType(0); - + saveBtn->setEnabled(toggle); spr->setOpacity(toggle ? 255 : 130); lbl->setOpacity(toggle ? 255 : 130); @@ -926,18 +927,18 @@ void MacroEditLayer::toggleSaveButton(bool toggle) { void MacroEditLayer::updateSaved() { saved = inputs == ogInputs; - + notSavedLabel->setVisible(!saved); saveBtn->setEnabled(!saved); toggleSaveButton(!saved); - + inputCountLbl->setString(fmt::format("Inputs: {}", inputs.size()).c_str()); } void MacroEditLayer::onClear(CCObject*) { auto& g = Global::get(); if (inputs.empty()) return; - + geode::createQuickPopup( "Clear", "Clear " + std::to_string(inputs.size()) + " macro actions?", @@ -953,39 +954,41 @@ void MacroEditLayer::onClear(CCObject*) { } void MacroEditLayer::onMerge(CCObject*) { - geode::Popup<>* layer = nullptr; - if (Global::get().layer) - layer = typeinfo_cast*>(Global::get().layer); - else { - CCArray* children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); - CCObject* child; - CCARRAY_FOREACH(children, child) { + geode::Popup* layer = nullptr; + + if (Global::get().layer) { + layer = typeinfo_cast(Global::get().layer); + } else { + auto children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); + + for (auto child : CCArrayExt(children)) { if (typeinfo_cast(child)) { - layer = typeinfo_cast*>(child); + layer = typeinfo_cast(child); break; } } } - + if (!layer) { onClose(nullptr); return; } - + LoadMacroLayer::open(layer, this, false); } + void MacroEditLayer::mergeMacro(std::vector mergeInputs, bool players[2], bool overwrite) { if (mergeInputs.empty()) return; - + std::vector actualInputs; int endFrame[2] = {0, 0}; - + for (input inp : mergeInputs) { if (players[static_cast(inp.player2)]) - actualInputs.push_back(inp); + actualInputs.push_back(inp); } - + for (int i = 0; i < 2; i++) { for (int j = mergeInputs.size() - 1; j >= 0; j--) { if (!players[i]) break; @@ -995,10 +998,10 @@ void MacroEditLayer::mergeMacro(std::vector mergeInputs, bool players[2], break; } } - + if (overwrite) { int startFrame[2] = {0, 0}; - + for (int i = 0; i < 2; i++) { for (input inp : mergeInputs) { if (!players[i]) break; @@ -1007,38 +1010,38 @@ void MacroEditLayer::mergeMacro(std::vector mergeInputs, bool players[2], break; } } - + auto condition = [startFrame, endFrame, players](const input& element) { int p = static_cast(element.player2); return element.frame >= startFrame[p] && element.frame <= endFrame[p] && players[p]; }; - + auto newEnd = std::remove_if(inputs.begin(), inputs.end(), condition); - + inputs.erase(newEnd, inputs.end()); } - + std::vector mergedVector; mergedVector.resize(inputs.size() + actualInputs.size()); std::merge(actualInputs.begin(), actualInputs.end(), inputs.begin(), inputs.end(), mergedVector.begin()); - + inputs = mergedVector; - + for (int j = inputs.size() - 1; j >= 0; j--) { if (inputs[j].frame >= endFrame[0]) continue; - + int co = j / 6; int newPage = co + 1; int newSelected = j - co * 6; - + loadPage(newPage); - + selectedInput = -1; hoveredInput = -2; selectInput(newSelected + (newSelected < 5 ? 1 : 0)); - + break; } - + updateSaved(); } \ No newline at end of file diff --git a/src/ui/macro_editor.hpp b/src/ui/macro_editor.hpp index 2eb02b03..e25c7639 100644 --- a/src/ui/macro_editor.hpp +++ b/src/ui/macro_editor.hpp @@ -11,11 +11,11 @@ struct InputText { std::string action; }; -class MacroEditLayer : public geode::Popup<>, public TextInputDelegate { +class MacroEditLayer : public geode::Popup, public TextInputDelegate { private: - bool setup(); + bool init() override; void onClose(CCObject*) override; @@ -29,7 +29,7 @@ class MacroEditLayer : public geode::Popup<>, public TextInputDelegate { public: - STATIC_CREATE(MacroEditLayer, 438, 247) + STATIC_CREATE(MacroEditLayer) TextInput* pageInput = nullptr; TextInput* frameInput = nullptr; diff --git a/src/ui/macro_info_layer.hpp b/src/ui/macro_info_layer.hpp index 3cab9919..40087bf0 100644 --- a/src/ui/macro_info_layer.hpp +++ b/src/ui/macro_info_layer.hpp @@ -2,13 +2,13 @@ #include "../includes.hpp" #include -class MacroInfoLayer : public geode::Popup<> { +class MacroInfoLayer : public geode::Popup { public: static MacroInfoLayer* create() { MacroInfoLayer* ret = new MacroInfoLayer(); - if (ret->initAnchored(417, 268, "square01_001.png", CCRectZero)) { + if (ret->init()) { ret->autorelease(); return ret; } @@ -18,7 +18,8 @@ class MacroInfoLayer : public geode::Popup<> { private: - bool setup() override { + bool init() { + if (!Popup::init(417, 268, "square01_001.png", CCRectZero)) return false; setTitle("Current Macro"); auto& g = Global::get(); diff --git a/src/ui/mirror_settings_layer.hpp b/src/ui/mirror_settings_layer.hpp index a84fcfb2..c5d32c12 100644 --- a/src/ui/mirror_settings_layer.hpp +++ b/src/ui/mirror_settings_layer.hpp @@ -1,11 +1,12 @@ #include "../includes.hpp" #include "record_layer.hpp" -class MirrorSettingsLayer : public geode::Popup<> { +class MirrorSettingsLayer : public geode::Popup { private: - bool setup() override { + bool init() { + if (!Popup::init(200, 146)) return false; setTitle("Input Mirror"); cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; @@ -38,7 +39,7 @@ class MirrorSettingsLayer : public geode::Popup<> { public: - STATIC_CREATE(MirrorSettingsLayer, 200, 146) + STATIC_CREATE(MirrorSettingsLayer) void open(CCObject*) { create()->show(); diff --git a/src/ui/noclip_settings_layer.hpp b/src/ui/noclip_settings_layer.hpp index 1f7ff7d4..ae768fba 100644 --- a/src/ui/noclip_settings_layer.hpp +++ b/src/ui/noclip_settings_layer.hpp @@ -1,10 +1,11 @@ #include "../includes.hpp" -class NoclipSettingsLayer : public geode::Popup<> { +class NoclipSettingsLayer : public geode::Popup { private: - bool setup() override { + bool init() { + if (!Popup::init(200, 176)) return false; setTitle("Noclip"); cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; @@ -49,7 +50,7 @@ class NoclipSettingsLayer : public geode::Popup<> { public: - STATIC_CREATE(NoclipSettingsLayer, 200, 176) + STATIC_CREATE(NoclipSettingsLayer) void open(CCObject*) { create()->show(); diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index f6ea1d69..ae8619e6 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -99,7 +99,7 @@ class $modify(PauseLayer) { }; $execute{ - geode::listenForSettingChanges("frame_offset", +[](int64_t value) { + geode::listenForSettingChanges("frame_offset", +[](int64_t value) { auto& g = Global::get(); g.frameOffset = value; @@ -111,7 +111,7 @@ class $modify(PauseLayer) { }); - geode::listenForSettingChanges("background_color", +[](cocos2d::ccColor3B value) { + geode::listenForSettingChanges("background_color", +[](cocos2d::ccColor3B value) { auto& g = Global::get(); if (g.layer) { CCArray* children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); @@ -129,7 +129,7 @@ void RecordLayer::openSaveMacro(CCObject*) { } void RecordLayer::openLoadMacro(CCObject*) { - LoadMacroLayer::open(static_cast*>(this), nullptr); + LoadMacroLayer::open(static_cast(this), nullptr); } RecordLayer* RecordLayer::openMenu(bool instant) { @@ -159,7 +159,7 @@ RecordLayer* RecordLayer::openMenu(bool instant) { layer->m_noElasticity = instant || Global::get().speedhackEnabled; layer->show(); - g.layer = static_cast*>(layer); + g.layer = static_cast(layer); return layer; } @@ -259,19 +259,19 @@ void RecordLayer::togglePlaying(CCObject*) { this->updateTPS(); } -#ifndef GEODE_IS_IOS -void RecordLayer::toggleRender(CCObject* btn) { +// #ifndef GEODE_IS_IOS +/*void RecordLayer::toggleRender(CCObject* btn) { if (!Renderer::toggle()) static_cast(btn)->toggle(true); if (Global::get().renderer.recordingAudio) static_cast(btn)->toggle(false); -} -#else +}*/ +// #else void RecordLayer::toggleRenderIOS(CCObject* btn) { - FLAlertLayer::create("Info", "Rendering on iOS is not supported yet!", "OK")->show(); + FLAlertLayer::create("Info", "Rendering is not supported yet!", "OK")->show(); } -#endif +// #endif void RecordLayer::onEditMacro(CCObject*) { MacroEditLayer::open(); @@ -522,7 +522,7 @@ void RecordLayer::onAutosaves(CCObject*) { std::filesystem::path path = Mod::get()->getSettingValue("autosaves_folder"); if (std::filesystem::exists(path)) - LoadMacroLayer::open(static_cast*>(this), nullptr, true); + LoadMacroLayer::open(static_cast(this), nullptr, true); else { FLAlertLayer::create("Error", "There was an error getting the folder. ID: 5", "Ok")->show(); } @@ -545,7 +545,8 @@ void RecordLayer::updateDots() { } } -bool RecordLayer::setup() { +bool RecordLayer::init() { + if (!Popup::init(455, 271)) return false; auto& g = Global::get(); mod = g.mod; @@ -933,17 +934,17 @@ bool RecordLayer::setup() { spriteOff2->setScale(0.74f); #endif - #ifdef GEODE_IS_IOS + //#ifdef GEODE_IS_IOS renderToggle = CCMenuItemToggler::create(spriteOn2, spriteOff2, this, menu_selector(RecordLayer::toggleRenderIOS)); renderToggle->setPosition(ccp(-65.5, -100)); menu->addChild(renderToggle); - #else - renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRender)); - renderToggle->toggle(g.renderer.recording || g.renderer.recordingAudio); + // #else + // renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRender)); + // renderToggle->toggle(g.renderer.recording || g.renderer.recordingAudio); renderToggle->setPosition(ccp(-65.5, -100)); menu->addChild(renderToggle); - #endif + // #endif spr = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png"); spr->setScale(0.65f); diff --git a/src/ui/record_layer.hpp b/src/ui/record_layer.hpp index 271c4b61..29e899b8 100644 --- a/src/ui/record_layer.hpp +++ b/src/ui/record_layer.hpp @@ -31,7 +31,7 @@ const float ySettingPositions[6]{ 76.5f, 47.5f, 18.5f, -11.5f, -40.5f, -69.5f }; -class RecordLayer : public geode::Popup<>, public TextInputDelegate { +class RecordLayer : public geode::Popup, public TextInputDelegate { public: CCMenuItemToggler* recording = nullptr; CCMenuItemToggler* playing = nullptr; @@ -73,7 +73,7 @@ class RecordLayer : public geode::Popup<>, public TextInputDelegate { protected: - bool setup() override; + bool init() override; ~RecordLayer() override { DESELECT_INPUT(widthInput) @@ -93,7 +93,7 @@ class RecordLayer : public geode::Popup<>, public TextInputDelegate { static std::string getTPSString(); - STATIC_CREATE(RecordLayer, 455, 271) + STATIC_CREATE(RecordLayer) virtual void onClose(cocos2d::CCObject*) override; diff --git a/src/ui/render_presets_layer.hpp b/src/ui/render_presets_layer.hpp index 63b910f5..053a8365 100644 --- a/src/ui/render_presets_layer.hpp +++ b/src/ui/render_presets_layer.hpp @@ -1,15 +1,16 @@ #include "../includes.hpp" #include "record_layer.hpp" -class RenderPresetsLayer : public geode::Popup<> { +class RenderPresetsLayer : public geode::Popup { public: - STATIC_CREATE(RenderPresetsLayer, 243, 231) + STATIC_CREATE(RenderPresetsLayer) private: - bool setup() override { + bool init() override { + if (!Popup::init(243, 231)) return false; setTitle("Render Presets"); CCScale9Sprite* bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index e6efd410..ea8d7043 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -11,15 +11,15 @@ class $modify(SliderTouchLogic) { }; void RenderSettingsLayer::textChanged(CCTextInputNode* node) { - + if (secondsInput->getString() != "" && node == secondsInput) { std::string value = secondsInput->getString(); if (value == ".") - secondsInput->setString("0."); + secondsInput->setString("0."); else if (std::count(value.begin(), value.end(), '.') == 2) - return secondsInput->setString(mod->getSavedValue("render_seconds_after").c_str()); + return secondsInput->setString(mod->getSavedValue("render_seconds_after").c_str()); } - + std::string secondsAfter = secondsInput->getString(); std::string args = argsInput->getString(); std::string audioArgs = audioArgsInput->getString(); @@ -27,7 +27,7 @@ void RenderSettingsLayer::textChanged(CCTextInputNode* node) { std::string fadeIn = fadeInInput->getString(); std::string fadeOut = fadeOutInput->getString(); std::string extension = extensionInput->getString(); - + mod->setSavedValue("render_seconds_after", secondsAfter); mod->setSavedValue("render_args", args); mod->setSavedValue("render_audio_args", audioArgs); @@ -38,7 +38,7 @@ void RenderSettingsLayer::textChanged(CCTextInputNode* node) { } void RenderSettingsLayer::onDefaults(CCObject*) { - geode::createQuickPopup( + geode::createQuickPopup( "Restore", "Restore default render settings?", "Cancel", "Yes", @@ -46,7 +46,7 @@ void RenderSettingsLayer::onDefaults(CCObject*) { auto& g = Global::get(); g.mod->setSavedValue("render_args", std::string("-pix_fmt yuv420p")); - g.mod->setSavedValue("render_audio_args", std::string("")); + g.mod->setSavedValue("render_audio_args", std::string("")); #ifdef GEODE_IS_WINDOWS g.mod->setSavedValue("render_video_args", std::string("colorspace=all=bt709:iall=bt470bg:fast=1")); #else @@ -63,16 +63,15 @@ void RenderSettingsLayer::onDefaults(CCObject*) { g.mod->setSavedValue("render_fade_out_time", std::to_string(2)); g.mod->setSavedValue("render_hide_endscreen", false); g.mod->setSavedValue("render_hide_levelcomplete", false); - - CCArray* children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); - CCObject* child; - CCARRAY_FOREACH(children, child) { - if (RecordLayer* layer = typeinfo_cast(child)) { + + auto children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); + for (auto obj : CCArrayExt(children)) { + if (auto layer = typeinfo_cast(obj)) { layer->onClose(nullptr); break; } } - + this->keyBackClicked(); RecordLayer::openMenu(true); RenderSettingsLayer* layer = create(); @@ -82,13 +81,14 @@ void RenderSettingsLayer::onDefaults(CCObject*) { ); } -bool RenderSettingsLayer::setup() { +bool RenderSettingsLayer::init() { + if (!Popup::init(396, 277)) return false; setTitle("Render Settings"); bool usingApi = false; -#ifndef GEODE_IS_IOS - usingApi = Renderer::shouldUseAPI(); -#endif - + // #ifndef GEODE_IS_IOS + // usingApi = Renderer::shouldUseAPI(); + // #endif + cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; m_mainLayer->setPosition(m_mainLayer->getPosition() - offset); m_closeBtn->setPosition(m_closeBtn->getPosition() + offset); @@ -98,16 +98,16 @@ bool RenderSettingsLayer::setup() { mod = Mod::get(); Utils::setBackgroundColor(m_bgSprite); - + if (mod->getSavedValue("render_seconds_after") == "") - mod->setSavedValue("render_seconds_after", std::to_string(0)); - + mod->setSavedValue("render_seconds_after", std::to_string(0)); + cocos2d::CCSize center = cocos2d::CCDirector::sharedDirector()->getWinSize() / 2; - + CCMenu* menu = CCMenu::create(); m_mainLayer->addChild(menu); menu->setPositionX(menu->getPositionX() - 67); - + CCScale9Sprite* bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); bg->setScale(0.355f); bg->setColor({ 0,0,0 }); @@ -116,22 +116,22 @@ bool RenderSettingsLayer::setup() { bg->setAnchorPoint({ 0, 1 }); bg->setContentSize({ 392, 55 }); menu->addChild(bg); - + #ifndef GEODE_IS_IOS if (usingApi) bg->setOpacity(40); #endif - + CCLabelBMFont* lbl = CCLabelBMFont::create("Extra Args:", "bigFont.fnt"); lbl->setPosition(ccp(-105, 88)); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setOpacity(200); lbl->setScale(0.325); menu->addChild(lbl); - + #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); #endif - + argsInput = CCTextInputNode::create(150, 30, "args", "chatFont.fnt"); argsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); argsInput->ignoreAnchorPointForPosition(true); @@ -147,7 +147,7 @@ bool RenderSettingsLayer::setup() { argsInput->setDelegate(this); argsInput->setAllowedChars(" 0123456789abcdefghijklmnopqrstuvwxyz-_:;.\"\\/[](){}+=<>|!*&'%@"); menu->addChild(argsInput); - + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); bg->setScale(0.355f); bg->setColor({ 0,0,0 }); @@ -160,7 +160,7 @@ bool RenderSettingsLayer::setup() { #ifndef GEODE_IS_IOS if (usingApi) bg->setOpacity(40); #endif - + lbl = CCLabelBMFont::create("Audio Args:", "bigFont.fnt"); lbl->setPosition(ccp(-105, 55)); lbl->setAnchorPoint({ 0, 0.5 }); @@ -171,7 +171,7 @@ bool RenderSettingsLayer::setup() { #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); #endif - + audioArgsInput = CCTextInputNode::create(150, 30, "audio args", "chatFont.fnt"); audioArgsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); audioArgsInput->ignoreAnchorPointForPosition(true); @@ -187,7 +187,7 @@ bool RenderSettingsLayer::setup() { audioArgsInput->setDelegate(this); audioArgsInput->setAllowedChars(" 0123456789abcdefghijklmnopqrstuvwxyz-_:;.\"\\/[](){}+=<>|!*&'%@"); menu->addChild(audioArgsInput); - + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); bg->setScale(0.375f); bg->setColor({ 0,0,0 }); @@ -196,7 +196,7 @@ bool RenderSettingsLayer::setup() { bg->setAnchorPoint({ 0, 1 }); bg->setContentSize({ 82, 55 }); menu->addChild(bg); - + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); bg->setScale(0.355f); bg->setColor({ 0,0,0 }); @@ -205,7 +205,7 @@ bool RenderSettingsLayer::setup() { bg->setAnchorPoint({ 0, 1 }); bg->setContentSize({ 395, 55 }); menu->addChild(bg); - + videoArgsInput = CCTextInputNode::create(150, 30, "video args", "chatFont.fnt"); videoArgsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); videoArgsInput->ignoreAnchorPointForPosition(true); @@ -221,21 +221,21 @@ bool RenderSettingsLayer::setup() { videoArgsInput->setAllowedChars(" 0123456789abcdefghijklmnopqrstuvwxyz-_:;.\"\\/[](){}+=<>|!*&'%@"); videoArgsInput->setDelegate(this); menu->addChild(videoArgsInput); - + lbl = CCLabelBMFont::create("Video Args:", "bigFont.fnt"); lbl->setAnchorPoint({0, 0.5}); lbl->setOpacity(200); lbl->setScale(0.325f); lbl->setPosition({-105, 24}); menu->addChild(lbl); - + lbl = CCLabelBMFont::create("Render after completion:", "bigFont.fnt"); lbl->setPosition(ccp(-105, -5)); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setOpacity(200); lbl->setScale(0.325); menu->addChild(lbl); - + secondsInput = CCTextInputNode::create(150, 30, "sec", "chatFont.fnt"); secondsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); secondsInput->ignoreAnchorPointForPosition(true); @@ -252,13 +252,13 @@ bool RenderSettingsLayer::setup() { secondsInput->setMaxLabelLength(2); secondsInput->setAllowedChars("0123456789."); menu->addChild(secondsInput); - + lbl = CCLabelBMFont::create("s", "chatFont.fnt"); lbl->setPosition(ccp(84, -5)); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.825); menu->addChild(lbl); - + lbl = CCLabelBMFont::create("Legacy Audio:", "bigFont.fnt"); lbl->setPosition(ccp(-105, -32)); lbl->setAnchorPoint({ 0, 0.5 }); @@ -269,294 +269,295 @@ bool RenderSettingsLayer::setup() { #ifndef GEODE_IS_IOS if (usingApi) lbl->setOpacity(90); #endif - - onlySongToggle = CCMenuItemToggler::create( - CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), - CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"), - this, menu_selector(RecordLayer::toggleSetting)); - onlySongToggle->setPosition(ccp(0, -32)); - onlySongToggle->setScale(0.555); - #ifndef GEODE_IS_IOS - if (!usingApi) onlySongToggle->toggle(mod->getSavedValue("render_only_song")); - #endif - onlySongToggle->setID("render_only_song"); - menu->addChild(onlySongToggle); - - lbl = CCLabelBMFont::create("Record Audio:", "bigFont.fnt"); - lbl->setPosition(ccp(-105, -58)); - lbl->setAnchorPoint({ 0, 0.5 }); - lbl->setOpacity(200); - lbl->setScale(0.325); - menu->addChild(lbl); - - #ifndef GEODE_IS_IOS - if (usingApi) lbl->setOpacity(90); - #endif - - recordAudioToggle = CCMenuItemToggler::create( - CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), - CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"), - this, menu_selector(RecordLayer::toggleSetting)); - recordAudioToggle->setPosition(ccp(0, -58)); - recordAudioToggle->setScale(0.555); - #ifndef GEODE_IS_IOS - if (!usingApi) recordAudioToggle->toggle(mod->getSavedValue("render_record_audio")); - #endif - recordAudioToggle->setID("render_record_audio"); - menu->addChild(recordAudioToggle); - - lbl = CCLabelBMFont::create("Fade In:", "bigFont.fnt"); - lbl->setPosition(ccp(25, -32)); - lbl->setAnchorPoint({ 0, 0.5 }); - lbl->setOpacity(200); - lbl->setScale(0.325); - menu->addChild(lbl); - - #ifndef GEODE_IS_IOS - if (usingApi) lbl->setOpacity(90); - #endif - - fadeInInput = TextInput::create(50.f, "s", "bigFont.fnt"); - fadeInInput->setScale(0.5f); - fadeInInput->setPosition(ccp(100, -32)); - fadeInInput->setString(Mod::get()->getSavedValue("render_fade_in_time").c_str()); - fadeInInput->getInputNode()->setDelegate(this); - fadeInInput->getInputNode()->setAllowedChars("0123456789."); - menu->addChild(fadeInInput); - CCMenuItemToggler* toggle = CCMenuItemToggler::create( - CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), - CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"), - this, menu_selector(RecordLayer::toggleSetting)); - toggle->setPosition(ccp(130, -32)); - toggle->setScale(0.555); - #ifndef GEODE_IS_IOS - if (!usingApi) toggle->toggle(mod->getSavedValue("render_fade_in")); - #endif - toggle->setID("render_fade_in"); - menu->addChild(toggle); - - #ifndef GEODE_IS_IOS - if (usingApi) { - toggle->setCascadeOpacityEnabled(true); - toggle->setEnabled(false); - toggle->setOpacity(100); - } - #endif - - lbl = CCLabelBMFont::create("Fade Out:", "bigFont.fnt"); - lbl->setPosition(ccp(25, -58)); - lbl->setAnchorPoint({ 0, 0.5 }); - lbl->setOpacity(200); - lbl->setScale(0.325); - menu->addChild(lbl); - - #ifndef GEODE_IS_IOS - if (usingApi) lbl->setOpacity(90); - #endif - - lbl = CCLabelBMFont::create("File Extension:", "bigFont.fnt"); - lbl->setPosition(ccp(110, -5)); - lbl->setAnchorPoint({ 0, 0.5 }); - lbl->setOpacity(200); - lbl->setScale(0.3f); - menu->addChild(lbl); - - #ifndef GEODE_IS_IOS - if (usingApi) lbl->setOpacity(90); - #endif - - extensionInput = TextInput::create(46.f, "", "chatFont.fnt"); - extensionInput->setScale(0.8f); - extensionInput->setPosition(ccp(209, -5)); - extensionInput->setString(Mod::get()->getSavedValue("render_file_extension").c_str()); - extensionInput->getInputNode()->setDelegate(this); - extensionInput->getInputNode()->setAllowedChars("abcdefghijklmnñopqrstuvwxyz0123456789."); - menu->addChild(extensionInput); - - fadeOutInput = TextInput::create(50.f, "s", "bigFont.fnt"); - fadeOutInput->setScale(0.5f); - fadeOutInput->setPosition(ccp(100, -58)); - fadeOutInput->setString(Mod::get()->getSavedValue("render_fade_out_time").c_str()); - fadeOutInput->getInputNode()->setDelegate(this); - fadeOutInput->getInputNode()->setAllowedChars("0123456789."); - menu->addChild(fadeOutInput); - - toggle = CCMenuItemToggler::create( - CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), - CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"), - this, menu_selector(RecordLayer::toggleSetting)); - toggle->setPosition(ccp(130, -58)); - toggle->setScale(0.555); - #ifndef GEODE_IS_IOS - if (!usingApi) toggle->toggle(mod->getSavedValue("render_fade_out")); - #endif - toggle->setID("render_fade_out"); - menu->addChild(toggle); - - #ifndef GEODE_IS_IOS - if (usingApi) { - toggle->setCascadeOpacityEnabled(true); - toggle->setEnabled(false); - toggle->setOpacity(100); - } - #endif - - lbl = CCLabelBMFont::create("Hide Endscreen:", "bigFont.fnt"); - lbl->setPosition(ccp(-105, -83)); - lbl->setAnchorPoint({ 0, 0.5 }); - lbl->setOpacity(200); - lbl->setScale(0.325); - menu->addChild(lbl); - - toggle = CCMenuItemToggler::create( - CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), - CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"), - this, menu_selector(RecordLayer::toggleSetting)); - toggle->setPosition(ccp(0, -83)); - toggle->setScale(0.555); - toggle->toggle(mod->getSavedValue("render_hide_endscreen")); - toggle->setID("render_hide_endscreen"); - menu->addChild(toggle); - - lbl = CCLabelBMFont::create("Hide Level Complete:", "bigFont.fnt"); - lbl->setPosition(ccp(-105, -108)); - lbl->setAnchorPoint({ 0, 0.5 }); - lbl->setOpacity(200); - lbl->setScale(0.25); - menu->addChild(lbl); - - toggle = CCMenuItemToggler::create( + onlySongToggle = CCMenuItemToggler::create( CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"), this, menu_selector(RecordLayer::toggleSetting)); - toggle->setPosition(ccp(0, -108)); - toggle->setScale(0.555); - toggle->toggle(mod->getSavedValue("render_hide_levelcomplete")); - toggle->setID("render_hide_levelcomplete"); - menu->addChild(toggle); - - lbl = CCLabelBMFont::create("SFX Volume", "goldFont.fnt"); - lbl->setScale(0.475f); - lbl->setPosition({188, 42}); - menu->addChild(lbl); - - #ifndef GEODE_IS_IOS - if (usingApi) lbl->setOpacity(90); - #endif - - sfxSlider = Slider::create( - this, - menu_selector(RenderSettingsLayer::onSlider), - 1.f - ); - sfxSlider->setPosition({188, 24}); - sfxSlider->setAnchorPoint({ 0.f, 0.f }); - sfxSlider->setScale(0.545f); - sfxSlider->setValue(Mod::get()->getSavedValue("render_sfx_volume")); - menu->addChild(sfxSlider); - - lbl = CCLabelBMFont::create("Music Volume", "goldFont.fnt"); - lbl->setScale(0.475f); - lbl->setPosition({188, 87}); - menu->addChild(lbl); - - #ifndef GEODE_IS_IOS - if (usingApi) lbl->setOpacity(90); - #endif - - musicSlider = Slider::create( - this, - menu_selector(RenderSettingsLayer::onSlider), - 1.f - ); - musicSlider->setPosition({188, 69}); - musicSlider->setAnchorPoint({ 0.f, 0.f }); - musicSlider->setScale(0.545f); - musicSlider->setValue(Mod::get()->getSavedValue("render_music_volume")); - menu->addChild(musicSlider); - - ButtonSprite* spr = ButtonSprite::create("Ok"); - spr->setScale(0.875); - CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(RenderSettingsLayer::close)); - btn->setPosition(ccp(67, -100)); - menu->addChild(btn); - - spr = ButtonSprite::create("Restore Defaults"); - spr->setScale(0.375f); - btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(RenderSettingsLayer::onDefaults)); - btn->setPosition({211, -123}); - menu->addChild(btn); - - CCSprite* spr2 = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png"); - spr2->setScale(0.33f); - btn = CCMenuItemSpriteExtra::create(spr2, this, menu_selector(RenderSettingsLayer::showInfoPopup)); - btn->setPosition({13, -22}); - btn->setTag(1); - menu->addChild(btn); - - spr2 = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png"); - spr2->setScale(0.33f); - btn = CCMenuItemSpriteExtra::create(spr2, this, menu_selector(RenderSettingsLayer::showInfoPopup)); - btn->setPosition({13, -48}); - btn->setTag(0); - menu->addChild(btn); - - #ifndef GEODE_IS_IOS - if (usingApi) { - argsInput->m_textLabel->setOpacity(100); - audioArgsInput->m_textLabel->setOpacity(100); - - argsInput->setID("disabled-input"_spr); - audioArgsInput->setID("disabled-input"_spr); - - extensionInput->setEnabled(false); - extensionInput->getInputNode()->m_textLabel->setOpacity(100); - extensionInput->getBGSprite()->setOpacity(40); - - fadeOutInput->setEnabled(false); - fadeOutInput->getInputNode()->m_textLabel->setOpacity(100); - fadeOutInput->getBGSprite()->setOpacity(40); - - fadeInInput->setEnabled(false); - fadeInInput->getInputNode()->m_textLabel->setOpacity(100); - fadeInInput->getBGSprite()->setOpacity(40); - - onlySongToggle->setCascadeOpacityEnabled(true); - onlySongToggle->setEnabled(false); - recordAudioToggle->setCascadeOpacityEnabled(true); - recordAudioToggle->setEnabled(false); - - onlySongToggle->setOpacity(100); - recordAudioToggle->setOpacity(100); - - sfxSlider->setID("disabled-slider"_spr); - musicSlider->setID("disabled-slider"_spr); - - sfxSlider->m_sliderBar->setOpacity(100); - sfxSlider->m_groove->setOpacity(100); - sfxSlider->m_touchLogic->setOpacity(100); - musicSlider->m_sliderBar->setOpacity(100); - musicSlider->m_groove->setOpacity(100); - musicSlider->m_touchLogic->setOpacity(100); - } -#endif - - return true; -} - -void RenderSettingsLayer::onSlider(CCObject*) { - Mod::get()->setSavedValue("render_sfx_volume", sfxSlider->getValue()); - Mod::get()->setSavedValue("render_music_volume", musicSlider->getValue()); -} - -void RenderSettingsLayer::showInfoPopup(CCObject* obj) { - int tag = static_cast(obj)->getTag(); - std::string title = tag ? "Legacy Audio" : "Record Audio"; - std::string msg = tag ? "Adds only the original level song to the video, ignoring all song and SFX triggers." : "Records the game's audio in another attempt and adds it to the video. This ensures all song and SFX triggers are captured."; - FLAlertLayer::create( - title.c_str(), - msg.c_str(), - "Ok" - )->show(); -} + onlySongToggle->setPosition(ccp(0, -32)); + onlySongToggle->setScale(0.555); + #ifndef GEODE_IS_IOS + if (!usingApi) onlySongToggle->toggle(mod->getSavedValue("render_only_song")); + #endif + onlySongToggle->setID("render_only_song"); + menu->addChild(onlySongToggle); + + lbl = CCLabelBMFont::create("Record Audio:", "bigFont.fnt"); + lbl->setPosition(ccp(-105, -58)); + lbl->setAnchorPoint({ 0, 0.5 }); + lbl->setOpacity(200); + lbl->setScale(0.325); + menu->addChild(lbl); + + #ifndef GEODE_IS_IOS + if (usingApi) lbl->setOpacity(90); + #endif + + recordAudioToggle = CCMenuItemToggler::create( + CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), + CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"), + this, menu_selector(RecordLayer::toggleSetting)); + recordAudioToggle->setPosition(ccp(0, -58)); + recordAudioToggle->setScale(0.555); + #ifndef GEODE_IS_IOS + if (!usingApi) recordAudioToggle->toggle(mod->getSavedValue("render_record_audio")); + #endif + recordAudioToggle->setID("render_record_audio"); + menu->addChild(recordAudioToggle); + + lbl = CCLabelBMFont::create("Fade In:", "bigFont.fnt"); + lbl->setPosition(ccp(25, -32)); + lbl->setAnchorPoint({ 0, 0.5 }); + lbl->setOpacity(200); + lbl->setScale(0.325); + menu->addChild(lbl); + + #ifndef GEODE_IS_IOS + if (usingApi) lbl->setOpacity(90); + #endif + + fadeInInput = TextInput::create(50.f, "s", "bigFont.fnt"); + fadeInInput->setScale(0.5f); + fadeInInput->setPosition(ccp(100, -32)); + fadeInInput->setString(Mod::get()->getSavedValue("render_fade_in_time").c_str()); + fadeInInput->getInputNode()->setDelegate(this); + fadeInInput->getInputNode()->setAllowedChars("0123456789."); + menu->addChild(fadeInInput); + + CCMenuItemToggler* toggle = CCMenuItemToggler::create( + CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), + CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"), + this, menu_selector(RecordLayer::toggleSetting)); + toggle->setPosition(ccp(130, -32)); + toggle->setScale(0.555); + #ifndef GEODE_IS_IOS + if (!usingApi) toggle->toggle(mod->getSavedValue("render_fade_in")); + #endif + toggle->setID("render_fade_in"); + menu->addChild(toggle); + + #ifndef GEODE_IS_IOS + if (usingApi) { + toggle->setCascadeOpacityEnabled(true); + toggle->setEnabled(false); + toggle->setOpacity(100); + } + #endif + + lbl = CCLabelBMFont::create("Fade Out:", "bigFont.fnt"); + lbl->setPosition(ccp(25, -58)); + lbl->setAnchorPoint({ 0, 0.5 }); + lbl->setOpacity(200); + lbl->setScale(0.325); + menu->addChild(lbl); + + #ifndef GEODE_IS_IOS + if (usingApi) lbl->setOpacity(90); + #endif + + lbl = CCLabelBMFont::create("File Extension:", "bigFont.fnt"); + lbl->setPosition(ccp(110, -5)); + lbl->setAnchorPoint({ 0, 0.5 }); + lbl->setOpacity(200); + lbl->setScale(0.3f); + menu->addChild(lbl); + + #ifndef GEODE_IS_IOS + if (usingApi) lbl->setOpacity(90); + #endif + + extensionInput = TextInput::create(46.f, "", "chatFont.fnt"); + extensionInput->setScale(0.8f); + extensionInput->setPosition(ccp(209, -5)); + extensionInput->setString(Mod::get()->getSavedValue("render_file_extension").c_str()); + extensionInput->getInputNode()->setDelegate(this); + extensionInput->getInputNode()->setAllowedChars("abcdefghijklmnñopqrstuvwxyz0123456789."); + menu->addChild(extensionInput); + + fadeOutInput = TextInput::create(50.f, "s", "bigFont.fnt"); + fadeOutInput->setScale(0.5f); + fadeOutInput->setPosition(ccp(100, -58)); + fadeOutInput->setString(Mod::get()->getSavedValue("render_fade_out_time").c_str()); + fadeOutInput->getInputNode()->setDelegate(this); + fadeOutInput->getInputNode()->setAllowedChars("0123456789."); + menu->addChild(fadeOutInput); + + toggle = CCMenuItemToggler::create( + CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), + CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"), + this, menu_selector(RecordLayer::toggleSetting)); + toggle->setPosition(ccp(130, -58)); + toggle->setScale(0.555); + #ifndef GEODE_IS_IOS + if (!usingApi) toggle->toggle(mod->getSavedValue("render_fade_out")); + #endif + toggle->setID("render_fade_out"); + menu->addChild(toggle); + + #ifndef GEODE_IS_IOS + if (usingApi) { + toggle->setCascadeOpacityEnabled(true); + toggle->setEnabled(false); + toggle->setOpacity(100); + } + #endif + + lbl = CCLabelBMFont::create("Hide Endscreen:", "bigFont.fnt"); + lbl->setPosition(ccp(-105, -83)); + lbl->setAnchorPoint({ 0, 0.5 }); + lbl->setOpacity(200); + lbl->setScale(0.325); + menu->addChild(lbl); + + toggle = CCMenuItemToggler::create( + CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), + CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"), + this, menu_selector(RecordLayer::toggleSetting)); + toggle->setPosition(ccp(0, -83)); + toggle->setScale(0.555); + toggle->toggle(mod->getSavedValue("render_hide_endscreen")); + toggle->setID("render_hide_endscreen"); + menu->addChild(toggle); + + lbl = CCLabelBMFont::create("Hide Level Complete:", "bigFont.fnt"); + lbl->setPosition(ccp(-105, -108)); + lbl->setAnchorPoint({ 0, 0.5 }); + lbl->setOpacity(200); + lbl->setScale(0.25); + menu->addChild(lbl); + + toggle = CCMenuItemToggler::create( + CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"), + CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"), + this, menu_selector(RecordLayer::toggleSetting)); + toggle->setPosition(ccp(0, -108)); + toggle->setScale(0.555); + toggle->toggle(mod->getSavedValue("render_hide_levelcomplete")); + toggle->setID("render_hide_levelcomplete"); + menu->addChild(toggle); + + lbl = CCLabelBMFont::create("SFX Volume", "goldFont.fnt"); + lbl->setScale(0.475f); + lbl->setPosition({188, 42}); + menu->addChild(lbl); + + #ifndef GEODE_IS_IOS + if (usingApi) lbl->setOpacity(90); + #endif + + sfxSlider = Slider::create( + this, + menu_selector(RenderSettingsLayer::onSlider), + 1.f + ); + sfxSlider->setPosition({188, 24}); + sfxSlider->setAnchorPoint({ 0.f, 0.f }); + sfxSlider->setScale(0.545f); + sfxSlider->setValue(Mod::get()->getSavedValue("render_sfx_volume")); + menu->addChild(sfxSlider); + + lbl = CCLabelBMFont::create("Music Volume", "goldFont.fnt"); + lbl->setScale(0.475f); + lbl->setPosition({188, 87}); + menu->addChild(lbl); + + #ifndef GEODE_IS_IOS + if (usingApi) lbl->setOpacity(90); + #endif + + musicSlider = Slider::create( + this, + menu_selector(RenderSettingsLayer::onSlider), + 1.f + ); + musicSlider->setPosition({188, 69}); + musicSlider->setAnchorPoint({ 0.f, 0.f }); + musicSlider->setScale(0.545f); + musicSlider->setValue(Mod::get()->getSavedValue("render_music_volume")); + menu->addChild(musicSlider); + + ButtonSprite* spr = ButtonSprite::create("Ok"); + spr->setScale(0.875); + CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(RenderSettingsLayer::close)); + btn->setPosition(ccp(67, -100)); + menu->addChild(btn); + + spr = ButtonSprite::create("Restore Defaults"); + spr->setScale(0.375f); + btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(RenderSettingsLayer::onDefaults)); + btn->setPosition({211, -123}); + menu->addChild(btn); + + CCSprite* spr2 = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png"); + spr2->setScale(0.33f); + btn = CCMenuItemSpriteExtra::create(spr2, this, menu_selector(RenderSettingsLayer::showInfoPopup)); + btn->setPosition({13, -22}); + btn->setTag(1); + menu->addChild(btn); + + spr2 = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png"); + spr2->setScale(0.33f); + btn = CCMenuItemSpriteExtra::create(spr2, this, menu_selector(RenderSettingsLayer::showInfoPopup)); + btn->setPosition({13, -48}); + btn->setTag(0); + menu->addChild(btn); + + #ifndef GEODE_IS_IOS + if (usingApi) { + argsInput->m_textLabel->setOpacity(100); + audioArgsInput->m_textLabel->setOpacity(100); + + argsInput->setID("disabled-input"_spr); + audioArgsInput->setID("disabled-input"_spr); + + extensionInput->setEnabled(false); + extensionInput->getInputNode()->m_textLabel->setOpacity(100); + extensionInput->getBGSprite()->setOpacity(40); + + fadeOutInput->setEnabled(false); + fadeOutInput->getInputNode()->m_textLabel->setOpacity(100); + fadeOutInput->getBGSprite()->setOpacity(40); + + fadeInInput->setEnabled(false); + fadeInInput->getInputNode()->m_textLabel->setOpacity(100); + fadeInInput->getBGSprite()->setOpacity(40); + + onlySongToggle->setCascadeOpacityEnabled(true); + onlySongToggle->setEnabled(false); + recordAudioToggle->setCascadeOpacityEnabled(true); + recordAudioToggle->setEnabled(false); + + onlySongToggle->setOpacity(100); + recordAudioToggle->setOpacity(100); + + sfxSlider->setID("disabled-slider"_spr); + musicSlider->setID("disabled-slider"_spr); + + sfxSlider->m_sliderBar->setOpacity(100); + sfxSlider->m_groove->setOpacity(100); + sfxSlider->m_touchLogic->setOpacity(100); + musicSlider->m_sliderBar->setOpacity(100); + musicSlider->m_groove->setOpacity(100); + musicSlider->m_touchLogic->setOpacity(100); + } + #endif + + return true; + } + + void RenderSettingsLayer::onSlider(CCObject*) { + Mod::get()->setSavedValue("render_sfx_volume", sfxSlider->getValue()); + Mod::get()->setSavedValue("render_music_volume", musicSlider->getValue()); + } + + void RenderSettingsLayer::showInfoPopup(CCObject* obj) { + int tag = static_cast(obj)->getTag(); + std::string title = tag ? "Legacy Audio" : "Record Audio"; + std::string msg = tag ? "Adds only the original level song to the video, ignoring all song and SFX triggers." : "Records the game's audio in another attempt and adds it to the video. This ensures all song and SFX triggers are captured."; + FLAlertLayer::create( + title.c_str(), + msg.c_str(), + "Ok" + )->show(); + } + \ No newline at end of file diff --git a/src/ui/render_settings_layer.hpp b/src/ui/render_settings_layer.hpp index 679b1955..89eb219b 100644 --- a/src/ui/render_settings_layer.hpp +++ b/src/ui/render_settings_layer.hpp @@ -2,7 +2,7 @@ #include "../includes.hpp" -class RenderSettingsLayer : public geode::Popup<>, public TextInputDelegate { +class RenderSettingsLayer : public geode::Popup, public TextInputDelegate { public: @@ -24,7 +24,7 @@ class RenderSettingsLayer : public geode::Popup<>, public TextInputDelegate { private: - bool setup() override; + bool init() override; public: @@ -35,7 +35,8 @@ class RenderSettingsLayer : public geode::Popup<>, public TextInputDelegate { DESELECT_INPUT(videoArgsInput) } - STATIC_CREATE(RenderSettingsLayer, 396, 277) + // STATIC_CREATE(RenderSettingsLayer, 396, 277) + STATIC_CREATE(RenderSettingsLayer) void open(CCObject*) { create()->show(); diff --git a/src/ui/save_macro_layer.hpp b/src/ui/save_macro_layer.hpp index d26c8152..47a9fd93 100644 --- a/src/ui/save_macro_layer.hpp +++ b/src/ui/save_macro_layer.hpp @@ -1,7 +1,7 @@ #pragma once #include "../includes.hpp" -class SaveMacroLayer : public geode::Popup<> { +class SaveMacroLayer : public geode::Popup { TextInput* authorInput = nullptr; TextInput* descInput = nullptr; @@ -11,7 +11,8 @@ class SaveMacroLayer : public geode::Popup<> { private: - bool setup() override { + bool init() override { + if (!Popup::init(285, 194)) return false; Utils::setBackgroundColor(m_bgSprite); setTitle("Save Macro"); @@ -70,7 +71,7 @@ class SaveMacroLayer : public geode::Popup<> { public: - STATIC_CREATE(SaveMacroLayer, 285, 194) + STATIC_CREATE(SaveMacroLayer) static void open() { if (Global::get().macro.inputs.empty()) diff --git a/src/ui/trajectory_settings_layer.hpp b/src/ui/trajectory_settings_layer.hpp index 644fb8e1..ab90f3a9 100644 --- a/src/ui/trajectory_settings_layer.hpp +++ b/src/ui/trajectory_settings_layer.hpp @@ -1,148 +1,153 @@ #include "../includes.hpp" #include "../hacks/show_trajectory.hpp" -class TrajectorySettingsLayer : public geode::Popup<>, public ColorPickPopupDelegate, public TextInputDelegate { - +class TrajectorySettingsLayer : public geode::Popup, public TextInputDelegate { + public: + STATIC_CREATE(TrajectorySettingsLayer) - STATIC_CREATE(TrajectorySettingsLayer, 250, 180) - - void open(CCObject*) { - create()->show(); - } + void open(CCObject*) { + create()->show(); + } private: + ColorChannelSprite* color1 = nullptr; + ColorChannelSprite* color2 = nullptr; - ColorChannelSprite* color1 = nullptr; - ColorChannelSprite* color2 = nullptr; + TextInput* input = nullptr; - TextInput* input = nullptr; - - bool setup() override { + bool init() override { + if (!Popup::init(250, 180)) return false; setTitle("Show Trajectory"); - Utils::setBackgroundColor(m_bgSprite); + Utils::setBackgroundColor(m_bgSprite); CCSprite* spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); CCSprite* spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); CCLabelBMFont* lbl = CCLabelBMFont::create("Both Sides", "bigFont.fnt"); - lbl->setPosition({m_size.width - 68, 77}); - lbl->setScale(0.35f); - m_mainLayer->addChild(lbl); + lbl->setPosition({m_size.width - 68, 77}); + lbl->setScale(0.35f); + m_mainLayer->addChild(lbl); CCMenuItemToggler* toggle = CCMenuItemToggler::create(spriteOff, spriteOn, this, menu_selector(TrajectorySettingsLayer::onToggle)); - toggle->setPosition({m_size.width - 68, 56}); - toggle->setScale(0.5f); - toggle->toggle(Mod::get()->getSavedValue("macro_trajectory_both_sides")); + toggle->setPosition({m_size.width - 68, 56}); + toggle->setScale(0.5f); + toggle->toggle(Mod::get()->getSavedValue("macro_trajectory_both_sides")); m_buttonMenu->addChild(toggle); lbl = CCLabelBMFont::create("Primary Color", "bigFont.fnt"); - lbl->setPosition({68, 126}); - lbl->setScale(0.35f); - m_mainLayer->addChild(lbl); + lbl->setPosition({68, 126}); + lbl->setScale(0.35f); + m_mainLayer->addChild(lbl); lbl = CCLabelBMFont::create("Secondary Color", "bigFont.fnt"); - lbl->setPosition({m_size.width - 68, 126}); - lbl->setScale(0.35f); - m_mainLayer->addChild(lbl); - - lbl = CCLabelBMFont::create("Trajectory Length", "bigFont.fnt"); - lbl->setPosition({68, 77}); - lbl->setScale(0.35f); - m_mainLayer->addChild(lbl); - - input = TextInput::create(50.f, "0"); - input->setPosition({68, 56}); - input->setScale(0.65f); - input->getInputNode()->setAllowedChars("0123456789"); - input->getInputNode()->setDelegate(this); - input->setString(Mod::get()->getSavedValue("trajectory_length").c_str()); - m_mainLayer->addChild(input); - - color1 = ColorChannelSprite::create(); - color1->setColor(ShowTrajectory::ccc3BFromccc4F(ShowTrajectory::get().color1)); - color1->setScale(0.5f); - - CCMenuItemSpriteExtra* colorButton = CCMenuItemSpriteExtra::create( - color1, - this, - menu_selector(TrajectorySettingsLayer::openColorPicker) - ); - colorButton->setPosition({68, 109}); - colorButton->setTag(1); - m_buttonMenu->addChild(colorButton); - - color2 = ColorChannelSprite::create(); - color2->setColor(ShowTrajectory::ccc3BFromccc4F(ShowTrajectory::get().color2)); - color2->setScale(0.5f); - - colorButton = CCMenuItemSpriteExtra::create( - color2, - this, - menu_selector(TrajectorySettingsLayer::openColorPicker) - ); - colorButton->setPosition({m_size.width - 68, 109}); - m_buttonMenu->addChild(colorButton); - - ButtonSprite* btnSpr = ButtonSprite::create("Ok"); - btnSpr->setScale(0.73f); - CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(btnSpr, this, menu_selector(TrajectorySettingsLayer::onClose)); - btn->setPosition({m_size.width / 2, 23}); - m_buttonMenu->addChild(btn); - - btnSpr = ButtonSprite::create("Restore"); - btnSpr->setScale(0.3f); - btn = CCMenuItemSpriteExtra::create(btnSpr, this, menu_selector(TrajectorySettingsLayer::onRestore)); - btn->setPosition({223, 14}); - m_buttonMenu->addChild(btn); - - return true; + lbl->setPosition({m_size.width - 68, 126}); + lbl->setScale(0.35f); + m_mainLayer->addChild(lbl); + + lbl = CCLabelBMFont::create("Trajectory Length", "bigFont.fnt"); + lbl->setPosition({68, 77}); + lbl->setScale(0.35f); + m_mainLayer->addChild(lbl); + + input = TextInput::create(50.f, "0"); + input->setPosition({68, 56}); + input->setScale(0.65f); + input->getInputNode()->setAllowedChars("0123456789"); + input->getInputNode()->setDelegate(this); + input->setString(Mod::get()->getSavedValue("trajectory_length").c_str()); + m_mainLayer->addChild(input); + + color1 = ColorChannelSprite::create(); + color1->setColor(ShowTrajectory::ccc3BFromccc4F(ShowTrajectory::get().color1)); + color1->setScale(0.5f); + + CCMenuItemSpriteExtra* colorButton = CCMenuItemSpriteExtra::create( + color1, + this, + menu_selector(TrajectorySettingsLayer::openColorPicker) + ); + colorButton->setPosition({68, 109}); + colorButton->setTag(1); + m_buttonMenu->addChild(colorButton); + + color2 = ColorChannelSprite::create(); + color2->setColor(ShowTrajectory::ccc3BFromccc4F(ShowTrajectory::get().color2)); + color2->setScale(0.5f); + + colorButton = CCMenuItemSpriteExtra::create( + color2, + this, + menu_selector(TrajectorySettingsLayer::openColorPicker) + ); + colorButton->setPosition({m_size.width - 68, 109}); + m_buttonMenu->addChild(colorButton); + + ButtonSprite* btnSpr = ButtonSprite::create("Ok"); + btnSpr->setScale(0.73f); + CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(btnSpr, this, menu_selector(TrajectorySettingsLayer::onClose)); + btn->setPosition({m_size.width / 2, 23}); + m_buttonMenu->addChild(btn); + + btnSpr = ButtonSprite::create("Restore"); + btnSpr->setScale(0.3f); + btn = CCMenuItemSpriteExtra::create(btnSpr, this, menu_selector(TrajectorySettingsLayer::onRestore)); + btn->setPosition({223, 14}); + m_buttonMenu->addChild(btn); + + return true; } - void onToggle(CCObject* obj) { - CCMenuItemToggler* toggle = static_cast(obj); + void onToggle(CCObject* obj) { + CCMenuItemToggler* toggle = static_cast(obj); + + Mod::get()->setSavedValue("macro_trajectory_both_sides", !toggle->isToggled()); + Global::get().trajectoryBothSides = !toggle->isToggled(); + } - Mod::get()->setSavedValue("macro_trajectory_both_sides", !toggle->isToggled()); - Global::get().trajectoryBothSides = !toggle->isToggled(); - } + void onRestore(CCObject*) { + color1->setColor(ccc3(74, 226, 85)); + color2->setColor(ccc3(130, 8, 8)); + input->setString("240"); - void onRestore(CCObject*) { - color1->setColor(ccc3(74, 226, 85)); - color2->setColor(ccc3(130, 8, 8)); - input->setString("240"); + textChanged(nullptr); + } - updateColor({}); - textChanged(nullptr); - } + // Corrected color conversion function + cocos2d::ccColor4F ccColor4FFromccColor4B(const cocos2d::ccColor4B& color) { + return cocos2d::ccColor4F( + color.r / 255.0f, + color.g / 255.0f, + color.b / 255.0f, + color.a / 255.0f + ); + } - void openColorPicker(CCObject* obj) { - ColorChannelSprite* color = static_cast(obj)->getTag() == 1 ? color1 : color2; - ColorPickPopup* popup = ColorPickPopup::create(color->getColor()); - popup->setColorTarget(color); - popup->setDelegate(this); - popup->show(); - } + void TrajectorySettingsLayer::openColorPicker(CCObject* obj) { + ColorChannelSprite* color = static_cast(obj)->getTag() == 1 ? color1 : color2; - void updateColor(const cocos2d::ccColor4B&) override { - ShowTrajectory& t = ShowTrajectory::get(); - t.color1 = ccc4FFromccc3B(color1->getColor()); - t.color2 = ccc4FFromccc3B(color2->getColor()); - t.updateMergedColor(); + ColorPickPopup* popup = ColorPickPopup::create(color->getColor()); + popup->setColorTarget(color); + popup->setCallback([this, color](const cocos2d::ccColor4B& newColor) { + color->setColor(ccc3(newColor.r, newColor.g, newColor.b)); + ShowTrajectory::get().color1 = ccColor4FFromccColor4B(newColor); + ShowTrajectory::get().updateMergedColor(); - Mod::get()->setSavedValue("trajectory_color1", ShowTrajectory::ccc3BFromccc4F(t.color1)); - Mod::get()->setSavedValue("trajectory_color2", ShowTrajectory::ccc3BFromccc4F(t.color2)); - } + Mod::get()->setSavedValue("trajectory_color1", ShowTrajectory::ccc3BFromccc4F(ccColor4FFromccColor4B(newColor))); + }); - void textChanged(CCTextInputNode*) override { - std::string str = input->getString(); - int length = geode::utils::numFromString(str).unwrapOr(0); + popup->show(); + } - if (length > 2560 || length < 1 || str.empty()) - return input->setString(Mod::get()->getSavedValue("trajectory_length").c_str()); + void textChanged(CCTextInputNode*) override { + std::string str = input->getString(); + int length = geode::utils::numFromString(str).unwrapOr(0); - ShowTrajectory::get().length = length; - Mod::get()->setSavedValue("trajectory_length", str); - } + if (length > 2560 || length < 1 || str.empty()) + return input->setString(Mod::get()->getSavedValue("trajectory_length").c_str()); -}; \ No newline at end of file + ShowTrajectory::get().length = length; + Mod::get()->setSavedValue("trajectory_length", str); + } +}; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index a0c2275b..1f8856eb 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -185,7 +185,7 @@ std::string Utils::getSimplifiedString(std::string str) { return str; } -void Utils::setBackgroundColor(cocos2d::extension::CCScale9Sprite* bg) { +void Utils::setBackgroundColor(geode::NineSlice* bg) { cocos2d::ccColor3B color = Mod::get()->getSettingValue("background_color"); if (color == ccc3(51, 68, 153)) diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp index 9f3ea75e..36feb33c 100644 --- a/src/utils/utils.hpp +++ b/src/utils/utils.hpp @@ -15,7 +15,7 @@ class Utils { static std::string getSimplifiedString(std::string str); - static void setBackgroundColor(cocos2d::extension::CCScale9Sprite* bg); + static void setBackgroundColor(geode::NineSlice* bg); static std::vector splitByChar(std::string str, char splitChar); From d23bc9832a361e0608f082bf8f5d94251492325e Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sat, 14 Feb 2026 00:45:15 +0300 Subject: [PATCH 057/211] geode v5 workflow --- .github/workflows/multi-platform-v5.yml | 64 +++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/multi-platform-v5.yml diff --git a/.github/workflows/multi-platform-v5.yml b/.github/workflows/multi-platform-v5.yml new file mode 100644 index 00000000..d3b04964 --- /dev/null +++ b/.github/workflows/multi-platform-v5.yml @@ -0,0 +1,64 @@ +name: Build Geode Mod (Geode v5) + +on: + workflow_dispatch: + push: + branches: + - "main" + +jobs: + build: + strategy: + fail-fast: false + matrix: + config: + - name: Windows + os: windows-latest + build-type: RelWithDebInfo + + - name: macOS + os: macos-latest + + - name: Android32 + os: ubuntu-latest + target: Android32 + + - name: Android64 + os: ubuntu-latest + target: Android64 + + - name: iOS + os: macos-latest + target: iOS + + name: ${{ matrix.config.name }} + runs-on: ${{ matrix.config.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Build the mod + uses: geode-sdk/build-geode-mod@main + with: + bindings: geode-sdk/bindings + build-config: ${{ matrix.config.build-type || 'Release' }} + export-pdb: true + bindings-ref: main + combine: true + sdk: nighlty + cli: nightly + target: ${{ matrix.config.target }} + + package: + name: Package builds + runs-on: ubuntu-latest + needs: ['build'] + + steps: + - uses: geode-sdk/build-geode-mod/combine@main + id: build + + - uses: actions/upload-artifact@v4 + with: + name: Build Output + path: ${{ steps.build.outputs.build-output }} From 2aef711498b79567a8e37a97643933846aa914c2 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sat, 14 Feb 2026 00:56:53 +0300 Subject: [PATCH 058/211] nice --- src/macro.cpp | 4 ++-- src/ui/load_macro_layer.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/macro.cpp b/src/macro.cpp index 803e54bf..1fd6f517 100644 --- a/src/macro.cpp +++ b/src/macro.cpp @@ -172,7 +172,7 @@ int Macro::save(std::string author, std::string desc, std::string path, bool jso if (widePath == L"Widen Error") return 30; - std::ofstream f(widePath, std::ios::binary); + std::ofstream f(std::filesystem::path(widePath), std::ios::binary); if (!f) f.open(path, std::ios::binary); @@ -216,7 +216,7 @@ Macro Macro::XDtoGDR(std::filesystem::path path) { newMacro.description = "N/A"; newMacro.gameVersion = GEODE_GD_VERSION; - std::ifstream file(Utils::widen(path.string())); + std::ifstream file(path, std::ios::binary); std::string line; if (!file.is_open()) { diff --git a/src/ui/load_macro_layer.cpp b/src/ui/load_macro_layer.cpp index 8e3cfd52..85e8630c 100644 --- a/src/ui/load_macro_layer.cpp +++ b/src/ui/load_macro_layer.cpp @@ -202,7 +202,7 @@ void LoadMacroLayer::onImportMacro(CCObject*) { pathString += ".gdr.json"; - std::ofstream f2(Utils::widen(pathString), std::ios::binary); + std::ofstream f2(std::filesystem::path(pathString), std::ios::binary); auto data = tempMacro.exportData(true); f2.write(reinterpret_cast(data.data()), data.size()); From 6393f92324c24a590206ccce95189eead29c3411 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sat, 14 Feb 2026 00:59:56 +0300 Subject: [PATCH 059/211] Update multi-platform-v5.yml --- .github/workflows/multi-platform-v5.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/multi-platform-v5.yml b/.github/workflows/multi-platform-v5.yml index d3b04964..14eb7a60 100644 --- a/.github/workflows/multi-platform-v5.yml +++ b/.github/workflows/multi-platform-v5.yml @@ -45,7 +45,7 @@ jobs: export-pdb: true bindings-ref: main combine: true - sdk: nighlty + sdk: nightly cli: nightly target: ${{ matrix.config.target }} From 42d54624d16b0fcc8ac4646c380aeba5e8dffbc1 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sat, 14 Feb 2026 01:05:49 +0300 Subject: [PATCH 060/211] change this LOL --- src/ui/trajectory_settings_layer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/trajectory_settings_layer.hpp b/src/ui/trajectory_settings_layer.hpp index ab90f3a9..128ec8ff 100644 --- a/src/ui/trajectory_settings_layer.hpp +++ b/src/ui/trajectory_settings_layer.hpp @@ -124,7 +124,7 @@ class TrajectorySettingsLayer : public geode::Popup, public TextInputDelegate { ); } - void TrajectorySettingsLayer::openColorPicker(CCObject* obj) { + void openColorPicker(CCObject* obj) { ColorChannelSprite* color = static_cast(obj)->getTag() == 1 ? color1 : color2; ColorPickPopup* popup = ColorPickPopup::create(color->getColor()); From ba7504b4758c54df7af12dbc20ca9d1b9974e620 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sat, 14 Feb 2026 01:10:38 +0300 Subject: [PATCH 061/211] can it compile now --- src/practice_fixes/player.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/practice_fixes/player.cpp b/src/practice_fixes/player.cpp index c589df3a..07f538fe 100644 --- a/src/practice_fixes/player.cpp +++ b/src/practice_fixes/player.cpp @@ -9,16 +9,16 @@ PlayerData PlayerPracticeFixes::saveData(PlayerObject* player) { // data.m_maybeRotatedObjectsMap.insert(player->m_maybeRotatedObjectsMap.begin(), player->m_maybeRotatedObjectsMap.end()); data.m_touchedRings.insert(player->m_touchedRings.begin(), player->m_touchedRings.end()); data.m_ringRelatedSet.insert(player->m_ringRelatedSet.begin(), player->m_ringRelatedSet.end()); - data.m_jumpPadRelated.insert(player->m_jumpPadRelated.begin(), player->m_jumpPadRelated.end()); - data.m_holdingButtons.insert(player->m_holdingButtons.begin(), player->m_holdingButtons.end()); + // data.m_jumpPadRelated.insert(player->m_jumpPadRelated.begin(), player->m_jumpPadRelated.end()); + // data.m_holdingButtons.insert(player->m_holdingButtons.begin(), player->m_holdingButtons.end()); for (const auto& el : player->m_playerFollowFloats) data.m_playerFollowFloats.push_back(el); #else - data.m_jumpPadRelated = player->m_jumpPadRelated; - data.m_holdingButtons = player->m_holdingButtons; + // data.m_jumpPadRelated = player->m_jumpPadRelated; + // data.m_holdingButtons = player->m_holdingButtons; #endif @@ -275,8 +275,8 @@ void PlayerPracticeFixes::applyData(PlayerObject* player, PlayerData data, bool // player->m_maybeRotatedObjectsMap.insert(data.m_maybeRotatedObjectsMap.begin(), data.m_maybeRotatedObjectsMap.end()); player->m_touchedRings.insert(data.m_touchedRings.begin(), data.m_touchedRings.end()); player->m_ringRelatedSet.insert(data.m_ringRelatedSet.begin(), data.m_ringRelatedSet.end()); - player->m_jumpPadRelated.insert(data.m_jumpPadRelated.begin(), data.m_jumpPadRelated.end()); - player->m_holdingButtons.insert(data.m_holdingButtons.begin(), data.m_holdingButtons.end()); + // player->m_jumpPadRelated.insert(data.m_jumpPadRelated.begin(), data.m_jumpPadRelated.end()); + // player->m_holdingButtons.insert(data.m_holdingButtons.begin(), data.m_holdingButtons.end()); player->m_playerFollowFloats.clear(); @@ -285,8 +285,8 @@ void PlayerPracticeFixes::applyData(PlayerObject* player, PlayerData data, bool #else - player->m_jumpPadRelated = data.m_jumpPadRelated; - player->m_holdingButtons = data.m_holdingButtons; + // player->m_jumpPadRelated = data.m_jumpPadRelated; + // player->m_holdingButtons = data.m_holdingButtons; #endif @@ -515,4 +515,4 @@ void PlayerPracticeFixes::applyData(PlayerObject* player, PlayerData data, bool player->setPosition(data.position); player->setRotation(data.rotation); -} \ No newline at end of file +} From 26b4722b3d899d2100e51f107e40af5050096abc Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sat, 14 Feb 2026 01:25:28 +0300 Subject: [PATCH 062/211] Update show_trajectory.cpp --- src/hacks/show_trajectory.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hacks/show_trajectory.cpp b/src/hacks/show_trajectory.cpp index 46dd89f2..70ae61b6 100644 --- a/src/hacks/show_trajectory.cpp +++ b/src/hacks/show_trajectory.cpp @@ -7,7 +7,6 @@ #include #include #include -#include ShowTrajectory& t = ShowTrajectory::get(); @@ -444,4 +443,4 @@ class $modify(EffectGameObject) { if (!t.creatingTrajectory) EffectGameObject::triggerObject(p0, p1, p2); } -}; \ No newline at end of file +}; From 5d9fe412acb0014e18d3d0d39054bda9db81f007 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sat, 14 Feb 2026 01:34:49 +0300 Subject: [PATCH 063/211] fix popups --- src/ui/autoclicker_settings_layer.hpp | 2 +- src/ui/autosave_settings_layer.hpp | 2 +- src/ui/button_edit_layer.cpp | 2 +- src/ui/clickbot_layer.cpp | 2 +- src/ui/macro_editor.cpp | 2 +- src/ui/mirror_settings_layer.hpp | 2 +- src/ui/noclip_settings_layer.hpp | 2 +- src/ui/record_layer.cpp | 2 +- src/ui/render_presets_layer.hpp | 2 +- src/ui/render_settings_layer.cpp | 2 +- src/ui/save_macro_layer.hpp | 2 +- src/ui/trajectory_settings_layer.hpp | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ui/autoclicker_settings_layer.hpp b/src/ui/autoclicker_settings_layer.hpp index f11493b0..2a160193 100644 --- a/src/ui/autoclicker_settings_layer.hpp +++ b/src/ui/autoclicker_settings_layer.hpp @@ -46,7 +46,7 @@ class AutoclickerLayer : public geode::Popup, public TextInputDelegate { } bool init() override { - if (!Popup::init(250, 240)) return false; + if (!Popup::init(250, 240, Utils::getTexture().c_str())) return false; setTitle("Autoclicker"); m_title->setScale(0.625f); m_title->setPositionY(224); diff --git a/src/ui/autosave_settings_layer.hpp b/src/ui/autosave_settings_layer.hpp index aa6dc936..f4c42082 100644 --- a/src/ui/autosave_settings_layer.hpp +++ b/src/ui/autosave_settings_layer.hpp @@ -22,7 +22,7 @@ class AutoSaveLayer : public geode::Popup, public TextInputDelegate { } bool init() override { - if (!Popup::init(250, 190)) return false; + if (!Popup::init(250, 190, Utils::getTexture().c_str())) return false; setTitle("AutoSave"); m_title->setScale(0.575f); m_title->setPositionY(171); diff --git a/src/ui/button_edit_layer.cpp b/src/ui/button_edit_layer.cpp index ae39a275..f45144dd 100644 --- a/src/ui/button_edit_layer.cpp +++ b/src/ui/button_edit_layer.cpp @@ -169,7 +169,7 @@ void ButtonEditLayer::updateOpacity(CCObject*) { } bool ButtonEditLayer::init() { - if (!Popup::init(200, 131)) return false; + if (!Popup::init(200, 131, Utils::getTexture().c_str())) return false; mod = Mod::get(); cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; diff --git a/src/ui/clickbot_layer.cpp b/src/ui/clickbot_layer.cpp index da7b940b..89a5bf6c 100644 --- a/src/ui/clickbot_layer.cpp +++ b/src/ui/clickbot_layer.cpp @@ -20,7 +20,7 @@ void ClickbotLayer::updateLabels() { } bool ClickbotLayer::init() { - if (!Popup::init(432, 250)) return false; + if (!Popup::init(432, 250, Utils::getTexture().c_str())) return false; setTitle("ClickBot"); m_title->setPositionY(m_title->getPositionY() + 5); diff --git a/src/ui/macro_editor.cpp b/src/ui/macro_editor.cpp index 56dde1a8..9380493c 100644 --- a/src/ui/macro_editor.cpp +++ b/src/ui/macro_editor.cpp @@ -114,7 +114,7 @@ void MacroEditLayer::updateHover(cocos2d::CCPoint pos) { } bool MacroEditLayer::init() { - if (!Popup::init(438, 247)) return false; + if (!Popup::init(438, 247, Utils::getTexture().c_str())) return false; Utils::setBackgroundColor(m_bgSprite); CCMenu* menu = CCMenu::create(); diff --git a/src/ui/mirror_settings_layer.hpp b/src/ui/mirror_settings_layer.hpp index c5d32c12..9dcfcb1c 100644 --- a/src/ui/mirror_settings_layer.hpp +++ b/src/ui/mirror_settings_layer.hpp @@ -6,7 +6,7 @@ class MirrorSettingsLayer : public geode::Popup { private: bool init() { - if (!Popup::init(200, 146)) return false; + if (!Popup::init(200, 146, Utils::getTexture().c_str())) return false; setTitle("Input Mirror"); cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; diff --git a/src/ui/noclip_settings_layer.hpp b/src/ui/noclip_settings_layer.hpp index ae768fba..b6c47aff 100644 --- a/src/ui/noclip_settings_layer.hpp +++ b/src/ui/noclip_settings_layer.hpp @@ -5,7 +5,7 @@ class NoclipSettingsLayer : public geode::Popup { private: bool init() { - if (!Popup::init(200, 176)) return false; + if (!Popup::init(200, 176, Utils::getTexture().c_str())) return false; setTitle("Noclip"); cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index ae8619e6..480da155 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -546,7 +546,7 @@ void RecordLayer::updateDots() { } bool RecordLayer::init() { - if (!Popup::init(455, 271)) return false; + if (!Popup::init(455, 271, Utils::getTexture().c_str())) return false; auto& g = Global::get(); mod = g.mod; diff --git a/src/ui/render_presets_layer.hpp b/src/ui/render_presets_layer.hpp index 053a8365..683865b3 100644 --- a/src/ui/render_presets_layer.hpp +++ b/src/ui/render_presets_layer.hpp @@ -10,7 +10,7 @@ class RenderPresetsLayer : public geode::Popup { private: bool init() override { - if (!Popup::init(243, 231)) return false; + if (!Popup::init(243, 231, Utils::getTexture().c_str())) return false; setTitle("Render Presets"); CCScale9Sprite* bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index ea8d7043..a644a680 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -82,7 +82,7 @@ void RenderSettingsLayer::onDefaults(CCObject*) { } bool RenderSettingsLayer::init() { - if (!Popup::init(396, 277)) return false; + if (!Popup::init(396, 277, Utils::getTexture().c_str())) return false; setTitle("Render Settings"); bool usingApi = false; // #ifndef GEODE_IS_IOS diff --git a/src/ui/save_macro_layer.hpp b/src/ui/save_macro_layer.hpp index 47a9fd93..cb6c6e60 100644 --- a/src/ui/save_macro_layer.hpp +++ b/src/ui/save_macro_layer.hpp @@ -12,7 +12,7 @@ class SaveMacroLayer : public geode::Popup { private: bool init() override { - if (!Popup::init(285, 194)) return false; + if (!Popup::init(285, 194, Utils::getTexture().c_str())) return false; Utils::setBackgroundColor(m_bgSprite); setTitle("Save Macro"); diff --git a/src/ui/trajectory_settings_layer.hpp b/src/ui/trajectory_settings_layer.hpp index 128ec8ff..6307e912 100644 --- a/src/ui/trajectory_settings_layer.hpp +++ b/src/ui/trajectory_settings_layer.hpp @@ -17,7 +17,7 @@ class TrajectorySettingsLayer : public geode::Popup, public TextInputDelegate { TextInput* input = nullptr; bool init() override { - if (!Popup::init(250, 180)) return false; + if (!Popup::init(250, 180, Utils::getTexture().c_str())) return false; setTitle("Show Trajectory"); Utils::setBackgroundColor(m_bgSprite); From e7f16f543555d3d462b18a245ff3aa43e4fbe76f Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:11:16 +0300 Subject: [PATCH 064/211] omg keybinds! --- mod.json | 71 +- src/keybinds.cpp | 385 +++---- src/ui/record_layer.cpp | 2372 +++++++++++++++++++-------------------- 3 files changed, 1402 insertions(+), 1426 deletions(-) diff --git a/mod.json b/mod.json index 32861513..82835296 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "5.0.0-alpha.2", + "geode": "5.0.0-beta.1", "gd": { "win": "2.2081", "mac": "2.2081", @@ -73,6 +73,69 @@ "ios": "{mod_save_dir}/renders" } }, + "open_menu_keybind": { + "name": "Open Menu Keybind", + "description": "The keybind to open the xdBot menu.", + "type": "keybind", + "default": "Alt+F", + "platforms": ["win", "mac"] + }, + "toggle_recording_keybind": { + "name": "Recording Keybind", + "description": "The keybind to start and stop recording a macro.", + "type": "keybind", + "default": "Alt+G", + "platforms": ["win", "mac"] + }, + "toggle_playing_keybind": { + "name": "Playing Keybind", + "description": "The keybind to start and stop playing a macro.", + "type": "keybind", + "default": "Alt+H", + "platforms": ["win", "mac"] + }, + "toggle_speedhack_keybind": { + "name": "Speedhack Keybind", + "description": "The keybind to toggle speedhack.", + "type": "keybind", + "default": "Alt+S", + "platforms": ["win", "mac"] + }, + "toggle_noclip_keybind": { + "name": "Noclip Keybind", + "description": "The keybind to toggle noclip.", + "type": "keybind", + "default": "Alt+N", + "platforms": ["win", "mac"] + }, + "toggle_frame_stepper_keybind": { + "name": "Frame Stepper Keybind", + "description": "The keybind to toggle the frame stepper.", + "type": "keybind", + "default": "Alt+C", + "platforms": ["win", "mac"] + }, + "step_frame_keybind": { + "name": "Step Frame Keybind", + "description": "The keybind to step a frame when the frame stepper is enabled.", + "type": "keybind", + "default": "V", + "platforms": ["win", "mac"] + }, + "show_trajectory_keybind": { + "name": "Show Trajectory Keybind", + "description": "The keybind to toggle the trajectory while recording a macro.", + "type": "keybind", + "default": "Alt+T", + "platforms": ["win", "mac"] + }, + "toggle_render_keybind": { + "name": "Render Keybind", + "description": "The keybind to start and stop the renderer.", + "type": "keybind", + "default": "Alt+P", + "platforms": ["win", "mac"] + }, "background_color": { "name": "Menu background color", "type": "color", @@ -83,21 +146,21 @@ "description": "Enables keybinds while on the level editor.", "type": "bool", "default": false, - "platforms": ["win"] + "platforms": ["win", "mac"] }, "disable_keybinds": { "name": "Disable keybinds", "description": "Disables all keybinds.", "type": "bool", "default": false, - "platforms": ["win"] + "platforms": ["win", "mac"] }, "recording_only_keybinds": { "name": "Keybinds only while recording", "description": "Keybinds only work while recording a macro.", "type": "bool", "default": false, - "platforms": ["win"] + "platforms": ["win", "mac"] }, "level_settings_button": { "name": "Show Button At Settings", diff --git a/src/keybinds.cpp b/src/keybinds.cpp index f4dffe78..f7384ff8 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -1,228 +1,157 @@ -// #include "includes.hpp" -// #include "ui/record_layer.hpp" -// #include "ui/game_ui.hpp" -// #include "ui/clickbot_layer.hpp" -// #include "ui/macro_editor.hpp" -// #include "ui/render_settings_layer.hpp" -// #include "hacks/layout_mode.hpp" -// #include "hacks/show_trajectory.hpp" - -// #include -// #include - -// #ifdef GEODE_IS_DESKTOP - -// #include -// #include - -// #endif - -// const std::vector keybindIDs = { -// "open_menu", "toggle_recording", "toggle_playing", -// "toggle_speedhack", "toggle_frame_stepper", "step_frame", -// "toggle_render", "toggle_noclip", "show_trajectory" -// }; - -// class $modify(CCKeyboardDispatcher) { -// bool dispatchKeyboardMSG(enumKeyCodes key, bool isKeyDown, bool isKeyRepeat) { - -// auto& g = Global::get(); - -// int keyInt = static_cast(key); -// if (g.allKeybinds.contains(keyInt) && !isKeyRepeat) { -// for (size_t i = 0; i < 6; i++) { -// if (std::find(g.keybinds[i].begin(), g.keybinds[i].end(), keyInt) != g.keybinds[i].end()) -// g.heldButtons[i] = isKeyDown; -// } -// } - -// // if (key == enumKeyCodes::KEY_L && !isKeyRepeat && isKeyDown) { -// // } - -// // if (key == enumKeyCodes::KEY_F && !isKeyRepeat && isKeyDown && PlayLayer::get()) { -// // log::debug("POS DEBUG {}", PlayLayer::get()->m_player1->getPosition()); -// // log::debug("POS2 DEBUG {}", PlayLayer::get()->m_player2->getPosition()); -// // } - - -// // if (key == enumKeyCodes::KEY_J && !isKeyRepeat && isKeyDown && PlayLayer::get()) { -// // std::string str = ZipUtils::decompressString(PlayLayer::get()->m_level->m_levelString.c_str(), true, 0); -// // log::debug("{}", str); -// // } - -// return CCKeyboardDispatcher::dispatchKeyboardMSG(key, isKeyDown, isKeyRepeat); -// } -// }; - -// #ifdef GEODE_IS_MOBILE - -// namespace keybinds { - -// struct ActionID {}; - -// }; - -// #endif - -// #ifdef GEODE_IS_DESKTOP -// using namespace keybinds; - -// void onKeybind(bool down, ActionID id) { - -// auto& g = Global::get(); - -// if (!down || (LevelEditorLayer::get() && !g.mod->getSettingValue("editor_keybinds")) || g.mod->getSettingValue("disable_keybinds")) -// return; - -// if (g.state != state::recording && g.mod->getSettingValue("recording_only_keybinds")) -// return; - -// if (id == "open_menu"_spr) { -// if (g.layer) { -// static_cast(g.layer)->onClose(nullptr); -// return; -// } - -// RecordLayer::openMenu(); -// } - -// if (id == "toggle_recording"_spr) -// Macro::toggleRecording(); - -// if (id == "toggle_playing"_spr) -// Macro::togglePlaying(); - -// if (id == "toggle_frame_stepper"_spr && PlayLayer::get()) -// Global::toggleFrameStepper(); - -// if (id == "step_frame"_spr) -// Global::frameStep(); - -// if (id == "toggle_speedhack"_spr) -// Global::toggleSpeedhack(); - -// if (id == "show_trajectory"_spr) { -// g.mod->setSavedValue("macro_show_trajectory", !g.mod->getSavedValue("macro_show_trajectory")); - -// if (g.layer) { -// if (static_cast(g.layer)->trajectoryToggle) -// static_cast(g.layer)->trajectoryToggle->toggle(g.mod->getSavedValue("macro_show_trajectory")); -// } - -// g.showTrajectory = g.mod->getSavedValue("macro_show_trajectory"); -// if (!g.showTrajectory) ShowTrajectory::trajectoryOff(); -// } - -// if (id == "toggle_render"_spr && PlayLayer::get()) { -// bool result = Renderer::toggle(); - -// if (result && Global::get().renderer.recording) -// Notification::create("Started Rendering", NotificationIcon::Info)->show(); - -// if (g.layer) { -// if (static_cast(g.layer)->renderToggle) -// static_cast(g.layer)->renderToggle->toggle(Global::get().renderer.recording); -// } - -// } - -// if (id == "toggle_noclip"_spr) { -// g.mod->setSavedValue("macro_noclip", !g.mod->getSavedValue("macro_noclip")); - -// if (g.layer) { -// if (static_cast(g.layer)->noclipToggle) -// static_cast(g.layer)->noclipToggle->toggle(g.mod->getSavedValue("macro_noclip")); -// } -// } -// } - -// $execute{ -// BindManager * bm = BindManager::get(); - -// bm->registerBindable({ -// "open_menu"_spr, -// "Open Menu", -// "Open Menu.", -// { Keybind::create(KEY_F, Modifier::Alt) }, -// "xdBot", -// false -// }); - -// bm->registerBindable({ -// "toggle_recording"_spr, -// "Record macro", -// "Toggles recording.", -// { Keybind::create(KEY_G, Modifier::Alt) }, -// "xdBot", -// false -// }); - -// bm->registerBindable({ -// "toggle_playing"_spr, -// "Play macro", -// "Toggles playing.", -// { Keybind::create(KEY_H, Modifier::Alt) }, -// "xdBot", -// false -// }); - -// bm->registerBindable({ -// "toggle_speedhack"_spr, -// "Speedhack", -// "Toggles speedhack.", -// { Keybind::create(KEY_S, Modifier::Alt) }, -// "xdBot", -// false -// }); - -// bm->registerBindable({ -// "toggle_noclip"_spr, -// "NoClip", -// "Toggles NoClip.", -// { Keybind::create(KEY_N, Modifier::Alt) }, -// "xdBot", -// false -// }); - -// bm->registerBindable({ -// "toggle_frame_stepper"_spr, -// "Toggle Frame Stepper", -// "Toggles frame stepper..", -// { Keybind::create(KEY_C, Modifier::Alt) }, -// "xdBot", -// false -// }); - -// bm->registerBindable({ -// "step_frame"_spr, -// "Advance frame", -// "Advances one frame if frame stepper is on.", -// { Keybind::create(KEY_V) }, -// "xdBot" -// }); - -// bm->setRepeatOptionsFor("step_frame"_spr, { true, 10, 450 }); - -// bm->registerBindable({ -// "show_trajectory"_spr, -// "Show Trajectory", -// "Toggles Show Trajectory.", -// { Keybind::create(KEY_T, Modifier::Alt) }, -// "xdBot" -// }); - -// bm->registerBindable({ -// "toggle_render"_spr, -// "Render", -// "Toggles rendering.", -// { Keybind::create(KEY_P, Modifier::Alt) }, -// "xdBot", -// false -// }); - -// for (int i = 0; i < keybindIDs.size(); i++) { -// new EventListener([=](InvokeBindEvent* event) { onKeybind(event->isDown(), event->getID()); return ListenerResult::Propagate; -// }, InvokeBindFilter(nullptr, (""_spr) + keybindIDs[i])); -// } -// } -// #endif +#ifdef GEODE_IS_DESKTOP +#include "includes.hpp" +#include "ui/record_layer.hpp" +#include "ui/game_ui.hpp" +#include "ui/clickbot_layer.hpp" +#include "ui/macro_editor.hpp" +#include "ui/render_settings_layer.hpp" +#include "hacks/layout_mode.hpp" +#include "hacks/show_trajectory.hpp" + +#include +#include +#include +#include +#include + +class $modify(CCKeyboardDispatcher) { + bool dispatchKeyboardMSG(enumKeyCodes key, bool isKeyDown, bool isKeyRepeat, double time) { + + auto& g = Global::get(); + + int keyInt = static_cast(key); + if (g.allKeybinds.contains(keyInt) && !isKeyRepeat) { + for (size_t i = 0; i < 6; i++) { + if (std::find(g.keybinds[i].begin(), g.keybinds[i].end(), keyInt) != g.keybinds[i].end()) + g.heldButtons[i] = isKeyDown; + } + } + + // if (key == enumKeyCodes::KEY_L && !isKeyRepeat && isKeyDown) { + // } + + // if (key == enumKeyCodes::KEY_F && !isKeyRepeat && isKeyDown && PlayLayer::get()) { + // log::debug("POS DEBUG {}", PlayLayer::get()->m_player1->getPosition()); + // log::debug("POS2 DEBUG {}", PlayLayer::get()->m_player2->getPosition()); + // } + + + // if (key == enumKeyCodes::KEY_J && !isKeyRepeat && isKeyDown && PlayLayer::get()) { + // std::string str = ZipUtils::decompressString(PlayLayer::get()->m_level->m_levelString.c_str(), true, 0); + // log::debug("{}", str); + // } + + return CCKeyboardDispatcher::dispatchKeyboardMSG(key, isKeyDown, isKeyRepeat, time); + } +}; + +class KeybindEditPopup : public geode::Popup {}; +class ModSettingsPopup : public geode::Popup {}; +class KeybindListPopup : public geode::Popup {}; + + +void handleKeybind(std::string const& id, bool down) { + auto& g = Global::get(); + + if (!down || (LevelEditorLayer::get() && !g.mod->getSettingValue("editor_keybinds")) || g.mod->getSettingValue("disable_keybinds")) return; + + if (auto scene = CCDirector::sharedDirector()->getRunningScene()) { + if (scene->getChildByType(0) || scene->getChildByType(0) || scene->getChildByType(0)) return; + } + + if (g.layer && id != "open_menu_keybind") return; + + if (g.state != state::recording && g.mod->getSettingValue("recording_only_keybinds")) return; + + if (id == "open_menu_keybind") { + if (g.layer) { + static_cast(g.layer)->onClose(nullptr); + return; + } + + RecordLayer::openMenu(); + } + + else if (id == "toggle_recording_keybind") + Macro::toggleRecording(); + + else if (id == "toggle_playing_keybind") + Macro::togglePlaying(); + + else if (id == "toggle_frame_stepper_keybind" && PlayLayer::get()) + Global::toggleFrameStepper(); + + else if (id == "step_frame_keybind") + Global::frameStep(); + + else if (id == "toggle_speedhack_keybind") + Global::toggleSpeedhack(); + + else if (id == "show_trajectory_keybind") { + g.mod->setSavedValue("macro_show_trajectory", !g.mod->getSavedValue("macro_show_trajectory")); + + if (g.layer) { + if (static_cast(g.layer)->trajectoryToggle) + static_cast(g.layer)->trajectoryToggle->toggle(g.mod->getSavedValue("macro_show_trajectory")); + } + + g.showTrajectory = g.mod->getSavedValue("macro_show_trajectory"); + if (!g.showTrajectory) ShowTrajectory::trajectoryOff(); + } + + // else if (id == "toggle_render_keybind" && PlayLayer::get()) { + // #ifndef GEODE_IS_IOS + // bool result = Renderer::toggle(); + + // // if (result && Global::get().renderer.recording) + // if (result) + // Notification::create("Started Rendering", NotificationIcon::Info)->show(); + + // if (g.layer) { + // // if (static_cast(g.layer)->renderToggle) + // // static_cast(g.layer)->renderToggle->toggle(Global::get().renderer.recording); + // } + // #endif + + // } + + else if (id == "toggle_noclip_keybind") { + g.mod->setSavedValue("macro_noclip", !g.mod->getSavedValue("macro_noclip")); + + if (g.layer) { + if (static_cast(g.layer)->noclipToggle) + static_cast(g.layer)->noclipToggle->toggle(g.mod->getSavedValue("macro_noclip")); + } + } +} + +$execute{ + listenForKeybindSettingPresses("open_menu_keybind", [](Keybind const&, bool down, bool repeat) { + if (!repeat) handleKeybind("open_menu_keybind", down); + }); + listenForKeybindSettingPresses("toggle_recording_keybind", [](Keybind const&, bool down, bool repeat) { + if (!repeat) handleKeybind("toggle_recording_keybind", down); + }); + listenForKeybindSettingPresses("toggle_playing_keybind", [](Keybind const&, bool down, bool repeat) { + if (!repeat) handleKeybind("toggle_playing_keybind", down); + }); + listenForKeybindSettingPresses("toggle_speedhack_keybind", [](Keybind const&, bool down, bool repeat) { + if (!repeat) handleKeybind("toggle_speedhack_keybind", down); + }); + listenForKeybindSettingPresses("toggle_frame_stepper_keybind", [](Keybind const&, bool down, bool repeat) { + if (!repeat) handleKeybind("toggle_frame_stepper_keybind", down); + }); + listenForKeybindSettingPresses("step_frame_keybind", [](Keybind const&, bool down, bool repeat) { + if (!repeat) handleKeybind("step_frame_keybind", down); + }); + listenForKeybindSettingPresses("show_trajectory_keybind", [](Keybind const&, bool down, bool repeat) { + if (!repeat) handleKeybind("show_trajectory_keybind", down); + }); + // listenForKeybindSettingPresses("toggle_render_keybind", [](Keybind const&, bool down, bool repeat) { + // if (!repeat) handleKeybind("toggle_render_keybind", down); + // }); + listenForKeybindSettingPresses("toggle_noclip_keybind", [](Keybind const&, bool down, bool repeat) { + if (!repeat) handleKeybind("toggle_noclip_keybind", down); + }); +} +#endif \ No newline at end of file diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 480da155..16e852b5 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -12,1283 +12,1267 @@ #include #include +#include const std::vector> settings { - { - { "TPS Bypass:", "macro_tps_enabled", InputType::Tps, 0.4f }, - { "Speedhack:", "macro_speedhack_enabled", InputType::Speedhack, 0.4f }, - { "Seed:", "macro_seed_enabled", InputType::Seed, 0.4f }, - { "Enable Noclip:", "macro_noclip", InputType::Settings, 0.325f, menu_selector(NoclipSettingsLayer::open) }, - { "Show Trajectory:", "macro_show_trajectory", InputType::Settings, 0.325f, menu_selector(TrajectorySettingsLayer::open) }, - { "Enable Frame Stepper:", "macro_frame_stepper", InputType::None }, - }, - { - { "Instant respawn:", "macro_instant_respawn", InputType::None }, - { "No death effect:", "macro_no_death_effect", InputType::None }, - { "No respawn flash:", "macro_no_respawn_flash", InputType::None }, - { "Enable Coin Finder:", "macro_coin_finder", InputType::None }, - { "Enable Layout Mode:", "macro_layout_mode", InputType::None }, - { "Auto Safe Mode:", "macro_auto_safe_mode", InputType::None } - }, - { - #ifdef GEODE_IS_WINDOWS - { "Force cursor on open:", "menu_show_cursor", InputType::None }, - { "Button on pause menu:", "menu_show_button", InputType::None }, - { "Pause on open:", "menu_pause_on_open", InputType::None }, - #else - { "Always show buttons:", "macro_always_show_buttons", InputType::None }, - { "Hide speedhack button:", "macro_hide_speedhack", InputType::None }, - { "Hide Frame Stepper button:", "macro_hide_stepper", InputType::None, 0.3f }, - #endif - { "Hide labels on render:", "render_hide_labels", InputType::None }, - { "Hide playing label:", "macro_hide_playing_label", InputType::None }, - { "Hide recording label:", "macro_hide_recording_label", InputType::None } - }, - { - { "Enable Clickbot:", "clickbot_enabled", InputType::Settings, 0.325f, menu_selector(ClickbotLayer::open)}, - { "Enable Autoclicker:", "autoclicker_enabled", InputType::Settings, 0.3f, menu_selector(AutoclickerLayer::open) }, - { "Always Practice Fixes:", "macro_always_practice_fixes", InputType::None }, - { "Ignore inputs:", "macro_ignore_inputs", InputType::None }, - { "Show Frame Label:", "macro_show_frame_label", InputType::None }, - { "Speedhack Audio:", "macro_speedhack_audio", InputType::None } - // { "Auto Stop Playing:", "macro_auto_stop_playing", InputType::None } - }, { - { "Respawn Time:", "respawn_time_enabled", InputType::Respawn }, - { "Input Mirror:", "p2_input_mirror", InputType::Settings, 0.325f, menu_selector(MirrorSettingsLayer::open) }, - { "Disable Shaders:", "disable_shaders", InputType::None }, - { "Instant Mirror Portal:", "instant_mirror_portal", InputType::None }, - { "No Mirror Portal:", "no_mirror_portal", InputType::None }, - { "Enable Auto Saving:", "macro_auto_save", InputType::Autosave } + { "TPS Bypass:", "macro_tps_enabled", InputType::Tps, 0.4f }, + { "Speedhack:", "macro_speedhack_enabled", InputType::Speedhack, 0.4f }, + { "Seed:", "macro_seed_enabled", InputType::Seed, 0.4f }, + { "Enable Noclip:", "macro_noclip", InputType::Settings, 0.325f, menu_selector(NoclipSettingsLayer::open) }, + { "Show Trajectory:", "macro_show_trajectory", InputType::Settings, 0.325f, menu_selector(TrajectorySettingsLayer::open) }, + { "Enable Frame Stepper:", "macro_frame_stepper", InputType::None }, + }, + { + { "Instant respawn:", "macro_instant_respawn", InputType::None }, + { "No death effect:", "macro_no_death_effect", InputType::None }, + { "No respawn flash:", "macro_no_respawn_flash", InputType::None }, + { "Enable Coin Finder:", "macro_coin_finder", InputType::None }, + { "Enable Layout Mode:", "macro_layout_mode", InputType::None }, + { "Auto Safe Mode:", "macro_auto_safe_mode", InputType::None } + }, + { + #ifdef GEODE_IS_WINDOWS + { "Force cursor on open:", "menu_show_cursor", InputType::None }, + { "Button on pause menu:", "menu_show_button", InputType::None }, + { "Pause on open:", "menu_pause_on_open", InputType::None }, + #else + { "Always show buttons:", "macro_always_show_buttons", InputType::None }, + { "Hide speedhack button:", "macro_hide_speedhack", InputType::None }, + { "Hide Frame Stepper button:", "macro_hide_stepper", InputType::None, 0.3f }, + #endif + { "Hide labels on render:", "render_hide_labels", InputType::None }, + { "Hide playing label:", "macro_hide_playing_label", InputType::None }, + { "Hide recording label:", "macro_hide_recording_label", InputType::None } + }, + { + { "Enable Clickbot:", "clickbot_enabled", InputType::Settings, 0.325f, menu_selector(ClickbotLayer::open)}, + { "Enable Autoclicker:", "autoclicker_enabled", InputType::Settings, 0.3f, menu_selector(AutoclickerLayer::open) }, + { "Always Practice Fixes:", "macro_always_practice_fixes", InputType::None }, + { "Ignore inputs:", "macro_ignore_inputs", InputType::None }, + { "Show Frame Label:", "macro_show_frame_label", InputType::None }, + { "Speedhack Audio:", "macro_speedhack_audio", InputType::None } + // { "Auto Stop Playing:", "macro_auto_stop_playing", InputType::None } + }, + { + { "Respawn Time:", "respawn_time_enabled", InputType::Respawn }, + { "Input Mirror:", "p2_input_mirror", InputType::Settings, 0.325f, menu_selector(MirrorSettingsLayer::open) }, + { "Disable Shaders:", "disable_shaders", InputType::None }, + { "Instant Mirror Portal:", "instant_mirror_portal", InputType::None }, + { "No Mirror Portal:", "no_mirror_portal", InputType::None }, + { "Enable Auto Saving:", "macro_auto_save", InputType::Autosave } } }; class $modify(PauseLayer) { void customSetup() { PauseLayer::customSetup(); - + #ifdef GEODE_IS_DESKTOP - + if (!Mod::get()->getSavedValue("menu_show_button")) return; - + #endif - + CCSprite* sprite = nullptr; - + sprite = CCSprite::createWithSpriteFrameName("GJ_playBtn2_001.png"); sprite->setScale(0.35f); - - + + CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(sprite, this, menu_selector(RecordLayer::openMenu2)); - - if (!Loader::get()->isModLoaded("geode.node-ids")) { - CCMenu* menu = CCMenu::create(); - menu->setID("button"_spr); - addChild(menu); - btn->setPosition({214, 88}); + + if (!Loader::get()->isModLoaded("geode.node-ids")) { + CCMenu* menu = CCMenu::create(); + menu->setID("button"_spr); + addChild(menu); + btn->setPosition({214, 88}); + menu->addChild(btn); + return; + } + + CCNode* menu = this->getChildByID("right-button-menu"); menu->addChild(btn); - return; + menu->updateLayout(); } - - CCNode* menu = this->getChildByID("right-button-menu"); - menu->addChild(btn); - menu->updateLayout(); + }; + + $execute{ + geode::listenForSettingChanges("frame_offset", +[](int64_t value) { + auto& g = Global::get(); + g.frameOffset = value; + + if (g.layer) { + static_cast(g.layer)->warningLabel->setString(("WARNING: Currently recording / playing macros with a frame offset of " + std::to_string(value)).c_str()); + static_cast(g.layer)->warningLabel->setVisible(value != 0); + static_cast(g.layer)->warningSprite->setVisible(value != 0); + } + + }); + + geode::listenForSettingChanges("background_color", +[](cocos2d::ccColor3B value) { + auto& g = Global::get(); + if (g.layer) { + CCArray* children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); + if (FLAlertLayer* layer = typeinfo_cast(children->lastObject())) + layer->keyBackClicked(); + + static_cast(g.layer)->onClose(nullptr); + RecordLayer::openMenu(true); + } + }); + }; + + void RecordLayer::openSaveMacro(CCObject*) { + SaveMacroLayer::open(); } -}; - -$execute{ - geode::listenForSettingChanges("frame_offset", +[](int64_t value) { - auto& g = Global::get(); - g.frameOffset = value; - - if (g.layer) { - static_cast(g.layer)->warningLabel->setString(("WARNING: Currently recording / playing macros with a frame offset of " + std::to_string(value)).c_str()); - static_cast(g.layer)->warningLabel->setVisible(value != 0); - static_cast(g.layer)->warningSprite->setVisible(value != 0); - } - - }); - - geode::listenForSettingChanges("background_color", +[](cocos2d::ccColor3B value) { + + void RecordLayer::openLoadMacro(CCObject*) { + LoadMacroLayer::open(static_cast(this), nullptr); + } + + RecordLayer* RecordLayer::openMenu(bool instant) { auto& g = Global::get(); - if (g.layer) { - CCArray* children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); - if (FLAlertLayer* layer = typeinfo_cast(children->lastObject())) - layer->keyBackClicked(); - - static_cast(g.layer)->onClose(nullptr); - RecordLayer::openMenu(true); - } - }); -}; - -void RecordLayer::openSaveMacro(CCObject*) { - SaveMacroLayer::open(); -} - -void RecordLayer::openLoadMacro(CCObject*) { - LoadMacroLayer::open(static_cast(this), nullptr); -} - -RecordLayer* RecordLayer::openMenu(bool instant) { - auto& g = Global::get(); - PlayLayer* pl = PlayLayer::get(); - bool cursor = false; - - CCArray* children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); - CCObject* child; - - if (g.layer) + PlayLayer* pl = PlayLayer::get(); + bool cursor = false; + + CCArray* children = CCDirector::sharedDirector()->getRunningScene()->getChildren(); + CCObject* child; + + if (g.layer) static_cast(g.layer)->onClose(nullptr); - - if (pl && g.mod->getSavedValue("menu_pause_on_open")) { - if (!pl->m_isPaused) + + if (pl && g.mod->getSavedValue("menu_pause_on_open")) { + if (!pl->m_isPaused) pl->pauseGame(false); + } + #ifdef GEODE_IS_WINDOWS + else if (pl && g.mod->getSavedValue("menu_show_cursor")) { + cursor = cocos2d::CCEGLView::sharedOpenGLView()->getShouldHideCursor(); + cocos2d::CCEGLView::sharedOpenGLView()->showCursor(true); + } + #endif + + RecordLayer* layer = create(); + layer->cursorWasHidden = cursor; + layer->m_noElasticity = instant || Global::get().speedhackEnabled; + layer->show(); + + g.layer = static_cast(layer); + + return layer; } -#ifdef GEODE_IS_WINDOWS - else if (pl && g.mod->getSavedValue("menu_show_cursor")) { - cursor = cocos2d::CCEGLView::sharedOpenGLView()->getShouldHideCursor(); - cocos2d::CCEGLView::sharedOpenGLView()->showCursor(true); - } -#endif - - RecordLayer* layer = create(); - layer->cursorWasHidden = cursor; - layer->m_noElasticity = instant || Global::get().speedhackEnabled; - layer->show(); - - g.layer = static_cast(layer); - - return layer; -} - -void RecordLayer::checkSpeedhack() { - std::string speedhackValue = mod->getSavedValue("macro_speedhack"); - - if (std::count(speedhackValue.begin(), speedhackValue.end(), '.') == 0) + + void RecordLayer::checkSpeedhack() { + std::string speedhackValue = mod->getSavedValue("macro_speedhack"); + + if (std::count(speedhackValue.begin(), speedhackValue.end(), '.') == 0) speedhackValue += ".0"; - - if (speedhackValue.back() == '.') + + if (speedhackValue.back() == '.') speedhackValue += "0"; - - if (speedhackValue[0] == '0' && speedhackValue[1] != '.') + + if (speedhackValue[0] == '0' && speedhackValue[1] != '.') speedhackValue.erase(0, 1); - - if (speedhackValue[0] == '.') + + if (speedhackValue[0] == '.') speedhackValue = "0" + speedhackValue; - - mod->setSavedValue("macro_speedhack", speedhackValue); -} - -void RecordLayer::onClose(CCObject*) { - checkSpeedhack(); - - PlayLayer* pl = PlayLayer::get(); - - if (cursorWasHidden && pl) + + mod->setSavedValue("macro_speedhack", speedhackValue); + } + + void RecordLayer::onClose(CCObject*) { + checkSpeedhack(); + + PlayLayer* pl = PlayLayer::get(); + + if (cursorWasHidden && pl) PlatformToolbox::hideCursor(); - - Global::get().layer = nullptr; - - this->setKeypadEnabled(false); - this->setTouchEnabled(false); - this->removeFromParentAndCleanup(true); -} - -void RecordLayer::toggleRecording(CCObject*) { - auto& g = Global::get(); - - if (Global::hasIncompatibleMods()) + + Global::get().layer = nullptr; + + this->setKeypadEnabled(false); + this->setTouchEnabled(false); + this->removeFromParentAndCleanup(true); + } + + void RecordLayer::toggleRecording(CCObject*) { + auto& g = Global::get(); + + if (Global::hasIncompatibleMods()) return recording->toggle(true); - - if (g.state == state::playing) playing->toggle(false); - g.state = g.state == state::recording ? state::none : state::recording; - - if (g.state == state::recording) { - g.currentAction = 0; - g.currentFrameFix = 0; - g.restart = true; - - PlayLayer* pl = PlayLayer::get(); - if (pl) { - if (!pl->m_isPaused) + + if (g.state == state::playing) playing->toggle(false); + g.state = g.state == state::recording ? state::none : state::recording; + + if (g.state == state::recording) { + g.currentAction = 0; + g.currentFrameFix = 0; + g.restart = true; + + PlayLayer* pl = PlayLayer::get(); + if (pl) { + if (!pl->m_isPaused) pl->pauseGame(false); + } } + + Interface::updateLabels(); + Interface::updateButtons(); + Macro::updateTPS(); + this->updateTPS(); + + g.lastAutoSaveMS = std::chrono::steady_clock::now(); } - - Interface::updateLabels(); - Interface::updateButtons(); - Macro::updateTPS(); - this->updateTPS(); - - g.lastAutoSaveMS = std::chrono::steady_clock::now(); -} - -void RecordLayer::togglePlaying(CCObject*) { - auto& g = Global::get(); - - if (Global::hasIncompatibleMods()) + + void RecordLayer::togglePlaying(CCObject*) { + auto& g = Global::get(); + + if (Global::hasIncompatibleMods()) return playing->toggle(true); - - if (g.state == state::recording) + + if (g.state == state::recording) recording->toggle(false); - - g.state = g.state == state::playing ? state::none : state::playing; - - if (g.state == state::playing) { - g.currentAction = 0; - g.currentFrameFix = 0; - - g.macro.xdBotMacro = g.macro.botInfo.name == "xdBot"; - PlayLayer* pl = PlayLayer::get(); - - if (pl) { - if (!pl->m_isPaused && !pl->m_levelEndAnimationStarted) + g.state = g.state == state::playing ? state::none : state::playing; + + if (g.state == state::playing) { + g.currentAction = 0; + g.currentFrameFix = 0; + + g.macro.xdBotMacro = g.macro.botInfo.name == "xdBot"; + + PlayLayer* pl = PlayLayer::get(); + + if (pl) { + if (!pl->m_isPaused && !pl->m_levelEndAnimationStarted) pl->m_levelSettings->m_platformerMode ? pl->resetLevelFromStart() : pl->resetLevel(); - else + else g.restart = true; + } } + + Interface::updateLabels(); + Interface::updateButtons(); + Macro::updateTPS(); + this->updateTPS(); } - - Interface::updateLabels(); - Interface::updateButtons(); - Macro::updateTPS(); - this->updateTPS(); -} - -// #ifndef GEODE_IS_IOS -/*void RecordLayer::toggleRender(CCObject* btn) { + + // #ifndef GEODE_IS_IOS + /*void RecordLayer::toggleRender(CCObject* btn) { if (!Renderer::toggle()) - static_cast(btn)->toggle(true); - + static_cast(btn)->toggle(true); + if (Global::get().renderer.recordingAudio) - static_cast(btn)->toggle(false); -}*/ -// #else -void RecordLayer::toggleRenderIOS(CCObject* btn) { - FLAlertLayer::create("Info", "Rendering is not supported yet!", "OK")->show(); -} -// #endif - -void RecordLayer::onEditMacro(CCObject*) { - MacroEditLayer::open(); -} - -void RecordLayer::toggleFPS(bool on) { // forgotten - return; - float scaleSpr = -0.8, scaleBtn = -1; - int opacityBtn = 57, opacityLbl = 80; - - if (on) { - return; - scaleSpr = 0.8; - scaleBtn = 1; - opacityBtn = 230; - opacityLbl = 255; + static_cast(btn)->toggle(false); + }*/ + // #else + void RecordLayer::toggleRenderIOS(CCObject* btn) { + FLAlertLayer::create("Info", "Rendering is not supported yet!", "OK")->show(); } - - CCSprite* spr = CCSprite::createWithSpriteFrameName("edit_leftBtn_001.png"); - spr->setScale(scaleSpr); - FPSLeft->setSprite(spr); - FPSLeft->setScale(scaleBtn); - FPSLeft->setOpacity(opacityBtn); - - spr = CCSprite::createWithSpriteFrameName("edit_rightBtn_001.png"); - spr->setScale(scaleSpr); - FPSRight->setSprite(spr); - FPSRight->setScale(scaleBtn); - FPSRight->setOpacity(opacityBtn); - - fpsLabel->setOpacity(opacityLbl); -} - -void RecordLayer::macroInfo(CCObject*) { - MacroInfoLayer::create()->show(); -} - -void RecordLayer::textChanged(CCTextInputNode* node) { - if (!node) return; - - mod = Mod::get(); - - if (node == seedInput) { - - if (auto num = numFromString(seedInput->getString())) { - mod->setSavedValue("macro_seed", std::to_string(num.unwrap())); + // #endif + + void RecordLayer::onEditMacro(CCObject*) { + MacroEditLayer::open(); + } + + void RecordLayer::toggleFPS(bool on) { // forgotten + return; + float scaleSpr = -0.8, scaleBtn = -1; + int opacityBtn = 57, opacityLbl = 80; + + if (on) { return; + scaleSpr = 0.8; + scaleBtn = 1; + opacityBtn = 230; + opacityLbl = 255; } - else { - return seedInput->setString(mod->getSavedValue("macro_seed").c_str()); - } + + CCSprite* spr = CCSprite::createWithSpriteFrameName("edit_leftBtn_001.png"); + spr->setScale(scaleSpr); + FPSLeft->setSprite(spr); + FPSLeft->setScale(scaleBtn); + FPSLeft->setOpacity(opacityBtn); + + spr = CCSprite::createWithSpriteFrameName("edit_rightBtn_001.png"); + spr->setScale(scaleSpr); + FPSRight->setSprite(spr); + FPSRight->setScale(scaleBtn); + FPSRight->setOpacity(opacityBtn); + + fpsLabel->setOpacity(opacityLbl); } - - if (node == codecInput) + + void RecordLayer::macroInfo(CCObject*) { + MacroInfoLayer::create()->show(); + } + + void RecordLayer::textChanged(CCTextInputNode* node) { + if (!node) return; + + mod = Mod::get(); + + if (node == seedInput) { + + if (auto num = numFromString(seedInput->getString())) { + mod->setSavedValue("macro_seed", std::to_string(num.unwrap())); + return; + } + else { + return seedInput->setString(mod->getSavedValue("macro_seed").c_str()); + } + } + + if (node == codecInput) mod->setSavedValue("render_codec", std::string(codecInput->getString())); - - if (std::string_view(widthInput->getString()) != "" && node == widthInput) + + if (std::string_view(widthInput->getString()) != "" && node == widthInput) mod->setSavedValue("render_width2", std::string(widthInput->getString())); - - if (std::string_view(heightInput->getString()) != "" && node == heightInput) + + if (std::string_view(heightInput->getString()) != "" && node == heightInput) mod->setSavedValue("render_height", std::string(heightInput->getString())); - - if (std::string_view(bitrateInput->getString()) != "" && node == bitrateInput) + + if (std::string_view(bitrateInput->getString()) != "" && node == bitrateInput) mod->setSavedValue("render_bitrate", std::string(bitrateInput->getString())); - - if (std::string_view(fpsInput->getString()) != "" && node == fpsInput) { - if (std::stoi(fpsInput->getString()) > 240) + + if (std::string_view(fpsInput->getString()) != "" && node == fpsInput) { + if (std::stoi(fpsInput->getString()) > 240) return fpsInput->setString(mod->getSavedValue("render_fps").c_str()); - mod->setSavedValue("render_fps", std::string(fpsInput->getString())); - } - - if (respawnInput && node == respawnInput) { - std::string str = respawnInput->getString(); - mod->setSavedValue("respawn_time", numFromString(str).unwrapOr(0.5)); - } - - if (tpsInput && node == tpsInput) { - float value = geode::utils::numFromString(tpsInput->getString()).unwrapOr(0.f); - if (std::string_view(tpsInput->getString()) != "" && value < 999999 && value >= 0.f) { - mod->setSavedValue("macro_tps", value); - Global::get().tps = value; - Global::get().leftOver = 0.f; + mod->setSavedValue("render_fps", std::string(fpsInput->getString())); } - } - - if (!speedhackInput || node != speedhackInput) return; - - if (std::string_view(speedhackInput->getString()) != "" && node == speedhackInput) { - std::string value = speedhackInput->getString(); - - if (value == ".") + + if (respawnInput && node == respawnInput) { + std::string str = respawnInput->getString(); + mod->setSavedValue("respawn_time", numFromString(str).unwrapOr(0.5)); + } + + if (tpsInput && node == tpsInput) { + float value = geode::utils::numFromString(tpsInput->getString()).unwrapOr(0.f); + if (std::string_view(tpsInput->getString()) != "" && value < 999999 && value >= 0.f) { + mod->setSavedValue("macro_tps", value); + Global::get().tps = value; + Global::get().leftOver = 0.f; + } + } + + if (!speedhackInput || node != speedhackInput) return; + + if (std::string_view(speedhackInput->getString()) != "" && node == speedhackInput) { + std::string value = speedhackInput->getString(); + + if (value == ".") speedhackInput->setString("0."); - else if (std::count(value.begin(), value.end(), '.') == 2 || std::stof(value) > 10) + else if (std::count(value.begin(), value.end(), '.') == 2 || std::stof(value) > 10) return speedhackInput->setString(mod->getSavedValue("macro_speedhack").c_str()); - } - - if (std::string_view(speedhackInput->getString()) != "") + } + + if (std::string_view(speedhackInput->getString()) != "") mod->setSavedValue("macro_speedhack", std::string(speedhackInput->getString())); -} - -void RecordLayer::updatePage(CCObject* obj) { - auto& g = Global::get(); - g.currentPage += static_cast(obj)->getID() == "page-left" ? -1 : 1; - if (g.currentPage == -1) g.currentPage = settings.size() - 1; - else if (g.currentPage == settings.size()) g.currentPage = 0; - - goToSettingsPage(g.currentPage); -} - -void RecordLayer::toggleSetting(CCObject* obj) { - CCMenuItemToggler* toggle = static_cast(obj); - std::string id = toggle->getID(); - auto& g = Global::get(); - mod = g.mod; - - bool value = !toggle->isToggled(); - - g.mod->setSavedValue(id, value); - - // Some of these get checked every frame so idk i didnt want to do mod->getSavedValue every time - if (id == "macro_seed_enabled") g.seedEnabled = value; - if (id == "macro_speedhack_enabled") g.speedhackEnabled = value; - if (id == "macro_speedhack_audio") g.speedhackAudio = value; - if (id == "p2_input_mirror") g.p2mirror = value; - if (id == "clickbot_enabled") g.clickbotEnabled = value; - if (id == "clickbot_playing_only") g.clickbotOnlyPlaying = value; - if (id == "clickbot_holding_only") g.clickbotOnlyHolding = value; - if (id == "macro_tps_enabled") g.tpsEnabled = value; - if (id == "autoclicker_enabled") g.autoclicker = value; - if (id == "disable_shaders") g.disableShaders = value; - if (id == "macro_auto_save") g.autosaveEnabled = value; - - if (id == "macro_show_trajectory") { - g.showTrajectory = value; - if (!value) ShowTrajectory::trajectoryOff(); - } - - if (id == "macro_coin_finder") { - g.coinFinder = value; - if (!value) CoinFinder::finderOff(); - } - - if (id == "macro_show_trajectory") { - g.showTrajectory = value; - if (!value) ShowTrajectory::trajectoryOff(); - } - - if (id == "macro_show_frame_label") { - g.frameLabel = value; - Interface::updateLabels(); } - - if (id == "macro_frame_stepper") { - g.frameStepper = value; - Interface::updateButtons(); + + void RecordLayer::updatePage(CCObject* obj) { + auto& g = Global::get(); + g.currentPage += static_cast(obj)->getID() == "page-left" ? -1 : 1; + if (g.currentPage == -1) g.currentPage = settings.size() - 1; + else if (g.currentPage == settings.size()) g.currentPage = 0; + + goToSettingsPage(g.currentPage); } - - if (id == "clickbot_enabled" || id == "clickbot_playing_only") + + void RecordLayer::toggleSetting(CCObject* obj) { + CCMenuItemToggler* toggle = static_cast(obj); + std::string id = toggle->getID(); + auto& g = Global::get(); + mod = g.mod; + + bool value = !toggle->isToggled(); + + g.mod->setSavedValue(id, value); + + // Some of these get checked every frame so idk i didnt want to do mod->getSavedValue every time + if (id == "macro_seed_enabled") g.seedEnabled = value; + if (id == "macro_speedhack_enabled") g.speedhackEnabled = value; + if (id == "macro_speedhack_audio") g.speedhackAudio = value; + if (id == "p2_input_mirror") g.p2mirror = value; + if (id == "clickbot_enabled") g.clickbotEnabled = value; + if (id == "clickbot_playing_only") g.clickbotOnlyPlaying = value; + if (id == "clickbot_holding_only") g.clickbotOnlyHolding = value; + if (id == "macro_tps_enabled") g.tpsEnabled = value; + if (id == "autoclicker_enabled") g.autoclicker = value; + if (id == "disable_shaders") g.disableShaders = value; + if (id == "macro_auto_save") g.autosaveEnabled = value; + + if (id == "macro_show_trajectory") { + g.showTrajectory = value; + if (!value) ShowTrajectory::trajectoryOff(); + } + + if (id == "macro_coin_finder") { + g.coinFinder = value; + if (!value) CoinFinder::finderOff(); + } + + if (id == "macro_show_trajectory") { + g.showTrajectory = value; + if (!value) ShowTrajectory::trajectoryOff(); + } + + if (id == "macro_show_frame_label") { + g.frameLabel = value; + Interface::updateLabels(); + } + + if (id == "macro_frame_stepper") { + g.frameStepper = value; + Interface::updateButtons(); + } + + if (id == "clickbot_enabled" || id == "clickbot_playing_only") Clickbot::updateSounds(); - - if (id == "macro_hide_recording_label" || id == "macro_hide_playing_label" || id == "render_hide_labels") + + if (id == "macro_hide_recording_label" || id == "macro_hide_playing_label" || id == "render_hide_labels") Interface::updateLabels(); - - if (id == "macro_hide_speedhack" || id == "macro_hide_stepper" || id == "macro_always_show_buttons") + + if (id == "macro_hide_speedhack" || id == "macro_hide_stepper" || id == "macro_always_show_buttons") Interface::updateButtons(); - - if (id == "render_only_song" && value) { - CCScene* scene = CCDirector::sharedDirector()->getRunningScene(); - if (RenderSettingsLayer* layer = scene->getChildByType(0)) { - if (!layer->recordAudioToggle) return; - layer->recordAudioToggle->toggle(false); - g.mod->setSavedValue("render_record_audio", false); - } - } - - if (id == "render_record_audio" && value) { - CCScene* scene = CCDirector::sharedDirector()->getRunningScene(); - if (RenderSettingsLayer* layer = scene->getChildByType(0)) { - if (!layer->onlySongToggle) return; - layer->onlySongToggle->toggle(false); - g.mod->setSavedValue("render_only_song", false); + + if (id == "render_only_song" && value) { + CCScene* scene = CCDirector::sharedDirector()->getRunningScene(); + if (RenderSettingsLayer* layer = scene->getChildByType(0)) { + if (!layer->recordAudioToggle) return; + layer->recordAudioToggle->toggle(false); + g.mod->setSavedValue("render_record_audio", false); + } } - } - - if (id == "menu_show_button") { - PlayLayer* pl = PlayLayer::get(); - - if (!pl) return; - if (!pl->m_isPaused) return; - - if (PauseLayer* layer = Global::getPauseLayer()) { - layer->onResume(nullptr); - PlayLayer::get()->pauseGame(false); - - this->onClose(nullptr); - RecordLayer::openMenu(true); + + if (id == "render_record_audio" && value) { + CCScene* scene = CCDirector::sharedDirector()->getRunningScene(); + if (RenderSettingsLayer* layer = scene->getChildByType(0)) { + if (!layer->onlySongToggle) return; + layer->onlySongToggle->toggle(false); + g.mod->setSavedValue("render_only_song", false); + } } - - if (!value) + + if (id == "menu_show_button") { + PlayLayer* pl = PlayLayer::get(); + + if (!pl) return; + if (!pl->m_isPaused) return; + + if (PauseLayer* layer = Global::getPauseLayer()) { + layer->onResume(nullptr); + PlayLayer::get()->pauseGame(false); + + this->onClose(nullptr); + RecordLayer::openMenu(true); + } + + if (!value) Notification::create("xdBot Button is disabled.", NotificationIcon::Warning)->show(); - } -} - -void RecordLayer::showKeybindsWarning() { - if (!mod->setSavedValue("opened_keybinds", true)) - FLAlertLayer::create( - "Warning", - "Scroll down to find xdBot's keybinds", - "Ok" - )->show(); -} - -void RecordLayer::openKeybinds(CCObject*) { -#ifdef GEODE_IS_DESKTOP - - MoreOptionsLayer::create()->onKeybindings(nullptr); - CCScene* scene = CCDirector::get()->getRunningScene(); - - FLAlertLayer* layer = typeinfo_cast(scene->getChildren()->lastObject()); - if (!layer) return showKeybindsWarning(); - - CCLayer* mainLayer = layer->getChildByType(0); - if (!mainLayer) return showKeybindsWarning(); - - CCNode* scrollLayer = mainLayer->getChildByID("ScrollLayer"); - if (!scrollLayer) return showKeybindsWarning(); - - CCNode* contentLayer = scrollLayer->getChildByID("content-layer"); - if (!contentLayer) return showKeybindsWarning(); - - CCNode* xdBot = contentLayer->getChildByID("xdBot"); - if (!xdBot) return showKeybindsWarning(); - - contentLayer->setPositionY(xdBot->getPositionY() - 118); - -#else - - Interface::openButtonEditor(); - -#endif -} - -void RecordLayer::openPresets(CCObject*) { - RenderPresetsLayer::create()->show(); -} - -void RecordLayer::onAutosaves(CCObject*) { - std::filesystem::path path = Mod::get()->getSettingValue("autosaves_folder"); - - if (std::filesystem::exists(path)) - LoadMacroLayer::open(static_cast(this), nullptr, true); - else { - FLAlertLayer::create("Error", "There was an error getting the folder. ID: 5", "Ok")->show(); - } -} - -void RecordLayer::showCodecPopup(CCObject*) { - FLAlertLayer::create("Codec", "AMD: h264_amf\nNVIDIA: h264_nvenc\nINTEL: h264_qsv\nI don't know: libx264", "Ok")->show(); -} - -void RecordLayer::updateDots() { - for (int i = 0; i < dots.size(); i++) { - if (i == Global::get().currentPage) { - dots[i]->setScale(0.4); - dots[i]->setOpacity(255); - } - else { - dots[i]->setScale(0.3f); - dots[i]->setOpacity(70); } } -} - -bool RecordLayer::init() { - if (!Popup::init(455, 271, Utils::getTexture().c_str())) return false; - auto& g = Global::get(); - mod = g.mod; - - Utils::setBackgroundColor(m_bgSprite); - cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; - m_mainLayer->setPosition(m_mainLayer->getPosition() - offset); - m_closeBtn->setPosition(m_closeBtn->getPosition() + offset); - m_bgSprite->setPosition(m_bgSprite->getPosition() + offset); - - m_closeBtn->setPosition(m_closeBtn->getPosition() + ccp(-6.75, 6.75)); - m_closeBtn->getNormalImage()->setScale(0.575f); - - menu = CCMenu::create(); - m_mainLayer->addChild(menu); - - for (int i = 0; i < settings.size(); i++) { - CCSprite* dot = CCSprite::create("smallDot.png"); - menu->addChild(dot); - dots.push_back(dot); + void RecordLayer::showKeybindsWarning() { + if (!mod->setSavedValue("opened_keybinds", true)) + queueInMainThread([this] { + FLAlertLayer::create( + "Warning", + "Scroll down to find xdBot's keybinds", + "Ok" + )->show(); + }); } - - float spacing = 10.f; - float width = (dots.size() - 1) * spacing; - float center = 103 - (width / 2.0f); - - for (int i = 0; i < dots.size(); ++i) - dots[i]->setPosition({ center + i * spacing, 96.5f }); - - updateDots(); - - warningSprite = CCSprite::createWithSpriteFrameName("geode.loader/info-alert.png"); - warningSprite->setScale(0.675f); - warningSprite->setPosition({ 82, 307 }); - m_mainLayer->addChild(warningSprite); - - warningLabel = CCLabelBMFont::create(("WARNING: Currently recording / playing macros with a frame offset of " + std::to_string(g.frameOffset)).c_str(), "bigFont.fnt"); - warningLabel->setAnchorPoint({ 0, 0.5 }); - warningLabel->setPosition({ 92, 307 }); - warningLabel->setScale(0.275f); - m_mainLayer->addChild(warningLabel); - - warningSprite->setVisible(g.frameOffset != 0); - warningLabel->setVisible(g.frameOffset != 0); - - CCSprite* spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); - CCSprite* spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); - - CCLabelBMFont* versionLabel = CCLabelBMFont::create(("xdBot " + xdBotVersion).c_str(), "chatFont.fnt"); - versionLabel->setOpacity(63); - versionLabel->setPosition(ccp(-217, -125)); - versionLabel->setAnchorPoint({ 0, 0.5 }); - versionLabel->setScale(0.4f); - versionLabel->setSkewX(4); - menu->addChild(versionLabel); - -#ifdef GEODE_IS_WINDOWS - - CCLabelBMFont* codecBtnLbl = CCLabelBMFont::create("?", "chatFont.fnt"); - codecBtnLbl->setOpacity(148); - codecBtnLbl->setScale(0.65f); - - CCMenuItemSpriteExtra* codecBtn = CCMenuItemSpriteExtra::create(codecBtnLbl, this, menu_selector(RecordLayer::showCodecPopup)); - codecBtn->setPosition({ -26, -49 }); - - menu->addChild(codecBtn); - -#endif - - CCScale9Sprite* bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - bg->setScale(0.7f); - bg->setColor({ 0,0,0 }); - bg->setOpacity(75); - bg->setPosition(ccp(-212, 121)); - bg->setAnchorPoint({ 0, 1 }); - bg->setContentSize({ 275, 151 }); - menu->addChild(bg); - - bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - bg->setScale(0.7f); - bg->setColor({ 0,0,0 }); - bg->setOpacity(75); - bg->setPosition(ccp(-212, 0)); - bg->setAnchorPoint({ 0, 1 }); - bg->setContentSize({ 275, 169 }); - menu->addChild(bg); - - bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - bg->setScale(0.7f); - bg->setColor({ 0,0,0 }); - bg->setOpacity(75); - bg->setPosition(ccp(103, 2)); - bg->setContentSize({ 313, 339 }); - menu->addChild(bg); - - recording = CCMenuItemToggler::create(spriteOff, spriteOn, this, menu_selector(RecordLayer::toggleRecording)); - recording->toggle(g.state == state::recording); - - playing = CCMenuItemToggler::create(spriteOff, spriteOn, this, menu_selector(RecordLayer::togglePlaying)); - playing->toggle(g.state == state::playing); - - recording->setPosition(ccp(-161.5, 78)); - recording->setScale(0.775); - playing->setPosition(ccp(-74.5, 78)); - playing->setScale(0.775); - - menu->addChild(recording); - menu->addChild(playing); - - actionsLabel = CCLabelBMFont::create(("Actions: " + std::to_string(g.macro.inputs.size())).c_str(), "chatFont.fnt"); - actionsLabel->limitLabelWidth(57.f, 0.6f, 0.01f); - actionsLabel->updateLabel(); - actionsLabel->setAnchorPoint({ 0, 0.5 }); - actionsLabel->setOpacity(83); - actionsLabel->setPosition(ccp(-201, 110)); - menu->addChild(actionsLabel); - - CCLabelBMFont* lbl = CCLabelBMFont::create("Macro", "goldFont.fnt"); - lbl->setPosition(ccp(-116.5, 112)); - lbl->setScale(0.575f); - menu->addChild(lbl); - - lbl = CCLabelBMFont::create("Render", "goldFont.fnt"); - lbl->setScale(0.6f); - lbl->setPosition(ccp(-116.5, -9)); - menu->addChild(lbl); - - - - lbl = CCLabelBMFont::create("Settings", "goldFont.fnt"); - lbl->setPosition(ccp(103, 111)); - lbl->setScale(0.7f); - menu->addChild(lbl); - - lbl = CCLabelBMFont::create("Record", "bigFont.fnt"); - lbl->setPosition(ccp(-161.5, 60)); - lbl->setScale(0.325f); - menu->addChild(lbl); - - lbl = CCLabelBMFont::create("Play", "bigFont.fnt"); - lbl->setPosition(ccp(-74, 60)); - lbl->setScale(0.325f); - menu->addChild(lbl); - - - lbl = CCLabelBMFont::create("X", "chatFont.fnt"); - lbl->setPosition(ccp(-114.5, -31)); - lbl->setScale(0.7f); - menu->addChild(lbl); - - - - lbl = CCLabelBMFont::create("M", "chatFont.fnt"); - lbl->setPosition(ccp(-164, -59)); - lbl->setScale(0.7f); - menu->addChild(lbl); - - - - lbl = CCLabelBMFont::create("FPS", "chatFont.fnt"); - lbl->setPosition(ccp(-108.5, -59)); - lbl->setScale(0.49f); - menu->addChild(lbl); - - - - ButtonSprite* btnSprite = ButtonSprite::create("Save"); - btnSprite->setScale(0.54f); - - CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(btnSprite, - this, - menu_selector(RecordLayer::openSaveMacro)); - - btn->setPosition(ccp(-176, 34)); - menu->addChild(btn); - -#ifdef GEODE_IS_DESKTOP - btnSprite = ButtonSprite::create("Keybinds"); -#else - btnSprite = ButtonSprite::create("Buttons"); -#endif - btnSprite->setScale(0.54f); - - btn = CCMenuItemSpriteExtra::create(btnSprite, - this, - menu_selector(RecordLayer::openKeybinds)); - - btn->setPosition(ccp(40, -100)); - menu->addChild(btn); - - - btnSprite = ButtonSprite::create("More Settings"); - btnSprite->setScale(0.54f); - - btn = CCMenuItemSpriteExtra::create(btnSprite, - this, - menu_selector(RecordLayer::moreSettings)); - - btn->setPosition(ccp(148, -100)); - menu->addChild(btn); - - btnSprite = ButtonSprite::create("Load"); - btnSprite->setScale(0.54f); - - btn = CCMenuItemSpriteExtra::create(btnSprite, - this, - menu_selector(RecordLayer::openLoadMacro)); - - btn->setPosition(ccp(-115, 34)); - menu->addChild(btn); - - btnSprite = ButtonSprite::create("Edit"); - btnSprite->setScale(0.54f); - - btn = CCMenuItemSpriteExtra::create(btnSprite, - this, - menu_selector(RecordLayer::onEditMacro)); - - btn->setPosition(ccp(-56, 34)); - menu->addChild(btn); - - widthInput = CCTextInputNode::create(150, 30, "Width", "chatFont.fnt"); - widthInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); - widthInput->ignoreAnchorPointForPosition(true); - widthInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); - widthInput->setPosition(ccp(-157, -31)); - widthInput->setMaxLabelScale(0.7f); - widthInput->setMouseEnabled(true); - widthInput->setContentSize({ 60, 20 }); - widthInput->setTouchEnabled(true); - widthInput->setAllowedChars("0123456789"); - widthInput->setString(mod->getSavedValue("render_width2").c_str()); - widthInput->setDelegate(this); - widthInput->setID("render-input"); - menu->addChild(widthInput); - - heightInput = CCTextInputNode::create(150, 30, "Height", "chatFont.fnt"); - heightInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); - heightInput->ignoreAnchorPointForPosition(true); - heightInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); - heightInput->setPosition(ccp(-72.5, -31)); - heightInput->setMaxLabelScale(0.7f); - heightInput->setMouseEnabled(true); - heightInput->setContentSize({ 60, 20 }); - heightInput->setTouchEnabled(true); - heightInput->setAllowedChars("0123456789"); - heightInput->setString(mod->getSavedValue("render_height").c_str()); - heightInput->setDelegate(this); - heightInput->setID("render-input"); - menu->addChild(heightInput); - - bitrateInput = CCTextInputNode::create(150, 30, "br", "chatFont.fnt"); - bitrateInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); - bitrateInput->ignoreAnchorPointForPosition(true); - bitrateInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); - bitrateInput->setPosition(ccp(-185.5, -59)); - bitrateInput->setMaxLabelScale(0.7f); - bitrateInput->setMouseEnabled(true); - bitrateInput->setContentSize({ 32, 20 }); - bitrateInput->setTouchEnabled(true); - bitrateInput->setAllowedChars("0123456789"); - bitrateInput->setString(mod->getSavedValue("render_bitrate").c_str()); - bitrateInput->setDelegate(this); - menu->addChild(bitrateInput); - - CCSprite* emptyBtn = CCSprite::createWithSpriteFrameName("GJ_plainBtn_001.png"); - emptyBtn->setScale(0.67f); - - CCSprite* folderIcon = CCSprite::createWithSpriteFrameName("folderIcon_001.png"); - folderIcon->setPosition(emptyBtn->getContentSize() / 2); - folderIcon->setScale(0.7f); - - emptyBtn->addChild(folderIcon); - btn = CCMenuItemSpriteExtra::create( - emptyBtn, - this, - menu_selector(RecordLayer::openPresets) - ); - btn->setPosition(ccp(-177.5, -97)); - - menu->addChild(btn); - - CCSprite* spr = CCSprite::createWithSpriteFrameName("GJ_optionsBtn_001.png"); - spr->setScale(0.65f); - - btn = CCMenuItemSpriteExtra::create( - spr, - this, - menu_selector(RenderSettingsLayer::open) - ); - btn->setPosition(ccp(-129.5, -97)); - menu->addChild(btn); - - - codecInput = CCTextInputNode::create(150, 30, "Codec", "chatFont.fnt"); - codecInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); - codecInput->ignoreAnchorPointForPosition(true); - codecInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); - codecInput->setPosition(ccp(-70.5, -62)); - codecInput->setMouseEnabled(true); - codecInput->setTouchEnabled(true); - codecInput->setContentSize({ 79, 20 }); - codecInput->setScale(0.75); - codecInput->setString(mod->getSavedValue("render_codec").c_str()); - codecInput->setDelegate(this); - codecInput->setAllowedChars("0123456789abcdefghijklmnopqrstuvwxyz-_.\"\\/"); - codecInput->setMaxLabelWidth(74.f); - menu->addChild(codecInput); - - fpsInput = CCTextInputNode::create(150, 30, "FPS", "chatFont.fnt"); - fpsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); - fpsInput->ignoreAnchorPointForPosition(true); - fpsInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); - fpsInput->m_textLabel->setScale(0.6); - fpsInput->setPosition(ccp(-133, -59)); - fpsInput->setMaxLabelScale(0.7f); - fpsInput->setMouseEnabled(true); - fpsInput->setTouchEnabled(true); - fpsInput->setContentSize({ 32, 20 }); - fpsInput->setAllowedChars("0123456789"); - fpsInput->setString(mod->getSavedValue("render_fps").c_str()); - fpsInput->setDelegate(this); - menu->addChild(fpsInput); - - bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - bg->setScale(0.375f); - bg->setColor({ 0,0,0 }); - bg->setOpacity(75); - bg->setPosition(ccp(-103.5, -21)); - bg->setAnchorPoint({ 0, 1 }); - bg->setContentSize({ 162, 55 }); - bg->setZOrder(29); - menu->addChild(bg); - - bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - bg->setScale(0.375f); - bg->setColor({ 0,0,0 }); - bg->setOpacity(75); - bg->setPosition(ccp(-188, -21)); - bg->setAnchorPoint({ 0, 1 }); - bg->setContentSize({ 162, 55 }); - bg->setZOrder(29); - menu->addChild(bg); - - bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - bg->setScale(0.375f); - bg->setColor({ 0,0,0 }); - bg->setOpacity(75); - bg->setPosition(ccp(-201.5, -49)); - bg->setAnchorPoint({ 0, 1 }); - bg->setContentSize({ 82, 55 }); - bg->setZOrder(29); - menu->addChild(bg); - - bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - bg->setScale(0.375f); - bg->setColor({ 0,0,0 }); - bg->setOpacity(75); - bg->setPosition(ccp(-148.5, -49)); - bg->setAnchorPoint({ 0, 1 }); - bg->setContentSize({ 82, 55 }); - bg->setZOrder(29); - menu->addChild(bg); - - bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - bg->setScale(0.375f); - bg->setColor({ 0,0,0 }); - bg->setOpacity(75); - bg->setPosition(ccp(-92, -49)); - bg->setAnchorPoint({ 0, 1 }); - bg->setContentSize({ 167, 55 }); - bg->setZOrder(29); - menu->addChild(bg); - - #ifdef GEODE_IS_IOS - ButtonSprite* spriteOn2 = ButtonSprite::create("N/A"); - spriteOn2->setScale(0.74f); - ButtonSprite* spriteOff2 = ButtonSprite::create("N/A"); - spriteOff2->setScale(0.74f); - #else - ButtonSprite* spriteOn2 = ButtonSprite::create("Stop"); - spriteOn2->setScale(0.74f); - ButtonSprite* spriteOff2 = ButtonSprite::create("Start"); - spriteOff2->setScale(0.74f); - #endif + void RecordLayer::openKeybinds(CCObject*) { + #ifdef GEODE_IS_DESKTOP + + geode::openSettingsPopup(Mod::get(), false); + RecordLayer::showKeybindsWarning(); + + #else + + Interface::openButtonEditor(); + + #endif + } - //#ifdef GEODE_IS_IOS - renderToggle = CCMenuItemToggler::create(spriteOn2, spriteOff2, this, menu_selector(RecordLayer::toggleRenderIOS)); - renderToggle->setPosition(ccp(-65.5, -100)); - menu->addChild(renderToggle); - // #else - // renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRender)); - // renderToggle->toggle(g.renderer.recording || g.renderer.recordingAudio); - - renderToggle->setPosition(ccp(-65.5, -100)); - menu->addChild(renderToggle); - // #endif - - spr = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png"); - spr->setScale(0.65f); - btn = CCMenuItemSpriteExtra::create( - spr, - this, - menu_selector(RecordLayer::macroInfo) - ); - btn->setPosition(ccp(-36, 107)); - menu->addChild(btn); - - spr = CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"); - spr->setScale(0.58f); - btn = CCMenuItemSpriteExtra::create( - spr, - this, - menu_selector(RecordLayer::updatePage) - ); - btn->setPosition(ccp(-5, 0)); - btn->setID("page-left"); - menu->addChild(btn); - - spr = CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"); - spr->setScale(0.58f); - spr->setScaleX(-0.58f); - btn = CCMenuItemSpriteExtra::create( - spr, - this, - menu_selector(RecordLayer::updatePage) - ); - btn->setPosition(ccp(209, 4.3)); - btn->setContentSize({ 26, 32.4 }); - menu->addChild(btn); - static_cast(btn->getChildren()->objectAtIndex(0))->setPositionX(13); - - for (int i = 0; i < 7; i++) { - CCLabelBMFont* lbl = CCLabelBMFont::create("_______________________", "chatFont.fnt"); - lbl->setPosition(ccp(103, 97 - (i * 29))); - lbl->setColor(ccc3(0, 0, 0)); - lbl->setOpacity(80); - menu->addChild(lbl); + void RecordLayer::openPresets(CCObject*) { + RenderPresetsLayer::create()->show(); } - - if (!mod->getSettingValue("restore_page")) - g.currentPage = 0; - - goToSettingsPage(g.currentPage); - - CCSprite* dickordSpr = CCSprite::createWithSpriteFrameName("gj_discordIcon_001.png"); - dickordSpr->setScale(0.9f); - CCMenuItemSpriteExtra* dickordBtn = CCMenuItemSpriteExtra::create(dickordSpr, this, menu_selector(RecordLayer::onDiscord)); - dickordBtn->setPosition((CCDirector::sharedDirector()->getWinSize() / 2 - m_size / 2 + ccp(-16, 16))); - m_buttonMenu->addChild(dickordBtn); - - if (!Mod::get()->setSavedValue("dickord", true)) - dickordSpr->runAction(CCSequence::create(CCScaleTo::create(0.25f, 1.5f), CCRotateTo::create(0.25f, 90), CCRotateTo::create(0.25f, 180), CCRotateTo::create(0.25f, 270), CCRotateTo::create(0.25f, 0), CCScaleTo::create(0.25f, 0.9f), nullptr)); - - return true; -} - -void RecordLayer::setToggleMember(CCMenuItemToggler* toggle, std::string id) { - if (id == "macro_speedhack_enabled") speedhackToggle = toggle; - if (id == "macro_show_trajectory") trajectoryToggle = toggle; - if (id == "macro_noclip") noclipToggle = toggle; - if (id == "macro_frame_stepper") frameStepperToggle = toggle; - if (id == "macro_tps_enabled") tpsToggle = toggle; -} - -void RecordLayer::loadSetting(RecordSetting sett, float yPos) { - CCLabelBMFont* lbl = CCLabelBMFont::create(sett.name.c_str(), "bigFont.fnt"); - lbl->setPosition(ccp(19.f, yPos)); - lbl->setAnchorPoint({ 0, 0.5 }); - lbl->setOpacity(200); - lbl->setScale(sett.labelScale); - - nodes.push_back(static_cast(lbl)); - menu->addChild(lbl); - - CCSprite* spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); - CCSprite* spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); - float toggleScale = 0.555f; - - if (sett.disabled) { - // Code when disabled xD! + + void RecordLayer::onAutosaves(CCObject*) { + std::filesystem::path path = Mod::get()->getSettingValue("autosaves_folder"); + + if (std::filesystem::exists(path)) + LoadMacroLayer::open(static_cast(this), nullptr, true); + else { + FLAlertLayer::create("Error", "There was an error getting the folder. ID: 5", "Ok")->show(); + } } - - CCMenuItemToggler* toggle = CCMenuItemToggler::create(spriteOff, spriteOn, this, menu_selector(RecordLayer::toggleSetting)); - toggle->setPosition(ccp(175, yPos)); - toggle->setScale(toggleScale); - toggle->toggle(mod->getSavedValue(sett.id)); - toggle->setID(sett.id.c_str()); - - nodes.push_back(static_cast(toggle)); - menu->addChild(toggle); - - setToggleMember(toggle, sett.id); - - if (sett.input == InputType::None) return; - - if (sett.input == InputType::Settings) { - CCSprite* spr = CCSprite::createWithSpriteFrameName("GJ_optionsBtn_001.png"); - spr->setScale(0.41f); - spr->setOpacity(215); - - CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create( - spr, - this, - sett.callback - ); - btn->setPosition(ccp(138, yPos)); - - nodes.push_back(static_cast(btn)); - menu->addChild(btn); + + void RecordLayer::showCodecPopup(CCObject*) { + FLAlertLayer::create("Codec", "AMD: h264_amf\nNVIDIA: h264_nvenc\nINTEL: h264_qsv\nI don't know: libx264", "Ok")->show(); } - - if (sett.input == InputType::Autosave) { - CCSprite* emptyBtn = CCSprite::createWithSpriteFrameName("GJ_plainBtn_001.png"); - emptyBtn->setScale(0.469f); - - CCSprite* folderIcon = CCSprite::createWithSpriteFrameName("folderIcon_001.png"); - folderIcon->setPosition(emptyBtn->getContentSize() / 2); - folderIcon->setScale(0.7f); - emptyBtn->addChild(folderIcon); - - CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create( - emptyBtn, - this, - menu_selector(RecordLayer::onAutosaves) - ); - btn->setPosition(ccp(147, yPos)); - - nodes.push_back(static_cast(btn)); - menu->addChild(btn); + + void RecordLayer::updateDots() { + for (int i = 0; i < dots.size(); i++) { + if (i == Global::get().currentPage) { + dots[i]->setScale(0.4); + dots[i]->setOpacity(255); + } + else { + dots[i]->setScale(0.3f); + dots[i]->setOpacity(70); + } + } } - - if (sett.input == InputType::Speedhack) { + + bool RecordLayer::init() { + if (!Popup::init(455, 271, Utils::getTexture().c_str())) return false; + auto& g = Global::get(); + mod = g.mod; + + Utils::setBackgroundColor(m_bgSprite); + + cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; + m_mainLayer->setPosition(m_mainLayer->getPosition() - offset); + m_closeBtn->setPosition(m_closeBtn->getPosition() + offset); + m_bgSprite->setPosition(m_bgSprite->getPosition() + offset); + + m_closeBtn->setPosition(m_closeBtn->getPosition() + ccp(-6.75, 6.75)); + m_closeBtn->getNormalImage()->setScale(0.575f); + + menu = CCMenu::create(); + m_mainLayer->addChild(menu); + + for (int i = 0; i < settings.size(); i++) { + CCSprite* dot = CCSprite::create("smallDot.png"); + menu->addChild(dot); + dots.push_back(dot); + } + + float spacing = 10.f; + float width = (dots.size() - 1) * spacing; + float center = 103 - (width / 2.0f); + + for (int i = 0; i < dots.size(); ++i) + dots[i]->setPosition({ center + i * spacing, 96.5f }); + + updateDots(); + + warningSprite = CCSprite::createWithSpriteFrameName("geode.loader/info-alert.png"); + warningSprite->setScale(0.675f); + warningSprite->setPosition({ 82, 307 }); + m_mainLayer->addChild(warningSprite); + + warningLabel = CCLabelBMFont::create(("WARNING: Currently recording / playing macros with a frame offset of " + std::to_string(g.frameOffset)).c_str(), "bigFont.fnt"); + warningLabel->setAnchorPoint({ 0, 0.5 }); + warningLabel->setPosition({ 92, 307 }); + warningLabel->setScale(0.275f); + m_mainLayer->addChild(warningLabel); + + warningSprite->setVisible(g.frameOffset != 0); + warningLabel->setVisible(g.frameOffset != 0); + + CCSprite* spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); + CCSprite* spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); + + CCLabelBMFont* versionLabel = CCLabelBMFont::create(("xdBot " + xdBotVersion).c_str(), "chatFont.fnt"); + versionLabel->setOpacity(63); + versionLabel->setPosition(ccp(-217, -125)); + versionLabel->setAnchorPoint({ 0, 0.5 }); + versionLabel->setScale(0.4f); + versionLabel->setSkewX(4); + menu->addChild(versionLabel); + + #ifdef GEODE_IS_WINDOWS + + CCLabelBMFont* codecBtnLbl = CCLabelBMFont::create("?", "chatFont.fnt"); + codecBtnLbl->setOpacity(148); + codecBtnLbl->setScale(0.65f); + + CCMenuItemSpriteExtra* codecBtn = CCMenuItemSpriteExtra::create(codecBtnLbl, this, menu_selector(RecordLayer::showCodecPopup)); + codecBtn->setPosition({ -26, -49 }); + + menu->addChild(codecBtn); + + #endif + CCScale9Sprite* bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - bg->setPosition(ccp(110, yPos + 10)); - bg->setScale(0.355f); + bg->setScale(0.7f); bg->setColor({ 0,0,0 }); bg->setOpacity(75); + bg->setPosition(ccp(-212, 121)); bg->setAnchorPoint({ 0, 1 }); - bg->setContentSize({ 100, 55 }); - bg->setZOrder(29); - nodes.push_back(static_cast(bg)); + bg->setContentSize({ 275, 151 }); menu->addChild(bg); - - speedhackInput = CCTextInputNode::create(150, 30, "SH", "chatFont.fnt"); - speedhackInput->setPosition(ccp(127.5, yPos)); - speedhackInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); - speedhackInput->ignoreAnchorPointForPosition(true); - speedhackInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); - speedhackInput->m_textLabel->setScale(0.6); - speedhackInput->setMaxLabelScale(0.7f); - speedhackInput->setMouseEnabled(true); - speedhackInput->setTouchEnabled(true); - speedhackInput->setContentSize({ 32, 20 }); - speedhackInput->setAllowedChars("0123456789."); - speedhackInput->setString(mod->getSavedValue("macro_speedhack").c_str()); - speedhackInput->setMaxLabelWidth(30.f); - speedhackInput->setDelegate(this); - speedhackInput->setMaxLabelLength(6); - - nodes.push_back(static_cast(speedhackInput)); - menu->addChild(speedhackInput); - } - - if (sett.input == InputType::Tps) { - tpsBg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - tpsBg->setPosition(ccp(116, yPos + 10)); - tpsBg->setScale(0.355f); - tpsBg->setColor({ 0,0,0 }); - tpsBg->setOpacity(75); - tpsBg->setAnchorPoint({ 0, 1 }); - tpsBg->setContentSize({ 100, 55 }); - tpsBg->setZOrder(29); - nodes.push_back(static_cast(tpsBg)); - menu->addChild(tpsBg); - - tpsInput = CCTextInputNode::create(150, 30, "tps", "chatFont.fnt"); - tpsInput->setPosition(ccp(133.5, yPos)); - tpsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); - tpsInput->ignoreAnchorPointForPosition(true); - tpsInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); - tpsInput->m_textLabel->setScale(0.6); - tpsInput->setMaxLabelScale(0.7f); - tpsInput->setMouseEnabled(true); - tpsInput->setTouchEnabled(true); - tpsInput->setContentSize({ 32, 20 }); - tpsInput->setAllowedChars("0123456789."); - tpsInput->setString(Utils::getSimplifiedString(fmt::format("{:.3f}", Mod::get()->getSavedValue("macro_tps"))).c_str()); - tpsInput->setMaxLabelWidth(30.f); - tpsInput->setDelegate(this); - tpsInput->setMaxLabelLength(9); - - nodes.push_back(static_cast(tpsInput)); - menu->addChild(tpsInput); - } - - if (sett.input == InputType::Seed) { - CCScale9Sprite* bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - bg->setPosition(ccp(64, yPos + 10)); - bg->setScale(0.355f); + + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); + bg->setScale(0.7f); bg->setColor({ 0,0,0 }); bg->setOpacity(75); + bg->setPosition(ccp(-212, 0)); bg->setAnchorPoint({ 0, 1 }); - bg->setContentSize({ 258, 55 }); - bg->setZOrder(29); - nodes.push_back(static_cast(bg)); + bg->setContentSize({ 275, 169 }); menu->addChild(bg); - - seedInput = CCTextInputNode::create(150, 30, "Seed", "chatFont.fnt"); - seedInput->setPosition(ccp(109.5, yPos)); - seedInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); - seedInput->ignoreAnchorPointForPosition(true); - seedInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); - seedInput->m_textLabel->setScale(0.6); - seedInput->setMaxLabelScale(0.7f); - seedInput->setMouseEnabled(true); - seedInput->setTouchEnabled(true); - seedInput->setContentSize({ 85, 20 }); - seedInput->setAllowedChars("0123456789"); - seedInput->setString(mod->getSavedValue("macro_seed").c_str()); - seedInput->setMaxLabelWidth(70.f); - seedInput->setDelegate(this); - seedInput->setMaxLabelLength(20); - - nodes.push_back(static_cast(seedInput)); - menu->addChild(seedInput); - } - - if (sett.input == InputType::Respawn) { - CCScale9Sprite* bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); - bg->setPosition(ccp(110, yPos + 10)); - bg->setScale(0.355f); + + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); + bg->setScale(0.7f); bg->setColor({ 0,0,0 }); bg->setOpacity(75); - bg->setAnchorPoint({ 0, 1 }); - bg->setContentSize({ 100, 55 }); - bg->setZOrder(29); - nodes.push_back(static_cast(bg)); + bg->setPosition(ccp(103, 2)); + bg->setContentSize({ 313, 339 }); menu->addChild(bg); - - respawnInput = CCTextInputNode::create(150, 30, "sec", "chatFont.fnt"); - respawnInput->setPosition(ccp(127.5, yPos)); - respawnInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); - respawnInput->ignoreAnchorPointForPosition(true); - respawnInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); - respawnInput->m_textLabel->setScale(0.6); - respawnInput->setMaxLabelScale(0.7f); - respawnInput->setMouseEnabled(true); - respawnInput->setTouchEnabled(true); - respawnInput->setContentSize({ 32.f, 20.f }); - respawnInput->setAllowedChars("0123456789."); - respawnInput->setString(fmt::format("{:.2}", mod->getSavedValue("respawn_time")).c_str()); - respawnInput->setMaxLabelWidth(30.f); - respawnInput->setDelegate(this); - respawnInput->setMaxLabelLength(4); - - nodes.push_back(static_cast(respawnInput)); - menu->addChild(respawnInput); - } -} - -void RecordLayer::goToSettingsPage(int page) { - checkSpeedhack(); - - for (size_t i = 0; i < nodes.size(); i++) - nodes[i]->removeFromParentAndCleanup(false); - - nodes.clear(); - - speedhackToggle = nullptr; - frameStepperToggle = nullptr; - trajectoryToggle = nullptr; - noclipToggle = nullptr; - tpsToggle = nullptr; - - speedhackInput = nullptr; - respawnInput = nullptr; - seedInput = nullptr; - tpsInput = nullptr; - - tpsBg = nullptr; - - for (size_t i = 0; i < 6; i++) - loadSetting(settings[page][i], ySettingPositions[i]); - - updateDots(); - updateTPS(); - - Mod::get()->setSavedValue("current_page", page); -} - -void RecordLayer::onDiscord(CCObject*) { - geode::createQuickPopup( - "Discord", - "Join the Discord server?\n(discord.gg/w6yvdzVzBd).", - "No", "Yes", - [](auto, bool btn2) { - if (btn2) - geode::utils::web::openLinkInBrowser("https://discord.gg/w6yvdzVzBd"); - } - ); -} - -void RecordLayer::updateTPS() { - if (!tpsInput || !tpsToggle || !tpsBg) return; - auto& g = Global::get(); - - tpsToggle->toggle(g.tpsEnabled); - tpsInput->setString(Utils::getSimplifiedString(fmt::format("{:.3f}", Mod::get()->getSavedValue("macro_tps"))).c_str()); - - if (g.state == state::none || g.macro.inputs.empty()) { - if (CCMenuItemSpriteExtra* btn = tpsToggle->getChildByType(0)) - if (CCSprite* spr = btn->getChildByType(0)) - spr->setOpacity(255); - if (CCMenuItemSpriteExtra* btn = tpsToggle->getChildByType(1)) - if (CCSprite* spr = btn->getChildByType(0)) - spr->setOpacity(255); - - tpsInput->setID(""); - tpsBg->setOpacity(75); - tpsToggle->setEnabled(true); - tpsInput->m_textLabel->setOpacity(255); - - tpsInput->detachWithIME(); - tpsInput->onClickTrackNode(false); - tpsInput->m_cursor->setVisible(false); - } else { - if (CCMenuItemSpriteExtra* btn = tpsToggle->getChildByType(0)) - if (CCSprite* spr = btn->getChildByType(0)) - spr->setOpacity(120); - if (CCMenuItemSpriteExtra* btn = tpsToggle->getChildByType(1)) - if (CCSprite* spr = btn->getChildByType(0)) - spr->setOpacity(120); - - tpsInput->setID("disabled-input"_spr); - tpsBg->setOpacity(30); - tpsToggle->setEnabled(false); - tpsInput->m_textLabel->setOpacity(120); - - tpsInput->detachWithIME(); - tpsInput->onClickTrackNode(false); - tpsInput->m_cursor->setVisible(false); - } -} + + recording = CCMenuItemToggler::create(spriteOff, spriteOn, this, menu_selector(RecordLayer::toggleRecording)); + recording->toggle(g.state == state::recording); + + playing = CCMenuItemToggler::create(spriteOff, spriteOn, this, menu_selector(RecordLayer::togglePlaying)); + playing->toggle(g.state == state::playing); + + recording->setPosition(ccp(-161.5, 78)); + recording->setScale(0.775); + playing->setPosition(ccp(-74.5, 78)); + playing->setScale(0.775); + + menu->addChild(recording); + menu->addChild(playing); + + actionsLabel = CCLabelBMFont::create(("Actions: " + std::to_string(g.macro.inputs.size())).c_str(), "chatFont.fnt"); + actionsLabel->limitLabelWidth(57.f, 0.6f, 0.01f); + actionsLabel->updateLabel(); + actionsLabel->setAnchorPoint({ 0, 0.5 }); + actionsLabel->setOpacity(83); + actionsLabel->setPosition(ccp(-201, 110)); + menu->addChild(actionsLabel); + + CCLabelBMFont* lbl = CCLabelBMFont::create("Macro", "goldFont.fnt"); + lbl->setPosition(ccp(-116.5, 112)); + lbl->setScale(0.575f); + menu->addChild(lbl); + + lbl = CCLabelBMFont::create("Render", "goldFont.fnt"); + lbl->setScale(0.6f); + lbl->setPosition(ccp(-116.5, -9)); + menu->addChild(lbl); + + + + lbl = CCLabelBMFont::create("Settings", "goldFont.fnt"); + lbl->setPosition(ccp(103, 111)); + lbl->setScale(0.7f); + menu->addChild(lbl); + + lbl = CCLabelBMFont::create("Record", "bigFont.fnt"); + lbl->setPosition(ccp(-161.5, 60)); + lbl->setScale(0.325f); + menu->addChild(lbl); + + lbl = CCLabelBMFont::create("Play", "bigFont.fnt"); + lbl->setPosition(ccp(-74, 60)); + lbl->setScale(0.325f); + menu->addChild(lbl); + + + + lbl = CCLabelBMFont::create("X", "chatFont.fnt"); + lbl->setPosition(ccp(-114.5, -31)); + lbl->setScale(0.7f); + menu->addChild(lbl); + + + + lbl = CCLabelBMFont::create("M", "chatFont.fnt"); + lbl->setPosition(ccp(-164, -59)); + lbl->setScale(0.7f); + menu->addChild(lbl); + + + + lbl = CCLabelBMFont::create("FPS", "chatFont.fnt"); + lbl->setPosition(ccp(-108.5, -59)); + lbl->setScale(0.49f); + menu->addChild(lbl); + + + + ButtonSprite* btnSprite = ButtonSprite::create("Save"); + btnSprite->setScale(0.54f); + + CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(btnSprite, + this, + menu_selector(RecordLayer::openSaveMacro)); + + btn->setPosition(ccp(-176, 34)); + menu->addChild(btn); + + #ifdef GEODE_IS_DESKTOP + btnSprite = ButtonSprite::create("Keybinds"); + #else + btnSprite = ButtonSprite::create("Buttons"); + #endif + btnSprite->setScale(0.54f); + + btn = CCMenuItemSpriteExtra::create(btnSprite, + this, + menu_selector(RecordLayer::openKeybinds)); + + btn->setPosition(ccp(40, -100)); + menu->addChild(btn); + + + btnSprite = ButtonSprite::create("More Settings"); + btnSprite->setScale(0.54f); + + btn = CCMenuItemSpriteExtra::create(btnSprite, + this, + menu_selector(RecordLayer::moreSettings)); + + btn->setPosition(ccp(148, -100)); + menu->addChild(btn); + + btnSprite = ButtonSprite::create("Load"); + btnSprite->setScale(0.54f); + + btn = CCMenuItemSpriteExtra::create(btnSprite, + this, + menu_selector(RecordLayer::openLoadMacro)); + + btn->setPosition(ccp(-115, 34)); + menu->addChild(btn); + + btnSprite = ButtonSprite::create("Edit"); + btnSprite->setScale(0.54f); + + btn = CCMenuItemSpriteExtra::create(btnSprite, + this, + menu_selector(RecordLayer::onEditMacro)); + + btn->setPosition(ccp(-56, 34)); + menu->addChild(btn); + + widthInput = CCTextInputNode::create(150, 30, "Width", "chatFont.fnt"); + widthInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); + widthInput->ignoreAnchorPointForPosition(true); + widthInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + widthInput->setPosition(ccp(-157, -31)); + widthInput->setMaxLabelScale(0.7f); + widthInput->setMouseEnabled(true); + widthInput->setContentSize({ 60, 20 }); + widthInput->setTouchEnabled(true); + widthInput->setAllowedChars("0123456789"); + widthInput->setString(mod->getSavedValue("render_width2").c_str()); + widthInput->setDelegate(this); + widthInput->setID("render-input"); + menu->addChild(widthInput); + + heightInput = CCTextInputNode::create(150, 30, "Height", "chatFont.fnt"); + heightInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); + heightInput->ignoreAnchorPointForPosition(true); + heightInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + heightInput->setPosition(ccp(-72.5, -31)); + heightInput->setMaxLabelScale(0.7f); + heightInput->setMouseEnabled(true); + heightInput->setContentSize({ 60, 20 }); + heightInput->setTouchEnabled(true); + heightInput->setAllowedChars("0123456789"); + heightInput->setString(mod->getSavedValue("render_height").c_str()); + heightInput->setDelegate(this); + heightInput->setID("render-input"); + menu->addChild(heightInput); + + bitrateInput = CCTextInputNode::create(150, 30, "br", "chatFont.fnt"); + bitrateInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); + bitrateInput->ignoreAnchorPointForPosition(true); + bitrateInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + bitrateInput->setPosition(ccp(-185.5, -59)); + bitrateInput->setMaxLabelScale(0.7f); + bitrateInput->setMouseEnabled(true); + bitrateInput->setContentSize({ 32, 20 }); + bitrateInput->setTouchEnabled(true); + bitrateInput->setAllowedChars("0123456789"); + bitrateInput->setString(mod->getSavedValue("render_bitrate").c_str()); + bitrateInput->setDelegate(this); + menu->addChild(bitrateInput); + + CCSprite* emptyBtn = CCSprite::createWithSpriteFrameName("GJ_plainBtn_001.png"); + emptyBtn->setScale(0.67f); + + CCSprite* folderIcon = CCSprite::createWithSpriteFrameName("folderIcon_001.png"); + folderIcon->setPosition(emptyBtn->getContentSize() / 2); + folderIcon->setScale(0.7f); + + emptyBtn->addChild(folderIcon); + btn = CCMenuItemSpriteExtra::create( + emptyBtn, + this, + menu_selector(RecordLayer::openPresets) + ); + btn->setPosition(ccp(-177.5, -97)); + + menu->addChild(btn); + + CCSprite* spr = CCSprite::createWithSpriteFrameName("GJ_optionsBtn_001.png"); + spr->setScale(0.65f); + + btn = CCMenuItemSpriteExtra::create( + spr, + this, + menu_selector(RenderSettingsLayer::open) + ); + btn->setPosition(ccp(-129.5, -97)); + menu->addChild(btn); + + + codecInput = CCTextInputNode::create(150, 30, "Codec", "chatFont.fnt"); + codecInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); + codecInput->ignoreAnchorPointForPosition(true); + codecInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + codecInput->setPosition(ccp(-70.5, -62)); + codecInput->setMouseEnabled(true); + codecInput->setTouchEnabled(true); + codecInput->setContentSize({ 79, 20 }); + codecInput->setScale(0.75); + codecInput->setString(mod->getSavedValue("render_codec").c_str()); + codecInput->setDelegate(this); + codecInput->setAllowedChars("0123456789abcdefghijklmnopqrstuvwxyz-_.\"\\/"); + codecInput->setMaxLabelWidth(74.f); + menu->addChild(codecInput); + + fpsInput = CCTextInputNode::create(150, 30, "FPS", "chatFont.fnt"); + fpsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); + fpsInput->ignoreAnchorPointForPosition(true); + fpsInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + fpsInput->m_textLabel->setScale(0.6); + fpsInput->setPosition(ccp(-133, -59)); + fpsInput->setMaxLabelScale(0.7f); + fpsInput->setMouseEnabled(true); + fpsInput->setTouchEnabled(true); + fpsInput->setContentSize({ 32, 20 }); + fpsInput->setAllowedChars("0123456789"); + fpsInput->setString(mod->getSavedValue("render_fps").c_str()); + fpsInput->setDelegate(this); + menu->addChild(fpsInput); + + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); + bg->setScale(0.375f); + bg->setColor({ 0,0,0 }); + bg->setOpacity(75); + bg->setPosition(ccp(-103.5, -21)); + bg->setAnchorPoint({ 0, 1 }); + bg->setContentSize({ 162, 55 }); + bg->setZOrder(29); + menu->addChild(bg); + + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); + bg->setScale(0.375f); + bg->setColor({ 0,0,0 }); + bg->setOpacity(75); + bg->setPosition(ccp(-188, -21)); + bg->setAnchorPoint({ 0, 1 }); + bg->setContentSize({ 162, 55 }); + bg->setZOrder(29); + menu->addChild(bg); + + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); + bg->setScale(0.375f); + bg->setColor({ 0,0,0 }); + bg->setOpacity(75); + bg->setPosition(ccp(-201.5, -49)); + bg->setAnchorPoint({ 0, 1 }); + bg->setContentSize({ 82, 55 }); + bg->setZOrder(29); + menu->addChild(bg); + + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); + bg->setScale(0.375f); + bg->setColor({ 0,0,0 }); + bg->setOpacity(75); + bg->setPosition(ccp(-148.5, -49)); + bg->setAnchorPoint({ 0, 1 }); + bg->setContentSize({ 82, 55 }); + bg->setZOrder(29); + menu->addChild(bg); + + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); + bg->setScale(0.375f); + bg->setColor({ 0,0,0 }); + bg->setOpacity(75); + bg->setPosition(ccp(-92, -49)); + bg->setAnchorPoint({ 0, 1 }); + bg->setContentSize({ 167, 55 }); + bg->setZOrder(29); + menu->addChild(bg); + + ButtonSprite* spriteOn2 = ButtonSprite::create("N/A"); + spriteOn2->setScale(0.74f); + ButtonSprite* spriteOff2 = ButtonSprite::create("N/A"); + spriteOff2->setScale(0.74f); + // ButtonSprite* spriteOn2 = ButtonSprite::create("Stop"); + // spriteOn2->setScale(0.74f); + // ButtonSprite* spriteOff2 = ButtonSprite::create("Start"); + // spriteOff2->setScale(0.74f); + + //#ifdef GEODE_IS_IOS + renderToggle = CCMenuItemToggler::create(spriteOn2, spriteOff2, this, menu_selector(RecordLayer::toggleRenderIOS)); + renderToggle->setPosition(ccp(-65.5, -100)); + menu->addChild(renderToggle); + // #else + // renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRender)); + // renderToggle->toggle(g.renderer.recording || g.renderer.recordingAudio); + + renderToggle->setPosition(ccp(-65.5, -100)); + menu->addChild(renderToggle); + // #endif + + spr = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png"); + spr->setScale(0.65f); + btn = CCMenuItemSpriteExtra::create( + spr, + this, + menu_selector(RecordLayer::macroInfo) + ); + btn->setPosition(ccp(-36, 107)); + menu->addChild(btn); + + spr = CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"); + spr->setScale(0.58f); + btn = CCMenuItemSpriteExtra::create( + spr, + this, + menu_selector(RecordLayer::updatePage) + ); + btn->setPosition(ccp(-5, 0)); + btn->setID("page-left"); + menu->addChild(btn); + + spr = CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"); + spr->setScale(0.58f); + spr->setScaleX(-0.58f); + btn = CCMenuItemSpriteExtra::create( + spr, + this, + menu_selector(RecordLayer::updatePage) + ); + btn->setPosition(ccp(209, 4.3)); + btn->setContentSize({ 26, 32.4 }); + menu->addChild(btn); + static_cast(btn->getChildren()->objectAtIndex(0))->setPositionX(13); + + for (int i = 0; i < 7; i++) { + CCLabelBMFont* lbl = CCLabelBMFont::create("_______________________", "chatFont.fnt"); + lbl->setPosition(ccp(103, 97 - (i * 29))); + lbl->setColor(ccc3(0, 0, 0)); + lbl->setOpacity(80); + menu->addChild(lbl); + } + + if (!mod->getSettingValue("restore_page")) + g.currentPage = 0; + + goToSettingsPage(g.currentPage); + + CCSprite* dickordSpr = CCSprite::createWithSpriteFrameName("gj_discordIcon_001.png"); + dickordSpr->setScale(0.9f); + CCMenuItemSpriteExtra* dickordBtn = CCMenuItemSpriteExtra::create(dickordSpr, this, menu_selector(RecordLayer::onDiscord)); + dickordBtn->setPosition((CCDirector::sharedDirector()->getWinSize() / 2 - m_size / 2 + ccp(-16, 16))); + m_buttonMenu->addChild(dickordBtn); + + if (!Mod::get()->setSavedValue("dickord", true)) + dickordSpr->runAction(CCSequence::create(CCScaleTo::create(0.25f, 1.5f), CCRotateTo::create(0.25f, 90), CCRotateTo::create(0.25f, 180), CCRotateTo::create(0.25f, 270), CCRotateTo::create(0.25f, 0), CCScaleTo::create(0.25f, 0.9f), nullptr)); + + return true; + } + + void RecordLayer::setToggleMember(CCMenuItemToggler* toggle, std::string id) { + if (id == "macro_speedhack_enabled") speedhackToggle = toggle; + if (id == "macro_show_trajectory") trajectoryToggle = toggle; + if (id == "macro_noclip") noclipToggle = toggle; + if (id == "macro_frame_stepper") frameStepperToggle = toggle; + if (id == "macro_tps_enabled") tpsToggle = toggle; + } + + void RecordLayer::loadSetting(RecordSetting sett, float yPos) { + CCLabelBMFont* lbl = CCLabelBMFont::create(sett.name.c_str(), "bigFont.fnt"); + lbl->setPosition(ccp(19.f, yPos)); + lbl->setAnchorPoint({ 0, 0.5 }); + lbl->setOpacity(200); + lbl->setScale(sett.labelScale); + + nodes.push_back(static_cast(lbl)); + menu->addChild(lbl); + + CCSprite* spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); + CCSprite* spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); + float toggleScale = 0.555f; + + if (sett.disabled) { + // Code when disabled xD! + } + + CCMenuItemToggler* toggle = CCMenuItemToggler::create(spriteOff, spriteOn, this, menu_selector(RecordLayer::toggleSetting)); + toggle->setPosition(ccp(175, yPos)); + toggle->setScale(toggleScale); + toggle->toggle(mod->getSavedValue(sett.id)); + toggle->setID(sett.id.c_str()); + + nodes.push_back(static_cast(toggle)); + menu->addChild(toggle); + + setToggleMember(toggle, sett.id); + + if (sett.input == InputType::None) return; + + if (sett.input == InputType::Settings) { + CCSprite* spr = CCSprite::createWithSpriteFrameName("GJ_optionsBtn_001.png"); + spr->setScale(0.41f); + spr->setOpacity(215); + + CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create( + spr, + this, + sett.callback + ); + btn->setPosition(ccp(138, yPos)); + + nodes.push_back(static_cast(btn)); + menu->addChild(btn); + } + + if (sett.input == InputType::Autosave) { + CCSprite* emptyBtn = CCSprite::createWithSpriteFrameName("GJ_plainBtn_001.png"); + emptyBtn->setScale(0.469f); + + CCSprite* folderIcon = CCSprite::createWithSpriteFrameName("folderIcon_001.png"); + folderIcon->setPosition(emptyBtn->getContentSize() / 2); + folderIcon->setScale(0.7f); + emptyBtn->addChild(folderIcon); + + CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create( + emptyBtn, + this, + menu_selector(RecordLayer::onAutosaves) + ); + btn->setPosition(ccp(147, yPos)); + + nodes.push_back(static_cast(btn)); + menu->addChild(btn); + } + + if (sett.input == InputType::Speedhack) { + CCScale9Sprite* bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); + bg->setPosition(ccp(110, yPos + 10)); + bg->setScale(0.355f); + bg->setColor({ 0,0,0 }); + bg->setOpacity(75); + bg->setAnchorPoint({ 0, 1 }); + bg->setContentSize({ 100, 55 }); + bg->setZOrder(29); + nodes.push_back(static_cast(bg)); + menu->addChild(bg); + + speedhackInput = CCTextInputNode::create(150, 30, "SH", "chatFont.fnt"); + speedhackInput->setPosition(ccp(127.5, yPos)); + speedhackInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); + speedhackInput->ignoreAnchorPointForPosition(true); + speedhackInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + speedhackInput->m_textLabel->setScale(0.6); + speedhackInput->setMaxLabelScale(0.7f); + speedhackInput->setMouseEnabled(true); + speedhackInput->setTouchEnabled(true); + speedhackInput->setContentSize({ 32, 20 }); + speedhackInput->setAllowedChars("0123456789."); + speedhackInput->setString(mod->getSavedValue("macro_speedhack").c_str()); + speedhackInput->setMaxLabelWidth(30.f); + speedhackInput->setDelegate(this); + speedhackInput->setMaxLabelLength(6); + + nodes.push_back(static_cast(speedhackInput)); + menu->addChild(speedhackInput); + } + + if (sett.input == InputType::Tps) { + tpsBg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); + tpsBg->setPosition(ccp(116, yPos + 10)); + tpsBg->setScale(0.355f); + tpsBg->setColor({ 0,0,0 }); + tpsBg->setOpacity(75); + tpsBg->setAnchorPoint({ 0, 1 }); + tpsBg->setContentSize({ 100, 55 }); + tpsBg->setZOrder(29); + nodes.push_back(static_cast(tpsBg)); + menu->addChild(tpsBg); + + tpsInput = CCTextInputNode::create(150, 30, "tps", "chatFont.fnt"); + tpsInput->setPosition(ccp(133.5, yPos)); + tpsInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); + tpsInput->ignoreAnchorPointForPosition(true); + tpsInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + tpsInput->m_textLabel->setScale(0.6); + tpsInput->setMaxLabelScale(0.7f); + tpsInput->setMouseEnabled(true); + tpsInput->setTouchEnabled(true); + tpsInput->setContentSize({ 32, 20 }); + tpsInput->setAllowedChars("0123456789."); + tpsInput->setString(Utils::getSimplifiedString(fmt::format("{:.3f}", Mod::get()->getSavedValue("macro_tps"))).c_str()); + tpsInput->setMaxLabelWidth(30.f); + tpsInput->setDelegate(this); + tpsInput->setMaxLabelLength(9); + + nodes.push_back(static_cast(tpsInput)); + menu->addChild(tpsInput); + } + + if (sett.input == InputType::Seed) { + CCScale9Sprite* bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); + bg->setPosition(ccp(64, yPos + 10)); + bg->setScale(0.355f); + bg->setColor({ 0,0,0 }); + bg->setOpacity(75); + bg->setAnchorPoint({ 0, 1 }); + bg->setContentSize({ 258, 55 }); + bg->setZOrder(29); + nodes.push_back(static_cast(bg)); + menu->addChild(bg); + + seedInput = CCTextInputNode::create(150, 30, "Seed", "chatFont.fnt"); + seedInput->setPosition(ccp(109.5, yPos)); + seedInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); + seedInput->ignoreAnchorPointForPosition(true); + seedInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + seedInput->m_textLabel->setScale(0.6); + seedInput->setMaxLabelScale(0.7f); + seedInput->setMouseEnabled(true); + seedInput->setTouchEnabled(true); + seedInput->setContentSize({ 85, 20 }); + seedInput->setAllowedChars("0123456789"); + seedInput->setString(mod->getSavedValue("macro_seed").c_str()); + seedInput->setMaxLabelWidth(70.f); + seedInput->setDelegate(this); + seedInput->setMaxLabelLength(20); + + nodes.push_back(static_cast(seedInput)); + menu->addChild(seedInput); + } + + if (sett.input == InputType::Respawn) { + CCScale9Sprite* bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); + bg->setPosition(ccp(110, yPos + 10)); + bg->setScale(0.355f); + bg->setColor({ 0,0,0 }); + bg->setOpacity(75); + bg->setAnchorPoint({ 0, 1 }); + bg->setContentSize({ 100, 55 }); + bg->setZOrder(29); + nodes.push_back(static_cast(bg)); + menu->addChild(bg); + + respawnInput = CCTextInputNode::create(150, 30, "sec", "chatFont.fnt"); + respawnInput->setPosition(ccp(127.5, yPos)); + respawnInput->m_textField->setAnchorPoint({ 0.5f, 0.5f }); + respawnInput->ignoreAnchorPointForPosition(true); + respawnInput->m_textLabel->setAnchorPoint({ 0.5f, 0.5f }); + respawnInput->m_textLabel->setScale(0.6); + respawnInput->setMaxLabelScale(0.7f); + respawnInput->setMouseEnabled(true); + respawnInput->setTouchEnabled(true); + respawnInput->setContentSize({ 32.f, 20.f }); + respawnInput->setAllowedChars("0123456789."); + respawnInput->setString(fmt::format("{:.2}", mod->getSavedValue("respawn_time")).c_str()); + respawnInput->setMaxLabelWidth(30.f); + respawnInput->setDelegate(this); + respawnInput->setMaxLabelLength(4); + + nodes.push_back(static_cast(respawnInput)); + menu->addChild(respawnInput); + } + } + + void RecordLayer::goToSettingsPage(int page) { + checkSpeedhack(); + + for (size_t i = 0; i < nodes.size(); i++) + nodes[i]->removeFromParentAndCleanup(false); + + nodes.clear(); + + speedhackToggle = nullptr; + frameStepperToggle = nullptr; + trajectoryToggle = nullptr; + noclipToggle = nullptr; + tpsToggle = nullptr; + + speedhackInput = nullptr; + respawnInput = nullptr; + seedInput = nullptr; + tpsInput = nullptr; + + tpsBg = nullptr; + + for (size_t i = 0; i < 6; i++) + loadSetting(settings[page][i], ySettingPositions[i]); + + updateDots(); + updateTPS(); + + Mod::get()->setSavedValue("current_page", page); + } + + void RecordLayer::onDiscord(CCObject*) { + geode::createQuickPopup( + "Discord", + "Join the Discord server?\n(discord.gg/w6yvdzVzBd).", + "No", "Yes", + [](auto, bool btn2) { + if (btn2) + geode::utils::web::openLinkInBrowser("https://discord.gg/w6yvdzVzBd"); + } + ); + } + + void RecordLayer::updateTPS() { + if (!tpsInput || !tpsToggle || !tpsBg) return; + auto& g = Global::get(); + + tpsToggle->toggle(g.tpsEnabled); + tpsInput->setString(Utils::getSimplifiedString(fmt::format("{:.3f}", Mod::get()->getSavedValue("macro_tps"))).c_str()); + + if (g.state == state::none || g.macro.inputs.empty()) { + if (CCMenuItemSpriteExtra* btn = tpsToggle->getChildByType(0)) + if (CCSprite* spr = btn->getChildByType(0)) + spr->setOpacity(255); + if (CCMenuItemSpriteExtra* btn = tpsToggle->getChildByType(1)) + if (CCSprite* spr = btn->getChildByType(0)) + spr->setOpacity(255); + + tpsInput->setID(""); + tpsBg->setOpacity(75); + tpsToggle->setEnabled(true); + tpsInput->m_textLabel->setOpacity(255); + + tpsInput->detachWithIME(); + tpsInput->onClickTrackNode(false); + tpsInput->m_cursor->setVisible(false); + } else { + if (CCMenuItemSpriteExtra* btn = tpsToggle->getChildByType(0)) + if (CCSprite* spr = btn->getChildByType(0)) + spr->setOpacity(120); + if (CCMenuItemSpriteExtra* btn = tpsToggle->getChildByType(1)) + if (CCSprite* spr = btn->getChildByType(0)) + spr->setOpacity(120); + + tpsInput->setID("disabled-input"_spr); + tpsBg->setOpacity(30); + tpsToggle->setEnabled(false); + tpsInput->m_textLabel->setOpacity(120); + + tpsInput->detachWithIME(); + tpsInput->onClickTrackNode(false); + tpsInput->m_cursor->setVisible(false); + } + } + \ No newline at end of file From e18553a909efbce1325733d0138930f9cf32779e Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:31:26 +0300 Subject: [PATCH 065/211] CBS and COS detection --- src/global.cpp | 33 +++++++++++++++++++++++++++++++-- src/includes.hpp | 2 ++ src/macro.cpp | 4 ++-- src/ui/record_layer.cpp | 4 ++-- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/global.cpp b/src/global.cpp index cb5dcf49..65e314f6 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -55,7 +55,7 @@ bool Global::hasIncompatibleMods() { } } - + #ifdef GEODE_IS_WINDOWS if (Mod* mod = Loader::get()->getLoadedMod("tobyadd.gdh")) { @@ -137,7 +137,7 @@ bool Global::hasIncompatibleMods() { for (const std::string name : settingsToDisable) incompatString += fmt::format("{}{}", name, (name != settingsToDisable.back() ? ", " : "")); - FLAlertLayer::create("Warning", "The following mod settings are incompatible: \n" + incompatString, "Ok")->show(); + FLAlertLayer::create("Warning", "The following mod settings are incompatible: \n" + incompatString, "OK")->show(); } @@ -152,6 +152,35 @@ bool Global::hasIncompatibleMods() { return ret; } +bool Global::enabledIncompatibleGDSettings() { + std::vector settingsToDisable; + + if (GameManager::sharedState()->getGameVariable(GameVar::ClickBetweenSteps)) + settingsToDisable.push_back("Click Between Steps"); + + if (GameManager::sharedState()->getGameVariable(GameVar::ClickOnSteps)) + settingsToDisable.push_back("Click On Steps"); + + if (!settingsToDisable.empty()) { + std::string incompatString = ""; + + for (const std::string name : settingsToDisable) + incompatString += fmt::format("{}{}", name, (name != settingsToDisable.back() ? ", " : "")); + + FLAlertLayer::create("Warning", "The following GD settings are incompatible: \n" + incompatString, "OK")->show(); + } + + bool ret = !settingsToDisable.empty(); + + if (ret) { + Global::get().state = state::none; + Interface::updateLabels(); + Interface::updateButtons(); + } + + return ret; +} + float Global::getTPS() { auto& g = Global::get(); return g.tpsEnabled ? g.tps : 240.f; diff --git a/src/includes.hpp b/src/includes.hpp index f0fc761c..df6f1fe5 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -61,6 +61,8 @@ class Global { } static bool hasIncompatibleMods(); + + static bool enabledIncompatibleGDSettings(); static float getTPS(); diff --git a/src/macro.cpp b/src/macro.cpp index 1fd6f517..2c861962 100644 --- a/src/macro.cpp +++ b/src/macro.cpp @@ -306,7 +306,7 @@ void Macro::resetState(bool cp) { } void Macro::togglePlaying() { - if (Global::hasIncompatibleMods()) return; + if (Global::hasIncompatibleMods() || Global::enabledIncompatibleGDSettings()) return; auto& g = Global::get(); @@ -321,7 +321,7 @@ void Macro::togglePlaying() { } void Macro::toggleRecording() { - if (Global::hasIncompatibleMods()) return; + if (Global::hasIncompatibleMods() || Global::enabledIncompatibleGDSettings()) return; auto& g = Global::get(); diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 16e852b5..2d79c136 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -201,7 +201,7 @@ class $modify(PauseLayer) { void RecordLayer::toggleRecording(CCObject*) { auto& g = Global::get(); - if (Global::hasIncompatibleMods()) + if (Global::hasIncompatibleMods() || Global::enabledIncompatibleGDSettings()) return recording->toggle(true); if (g.state == state::playing) playing->toggle(false); @@ -230,7 +230,7 @@ class $modify(PauseLayer) { void RecordLayer::togglePlaying(CCObject*) { auto& g = Global::get(); - if (Global::hasIncompatibleMods()) + if (Global::hasIncompatibleMods() || Global::enabledIncompatibleGDSettings()) return playing->toggle(true); if (g.state == state::recording) From 7d0b2f46c4f64deb99a9df119d9aae647bf2159f Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 15 Feb 2026 19:13:20 +0300 Subject: [PATCH 066/211] fix open menu keybinds in popups --- src/keybinds.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index f7384ff8..3af9c700 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -55,8 +55,8 @@ void handleKeybind(std::string const& id, bool down) { if (!down || (LevelEditorLayer::get() && !g.mod->getSettingValue("editor_keybinds")) || g.mod->getSettingValue("disable_keybinds")) return; - if (auto scene = CCDirector::sharedDirector()->getRunningScene()) { - if (scene->getChildByType(0) || scene->getChildByType(0) || scene->getChildByType(0)) return; + if (auto scene = CCScene::get()) { + if (g.layer && scene->getChildByIndex(-1) != g.layer) return; } if (g.layer && id != "open_menu_keybind") return; From d9eceef80d22339d7b268a900f6330145316db8d Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 15 Feb 2026 19:13:49 +0300 Subject: [PATCH 067/211] we don't need these anymore --- src/keybinds.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 3af9c700..5a3e0c24 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -45,11 +45,6 @@ class $modify(CCKeyboardDispatcher) { } }; -class KeybindEditPopup : public geode::Popup {}; -class ModSettingsPopup : public geode::Popup {}; -class KeybindListPopup : public geode::Popup {}; - - void handleKeybind(std::string const& id, bool down) { auto& g = Global::get(); From c9731e1d2b8f1981ec05da478163b404020c414c Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 15 Feb 2026 19:17:13 +0300 Subject: [PATCH 068/211] remove unnecessary includes --- src/keybinds.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 5a3e0c24..502e9a54 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -1,18 +1,12 @@ #ifdef GEODE_IS_DESKTOP #include "includes.hpp" #include "ui/record_layer.hpp" -#include "ui/game_ui.hpp" -#include "ui/clickbot_layer.hpp" -#include "ui/macro_editor.hpp" -#include "ui/render_settings_layer.hpp" -#include "hacks/layout_mode.hpp" #include "hacks/show_trajectory.hpp" #include #include #include #include -#include class $modify(CCKeyboardDispatcher) { bool dispatchKeyboardMSG(enumKeyCodes key, bool isKeyDown, bool isKeyRepeat, double time) { From 5820e83b4dc30049729d8dd4b352793057cca1d0 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 15 Feb 2026 19:24:26 +0300 Subject: [PATCH 069/211] make it not disable all keybinds --- src/keybinds.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 502e9a54..029bcbdf 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -45,11 +45,9 @@ void handleKeybind(std::string const& id, bool down) { if (!down || (LevelEditorLayer::get() && !g.mod->getSettingValue("editor_keybinds")) || g.mod->getSettingValue("disable_keybinds")) return; if (auto scene = CCScene::get()) { - if (g.layer && scene->getChildByIndex(-1) != g.layer) return; + if (id == "open_menu_keybind" && g.layer && scene->getChildByIndex(-1) != g.layer) return; } - if (g.layer && id != "open_menu_keybind") return; - if (g.state != state::recording && g.mod->getSettingValue("recording_only_keybinds")) return; if (id == "open_menu_keybind") { From 5d7a1ce66604a2af0d44c08c946b0ae3931de49a Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Mon, 16 Feb 2026 04:59:56 +0300 Subject: [PATCH 070/211] Update mod.json --- mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod.json b/mod.json index 82835296..fe22d7c2 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "5.0.0-beta.1", + "geode": "5.0.0-beta.2", "gd": { "win": "2.2081", "mac": "2.2081", From 71c483b1381d9ff3dacc48176031471f5bcc20ef Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Mon, 16 Feb 2026 19:34:55 +0300 Subject: [PATCH 071/211] 5.0.0-beta.1 + open menu instantly --- mod.json | 6 ++++++ src/keybinds.cpp | 2 +- src/ui/button_setting.cpp | 2 +- src/ui/record_layer.cpp | 1 - src/ui/record_layer.hpp | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/mod.json b/mod.json index fe22d7c2..e9ec4ac0 100644 --- a/mod.json +++ b/mod.json @@ -36,6 +36,12 @@ "type": "bool", "default": false }, + "open_menu_instant": { + "name": "Open Menu Instantly", + "description": "Opens the menu without the opening animation.", + "type": "bool", + "default": false + }, "ffmpeg_path": { "name": "ffmpeg.exe Path", "description": "The path for ffmpeg.exe, needed to use render.", diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 029bcbdf..de2a287d 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -56,7 +56,7 @@ void handleKeybind(std::string const& id, bool down) { return; } - RecordLayer::openMenu(); + RecordLayer::openMenu(Mod::get()->getSettingValue("open_menu_instant")); } else if (id == "toggle_recording_keybind") diff --git a/src/ui/button_setting.cpp b/src/ui/button_setting.cpp index ee9be7bc..0b3843ab 100644 --- a/src/ui/button_setting.cpp +++ b/src/ui/button_setting.cpp @@ -62,7 +62,7 @@ class MyButtonSettingNodeV3 : public SettingNodeV3 { if (FLAlertLayer* layer = typeinfo_cast(children->lastObject())) layer->keyBackClicked(); - RecordLayer::openMenu(); + RecordLayer::openMenu(Mod::get()->getSettingValue("open_menu_instant")); } void onCommit() override {} diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 2d79c136..3f537cfb 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -12,7 +12,6 @@ #include #include -#include const std::vector> settings { { diff --git a/src/ui/record_layer.hpp b/src/ui/record_layer.hpp index 29e899b8..eb0769bf 100644 --- a/src/ui/record_layer.hpp +++ b/src/ui/record_layer.hpp @@ -104,7 +104,7 @@ class RecordLayer : public geode::Popup, public TextInputDelegate { static RecordLayer* openMenu(bool instant = false); void openMenu2(CCObject*) { - RecordLayer::openMenu(); + RecordLayer::openMenu(Mod::get()->getSettingValue("open_menu_instant")); } void moreSettings(CCObject*) { From ec6c004ae884c4029e3b72ef88efb5f46cb67470 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Mon, 16 Feb 2026 22:38:02 +0300 Subject: [PATCH 072/211] Update multi-platform-v5.yml --- .github/workflows/multi-platform-v5.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/multi-platform-v5.yml b/.github/workflows/multi-platform-v5.yml index 14eb7a60..58af44a8 100644 --- a/.github/workflows/multi-platform-v5.yml +++ b/.github/workflows/multi-platform-v5.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: branches: - - "main" + - "geode-v5" jobs: build: From da432b4d54a7561d4590921c7789fe6842509783 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Mon, 16 Feb 2026 22:43:08 +0300 Subject: [PATCH 073/211] Update multi-platform-v5.yml --- .github/workflows/multi-platform-v5.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/multi-platform-v5.yml b/.github/workflows/multi-platform-v5.yml index 58af44a8..0f8aa866 100644 --- a/.github/workflows/multi-platform-v5.yml +++ b/.github/workflows/multi-platform-v5.yml @@ -45,8 +45,6 @@ jobs: export-pdb: true bindings-ref: main combine: true - sdk: nightly - cli: nightly target: ${{ matrix.config.target }} package: From ebd9f53df442ac602c4d9265a8090880f8609f5d Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 17 Feb 2026 08:35:25 +0300 Subject: [PATCH 074/211] cant fix cceglview hook rn --- src/ui/macro_editor.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ui/macro_editor.cpp b/src/ui/macro_editor.cpp index 9380493c..83983f0d 100644 --- a/src/ui/macro_editor.cpp +++ b/src/ui/macro_editor.cpp @@ -1,12 +1,15 @@ #include "macro_editor.hpp" #include "record_layer.hpp" +#ifndef GEODE_IS_WINDOWS #include +#endif + #include MacroEditLayer* editLayer = nullptr; -#ifdef GEODE_IS_WINDOWS +#ifndef GEODE_IS_WINDOWS class $modify(CCEGLView) { void onGLFWMouseMoveCallBack(GLFWwindow* v1, double v2, double v3) { From 69571c434df1dc9e55c7d91a445bd4266ee73709 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 17 Feb 2026 08:38:54 +0300 Subject: [PATCH 075/211] =?UTF-8?q?rip=20hovering=20for=20now=20?= =?UTF-8?q?=F0=9F=98=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/macro_editor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/macro_editor.cpp b/src/ui/macro_editor.cpp index 83983f0d..5c527fa5 100644 --- a/src/ui/macro_editor.cpp +++ b/src/ui/macro_editor.cpp @@ -1,15 +1,15 @@ #include "macro_editor.hpp" #include "record_layer.hpp" -#ifndef GEODE_IS_WINDOWS +/* #ifndef GEODE_IS_WINDOWS #include -#endif +#endif */ #include MacroEditLayer* editLayer = nullptr; -#ifndef GEODE_IS_WINDOWS +/* #ifndef GEODE_IS_WINDOWS class $modify(CCEGLView) { void onGLFWMouseMoveCallBack(GLFWwindow* v1, double v2, double v3) { @@ -26,7 +26,7 @@ class $modify(CCEGLView) { editLayer->updateHover(getMousePos()); } -}; +};*/ #endif From b088a726b1c51161e3cd884c46d251a4d18141e0 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 17 Feb 2026 08:39:49 +0300 Subject: [PATCH 076/211] oops syntax error (editing in github mobile) --- src/ui/macro_editor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/macro_editor.cpp b/src/ui/macro_editor.cpp index 5c527fa5..ae0eb86b 100644 --- a/src/ui/macro_editor.cpp +++ b/src/ui/macro_editor.cpp @@ -26,9 +26,9 @@ class $modify(CCEGLView) { editLayer->updateHover(getMousePos()); } -};*/ +}; -#endif +#endif*/ class $modify(FLAlertLayer) { From ed1712b3bbf41ab232026042e012a13d9c9bbe0d Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 17 Feb 2026 19:13:58 +0300 Subject: [PATCH 077/211] fix hover :3 --- src/ui/macro_editor.cpp | 37 ++++++++++++------------------------- src/ui/macro_editor.hpp | 2 ++ 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/ui/macro_editor.cpp b/src/ui/macro_editor.cpp index ae0eb86b..8e3cd7f5 100644 --- a/src/ui/macro_editor.cpp +++ b/src/ui/macro_editor.cpp @@ -1,35 +1,10 @@ #include "macro_editor.hpp" #include "record_layer.hpp" -/* #ifndef GEODE_IS_WINDOWS -#include -#endif */ - #include MacroEditLayer* editLayer = nullptr; -/* #ifndef GEODE_IS_WINDOWS - -class $modify(CCEGLView) { - void onGLFWMouseMoveCallBack(GLFWwindow* v1, double v2, double v3) { - CCEGLView::onGLFWMouseMoveCallBack(v1, v2, v3); - - if (!editLayer) return; - - CCScene* scene = CCDirector::get()->getRunningScene(); - if (MacroEditLayer* layer = scene->getChildByType(0)) - editLayer = layer; - else - return; - - editLayer->updateHover(getMousePos()); - - } -}; - -#endif*/ - class $modify(FLAlertLayer) { #ifdef GEODE_IS_MOBILE @@ -81,6 +56,7 @@ void MacroEditLayer::onClose(CCObject*) { [this](auto, bool btn2) { if (!btn2) return; editLayer = nullptr; + this->unscheduleUpdate(); this->setKeypadEnabled(false); this->setTouchEnabled(false); this->removeFromParentAndCleanup(true); @@ -88,6 +64,7 @@ void MacroEditLayer::onClose(CCObject*) { ); } else { editLayer = nullptr; + this->unscheduleUpdate(); this->setKeypadEnabled(false); this->setTouchEnabled(false); this->removeFromParentAndCleanup(true); @@ -410,6 +387,8 @@ bool MacroEditLayer::init() { m_closeBtn->setPosition(m_closeBtn->getPosition() + offset); m_bgSprite->setPosition(m_bgSprite->getPosition() + offset); + this->scheduleUpdate(); + return true; } @@ -642,6 +621,14 @@ void MacroEditLayer::reSelectInput() { selectInput(prevSelected); } +void MacroEditLayer::update(float dt) { + #ifdef GEODE_IS_DESKTOP + if (!editLayer) return; + + updateHover(geode::cocos::getMousePos()); + #endif +} + int MacroEditLayer::getSum(CCObject* obj) { if (std::string_view(static_cast(obj)->getID()) == "left") return -1; diff --git a/src/ui/macro_editor.hpp b/src/ui/macro_editor.hpp index e25c7639..c55fa3c1 100644 --- a/src/ui/macro_editor.hpp +++ b/src/ui/macro_editor.hpp @@ -78,6 +78,8 @@ class MacroEditLayer : public geode::Popup, public TextInputDelegate { void selectInput(int input); void reSelectInput(); + + void update(float dt) override; void updatePageInputs(int page); From 026574191ceb9127d0e8c2533506571a1bf1737b Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 17 Feb 2026 21:15:18 +0300 Subject: [PATCH 078/211] change a lot of filesystem stuff to use geode utils --- src/gdr/gdr.cpp | 4 ++-- src/hacks/clickbot.cpp | 2 +- src/hacks/clickbot.hpp | 2 +- src/hacks/layout_mode.cpp | 22 +++++++++++----------- src/hacks/other.cpp | 2 +- src/macro.cpp | 36 +++++++++++++----------------------- src/renderer/renderer.cpp | 16 ++++++++-------- src/renderer/renderer.hpp | 2 +- src/ui/clickbot_layer.cpp | 8 ++++---- src/ui/load_macro_layer.cpp | 12 ++++++------ src/ui/macro_editor.cpp | 4 ++-- src/ui/record_layer.cpp | 4 ++-- src/ui/save_macro_layer.hpp | 4 ++-- 13 files changed, 54 insertions(+), 64 deletions(-) diff --git a/src/gdr/gdr.cpp b/src/gdr/gdr.cpp index a3b7e57f..8b3388f7 100644 --- a/src/gdr/gdr.cpp +++ b/src/gdr/gdr.cpp @@ -13,9 +13,9 @@ cocos2d::CCPoint dataFromString(std::string dataString) { for (int i = 0; i < 3; i++) { std::getline(ss, item, ','); if (i == 1) - xPos = std::stof(item); + xPos = geode::utils::numFromString(item).unwrap(); else if (i == 2) - yPos = std::stof(item); + yPos = geode::utils::numFromString(item).unwrap(); } return { xPos, yPos }; diff --git a/src/hacks/clickbot.cpp b/src/hacks/clickbot.cpp index e28998b1..dc3665ab 100644 --- a/src/hacks/clickbot.cpp +++ b/src/hacks/clickbot.cpp @@ -145,7 +145,7 @@ void Clickbot::updateSounds() { if (!std::filesystem::exists(settings.path)) continue; FMOD::Sound* sound = getSound(name); - result = c.system->createSound(settings.path.string().c_str(), FMOD_DEFAULT, nullptr, &sound); + result = c.system->createSound(geode::utils::string::pathToString(settings.path).c_str(), FMOD_DEFAULT, nullptr, &sound); if (result != FMOD_OK) { log::debug("Click sound errored. ID: 1"); continue; diff --git a/src/hacks/clickbot.hpp b/src/hacks/clickbot.hpp index 5da88e9a..3ba55032 100644 --- a/src/hacks/clickbot.hpp +++ b/src/hacks/clickbot.hpp @@ -28,7 +28,7 @@ struct matjson::Serialize { matjson::Value obj; obj["disabled"] = sett.disabled; - obj["path"] = sett.path.string(); + obj["path"] = geode::utils::string::pathToString(sett.path); obj["volume"] = sett.volume; obj["pitch"] = sett.pitch; diff --git a/src/hacks/layout_mode.cpp b/src/hacks/layout_mode.cpp index fcba575f..f09e07c6 100644 --- a/src/hacks/layout_mode.cpp +++ b/src/hacks/layout_mode.cpp @@ -81,8 +81,8 @@ std::string LayoutMode::getModifiedString(std::string levelString) { for (int i = 0; i < levelSettings.size(); i++) { if (levelSettings[i] == "kA36") { - if (std::stoi(levelSettings[i + 1]) != 0) - importantGroups.insert(std::stoi(levelSettings[i + 1])); + if (geode::utils::numFromString(levelSettings[i + 1]).unwrapOr(0) != 0) + importantGroups.insert(geode::utils::numFromString(levelSettings[i + 1]).unwrap()); break; } @@ -109,14 +109,14 @@ std::string LayoutMode::getModifiedString(std::string levelString) { if (!props.contains(1)) continue; - if (!importantTriggerIDs.contains(std::stoi(props.at(1)))) continue; + if (!importantTriggerIDs.contains(geode::utils::numFromString(props.at(1)).unwrap())) continue; - for (int i = 0; i < importantTriggerIDs.at(std::stoi(props.at(1))).size(); i++) { - int propID = importantTriggerIDs.at(std::stoi(props.at(1)))[i]; + for (int i = 0; i < importantTriggerIDs.at(geode::utils::numFromString(props.at(1)).unwrap()).size(); i++) { + int propID = importantTriggerIDs.at(geode::utils::numFromString(props.at(1)).unwrap())[i]; if (!props.contains(propID)) continue; - if (std::stoi(props[propID]) != 0) - importantGroups.insert(std::stoi(props[propID])); + if (geode::utils::numFromString(props[propID]).unwrapOr(0) != 0) + importantGroups.insert(geode::utils::numFromString(props[propID]).unwrap()); } } @@ -131,12 +131,12 @@ std::string LayoutMode::getModifiedString(std::string levelString) { if (!props.contains(1)) continue; - if (decoObjectIDs.contains(std::stoi(props.at(1))) || props.contains(121)) { + if (decoObjectIDs.contains(geode::utils::numFromString(props.at(1)).unwrap()) || props.contains(121)) { if (!props.contains(57)) continue; for (const auto& el : Utils::splitByChar(props.at(57), '.')) { if (el.empty()) continue; - if (!importantGroups.contains(std::stoi(el))) continue; + if (!importantGroups.contains(geode::utils::numFromString(el).unwrapOr(0))) continue; if (!props.contains(135)) { vec.push_back("135"); @@ -150,13 +150,13 @@ std::string LayoutMode::getModifiedString(std::string levelString) { continue; } - if (!solidObjectIDs.contains(std::stoi(props.at(1)))) { + if (!solidObjectIDs.contains(geode::utils::numFromString(props.at(1)).unwrap())) { newString += ";" + obj.ogString; continue; } if (props.contains(129)) { - if (std::stof(props[129]) <= 0.f && hidden == 0) { + if (geode::utils::numFromString(props[129]).unwrap() <= 0.f && hidden == 0) { vec.push_back("135"); vec.push_back("1"); diff --git a/src/hacks/other.cpp b/src/hacks/other.cpp index 8a9959c1..9f924c15 100644 --- a/src/hacks/other.cpp +++ b/src/hacks/other.cpp @@ -37,7 +37,7 @@ class $modify(CCScheduler) { std::string speedhackValue = g.mod->getSavedValue("macro_speedhack"); if (speedhackValue != "0.0" && speedhackValue != "") { - speedhack = std::stof(speedhackValue); + speedhack = geode::utils::numFromString(speedhackValue).unwrap(); float decimals = speedhack - static_cast(speedhack); float closest = safeValues[0]; diff --git a/src/macro.cpp b/src/macro.cpp index 2c861962..c4590acf 100644 --- a/src/macro.cpp +++ b/src/macro.cpp @@ -56,7 +56,7 @@ void Macro::autoSave(GJGameLevel* level, int number) { if (!std::filesystem::exists(autoSavesPath)) return; std::string username = GJAccountManager::sharedState() != nullptr ? GJAccountManager::sharedState()->m_username : ""; - int result = Macro::save(username, fmt::format("AutoSave {} in level {}", number, levelname), path.string()); + int result = Macro::save(username, fmt::format("AutoSave {} in level {}", number, levelname), geode::utils::string::pathToString(path)); if (result != 0) log::debug("Failed to autosave macro. ID: {}. Path: {}", result, path); @@ -78,7 +78,7 @@ void Macro::tryAutosave(GJGameLevel* level, CheckpointObject* cp) { std::string levelname = level->m_levelName; std::filesystem::path path = autoSavesPath / fmt::format("autosave_{}_{}", levelname, g.currentSession); std::error_code ec; - std::filesystem::remove(path.string() + ".gdr", ec); // Remove previous save + std::filesystem::remove(geode::utils::string::pathToString(path) + ".gdr", ec); // Remove previous save if (ec) log::warn("Failed to remove previous autosave"); autoSave(level, g.currentSession); @@ -167,33 +167,23 @@ int Macro::save(std::string author, std::string desc, std::string path, bool jso g.macro.description = desc; g.macro.duration = g.macro.inputs.back().frame / g.macro.framerate; - std::wstring widePath = Utils::widen(path); + std::ofstream f(path, std::ios::binary); - if (widePath == L"Widen Error") - return 30; - - std::ofstream f(std::filesystem::path(widePath), std::ios::binary); - - if (!f) - f.open(path, std::ios::binary); - - if (!f) + if (!f.is_open()) return 20; - std::vector frameFixes = g.macro.frameFixes; - auto data = g.macro.exportData(json); + if (data.empty()) + return 23; + f.write(reinterpret_cast(data.data()), data.size()); - if (!f) { + if (!f.good()) { f.close(); return 21; } - if (!f) - return 22; - f.close(); return 0; @@ -241,15 +231,15 @@ Macro Macro::XDtoGDR(std::filesystem::path path) { if (action[0] == "android") fpsMultiplier = 4.f; else { - int fps = std::stoi(action[0]); + int fps = geode::utils::numFromString(action[0]).unwrap(); fpsMultiplier = 240.f / fps; } continue; } - int frame = static_cast(round(std::stoi(action[0]) * fpsMultiplier)); - int button = std::stoi(action[2]); + int frame = static_cast(round(geode::utils::numFromString(action[0]).unwrap() * fpsMultiplier)); + int button = geode::utils::numFromString(action[2]).unwrap(); bool hold = action[1] == "1"; bool player2 = action[3] == "1"; bool posOnly = action[4] == "1"; @@ -257,8 +247,8 @@ Macro Macro::XDtoGDR(std::filesystem::path path) { if (!posOnly) newMacro.inputs.push_back(input(frame, button, player2, hold)); else { - cocos2d::CCPoint p1Pos = ccp(std::stof(action[5]), std::stof(action[6])); - cocos2d::CCPoint p2Pos = ccp(std::stof(action[11]), std::stof(action[12])); + cocos2d::CCPoint p1Pos = ccp(geode::utils::numFromString(action[5]).unwrap(), geode::utils::numFromString(action[6]).unwrap()); + cocos2d::CCPoint p2Pos = ccp(geode::utils::numFromString(action[11]).unwrap(), geode::utils::numFromString(action[12]).unwrap()); newMacro.frameFixes.push_back({ frame, {p1Pos, 0.f, false}, {p2Pos, 0.f, false} }); } diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index fe646cbb..a0d2d1f8 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -150,7 +150,7 @@ // bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); // std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); -// bool foundExe = std::filesystem::exists(ffmpegPath) && ffmpegPath.filename().string() == "ffmpeg.exe"; +// bool foundExe = std::filesystem::exists(ffmpegPath) && geode::utils::string::pathToString(ffmpegPath.filename()) == "ffmpeg.exe"; // return !foundExe && foundApi; @@ -171,7 +171,7 @@ // bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); // std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); -// bool foundExe = std::filesystem::exists(ffmpegPath) && ffmpegPath.filename().string() == "ffmpeg.exe"; +// bool foundExe = std::filesystem::exists(ffmpegPath) && geode::utils::string::pathToString(ffmpegPath.filename()) == "ffmpeg.exe"; // g.renderer.usingApi = Renderer::shouldUseAPI(); @@ -196,7 +196,7 @@ // return false; // } -// g.renderer.ffmpegPath = ffmpegPath.string(); +// g.renderer.ffmpegPath = geode::utils::string::pathToString(ffmpegPath); // #else // if (!foundApi) { // FLAlertLayer::create("Error", "FFmpeg API not found. Download it to render a level.", "Ok")->show(); @@ -234,7 +234,7 @@ // Mod* mod = Mod::get(); // fmod = FMODAudioEngine::sharedEngine(); -// fps = std::stoi(mod->getSavedValue("render_fps")); +// fps = geode::utils::numFromString(mod->getSavedValue("render_fps")).unwrap(); // codec = mod->getSavedValue("render_codec"); // bitrate = mod->getSavedValue("render_bitrate") + "M"; // extraArgs = mod->getSavedValue("render_args"); @@ -254,10 +254,10 @@ // auto timestamp = std::chrono::duration_cast(duration).count(); // std::string filename = fmt::format("render_{}_{}{}", std::string_view(pl->m_level->m_levelName), std::to_string(timestamp), extension); -// std::string path = (Mod::get()->getSettingValue("render_folder") / filename).string(); +// std::string path = geode::utils::string::pathToString(Mod::get()->getSettingValue("render_folder") / filename); -// width = std::stoi(mod->getSavedValue("render_width2")); -// height = std::stoi(mod->getSavedValue("render_height")); +// width = geode::utils::numFromString(mod->getSavedValue("render_width2")).unwrap(); +// height = geode::utils::numFromString(mod->getSavedValue("render_height")).unwrap(); // if (width % 2 != 0) // width++; @@ -437,7 +437,7 @@ // return; // } -// std::filesystem::path tempPath = std::filesystem::path(path).parent_path() / ("temp_" + std::filesystem::path(path).filename().string()); +// std::filesystem::path tempPath = std::filesystem::path(path).parent_path() / ("temp_" + geode::utils::string::pathToString(std::filesystem::path(path).filename())); // std::filesystem::path tempPathAudio = (Mod::get()->getSaveDir() / "temp_audio_file.wav"); // if (usingApi) { diff --git a/src/renderer/renderer.hpp b/src/renderer/renderer.hpp index b6c2b5bf..9ef180e8 100644 --- a/src/renderer/renderer.hpp +++ b/src/renderer/renderer.hpp @@ -54,7 +54,7 @@ // std::vector currentFrame; // std::mutex lock; // std::string codec = "", bitrate = "12M", extraArgs = "", videoArgs = "", extraAudioArgs = "", path = ""; -// std::string ffmpegPath = (geode::dirs::getGameDir() / "ffmpeg.exe").string(); +// std::string ffmpegPath = geode::utils::string::pathToString(geode::dirs::getGameDir() / "ffmpeg.exe"); // std::unordered_set renderedFrames; // FMODAudioEngine* fmod = nullptr; diff --git a/src/ui/clickbot_layer.cpp b/src/ui/clickbot_layer.cpp index 89a5bf6c..a5f9edb7 100644 --- a/src/ui/clickbot_layer.cpp +++ b/src/ui/clickbot_layer.cpp @@ -8,7 +8,7 @@ void ClickbotLayer::updateLabels() { ClickSetting settings = matjson::Serialize::from_json(data); - std::string filename = settings.path.filename().string(); + std::string filename = geode::utils::string::pathToString(settings.path.filename()); if (!std::filesystem::exists(settings.path)) filename = "N/A"; @@ -314,7 +314,7 @@ bool ClickSettingsLayer::init(std::string button, geode::Popup* layer) { matjson::Value data = Mod::get()->getSavedValue(button); settings = matjson::Serialize::from_json(data); - std::string filename = settings.path.filename().string(); + std::string filename = geode::utils::string::pathToString(settings.path.filename()); if (!std::filesystem::exists(settings.path)) filename = "N/A"; @@ -410,7 +410,7 @@ void ClickSettingsLayer::onSelectFile(CCObject*) { auto pathOpt = res.unwrapOrDefault(); if (pathOpt) { std::filesystem::path path = pathOpt.value(); - self->filenameLabel->setString(path.filename().string().c_str()); + self->filenameLabel->setString(geode::utils::string::pathToString(path.filename()).c_str()); self->settings.path = path; self->saveSettings(); static_cast(self->clickbotLayer)->updateLabels(); @@ -432,7 +432,7 @@ void ClickSettingsLayer::onRestore(CCObject*) { std::filesystem::path path = Mod::get()->getResourcesDir() / fmt::format("default_{}.mp3", button); - filenameLabel->setString(path.filename().string().c_str()); + filenameLabel->setString(geode::utils::string::pathToString(path.filename()).c_str()); settings.path = path; saveSettings(); diff --git a/src/ui/load_macro_layer.cpp b/src/ui/load_macro_layer.cpp index 85e8630c..c933aa01 100644 --- a/src/ui/load_macro_layer.cpp +++ b/src/ui/load_macro_layer.cpp @@ -183,11 +183,11 @@ void LoadMacroLayer::onImportMacro(CCObject*) { int iterations = 0; - std::string name = path.filename().string().substr(0, path.filename().string().find_last_of('.')); + std::string name = geode::utils::string::pathToString(path.filename()).substr(0, geode::utils::string::pathToString(path.filename()).find_last_of('.')); std::filesystem::path newPath = Mod::get()->getSettingValue("macros_folder") / name; - std::string pathString = newPath.string(); + std::string pathString = geode::utils::string::pathToString(newPath); while (std::filesystem::exists(pathString + ".gdr.json")) { iterations++; @@ -427,7 +427,7 @@ void LoadMacroLayer::addList(bool refresh, float prevScroll) { if (macros[i].extension() != ".gdr" && macros[i].extension() != ".xd" && macros[i].extension() != ".json") continue; - std::string name = macros[i].filename().string().substr(0, macros[i].filename().string().find_last_of('.')); + std::string name = geode::utils::string::pathToString(macros[i].filename()).substr(0, geode::utils::string::pathToString(macros[i].filename()).find_last_of('.')); if (macros[i].extension() == ".json") name = name.substr(0, name.find_last_of('.')); @@ -617,11 +617,11 @@ bool MacroCell::init(std::filesystem::path path, std::string name, std::time_t d #ifdef GEODE_IS_WINDOWS std::string subText = Utils::formatTime(date) + " | "; - subText += autosave ? "Auto Save" : path.extension().string(); + subText += autosave ? "Auto Save" : geode::utils::string::pathToString(path.extension()); lbl = CCLabelBMFont::create(subText.c_str(), "chatFont.fnt"); #else - std::string subText = autosave ? "Auto Save" : path.extension().string(); + std::string subText = autosave ? "Auto Save" : geode::utils::string::pathToString(path.extension()); lbl = CCLabelBMFont::create(subText.c_str(), "chatFont.fnt"); #endif @@ -686,7 +686,7 @@ void MacroCell::handleLoad() { g.macro = oldMacro; } else { - std::ifstream f(path.string(), std::ios::binary); + std::ifstream f(geode::utils::string::pathToString(path), std::ios::binary); f.seekg(0, std::ios::end); size_t fileSize = f.tellg(); diff --git a/src/ui/macro_editor.cpp b/src/ui/macro_editor.cpp index 8e3cd7f5..d11e6b80 100644 --- a/src/ui/macro_editor.cpp +++ b/src/ui/macro_editor.cpp @@ -527,7 +527,7 @@ void MacroEditLayer::textChanged(CCTextInputNode* input) { if (text == "") return; if (input == editLayer->pageInput->getInputNode()) { - int page = std::stoi(text); + int page = geode::utils::numFromString(text).unwrap(); if (page <= 0) return; @@ -538,7 +538,7 @@ void MacroEditLayer::textChanged(CCTextInputNode* input) { } if (input == editLayer->frameInput->getInputNode()) { - int frame = std::stoi(text); + int frame = geode::utils::numFromString(text).unwrap(); editLayer->changeSelectedInputFrame(frame, false); diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 3f537cfb..ac748f53 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -338,7 +338,7 @@ class $modify(PauseLayer) { mod->setSavedValue("render_bitrate", std::string(bitrateInput->getString())); if (std::string_view(fpsInput->getString()) != "" && node == fpsInput) { - if (std::stoi(fpsInput->getString()) > 240) + if (geode::utils::numFromString(fpsInput->getString()).unwrapOr(0) > 240) return fpsInput->setString(mod->getSavedValue("render_fps").c_str()); mod->setSavedValue("render_fps", std::string(fpsInput->getString())); } @@ -364,7 +364,7 @@ class $modify(PauseLayer) { if (value == ".") speedhackInput->setString("0."); - else if (std::count(value.begin(), value.end(), '.') == 2 || std::stof(value) > 10) + else if (std::count(value.begin(), value.end(), '.') == 2 || geode::utils::numFromString(value).unwrapOr(0) > 10) return speedhackInput->setString(mod->getSavedValue("macro_speedhack").c_str()); } diff --git a/src/ui/save_macro_layer.hpp b/src/ui/save_macro_layer.hpp index cb6c6e60..f6ec6e13 100644 --- a/src/ui/save_macro_layer.hpp +++ b/src/ui/save_macro_layer.hpp @@ -81,7 +81,7 @@ class SaveMacroLayer : public geode::Popup { if (!std::filesystem::exists(path)) { if (!utils::file::createDirectoryAll(path).isOk()) - return FLAlertLayer::create("Error", ("There was an error getting the folder \"" + path.string() + "\". ID: 10").c_str(), "Ok")->show(); + return FLAlertLayer::create("Error", ("There was an error getting the folder \"" + geode::utils::string::pathToString(path) + "\". ID: 10").c_str(), "Ok")->show(); } SaveMacroLayer* layerReal = create(); @@ -98,7 +98,7 @@ class SaveMacroLayer : public geode::Popup { std::string author = authorInput->getString(); std::string desc = descInput->getString(); - int result = Macro::save(author, desc, path.string(), jsonToggle->isToggled()); + int result = Macro::save(author, desc, geode::utils::string::pathToString(path), jsonToggle->isToggled()); if (result != 0) return FLAlertLayer::create("Error", "There was an error saving the macro. ID: " + std::to_string(result), "Ok")->show(); From 407664f7ddef783aaff956d06d268ff924712b21 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 17 Feb 2026 21:27:39 +0300 Subject: [PATCH 079/211] remove save location options on ios --- mod.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mod.json b/mod.json index e9ec4ac0..313a039d 100644 --- a/mod.json +++ b/mod.json @@ -55,9 +55,9 @@ "default": { "win": "{gd_dir}/macros", "mac": "{gd_dir}/macros", - "android": "{gd_dir}/macros", - "ios": "{mod_save_dir}/macros" - } + "android": "{gd_dir}/macros" + }, + "platforms": ["win", "mac", "android"] }, "autosaves_folder": { "name": "Auto Saves Location", @@ -65,9 +65,9 @@ "default": { "win": "{gd_dir}/autosaves", "mac": "{gd_dir}/autosaves", - "android": "{gd_dir}/autosaves", - "ios": "{mod_save_dir}/autosaves" - } + "android": "{gd_dir}/autosaves" + }, + "platforms": ["win", "mac", "android"] }, "render_folder": { "name": "Render Save Location", @@ -75,9 +75,9 @@ "default": { "win": "{gd_dir}/renders", "mac": "{gd_dir}/renders", - "android": "{gd_dir}/renders", - "ios": "{mod_save_dir}/renders" - } + "android": "{gd_dir}/renders" + }, + "platforms": ["win", "mac", "android"] }, "open_menu_keybind": { "name": "Open Menu Keybind", From 405b6253a40102aa83dfad16de251b9c8ab84e92 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 17 Feb 2026 21:32:41 +0300 Subject: [PATCH 080/211] why did i remove default paths on ios --- mod.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mod.json b/mod.json index 313a039d..6ac7fdd0 100644 --- a/mod.json +++ b/mod.json @@ -55,7 +55,8 @@ "default": { "win": "{gd_dir}/macros", "mac": "{gd_dir}/macros", - "android": "{gd_dir}/macros" + "android": "{gd_dir}/macros", + "ios": "{gd_dir}/macros" }, "platforms": ["win", "mac", "android"] }, @@ -65,7 +66,8 @@ "default": { "win": "{gd_dir}/autosaves", "mac": "{gd_dir}/autosaves", - "android": "{gd_dir}/autosaves" + "android": "{gd_dir}/autosaves", + "ios": "{gd_dir}/autosaves" }, "platforms": ["win", "mac", "android"] }, @@ -75,7 +77,8 @@ "default": { "win": "{gd_dir}/renders", "mac": "{gd_dir}/renders", - "android": "{gd_dir}/renders" + "android": "{gd_dir}/renders", + "ios": "{gd_dir}/renders" }, "platforms": ["win", "mac", "android"] }, From 2dc06c604b6d90852501b16661c99c8cf0746d1e Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 17 Feb 2026 22:38:23 +0300 Subject: [PATCH 081/211] fix macro importing + fix OK capitalization --- src/global.cpp | 2 +- src/renderer/renderer.cpp | 24 ++--- src/ui/autoclicker_settings_layer.hpp | 2 +- src/ui/autosave_settings_layer.hpp | 2 +- src/ui/load_macro_layer.cpp | 137 +++++++++++++------------- src/ui/load_macro_layer.hpp | 2 +- src/ui/record_layer.cpp | 6 +- src/ui/render_presets_layer.hpp | 2 +- src/ui/render_settings_layer.cpp | 4 +- src/ui/save_macro_layer.hpp | 8 +- src/ui/trajectory_settings_layer.hpp | 2 +- 11 files changed, 98 insertions(+), 93 deletions(-) diff --git a/src/global.cpp b/src/global.cpp index 65e314f6..a5dc6fd4 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -129,7 +129,7 @@ bool Global::hasIncompatibleMods() { for (const std::string name : modsToDisable) incompatString += fmt::format("{}{}", name, (name != modsToDisable.back() ? ", " : "")); - FLAlertLayer::create("Warning", "The following mods are incompatible: \n" + incompatString, "Ok")->show(); + FLAlertLayer::create("Warning", "The following mods are incompatible: \n" + incompatString, "OK")->show(); } else if (!settingsToDisable.empty()) { std::string incompatString = ""; diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index a0d2d1f8..06860f06 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -188,7 +188,7 @@ // "Cancel", "Yes", // [](auto, bool btn2) { // if (btn2) { -// FLAlertLayer::create("Info", "Unzip the downloaded file and look for ffmpeg.exe in the 'bin' folder.", "Ok")->show(); +// FLAlertLayer::create("Info", "Unzip the downloaded file and look for ffmpeg.exe in the 'bin' folder.", "OK")->show(); // utils::web::openLinkInBrowser("https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-essentials.7z"); // } // } @@ -199,13 +199,13 @@ // g.renderer.ffmpegPath = geode::utils::string::pathToString(ffmpegPath); // #else // if (!foundApi) { -// FLAlertLayer::create("Error", "FFmpeg API not found. Download it to render a level.", "Ok")->show(); +// FLAlertLayer::create("Error", "FFmpeg API not found. Download it to render a level.", "OK")->show(); // return false; // } // #endif // if (!PlayLayer::get()) { -// FLAlertLayer::create("Warning", "Open a level to start rendering it.", "Ok")->show(); +// FLAlertLayer::create("Warning", "Open a level to start rendering it.", "OK")->show(); // return false; // } @@ -217,7 +217,7 @@ // if (utils::file::createDirectoryAll(path).isOk()) // g.renderer.start(); // else { -// FLAlertLayer::create("Error", "There was an error getting the renders folder. ID: 11", "Ok")->show(); +// FLAlertLayer::create("Error", "There was an error getting the renders folder. ID: 11", "OK")->show(); // return false; // } // } @@ -314,7 +314,7 @@ // FLAlertLayer::create( // "Warning", // "If you have a macro for the level, let it run to allow the level to render.", -// "Ok" +// "OK" // )->show(); // } @@ -343,7 +343,7 @@ // if (res.isErr()) { // Loader::get()->queueInMainThread([] { // // std::string err = res.unwrapErr(); -// FLAlertLayer::create("Error", "FFmpeg API failed to initialize: ", "Ok")->show(); +// FLAlertLayer::create("Error", "FFmpeg API failed to initialize: ", "OK")->show(); // }); // audioMode = AudioMode::Off; @@ -382,7 +382,7 @@ // auto res = ffmpeg.writeFrame(frame); // if (res.isErr()) { // Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "FFmpeg API failed: ", "Ok")->show(); +// FLAlertLayer::create("Error", "FFmpeg API failed: ", "OK")->show(); // }); // audioMode = AudioMode::Off; @@ -405,7 +405,7 @@ // #ifdef GEODE_IS_WINDOWS // if (process.close()) { // Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "There was an error saving the render. Wrong render Args.", "Ok")->show(); +// FLAlertLayer::create("Error", "There was an error saving the render. Wrong render Args.", "OK")->show(); // }); // return; // } @@ -420,7 +420,7 @@ // if ((SFXVolume == 0.f && musicVolume == 0.f) || audioMode == AudioMode::Off || (audioMode == AudioMode::Song && !std::filesystem::exists(songFile)) || (audioMode == AudioMode::Record && !std::filesystem::exists("fmodoutput.wav"))) { // if (audioMode != AudioMode::Off) { // Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "Song File not found.", "Ok")->show(); +// FLAlertLayer::create("Error", "Song File not found.", "OK")->show(); // }); // std::this_thread::sleep_for(std::chrono::milliseconds(100)); @@ -446,7 +446,7 @@ // log::debug("XD"); // if (res.isErr()) { // Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "FFmpeg failed to add audio: ", "Ok")->show(); +// FLAlertLayer::create("Error", "FFmpeg failed to add audio: ", "OK")->show(); // }); // return; // } @@ -483,7 +483,7 @@ // process = subprocess::Popen(command); // Fix ffmpeg not reading it // if (process.close()) { // Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "There was an error adding the song. ID: 140", "Ok")->show(); +// FLAlertLayer::create("Error", "There was an error adding the song. ID: 140", "OK")->show(); // }); // return; // } @@ -529,7 +529,7 @@ // auto process = subprocess::Popen(command); // if (process.close()) { // Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "There was an error adding the song. Wrong Audio Args.", "Ok")->show(); +// FLAlertLayer::create("Error", "There was an error adding the song. Wrong Audio Args.", "OK")->show(); // }); // return; // } diff --git a/src/ui/autoclicker_settings_layer.hpp b/src/ui/autoclicker_settings_layer.hpp index 2a160193..a246ed3d 100644 --- a/src/ui/autoclicker_settings_layer.hpp +++ b/src/ui/autoclicker_settings_layer.hpp @@ -163,7 +163,7 @@ class AutoclickerLayer : public geode::Popup, public TextInputDelegate { toggleP2->toggle(Global::get().autoclickerP2); m_buttonMenu->addChild(toggleP2); - ButtonSprite* btnSpr = ButtonSprite::create("Ok"); + ButtonSprite* btnSpr = ButtonSprite::create("OK"); btnSpr->setScale(0.7f); CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(btnSpr, this, menu_selector(AutoclickerLayer::onClose)); btn->setPosition({m_size.width / 2, 24}); diff --git a/src/ui/autosave_settings_layer.hpp b/src/ui/autosave_settings_layer.hpp index f4c42082..99c9bc9b 100644 --- a/src/ui/autosave_settings_layer.hpp +++ b/src/ui/autosave_settings_layer.hpp @@ -99,7 +99,7 @@ class AutoSaveLayer : public geode::Popup, public TextInputDelegate { levelEndToggle->toggle(Mod::get()->getSavedValue("autosave_levelend_enabled")); m_buttonMenu->addChild(levelEndToggle); - ButtonSprite* btnSpr = ButtonSprite::create("Ok"); + ButtonSprite* btnSpr = ButtonSprite::create("OK"); btnSpr->setScale(0.7f); CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(btnSpr, this, menu_selector(AutoSaveLayer::onClose)); btn->setPosition({m_size.width / 2, 24}); diff --git a/src/ui/load_macro_layer.cpp b/src/ui/load_macro_layer.cpp index c933aa01..5e0d002a 100644 --- a/src/ui/load_macro_layer.cpp +++ b/src/ui/load_macro_layer.cpp @@ -3,6 +3,7 @@ #include "macro_editor.hpp" #include +#include class $modify(CCMenu) { virtual bool ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) { @@ -30,14 +31,14 @@ void LoadMacroLayer::open(geode::Popup* layer, geode::Popup* layer2, bool autosa if (!std::filesystem::exists(path)) { if (utils::file::createDirectoryAll(path).isErr()) - return FLAlertLayer::create("Error", "There was an error getting the folder. ID: 6", "Ok")->show(); + return FLAlertLayer::create("Error", "There was an error getting the folder. ID: 6", "OK")->show(); } path = Mod::get()->getSettingValue("autosaves_folder"); if (!std::filesystem::exists(path)) { if (utils::file::createDirectoryAll(path).isErr()) - return FLAlertLayer::create("Error", "There was an error getting the folder. ID: 61", "Ok")->show(); + return FLAlertLayer::create("Error", "There was an error getting the folder. ID: 61", "OK")->show(); } LoadMacroLayer* layerReal = create(layer, layer2, autosaves); @@ -144,78 +145,82 @@ void LoadMacroLayer::onImportMacro(CCObject*) { textFilter.files = { "*.gdr", "*.xd", "*.json" }; fileOptions.filters.push_back(textFilter); - m_importFuture = [](LoadMacroLayer* self, file::FilePickOptions options) -> arc::Future { - auto res = co_await file::pick(file::PickMode::OpenFile, options); - if (res.isOk()) { - auto pathOpt = res.unwrapOrDefault(); - if (!pathOpt) co_return; - std::filesystem::path path = pathOpt.value(); - - auto& g = Global::get(); - Macro tempMacro; - - if (path.extension() == ".xd") { - tempMacro = Macro::XDtoGDR(path); + auto self = this; + m_importFuture = async::runtime().spawn([self, fileOptions]() -> arc::Future { + auto res = co_await file::pick(file::PickMode::OpenFile, fileOptions); + + geode::queueInMainThread([self, res]() { + if (res.isOk()) { + auto pathOpt = res.unwrapOrDefault(); + if (!pathOpt) return; + std::filesystem::path path = pathOpt.value(); - if (tempMacro.description == "fail") { - FLAlertLayer::create("Error", "There was an error importing this macro. ID: 46", "Ok")->show(); - co_return; - } - } - else { + auto& g = Global::get(); + Macro tempMacro; - std::ifstream f(path, std::ios::binary); + if (path.extension() == ".xd") { + tempMacro = Macro::XDtoGDR(path); + + if (tempMacro.description == "fail") { + FLAlertLayer::create("Error", "There was an error importing this macro. ID: 46", "OK")->show(); + return; + } + } + else { + + std::ifstream f(path, std::ios::binary); + + f.seekg(0, std::ios::end); + size_t fileSize = f.tellg(); + f.seekg(0, std::ios::beg); + + std::vector macroData(fileSize); + + f.read(reinterpret_cast(macroData.data()), fileSize); + f.close(); + + tempMacro = Macro::importData(macroData); + + } - f.seekg(0, std::ios::end); - size_t fileSize = f.tellg(); - f.seekg(0, std::ios::beg); + bool xdMacro = path.extension() == ".xd"; - std::vector macroData(fileSize); + int iterations = 0; - f.read(reinterpret_cast(macroData.data()), fileSize); - f.close(); + std::string name = geode::utils::string::pathToString(path.filename()).substr(0, geode::utils::string::pathToString(path.filename()).find_last_of('.')); - tempMacro = Macro::importData(macroData); + std::filesystem::path newPath = Mod::get()->getSettingValue("macros_folder") / name; - } - - bool xdMacro = path.extension() == ".xd"; - - int iterations = 0; - - std::string name = geode::utils::string::pathToString(path.filename()).substr(0, geode::utils::string::pathToString(path.filename()).find_last_of('.')); - - std::filesystem::path newPath = Mod::get()->getSettingValue("macros_folder") / name; - - std::string pathString = geode::utils::string::pathToString(newPath); - - while (std::filesystem::exists(pathString + ".gdr.json")) { - iterations++; + std::string pathString = geode::utils::string::pathToString(newPath); - if (iterations > 1) { - int length = 3 + std::to_string(iterations - 1).length(); - pathString.erase(pathString.length() - length, length); + while (std::filesystem::exists(pathString + ".gdr.json")) { + iterations++; + + if (iterations > 1) { + int length = 3 + std::to_string(iterations - 1).length(); + pathString.erase(pathString.length() - length, length); + } + + pathString += fmt::format(" ({})", std::to_string(iterations)); } - pathString += fmt::format(" ({})", std::to_string(iterations)); + pathString += ".gdr.json"; + + std::ofstream f2(std::filesystem::path(pathString), std::ios::binary); + auto data = tempMacro.exportData(true); + + f2.write(reinterpret_cast(data.data()), data.size()); + f2.close(); + + self->reloadList(0); + + if (xdMacro) + FLAlertLayer::create("Warning", ".xd extension macros may not function correctly in this version.", "OK")->show(); + + Notification::create("Macro Imported", NotificationIcon::Success)->show(); } - - pathString += ".gdr.json"; - - std::ofstream f2(std::filesystem::path(pathString), std::ios::binary); - auto data = tempMacro.exportData(true); - - f2.write(reinterpret_cast(data.data()), data.size()); - f2.close(); - - self->reloadList(0); - - if (xdMacro) - FLAlertLayer::create("Warning", ".xd extension macros may not function correctly in this version.", "Ok")->show(); - - Notification::create("Macro Imported", NotificationIcon::Success)->show(); - } - }(this, { dirs::getGameDir(), { textFilter } }); + }); + }); } bool LoadMacroLayer::init(geode::Popup* layer, geode::Popup* layer2, bool autosaves) { @@ -675,7 +680,7 @@ void MacroCell::handleLoad() { if (path.extension() == ".xd") { if (!Macro::loadXDFile(path)) { if (!isMerge) - return FLAlertLayer::create("Error", "There was an error loading this macro. ID: 45", "Ok")->show(); + return FLAlertLayer::create("Error", "There was an error loading this macro. ID: 45", "OK")->show(); else return; } @@ -753,7 +758,7 @@ void MacroCell::handleLoad() { } if (path.extension() == ".xd") - FLAlertLayer::create("Warning", ".xd extension macros may not function correctly in this version.", "Ok")->show(); + FLAlertLayer::create("Warning", ".xd extension macros may not function correctly in this version.", "OK")->show(); Notification::create("Macro Loaded", NotificationIcon::Success)->show(); } @@ -792,7 +797,7 @@ void MacroCell::deleteMacro(bool reload) { std::error_code ec; std::filesystem::remove(path, ec); if (ec) { - return FLAlertLayer::create("Error", "There was an error deleting this macro. ID: 7", "Ok")->show(); + return FLAlertLayer::create("Error", "There was an error deleting this macro. ID: 7", "OK")->show(); } else { if (reload) { diff --git a/src/ui/load_macro_layer.hpp b/src/ui/load_macro_layer.hpp index c21ca77e..def2f366 100644 --- a/src/ui/load_macro_layer.hpp +++ b/src/ui/load_macro_layer.hpp @@ -67,7 +67,7 @@ class LoadMacroLayer : public geode::Popup, TextInputDelegate { bool isMerge = false; bool invertSort = false; - std::optional> m_importFuture; + arc::TaskHandle m_importFuture; static LoadMacroLayer* create(geode::Popup* layer, geode::Popup* layer2, bool autosaves); diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index ac748f53..9e449370 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -481,7 +481,7 @@ class $modify(PauseLayer) { FLAlertLayer::create( "Warning", "Scroll down to find xdBot's keybinds", - "Ok" + "OK" )->show(); }); } @@ -509,12 +509,12 @@ class $modify(PauseLayer) { if (std::filesystem::exists(path)) LoadMacroLayer::open(static_cast(this), nullptr, true); else { - FLAlertLayer::create("Error", "There was an error getting the folder. ID: 5", "Ok")->show(); + FLAlertLayer::create("Error", "There was an error getting the folder. ID: 5", "OK")->show(); } } void RecordLayer::showCodecPopup(CCObject*) { - FLAlertLayer::create("Codec", "AMD: h264_amf\nNVIDIA: h264_nvenc\nINTEL: h264_qsv\nI don't know: libx264", "Ok")->show(); + FLAlertLayer::create("Codec", "AMD: h264_amf\nNVIDIA: h264_nvenc\nINTEL: h264_qsv\nI don't know: libx264", "OK")->show(); } void RecordLayer::updateDots() { diff --git a/src/ui/render_presets_layer.hpp b/src/ui/render_presets_layer.hpp index 683865b3..a5915740 100644 --- a/src/ui/render_presets_layer.hpp +++ b/src/ui/render_presets_layer.hpp @@ -112,7 +112,7 @@ class RenderPresetsLayer : public geode::Popup { else if (geode::utils::file::createDirectoryAll(path).isOk()) file::openFolder(path); else - FLAlertLayer::create("Error", "There was an error getting the folder. ID: 4", "Ok")->show(); + FLAlertLayer::create("Error", "There was an error getting the folder. ID: 4", "OK")->show(); } void onLoad(CCObject* obj) { diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index a644a680..669d333d 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -476,7 +476,7 @@ bool RenderSettingsLayer::init() { musicSlider->setValue(Mod::get()->getSavedValue("render_music_volume")); menu->addChild(musicSlider); - ButtonSprite* spr = ButtonSprite::create("Ok"); + ButtonSprite* spr = ButtonSprite::create("OK"); spr->setScale(0.875); CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(RenderSettingsLayer::close)); btn->setPosition(ccp(67, -100)); @@ -557,7 +557,7 @@ bool RenderSettingsLayer::init() { FLAlertLayer::create( title.c_str(), msg.c_str(), - "Ok" + "OK" )->show(); } \ No newline at end of file diff --git a/src/ui/save_macro_layer.hpp b/src/ui/save_macro_layer.hpp index f6ec6e13..3f891609 100644 --- a/src/ui/save_macro_layer.hpp +++ b/src/ui/save_macro_layer.hpp @@ -75,13 +75,13 @@ class SaveMacroLayer : public geode::Popup { static void open() { if (Global::get().macro.inputs.empty()) - return FLAlertLayer::create("Save Macro", "You can't save an empty macro.", "Ok")->show(); + return FLAlertLayer::create("Save Macro", "You can't save an empty macro.", "OK")->show(); std::filesystem::path path = Mod::get()->getSettingValue("macros_folder"); if (!std::filesystem::exists(path)) { if (!utils::file::createDirectoryAll(path).isOk()) - return FLAlertLayer::create("Error", ("There was an error getting the folder \"" + geode::utils::string::pathToString(path) + "\". ID: 10").c_str(), "Ok")->show(); + return FLAlertLayer::create("Error", ("There was an error getting the folder \"" + geode::utils::string::pathToString(path) + "\". ID: 10").c_str(), "OK")->show(); } SaveMacroLayer* layerReal = create(); @@ -92,7 +92,7 @@ class SaveMacroLayer : public geode::Popup { void onSave(CCObject*) { std::string macroName = nameInput->getString(); if (macroName == "") - return FLAlertLayer::create("Save Macro", "Give a name to the macro.", "Ok")->show(); + return FLAlertLayer::create("Save Macro", "Give a name to the macro.", "OK")->show(); std::filesystem::path path = Mod::get()->getSettingValue("macros_folder") / macroName; std::string author = authorInput->getString(); @@ -101,7 +101,7 @@ class SaveMacroLayer : public geode::Popup { int result = Macro::save(author, desc, geode::utils::string::pathToString(path), jsonToggle->isToggled()); if (result != 0) - return FLAlertLayer::create("Error", "There was an error saving the macro. ID: " + std::to_string(result), "Ok")->show(); + return FLAlertLayer::create("Error", "There was an error saving the macro. ID: " + std::to_string(result), "OK")->show(); this->keyBackClicked(); Notification::create("Macro Saved", NotificationIcon::Success)->show(); diff --git a/src/ui/trajectory_settings_layer.hpp b/src/ui/trajectory_settings_layer.hpp index 6307e912..f429567a 100644 --- a/src/ui/trajectory_settings_layer.hpp +++ b/src/ui/trajectory_settings_layer.hpp @@ -84,7 +84,7 @@ class TrajectorySettingsLayer : public geode::Popup, public TextInputDelegate { colorButton->setPosition({m_size.width - 68, 109}); m_buttonMenu->addChild(colorButton); - ButtonSprite* btnSpr = ButtonSprite::create("Ok"); + ButtonSprite* btnSpr = ButtonSprite::create("OK"); btnSpr->setScale(0.73f); CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(btnSpr, this, menu_selector(TrajectorySettingsLayer::onClose)); btn->setPosition({m_size.width / 2, 23}); From 78ab66cab8907a51aa92f38fee3d0d5cd271159b Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 18 Feb 2026 00:01:15 +0300 Subject: [PATCH 082/211] renderer! (Windows/Linux only for now) --- src/hacks/frame_stepper.cpp | 4 +- src/hacks/other.cpp | 20 +- src/includes.hpp | 4 +- src/keybinds.cpp | 35 +- src/main.cpp | 38 +- src/renderer/ffmpeg/events.hpp | 368 ++---- src/renderer/renderer.cpp | 1648 +++++++++++++------------- src/renderer/renderer.hpp | 134 +-- src/ui/game_ui.cpp | 36 +- src/ui/record_layer.cpp | 56 +- src/ui/record_layer.hpp | 2 +- src/ui/render_settings_layer.cpp | 40 +- src/ui/trajectory_settings_layer.hpp | 1 - src/utils/utils.cpp | 4 +- 14 files changed, 1129 insertions(+), 1261 deletions(-) diff --git a/src/hacks/frame_stepper.cpp b/src/hacks/frame_stepper.cpp index 95d8c584..aefbf66d 100644 --- a/src/hacks/frame_stepper.cpp +++ b/src/hacks/frame_stepper.cpp @@ -72,8 +72,8 @@ class $modify(GJBaseGameLayer) { } auto& g = Global::get(); - // #ifndef GEODE_IS_IOS - // if (!g.renderer.recording && g.frameStepper) { + #ifdef GEODE_IS_WINDOWS + if (!g.renderer.recording && g.frameStepper) { // if (g.stepFrameParticle != 0) // g.stepFrameParticle--; diff --git a/src/hacks/other.cpp b/src/hacks/other.cpp index 9f924c15..e823d934 100644 --- a/src/hacks/other.cpp +++ b/src/hacks/other.cpp @@ -22,14 +22,14 @@ class $modify(CCScheduler) { return CCScheduler::update(dt); } - // #ifndef GEODE_IS_IOS - // if (g.renderer.recording || g.renderer.recordingAudio) { - // if (g.currentPitch != 1.f) - // Global::updatePitch(1.f); + #ifdef GEODE_IS_WINDOWS + if (g.renderer.recording || g.renderer.recordingAudio) { + if (g.currentPitch != 1.f) + Global::updatePitch(1.f); - // return CCScheduler::update(dt); - // } - // #endif + return CCScheduler::update(dt); + } + #endif float speedhack = 1.f; @@ -130,9 +130,9 @@ class $modify(PlayLayer) { Global::get().safeMode = true; if (getActionByTag(16)) { - // #ifndef GEODE_IS_IOS - // if (Global::get().renderer.recordingAudio) Global::get().renderer.stopAudio(); - // #endif + #ifndef GEODE_IS_MOBILE + /if (Global::get().renderer.recordingAudio) Global::get().renderer.stopAudio(); + #endif if (g.mod->getSavedValue("respawn_time_enabled")) { stopActionByTag(16); diff --git a/src/includes.hpp b/src/includes.hpp index df6f1fe5..37da044f 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -90,8 +90,8 @@ class Global { geode::Popup* layer = nullptr; Macro macro; - #ifndef GEODE_IS_IOS - // Renderer renderer; + #ifdef GEODE_IS_DESKTOP + Renderer renderer; #endif state state = none; diff --git a/src/keybinds.cpp b/src/keybinds.cpp index de2a287d..b30bfc8e 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -86,21 +86,20 @@ void handleKeybind(std::string const& id, bool down) { if (!g.showTrajectory) ShowTrajectory::trajectoryOff(); } - // else if (id == "toggle_render_keybind" && PlayLayer::get()) { - // #ifndef GEODE_IS_IOS - // bool result = Renderer::toggle(); - - // // if (result && Global::get().renderer.recording) - // if (result) - // Notification::create("Started Rendering", NotificationIcon::Info)->show(); - - // if (g.layer) { - // // if (static_cast(g.layer)->renderToggle) - // // static_cast(g.layer)->renderToggle->toggle(Global::get().renderer.recording); - // } - // #endif - - // } + else if (id == "toggle_render_keybind" && PlayLayer::get()) { + #ifdef GEODE_IS_WINDOWS + bool result = Renderer::toggle(); + + if (result) + Notification::create("Started Rendering", NotificationIcon::Info)->show(); + + if (g.layer) { + if (static_cast(g.layer)->renderToggle) + static_cast(g.layer)->renderToggle->toggle(Global::get().renderer.recording); + } + #endif + + } else if (id == "toggle_noclip_keybind") { g.mod->setSavedValue("macro_noclip", !g.mod->getSavedValue("macro_noclip")); @@ -134,9 +133,9 @@ void handleKeybind(std::string const& id, bool down) { listenForKeybindSettingPresses("show_trajectory_keybind", [](Keybind const&, bool down, bool repeat) { if (!repeat) handleKeybind("show_trajectory_keybind", down); }); - // listenForKeybindSettingPresses("toggle_render_keybind", [](Keybind const&, bool down, bool repeat) { - // if (!repeat) handleKeybind("toggle_render_keybind", down); - // }); + listenForKeybindSettingPresses("toggle_render_keybind", [](Keybind const&, bool down, bool repeat) { + if (!repeat) handleKeybind("toggle_render_keybind", down); + }); listenForKeybindSettingPresses("toggle_noclip_keybind", [](Keybind const&, bool down, bool repeat) { if (!repeat) handleKeybind("toggle_noclip_keybind", down); }); diff --git a/src/main.cpp b/src/main.cpp index b48baafe..d6416e08 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -60,8 +60,8 @@ class $modify(PlayLayer) { void pauseGame(bool b1) { // Global::updateKeybinds(); - #ifndef GEODE_IS_IOS - // if (!Global::get().renderer.tryPause()) return; + #ifdef GEODE_IS_WINDOWS + if (!Global::get().renderer.tryPause()) return; #endif auto& g = Global::get(); @@ -131,10 +131,10 @@ class $modify(PlayLayer) { auto& g = Global::get(); int frame = Global::getCurrentFrame(); - // #ifndef GEODE_IS_IOS - // if (!m_isPracticeMode) - // g.renderer.levelStartFrame = frame; - // #endif + #ifdef GEODE_IS_WINDOWS + if (!m_isPracticeMode) + g.renderer.levelStartFrame = frame; + #endif if (g.restart && m_levelSettings->m_platformerMode && g.state != state::none) m_fields->delayedLevelRestart = frame + 2; @@ -209,21 +209,21 @@ class $modify(BGLHook, GJBaseGameLayer) { Global::updateSeed(); bool rendering = false; - #ifndef GEODE_IS_IOS - // rendering = g.renderer.recording || g.renderer.recordingAudio; + #ifdef GEODE_IS_WINDOWS + rendering = g.renderer.recording || g.renderer.recordingAudio; #endif if (g.state != state::none || rendering) { - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (!g.firstAttempt) { - // g.renderer.dontRender = false; - // g.renderer.dontRecordAudio = false; + g.renderer.dontRender = false; + g.renderer.dontRecordAudio = false; } #endif int frame = Global::getCurrentFrame(); if (frame > 2 && g.firstAttempt && g.macro.xdBotMacro) { g.firstAttempt = false; - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if ((m_levelSettings->m_platformerMode || rendering) && !m_levelEndAnimationStarted) return pl->resetLevelFromStart(); else if (!m_levelEndAnimationStarted) @@ -244,7 +244,7 @@ class $modify(BGLHook, GJBaseGameLayer) { g.previousFrame = frame; if (g.macro.xdBotMacro && g.restart && !m_levelEndAnimationStarted) { - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if ((m_levelSettings->m_platformerMode && g.state != state::none) /*|| g.renderer.recordingAudio*/) return pl->resetLevelFromStart(); else @@ -466,9 +466,9 @@ class $modify(PauseLayer) { Loader::get()->queueInMainThread([] { auto& g = Global::get(); - #ifndef GEODE_IS_IOS - // if (g.renderer.recording) g.renderer.stop(); - // if (g.renderer.recordingAudio) g.renderer.stopAudio(); + #ifndef GEODE_IS_MOBILE + /if (g.renderer.recording) g.renderer.stop(); + if (g.renderer.recordingAudio) g.renderer.stopAudio(); #endif }); } @@ -480,9 +480,9 @@ class $modify(PauseLayer) { Loader::get()->queueInMainThread([] { auto& g = Global::get(); - #ifndef GEODE_IS_IOS - // if (g.renderer.recording) g.renderer.stop(); - // if (g.renderer.recordingAudio) g.renderer.stopAudio(); + #ifndef GEODE_IS_MOBILE + if (g.renderer.recording) g.renderer.stop(); + if (g.renderer.recordingAudio) g.renderer.stopAudio(); #endif }); } diff --git a/src/renderer/ffmpeg/events.hpp b/src/renderer/ffmpeg/events.hpp index ccf0be3e..561b6f8d 100644 --- a/src/renderer/ffmpeg/events.hpp +++ b/src/renderer/ffmpeg/events.hpp @@ -1,249 +1,119 @@ -// #pragma once - -// #include "render_settings.hpp" - -// #include - -// namespace ffmpeg::events { -// namespace impl { -// #define DEFAULT_RESULT_ERROR geode::Err("Event was not handled") - -// class CreateRecorderEvent : public geode::Event { -// public: -// CreateRecorderEvent() {m_ptr = nullptr;} -// void setPtr(void* ptr) {m_ptr = ptr;} -// void* getPtr() const {return m_ptr;} -// private: -// void* m_ptr; -// }; - -// class DeleteRecorderEvent : public geode::Event { -// public: -// DeleteRecorderEvent(void* ptr) {m_ptr = ptr;} -// void* getPtr() const {return m_ptr;} -// private: -// void* m_ptr; -// }; - -// class InitRecorderEvent : public geode::Event { -// public: -// InitRecorderEvent(void* ptr, const RenderSettings* settings) { -// m_ptr = ptr; -// m_renderSettings = settings; -// } - -// void setResult(geode::Result<>&& result) {m_result = std::move(result);} -// geode::Result<> getResult() {return m_result;} - -// void* getPtr() const {return m_ptr;} - -// const RenderSettings& getRenderSettings() const {return *m_renderSettings;} - -// private: -// const RenderSettings* m_renderSettings; -// void* m_ptr; -// geode::Result<> m_result = DEFAULT_RESULT_ERROR; -// }; - -// class StopRecorderEvent : public geode::Event { -// public: -// StopRecorderEvent(void* ptr) {m_ptr = ptr;} -// void* getPtr() const {return m_ptr;} -// private: -// void* m_ptr; -// }; - -// struct Dummy {}; - -// class GetWriteFrameFunctionEvent : public geode::Event { -// public: -// using writeFrame_t = geode::Result<>(Dummy::*)(std::vector const&); -// GetWriteFrameFunctionEvent() = default; - -// void setFunction(writeFrame_t function) {m_function = function;} -// writeFrame_t getFunction() const {return m_function;} -// private: -// writeFrame_t m_function; -// }; - -// class CodecRecorderEvent : public geode::Event { -// public: -// CodecRecorderEvent() = default; - -// void setCodecs(std::vector&& codecs) {m_codecs = std::move(codecs);} -// const std::vector& getCodecs() const {return m_codecs;} -// private: -// std::vector m_codecs; -// }; - -// class MixVideoAudioEvent : public geode::Event { -// public: -// MixVideoAudioEvent(const std::filesystem::path& videoFile, const std::filesystem::path& audioFile, const std::filesystem::path& outputMp4File) { -// m_videoFile = &videoFile; -// m_audioFile = &audioFile; -// m_outputMp4File = &outputMp4File; -// } - -// void setResult(geode::Result<>&& result) {m_result = std::move(result);} -// geode::Result<> getResult() {return m_result;} - -// std::filesystem::path const& getVideoFile() const {return *m_videoFile;} -// std::filesystem::path const& getAudioFile() const {return *m_audioFile;} -// std::filesystem::path const& getOutputMp4File() const {return *m_outputMp4File;} - -// private: -// const std::filesystem::path* m_videoFile; -// const std::filesystem::path* m_audioFile; -// const std::filesystem::path* m_outputMp4File; -// geode::Result<> m_result = DEFAULT_RESULT_ERROR; -// }; - -// class MixVideoRawEvent : public geode::Event { -// public: -// MixVideoRawEvent(const std::filesystem::path& videoFile, const std::vector& raw, const std::filesystem::path& outputMp4File) { -// m_videoFile = &videoFile; -// m_raw = &raw; -// m_outputMp4File = &outputMp4File; -// } - -// void setResult(const geode::Result<>& result) {m_result = geode::Result(result);} -// geode::Result<> getResult() {return m_result;} - -// std::filesystem::path const& getVideoFile() const {return *m_videoFile;} -// std::vector const& getRaw() const {return *m_raw;} -// std::filesystem::path const& getOutputMp4File() const {return *m_outputMp4File;} - -// private: -// const std::filesystem::path* m_videoFile; -// const std::vector* m_raw; -// const std::filesystem::path* m_outputMp4File; -// geode::Result<> m_result = DEFAULT_RESULT_ERROR; -// }; -// #undef DEFAULT_RESULT_ERROR -// } - -// class Recorder { -// public: -// Recorder() { -// impl::CreateRecorderEvent createEvent; -// createEvent.post(); -// m_ptr = static_cast(createEvent.getPtr()); -// } - -// ~Recorder() { -// impl::DeleteRecorderEvent deleteEvent(m_ptr); -// deleteEvent.post(); -// } - -// bool isValid() const {return m_ptr != nullptr;} - -// /** -// * @brief Initializes the Recorder with the specified rendering settings. -// * -// * This function configures the recorder with the given render settings, -// * allocates necessary resources, and prepares for video encoding. -// * -// * @param settings The rendering settings that define the output characteristics, -// * including codec, bitrate, resolution, and pixel format. -// * -// * @return true if initialization is successful, false otherwise. -// */ -// geode::Result<> init(RenderSettings const& settings) { -// impl::InitRecorderEvent initEvent(m_ptr, &settings); -// initEvent.post(); -// return initEvent.getResult(); -// } -// /** -// * @brief Stops the recording process and finalizes the output file. -// * -// * This function ensures that all buffered frames are written to the output file, -// * releases allocated resources, and properly closes the output file. -// */ -// void stop() { -// impl::StopRecorderEvent(m_ptr).post(); -// } - -// /** -// * @brief Writes a single video frame to the output. -// * -// * This function takes the frame data as a byte vector and encodes it -// * to the output file. The frame data must match the expected format and -// * dimensions defined during initialization. -// * -// * @param frameData A vector containing the raw frame data to be written. -// * -// * @return true if the frame is successfully written, false if there is an error. -// * -// * @warning Ensure that the frameData size matches the expected dimensions of the frame. -// */ -// geode::Result<> writeFrame(const std::vector& frameData) { -// static auto writeFrame = []{ -// impl::GetWriteFrameFunctionEvent event; -// event.post(); -// return event.getFunction(); -// }(); -// if (!writeFrame) return geode::Err("Failed to call writeFrame function."); -// return std::invoke(writeFrame, m_ptr, frameData); -// } - -// /** -// * @brief Retrieves a list of available codecs for video encoding. -// * -// * This function iterates through all available codecs in FFmpeg and -// * returns a sorted vector of codec names. -// * -// * @return A vector representing the names of available codecs. -// */ -// static std::vector getAvailableCodecs() { -// impl::CodecRecorderEvent codecEvent; -// codecEvent.post(); -// return codecEvent.getCodecs(); -// } -// private: -// impl::Dummy* m_ptr = nullptr; -// }; - -// class AudioMixer { -// public: -// AudioMixer() = delete; - -// /** -// * @brief Mixes a video file and an audio file into a single MP4 output. -// * -// * This function takes an input video file and an audio file, and merges them into a single MP4 output file. -// * The output MP4 file will have both the video and audio streams synchronized. -// * -// * @param videoFile The path to the input video file. -// * @param audioFile The path to the input audio file. -// * @param outputMp4File The path where the output MP4 file will be saved. -// * -// * @warning The audio file is expected to contain stereo (dual-channel) audio. Using other formats might lead to unexpected results. -// * @warning The video file is expected to contain a single video stream. Only the first video stream will be copied. -// */ -// static geode::Result<> mixVideoAudio(std::filesystem::path const& videoFile, std::filesystem::path const& audioFile, std::filesystem::path const& outputMp4File) { -// impl::MixVideoAudioEvent mixEvent(videoFile, audioFile, outputMp4File); -// mixEvent.post(); -// return mixEvent.getResult(); -// } - -// /** -// * @brief Mixes a video file and raw audio data into a single MP4 output. -// * -// * This function takes an input video file and raw audio data (in the form of a vector of floating-point samples), -// * and merges them into a single MP4 output file. -// * -// * @param videoFile The path to the input video file. -// * @param raw A vector containing the raw audio data (floating-point samples). -// * @param outputMp4File The path where the output MP4 file will be saved. -// * -// * @warning The raw audio data is expected to be stereo (dual-channel). Using mono or multi-channel audio might lead to issues. -// * @warning The video file is expected to contain a single video stream. Only the first video stream will be copied. -// */ -// static geode::Result<> mixVideoRaw(std::filesystem::path const& videoFile, const std::vector& raw, std::filesystem::path const& outputMp4File) { -// impl::MixVideoRawEvent mixEvent(videoFile, raw, outputMp4File); -// mixEvent.post(); -// return mixEvent.getResult(); -// } -// }; - -// } \ No newline at end of file +#pragma once + +#include "render_settings.hpp" + +#include +#include +#include + +namespace ffmpeg::events { +namespace impl { + +#define DEFAULT_RESULT_ERROR geode::Err("Event was not handled") + + // Listeners should supply a pointer to an internal recorder implementation + // by returning it when CreateRecorderEvent is sent. + // Create: returns created pointer via out-parameter + class CreateRecorderEvent : public geode::ThreadSafeEvent {}; + + // Listener will be called with the pointer to delete/cleanup. + class DeleteRecorderEvent : public geode::ThreadSafeEvent {}; + + // Initialize recorder: listener should return a geode::Result<> + // Initialize: listener should write result into out param + class InitRecorderEvent : public geode::ThreadSafeEvent&, const RenderSettings&)> {}; + + class StopRecorderEvent : public geode::ThreadSafeEvent {}; + + // Provide a write-frame function. Listener should return a callable which accepts (void* impl, const std::vector&) + using write_frame_fn_t = std::function(void*, const std::vector&)>; + // Provide write-frame function via out param + class GetWriteFrameFunctionEvent : public geode::ThreadSafeEvent {}; + + // Provide codecs via out param + class CodecRecorderEvent : public geode::ThreadSafeEvent&)> {}; + + // Mixing: write result into out param + class MixVideoAudioEvent : public geode::ThreadSafeEvent&, const std::filesystem::path&, const std::filesystem::path&, const std::filesystem::path&)> {}; + + class MixVideoRawEvent : public geode::ThreadSafeEvent&, const std::filesystem::path&, const std::vector&, const std::filesystem::path&)> {}; + +#undef DEFAULT_RESULT_ERROR +} + +// Recorder wrapper that communicates with a platform-specific backend via Geode events. +class Recorder { +public: + Recorder() { + // Ask listeners to create a recorder and return implementation pointer via out-param + void* ptr = nullptr; + if (impl::CreateRecorderEvent().send(ptr)) { + m_ptr = static_cast(ptr); + } else { + m_ptr = nullptr; + } + } + + ~Recorder() { + if (m_ptr) { + impl::DeleteRecorderEvent().send(reinterpret_cast(m_ptr)); + m_ptr = nullptr; + } + } + + bool isValid() const { return m_ptr != nullptr; } + + geode::Result<> init(RenderSettings const& settings) { + if (!m_ptr) return geode::Err("Recorder not initialized"); + geode::Result<> res = geode::Err("Event was not handled"); + if (!impl::InitRecorderEvent().send(reinterpret_cast(m_ptr), res, settings)) + return geode::Err("Event was not handled"); + return res; + } + + void stop() { + if (!m_ptr) return; + impl::StopRecorderEvent().send(reinterpret_cast(m_ptr)); + } + + geode::Result<> writeFrame(const std::vector& frameData) { + impl::write_frame_fn_t fn; + if (!impl::GetWriteFrameFunctionEvent().send(fn)) + return geode::Err("Failed to obtain write-frame function"); + if (!fn) return geode::Err("No write-frame function available"); + return fn(reinterpret_cast(m_ptr), frameData); + } + + static std::vector getAvailableCodecs() { + std::vector out; + if (!impl::CodecRecorderEvent().send(out)) + return {}; + return out; + } + +private: + // opaque impl pointer returned by platform-specific listener + struct Dummy {}; + Dummy* m_ptr = nullptr; +}; + +class AudioMixer { +public: + AudioMixer() = delete; + + static geode::Result<> mixVideoAudio(const std::filesystem::path& videoFile, const std::filesystem::path& audioFile, const std::filesystem::path& outputMp4File) { + geode::Result<> out = geode::Err("Event was not handled"); + if (!impl::MixVideoAudioEvent().send(out, videoFile, audioFile, outputMp4File)) + return geode::Err("Event was not handled"); + return out; + } + + static geode::Result<> mixVideoRaw(const std::filesystem::path& videoFile, const std::vector& raw, const std::filesystem::path& outputMp4File) { + geode::Result<> out = geode::Err("Event was not handled"); + if (!impl::MixVideoRawEvent().send(out, videoFile, raw, outputMp4File)) + return geode::Err("Event was not handled"); + return out; + } +}; + +} // namespace ffmpeg::events diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 06860f06..17b42730 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -1,841 +1,839 @@ -// #include "../includes.hpp" -// #include "../ui/game_ui.hpp" -// #include "../utils/subprocess.hpp" - -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include - -// #include -// #include -// #include - -// #ifndef GEODE_IS_IOS -// class $modify(CCParticleSystemQuad) { - -// static CCParticleSystemQuad* create(const char* v1, bool v2) { -// CCParticleSystemQuad* ret = CCParticleSystemQuad::create(v1, v2); -// if (!Global::get().renderer.recording) return ret; - -// if (std::string_view(v1) == "levelComplete01.plist" && Mod::get()->getSavedValue("render_hide_levelcomplete")) -// ret->setVisible(false); - -// return ret; -// } - -// }; - -// class $modify(CCCircleWave) { - -// static CCCircleWave* create(float v1, float v2, float v3, bool v4, bool v5) { -// CCCircleWave* ret = CCCircleWave::create(v1, v2, v3, v4, v5); - -// if (!Global::get().renderer.recording || !PlayLayer::get()->m_levelEndAnimationStarted) return ret; - -// if (Mod::get()->getSavedValue("render_hide_levelcomplete")) -// ret->setVisible(false); - -// return ret; -// } - -// }; - -// class $modify(PlayLayer) { - -// void showCompleteText() { -// PlayLayer::showCompleteText(); -// if (!Global::get().renderer.recording) return; - -// if (m_levelEndAnimationStarted && Mod::get()->getSavedValue("render_hide_levelcomplete")) { -// for (CCNode* node : CCArrayExt(getChildren())) { -// CCSprite* spr = typeinfo_cast(node); -// if (!spr) continue; -// if (!isSpriteFrameName(spr, "GJ_levelComplete_001.png")) continue; -// spr->setVisible(false); -// } -// } -// } - -// }; - -// class $modify(EndLevelLayer) { +#include "../includes.hpp" +#include "../ui/game_ui.hpp" +#include "../utils/subprocess.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef GEODE_IS_WINDOWS +class $modify(CCParticleSystemQuad) { -// void customSetup() { -// EndLevelLayer::customSetup(); - -// if (!PlayLayer::get()) return; -// if (Global::get().renderer.recording && PlayLayer::get()->m_levelEndAnimationStarted && Mod::get()->getSavedValue("render_hide_endscreen")) { -// Loader::get()->queueInMainThread([this] { -// setVisible(false); -// }); -// } -// } - -// }; - -// class $modify(FMODAudioEngine) { - -// int playEffect(gd::string path, float speed, float p2, float volume) { -// if (path == "explode_11.ogg" && Global::get().renderer.recording) return 0; - -// if (path != "playSound_01.ogg" || !Global::get().renderer.recordingAudio) -// return FMODAudioEngine::playEffect(path, speed, p2, volume); - -// return 0; -// } -// }; - -// class $modify(GJBaseGameLayer) { -// void update(float dt) { -// GJBaseGameLayer::update(dt); -// auto& g = Global::get(); - -// PlayLayer* pl = PlayLayer::get(); - -// if ((!g.renderer.recording && !g.renderer.recordingAudio) || !pl) return; + static CCParticleSystemQuad* create(const char* v1, bool v2) { + CCParticleSystemQuad* ret = CCParticleSystemQuad::create(v1, v2); + if (!Global::get().renderer.recording) return ret; -// int frame = Global::getCurrentFrame(); - -// if (g.renderer.recording && frame % static_cast(Global::getTPS() / g.renderer.fps) == 0) -// return g.renderer.handleRecording(pl, frame); - -// if (g.renderer.recordingAudio && !g.renderer.startedAudio) { -// return g.renderer.startAudio(pl); -// } - -// if (g.renderer.recordingAudio && frame % static_cast(Global::getTPS() / g.renderer.fps) == 0) -// return g.renderer.handleAudioRecording(pl, frame); -// } -// }; - -// float leftOver = 0.f; - -// class $modify(CCScheduler) { - -// void update(float dt) { -// Renderer& r = Global::get().renderer; -// if (!r.recording) return CCScheduler::update(dt); - -// r.changeRes(false); - -// using namespace std::literals; + if (std::string_view(v1) == "levelComplete01.plist" && Mod::get()->getSavedValue("render_hide_levelcomplete")) + ret->setVisible(false); -// float newDt = 1.f / Global::getTPS(); - -// auto startTime = std::chrono::high_resolution_clock::now(); -// int mult = static_cast((dt + leftOver) / newDt); - -// for (int i = 0; i < mult; ++i) { -// CCScheduler::update(newDt); -// if (std::chrono::high_resolution_clock::now() - startTime > 33.333ms) { -// mult = i + 1; -// break; -// } -// } - -// leftOver += (dt - newDt * mult); - -// r.changeRes(true); -// } - -// }; - -// bool Renderer::shouldUseAPI() { -// #ifdef GEODE_IS_WINDOWS - -// bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); -// std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); -// bool foundExe = std::filesystem::exists(ffmpegPath) && geode::utils::string::pathToString(ffmpegPath.filename()) == "ffmpeg.exe"; - -// return !foundExe && foundApi; - -// #else - -// return true; - -// #endif - -// } - -// bool Renderer::toggle() { -// auto& g = Global::get(); -// if (Loader::get()->isModLoaded("syzzi.click_between_frames")) { -// FLAlertLayer::create("Render", "Disable CBF in Geode to render a level.", "OK")->show(); -// return false; -// } - -// bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); -// std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); -// bool foundExe = std::filesystem::exists(ffmpegPath) && geode::utils::string::pathToString(ffmpegPath.filename()) == "ffmpeg.exe"; - -// g.renderer.usingApi = Renderer::shouldUseAPI(); - -// if (g.renderer.recording || g.renderer.recordingAudio) { -// g.renderer.recordingAudio ? g.renderer.stopAudio() : g.renderer.stop(Global::getCurrentFrame()); -// } -// else { - -// #ifdef GEODE_IS_WINDOWS -// if (!foundExe && !foundApi) { -// geode::createQuickPopup( -// "Error", -// "FFmpeg not found, set the path to the .exe in mod settings or install FFmpeg API.\nOpen download link?", -// "Cancel", "Yes", -// [](auto, bool btn2) { -// if (btn2) { -// FLAlertLayer::create("Info", "Unzip the downloaded file and look for ffmpeg.exe in the 'bin' folder.", "OK")->show(); -// utils::web::openLinkInBrowser("https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-essentials.7z"); -// } -// } -// ); -// return false; -// } - -// g.renderer.ffmpegPath = geode::utils::string::pathToString(ffmpegPath); -// #else -// if (!foundApi) { -// FLAlertLayer::create("Error", "FFmpeg API not found. Download it to render a level.", "OK")->show(); -// return false; -// } -// #endif - -// if (!PlayLayer::get()) { -// FLAlertLayer::create("Warning", "Open a level to start rendering it.", "OK")->show(); -// return false; -// } - -// std::filesystem::path path = Mod::get()->getSettingValue("render_folder"); - -// if (std::filesystem::exists(path)) -// g.renderer.start(); -// else { -// if (utils::file::createDirectoryAll(path).isOk()) -// g.renderer.start(); -// else { -// FLAlertLayer::create("Error", "There was an error getting the renders folder. ID: 11", "OK")->show(); -// return false; -// } -// } -// } - -// Interface::updateLabels(); - -// return true; -// } - -// void Renderer::start() { -// PlayLayer* pl = PlayLayer::get(); -// GameManager* gm = GameManager::sharedState(); -// Mod* mod = Mod::get(); -// fmod = FMODAudioEngine::sharedEngine(); - -// fps = geode::utils::numFromString(mod->getSavedValue("render_fps")).unwrap(); -// codec = mod->getSavedValue("render_codec"); -// bitrate = mod->getSavedValue("render_bitrate") + "M"; -// extraArgs = mod->getSavedValue("render_args"); -// videoArgs = mod->getSavedValue("render_video_args"); -// extraAudioArgs = mod->getSavedValue("render_audio_args"); -// SFXVolume = mod->getSavedValue("render_sfx_volume"); -// musicVolume = mod->getSavedValue("render_music_volume"); -// stopAfter = geode::utils::numFromString(mod->getSavedValue("render_seconds_after")).unwrapOr(0.f); -// audioMode = AudioMode::Off; -// std::string extension = mod->getSavedValue("render_file_extension"); - -// if (mod->getSavedValue("render_only_song")) audioMode = AudioMode::Song; -// if (mod->getSavedValue("render_record_audio")) audioMode = AudioMode::Record; - -// auto now = std::chrono::system_clock::now(); -// auto duration = now.time_since_epoch(); -// auto timestamp = std::chrono::duration_cast(duration).count(); + return ret; + } -// std::string filename = fmt::format("render_{}_{}{}", std::string_view(pl->m_level->m_levelName), std::to_string(timestamp), extension); -// std::string path = geode::utils::string::pathToString(Mod::get()->getSettingValue("render_folder") / filename); - -// width = geode::utils::numFromString(mod->getSavedValue("render_width2")).unwrap(); -// height = geode::utils::numFromString(mod->getSavedValue("render_height")).unwrap(); - -// if (width % 2 != 0) -// width++; -// if (height % 2 != 0) -// height++; - -// renderer.width = width; -// renderer.height = height; -// ogRes = cocos2d::CCEGLView::get()->getDesignResolutionSize(); -// ogScaleX = cocos2d::CCEGLView::get()->m_fScaleX; -// ogScaleY = cocos2d::CCEGLView::get()->m_fScaleY; - -// dontRender = true; -// recording = true; -// frameHasData = false; -// levelFinished = false; -// startedAudio = false; -// timeAfter = 0.f; -// finishFrame = 0; -// pauseAttempts = 0; -// lastFrame_t = extra_t = 0; - -// if (!pl->m_levelEndAnimationStarted && pl->m_isPaused) -// Global::get().restart = true; - -// if (Global::get().state != state::playing && !Global::get().macro.inputs.empty()) -// Macro::togglePlaying(); - -// std::string songFile = pl->m_level->getAudioFileName(); -// if (pl->m_level->m_songID == 0) -// songFile = cocos2d::CCFileUtils::sharedFileUtils()->fullPathForFilename(songFile.c_str(), false); - -// float songOffset = pl->m_levelSettings->m_songOffset + (fmod->m_musicOffset / 1000.f) + (levelStartFrame / Global::getTPS()); -// bool fadeIn = pl->m_levelSettings->m_fadeIn; -// bool fadeOut = pl->m_levelSettings->m_fadeOut; -// int bitrateApi = geode::utils::numFromString(mod->getSavedValue("render_bitrate")).unwrapOr(30) * 1000000; - -// currentFrame.resize(width * height * 3, 0); -// renderedFrames.clear(); -// renderer.begin(); -// changeRes(false); +}; -// ffmpeg::RenderSettings settings; -// settings.m_pixelFormat = ffmpeg::PixelFormat::RGB24; -// settings.m_codec = codec; -// settings.m_bitrate = bitrateApi; -// settings.m_width = width; -// settings.m_height = height; -// settings.m_fps = fps; -// settings.m_outputFile = path; -// settings.m_colorspaceFilters = videoArgs; - -// if (!Mod::get()->setSavedValue("first_render_", true)) { -// FLAlertLayer::create( -// "Warning", -// "If you have a macro for the level, let it run to allow the level to render.", -// "OK" -// )->show(); -// } +class $modify(CCCircleWave) { + + static CCCircleWave* create(float v1, float v2, float v3, bool v4, bool v5) { + CCCircleWave* ret = CCCircleWave::create(v1, v2, v3, v4, v5); + + if (!Global::get().renderer.recording || !PlayLayer::get()->m_levelEndAnimationStarted) return ret; + + if (Mod::get()->getSavedValue("render_hide_levelcomplete")) + ret->setVisible(false); + + return ret; + } + +}; -// std::thread([&, path, songFile, songOffset, fadeIn, fadeOut, extension, bitrateApi, settings]() { -// if (!codec.empty()) codec = "-c:v " + codec + " "; -// if (!bitrate.empty()) bitrate = "-b:v " + bitrate + " "; -// if (extraArgs.empty()) extraArgs = "-pix_fmt yuv420p"; -// if (videoArgs.empty()) videoArgs = "colorspace=all=bt709:iall=bt470bg:fast=1"; +class $modify(PlayLayer) { + + void showCompleteText() { + PlayLayer::showCompleteText(); + if (!Global::get().renderer.recording) return; + + if (m_levelEndAnimationStarted && Mod::get()->getSavedValue("render_hide_levelcomplete")) { + for (CCNode* node : CCArrayExt(getChildren())) { + CCSprite* spr = typeinfo_cast(node); + if (!spr) continue; + if (!isSpriteFrameName(spr, "GJ_levelComplete_001.png")) continue; + spr->setVisible(false); + } + } + } + +}; -// float fadeInTime = geode::utils::numFromString(Mod::get()->getSavedValue("render_fade_in_time")).unwrapOr(0.f); -// bool fadeInVideo = Mod::get()->getSavedValue("render_fade_in") && fadeInTime != 0.f; -// float fadeOutTime = geode::utils::numFromString(Mod::get()->getSavedValue("render_fade_out_time")).unwrapOr(0.f); -// bool fadeOutVideo = Mod::get()->getSavedValue("render_fade_out") && fadeOutTime != 0.f; +class $modify(EndLevelLayer) { + + void customSetup() { + EndLevelLayer::customSetup(); + + if (!PlayLayer::get()) return; + if (Global::get().renderer.recording && PlayLayer::get()->m_levelEndAnimationStarted && Mod::get()->getSavedValue("render_hide_endscreen")) { + Loader::get()->queueInMainThread([this] { + setVisible(false); + }); + } + } + +}; -// std::string fadeArgs; -// std::string command; -// #ifdef GEODE_IS_WINDOWS -// subprocess::Popen process; -// #endif +class $modify(FMODAudioEngine) { + + int playEffect(gd::string path, float speed, float p2, float volume) { + if (path == "explode_11.ogg" && Global::get().renderer.recording) return 0; + + if (path != "playSound_01.ogg" || !Global::get().renderer.recordingAudio) + return FMODAudioEngine::playEffect(path, speed, p2, volume); + + return 0; + } +}; + +class $modify(GJBaseGameLayer) { + void update(float dt) { + GJBaseGameLayer::update(dt); + auto& g = Global::get(); + + PlayLayer* pl = PlayLayer::get(); + + if ((!g.renderer.recording && !g.renderer.recordingAudio) || !pl) return; + + int frame = Global::getCurrentFrame(); + + if (g.renderer.recording && frame % static_cast(Global::getTPS() / g.renderer.fps) == 0) + return g.renderer.handleRecording(pl, frame); + + if (g.renderer.recordingAudio && !g.renderer.startedAudio) { + return g.renderer.startAudio(pl); + } + + if (g.renderer.recordingAudio && frame % static_cast(Global::getTPS() / g.renderer.fps) == 0) + return g.renderer.handleAudioRecording(pl, frame); + } +}; -// if (fadeInVideo) -// fadeArgs = fmt::format(",fade=t=in:st=0:d={}", fadeInTime); +float leftOver = 0.f; -// if (usingApi) { -// auto res = ffmpeg.init(settings); -// if (res.isErr()) { -// Loader::get()->queueInMainThread([] { -// // std::string err = res.unwrapErr(); -// FLAlertLayer::create("Error", "FFmpeg API failed to initialize: ", "OK")->show(); -// }); +class $modify(CCScheduler) { + + void update(float dt) { + Renderer& r = Global::get().renderer; + if (!r.recording) return CCScheduler::update(dt); + + r.changeRes(false); + + using namespace std::literals; + + float newDt = 1.f / Global::getTPS(); + + auto startTime = std::chrono::high_resolution_clock::now(); + int mult = static_cast((dt + leftOver) / newDt); + + for (int i = 0; i < mult; ++i) { + CCScheduler::update(newDt); + if (std::chrono::high_resolution_clock::now() - startTime > 33.333ms) { + mult = i + 1; + break; + } + } + + leftOver += (dt - newDt * mult); + + r.changeRes(true); + } + +}; -// audioMode = AudioMode::Off; -// return stop(); -// } +bool Renderer::shouldUseAPI() { + // ffmpeg api is not ported + return false; + +} + +bool Renderer::toggle() { + auto& g = Global::get(); + if (Loader::get()->isModLoaded("syzzi.click_between_frames")) { + FLAlertLayer::create("Render", "Disable CBF in Geode to render a level.", "OK")->show(); + return false; + } + + bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); + std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); + bool foundExe = std::filesystem::exists(ffmpegPath) && geode::utils::string::pathToString(ffmpegPath.filename()) == "ffmpeg.exe"; + + g.renderer.usingApi = false; + + if (g.renderer.recording || g.renderer.recordingAudio) { + g.renderer.recordingAudio ? g.renderer.stopAudio() : g.renderer.stop(Global::getCurrentFrame()); + } + else { + + #ifdef GEODE_IS_WINDOWS + if (!foundExe) { + geode::createQuickPopup( + "Error", + "FFmpeg not found, set the path to the .exe in mod settings.\nOpen download link?", + "Cancel", "Yes", + [](auto, bool btn2) { + if (btn2) { + FLAlertLayer::create("Info", "Unzip the downloaded file and look for ffmpeg.exe in the 'bin' folder.", "OK")->show(); + utils::web::openLinkInBrowser("https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-essentials.7z"); + } + } + ); + return false; + } + + g.renderer.ffmpegPath = geode::utils::string::pathToString(ffmpegPath); + #else + FLAlertLayer::create("Error", "Rendering is not supported on this platform yet.", "OK")->show(); + return false; + #endif + + if (!PlayLayer::get()) { + FLAlertLayer::create("Warning", "Open a level to start rendering it.", "OK")->show(); + return false; + } + + std::filesystem::path path = Mod::get()->getSettingValue("render_folder"); + + if (std::filesystem::exists(path)) + g.renderer.start(); + else { + if (utils::file::createDirectoryAll(path).isOk()) + g.renderer.start(); + else { + FLAlertLayer::create("Error", "There was an error getting the renders folder. ID: 11", "OK")->show(); + return false; + } + } + } + + Interface::updateLabels(); + + return true; +} + +void Renderer::start() { + PlayLayer* pl = PlayLayer::get(); + GameManager* gm = GameManager::sharedState(); + Mod* mod = Mod::get(); + fmod = FMODAudioEngine::sharedEngine(); + + fps = geode::utils::numFromString(mod->getSavedValue("render_fps")).unwrap(); + codec = mod->getSavedValue("render_codec"); + bitrate = mod->getSavedValue("render_bitrate") + "M"; + extraArgs = mod->getSavedValue("render_args"); + videoArgs = mod->getSavedValue("render_video_args"); + extraAudioArgs = mod->getSavedValue("render_audio_args"); + SFXVolume = mod->getSavedValue("render_sfx_volume"); + musicVolume = mod->getSavedValue("render_music_volume"); + stopAfter = geode::utils::numFromString(mod->getSavedValue("render_seconds_after")).unwrapOr(0.f); + audioMode = AudioMode::Off; + std::string extension = mod->getSavedValue("render_file_extension"); + + if (mod->getSavedValue("render_only_song")) audioMode = AudioMode::Song; + if (mod->getSavedValue("render_record_audio")) audioMode = AudioMode::Record; + + auto now = std::chrono::system_clock::now(); + auto duration = now.time_since_epoch(); + auto timestamp = std::chrono::duration_cast(duration).count(); + + std::string filename = fmt::format("render_{}_{}{}", std::string_view(pl->m_level->m_levelName), std::to_string(timestamp), extension); + std::string path = geode::utils::string::pathToString(Mod::get()->getSettingValue("render_folder") / filename); + + width = geode::utils::numFromString(mod->getSavedValue("render_width2")).unwrap(); + height = geode::utils::numFromString(mod->getSavedValue("render_height")).unwrap(); + + if (width % 2 != 0) + width++; + if (height % 2 != 0) + height++; + + renderer.width = width; + renderer.height = height; + ogRes = cocos2d::CCEGLView::get()->getDesignResolutionSize(); + ogScaleX = cocos2d::CCEGLView::get()->m_fScaleX; + ogScaleY = cocos2d::CCEGLView::get()->m_fScaleY; + + dontRender = true; + recording = true; + frameHasData = false; + levelFinished = false; + startedAudio = false; + timeAfter = 0.f; + finishFrame = 0; + pauseAttempts = 0; + lastFrame_t = extra_t = 0; + + if (!pl->m_levelEndAnimationStarted && pl->m_isPaused) + Global::get().restart = true; + + if (Global::get().state != state::playing && !Global::get().macro.inputs.empty()) + Macro::togglePlaying(); + + std::string songFile = pl->m_level->getAudioFileName(); + if (pl->m_level->m_songID == 0) + songFile = cocos2d::CCFileUtils::sharedFileUtils()->fullPathForFilename(songFile.c_str(), false); + + float songOffset = pl->m_levelSettings->m_songOffset + (fmod->m_musicOffset / 1000.f) + (levelStartFrame / Global::getTPS()); + bool fadeIn = pl->m_levelSettings->m_fadeIn; + bool fadeOut = pl->m_levelSettings->m_fadeOut; + int bitrateApi = geode::utils::numFromString(mod->getSavedValue("render_bitrate")).unwrapOr(30) * 1000000; + + currentFrame.resize(width * height * 3, 0); + renderedFrames.clear(); + renderer.begin(); + changeRes(false); + + ffmpeg::RenderSettings settings; + settings.m_pixelFormat = ffmpeg::PixelFormat::RGB24; + settings.m_codec = codec; + settings.m_bitrate = bitrateApi; + settings.m_width = width; + settings.m_height = height; + settings.m_fps = fps; + settings.m_outputFile = path; + settings.m_colorspaceFilters = videoArgs; + + if (!Mod::get()->setSavedValue("first_render_", true)) { + FLAlertLayer::create( + "Warning", + "If you have a macro for the level, let it run to allow the level to render.", + "OK" + )->show(); + } + + std::thread([&, path, songFile, songOffset, fadeIn, fadeOut, extension, bitrateApi, settings]() { + if (!codec.empty()) codec = "-c:v " + codec + " "; + if (!bitrate.empty()) bitrate = "-b:v " + bitrate + " "; + if (extraArgs.empty()) extraArgs = "-pix_fmt yuv420p"; + if (videoArgs.empty()) videoArgs = "colorspace=all=bt709:iall=bt470bg:fast=1"; + + float fadeInTime = geode::utils::numFromString(Mod::get()->getSavedValue("render_fade_in_time")).unwrapOr(0.f); + bool fadeInVideo = Mod::get()->getSavedValue("render_fade_in") && fadeInTime != 0.f; + float fadeOutTime = geode::utils::numFromString(Mod::get()->getSavedValue("render_fade_out_time")).unwrapOr(0.f); + bool fadeOutVideo = Mod::get()->getSavedValue("render_fade_out") && fadeOutTime != 0.f; + + std::string fadeArgs; + std::string command; + #ifdef GEODE_IS_WINDOWS + subprocess::Popen process; + #endif + + if (fadeInVideo) + fadeArgs = fmt::format(",fade=t=in:st=0:d={}", fadeInTime); + + if (usingApi) { + auto res = ffmpeg.init(settings); + if (res.isErr()) { + Loader::get()->queueInMainThread([] { + // std::string err = res.unwrapErr(); + FLAlertLayer::create("Error", "FFmpeg API failed to initialize: ", "OK")->show(); + }); + + audioMode = AudioMode::Off; + return stop(); + } -// } else { -// #ifdef GEODE_IS_WINDOWS -// command = fmt::format( -// "\"{}\" -y -f rawvideo -pix_fmt rgb24 -s {}x{} -r {} -i - {}{}{} -vf \"vflip,{}{}\" -an \"{}\" ", -// ffmpegPath, -// std::to_string(width), -// std::to_string(height), -// std::to_string(fps), -// codec, -// bitrate, -// extraArgs, -// videoArgs, -// fadeArgs, -// path -// ); - -// log::info("Executing: {}", command); - -// process = subprocess::Popen(command); -// #endif -// } - -// while (recording || pause || recordingAudio || frameHasData) { -// lock.lock(); -// if (frameHasData) { -// const std::vector frame = currentFrame; -// frameHasData = false; -// lock.unlock(); -// if (usingApi) { -// auto res = ffmpeg.writeFrame(frame); -// if (res.isErr()) { -// Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "FFmpeg API failed: ", "OK")->show(); -// }); - -// audioMode = AudioMode::Off; -// stop(); -// break; -// } -// } -// #ifdef GEODE_IS_WINDOWS -// else -// process.m_stdin.write(frame.data(), frame.size()); -// #endif -// } -// else lock.unlock(); -// } - -// if (usingApi) { -// ffmpeg.stop(); -// } -// else { -// #ifdef GEODE_IS_WINDOWS -// if (process.close()) { -// Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "There was an error saving the render. Wrong render Args.", "OK")->show(); -// }); -// return; -// } -// #endif -// } - -// Loader::get()->queueInMainThread([] { -// Notification::create("Saving Render...", NotificationIcon::Loading)->show(); -// }); -// std::this_thread::sleep_for(std::chrono::milliseconds(100)); - -// if ((SFXVolume == 0.f && musicVolume == 0.f) || audioMode == AudioMode::Off || (audioMode == AudioMode::Song && !std::filesystem::exists(songFile)) || (audioMode == AudioMode::Record && !std::filesystem::exists("fmodoutput.wav"))) { -// if (audioMode != AudioMode::Off) { -// Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "Song File not found.", "OK")->show(); -// }); - -// std::this_thread::sleep_for(std::chrono::milliseconds(100)); -// } - -// Loader::get()->queueInMainThread([] { -// Notification::create("Render Saved Without Audio", NotificationIcon::Success)->show(); -// if (!Mod::get()->getSavedValue("render_hide_endscreen")) return; -// if (PlayLayer* pl = PlayLayer::get()) -// if (EndLevelLayer* layer = pl->getChildByType(0)) -// layer->setVisible(true); -// }); - -// return; -// } - -// std::filesystem::path tempPath = std::filesystem::path(path).parent_path() / ("temp_" + geode::utils::string::pathToString(std::filesystem::path(path).filename())); -// std::filesystem::path tempPathAudio = (Mod::get()->getSaveDir() / "temp_audio_file.wav"); - -// if (usingApi) { -// std::string file = audioMode == AudioMode::Song ? songFile : "fmodoutput.wav"; -// auto res = ffmpeg::events::AudioMixer::mixVideoAudio(path, file, tempPath); -// log::debug("XD"); -// if (res.isErr()) { -// Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "FFmpeg failed to add audio: ", "OK")->show(); -// }); -// return; -// } -// } -// else { -// #ifdef GEODE_IS_WINDOWS - -// double totalTime = lastFrame_t; -// if (fadeOutTime > totalTime) fadeOutTime = totalTime / 2; -// float fadeOutStart = totalTime - fadeOutTime; - -// if (fadeOutVideo) { -// command = fmt::format("\"{}\" -i \"{}\" -vf \"fade=t=out:st={}:d={}\" {}{}-c:a copy \"{}\"", ffmpegPath, path, fadeOutStart, std::to_string(fadeOutTime), codec, bitrate, path + "_temp" + extension); - -// log::info("Executing (Fade Out): {}", command); -// process = subprocess::Popen(command); -// if (!process.close()) { -// std::error_code ec; -// std::filesystem::remove(path, ec); -// if (ec) log::warn("Failed to remove old render file."); -// else { -// ec.clear(); -// std::filesystem::rename(path + "_temp" + extension, path, ec); -// if (ec) log::warn("Failed to rename temp render file."); -// } -// } else log::debug("Fade Out Error xD"); -// } - -// if (audioMode == AudioMode::Record) { -// command = fmt::format("\"{}\" -i \"fmodoutput.wav\" -acodec pcm_s16le -ar 44100 -ac 2 \"{}\"", -// ffmpegPath, tempPathAudio -// ); - -// process = subprocess::Popen(command); // Fix ffmpeg not reading it -// if (process.close()) { -// Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "There was an error adding the song. ID: 140", "OK")->show(); -// }); -// return; -// } -// } - -// { - -// std::string fadeInString; -// if ((fadeIn && audioMode == AudioMode::Song) || fadeInVideo) -// fadeInString = fmt::format(", afade=t=in:d={}", fadeInVideo ? std::to_string(fadeInTime) : "2"); - -// std::string fadeOutString; -// if ((fadeOut && audioMode == AudioMode::Song) || fadeOutVideo) -// fadeOutString = fmt::format( -// ", afade=t=out:d={}:st={}", -// fadeOutVideo ? std::to_string(fadeOutTime) : "2", -// fadeOutVideo ? fadeOutStart : totalTime - timeAfter - 3.5f -// ); - -// std::filesystem::path file = audioMode == AudioMode::Song ? songFile : tempPathAudio; -// float offset = audioMode == AudioMode::Song ? songOffset : (isPlatformer ? 0.28f : 0.f); - -// if (!extraAudioArgs.empty()) extraAudioArgs += " "; - -// std::string volume = audioMode == AudioMode::Song ? fmt::format(",volume={:.2f}", musicVolume) : ""; - -// command = fmt::format( -// "\"{}\" -y -ss {} -i \"{}\" -i \"{}\" -t {} -c:v copy {} -filter:a \"[1:a]adelay=0|0{}{}{}\" \"{}\"", -// ffmpegPath, -// offset, -// file, -// path, -// totalTime, -// extraAudioArgs, -// fadeInString, -// fadeOutString, -// volume, -// tempPath -// ); - -// log::info("Executing (Audio): {}", command); - -// auto process = subprocess::Popen(command); -// if (process.close()) { -// Loader::get()->queueInMainThread([] { -// FLAlertLayer::create("Error", "There was an error adding the song. Wrong Audio Args.", "OK")->show(); -// }); -// return; -// } -// } - -// #endif -// } - -// std::error_code ec; -// std::filesystem::remove(Utils::widen(path), ec); -// if (ec) log::warn("Failed to remove old render file."); -// else { -// ec.clear(); -// std::filesystem::rename(tempPath, Utils::widen(path), ec); -// if (ec) log::warn("Failed to rename temp render file."); -// } - -// ec.clear(); -// std::filesystem::remove(tempPathAudio, ec); -// if (ec) log::warn("Failed to remove temp audio file."); - -// ec.clear(); -// std::filesystem::remove("fmodoutput.wav", ec); -// if (ec) log::warn("Failed to remove fmod audio file."); - -// Loader::get()->queueInMainThread([] { -// Notification::create("Render Saved With Audio", NotificationIcon::Success)->show(); -// }); + } else { + #ifdef GEODE_IS_WINDOWS + command = fmt::format( + "\"{}\" -y -f rawvideo -pix_fmt rgb24 -s {}x{} -r {} -i - {}{}{} -vf \"vflip,{}{}\" -an \"{}\" ", + ffmpegPath, + std::to_string(width), + std::to_string(height), + std::to_string(fps), + codec, + bitrate, + extraArgs, + videoArgs, + fadeArgs, + path + ); + + log::info("Executing: {}", command); + + process = subprocess::Popen(command); + #endif + } -// }).detach(); -// } - -// void Renderer::stop(int frame) { -// renderedFrames.clear(); -// finishFrame = Global::getCurrentFrame(); -// pause = true; -// recording = false; -// timeAfter = 0.f; - -// if (usingApi) audioMode = AudioMode::Off; - -// if (PlayLayer* pl = PlayLayer::get()) { - -// if (pl->m_isPaused && audioMode == AudioMode::Record) { -// if (PauseLayer* layer = Global::getPauseLayer()) { -// CCScene* scene = CCDirector::sharedDirector()->getRunningScene(); -// if (RecordLayer* xdbot = scene->getChildByType(0)) -// xdbot->onClose(nullptr); + int frameCount = 0; + while (recording || pause || recordingAudio || frameHasData) { + lock.lock(); + if (frameHasData) { + const std::vector frame = currentFrame; + frameHasData = false; + lock.unlock(); + if (usingApi) { + auto res = ffmpeg.writeFrame(frame); + if (res.isErr()) { + Loader::get()->queueInMainThread([] { + FLAlertLayer::create("Error", "FFmpeg API failed: ", "OK")->show(); + }); + + audioMode = AudioMode::Off; + stop(); + break; + } + } + #ifdef GEODE_IS_WINDOWS + else { + process.m_stdin.write(frame.data(), frame.size()); + frameCount++; + + } + #endif + } + else lock.unlock(); + } + + + if (usingApi) { + ffmpeg.stop(); + } + else { + #ifdef GEODE_IS_WINDOWS + + if (process.close()) { + log::error("[RENDER] FFmpeg process failed with error code"); + Loader::get()->queueInMainThread([] { + FLAlertLayer::create("Error", "There was an error saving the render. Wrong render Args.", "OK")->show(); + }); + return; + } + + #endif + } + + Loader::get()->queueInMainThread([] { + Notification::create("Saving Render...", NotificationIcon::Loading)->show(); + }); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + if ((SFXVolume == 0.f && musicVolume == 0.f) || audioMode == AudioMode::Off || (audioMode == AudioMode::Song && !std::filesystem::exists(songFile)) || (audioMode == AudioMode::Record && !std::filesystem::exists("fmodoutput.wav"))) { + if (audioMode != AudioMode::Off) { + Loader::get()->queueInMainThread([] { + FLAlertLayer::create("Error", "Song File not found.", "OK")->show(); + }); -// layer->onResume(nullptr); -// } -// } -// else if (pl->m_levelEndAnimationStarted) { -// finishFrame = 0; -// levelFinished = true; -// } - -// } else -// audioMode = AudioMode::Off; - -// if (audioMode == AudioMode::Record) { -// recordingAudio = true; -// dontRecordAudio = true; -// Notification::create("Recording Audio...", NotificationIcon::Loading)->show(); -// } - -// pause = false; -// changeRes(true); -// } - -// void Renderer::changeRes(bool og) { -// cocos2d::CCEGLView* view = cocos2d::CCEGLView::get(); -// cocos2d::CCSize res = {0, 0}; -// float scaleX = 1.f; -// float scaleY = 1.f; - -// res = og ? ogRes : CCSize(320.f * (width / static_cast(height)), 320.f); -// scaleX = og ? ogScaleX : (width / res.width); -// scaleY = og ? ogScaleY : (height / res.height); - -// if (res == CCSize(0, 0) && !og) return changeRes(true); - -// CCDirector::sharedDirector()->m_obWinSizeInPoints = res; -// view->setDesignResolutionSize(res.width, res.height, ResolutionPolicy::kResolutionExactFit); -// view->m_fScaleX = scaleX; -// view->m_fScaleY = scaleY; -// } - -// void MyRenderTexture::begin() { -// if (Global::get().renderer.usingApi) { -// glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo); - -// texture = new CCTexture2D(); -// { -// std::unique_ptr data(static_cast(malloc(width * height * 3)), free); -// memset(data.get(), 0, width * height * 3); -// texture->initWithData(data.get(), kCCTexture2DPixelFormat_RGB888, width, height, CCSize(static_cast(width), static_cast(height))); -// } - -// glGetIntegerv(GL_RENDERBUFFER_BINDING, &old_rbo); - -// glGenFramebuffers(1, &fbo); -// glBindFramebuffer(GL_FRAMEBUFFER, fbo); - -// glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture->getName(), 0); - -// texture->setAliasTexParameters(); - -// texture->autorelease(); - -// glBindRenderbuffer(GL_RENDERBUFFER, old_rbo); -// glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); -// #ifdef GEODE_IS_WINDOWS -// } else { -// glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); - -// texture = new CCTexture2D(); -// { -// auto data = malloc(width * height * 3); -// memset(data, 0, width * height * 3); -// texture->initWithData(data, kCCTexture2DPixelFormat_RGB888, width, height, CCSize(static_cast(width), static_cast(height))); -// free(data); -// } - -// glGetIntegerv(GL_RENDERBUFFER_BINDING_EXT, &old_rbo); - -// glGenFramebuffersEXT(1, &fbo); -// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); - -// glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture->getName(), 0); - -// texture->setAliasTexParameters(); - -// texture->autorelease(); - -// glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, old_rbo); -// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo); -// } -// #else -// } -// #endif -// } - -// void MyRenderTexture::capture(std::mutex& lock, std::vector& data, volatile bool& hasData) { -// CCDirector* director = CCDirector::sharedDirector(); -// PlayLayer* pl = PlayLayer::get(); - -// if (Global::get().renderer.usingApi) { -// glViewport(0, 0, width, height); -// glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo); -// glBindFramebuffer(GL_FRAMEBUFFER, fbo); - -// pl->visit(); - -// glPixelStorei(GL_PACK_ALIGNMENT, 1); -// lock.lock(); -// hasData = true; -// glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data.data()); -// lock.unlock(); - -// glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); -// director->setViewport(); -// #ifdef GEODE_IS_WINDOWS -// } else { -// glViewport(-1, 1.0, width, height); -// glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); -// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); - -// pl->visit(); - -// glPixelStorei(GL_PACK_ALIGNMENT, 1); -// lock.lock(); -// hasData = true; -// glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data.data()); -// lock.unlock(); - -// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo); -// director->setViewport(); -// } -// #else -// } -// #endif -// } - -// void Renderer::captureFrame() { -// while (frameHasData) {} -// renderer.capture(lock, currentFrame, frameHasData); -// } -// int wa = 0; -// void Renderer::handleRecording(PlayLayer* pl, int frame) { -// if (!pl) stop(frame); -// isPlatformer = pl->m_levelSettings->m_platformerMode; -// if (dontRender || pl->m_player1->m_isDead) return; - -// auto& g = Global::get(); -// if (renderedFrames.contains(frame) && frame > 10) -// return; - -// renderedFrames.insert(frame); - -// if (!pl->m_hasCompletedLevel || timeAfter < stopAfter) { - -// float dt = 1.f / static_cast(fps); -// if (pl->m_hasCompletedLevel) { -// timeAfter += dt; -// levelFinished = true; -// } - -// float time = pl->m_gameState.m_levelTime + extra_t - lastFrame_t; -// if (time >= dt) { -// extra_t = time - dt; -// lastFrame_t = pl->m_gameState.m_levelTime; - -// int correctMusicTime = static_cast((frame / static_cast(Global::getTPS()) + pl->m_levelSettings->m_songOffset) * 1000); -// correctMusicTime += fmod->m_musicOffset; - -// if (fmod->getMusicTimeMS(0) - correctMusicTime >= 110) -// fmod->setMusicTimeMS(correctMusicTime, true, 0); - -// captureFrame(); -// } -// } -// else stop(frame); -// } - -// bool Renderer::tryPause() { -// if (!recordingAudio) return true; - -// pauseAttempts++; - -// if (pauseAttempts > 5) { -// pauseAttempts = 0; -// stopAudio(); -// return true; -// } - -// return false; -// } - -// void Renderer::startAudio(PlayLayer* pl) { -// EndLevelLayer* endLevelLayer = pl->getChildByType(0); -// if (dontRecordAudio) return; - -// if (pl->m_levelEndAnimationStarted && endLevelLayer != nullptr) { -// CCKeyboardDispatcher::get()->dispatchKeyboardMSG(enumKeyCodes::KEY_Space, true, false); -// CCKeyboardDispatcher::get()->dispatchKeyboardMSG(enumKeyCodes::KEY_Space, false, false); -// } -// else if (!pl->m_levelEndAnimationStarted) { - -// if (!pl->m_isPaused) -// pl->pauseGame(false); - -// if (Global::get().state != state::playing) -// Macro::togglePlaying(); - -// Global::get().restart = true; - -// if (PauseLayer* layer = Global::getPauseLayer()) -// layer->onResume(nullptr); - -// auto fmod = FMODAudioEngine::sharedEngine(); -// fmod->m_globalChannel->getVolume(&ogSFXVol); -// fmod->m_backgroundMusicChannel->getVolume(&ogMusicVol); - -// FMODAudioEngine::sharedEngine()->m_system->setOutput(FMOD_OUTPUTTYPE_WAVWRITER); -// startedAudio = true; -// pauseAttempts = 0; -// if (CCNode* lbl = pl->getChildByID("recording-audio-label"_spr)) -// lbl->setVisible(true); -// } -// } - -// void Renderer::stopAudio() { -// FMODAudioEngine::sharedEngine()->m_system->setOutput(FMOD_OUTPUTTYPE_AUTODETECT); -// auto fmod = FMODAudioEngine::sharedEngine(); -// fmod->m_globalChannel->setVolume(ogSFXVol); -// fmod->m_backgroundMusicChannel->setVolume(ogMusicVol); - -// recordingAudio = false; -// if (PlayLayer* pl = PlayLayer::get()) -// if (CCNode* lbl = pl->getChildByID("recording-audio-label"_spr)) -// lbl->setVisible(false); -// } - -// void Renderer::handleAudioRecording(PlayLayer* pl, int frame) { -// auto& g = Global::get(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + Loader::get()->queueInMainThread([] { + Notification::create("Render Saved Without Audio", NotificationIcon::Success)->show(); + if (!Mod::get()->getSavedValue("render_hide_endscreen")) return; + if (PlayLayer* pl = PlayLayer::get()) + if (EndLevelLayer* layer = pl->getChildByType(0)) + layer->setVisible(true); + }); + + return; + } + + std::filesystem::path tempPath = std::filesystem::path(path).parent_path() / ("temp_" + geode::utils::string::pathToString(std::filesystem::path(path).filename())); + std::filesystem::path tempPathAudio = (Mod::get()->getSaveDir() / "temp_audio_file.wav"); + + if (usingApi) { + std::string file = audioMode == AudioMode::Song ? songFile : "fmodoutput.wav"; + auto res = ffmpeg::events::AudioMixer::mixVideoAudio(path, file, tempPath); + log::debug("XD"); + if (res.isErr()) { + Loader::get()->queueInMainThread([] { + FLAlertLayer::create("Error", "FFmpeg failed to add audio: ", "OK")->show(); + }); + return; + } + } + else { + #ifdef GEODE_IS_WINDOWS + + double totalTime = lastFrame_t; + if (fadeOutTime > totalTime) fadeOutTime = totalTime / 2; + float fadeOutStart = totalTime - fadeOutTime; + + if (fadeOutVideo) { + command = fmt::format("\"{}\" -i \"{}\" -vf \"fade=t=out:st={}:d={}\" {}{}-c:a copy \"{}\"", ffmpegPath, path, fadeOutStart, std::to_string(fadeOutTime), codec, bitrate, path + "_temp" + extension); + + log::info("Executing (Fade Out): {}", command); + process = subprocess::Popen(command); + if (!process.close()) { + std::error_code ec; + std::filesystem::remove(path, ec); + if (ec) log::warn("Failed to remove old render file."); + else { + ec.clear(); + std::filesystem::rename(path + "_temp" + extension, path, ec); + if (ec) log::warn("Failed to rename temp render file."); + } + } else log::debug("Fade Out Error xD"); + } + + if (audioMode == AudioMode::Record) { + command = fmt::format("\"{}\" -i \"fmodoutput.wav\" -acodec pcm_s16le -ar 44100 -ac 2 \"{}\"", + ffmpegPath, tempPathAudio + ); + + process = subprocess::Popen(command); + if (process.close()) { + Loader::get()->queueInMainThread([] { + FLAlertLayer::create("Error", "There was an error adding the song. ID: 140", "OK")->show(); + }); + return; + } + } + + { + + std::string fadeInString; + if ((fadeIn && audioMode == AudioMode::Song) || fadeInVideo) + fadeInString = fmt::format(", afade=t=in:d={}", fadeInVideo ? std::to_string(fadeInTime) : "2"); + + std::string fadeOutString; + if ((fadeOut && audioMode == AudioMode::Song) || fadeOutVideo) + fadeOutString = fmt::format( + ", afade=t=out:d={}:st={}", + fadeOutVideo ? std::to_string(fadeOutTime) : "2", + fadeOutVideo ? fadeOutStart : totalTime - timeAfter - 3.5f + ); + + std::filesystem::path file = audioMode == AudioMode::Song ? songFile : tempPathAudio; + float offset = audioMode == AudioMode::Song ? songOffset : (isPlatformer ? 0.28f : 0.f); + + if (!extraAudioArgs.empty()) extraAudioArgs += " "; + + std::string volume = audioMode == AudioMode::Song ? fmt::format(",volume={:.2f}", musicVolume) : ""; + + command = fmt::format( + "\"{}\" -y -ss {} -i \"{}\" -i \"{}\" -t {} -c:v copy {} -filter:a \"[1:a]adelay=0|0{}{}{}\" \"{}\"", + ffmpegPath, + offset, + file, + path, + totalTime, + extraAudioArgs, + fadeInString, + fadeOutString, + volume, + tempPath + ); + + log::info("Executing (Audio): {}", command); + + auto process = subprocess::Popen(command); + if (process.close()) { + Loader::get()->queueInMainThread([] { + FLAlertLayer::create("Error", "There was an error adding the song. Wrong Audio Args.", "OK")->show(); + }); + return; + } + } + + #endif + } + + std::error_code ec; + std::filesystem::remove(Utils::widen(path), ec); + if (ec) log::warn("Failed to remove old render file."); + else { + ec.clear(); + std::filesystem::rename(tempPath, Utils::widen(path), ec); + if (ec) log::warn("Failed to rename temp render file."); + } + + ec.clear(); + std::filesystem::remove(tempPathAudio, ec); + if (ec) log::warn("Failed to remove temp audio file."); + + ec.clear(); + std::filesystem::remove("fmodoutput.wav", ec); + if (ec) log::warn("Failed to remove fmod audio file."); + + Loader::get()->queueInMainThread([] { + Notification::create("Render Saved With Audio", NotificationIcon::Success)->show(); + }); + + }).detach(); +} + +void Renderer::stop(int frame) { + renderedFrames.clear(); + finishFrame = Global::getCurrentFrame(); + pause = true; + recording = false; + timeAfter = 0.f; -// fmod->m_globalChannel->setVolume(SFXVolume); -// fmod->m_backgroundMusicChannel->setVolume(musicVolume); - -// if (!pl) { -// g.renderer.stopAudio(); -// return; -// } - -// if (finishFrame != 0 && frame >= finishFrame) { -// g.renderer.stopAudio(); -// return; -// } + if (usingApi) audioMode = AudioMode::Off; + + if (PlayLayer* pl = PlayLayer::get()) { + + if (pl->m_isPaused && audioMode == AudioMode::Record) { + if (PauseLayer* layer = Global::getPauseLayer()) { + CCScene* scene = CCDirector::sharedDirector()->getRunningScene(); + if (RecordLayer* xdbot = scene->getChildByType(0)) + xdbot->onClose(nullptr); + + layer->onResume(nullptr); + } + } + else if (pl->m_levelEndAnimationStarted) { + finishFrame = 0; + levelFinished = true; + } + + } else + audioMode = AudioMode::Off; + + if (audioMode == AudioMode::Record) { + recordingAudio = true; + dontRecordAudio = true; + Notification::create("Recording Audio...", NotificationIcon::Loading)->show(); + } + + pause = false; + changeRes(true); +} + +void Renderer::changeRes(bool og) { + cocos2d::CCEGLView* view = cocos2d::CCEGLView::get(); + cocos2d::CCSize res = {0, 0}; + float scaleX = 1.f; + float scaleY = 1.f; + + res = og ? ogRes : CCSize(320.f * (width / static_cast(height)), 320.f); + scaleX = og ? ogScaleX : (width / res.width); + scaleY = og ? ogScaleY : (height / res.height); + + if (res == CCSize(0, 0) && !og) return changeRes(true); + + CCDirector::sharedDirector()->m_obWinSizeInPoints = res; + view->setDesignResolutionSize(res.width, res.height, ResolutionPolicy::kResolutionExactFit); + view->m_fScaleX = scaleX; + view->m_fScaleY = scaleY; +} + +void MyRenderTexture::begin() { + if (Global::get().renderer.usingApi) { + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo); + + texture = new CCTexture2D(); + { + std::unique_ptr data(static_cast(malloc(width * height * 3)), free); + memset(data.get(), 0, width * height * 3); + texture->initWithData(data.get(), kCCTexture2DPixelFormat_RGB888, width, height, CCSize(static_cast(width), static_cast(height))); + } + + glGetIntegerv(GL_RENDERBUFFER_BINDING, &old_rbo); + + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture->getName(), 0); + + texture->setAliasTexParameters(); + + texture->autorelease(); + + glBindRenderbuffer(GL_RENDERBUFFER, old_rbo); + glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); + #ifdef GEODE_IS_WINDOWS + } else { + glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); + + texture = new CCTexture2D(); + { + auto data = malloc(width * height * 3); + memset(data, 0, width * height * 3); + texture->initWithData(data, kCCTexture2DPixelFormat_RGB888, width, height, CCSize(static_cast(width), static_cast(height))); + free(data); + } + + glGetIntegerv(GL_RENDERBUFFER_BINDING_EXT, &old_rbo); + + glGenFramebuffersEXT(1, &fbo); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture->getName(), 0); + + texture->setAliasTexParameters(); + + texture->autorelease(); + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, old_rbo); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo); + } + #else +} +#endif +} + +void MyRenderTexture::capture(std::mutex& lock, std::vector& data, volatile bool& hasData) { + CCDirector* director = CCDirector::sharedDirector(); + PlayLayer* pl = PlayLayer::get(); + + if (Global::get().renderer.usingApi) { + glViewport(0, 0, width, height); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + pl->visit(); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + lock.lock(); + hasData = true; + glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data.data()); + lock.unlock(); + + glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); + director->setViewport(); + #ifdef GEODE_IS_WINDOWS + } else { + glViewport(0, 0, width, height); + glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); + + pl->visit(); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + lock.lock(); + hasData = true; + glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data.data()); + lock.unlock(); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo); + director->setViewport(); + } + #else +} +#endif +} + +void Renderer::captureFrame() { + static int captureCount = 0; + while (frameHasData) {} + renderer.capture(lock, currentFrame, frameHasData); + captureCount++; + if (captureCount % 30 == 0) log::debug("[RENDER] Captured {} frames", captureCount); +} +int wa = 0; +void Renderer::handleRecording(PlayLayer* pl, int frame) { + if (!pl) stop(frame); + isPlatformer = pl->m_levelSettings->m_platformerMode; + if (dontRender || pl->m_player1->m_isDead) return; + + auto& g = Global::get(); + if (renderedFrames.contains(frame) && frame > 10) + return; + + renderedFrames.insert(frame); + + if (!pl->m_hasCompletedLevel || timeAfter < stopAfter) { + + float dt = 1.f / static_cast(fps); + if (pl->m_hasCompletedLevel) { + timeAfter += dt; + levelFinished = true; + } + + float time = pl->m_gameState.m_levelTime + extra_t - lastFrame_t; + if (time >= dt) { + extra_t = time - dt; + lastFrame_t = pl->m_gameState.m_levelTime; + + int correctMusicTime = static_cast((frame / static_cast(Global::getTPS()) + pl->m_levelSettings->m_songOffset) * 1000); + correctMusicTime += fmod->m_musicOffset; + + if (fmod->getMusicTimeMS(0) - correctMusicTime >= 110) + fmod->setMusicTimeMS(correctMusicTime, true, 0); + + captureFrame(); + } + } + else stop(frame); +} + +bool Renderer::tryPause() { + if (!recordingAudio) return true; + + pauseAttempts++; + + if (pauseAttempts > 5) { + pauseAttempts = 0; + stopAudio(); + return true; + } + + return false; +} -// if (!pl->m_hasCompletedLevel || timeAfter < stopAfter) { -// float dt = 1.f / static_cast(fps); -// if (pl->m_hasCompletedLevel) -// timeAfter += dt; -// } -// else -// g.renderer.stopAudio(); -// } -// #endif \ No newline at end of file +void Renderer::startAudio(PlayLayer* pl) { + EndLevelLayer* endLevelLayer = pl->getChildByType(0); + if (dontRecordAudio) return; + + if (pl->m_levelEndAnimationStarted && endLevelLayer != nullptr) { + CCKeyboardDispatcher::get()->dispatchKeyboardMSG(enumKeyCodes::KEY_Space, true, false, 0.0); + CCKeyboardDispatcher::get()->dispatchKeyboardMSG(enumKeyCodes::KEY_Space, false, false, 0.0); + } + else if (!pl->m_levelEndAnimationStarted) { + + if (!pl->m_isPaused) + pl->pauseGame(false); + + if (Global::get().state != state::playing) + Macro::togglePlaying(); + + Global::get().restart = true; + + if (PauseLayer* layer = Global::getPauseLayer()) + layer->onResume(nullptr); + + auto fmod = FMODAudioEngine::sharedEngine(); + fmod->m_globalChannel->getVolume(&ogSFXVol); + fmod->m_backgroundMusicChannel->getVolume(&ogMusicVol); + + FMODAudioEngine::sharedEngine()->m_system->setOutput(FMOD_OUTPUTTYPE_WAVWRITER); + startedAudio = true; + pauseAttempts = 0; + if (CCNode* lbl = pl->getChildByID("recording-audio-label"_spr)) + lbl->setVisible(true); + } +} + +void Renderer::stopAudio() { + FMODAudioEngine::sharedEngine()->m_system->setOutput(FMOD_OUTPUTTYPE_AUTODETECT); + auto fmod = FMODAudioEngine::sharedEngine(); + fmod->m_globalChannel->setVolume(ogSFXVol); + fmod->m_backgroundMusicChannel->setVolume(ogMusicVol); + + recordingAudio = false; + if (PlayLayer* pl = PlayLayer::get()) + if (CCNode* lbl = pl->getChildByID("recording-audio-label"_spr)) + lbl->setVisible(false); +} + +void Renderer::handleAudioRecording(PlayLayer* pl, int frame) { + auto& g = Global::get(); + + fmod->m_globalChannel->setVolume(SFXVolume); + fmod->m_backgroundMusicChannel->setVolume(musicVolume); + + if (!pl) { + g.renderer.stopAudio(); + return; + } + + if (finishFrame != 0 && frame >= finishFrame) { + g.renderer.stopAudio(); + return; + } + + if (!pl->m_hasCompletedLevel || timeAfter < stopAfter) { + float dt = 1.f / static_cast(fps); + if (pl->m_hasCompletedLevel) + timeAfter += dt; + } + else + g.renderer.stopAudio(); +} +#endif \ No newline at end of file diff --git a/src/renderer/renderer.hpp b/src/renderer/renderer.hpp index 9ef180e8..00cd9d11 100644 --- a/src/renderer/renderer.hpp +++ b/src/renderer/renderer.hpp @@ -1,81 +1,81 @@ -// #include "../includes.hpp" -// #include "ffmpeg/events.hpp" +#include "../includes.hpp" +#include "ffmpeg/events.hpp" -// #ifndef GEODE_IS_IOS -// enum AudioMode { -// Off = 0, -// Song = 1, -// Record = 2 -// }; +#ifdef GEODE_IS_WINDOWS +enum AudioMode { + Off = 0, + Song = 1, + Record = 2 +}; -// class MyRenderTexture { -// public: -// unsigned width, height; -// int old_fbo, old_rbo; -// unsigned fbo; -// geode::prelude::CCTexture2D* texture = nullptr; -// void begin(); -// void capture(std::mutex& lock, std::vector& data, volatile bool& lul); -// }; +class MyRenderTexture { +public: + unsigned width, height; + int old_fbo, old_rbo; + unsigned fbo; + geode::prelude::CCTexture2D* texture = nullptr; + void begin(); + void capture(std::mutex& lock, std::vector& data, volatile bool& lul); +}; -// class Renderer { -// public: +class Renderer { +public: -// Renderer() : width(1920), height(1080), fps(60) {} + Renderer() : width(1920), height(1080), fps(60) {} -// volatile bool frameHasData; -// bool levelFinished = false; -// bool recording = false; -// bool pause = false; -// int audioMode = 0; -// float ogMusicVol; -// float ogSFXVol; -// float SFXVolume = 1.f; -// float musicVolume = 1.f; + volatile bool frameHasData; + bool levelFinished = false; + bool recording = false; + bool pause = false; + int audioMode = 0; + float ogMusicVol; + float ogSFXVol; + float SFXVolume = 1.f; + float musicVolume = 1.f; -// bool usingApi = false; -// bool dontRender = false; -// bool dontRecordAudio = false; -// bool recordingAudio = false; -// bool startedAudio = false; -// bool isPlatformer = false; -// int finishFrame = 0; -// int levelStartFrame = 0; + bool usingApi = false; + bool dontRender = false; + bool dontRecordAudio = false; + bool recordingAudio = false; + bool startedAudio = false; + bool isPlatformer = false; + int finishFrame = 0; + int levelStartFrame = 0; -// float stopAfter = 3.f; -// float timeAfter = 0.f; -// unsigned width, height; -// unsigned fps; -// double lastFrame_t, extra_t; -// int pauseAttempts = 0; + float stopAfter = 3.f; + float timeAfter = 0.f; + unsigned width, height; + unsigned fps; + double lastFrame_t, extra_t; + int pauseAttempts = 0; -// MyRenderTexture renderer; -// ffmpeg::events::Recorder ffmpeg; -// std::vector currentFrame; -// std::mutex lock; -// std::string codec = "", bitrate = "12M", extraArgs = "", videoArgs = "", extraAudioArgs = "", path = ""; -// std::string ffmpegPath = geode::utils::string::pathToString(geode::dirs::getGameDir() / "ffmpeg.exe"); -// std::unordered_set renderedFrames; + MyRenderTexture renderer; + ffmpeg::events::Recorder ffmpeg; + std::vector currentFrame; + std::mutex lock; + std::string codec = "", bitrate = "12M", extraArgs = "", videoArgs = "", extraAudioArgs = "", path = ""; + std::string ffmpegPath = geode::utils::string::pathToString(geode::dirs::getGameDir() / "ffmpeg.exe"); + std::unordered_set renderedFrames; -// FMODAudioEngine* fmod = nullptr; -// cocos2d::CCSize ogRes = {0, 0}; -// float ogScaleX = 1.f; -// float ogScaleY = 1.f; + FMODAudioEngine* fmod = nullptr; + cocos2d::CCSize ogRes = {0, 0}; + float ogScaleX = 1.f; + float ogScaleY = 1.f; -// void captureFrame(); -// void changeRes(bool og); + void captureFrame(); + void changeRes(bool og); -// void start(); -// void startAudio(PlayLayer* pl); + void start(); + void startAudio(PlayLayer* pl); -// void stop(int frame = 0); -// void stopAudio(); + void stop(int frame = 0); + void stopAudio(); -// void handleRecording(PlayLayer* pl, int frame); -// void handleAudioRecording(PlayLayer* pl, int frame); + void handleRecording(PlayLayer* pl, int frame); + void handleAudioRecording(PlayLayer* pl, int frame); -// static bool toggle(); -// static bool shouldUseAPI(); -// bool tryPause(); -// }; -// #endif \ No newline at end of file + static bool toggle(); + static bool shouldUseAPI(); + bool tryPause(); +}; +#endif \ No newline at end of file diff --git a/src/ui/game_ui.cpp b/src/ui/game_ui.cpp index 6a3993f8..a543ce92 100644 --- a/src/ui/game_ui.cpp +++ b/src/ui/game_ui.cpp @@ -13,15 +13,15 @@ class $modify(PlayLayer) { PlayLayer::postUpdate(dt); auto& g = Global::get(); - //#ifndef GEODE_IS_IOS - // if (g.state != state::none && g.frameLabel && !g.renderer.recording) { - // m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); - // } - // #else + #ifdef GEODE_IS_WINDOWS + if (g.state != state::none && g.frameLabel && !g.renderer.recording) { + m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); + } + #else if (g.state != state::none && g.frameLabel) { m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); } - // #endif + #endif } bool init(GJGameLevel * level, bool b1, bool b2) { @@ -114,34 +114,34 @@ void Interface::updateLabels() { if (!pl) return; if (g.state == state::none || !g.frameLabel) - static_cast(pl->getChildByID("frame-label"_spr))->setString(""); + static_cast(pl->getChildByID("frame-label"_spr))->setString(""); CCLabelBMFont* label = typeinfo_cast(pl->getChildByID("state-label"_spr)); if (!label) return; if (g.mod->getSavedValue("macro_hide_labels")) - return label->setString(""); + return label->setString(""); state state = g.state; std::string labelText = state == state::none ? "" : "Playing"; if (state == state::recording) - labelText = "Recording"; + labelText = "Recording"; if (labelText == "Recording" && state == state::recording && g.mod->getSavedValue("macro_hide_recording_label")) - labelText = ""; + labelText = ""; if (labelText == "Playing" && state == state::playing && g.mod->getSavedValue("macro_hide_playing_label")) + labelText = ""; + +#ifdef GEODE_IS_WINDOWS + if (g.renderer.recording && g.mod->getSavedValue("render_hide_labels")) { labelText = ""; + if (CCLabelBMFont* lbl = typeinfo_cast(pl->getChildByID("frame-label"_spr))) + lbl->setString(""); + } + #endif -// #ifndef GEODE_IS_IOS - // if (g.renderer.recording && g.mod->getSavedValue("render_hide_labels")) { - // labelText = ""; - // if (CCLabelBMFont* lbl = typeinfo_cast(pl->getChildByID("frame-label"_spr))) - // lbl->setString(""); - // } -// #endif - label->setString(labelText.c_str()); } diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 9e449370..dcf2f1c4 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -259,25 +259,27 @@ class $modify(PauseLayer) { this->updateTPS(); } - // #ifndef GEODE_IS_IOS - /*void RecordLayer::toggleRender(CCObject* btn) { - if (!Renderer::toggle()) - static_cast(btn)->toggle(true); - - if (Global::get().renderer.recordingAudio) - static_cast(btn)->toggle(false); - }*/ - // #else - void RecordLayer::toggleRenderIOS(CCObject* btn) { - FLAlertLayer::create("Info", "Rendering is not supported yet!", "OK")->show(); + void RecordLayer::toggleRender(CCObject* btn) { +#ifdef GEODE_IS_WINDOWS + if (!Renderer::toggle()) + static_cast(btn)->toggle(true); + + if (Global::get().renderer.recordingAudio) + static_cast(btn)->toggle(false); +#else + toggleRender2(btn); +#endif + } + + void RecordLayer::toggleRender2(CCObject* btn) { + FLAlertLayer::create("Info", "Rendering is not supported on your platform due to technical limitations.", "OK")->show(); } - // #endif void RecordLayer::onEditMacro(CCObject*) { MacroEditLayer::open(); } - void RecordLayer::toggleFPS(bool on) { // forgotten + void RecordLayer::toggleFPS(bool on) { return; float scaleSpr = -0.8, scaleBtn = -1; int opacityBtn = 57, opacityLbl = 80; @@ -907,26 +909,26 @@ class $modify(PauseLayer) { bg->setZOrder(29); menu->addChild(bg); - ButtonSprite* spriteOn2 = ButtonSprite::create("N/A"); + #ifdef GEODE_IS_WINDOWS + ButtonSprite* spriteOn2 = ButtonSprite::create("Stop"); spriteOn2->setScale(0.74f); - ButtonSprite* spriteOff2 = ButtonSprite::create("N/A"); + ButtonSprite* spriteOff2 = ButtonSprite::create("Start"); spriteOff2->setScale(0.74f); - // ButtonSprite* spriteOn2 = ButtonSprite::create("Stop"); - // spriteOn2->setScale(0.74f); - // ButtonSprite* spriteOff2 = ButtonSprite::create("Start"); - // spriteOff2->setScale(0.74f); - - //#ifdef GEODE_IS_IOS - renderToggle = CCMenuItemToggler::create(spriteOn2, spriteOff2, this, menu_selector(RecordLayer::toggleRenderIOS)); + + renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRender)); + renderToggle->toggle(g.renderer.recording || g.renderer.recordingAudio); renderToggle->setPosition(ccp(-65.5, -100)); menu->addChild(renderToggle); - // #else - // renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRender)); - // renderToggle->toggle(g.renderer.recording || g.renderer.recordingAudio); - + #else + ButtonSprite* spriteOn2 = ButtonSprite::create("N/A"); + spriteOn2->setScale(0.74f); + ButtonSprite* spriteOff2 = ButtonSprite::create("N/A"); + spriteOff2->setScale(0.74f); + + renderToggle = CCMenuItemToggler::create(spriteOn2, spriteOff2, this, menu_selector(RecordLayer::toggleRender2)); renderToggle->setPosition(ccp(-65.5, -100)); menu->addChild(renderToggle); - // #endif + #endif spr = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png"); spr->setScale(0.65f); diff --git a/src/ui/record_layer.hpp b/src/ui/record_layer.hpp index eb0769bf..7d832098 100644 --- a/src/ui/record_layer.hpp +++ b/src/ui/record_layer.hpp @@ -125,7 +125,7 @@ class RecordLayer : public geode::Popup, public TextInputDelegate { void toggleRender(CCObject* btn); - void toggleRenderIOS(CCObject* btn); + void toggleRender2(CCObject* btn); void openPresets(CCObject*); diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index 669d333d..4d5e3f23 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -85,8 +85,8 @@ bool RenderSettingsLayer::init() { if (!Popup::init(396, 277, Utils::getTexture().c_str())) return false; setTitle("Render Settings"); bool usingApi = false; - // #ifndef GEODE_IS_IOS - // usingApi = Renderer::shouldUseAPI(); + // #ifndef GEODE_IS_MOBILE + usingApi = Renderer::shouldUseAPI(); // #endif cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; @@ -117,7 +117,7 @@ bool RenderSettingsLayer::init() { bg->setContentSize({ 392, 55 }); menu->addChild(bg); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) bg->setOpacity(40); #endif @@ -128,7 +128,7 @@ bool RenderSettingsLayer::init() { lbl->setScale(0.325); menu->addChild(lbl); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) lbl->setOpacity(90); #endif @@ -157,7 +157,7 @@ bool RenderSettingsLayer::init() { bg->setContentSize({ 401, 55 }); menu->addChild(bg); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) bg->setOpacity(40); #endif @@ -168,7 +168,7 @@ bool RenderSettingsLayer::init() { lbl->setScale(0.325); menu->addChild(lbl); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) lbl->setOpacity(90); #endif @@ -266,7 +266,7 @@ bool RenderSettingsLayer::init() { lbl->setScale(0.325); menu->addChild(lbl); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) lbl->setOpacity(90); #endif @@ -276,7 +276,7 @@ bool RenderSettingsLayer::init() { this, menu_selector(RecordLayer::toggleSetting)); onlySongToggle->setPosition(ccp(0, -32)); onlySongToggle->setScale(0.555); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (!usingApi) onlySongToggle->toggle(mod->getSavedValue("render_only_song")); #endif onlySongToggle->setID("render_only_song"); @@ -289,7 +289,7 @@ bool RenderSettingsLayer::init() { lbl->setScale(0.325); menu->addChild(lbl); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) lbl->setOpacity(90); #endif @@ -299,7 +299,7 @@ bool RenderSettingsLayer::init() { this, menu_selector(RecordLayer::toggleSetting)); recordAudioToggle->setPosition(ccp(0, -58)); recordAudioToggle->setScale(0.555); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (!usingApi) recordAudioToggle->toggle(mod->getSavedValue("render_record_audio")); #endif recordAudioToggle->setID("render_record_audio"); @@ -312,7 +312,7 @@ bool RenderSettingsLayer::init() { lbl->setScale(0.325); menu->addChild(lbl); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) lbl->setOpacity(90); #endif @@ -330,13 +330,13 @@ bool RenderSettingsLayer::init() { this, menu_selector(RecordLayer::toggleSetting)); toggle->setPosition(ccp(130, -32)); toggle->setScale(0.555); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (!usingApi) toggle->toggle(mod->getSavedValue("render_fade_in")); #endif toggle->setID("render_fade_in"); menu->addChild(toggle); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) { toggle->setCascadeOpacityEnabled(true); toggle->setEnabled(false); @@ -351,7 +351,7 @@ bool RenderSettingsLayer::init() { lbl->setScale(0.325); menu->addChild(lbl); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) lbl->setOpacity(90); #endif @@ -362,7 +362,7 @@ bool RenderSettingsLayer::init() { lbl->setScale(0.3f); menu->addChild(lbl); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) lbl->setOpacity(90); #endif @@ -388,13 +388,13 @@ bool RenderSettingsLayer::init() { this, menu_selector(RecordLayer::toggleSetting)); toggle->setPosition(ccp(130, -58)); toggle->setScale(0.555); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (!usingApi) toggle->toggle(mod->getSavedValue("render_fade_out")); #endif toggle->setID("render_fade_out"); menu->addChild(toggle); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) { toggle->setCascadeOpacityEnabled(true); toggle->setEnabled(false); @@ -441,7 +441,7 @@ bool RenderSettingsLayer::init() { lbl->setPosition({188, 42}); menu->addChild(lbl); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) lbl->setOpacity(90); #endif @@ -461,7 +461,7 @@ bool RenderSettingsLayer::init() { lbl->setPosition({188, 87}); menu->addChild(lbl); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) lbl->setOpacity(90); #endif @@ -502,7 +502,7 @@ bool RenderSettingsLayer::init() { btn->setTag(0); menu->addChild(btn); - #ifndef GEODE_IS_IOS + #ifndef GEODE_IS_MOBILE if (usingApi) { argsInput->m_textLabel->setOpacity(100); audioArgsInput->m_textLabel->setOpacity(100); diff --git a/src/ui/trajectory_settings_layer.hpp b/src/ui/trajectory_settings_layer.hpp index f429567a..6fbcb617 100644 --- a/src/ui/trajectory_settings_layer.hpp +++ b/src/ui/trajectory_settings_layer.hpp @@ -114,7 +114,6 @@ class TrajectorySettingsLayer : public geode::Popup, public TextInputDelegate { textChanged(nullptr); } - // Corrected color conversion function cocos2d::ccColor4F ccColor4FFromccColor4B(const cocos2d::ccColor4B& color) { return cocos2d::ccColor4F( color.r / 255.0f, diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 1f8856eb..c46fd394 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -25,7 +25,7 @@ std::string Utils::narrow(const wchar_t* str) { return result; #else -#if !defined (GEODE_IS_IOS) && !defined (GEODE_IS_MACOS) +#if !defined (GEODE_IS_MOBILE) && !defined (GEODE_IS_MACOS) int size = WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr); if (size <= 0) { return ""; @@ -58,7 +58,7 @@ std::wstring Utils::widen(const char* str) { return result; #else -#if !defined (GEODE_IS_IOS) && !defined (GEODE_IS_MACOS) +#if !defined (GEODE_IS_MOBILE) && !defined (GEODE_IS_MACOS) if (str == nullptr) { return L"Widen Error"; } From 41e6dca2233d40db245476aaa13d90dfa9f76a4d Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 18 Feb 2026 00:03:49 +0300 Subject: [PATCH 083/211] fix syntax --- src/hacks/frame_stepper.cpp | 94 ++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/hacks/frame_stepper.cpp b/src/hacks/frame_stepper.cpp index aefbf66d..060a297f 100644 --- a/src/hacks/frame_stepper.cpp +++ b/src/hacks/frame_stepper.cpp @@ -9,96 +9,96 @@ #ifdef GEODE_IS_WINDOWS class $modify(PauseLayer) { - + void onResume(CCObject * sender) { PauseLayer::onResume(sender); - + if (Global::get().frameStepper) { Global::get().stepFrameDrawMultiple = 4; } } - + }; class $modify(CCDirector) { - + void drawScene() { auto& g = Global::get(); - + if (!g.frameStepper) return CCDirector::drawScene(); - + PlayLayer* pl = PlayLayer::get(); - + if (!pl) return CCDirector::drawScene(); - + if (pl->m_isPaused || pl->m_player1->m_isDead) return CCDirector::drawScene(); if (Global::getCurrentFrame() < 3) return CCDirector::drawScene(); - + if (g.stepFrameDraw || g.stepFrameDrawMultiple != 0) { g.stepFrameDraw = false; - + if (g.stepFrameDrawMultiple != 0) - g.stepFrameDrawMultiple--; - + g.stepFrameDrawMultiple--; + CCDirector::drawScene(); } else - this->getScheduler()->update(1.f / Global::getTPS()); - + this->getScheduler()->update(1.f / Global::getTPS()); + } }; #endif class $modify(PlayLayer) { - + void setupHasCompleted() { PlayLayer::setupHasCompleted(); - + if (Global::get().frameStepper) - Global::toggleFrameStepper(); + Global::toggleFrameStepper(); } - + }; class $modify(GJBaseGameLayer) { - + void update(float dt) { if (!PlayLayer::get()) return GJBaseGameLayer::update(dt); - + if (this->m_player1->m_isDead) { if (Global::get().mod->getSavedValue("macro_instant_respawn")) - PlayLayer::get()->resetLevel(); + PlayLayer::get()->resetLevel(); } - + auto& g = Global::get(); #ifdef GEODE_IS_WINDOWS if (!g.renderer.recording && g.frameStepper) { - // if (g.stepFrameParticle != 0) - // g.stepFrameParticle--; - - // if (Macro::shouldStep()) { - // g.stepFrame = false; - - // GJBaseGameLayer::update(1.f / Global::getTPS()); - - // return; - // } - // else { - // g.safeMode = true; - // return; - // } - // } - // #else + if (g.stepFrameParticle != 0) + g.stepFrameParticle--; + + if (Macro::shouldStep()) { + g.stepFrame = false; + + GJBaseGameLayer::update(1.f / Global::getTPS()); + + return; + } + else { + g.safeMode = true; + return; + } + } + #else if (g.frameStepper) { if (g.stepFrameParticle != 0) - g.stepFrameParticle--; - + g.stepFrameParticle--; + if (Macro::shouldStep()) { g.stepFrame = false; - + GJBaseGameLayer::update(1.f / Global::getTPS()); - + return; } else { @@ -107,14 +107,14 @@ class $modify(GJBaseGameLayer) { } } // #endif - + GJBaseGameLayer::update(dt); } - + }; class $modify(CCParticleSystem) { - + virtual void update(float dt) { auto& g = Global::get(); if (!PlayLayer::get()) return CCParticleSystem::update(dt); @@ -132,10 +132,10 @@ class $modify(CCParticleSystem) { CCParticleSystem::update(dt); } else - return; + return; } // #endif - + CCParticleSystem::update(dt); } }; From a7798ef4de4f76ccfad971d0fc9a6bb6f5fdb211 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 18 Feb 2026 00:05:45 +0300 Subject: [PATCH 084/211] fix syntax v2 --- src/hacks/frame_stepper.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hacks/frame_stepper.cpp b/src/hacks/frame_stepper.cpp index 060a297f..e7b81cd1 100644 --- a/src/hacks/frame_stepper.cpp +++ b/src/hacks/frame_stepper.cpp @@ -106,7 +106,7 @@ class $modify(GJBaseGameLayer) { return; } } - // #endif + #endif GJBaseGameLayer::update(dt); } @@ -118,15 +118,15 @@ class $modify(CCParticleSystem) { virtual void update(float dt) { auto& g = Global::get(); if (!PlayLayer::get()) return CCParticleSystem::update(dt); - // #ifndef GEODE_IS_IOS - // if (!g.renderer.recording && g.frameStepper) { - // if (g.stepFrameParticle != 0) { - // CCParticleSystem::update(dt); - // } - // else - // return; - // } - // #else + #ifdef GEODE_IS_WINDOWS + if (!g.renderer.recording && g.frameStepper) { + if (g.stepFrameParticle != 0) { + CCParticleSystem::update(dt); + } + else + return; + } + #else if (g.frameStepper) { if (g.stepFrameParticle != 0) { CCParticleSystem::update(dt); @@ -134,7 +134,7 @@ class $modify(CCParticleSystem) { else return; } - // #endif + #endif CCParticleSystem::update(dt); } From 379e0c9aca5536fa898ec8077f119cc61fd4dadb Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 18 Feb 2026 00:12:17 +0300 Subject: [PATCH 085/211] fix some stuff more + cbs/cos detection in renderer --- src/renderer/renderer.cpp | 8 ++++++++ src/ui/render_settings_layer.cpp | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 17b42730..6c37e547 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -158,6 +158,14 @@ bool Renderer::toggle() { return false; } + #ifdef GEODE_IS_WINDOWS + if (GameManager::sharedState()->getGameVariable(GameVar::ClickBetweenSteps) || + GameManager::sharedState()->getGameVariable(GameVar::ClickOnSteps)) { + FLAlertLayer::create("Render", "Disable Click Between Steps and Click On Steps in GD settings to render a level.", "OK")->show(); + return false; + } + #endif + bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); bool foundExe = std::filesystem::exists(ffmpegPath) && geode::utils::string::pathToString(ffmpegPath.filename()) == "ffmpeg.exe"; diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index 4d5e3f23..5c2882c2 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -85,9 +85,9 @@ bool RenderSettingsLayer::init() { if (!Popup::init(396, 277, Utils::getTexture().c_str())) return false; setTitle("Render Settings"); bool usingApi = false; - // #ifndef GEODE_IS_MOBILE + #ifdef GEODE_IS_WINDOWS usingApi = Renderer::shouldUseAPI(); - // #endif + #endif cocos2d::CCPoint offset = (CCDirector::sharedDirector()->getWinSize() - m_mainLayer->getContentSize()) / 2; m_mainLayer->setPosition(m_mainLayer->getPosition() - offset); From e1ad147d6a8a05659ce624cb8064aab921ed9e80 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 18 Feb 2026 00:15:12 +0300 Subject: [PATCH 086/211] how am i missing syntax issues --- src/hacks/other.cpp | 2 +- src/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hacks/other.cpp b/src/hacks/other.cpp index e823d934..6210b154 100644 --- a/src/hacks/other.cpp +++ b/src/hacks/other.cpp @@ -131,7 +131,7 @@ class $modify(PlayLayer) { if (getActionByTag(16)) { #ifndef GEODE_IS_MOBILE - /if (Global::get().renderer.recordingAudio) Global::get().renderer.stopAudio(); + if (Global::get().renderer.recordingAudio) Global::get().renderer.stopAudio(); #endif if (g.mod->getSavedValue("respawn_time_enabled")) { diff --git a/src/main.cpp b/src/main.cpp index d6416e08..4f670f9e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -467,7 +467,7 @@ class $modify(PauseLayer) { Loader::get()->queueInMainThread([] { auto& g = Global::get(); #ifndef GEODE_IS_MOBILE - /if (g.renderer.recording) g.renderer.stop(); + if (g.renderer.recording) g.renderer.stop(); if (g.renderer.recordingAudio) g.renderer.stopAudio(); #endif }); From 1db01ae5908b2208e36944bbda9a70f888f07622 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 18 Feb 2026 00:16:08 +0300 Subject: [PATCH 087/211] a --- src/includes.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/includes.hpp b/src/includes.hpp index 37da044f..37749c4e 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -90,7 +90,7 @@ class Global { geode::Popup* layer = nullptr; Macro macro; - #ifdef GEODE_IS_DESKTOP + #ifdef GEODE_IS_WINDOWS Renderer renderer; #endif state state = none; From eef775f03879debafc3f7964a387d1d12385f71a Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 18 Feb 2026 00:21:29 +0300 Subject: [PATCH 088/211] ok --- src/hacks/other.cpp | 2 +- src/main.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hacks/other.cpp b/src/hacks/other.cpp index 6210b154..56354320 100644 --- a/src/hacks/other.cpp +++ b/src/hacks/other.cpp @@ -130,7 +130,7 @@ class $modify(PlayLayer) { Global::get().safeMode = true; if (getActionByTag(16)) { - #ifndef GEODE_IS_MOBILE + #ifdef GEODE_IS_WINDOWS if (Global::get().renderer.recordingAudio) Global::get().renderer.stopAudio(); #endif diff --git a/src/main.cpp b/src/main.cpp index 4f670f9e..dd98d3a2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -214,7 +214,7 @@ class $modify(BGLHook, GJBaseGameLayer) { #endif if (g.state != state::none || rendering) { - #ifndef GEODE_IS_MOBILE + #ifdef GEODE_IS_WINDOWS if (!g.firstAttempt) { g.renderer.dontRender = false; g.renderer.dontRecordAudio = false; @@ -466,7 +466,7 @@ class $modify(PauseLayer) { Loader::get()->queueInMainThread([] { auto& g = Global::get(); - #ifndef GEODE_IS_MOBILE + #ifdef GEODE_IS_WINDOWS if (g.renderer.recording) g.renderer.stop(); if (g.renderer.recordingAudio) g.renderer.stopAudio(); #endif @@ -480,7 +480,7 @@ class $modify(PauseLayer) { Loader::get()->queueInMainThread([] { auto& g = Global::get(); - #ifndef GEODE_IS_MOBILE + #ifdef GEODE_IS_WINDOWS if (g.renderer.recording) g.renderer.stop(); if (g.renderer.recordingAudio) g.renderer.stopAudio(); #endif From 813a927a6a960fbdd06c6655322ebc8c7d241953 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 18 Feb 2026 00:30:45 +0300 Subject: [PATCH 089/211] lastly remove these logs --- src/renderer/renderer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 6c37e547..01c10911 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -405,7 +405,6 @@ void Renderer::start() { #ifdef GEODE_IS_WINDOWS if (process.close()) { - log::error("[RENDER] FFmpeg process failed with error code"); Loader::get()->queueInMainThread([] { FLAlertLayer::create("Error", "There was an error saving the render. Wrong render Args.", "OK")->show(); }); @@ -722,7 +721,6 @@ void Renderer::captureFrame() { while (frameHasData) {} renderer.capture(lock, currentFrame, frameHasData); captureCount++; - if (captureCount % 30 == 0) log::debug("[RENDER] Captured {} frames", captureCount); } int wa = 0; void Renderer::handleRecording(PlayLayer* pl, int frame) { From f9dc1f74ef45670715ece2de4025d7ff07051688 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 18 Feb 2026 01:00:07 +0300 Subject: [PATCH 090/211] ios specific fix --- src/macro.cpp | 8 ++++++++ src/renderer/renderer.cpp | 8 ++++++++ src/ui/load_macro_layer.cpp | 16 ++++++++++++++++ src/ui/load_macro_layer.hpp | 4 ++++ src/ui/record_layer.cpp | 4 ++++ src/ui/render_presets_layer.hpp | 4 ++++ src/ui/save_macro_layer.hpp | 8 ++++++++ 7 files changed, 52 insertions(+) diff --git a/src/macro.cpp b/src/macro.cpp index c4590acf..dc99850b 100644 --- a/src/macro.cpp +++ b/src/macro.cpp @@ -50,7 +50,11 @@ void Macro::autoSave(GJGameLevel* level, int number) { if (!level) return; std::string levelname = level->m_levelName; + #ifdef GEODE_IS_IOS + std::filesystem::path autoSavesPath = Mod::get()->getSaveDir() / "autosaves"; + #else std::filesystem::path autoSavesPath = Mod::get()->getSettingValue("autosaves_folder"); + #endif std::filesystem::path path = autoSavesPath / fmt::format("autosave_{}_{}", levelname, number); if (!std::filesystem::exists(autoSavesPath)) return; @@ -70,7 +74,11 @@ void Macro::tryAutosave(GJGameLevel* level, CheckpointObject* cp) { if (!g.checkpoints.contains(cp)) return; if (g.checkpoints[cp].frame < g.lastAutoSaveFrame) return; + #ifdef GEODE_IS_IOS + std::filesystem::path autoSavesPath = g.mod->getSaveDir() / "autosaves"; + #else std::filesystem::path autoSavesPath = g.mod->getSettingValue("autosaves_folder"); + #endif if (!std::filesystem::exists(autoSavesPath)) return log::debug("Failed to access auto saves path."); diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 01c10911..b3cf3796 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -204,7 +204,11 @@ bool Renderer::toggle() { return false; } + #ifdef GEODE_IS_IOS + std::filesystem::path path = Mod::get()->getSaveDir() / "renders"; + #else std::filesystem::path path = Mod::get()->getSettingValue("render_folder"); + #endif if (std::filesystem::exists(path)) g.renderer.start(); @@ -249,7 +253,11 @@ void Renderer::start() { auto timestamp = std::chrono::duration_cast(duration).count(); std::string filename = fmt::format("render_{}_{}{}", std::string_view(pl->m_level->m_levelName), std::to_string(timestamp), extension); + #ifdef GEODE_IS_IOS + std::string path = geode::utils::string::pathToString(Mod::get()->getSaveDir() / "renders" / filename); + #else std::string path = geode::utils::string::pathToString(Mod::get()->getSettingValue("render_folder") / filename); + #endif width = geode::utils::numFromString(mod->getSavedValue("render_width2")).unwrap(); height = geode::utils::numFromString(mod->getSavedValue("render_height")).unwrap(); diff --git a/src/ui/load_macro_layer.cpp b/src/ui/load_macro_layer.cpp index 5e0d002a..b6154c74 100644 --- a/src/ui/load_macro_layer.cpp +++ b/src/ui/load_macro_layer.cpp @@ -27,14 +27,22 @@ class $modify(CCMenu) { }; void LoadMacroLayer::open(geode::Popup* layer, geode::Popup* layer2, bool autosaves) { + #ifdef GEODE_IS_IOS + std::filesystem::path path = Mod::get()->getSaveDir(); + #else std::filesystem::path path = Mod::get()->getSettingValue("macros_folder"); + #endif if (!std::filesystem::exists(path)) { if (utils::file::createDirectoryAll(path).isErr()) return FLAlertLayer::create("Error", "There was an error getting the folder. ID: 6", "OK")->show(); } + #ifdef GEODE_IS_IOS + path = Mod::get()->getSaveDir(); + #else path = Mod::get()->getSettingValue("autosaves_folder"); + #endif if (!std::filesystem::exists(path)) { if (utils::file::createDirectoryAll(path).isErr()) @@ -189,7 +197,11 @@ void LoadMacroLayer::onImportMacro(CCObject*) { std::string name = geode::utils::string::pathToString(path.filename()).substr(0, geode::utils::string::pathToString(path.filename()).find_last_of('.')); + #ifdef GEODE_IS_IOS + std::filesystem::path newPath = Mod::get()->getSaveDir() / "macros" / name; + #else std::filesystem::path newPath = Mod::get()->getSettingValue("macros_folder") / name; + #endif std::string pathString = geode::utils::string::pathToString(newPath); @@ -423,7 +435,11 @@ void LoadMacroLayer::updateSort(CCObject*) { void LoadMacroLayer::addList(bool refresh, float prevScroll) { cocos2d::CCSize winSize = cocos2d::CCDirector::sharedDirector()->getWinSize(); + #ifdef GEODE_IS_IOS + std::filesystem::path path = Mod::get()->getSaveDir() / (isAutosaves ? "autosaves" : "macros"); + #else std::filesystem::path path = Mod::get()->getSettingValue(isAutosaves ? "autosaves_folder" : "macros_folder"); + #endif std::vector macros = file::readDirectory(path).unwrapOrDefault(); CCArray* cells = CCArray::create(); diff --git a/src/ui/load_macro_layer.hpp b/src/ui/load_macro_layer.hpp index def2f366..e15aedcf 100644 --- a/src/ui/load_macro_layer.hpp +++ b/src/ui/load_macro_layer.hpp @@ -76,7 +76,11 @@ class LoadMacroLayer : public geode::Popup, TextInputDelegate { static void open(geode::Popup* layer, geode::Popup* layer2, bool autosaves = false); void openFolder(CCObject*) { + #ifdef GEODE_IS_IOS + file::openFolder(Mod::get()->getSaveDir() / (isAutosaves ? "autosaves" : "macros")); + #else file::openFolder(Mod::get()->getSettingValue(isAutosaves ? "autosaves_folder" : "macros_folder")); + #endif } void textChanged(CCTextInputNode* p) override; diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index dcf2f1c4..0e0e08ef 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -506,7 +506,11 @@ class $modify(PauseLayer) { } void RecordLayer::onAutosaves(CCObject*) { + #ifdef GEODE_IS_IOS + std::filesystem::path path = Mod::get()->getSaveDir() / "autosaves"; + #else std::filesystem::path path = Mod::get()->getSettingValue("autosaves_folder"); + #endif if (std::filesystem::exists(path)) LoadMacroLayer::open(static_cast(this), nullptr, true); diff --git a/src/ui/render_presets_layer.hpp b/src/ui/render_presets_layer.hpp index a5915740..2421e118 100644 --- a/src/ui/render_presets_layer.hpp +++ b/src/ui/render_presets_layer.hpp @@ -105,7 +105,11 @@ class RenderPresetsLayer : public geode::Popup { } void openRendersFolder(CCObject*) { + #ifdef GEODE_IS_IOS + std::filesystem::path path = Mod::get()->getSaveDir() / "renders"; + #else std::filesystem::path path = Mod::get()->getSettingValue("render_folder"); + #endif if (std::filesystem::exists(path)) file::openFolder(path); diff --git a/src/ui/save_macro_layer.hpp b/src/ui/save_macro_layer.hpp index 3f891609..49f81a2c 100644 --- a/src/ui/save_macro_layer.hpp +++ b/src/ui/save_macro_layer.hpp @@ -77,7 +77,11 @@ class SaveMacroLayer : public geode::Popup { if (Global::get().macro.inputs.empty()) return FLAlertLayer::create("Save Macro", "You can't save an empty macro.", "OK")->show(); + #ifdef GEODE_IS_IOS + std::filesystem::path path = Mod::get()->getSaveDir() / "macros"; + #else std::filesystem::path path = Mod::get()->getSettingValue("macros_folder"); + #endif if (!std::filesystem::exists(path)) { if (!utils::file::createDirectoryAll(path).isOk()) @@ -94,7 +98,11 @@ class SaveMacroLayer : public geode::Popup { if (macroName == "") return FLAlertLayer::create("Save Macro", "Give a name to the macro.", "OK")->show(); + #ifdef GEODE_IS_IOS + std::filesystem::path path = Mod::get()->getSaveDir() / "macros" / macroName; + #else std::filesystem::path path = Mod::get()->getSettingValue("macros_folder") / macroName; + #endif std::string author = authorInput->getString(); std::string desc = descInput->getString(); From 138b0633ee14d69d4168e67712e0abcf59c9be35 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 18 Feb 2026 23:57:11 +0300 Subject: [PATCH 091/211] beta 3 --- mod.json | 38 ++++++++--- src/keybinds.cpp | 38 +++++------ src/ui/load_macro_layer.cpp | 127 +++++++++++++----------------------- src/ui/load_macro_layer.hpp | 2 +- 4 files changed, 92 insertions(+), 113 deletions(-) diff --git a/mod.json b/mod.json index 6ac7fdd0..6464cdd7 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "5.0.0-beta.2", + "geode": "5.0.0-beta.3", "gd": { "win": "2.2081", "mac": "2.2081", @@ -87,63 +87,81 @@ "description": "The keybind to open the xdBot menu.", "type": "keybind", "default": "Alt+F", - "platforms": ["win", "mac"] + "platforms": ["win", "mac"], + "category": "universal", + "migrate-from": "zilko.xdbot/open_menu" }, "toggle_recording_keybind": { "name": "Recording Keybind", "description": "The keybind to start and stop recording a macro.", "type": "keybind", "default": "Alt+G", - "platforms": ["win", "mac"] + "platforms": ["win", "mac"], + "category": "gameplay", + "migrate-from": "zilko.xdbot/toggle_recording" }, "toggle_playing_keybind": { "name": "Playing Keybind", "description": "The keybind to start and stop playing a macro.", "type": "keybind", "default": "Alt+H", - "platforms": ["win", "mac"] + "platforms": ["win", "mac"], + "category": "gameplay", + "migrate-from": "zilko.xdbot/toggle_playing" }, "toggle_speedhack_keybind": { "name": "Speedhack Keybind", "description": "The keybind to toggle speedhack.", "type": "keybind", "default": "Alt+S", - "platforms": ["win", "mac"] + "platforms": ["win", "mac"], + "category": "gameplay", + "migrate-from": "zilko.xdbot/toggle_speedhack" }, "toggle_noclip_keybind": { "name": "Noclip Keybind", "description": "The keybind to toggle noclip.", "type": "keybind", "default": "Alt+N", - "platforms": ["win", "mac"] + "platforms": ["win", "mac"], + "category": "gameplay", + "migrate-from": "zilko.xdbot/toggle_noclip" }, "toggle_frame_stepper_keybind": { "name": "Frame Stepper Keybind", "description": "The keybind to toggle the frame stepper.", "type": "keybind", "default": "Alt+C", - "platforms": ["win", "mac"] + "platforms": ["win", "mac"], + "category": "gameplay", + "migrate-from": "zilko.xdbot/toggle_frame_stepper" }, "step_frame_keybind": { "name": "Step Frame Keybind", "description": "The keybind to step a frame when the frame stepper is enabled.", "type": "keybind", "default": "V", - "platforms": ["win", "mac"] + "platforms": ["win", "mac"], + "category": "gameplay", + "migrate-from": "zilko.xdbot/step_frame" }, "show_trajectory_keybind": { "name": "Show Trajectory Keybind", "description": "The keybind to toggle the trajectory while recording a macro.", "type": "keybind", "default": "Alt+T", - "platforms": ["win", "mac"] + "platforms": ["win", "mac"], + "category": "gameplay", + "migrate-from": "zilko.xdbot/show_trajectory" }, "toggle_render_keybind": { "name": "Render Keybind", "description": "The keybind to start and stop the renderer.", "type": "keybind", "default": "Alt+P", - "platforms": ["win", "mac"] + "platforms": ["win", "mac"], + "category": "gameplay", + "migrate-from": "zilko.xdbot/toggle_render" }, "background_color": { "name": "Menu background color", diff --git a/src/keybinds.cpp b/src/keybinds.cpp index b30bfc8e..b6050a69 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -39,7 +39,7 @@ class $modify(CCKeyboardDispatcher) { } }; -void handleKeybind(std::string const& id, bool down) { +void handleKeybind(std::string const& id, bool down, bool repeat, double time) { auto& g = Global::get(); if (!down || (LevelEditorLayer::get() && !g.mod->getSettingValue("editor_keybinds")) || g.mod->getSettingValue("disable_keybinds")) return; @@ -112,32 +112,32 @@ void handleKeybind(std::string const& id, bool down) { } $execute{ - listenForKeybindSettingPresses("open_menu_keybind", [](Keybind const&, bool down, bool repeat) { - if (!repeat) handleKeybind("open_menu_keybind", down); + listenForKeybindSettingPresses("open_menu_keybind", [](Keybind const&, bool down, bool repeat, double time) { + handleKeybind("open_menu_keybind", down, false, time); }); - listenForKeybindSettingPresses("toggle_recording_keybind", [](Keybind const&, bool down, bool repeat) { - if (!repeat) handleKeybind("toggle_recording_keybind", down); + listenForKeybindSettingPresses("toggle_recording_keybind", [](Keybind const&, bool down, bool repeat, double time) { + handleKeybind("toggle_recording_keybind", down, false, time); }); - listenForKeybindSettingPresses("toggle_playing_keybind", [](Keybind const&, bool down, bool repeat) { - if (!repeat) handleKeybind("toggle_playing_keybind", down); + listenForKeybindSettingPresses("toggle_playing_keybind", [](Keybind const&, bool down, bool repeat, double time) { + handleKeybind("toggle_playing_keybind", down, false, time); }); - listenForKeybindSettingPresses("toggle_speedhack_keybind", [](Keybind const&, bool down, bool repeat) { - if (!repeat) handleKeybind("toggle_speedhack_keybind", down); + listenForKeybindSettingPresses("toggle_speedhack_keybind", [](Keybind const&, bool down, bool repeat, double time) { + handleKeybind("toggle_speedhack_keybind", down, false, time); }); - listenForKeybindSettingPresses("toggle_frame_stepper_keybind", [](Keybind const&, bool down, bool repeat) { - if (!repeat) handleKeybind("toggle_frame_stepper_keybind", down); + listenForKeybindSettingPresses("toggle_frame_stepper_keybind", [](Keybind const&, bool down, bool repeat, double time) { + handleKeybind("toggle_frame_stepper_keybind", down, false, time); }); - listenForKeybindSettingPresses("step_frame_keybind", [](Keybind const&, bool down, bool repeat) { - if (!repeat) handleKeybind("step_frame_keybind", down); + listenForKeybindSettingPresses("step_frame_keybind", [](Keybind const&, bool down, bool repeat, double time) { + handleKeybind("step_frame_keybind", down, repeat, time); }); - listenForKeybindSettingPresses("show_trajectory_keybind", [](Keybind const&, bool down, bool repeat) { - if (!repeat) handleKeybind("show_trajectory_keybind", down); + listenForKeybindSettingPresses("show_trajectory_keybind", [](Keybind const&, bool down, bool repeat, double time) { + handleKeybind("show_trajectory_keybind", down, false, time); }); - listenForKeybindSettingPresses("toggle_render_keybind", [](Keybind const&, bool down, bool repeat) { - if (!repeat) handleKeybind("toggle_render_keybind", down); + listenForKeybindSettingPresses("toggle_render_keybind", [](Keybind const&, bool down, bool repeat, double time) { + handleKeybind("toggle_render_keybind", down, false, time); }); - listenForKeybindSettingPresses("toggle_noclip_keybind", [](Keybind const&, bool down, bool repeat) { - if (!repeat) handleKeybind("toggle_noclip_keybind", down); + listenForKeybindSettingPresses("toggle_noclip_keybind", [](Keybind const&, bool down, bool repeat, double time) { + handleKeybind("toggle_noclip_keybind", down, false, time); }); } #endif \ No newline at end of file diff --git a/src/ui/load_macro_layer.cpp b/src/ui/load_macro_layer.cpp index b6154c74..ffd4cce2 100644 --- a/src/ui/load_macro_layer.cpp +++ b/src/ui/load_macro_layer.cpp @@ -147,91 +147,52 @@ LoadMacroLayer* LoadMacroLayer::create(geode::Popup* layer, geode::Popup* layer2 } void LoadMacroLayer::onImportMacro(CCObject*) { - file::FilePickOptions::Filter textFilter; file::FilePickOptions fileOptions; - textFilter.description = "Macro Files"; - textFilter.files = { "*.gdr", "*.xd", "*.json" }; - fileOptions.filters.push_back(textFilter); - - auto self = this; - m_importFuture = async::runtime().spawn([self, fileOptions]() -> arc::Future { - auto res = co_await file::pick(file::PickMode::OpenFile, fileOptions); - - geode::queueInMainThread([self, res]() { - if (res.isOk()) { - auto pathOpt = res.unwrapOrDefault(); - if (!pathOpt) return; - std::filesystem::path path = pathOpt.value(); - - auto& g = Global::get(); - Macro tempMacro; - - if (path.extension() == ".xd") { - tempMacro = Macro::XDtoGDR(path); - - if (tempMacro.description == "fail") { - FLAlertLayer::create("Error", "There was an error importing this macro. ID: 46", "OK")->show(); - return; - } - } - else { - - std::ifstream f(path, std::ios::binary); - - f.seekg(0, std::ios::end); - size_t fileSize = f.tellg(); - f.seekg(0, std::ios::beg); - - std::vector macroData(fileSize); - - f.read(reinterpret_cast(macroData.data()), fileSize); - f.close(); - - tempMacro = Macro::importData(macroData); - - } - - bool xdMacro = path.extension() == ".xd"; - - int iterations = 0; - - std::string name = geode::utils::string::pathToString(path.filename()).substr(0, geode::utils::string::pathToString(path.filename()).find_last_of('.')); - - #ifdef GEODE_IS_IOS - std::filesystem::path newPath = Mod::get()->getSaveDir() / "macros" / name; - #else - std::filesystem::path newPath = Mod::get()->getSettingValue("macros_folder") / name; - #endif - - std::string pathString = geode::utils::string::pathToString(newPath); - - while (std::filesystem::exists(pathString + ".gdr.json")) { - iterations++; - - if (iterations > 1) { - int length = 3 + std::to_string(iterations - 1).length(); - pathString.erase(pathString.length() - length, length); - } - - pathString += fmt::format(" ({})", std::to_string(iterations)); - } - - pathString += ".gdr.json"; - - std::ofstream f2(std::filesystem::path(pathString), std::ios::binary); - auto data = tempMacro.exportData(true); - - f2.write(reinterpret_cast(data.data()), data.size()); - f2.close(); - - self->reloadList(0); - - if (xdMacro) - FLAlertLayer::create("Warning", ".xd extension macros may not function correctly in this version.", "OK")->show(); - - Notification::create("Macro Imported", NotificationIcon::Success)->show(); + fileOptions.filters.push_back({"Macro Files", { "*.gdr", "*.xd", "*.json" }}); + + m_importTask.spawn(file::pick(file::PickMode::OpenFile, fileOptions), [this](auto res) { + if (!res.isOk()) return; + + auto pathOpt = res.unwrap(); + if (!pathOpt) return; + + std::filesystem::path path = pathOpt.value(); + + Macro tempMacro; + if (path.extension() == ".xd") { + tempMacro = Macro::XDtoGDR(path); + if (tempMacro.description == "fail") { + FLAlertLayer::create("Error", "Import failed. ID: 46", "OK")->show(); + return; } - }); + } else { + auto dataRes = geode::utils::file::readBinary(path); + if (!dataRes) return; + tempMacro = Macro::importData(dataRes.unwrap()); + } + + std::string name = path.stem().string(); + + #ifdef GEODE_IS_IOS + std::filesystem::path folder = Mod::get()->getSaveDir() / "macros"; + #else + std::filesystem::path folder = Mod::get()->getSettingValue("macros_folder"); + #endif + + std::filesystem::path finalPath = folder / (name + ".gdr.json"); + int iterations = 1; + while (std::filesystem::exists(finalPath)) { + finalPath = folder / fmt::format("{} ({}).gdr.json", name, iterations++); + } + + if (geode::utils::file::writeBinary(finalPath, tempMacro.exportData(true))) { + this->reloadList(0); + + if (path.extension() == ".xd") { + FLAlertLayer::create("Warning", "Legacy .xd macros may be unstable.", "OK")->show(); + } + Notification::create("Macro Imported", NotificationIcon::Success)->show(); + } }); } diff --git a/src/ui/load_macro_layer.hpp b/src/ui/load_macro_layer.hpp index e15aedcf..b13f9343 100644 --- a/src/ui/load_macro_layer.hpp +++ b/src/ui/load_macro_layer.hpp @@ -67,7 +67,7 @@ class LoadMacroLayer : public geode::Popup, TextInputDelegate { bool isMerge = false; bool invertSort = false; - arc::TaskHandle m_importFuture; + async::TaskHolder>> m_importTask; static LoadMacroLayer* create(geode::Popup* layer, geode::Popup* layer2, bool autosaves); From 36ddec8f4bb55a8d18d880f787aa3dc99f895d46 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Thu, 19 Feb 2026 01:57:04 +0300 Subject: [PATCH 092/211] cbf override thing --- .gitignore | 1 + src/global.cpp | 290 ++++++++++++++++++++++++-------------------- src/utils/utils.cpp | 260 +++++++++++++++++++-------------------- 3 files changed, 287 insertions(+), 264 deletions(-) diff --git a/.gitignore b/.gitignore index a58e6c40..2ffc61a4 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,4 @@ build-*/ # CLion /cmake-build-*/ +build.sh \ No newline at end of file diff --git a/src/global.cpp b/src/global.cpp index a5dc6fd4..0c494204 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -10,12 +10,12 @@ #include class $modify(CCTextInputNode) { - - bool ccTouchBegan(cocos2d::CCTouch * v1, cocos2d::CCEvent * v2) { - if (this->getID() == "disabled-input"_spr) return false; - - return CCTextInputNode::ccTouchBegan(v1, v2); - } + + bool ccTouchBegan(cocos2d::CCTouch * v1, cocos2d::CCEvent * v2) { + if (this->getID() == "disabled-input"_spr) return false; + + return CCTextInputNode::ccTouchBegan(v1, v2); + } }; struct IncompatibleSetting { @@ -41,27 +41,27 @@ const std::vector incompatibleMods { bool Global::hasIncompatibleMods() { std::vector modsToDisable; std::vector settingsToDisable; - + if (Mod* mod = Loader::get()->getLoadedMod("firee.prism")) { auto json = mod->getSavedValue("values"); for (const auto& obj : json.asArray().unwrap()) { - + if (obj["name"].asString().unwrapOrDefault() != "TPS Bypass") continue; - + if (obj["value"].asInt().unwrapOrDefault() != 240) - settingsToDisable.push_back("TPS Bypass (Prism Menu)"); - + settingsToDisable.push_back("TPS Bypass (Prism Menu)"); + break; - + } } #ifdef GEODE_IS_WINDOWS - + if (Mod* mod = Loader::get()->getLoadedMod("tobyadd.gdh")) { std::filesystem::path configPath = mod->getSaveDir() / "config.json"; - using namespace nlohmann; - + using namespace nlohmann; + if (std::filesystem::exists(configPath)) { std::ifstream jsonFile(configPath); if (jsonFile.is_open()) { @@ -69,17 +69,17 @@ bool Global::hasIncompatibleMods() { jsonFile >> jsonData; if (jsonData.contains("tps_enabled")) { if (jsonData["tps_enabled"]) - settingsToDisable.push_back("TPS Bypass (GDH)"); + settingsToDisable.push_back("TPS Bypass (GDH)"); } } } } - + #else - + if (Mod* mod = Loader::get()->getLoadedMod("tobyadd.gdh_mobile")) { std::filesystem::path configPath = mod->getSaveDir() / "config.json"; - using namespace nlohmann; + using namespace nlohmann; if (std::filesystem::exists(configPath)) { std::ifstream jsonFile(configPath); @@ -88,96 +88,118 @@ bool Global::hasIncompatibleMods() { jsonFile >> jsonData; if (jsonData.contains("fps_value")) { if (jsonData["fps_value"] != 240) - settingsToDisable.push_back("TPS Bypass (GDH)"); + settingsToDisable.push_back("TPS Bypass (GDH)"); } } } } - + #endif - + for (IncompatibleMod incompatMod : incompatibleMods) { Mod* mod = Loader::get()->getLoadedMod(incompatMod.ID); - + if (!mod) continue; - + std::string modName = mod->getName(); - + if (!incompatMod.canBeDisabled) { modsToDisable.push_back(modName); continue; } - + for (IncompatibleSetting sett : incompatMod.incompatSettings) { bool value = sett.isSavedValue ? mod->getSavedValue(sett.ID) : mod->getSettingValue(sett.ID); - + if (value != sett.incompatValue) continue; - + if (sett.isModToggle) - modsToDisable.push_back(modName); + modsToDisable.push_back(modName); else { std::string settName = sett.isSavedValue ? sett.ID : mod->getSetting(sett.ID)->getDisplayName(); settingsToDisable.push_back(fmt::format("{} ({})", settName, modName)); } - + } } - + if (!modsToDisable.empty()) { std::string incompatString = ""; - + for (const std::string name : modsToDisable) - incompatString += fmt::format("{}{}", name, (name != modsToDisable.back() ? ", " : "")); - + incompatString += fmt::format("{}{}", name, (name != modsToDisable.back() ? ", " : "")); + FLAlertLayer::create("Warning", "The following mods are incompatible: \n" + incompatString, "OK")->show(); - + } else if (!settingsToDisable.empty()) { std::string incompatString = ""; - + for (const std::string name : settingsToDisable) - incompatString += fmt::format("{}{}", name, (name != settingsToDisable.back() ? ", " : "")); - + incompatString += fmt::format("{}{}", name, (name != settingsToDisable.back() ? ", " : "")); + FLAlertLayer::create("Warning", "The following mod settings are incompatible: \n" + incompatString, "OK")->show(); } - + bool ret = !modsToDisable.empty() || !settingsToDisable.empty(); - + if (ret) { Global::get().state = state::none; Interface::updateLabels(); Interface::updateButtons(); } - + return ret; } bool Global::enabledIncompatibleGDSettings() { std::vector settingsToDisable; - + if (GameManager::sharedState()->getGameVariable(GameVar::ClickBetweenSteps)) - settingsToDisable.push_back("Click Between Steps"); - + settingsToDisable.push_back("Click Between Steps"); + if (GameManager::sharedState()->getGameVariable(GameVar::ClickOnSteps)) - settingsToDisable.push_back("Click On Steps"); - + settingsToDisable.push_back("Click On Steps"); + + #ifdef GEODE_IS_MOBILE + if (auto pl = PlayLayer::get()) { + if (pl->m_level->m_cbsOverride == 1) + settingsToDisable.push_back("Click Between Steps (Override)"); + } + else if (auto el = LevelEditorLayer::get()) { + if (el->m_level->m_cbsOverride == 1) + settingsToDisable.push_back("Click Between Steps (Override)"); + } + else if (auto scene = CCScene::get()) { + if (auto children = scene->getChildren()) { + for (auto obj : CCArrayExt(children)) { + if (auto layer = typeinfo_cast(obj)) { + if (layer->m_level->m_cbsOverride == 1) { + settingsToDisable.push_back("Click Between Steps (Override)"); + } + } + } + } + } + #endif + if (!settingsToDisable.empty()) { - std::string incompatString = ""; - - for (const std::string name : settingsToDisable) - incompatString += fmt::format("{}{}", name, (name != settingsToDisable.back() ? ", " : "")); - - FLAlertLayer::create("Warning", "The following GD settings are incompatible: \n" + incompatString, "OK")->show(); + geode::utils::StringBuffer incompatString; + + for (const std::string& name : settingsToDisable) + incompatString.append("{}{}", name, (name != settingsToDisable.back() ? ", " : "")); + + FLAlertLayer::create("Warning", "The following GD settings are incompatible: \n" + incompatString.str(), "OK")->show(); } - + bool ret = !settingsToDisable.empty(); - + if (ret) { Global::get().state = state::none; Interface::updateLabels(); Interface::updateButtons(); } - + return ret; } @@ -189,17 +211,17 @@ float Global::getTPS() { int Global::getCurrentFrame(bool editor) { // double levelTime; PlayLayer* pl = PlayLayer::get(); - + if (!pl) { if (!editor) return 0; - + // levelTime = GJBaseGameLayer::get()->m_gameState.m_levelTime; } - + auto& g = Global::get(); int frame; // levelTime = pl->m_gameState.m_levelTime; - + if (!g.macro.xdBotMacro && g.state == state::playing) { frame = pl->m_gameState.m_currentProgress; } @@ -207,10 +229,10 @@ int Global::getCurrentFrame(bool editor) { frame = static_cast(pl->m_gameState.m_levelTime * getTPS()); frame++; } - + frame -= g.frameOffset; if (frame < 0) return 0; - + return frame; } @@ -235,17 +257,17 @@ int Global::getCurrentFrame(bool editor) { // } void Global::updateSeed(bool isRestart) { - + auto& g = Global::get(); - + if (g.seedEnabled) { PlayLayer* pl = PlayLayer::get(); if (!pl) return; - + unsigned long long ull = std::stoull(g.mod->getSavedValue("macro_seed"), nullptr, 0); uintptr_t seed = static_cast(ull); int finalSeed; - + if (!pl->m_player1->m_isDead) { std::mt19937 generator(seed + pl->m_gameState.m_currentProgress); std::uniform_int_distribution distribution(10000, 999999999); @@ -257,24 +279,24 @@ void Global::updateSeed(bool isRestart) { std::uniform_int_distribution distribution(1000, 999999999); finalSeed = distribution(generator); } - -#ifdef GEODE_IS_WINDOWS + + #ifdef GEODE_IS_WINDOWS *(uintptr_t*)((char*)geode::base::get() + seedAddr) = finalSeed; -#else + #else GameToolbox::fast_srand(finalSeed); -#endif - + #endif + g.safeMode = true; } - + if (isRestart && g.state == state::recording) { -#ifdef GEODE_IS_WINDOWS + #ifdef GEODE_IS_WINDOWS g.macro.seed = *(uintptr_t*)((char*)geode::base::get() + seedAddr); -#else + #else g.macro.seed = 0; -#endif + #endif } - + } void Global::updatePitch(float value) { @@ -283,11 +305,11 @@ void Global::updatePitch(float value) { if (g.currentPitch != 1.f) value = 1.f; else return; } - + FMODAudioEngine* fmod = FMODAudioEngine::sharedEngine(); FMOD::ChannelGroup* channel = nullptr; fmod->m_system->getMasterChannelGroup(&channel); - + if (channel) { channel->setPitch(value); g.currentPitch = value; @@ -297,7 +319,7 @@ void Global::updatePitch(float value) { void Global::frameStep() { auto& g = Global::get(); if (!PlayLayer::get() || !g.frameStepper) return; - + g.stepFrame = true; g.stepFrameDraw = true; g.stepFrameParticle = 4; @@ -307,99 +329,99 @@ void Global::toggleSpeedhack() { auto& g = Global::get(); g.mod->setSavedValue("macro_speedhack_enabled", !g.mod->getSavedValue("macro_speedhack_enabled")); g.speedhackEnabled = g.mod->getSavedValue("macro_speedhack_enabled"); - + if (g.layer) { if (static_cast(g.layer)->speedhackToggle) - static_cast(g.layer)->speedhackToggle->toggle(g.mod->getSavedValue("macro_speedhack_enabled")); + static_cast(g.layer)->speedhackToggle->toggle(g.mod->getSavedValue("macro_speedhack_enabled")); } - + if (!g.mod->getSavedValue("macro_speedhack_enabled")) - Global::updatePitch(1.f); + Global::updatePitch(1.f); } void Global::toggleFrameStepper() { if (Global::get().frameStepper) - Global::frameStepperOff(); + Global::frameStepperOff(); else - Global::frameStepperOn(); + Global::frameStepperOn(); } void Global::frameStepperOn() { auto& g = Global::get(); - + g.mod->setSavedValue("macro_frame_stepper", true); g.frameStepper = true; - + if (g.layer) { if (static_cast(g.layer)->frameStepperToggle) - static_cast(g.layer)->frameStepperToggle->toggle(true); + static_cast(g.layer)->frameStepperToggle->toggle(true); } - + if (PlayLayer::get()) - g.frameStepperMusicTime = FMODAudioEngine::sharedEngine()->getMusicTimeMS(0); - + g.frameStepperMusicTime = FMODAudioEngine::sharedEngine()->getMusicTimeMS(0); + Interface::updateButtons(); } void Global::frameStepperOff() { auto& g = Global::get(); - + g.mod->setSavedValue("macro_frame_stepper", false); g.stepFrame = false; g.stepFrameParticle = false; g.frameStepper = false; - + if (PlayLayer::get() && g.frameStepperMusicTime != 0) { FMODAudioEngine::sharedEngine()->setMusicTimeMS(g.frameStepperMusicTime, true, 0); g.frameStepperMusicTime = 0; } - + if (g.layer) { if (static_cast(g.layer)->frameStepperToggle) - static_cast(g.layer)->frameStepperToggle->toggle(false); + static_cast(g.layer)->frameStepperToggle->toggle(false); } - + Interface::updateButtons(); } - PauseLayer* Global::getPauseLayer() { - auto children = CCDirector::sharedDirector() - ->getRunningScene() - ->getChildren(); - - for (auto child : CCArrayExt(children)) { - if (auto pauseLayer = typeinfo_cast(child)) - return pauseLayer; - } - return nullptr; - } +PauseLayer* Global::getPauseLayer() { + auto children = CCDirector::sharedDirector() + ->getRunningScene() + ->getChildren(); + + for (auto child : CCArrayExt(children)) { + if (auto pauseLayer = typeinfo_cast(child)) + return pauseLayer; + } + return nullptr; +} $execute{ auto & g = Global::get(); - + if (!g.mod->setSavedValue("defaults_set_14", true)) { g.mod->setSavedValue("render_fade_in_video", std::to_string(2)); g.mod->setSavedValue("render_fade_out_video", std::to_string(2)); } - + if (!g.mod->setSavedValue("defaults_set_12", true)) { g.mod->setSettingValue("macros_folder", g.mod->getSaveDir() / "macros"); g.mod->setSettingValue("autosaves_folder", g.mod->getSaveDir() / "autosaves"); } - + #ifdef GEODE_IS_ANDROID if (!g.mod->setSavedValue("defaults_set_15", true)) - g.mod->setSavedValue("render_video_args", std::string("")); + g.mod->setSavedValue("render_video_args", std::string("")); if (!g.mod->setSavedValue("defaults_set_11", true)) - g.mod->setSavedValue("render_codec", std::string("libx264")); + g.mod->setSavedValue("render_codec", std::string("libx264")); #endif - + if (!g.mod->setSavedValue("defaults_set_10", true)) { g.mod->setSettingValue("restore_page", true); - + g.mod->setSavedValue("autosave_interval_enabled", false); g.mod->setSavedValue("autosave_interval", std::to_string(10)); g.mod->setSavedValue("autosave_checkpoint_enabled", true); @@ -407,24 +429,24 @@ void Global::frameStepperOff() { g.mod->setSavedValue("render_fade_in_video", std::to_string(2)); g.mod->setSavedValue("render_fade_out_video", std::to_string(2)); - + g.mod->setSavedValue("macro_auto_stop_playing", false); g.mod->setSavedValue("macro_tps", 240.f); g.mod->setSavedValue("macro_tps_enabled", false); - + g.mod->setSavedValue("autoclicker_hold_for", 5); g.mod->setSavedValue("autoclicker_release_for", 5); g.mod->setSavedValue("autoclicker_hold_for2", 5); g.mod->setSavedValue("autoclicker_release_for2", 5); g.mod->setSavedValue("autoclicker_p1", true); g.mod->setSavedValue("autoclicker_p2", true); - + g.mod->setSavedValue("trajectory_color1", ccc3(74, 226, 85)); g.mod->setSavedValue("trajectory_color2", ccc3(130, 8, 8)); g.mod->setSavedValue("trajectory_length", std::to_string(240)); - + } - + if (!g.mod->setSavedValue("defaults_set3", true)) { g.mod->setSettingValue("render_folder", g.mod->getSaveDir() / "renders"); g.mod->setSavedValue("render_file_extension", std::string(".mp4")); @@ -436,41 +458,41 @@ void Global::frameStepperOff() { g.mod->setSavedValue("render_args", std::string("-pix_fmt yuv420p")); g.mod->setSavedValue("macro_noclip_p1", true); g.mod->setSavedValue("macro_noclip_p2", true); - + g.mod->setSavedValue("render_width2", std::to_string(1920)); g.mod->setSavedValue("render_height", std::to_string(1080)); g.mod->setSavedValue("render_bitrate", std::to_string(12)); g.mod->setSavedValue("render_fps", std::to_string(60)); g.mod->setSavedValue("render_video_args", std::string("colorspace=all=bt709:iall=bt470bg:fast=1")); - + g.mod->setSavedValue("render_codec", std::string("libx264")); #ifdef GEODE_IS_WINDOWS g.mod->setSettingValue("ffmpeg_path", geode::dirs::getGameDir() / "ffmpeg.exe"); #endif - + g.mod->setSavedValue("render_record_audio", true); g.mod->setSavedValue("render_hide_labels", true); - + g.mod->setSavedValue("macro_seed", std::to_string(1)); g.mod->setSavedValue("macro_speedhack", std::string("0.5")); g.mod->setSavedValue("macro_fps", 3); - + g.mod->setSavedValue("macro_ignore_inputs", true); g.mod->setSavedValue("macro_auto_safe_mode", true); g.mod->setSavedValue("macro_speedhack_audio", true); g.mod->setSavedValue("macro_show_frame_label", false); g.mod->setSavedValue("macro_hide_playing_label", true); - + g.mod->setSavedValue("menu_show_button", true); g.mod->setSavedValue("menu_pause_on_open", false); g.mod->setSavedValue("menu_show_cursor", true); - + #ifdef GEODE_IS_MOBILE g.mod->setSavedValue("menu_show_cursor", false); #endif - + } - + g.showTrajectory = g.mod->getSavedValue("macro_show_trajectory"); g.coinFinder = g.mod->getSavedValue("macro_coin_finder"); g.frameStepper = g.mod->getSavedValue("macro_frame_stepper"); @@ -487,28 +509,28 @@ void Global::frameStepperOff() { g.disableShaders = g.mod->getSavedValue("disableShaders"); g.autosaveIntervalEnabled = g.mod->getSavedValue("autosave_interval_enabled"); g.autosaveEnabled = g.mod->getSavedValue("macro_auto_save"); - + g.holdFor = g.mod->getSavedValue("autoclicker_hold_for"); g.releaseFor = g.mod->getSavedValue("autoclicker_release_for"); g.holdFor2 = g.mod->getSavedValue("autoclicker_hold_for2"); g.releaseFor2 = g.mod->getSavedValue("autoclicker_release_for2"); g.currentPage = g.mod->getSavedValue("current_page"); - + g.autosaveInterval = (geode::utils::numFromString(g.mod->getSavedValue("autosave_interval")).unwrapOr(0.f) * 60); g.speedhackEnabled = false; g.mod->setSavedValue("macro_speedhack_enabled", false); - + g.frameOffset = g.mod->getSettingValue("frame_offset"); g.frameFixesLimit = g.mod->getSettingValue("frame_fixes_limit"); g.lockDelta = g.mod->getSettingValue("lock_delta"); g.stopPlaying = g.mod->getSettingValue("auto_stop_playing"); - + if (g.mod->getSettingValue("macro_accuracy") == "Frame Fixes") - g.frameFixes = true; + g.frameFixes = true; else if (g.mod->getSettingValue("macro_accuracy") == "Input Fixes") - g.inputFixes = true; - + g.inputFixes = true; + g.macro.author = "N/A"; g.macro.description = "N/A"; g.macro.gameVersion = 2.206; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index c46fd394..d01e13ae 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -1,195 +1,195 @@ #include "utils.hpp" -std::string Utils::narrow(const wchar_t* str) { - if (!str) { - return ""; - } +std::string Utils::narrow(const wchar_t *str) { + if (!str) { + return ""; + } #ifdef GEODE_IS_ANDROID - std::string result; - size_t len = wcslen(str); - - if (len == 0) { - return result; - } - - result.reserve(len); - - for (size_t i = 0; i < len; ++i) { - if (str[i] > 0x7F) { - return ""; - } - result.push_back(static_cast(str[i])); - } + std::string result; + size_t len = wcslen(str); + if (len == 0) { return result; + } -#else -#if !defined (GEODE_IS_MOBILE) && !defined (GEODE_IS_MACOS) - int size = WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr); - if (size <= 0) { - return ""; - } + result.reserve(len); - auto buffer = new char[size]; - if (!buffer) { - return ""; + for (size_t i = 0; i < len; ++i) { + if (str[i] > 0x7F) { + return ""; } + result.push_back(static_cast(str[i])); + } - WideCharToMultiByte(CP_UTF8, 0, str, -1, buffer, size, nullptr, nullptr); - std::string result(buffer, size_t(size) - 1); - delete[] buffer; + return result; - return result; +#else +#if !defined(GEODE_IS_MOBILE) && !defined(GEODE_IS_MACOS) + int size = + WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr); + if (size <= 0) { + return ""; + } + + std::vector buffer(size); + + WideCharToMultiByte(CP_UTF8, 0, str, -1, buffer.data(), size, nullptr, + nullptr); + + return std::string(buffer.data(), size - 1); #endif #endif + + // ✅ Fallback return (fixes error) + return ""; } -std::wstring Utils::widen(const char* str) { +std::wstring Utils::widen(const char *str) { #ifdef GEODE_IS_ANDROID + if (!str) + return L""; - std::wstring result; - result.reserve(strlen(str)); + std::wstring result; + result.reserve(strlen(str)); - for (size_t i = 0; i < strlen(str); ++i) { - result.push_back(static_cast(str[i])); - } + for (size_t i = 0; i < strlen(str); ++i) { + result.push_back(static_cast(str[i])); + } - return result; + return result; #else -#if !defined (GEODE_IS_MOBILE) && !defined (GEODE_IS_MACOS) - if (str == nullptr) { - return L"Widen Error"; - } +#if !defined(GEODE_IS_MOBILE) && !defined(GEODE_IS_MACOS) + if (str == nullptr) { + return L"Widen Error"; + } - int size = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0); - if (size <= 0) { - return L"Widen Error"; - } + int size = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0); + if (size <= 0) { + return L"Widen Error"; + } - auto buffer = new wchar_t[size]; - if (!buffer) { - return L"Widen Error"; - } + std::vector buffer(size); - if (MultiByteToWideChar(CP_UTF8, 0, str, -1, buffer, size) <= 0) { - delete[] buffer; - return L"Widen Error"; - } - - std::wstring result(buffer, size_t(size) - 1); - delete[] buffer; - return result; + if (MultiByteToWideChar(CP_UTF8, 0, str, -1, buffer.data(), size) <= 0) { + return L"Widen Error"; + } + return std::wstring(buffer.data(), size - 1); #endif #endif + + // ✅ Fallback return + return L""; } std::string Utils::toLower(std::string str) { - std::transform(str.begin(), str.end(), str.begin(), ::tolower); - return str; + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + return str; } -std::time_t Utils::getFileCreationTime(const std::filesystem::path& path) { +std::time_t Utils::getFileCreationTime(const std::filesystem::path &path) { #ifdef GEODE_IS_WINDOWS - HANDLE hFile = CreateFileW( - path.wstring().c_str(), - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL - ); - - if (hFile == INVALID_HANDLE_VALUE) { - return 0; - } + HANDLE hFile = + CreateFileW(path.wstring().c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - FILETIME creationTime, lastAccessTime, lastWriteTime; - if (!GetFileTime(hFile, &creationTime, &lastAccessTime, &lastWriteTime)) { - CloseHandle(hFile); - return 0; - } + if (hFile == INVALID_HANDLE_VALUE) { + return 0; + } + FILETIME creationTime, lastAccessTime, lastWriteTime; + if (!GetFileTime(hFile, &creationTime, &lastAccessTime, &lastWriteTime)) { CloseHandle(hFile); + return 0; + } - ULARGE_INTEGER ull; - ull.LowPart = creationTime.dwLowDateTime; - ull.HighPart = creationTime.dwHighDateTime; + CloseHandle(hFile); - return ull.QuadPart / 10000000ULL - 11644473600ULL; + ULARGE_INTEGER ull; + ull.LowPart = creationTime.dwLowDateTime; + ull.HighPart = creationTime.dwHighDateTime; + + return ull.QuadPart / 10000000ULL - 11644473600ULL; +#else + // ✅ Safe fallback for other platforms + return 0; #endif - std::time_t ret; - return ret; } std::string Utils::formatTime(std::time_t time) { - std::tm tm = *std::localtime(&time); - std::ostringstream oss; - oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S"); - return oss.str(); + std::tm tm = *std::localtime(&time); + std::ostringstream oss; + oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S"); + return oss.str(); } -int Utils::copyFile(const std::string& sourcePath, const std::string& destinationPath) { - std::ifstream source(sourcePath, std::ios::binary); - std::ofstream destination(destinationPath, std::ios::binary); +int Utils::copyFile(const std::string &sourcePath, + const std::string &destinationPath) { + std::ifstream source(sourcePath, std::ios::binary); + std::ofstream destination(destinationPath, std::ios::binary); - if (!source) - return 1; + if (!source) + return 1; - if (!destination) - return 2; + if (!destination) + return 2; - destination << source.rdbuf(); + destination << source.rdbuf(); - return 0; + return 0; } std::vector Utils::splitByChar(std::string str, char splitChar) { - std::vector strs; - strs.reserve(std::count(str.begin(), str.end(), splitChar) + 1); - - size_t start = 0; - size_t end = str.find(splitChar); - while (end != std::string::npos) { - strs.emplace_back(str.substr(start, end - start)); - start = end + 1; - end = str.find(splitChar, start); - } - strs.emplace_back(str.substr(start)); - - return strs; + std::vector strs; + strs.reserve(std::count(str.begin(), str.end(), splitChar) + 1); + + size_t start = 0; + size_t end = str.find(splitChar); + while (end != std::string::npos) { + strs.emplace_back(str.substr(start, end - start)); + start = end + 1; + end = str.find(splitChar, start); + } + strs.emplace_back(str.substr(start)); + + return strs; } std::string Utils::getTexture() { - cocos2d::ccColor3B color = Mod::get()->getSettingValue("background_color"); - - std::string texture = color == ccc3(51, 68, 153) ? "GJ_square02.png" : "GJ_square06.png"; + cocos2d::ccColor3B color = + Mod::get()->getSettingValue("background_color"); + + std::string texture = + color == ccc3(51, 68, 153) ? "GJ_square02.png" : "GJ_square06.png"; - return texture; + return texture; } std::string Utils::getSimplifiedString(std::string str) { - if (str.find(".") == std::string::npos) return str; + if (str.find(".") == std::string::npos) + return str; - while(str.back() == '0') { - str.pop_back(); - if (str.empty()) break; - } + while (str.back() == '0') { + str.pop_back(); + if (str.empty()) + break; + } - if (!str.empty()) - if (str.back() == '.') str.pop_back(); + if (!str.empty()) + if (str.back() == '.') + str.pop_back(); - return str; + return str; } -void Utils::setBackgroundColor(geode::NineSlice* bg) { - cocos2d::ccColor3B color = Mod::get()->getSettingValue("background_color"); +void Utils::setBackgroundColor(geode::NineSlice *bg) { + cocos2d::ccColor3B color = + Mod::get()->getSettingValue("background_color"); - if (color == ccc3(51, 68, 153)) - color = ccc3(255, 255, 255); + if (color == ccc3(51, 68, 153)) + color = ccc3(255, 255, 255); - bg->setColor(color); -} \ No newline at end of file + bg->setColor(color); +} From 0c39ce9973e28cb6f822388b066652e649ad9cdd Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:04:34 +0300 Subject: [PATCH 093/211] seed fix + optimization --- src/global.cpp | 67 ++++----- src/includes.hpp | 6 +- src/macro.hpp | 2 +- src/practice_fixes/play_layer.cpp | 219 +++++++++++++++--------------- 4 files changed, 142 insertions(+), 152 deletions(-) diff --git a/src/global.cpp b/src/global.cpp index 0c494204..ca20d73a 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -257,46 +257,37 @@ int Global::getCurrentFrame(bool editor) { // } void Global::updateSeed(bool isRestart) { - - auto& g = Global::get(); - - if (g.seedEnabled) { - PlayLayer* pl = PlayLayer::get(); - if (!pl) return; - - unsigned long long ull = std::stoull(g.mod->getSavedValue("macro_seed"), nullptr, 0); - uintptr_t seed = static_cast(ull); - int finalSeed; - - if (!pl->m_player1->m_isDead) { - std::mt19937 generator(seed + pl->m_gameState.m_currentProgress); - std::uniform_int_distribution distribution(10000, 999999999); - finalSeed = distribution(generator); - } - else { - std::random_device rd; - std::mt19937 generator(rd()); - std::uniform_int_distribution distribution(1000, 999999999); - finalSeed = distribution(generator); + auto& g = Global::get(); + + if (g.seedEnabled) { + PlayLayer* pl = PlayLayer::get(); + if (!pl) return; + + uint64_t seed = geode::utils::numFromString( + g.mod->getSavedValue("macro_seed") + ).unwrapOr(0); + + int finalSeed; + + if (!pl->m_player1->m_isDead) { + g.gen.seed(seed + static_cast(pl->m_gameState.m_currentProgress)); + + finalSeed = g.gen.generate(10000, 1000000000); + } + else { + finalSeed = geode::utils::random::generate(1000, 1000000000); + } + + GameToolbox::fast_srand(finalSeed); + g.safeMode = true; } - #ifdef GEODE_IS_WINDOWS - *(uintptr_t*)((char*)geode::base::get() + seedAddr) = finalSeed; - #else - GameToolbox::fast_srand(finalSeed); - #endif - - g.safeMode = true; - } - - if (isRestart && g.state == state::recording) { - #ifdef GEODE_IS_WINDOWS - g.macro.seed = *(uintptr_t*)((char*)geode::base::get() + seedAddr); - #else - g.macro.seed = 0; - #endif - } - + if (isRestart && g.state == state::recording) { + uint64_t gdSeed = GameToolbox::getfast_srand(); + g.macro.seed = gdSeed; + + g.gen.seed(gdSeed); + } } void Global::updatePitch(float value) { diff --git a/src/includes.hpp b/src/includes.hpp index 37749c4e..6cdc9e30 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -15,7 +15,7 @@ using namespace geode::prelude; -const int seedAddr = 0x6a4e20; +// const int seedAddr = 0x6a4e20; const int indexButton[6] = { 1, 2, 3, 1, 2, 3 }; @@ -94,7 +94,8 @@ class Global { Renderer renderer; #endif state state = none; - + + geode::utils::random::Generator gen; std::unordered_map checkpoints; std::unordered_set allKeybinds; std::unordered_set playedFrames; @@ -167,6 +168,7 @@ class Global { size_t currentAction = 0; size_t currentFrameFix = 0; int frameFixesLimit = 240; + int currentActiveSeed = 0; bool frameFixes = false; bool inputFixes = false; diff --git a/src/macro.hpp b/src/macro.hpp index ad52bf3d..0bd78a7c 100644 --- a/src/macro.hpp +++ b/src/macro.hpp @@ -334,6 +334,6 @@ struct CheckpointData { int frame; PlayerData p1; PlayerData p2; - uintptr_t seed; + uint64_t seed; int previousFrame; }; diff --git a/src/practice_fixes/play_layer.cpp b/src/practice_fixes/play_layer.cpp index 19ffb40f..0e3fd203 100644 --- a/src/practice_fixes/play_layer.cpp +++ b/src/practice_fixes/play_layer.cpp @@ -5,24 +5,24 @@ #include class $modify(GJBaseGameLayer) { - + void toggleFlipped(bool p0, bool p1) { if (Mod::get()->getSavedValue("no_mirror_portal")) - p0 = false; + p0 = false; if (Global::get().state == state::recording || Mod::get()->getSavedValue("instant_mirror_portal")) - p1 = true; - + p1 = true; + GJBaseGameLayer::toggleFlipped(p0, p1); } - + void checkpointActivated(CheckpointGameObject * cp) { - + if (Global::get().state == state::none) - GJBaseGameLayer::checkpointActivated(cp); + GJBaseGameLayer::checkpointActivated(cp); else - Global::get().cancelCheckpoint = true; + Global::get().cancelCheckpoint = true; } - + }; class $modify(CheckpointObject) { @@ -30,115 +30,112 @@ class $modify(CheckpointObject) { bool init() { bool ret = CheckpointObject::init(); CheckpointObject* cp = this; - #else - static CheckpointObject* create() { - CheckpointObject* ret = CheckpointObject::create(); - CheckpointObject* cp = ret; - #endif - - if (!cp) return ret; - - auto& g = Global::get(); - PlayLayer* pl = PlayLayer::get(); - - PlayerData p1Data = PlayerPracticeFixes::saveData(pl->m_player1); - PlayerData p2Data = PlayerPracticeFixes::saveData(pl->m_player2); - - Global::get().checkpoints[cp] = { - Global::getCurrentFrame(), - p1Data, - p2Data, - #ifdef GEODE_IS_WINDOWS - *(uintptr_t*)((char*)geode::base::get() + seedAddr), - #else - 0, + #else + static CheckpointObject* create() { + CheckpointObject* ret = CheckpointObject::create(); + CheckpointObject* cp = ret; #endif - Global::get().previousFrame - }; - - return ret; - - } -}; - -class $modify(PlayLayer) { - - void storeCheckpoint(CheckpointObject * cp) { - if (!cp) return PlayLayer::storeCheckpoint(cp); - - auto& g = Global::get(); - - if (!g.cancelCheckpoint) + + if (!cp) return ret; + + auto& g = Global::get(); + PlayLayer* pl = PlayLayer::get(); + + PlayerData p1Data = PlayerPracticeFixes::saveData(pl->m_player1); + PlayerData p2Data = PlayerPracticeFixes::saveData(pl->m_player2); + + uint64_t currentSeed = GameToolbox::getfast_srand(); + + g.checkpoints[cp] = { + Global::getCurrentFrame(), + p1Data, + p2Data, + currentSeed, + g.previousFrame + }; + + return ret; + } + }; + + class $modify(PlayLayer) { + + void storeCheckpoint(CheckpointObject * cp) { + if (!cp) return PlayLayer::storeCheckpoint(cp); + + auto& g = Global::get(); + + if (!g.cancelCheckpoint) PlayLayer::storeCheckpoint(cp); - else { - g.cancelCheckpoint = false; - return; + else { + g.cancelCheckpoint = false; + return; + } + } - - } - - void loadFromCheckpoint(CheckpointObject* cp) { - if (!cp) return PlayLayer::loadFromCheckpoint(cp); - - auto& g = Global::get(); - - if (g.mod->getSavedValue("autosave_checkpoint_enabled")) - Macro::tryAutosave(m_level, cp); - - if (g.state == state::playing) { - PlayLayer::loadFromCheckpoint(cp); - - if (!g.checkpoints.contains(cp)) return; - if (g.checkpoints[cp].frame <= 1) return; - + void loadFromCheckpoint(CheckpointObject* cp) { + + if (!cp) return PlayLayer::loadFromCheckpoint(cp); + + auto& g = Global::get(); + + if (g.mod->getSavedValue("autosave_checkpoint_enabled")) + Macro::tryAutosave(m_level, cp); + + if (g.state == state::playing) { + PlayLayer::loadFromCheckpoint(cp); + + if (!g.checkpoints.contains(cp)) return; + if (g.checkpoints[cp].frame <= 1) return; + + PlayerData p1Data = g.checkpoints[cp].p1; + PlayerData p2Data = g.checkpoints[cp].p2; + + g.respawnFrame = g.checkpoints[cp].frame; + g.previousFrame = g.checkpoints[cp].previousFrame; + PlayerPracticeFixes::applyData(this->m_player1, p1Data, false); + PlayerPracticeFixes::applyData(this->m_player2, p2Data, true); + + return; + } + + if ((g.state != state::recording && !Mod::get()->getSavedValue("macro_always_practice_fixes"))) + return PlayLayer::loadFromCheckpoint(cp); + + if (!g.checkpoints.contains(cp)) return PlayLayer::loadFromCheckpoint(cp); + + Macro::resetVariables(); + + int frame = g.checkpoints[cp].frame; PlayerData p1Data = g.checkpoints[cp].p1; PlayerData p2Data = g.checkpoints[cp].p2; - - g.respawnFrame = g.checkpoints[cp].frame; + + g.ignoreJumpButton = frame + 1; g.previousFrame = g.checkpoints[cp].previousFrame; + + if (g.seedEnabled) { + uint64_t savedSeed = g.checkpoints[cp].seed; + + GameToolbox::fast_srand(static_cast(savedSeed)); + + g.gen.seed(savedSeed); + } + + if (g.state == state::recording) + InputPracticeFixes::applyFixes(this, p1Data, p2Data, frame); + + PlayLayer::loadFromCheckpoint(cp); + PlayerPracticeFixes::applyData(this->m_player1, p1Data, false); PlayerPracticeFixes::applyData(this->m_player2, p2Data, true); - - return; - } - - if ((g.state != state::recording && !Mod::get()->getSavedValue("macro_always_practice_fixes"))) - return PlayLayer::loadFromCheckpoint(cp); - - if (!g.checkpoints.contains(cp)) return PlayLayer::loadFromCheckpoint(cp); - - Macro::resetVariables(); - - int frame = g.checkpoints[cp].frame; - PlayerData p1Data = g.checkpoints[cp].p1; - PlayerData p2Data = g.checkpoints[cp].p2; - - g.ignoreJumpButton = frame + 1; - g.previousFrame = g.checkpoints[cp].previousFrame; - - #ifdef GEODE_IS_WINDOWS - - if (g.seedEnabled) { - uintptr_t seed = g.checkpoints[cp].seed; - *(uintptr_t*)((char*)geode::base::get() + seedAddr) = seed; - } - - #endif - - if (g.state == state::recording) - InputPracticeFixes::applyFixes(this, p1Data, p2Data, frame); - - PlayLayer::loadFromCheckpoint(cp); - - PlayerPracticeFixes::applyData(this->m_player1, p1Data, false); - PlayerPracticeFixes::applyData(this->m_player2, p2Data, true); - - if (g.state != state::recording && g.mod->getSavedValue("macro_always_practice_fixes")) { - this->m_player1->releaseButton(static_cast(1)); - this->m_player2->releaseButton(static_cast(1)); + + if (g.state != state::recording && g.mod->getSavedValue("macro_always_practice_fixes")) { + this->m_player1->releaseButton(static_cast(1)); + this->m_player2->releaseButton(static_cast(1)); + } + } - - } - -}; + + }; + \ No newline at end of file From cdd9c6cc5e1c1543b0cb15b0f875ef65ef1fa558 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:07:22 +0300 Subject: [PATCH 094/211] stop casting here --- src/practice_fixes/play_layer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/practice_fixes/play_layer.cpp b/src/practice_fixes/play_layer.cpp index 0e3fd203..ccaef54e 100644 --- a/src/practice_fixes/play_layer.cpp +++ b/src/practice_fixes/play_layer.cpp @@ -117,7 +117,7 @@ class $modify(CheckpointObject) { if (g.seedEnabled) { uint64_t savedSeed = g.checkpoints[cp].seed; - GameToolbox::fast_srand(static_cast(savedSeed)); + GameToolbox::fast_srand(savedSeed); g.gen.seed(savedSeed); } From 6bef065520ba8f521ee1f6c69b96918da4625e57 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:13:21 +0300 Subject: [PATCH 095/211] cleanup --- src/global.cpp | 2 +- src/includes.hpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/global.cpp b/src/global.cpp index ca20d73a..89c50b7a 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -267,7 +267,7 @@ void Global::updateSeed(bool isRestart) { g.mod->getSavedValue("macro_seed") ).unwrapOr(0); - int finalSeed; + uint64_t finalSeed; if (!pl->m_player1->m_isDead) { g.gen.seed(seed + static_cast(pl->m_gameState.m_currentProgress)); diff --git a/src/includes.hpp b/src/includes.hpp index 6cdc9e30..6e95ec05 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -168,7 +168,6 @@ class Global { size_t currentAction = 0; size_t currentFrameFix = 0; int frameFixesLimit = 240; - int currentActiveSeed = 0; bool frameFixes = false; bool inputFixes = false; From 4820ad678b0146e1daca228808f2083f1e156938 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:25:04 +0300 Subject: [PATCH 096/211] change renderer message for cbs/cos --- src/renderer/renderer.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index b3cf3796..266623da 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -159,11 +159,21 @@ bool Renderer::toggle() { } #ifdef GEODE_IS_WINDOWS - if (GameManager::sharedState()->getGameVariable(GameVar::ClickBetweenSteps) || - GameManager::sharedState()->getGameVariable(GameVar::ClickOnSteps)) { - FLAlertLayer::create("Render", "Disable Click Between Steps and Click On Steps in GD settings to render a level.", "OK")->show(); - return false; + std::vector incompatSettings; + + if (GameManager::sharedState()->getGameVariable(GameVar::ClickBetweenSteps)) incompatSettings.push_back("Click Between Steps"); + if (GameManager::sharedState()->getGameVariable(GameVar::ClickOnSteps)) incompatSettings.push_back("Click On Steps"); + + if (!incompatSettings.empty()) { + geode::utils::StringBuffer incompatString; + + for (const std::string& name : incompatSettings) { + incompatString.append("{}{}", name, (name != incompatSettings.back() ? "," : "")); + + FLAlertLayer::create("Render", "Disable incompatible GD settings to render a level: \n" + incompatString.str(), "OK")->show(); + } } + #endif bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); From d5bfddaf628f45e0d18d023b10f5a6a7577807c9 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sat, 21 Feb 2026 05:55:49 +0300 Subject: [PATCH 097/211] rewrite layout mode --- src/hacks/layout_mode.cpp | 254 ++++++++++------------------------ src/hacks/layout_mode.hpp | 60 -------- src/hacks/show_trajectory.hpp | 1 - src/main.cpp | 1 - 4 files changed, 72 insertions(+), 244 deletions(-) delete mode 100644 src/hacks/layout_mode.hpp diff --git a/src/hacks/layout_mode.cpp b/src/hacks/layout_mode.cpp index f09e07c6..ff441f2a 100644 --- a/src/hacks/layout_mode.cpp +++ b/src/hacks/layout_mode.cpp @@ -1,200 +1,90 @@ -#include "layout_mode.hpp" - -#include +#include "../includes.hpp" +#include +#include #include -class $modify(LevelTools) { - static bool verifyLevelIntegrity(gd::string v1, int v2) { - if (Global::get().layoutMode) return true; - return LevelTools::verifyLevelIntegrity(v1, v2); - } -}; - -class $modify(PlayLayer) { - - void addObject(GameObject * obj) { - if (!Global::get().layoutMode) return PlayLayer::addObject(obj); +using namespace geode::prelude; - if (excludedTriggerIDs.contains(obj->m_objectID)) return; +static std::unordered_set s_decoIDs = {5, 15, 16, 17, 18, 19, 20, 21, 41, 48, 49, 50, 51, 52, 53, 54, 60, 73, 80, 85, 86, 87, 97, 106, 107, 110, 113, 114, 115, 120, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 136, 137, 138, 139, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 180, 181, 182, 190, 211, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 245, 246, 259, 266, 273, 277, 278, 279, 280, 281, 282, 283, 284, 285, 296, 297, 324, 325, 358, 373, 374, 375, 376, 377, 378, 394, 395, 396, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 419, 420, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 460, 472, 473, 474, 476, 477, 478, 479, 480, 481, 482, 485, 486, 487, 488, 489, 490, 491, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 653, 654, 655, 656, 657, 658, 659, 668, 669, 670, 671, 672, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 713, 714, 715, 716, 719, 721, 722, 723, 724, 730, 731, 732, 733, 734, 735, 736, 738, 739, 752, 753, 754, 755, 756, 757, 758, 759, 762, 763, 764, 765, 766, 767, 769, 770, 771, 772, 773, 774, 775, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 841, 842, 843, 844, 845, 846, 847, 848, 850, 853, 854, 855, 856, 857, 859, 861, 862, 863, 867, 868, 869, 870, 871, 872, 873, 874, 877, 878, 880, 881, 882, 883, 884, 885, 888, 889, 890, 891, 893, 894, 895, 896, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 916, 917, 920, 921, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 980, 981, 982, 983, 984, 985, 986, 987, 988, 990, 992, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1205, 1206, 1207, 1223, 1224, 1225, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1261, 1263, 1265, 1266, 1267, 1269, 1270, 1271, 1272, 1273, 1274, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1322, 1325, 1326, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1395, 1431, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1471, 1472, 1473, 1496, 1507, 1510, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1529, 1530, 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1586, 1588, 1590, 1591, 1592, 1593, 1596, 1597, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 1617, 1618, 1621, 1622, 1623, 1624, 1625, 1626, 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659, 1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, 1737, 1738, 1739, 1740, 1741, 1742, 1752, 1753, 1754, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1791, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1804, 1805, 1806, 1807, 1808, 1809, 1810, 1820, 1821, 1823, 1824, 1825, 1826, 1827, 1828, 1830, 1831, 1832, 1833, 1834, 1835, 1836, 1837, 1838, 1839, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1858, 1860, 1861, 1862, 1863, 1864, 1865, 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873, 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1881, 1882, 1883, 1884, 1885, 1886, 1887, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, 1899, 1900, 1901, 1902, 1908, 1909, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1936, 1937, 1938, 1939, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2064, 2065, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2087, 2088, 2089, 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149, 2150, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 2180, 2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193, 2194, 2195, 2196, 2197, 2198, 2199, 2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224, 2225, 2226, 2227, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, 2241, 2242, 2243, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, 2270, 2271, 2272, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2296, 2297, 2298, 2299, 2300, 2301, 2302, 2303, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2316, 2317, 2318, 2319, 2320, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2330, 2331, 2332, 2333, 2334, 2335, 2336, 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2344, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 2354, 2355, 2356, 2357, 2358, 2359, 2360, 2361, 2362, 2363, 2364, 2365, 2366, 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379, 2380, 2381, 2382, 2383, 2384, 2385, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2393, 2394, 2395, 2396, 2397, 2398, 2399, 2400, 2401, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 2412, 2413, 2414, 2415, 2416, 2417, 2418, 2419, 2420, 2421, 2422, 2423, 2424, 2425, 2426, 2427, 2428, 2429, 2430, 2431, 2432, 2433, 2434, 2435, 2436, 2437, 2438, 2439, 2440, 2441, 2442, 2443, 2444, 2445, 2446, 2447, 2448, 2449, 2450, 2451, 2452, 2453, 2454, 2455, 2456, 2457, 2458, 2459, 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 2470, 2471, 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, 2480, 2481, 2482, 2483, 2484, 2485, 2486, 2487, 2488, 2489, 2490, 2491, 2492, 2493, 2494, 2495, 2496, 2497, 2498, 2499, 2500, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513, 2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2527, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2540, 2541, 2542, 2543, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2577, 2578, 2579, 2580, 2581, 2582, 2583, 2584, 2585, 2586, 2587, 2588, 2589, 2590, 2591, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2600, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611, 2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, 2650, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676, 2677, 2678, 2679, 2680, 2681, 2682, 2683, 2684, 2685, 2686, 2687, 2688, 2689, 2690, 2691, 2692, 2693, 2694, 2695, 2696, 2697, 2698, 2699, 2700, 2703, 2704, 2708, 2709, 2710, 2711, 2712, 2713, 2714, 2715, 2716, 2717, 2718, 2719, 2720, 2721, 2722, 2723, 2724, 2725, 2726, 2727, 2728, 2729, 2730, 2731, 2732, 2733, 2734, 2735, 2736, 2737, 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745, 2746, 2747, 2748, 2749, 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2773, 2776, 2777, 2778, 2779, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2800, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2838, 2839, 2840, 2841, 2842, 2843, 2844, 2845, 2846, 2847, 2848, 2849, 2850, 2851, 2852, 2853, 2854, 2855, 2856, 2857, 2858, 2859, 2860, 2861, 2862, 2863, 2864, 2865, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2881, 2882, 2883, 2884, 2885, 2886, 2887, 2888, 2889, 2890, 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2927, 2928, 2929, 2930, 2931, 2932, 2933, 2934, 2935, 2936, 2937, 2938, 2939, 2940, 2941, 2942, 2943, 2944, 2945, 2946, 2947, 2948, 2949, 2950, 2951, 2952, 2953, 2954, 2955, 2956, 2957, 2958, 2959, 2960, 2961, 2962, 2963, 2964, 2965, 2966, 2967, 2968, 2969, 2970, 2971, 2972, 2973, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2986, 2987, 2988, 2989, 2990, 2991, 2992, 2993, 2994, 2995, 2996, 2997, 2998, 3000, 3001, 3002, 3032, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063, 3064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 3077, 3078, 3079, 3080, 3081, 3082, 3083, 3084, 3085, 3086, 3087, 3088, 3089, 3090, 3091, 3092, 3093, 3094, 3095, 3096, 3097, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, 3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126, 3127, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3143, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161, 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176, 3177, 3178, 3179, 3180, 3181, 3182, 3183, 3184, 3185, 3186, 3187, 3188, 3189, 3190, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3199, 3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3210, 3211, 3212, 3213, 3214, 3215, 3216, 3217, 3218, 3219, 3220, 3221, 3222, 3223, 3224, 3225, 3226, 3227, 3228, 3229, 3230, 3231, 3232, 3233, 3234, 3235, 3236, 3237, 3238, 3239, 3240, 3241, 3242, 3243, 3244, 3245, 3246, 3247, 3248, 3249, 3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3260, 3261, 3262, 3263, 3264, 3265, 3266, 3267, 3268, 3269, 3270, 3271, 3272, 3273, 3274, 3275, 3276, 3277, 3278, 3279, 3280, 3281, 3282, 3283, 3284, 3285, 3286, 3287, 3288, 3289, 3290, 3291, 3292, 3293, 3294, 3295, 3296, 3297, 3298, 3299, 3300, 3301, 3302, 3303, 3304, 3305, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3317, 3318, 3319, 3320, 3321, 3322, 3323, 3324, 3325, 3326, 3327, 3328, 3329, 3330, 3331, 3332, 3333, 3334, 3335, 3336, 3337, 3338, 3339, 3340, 3341, 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, 3350, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, 3368, 3369, 3370, 3371, 3372, 3373, 3374, 3375, 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3384, 3385, 3386, 3387, 3388, 3389, 3390, 3391, 3392, 3393, 3394, 3395, 3396, 3397, 3398, 3399, 3400, 3401, 3402, 3403, 3404, 3405, 3406, 3407, 3408, 3409, 3410, 3411, 3412, 3413, 3414, 3415, 3416, 3417, 3418, 3419, 3420, 3421, 3422, 3423, 3424, 3425, 3426, 3427, 3428, 3429, 3430, 3431, 3432, 3433, 3434, 3435, 3436, 3437, 3438, 3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448, 3449, 3450, 3451, 3452, 3453, 3454, 3455, 3456, 3457, 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3465, 3466, 3467, 3468, 3469, 3470, 3471, 3472, 3473, 3474, 3475, 3476, 3477, 3478, 3479, 3480, 3481, 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3489, 3490, 3491, 3492, 3493, 3494, 3495, 3496, 3497, 3498, 3499, 3500, 3501, 3502, 3503, 3504, 3505, 3506, 3507, 3508, 3509, 3510, 3511, 3512, 3513, 3514, 3515, 3516, 3517, 3518, 3519, 3520, 3521, 3522, 3523, 3524, 3525, 3526, 3527, 3528, 3529, 3530, 3531, 3532, 3533, 3534, 3535, 3536, 3537, 3538, 3539, 3540, 3541, 3542, 3543, 3544, 3545, 3546, 3547, 3548, 3549, 3550, 3551, 3552, 3553, 3554, 3555, 3556, 3557, 3558, 3559, 3560, 3561, 3562, 3563, 3564, 3565, 3566, 3567, 3568, 3569, 3570, 3571, 3572, 3573, 3574, 3575, 3576, 3577, 3578, 3579, 3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3591, 3592, 3593, 3594, 3595, 3596, 3597, 3598, 3599, 3621, 3622, 3623, 3624, 3625, 3626, 3627, 3628, 3629, 3630, 3631, 3632, 3633, 3634, 3635, 3636, 3637, 3638, 3639, 3646, 3647, 3648, 3649, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3658, 3659, 3700, 3701, 3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, 3710, 3711, 3712, 3713, 3714, 3715, 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724, 3725, 3726, 3727, 3728, 3729, 3730, 3731, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3742, 3743, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3760, 3761, 3762, 3763, 3764, 3765, 3766, 3767, 3768, 3769, 3770, 3771, 3772, 3773, 3774, 3775, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, 3785, 3786, 3787, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799, 3801, 3802, 3803, 3804, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3813, 3814, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3826, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3841, 3842, 3843, 3844, 3845, 3846, 3847, 3848, 3849, 3850, 3851, 3852, 3853, 3854, 3855, 3856, 3857, 3858, 3859, 3860, 3861, 3862, 3863, 3864, 3865, 3866, 3867, 3868, 3869, 3870, 3871, 3872, 3873, 3874, 3875, 3876, 3877, 3878, 3879, 3880, 3881, 3882, 3883, 3884, 3885, 3886, 3887, 3888, 3889, 3890, 3891, 3892, 3893, 3894, 3895, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3904, 3905, 3906, 3907, 3908, 3909, 3910, 3911, 3912, 3913, 3914, 3915, 3916, 3917, 3918, 3919, 3920, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3934, 3935, 3936, 3937, 3938, 3939, 3940, 3941, 3942, 3943, 3944, 3945, 3946, 3947, 3948, 3949, 3950, 3951, 3952, 3953, 3954, 3955, 3956, 3957, 3958, 3959, 3960, 3961, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3980, 3981, 3982, 3983, 3984, 3985, 3986, 3987, 3988, 3989, 3990, 3991, 3992, 3993, 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4035, 4036, 4037, 4038, 4039, 4040, 4041, 4042, 4043, 4044, 4045, 4046, 4047, 4048, 4049, 4050, 4051, 4052, 4053, 4054, 4055, 4056, 4057, 4058, 4059, 4060, 4061, 4062, 4063, 4064, 4065, 4066, 4067, 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4078, 4079, 4080, 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095, 4096, 4097, 4098, 4099, 4100, 4101, 4102, 4103, 4104, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4116, 4117, 4118, 4119, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 4140, 4141, 4142, 4143, 4144, 4145, 4146, 4147, 4148, 4149, 4150, 4151, 4152, 4153, 4154, 4155, 4156, 4157, 4158, 4159, 4160, 4161, 4162, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4175, 4176, 4177, 4178, 4179, 4180, 4181, 4182, 4183, 4184, 4185, 4186, 4187, 4188, 4189, 4190, 4191, 4192, 4193, 4194, 4195, 4196, 4197, 4198, 4199, 4200, 4201, 4202, 4203, 4204, 4205, 4206, 4207, 4208, 4209, 4210, 4211, 4212, 4213, 4214, 4215, 4216, 4217, 4218, 4219, 4220, 4221, 4222, 4223, 4224, 4225, 4226, 4227, 4228, 4229, 4230, 4231, 4232, 4233, 4234, 4235, 4236, 4237, 4238, 4239, 4240, 4241, 4242, 4243, 4244, 4245, 4246, 4247, 4248, 4249, 4250, 4251, 4252, 4253, 4254, 4255, 4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, 4264, 4265, 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 4292, 4293, 4294, 4295, 4296, 4297, 4298, 4299, 4300, 4301, 4302, 4303, 4304, 4305, 4306, 4307, 4308, 4309, 4310, 4311, 4312, 4313, 4314, 4315, 4316, 4317, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4326, 4327, 4328, 4329, 4330, 4331, 4332, 4333, 4334, 4335, 4336, 4337, 4338, 4339, 4340, 4341, 4342, 4343, 4344, 4345, 4346, 4347, 4348, 4349, 4350, 4351, 4352, 4353, 4354, 4355, 4356, 4357, 4358, 4359, 4360, 4361, 4362, 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, 4371, 4372, 4373, 4374, 4375, 4376, 4377, 4378, 4379, 4380, 4381, 4382, 4383, 4384, 4385}; +static std::unordered_set s_objectFilter = { 16, 17, 221, 743, 744, 899, 900, 915, 1006, 32, 33, 899, 900, 29, 30, 104, 105, 717, 718, 1007, 1520, 2903, 3029, 3030, 3031, 2999, 3606, 3612, 3009, 3010, 3014, 3015, 3021, 3020, 1818, 1819, 32, 33, 1612, 1613, 3608}; - PlayLayer::addObject(obj); - - obj->m_activeMainColorID = -1; - obj->m_activeDetailColorID = -1; - obj->m_detailUsesHSV = false; - obj->m_baseUsesHSV = false; - obj->m_hasNoGlow = true; - obj->m_isHide = obj->m_objectID == 2065; - obj->setOpacity(obj->m_objectID == 2065 ? 0 : 255); - obj->setVisible(obj->m_objectID != 2065); - } - - bool init(GJGameLevel * level, bool b1, bool b2) { +class $modify(LayoutModePL, PlayLayer) { + struct Fields { + bool m_didApply = false; + }; + + void processCreateObjectsFromSetup() { auto& g = Global::get(); - -#ifdef GEODE_IS_ANDROID - - if (robtopLevelIDs.contains(level->m_levelID.value())) - return PlayLayer::init(level, b1, b2); - -#endif - g.layoutMode = Mod::get()->getSavedValue("macro_layout_mode"); - std::string oldString = level->m_levelString; - - if (g.layoutMode) - level->m_levelString = LayoutMode::getModifiedString(level->m_levelString); - - if (!PlayLayer::init(level, b1, b2)) { - if (g.layoutMode) - level->m_levelString = oldString; - - return false; + if (g.layoutMode) { + m_fields->m_didApply = true; } - - if (g.layoutMode) - level->m_levelString = oldString; - - return true; + + PlayLayer::processCreateObjectsFromSetup(); } -}; - -std::string LayoutMode::getModifiedString(std::string levelString) { - if (levelString.empty()) return ""; - - std::string decompString = ZipUtils::decompressString(levelString.c_str(), true, 0); - - std::vector objectStrings = Utils::splitByChar(decompString, ';'); - std::string firstPart = objectStrings[0]; - - std::vector levelSettings = Utils::splitByChar(firstPart, ','); - std::vector levelColors = Utils::splitByChar(levelSettings[1], '|'); - - if (levelColors.size() >= 6) - levelColors.erase(levelColors.begin(), levelColors.begin() + 6); - - levelSettings[1] = newColors; - - firstPart = mergeVector(levelSettings); - - std::unordered_set importantGroups; - - for (int i = 0; i < levelSettings.size(); i++) { - if (levelSettings[i] == "kA36") { - if (geode::utils::numFromString(levelSettings[i + 1]).unwrapOr(0) != 0) - importantGroups.insert(geode::utils::numFromString(levelSettings[i + 1]).unwrap()); - - break; + + void addObject(GameObject* obj) { + if (m_fields->m_didApply) { + if (s_objectFilter.contains(obj->m_objectID)) { + obj->m_isHide = true; + return; + } + + obj->m_hasNoGlow = true; + obj->m_activeMainColorID = -1; + obj->m_activeDetailColorID = -1; + obj->m_detailUsesHSV = false; + obj->m_baseUsesHSV = false; + obj->m_isHide = false; + obj->setOpacity(255); } + PlayLayer::addObject(obj); } +}; - std::vector objects; - - for (int i = 1; i < objectStrings.size(); i++) { - std::vector result = Utils::splitByChar(objectStrings[i], ','); - std::map props; - size_t hidden = 0; - - for (size_t i = 0; i <= result.size(); i += 2) { - if (i >= result.size()) break; - auto propID = numFromString(result[i]); - - if (propID.isErr()) continue; - - if (result[i] == "135") hidden = i; - props[propID.unwrap()] = result[i + 1]; - } - - objects.push_back({ result, props, hidden, objectStrings[i] }); - - if (!props.contains(1)) continue; - - if (!importantTriggerIDs.contains(geode::utils::numFromString(props.at(1)).unwrap())) continue; - - for (int i = 0; i < importantTriggerIDs.at(geode::utils::numFromString(props.at(1)).unwrap()).size(); i++) { - int propID = importantTriggerIDs.at(geode::utils::numFromString(props.at(1)).unwrap())[i]; - if (!props.contains(propID)) continue; - - if (geode::utils::numFromString(props[propID]).unwrapOr(0) != 0) - importantGroups.insert(geode::utils::numFromString(props[propID]).unwrap()); +class $modify(LayoutModeGO, GameObject) { + void addGlow(gd::string p0) { + auto pl = PlayLayer::get(); + GameObject::addGlow(std::move(p0)); + if (!pl) return; + + if (static_cast(pl)->m_fields->m_didApply) { + if ((m_objectType == GameObjectType::Decoration && m_objectID != 44 && m_objectID != 38 && m_objectID != 749 && m_objectID != 747) || m_isNoTouch || s_decoIDs.contains(m_objectID)) { // 44 being practice mode checkpoint, because thats a "decoration" + m_isHide = true; + } else { + m_isHide = false; + } } - } +}; - std::string newString = ""; - - for (LevelObject obj : objects) { - - std::vector vec = obj.vecString; - std::map props = obj.props; - int hidden = obj.hiddenIndex; - - if (!props.contains(1)) continue; - - if (decoObjectIDs.contains(geode::utils::numFromString(props.at(1)).unwrap()) || props.contains(121)) { - if (!props.contains(57)) continue; - - for (const auto& el : Utils::splitByChar(props.at(57), '.')) { - if (el.empty()) continue; - if (!importantGroups.contains(geode::utils::numFromString(el).unwrapOr(0))) continue; - - if (!props.contains(135)) { - vec.push_back("135"); - vec.push_back("1"); - } - newString += ";" + mergeVector(vec); - +class $modify(LayoutModeGJBGL, GJBaseGameLayer) { + void updateColor(ccColor3B& color, float fadeTime, int colorID, bool blending, float opacity, ccHSVValue& copyHSV, int colorIDToCopy, bool copyOpacity, EffectGameObject* callerObject, int unk1, int unk2) override { + auto pl = PlayLayer::get(); + if (pl && !m_isEditor && static_cast(pl)->m_fields->m_didApply) { + switch (colorID) { + case 1000: // background + color = {40, 125, 255}; + break; + case 1001: // ground (G1) + color = {0, 102, 255}; + break; + case 1002: // line (L) + color = {255, 255, 255}; + break; + case 1009: // ground 2 (G2) + color = {0, 102, 255}; + break; + case 1013: // middle ground (MG) + color = {40, 125, 255}; + break; + case 1014: // middle ground 2 (MG2) + color = {40, 125, 255}; + break; + default: break; - } - - continue; - } - - if (!solidObjectIDs.contains(geode::utils::numFromString(props.at(1)).unwrap())) { - newString += ";" + obj.ogString; - continue; - } - - if (props.contains(129)) { - if (geode::utils::numFromString(props[129]).unwrap() <= 0.f && hidden == 0) { - vec.push_back("135"); - vec.push_back("1"); - - newString += ";" + mergeVector(vec); - continue; } } - - if (hidden != 0) { - vec.erase(vec.begin() + hidden); - vec.erase(vec.begin() + hidden); - newString += ";" + mergeVector(vec); - } - else - newString += ";" + obj.ogString; + GJBaseGameLayer::updateColor(color, fadeTime, colorID, blending, opacity, copyHSV, colorIDToCopy, copyOpacity, callerObject, unk1, unk2); } - - return firstPart + newString + ";"; - -} - -std::string LayoutMode::mergeVector(std::vector vec, std::string separator) { - if (vec.empty()) return ""; - - std::string result; - - size_t total_size = 0; - for (const auto& s : vec) - total_size += s.size() + separator.size(); - - result.reserve(total_size); - - for (size_t i = 0; i < vec.size(); ++i) { - result += vec[i]; - - if (i != vec.size() - 1) - result += separator; - } - - return result; -} +}; \ No newline at end of file diff --git a/src/hacks/layout_mode.hpp b/src/hacks/layout_mode.hpp deleted file mode 100644 index b56e2556..00000000 --- a/src/hacks/layout_mode.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "../includes.hpp" -#include -#include - -struct LevelObject { - std::vector vecString; - std::map props; - size_t hiddenIndex = 0; - std::string ogString; -}; - -class LayoutMode { - -public: - - static std::string getModifiedString(std::string levelString); - - static std::string mergeVector(std::vector vec, std::string separator = ","); - -}; - -const std::string newColors = "1_40_2_125_3_255_11_255_12_255_13_255_4_-1_6_1000_7_1_15_1_18_0_8_1|1_0_2_102_3_255_11_255_12_255_13_255_4_-1_6_1001_7_1_15_1_18_0_8_1|1_0_2_102_3_255_11_255_12_255_13_255_4_-1_6_1009_7_1_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_1002_5_1_7_1_15_1_18_0_8_1|1_40_2_125_3_255_11_255_12_255_13_255_4_-1_6_1013_7_1_15_1_18_0_8_1|1_40_2_125_3_255_11_255_12_255_13_255_4_-1_6_1014_7_1_15_1_18_0_8_1|"; - -const std::unordered_set robtopLevelIDs = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 3001, 5001, 5002, 5003, 5004 }; - -const std::unordered_set excludedTriggerIDs = { 32, 33, 24, 23, 25, 26, 27, 28, 55, 56, 57, 58, 59, 22, 24, 27, 28, 29, 30, 56, 58, 59, 105, 899, 915, 1007, 1006, 2903, 2904, 2905, 2907, 2909, 2910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2919, 2920, 2921, 2922, 2923, 2924, 3009,3010, 3029, 3030, 3031, 3606, 3612, 1612, 1613, 1818, 1819 }; - -const std::map> importantTriggerIDs = { - {1346, {71, 51, 516, 517, 518, 519}}, - {2067, {71, 51}}, - {1347, {71, 51}}, - {3033, {71, 51}}, - {3016, {51, 71}}, - {3661, {51, 71}}, - {3006, {71, 51}}, - {3007, {71, 51}}, - {3008, {71, 51}}, - {1914, {71, 51}}, - {2062, {51, 71}}, - {901, {71, 395}}, - {3613, {71, 51}}, - {3022, {71, 51}}, - {3032, {71, 51}}, - {1811, {80, 51, 71}}, - {1611, {80, 51, 71}}, - {1814, {51}}, - {3660, {51}}, - {3027, {51}}, - {747, {51}}, - {2902, {51}}, - {2063, {51, 71 ,448}} -}; - -const std::unordered_set decoObjectIDs = -{ 5,502,73,80,120,211,1820,1821,1823,1824,1825,1826,1827,259,1828,266,273,1142,1140,1141,1143,1144,1149,1145,1146,1147,1153,1148,1150,1151,1152,476,477,478,479,480,481,482,485,486,488,487,489,490,491,644,650,641,1075,646,642,739,643,645,647,648,649,1077,1298,1076,658,722,659,734,752,753,754,755,756,757,758,759,903,904,905,911,1045,1046,1294,1295,952,953,954,955,1294,952,953,954,955,956,957,958,959,974,975,976,977,1047,1048,1296,1297,1299,1300,1301,1302,1303,1304,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1322,1191,1192,1193,1197,1196,1194,1195,807,808,809,810,811,812,814,815,813,816,817,818,819,820,820,821,819,821,822,824,822,823,825,1082,1100,1083,1101,1103,1085,1086,1104,1088,1105,1089,1106,1087,1090,1099,841,1112,842,1113,843,844,1114,845,1115,846,1116,847,1117,848,1118,867,868,869,870,870,871,872,1266,1267,873,874,874,874,874,880,881,882,883,1160,1161,884,885,1062,1159,890,1247,1278,1277,1248,1279,1249,1280,1250,1281,1251,1252,1253,1282,1254,1283,1255,1284,1285,1286,1287,1288,1289,1290,927,928,929,930,931,932,933,935,1229,934,1230,1238,1231,1232,1233,1234,1237,1235,1236,1239,1240,1348,1352,1349,1353,1350,1354,1351,1355,1395,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1387,1388,1389,1390,1391,1392,1387,1394,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1431,1442,1432,1443,1433,1444,1434,1445,1435,1446,1436,1447,1437,1448,1438,1449,1439,1450,1440,1451,1441,1452,1510,1513,1511,1514,1512,1515,1453,1513,1454,1455,1511,1456,1457,1458,1459,1460,1461,1462,1463,1464,1621,1622,1623,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1647,1647,1648,1650,1651,1652,1471,1507,1617,1472,1473,1496,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1683,1682,1684,1685,1687,1686,1688,1689,1690,1691,1692,1694,1695,1696,1695,1769,1772,1770,1771,1773,1774,1775,1776,1777,1781,1780,1784,1782,1778,1782,1779,1783,1785,1789,1786,1790,1787,1791,1788,1792,1793,1799,1803,1805,1794,1800,1804,1806,1795,1801,1807,1809,1796,1802,1808,1810,1797,1798,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,2703,2704,2708,2709,2710,2711,2712,2713,2714,2715,2716,2722,2717,2718,2724,2719,2725,2720,2725,2721,2727,2728,2729,2730,2731,2732,2733,2734,2735,2736,2737,2737,2738,2740,2741,2742,2743,2744,2745,2746,2748,2749,2750,2751,2752,2753,2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,2770,2773,2776,2777,2778,2779,2779,2780,2782,2783,2784,2785,2786,2787,2788,2927,2928,2789,2929,2930,2790,2931,2932,2791,2933,2934,2792,2935,2936,2793,2937,2938,2938,2794,2939,2940,2795,2941,2942,2796,2797,2797,2798,2799,2800,2801,2802,2803,2804,2805,2806,2807,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,2860,2861,2862,2863,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2972,2976,2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,3038,3042,3046,3039,3043,3047,3040,3044,3048,3045,3049,3050,3051,3052,3053,3054,3067,3055,3068,3056,3069,3057,3058,3071,3059,3072,3060,3073,3061,3074,3062,3075,3063,3076,3064,3077,3065,3078,3066,3079,3090,3091,3080,3081,3082,3083,3084,3085,3087,3086,3089,1919,1920,1921,1922,1923,3088,1924,1926,1927,1928,653,724,654,736,657,656,723,655,735,769,770,967,968,1078,1079,1080,1081,1095,1110,1096,1097,1098,1111,850,853,855,856,857,859,861,862,863,891,893,894,2895,2896,2897,373,374,1908,1909,296,297,762,763,764,765,766,1033,1034,1035,1036,1041,1042,771,772,773,774,775,960,961,964,965,966,1037,1038,1037,1039,1040,1043,1044,969,970,971,972,973,1305,1306,1307,1308,1309,681,682,683,684,685,686,687,688,689,690,691,692,324,325,358,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,713,714,730,731,715,716,732,733,1187,1188,1189,1190,1325,1326,1198,1199,1200,1201,826,827,828,829,830,831,832,833,1091,1107,1092,1108,1093,1109,1094,877,878,888,889,895,896,1256,1257,1258,1259,1014,896,1016,1017,1018,472,474,474,1158,1205,1206,1207,1223,1224,1225,1261,1263,1265,1889,1890,1891,1892,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,574,573,575,576,577,578,580,581,582,583,584,585,586,902,587,588,589,590,591,592,593,594,595,597,598,597,599,600,601,602,603,604,605,606,607,608,610,609,611,612,613,614,615,616,617,617,618,619,620,621,622,623,624,625,626,627,628,628,629,630,631,632,627,628,629,630,632,633,634,635,636,637,638,639,640,943,944,945,947,946,948,949,950,951,1024,1025,1026,1027,1028,1029,1030,1031,1032,980,981,982,983,984,985,986,987,988,1063,1064,1065,1066,1067,1068,1069,1070,1071,1552,1553,1554,1555,1556,1557,1558,1559,1560,1529,1530,1531,1532,1533,1534,1534,1535,1536,1537,1538,1539,1540,914,1050,1051,1052,3000,3001,3002,1228,1053,1054,1592,920,923,924,921,1591,1593,1849,1850,1851,1852,1853,1854,1855,1850,1856,1697,1698,1699,1857,1860,1516,1518,1517,1519,1618,1839,1840,1841,1842,1936,1937,1938,1939,2020,2021,2022,2023,2024,2025,2026,2028,2027,2029,2030,2031,2032,2034,2033,2034,2035,2036,2037,2038,2039,2041,2042,2043,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2864,2865,2867,2867,2868,2869,2870,2871,2871,2871,2871,2871,2872,2872,2872,2872,2872,2872,2872,2873,2874,2875,2876,2877,2878,2879,2880,2881,2882,2882,2882,2882,2882,2883,2883,2883,2883,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,2894,2222,2223,2245,2246,2605,2606,2629,2694,2630,2695,3119,3120,3121,3219,3302,3303,3304,3305,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,4211,4300,2083,2084,2085,2086,2087,2088,2089,2078,2079,2080,2081,2082,2093,2094,2095,2096,2120,2121,2123,2097,2070,2071,2072,2073,2074,2075,2076,2092,2077,2090,2091,2098,2099,2100,2101,2102,2103,2104,2105,2105,2106,2107,2457,2458,2108,2109,2110,2111,2456,2112,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2626,2154,2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2459,2460,2461,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2196,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,2220,2221,2224,2225,2226,2227,2228,2229,2224,2225,2226,2230,2231,2232,2233,2234,2235,2236,2237,2238,3540,3541,3542,3543,2239,2240,2241,2242,2243,2244,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2279,2280,2278,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2334,2333,2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2633,2374,2375,2376,2377,2379,2380,2384,2381,2382,2383,2385,2386,2387,2388,2389,2390,2391,2392,2634,2636,2635,2393,2394,2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,2414,2627,2696,2697,2698,2699,2700,2415,2628,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,2429,2430,2462,4368,2463,4369,2464,4370,2465,4371,2466,2467,4372,2468,4373,2469,4374,2470,4375,2471,4376,2472,4377,2473,4378,2474,4379,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2482,4380,2489,4381,2490,4382,2491,4383,2492,2493,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2531,2514,2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2534,2535,2536,2537,2538,2539,2540,2541,2542,2544,2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2631,2555,2556,2557,2558,2559,2560,2632,2555,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2566,2571,2573,2574,2575,2579,2580,2581,2576,2577,2578,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,2693,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,2624,2625,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2677,2676,2678,2679,2680,2681,2682,2683,2684,2685,2686,2687,2689,2690,2691,2692,3101,3102,3103,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3158,3159,3160,3161,3162,3156,3157,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,3194,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3221,3220,3222,3223,3224,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3279,3280,3281,3276,3282,32843,3277,3284,3278,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,3299,3300,3301,3306,3307,3308,3309,3310,3310,3311,3312,3318,3319,3320,3321,3322,3323,3324,3325,3313,3314,3315,3316,3317,3326,3327,3328,3329,3330,3331,3332,3333,3335,3336,3337,3338,3339,3340,3341,3341,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3360,3361,3354,3355,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3390,3397,3398,3399,3400,3401,3403,3402,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3431,3432,3430,3433,3434,3435,3436,3437,3438,3441,3442,3439,3440,3443,3444,3445,3446,3447,3448,3449,3450,3334,3451,3538,3452,3453,3539,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,3479,3480,3481,3481,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3587,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3715,3716,3717,3718,3719,3720,3722,3721,3723,3724,3725,3726,3727,3728,3729,3730,3730,3731,3732,3733,3734,3735,3736,3737,3738,3740,3733,3741,3742,3743,3744,3745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3756,3757,3758,3759,3760,3761,3762,3763,3764,3762,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3785,3786,3787,3782,3789,3790,3791,3792,4000,4004,4001,4002,4006,4003,4007,2452,2453,4384,4385,4008,4010,4009,4011,2454,2455,4012,4013,4014,4015,4016,4017,4018,4019,4020,4015,4022,4023,4024,4030,4031,4025,4032,4033,4026,2434,2435,4027,2436,2437,4028,2438,2439,4029,4214,2440,4215,2441,4216,2442,4217,2443,4218,2444,2451,4219,2445,4220,2446,4221,4222,2447,4223,2448,4224,2449,4225,2450,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4062,4063,4065,4066,4064,4066,4067,4068,4069,4070,4071,4072,4073,4074,4075,4076,4234,4235,4236,4237,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4087,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,4120,4121,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4162,4163,4163,4163,4163,4164,4165,4166,4167,4168,4170,4171,4169,4172,4173,4174,4175,4176,4177,4178,4179,4180,4182,4181,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4212,4213,4226,4227,4228,4229,4230,4231,4232,4233,2532,2533,4299,4122,3793,3794,3795,3796,3797,3798,3799,4238,4239,4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4256,4257,4258,4255,4264,4259,4260,4261,4060,4061,4262,4263,4265,4266,4267,4268,4269,4270,4271,2247,2248,4272,4273,2433,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,2431,2432,4286,4287,4288,4289,4290,4291,4292,4293,4294,4302,4303,4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4331,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,4364,4365,4366,4367,3092,3093,3094,3095,3096,3097,1276,1588,1590,1599,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3816,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3842,3844,3845,3846,3847,3848,3843,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,3646,3647,3648,3649,3650,3651,3652,3653,3654,3656,3657,3658,3659,41,110,106,107,498,499,129,130,131,128,123,124,125,126,127,134,190,151,152,153,225,226,500,501,229,230,237,238,239,240,241,231,232,283,284,285,279,280,233,281,282,234,235,277,278,245,246,906,414,406,407,408,907,908,909,910,940,941,942,409,410,411,412,413,1756,453,454,455,456,457,1001,1002,1003,1004,1005,668,669,670,671,672,738,1737,1738,1739,1740,1741,1742,719,721,990,992,916,917,925,936,926,937,938,1120,939,1122,1123,1124,1125,1126,1127,1132,1133,1134,1135,1136,1137,1241,1242,1243,1244,1245,1246,1138,1139,1310,1311,1312,1313,1314,1315,1316,1317,1318,1319,1320,1596,1597,1600,1601,1843,1602,1603,1604,1605,1606,1607,1608,1609,1610,1753,1754,1757,1765,1767,1766,1768,1830,1830,1835,1837,1838,1844,1845,1846,1847,1848,1893,1897,1896,1898,1894,1895,1899,1900,1901,1902,3621,3623,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,18,19,20,20,21,48,49,113,114,115,158,159,227,228,242,419,420,767,448,449,242,450,451,452,1292,1010,1009,1271,1272,1760,1761,1887,503,505,504,1273,1274,1291,1291,1758,1886,1013,1012,1269,1270,1293,1762,1763,1888,85,86,87,97,137,138,139,154,155,156,180,181,182,222,223,224,375,376,377,378,1521,1522,1523,1524,1525,1526,1527,1528,394,395,396,997,998,999,1000,1019,1020,1021,1055,1056,1057,1058,1059,1060,1061,1752,1831,1832,1833,1834,15,16,17,50,51,52,53,54,60,148,149,405,132,460,494,133,136,150,236,497,495,496,749,4425,157,164,191,193,198,199,251,393,461,462,463,464,465,466,473,579,596,725,737,854,1011,1015,1084,1102,1393,1586,1615,1649,1693,1700,1759,1764,1836,1858,1925,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,1964,2040,2044,2065,2113,2114,2115,2116,2117,2118,2119,2122,2124,2125,2126,2202,2378,2488,2543,2572,2688,2723,2726,2739,2747,2754,2781,2808,2809,2810,2811,2812,2813,2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,2834,2835,2836,2837,3032,3041,3070,3104,3283,3342,3396,3739,3784,3788,3822,4005,4021,4295,4296,4297,4298,4301 }; - -const std::unordered_set solidObjectIDs = -{ 2064,1329,1275,1587,1589,1598,1614,3601,4401,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4538,4489,4490,4491,4492,4493,4494,4495,4496,4497,4537,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4539,44,1,83,2,3,4,6,7,69,70,71,72,74,75,76,77,78,81,82,90,91,92,93,94,96,95,116,117,118,119,121,122,207,208,209,210,212,213,258,260,255,261,256,263,257,264,265,267,268,269,270,271,271,272,274,275,3034,3035,3036,3037,1903,1904,1905,1910,1911,215,220,219,62,66,65,68,63,64,170,171,172,192,173,194,174,175,176,197,1743,1744,1745,1746,305,307,1747,1748,1749,1750,371,372,1906,1907,294,295,326,327,328,329,349,351,467,468,469,470,471,1338,1339,661,662,663,664,1154,1155,1156,1157,475,1210,1202,1203,1204,1209,1208,1227,1220,1222,1226,1260,1262,1264,146,147,206,204,673,674,1340,1341,1343,1342,1344,1345,8,39,103,392,216,217,218,458,144,205,145,459,177,178,179,1715,1719,1720,1721,135,1711,1712,1713,1714,1717,1718,1716,1723,1724,1722,1725,1726,1727,1728,1729,1730,1731,1732,1733,3610,3611,918,1327,1328,1584,2012,919,1582,1583,1705,1706,1707,1708,1709,1710,1734,1735,1736,186,187,188,740,741,742,678,679,680,1619,1620,1701,1702,1703,183,184,185,8,9,34,40,61,88,89,98,160,161,162,163,165,166,167,168,169,195,196,243,244,247,248,249,250,252,253,254,289,291,299,301,309,311,315,317,321,323,331,333,337,339,343,345,353,355,363,364,365,366,367,368,369,370,397,398,399,421,422,446,447,483,484,492,493,651,652,665,666,667,709,710,711,712,720,726,727,728,729,768,886,887,989,991,1221,1561,1562,1563,1564,1565,1566,1567,1568,1569,3800 }; \ No newline at end of file diff --git a/src/hacks/show_trajectory.hpp b/src/hacks/show_trajectory.hpp index 0c79e31d..d7c154ec 100644 --- a/src/hacks/show_trajectory.hpp +++ b/src/hacks/show_trajectory.hpp @@ -2,7 +2,6 @@ #include "../includes.hpp" #include "../practice_fixes/practice_fixes.hpp" -#include "layout_mode.hpp" const std::unordered_set portalIDs = { 101, 99, 11, 10, 200, 201, 202, 203, 1334 }; const std::unordered_set collectibleIDs = { 1329,1275,1587,1589,1598,1614,3601,4401,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4538,4489,4490,4491,4492,4493,4494,4495,4496,4497,4537,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4539 }; diff --git a/src/main.cpp b/src/main.cpp index dd98d3a2..b0909861 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,6 @@ #include "ui/record_layer.hpp" #include "practice_fixes/practice_fixes.hpp" -#include "hacks/layout_mode.hpp" #include #include From 90fd63bc71fd24d7d27872a28228ca6067363c46 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 22 Feb 2026 07:35:03 +0300 Subject: [PATCH 098/211] make game version in macro dynamically change --- src/global.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/global.cpp b/src/global.cpp index 89c50b7a..83f896ae 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -524,5 +524,5 @@ PauseLayer* Global::getPauseLayer() { g.macro.author = "N/A"; g.macro.description = "N/A"; - g.macro.gameVersion = 2.206; + g.macro.gameVersion = geode::utils::numFromString(geode::Loader::get()->getGameVersion()).unwrapOr(0.0f); }; From aa4c7c9f4cbc24b84803194ea407d746a29e9847 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 22 Feb 2026 18:37:12 +0300 Subject: [PATCH 099/211] numToString changes & other fixes - Fix file picker crashing if layer is clickable due to a bug - Make game version show properly in UI without trailing zeros - Change std::to_string calls to geode::utils::numToString --- mod.json | 2 +- src/gdr/json.hpp | 72 ++++++------- src/global.cpp | 26 ++--- src/macro.cpp | 4 +- src/renderer/renderer.cpp | 14 +-- src/ui/autoclicker_settings_layer.hpp | 8 +- src/ui/clickbot_layer.cpp | 4 +- src/ui/clickbot_layer.hpp | 4 +- src/ui/game_ui.cpp | 4 +- src/ui/load_macro_layer.cpp | 22 ++-- src/ui/load_macro_layer.hpp | 1 + src/ui/macro_editor.cpp | 8 +- src/ui/macro_info_layer.hpp | 140 +++++++++++++------------- src/ui/record_layer.cpp | 8 +- src/ui/render_presets_layer.hpp | 4 +- src/ui/render_settings_layer.cpp | 6 +- src/ui/save_macro_layer.hpp | 2 +- 17 files changed, 170 insertions(+), 159 deletions(-) diff --git a/mod.json b/mod.json index 6464cdd7..a7d8a22a 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "5.0.0-beta.3", + "geode": "5.0.0-beta.4", "gd": { "win": "2.2081", "mac": "2.2081", diff --git a/src/gdr/json.hpp b/src/gdr/json.hpp index 8b72ea65..9e0d267a 100644 --- a/src/gdr/json.hpp +++ b/src/gdr/json.hpp @@ -4386,7 +4386,7 @@ class exception : public std::exception static std::string name(const std::string& ename, int id_) { - return concat("[json.exception.", ename, '.', std::to_string(id_), "] "); + return concat("[json.exception.", ename, '.', geode::utils::numToString(id_), "] "); } static std::string diagnostics(std::nullptr_t /*leaf_element*/) @@ -4409,7 +4409,7 @@ class exception : public std::exception { if (¤t->m_parent->m_data.m_value.array->operator[](i) == current) { - tokens.emplace_back(std::to_string(i)); + tokens.emplace_back(geode::utils::numToString(i)); break; } } @@ -4490,7 +4490,7 @@ class parse_error : public exception static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context) { const std::string w = concat(exception::name("parse_error", id_), "parse error", - (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""), + (byte_ != 0 ? (concat(" at byte ", geode::utils::numToString(byte_))) : ""), ": ", exception::diagnostics(context), what_arg); return {id_, byte_, w.c_str()}; } @@ -4512,8 +4512,8 @@ class parse_error : public exception static std::string position_string(const position_t& pos) { - return concat(" at line ", std::to_string(pos.lines_read + 1), - ", column ", std::to_string(pos.chars_read_current_line)); + return concat(" at line ", geode::utils::numToString(pos.lines_read + 1), + ", column ", geode::utils::numToString(pos.chars_read_current_line)); } }; @@ -5179,7 +5179,7 @@ template void int_to_string( string_type& target, std::size_t value ) { // For ADL - using std::to_string; + using geode::utils::numToString; target = to_string(value); } template class iteration_proxy_value @@ -6869,7 +6869,7 @@ class json_sax_dom_parser if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + JSON_THROW(out_of_range::create(408, concat("excessive object size: ", geode::utils::numToString(len)), ref_stack.back())); } return true; @@ -6901,7 +6901,7 @@ class json_sax_dom_parser if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + JSON_THROW(out_of_range::create(408, concat("excessive array size: ", geode::utils::numToString(len)), ref_stack.back())); } return true; @@ -7059,7 +7059,7 @@ class json_sax_dom_callback_parser // check object limit if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + JSON_THROW(out_of_range::create(408, concat("excessive object size: ", geode::utils::numToString(len)), ref_stack.back())); } return true; @@ -7129,7 +7129,7 @@ class json_sax_dom_callback_parser // check array limit if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + JSON_THROW(out_of_range::create(408, concat("excessive array size: ", geode::utils::numToString(len)), ref_stack.back())); } return true; @@ -9370,7 +9370,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr)); + exception_message(input_format_t::bson, concat("string length must be at least 1, is ", geode::utils::numToString(len)), "string"), nullptr)); } return get_string(input_format_t::bson, len - static_cast(1), result) && get() != char_traits::eof(); @@ -9392,7 +9392,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr)); + exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", geode::utils::numToString(len)), "binary"), nullptr)); } // All BSON binary values have a subtype @@ -13920,7 +13920,7 @@ class json_pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ json_pointer& operator/=(std::size_t array_idx) { - return *this /= std::to_string(array_idx); + return *this /= geode::utils::numToString(array_idx); } /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer @@ -14243,7 +14243,7 @@ class json_pointer { // "-" always fails the range check JSON_THROW(detail::out_of_range::create(402, detail::concat( - "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), + "array index '-' (", geode::utils::numToString(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); } @@ -14300,7 +14300,7 @@ class json_pointer if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" cannot be used for const access - JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); + JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", geode::utils::numToString(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); } // use unchecked array access @@ -14350,7 +14350,7 @@ class json_pointer { // "-" always fails the range check JSON_THROW(detail::out_of_range::create(402, detail::concat( - "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), + "array index '-' (", geode::utils::numToString(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); } @@ -14555,7 +14555,7 @@ class json_pointer // iterate array and use index as reference string for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i) { - flatten(detail::concat(reference_string, '/', std::to_string(i)), + flatten(detail::concat(reference_string, '/', geode::utils::numToString(i)), value.m_data.m_value.array->operator[](i), result); } } @@ -16001,7 +16001,7 @@ class binary_writer const auto it = name.find(static_cast(0)); if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) { - JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j)); + JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", geode::utils::numToString(it), ")"), &j)); static_cast(j); } @@ -16126,7 +16126,7 @@ class binary_writer } else { - JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j)); + JSON_THROW(out_of_range::create(407, concat("integer number ", geode::utils::numToString(j.m_data.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j)); } } @@ -16149,7 +16149,7 @@ class binary_writer const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) { - return result + calc_bson_element_size(std::to_string(array_index++), el); + return result + calc_bson_element_size(geode::utils::numToString(array_index++), el); }); return sizeof(std::int32_t) + embedded_document_size + 1ul; @@ -16176,7 +16176,7 @@ class binary_writer for (const auto& el : value) { - write_bson_element(std::to_string(array_index++), el); + write_bson_element(geode::utils::numToString(array_index++), el); } oa->write_character(to_char_type(0x00)); @@ -18518,7 +18518,7 @@ class serializer { case error_handler_t::strict: { - JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", hex_bytes(byte | 0)), nullptr)); + JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", geode::utils::numToString(i), ": 0x", hex_bytes(byte | 0)), nullptr)); } case error_handler_t::ignore: @@ -19555,9 +19555,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec result["name"] = "JSON for Modern C++"; result["url"] = "https://github.com/nlohmann/json"; result["version"]["string"] = - detail::concat(std::to_string(NLOHMANN_JSON_VERSION_MAJOR), '.', - std::to_string(NLOHMANN_JSON_VERSION_MINOR), '.', - std::to_string(NLOHMANN_JSON_VERSION_PATCH)); + detail::concat(geode::utils::numToString(NLOHMANN_JSON_VERSION_MAJOR), '.', + geode::utils::numToString(NLOHMANN_JSON_VERSION_MINOR), '.', + geode::utils::numToString(NLOHMANN_JSON_VERSION_PATCH)); result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; @@ -19580,9 +19580,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; #elif defined(__GNUC__) || defined(__GNUG__) result["compiler"] = {{"family", "gcc"}, {"version", detail::concat( - std::to_string(__GNUC__), '.', - std::to_string(__GNUC_MINOR__), '.', - std::to_string(__GNUC_PATCHLEVEL__)) + geode::utils::numToString(__GNUC__), '.', + geode::utils::numToString(__GNUC_MINOR__), '.', + geode::utils::numToString(__GNUC_PATCHLEVEL__)) } }; #elif defined(__HP_cc) || defined(__HP_aCC) @@ -19600,9 +19600,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #endif #if defined(_MSVC_LANG) - result["compiler"]["c++"] = std::to_string(_MSVC_LANG); + result["compiler"]["c++"] = geode::utils::numToString(_MSVC_LANG); #elif defined(__cplusplus) - result["compiler"]["c++"] = std::to_string(__cplusplus); + result["compiler"]["c++"] = geode::utils::numToString(__cplusplus); #else result["compiler"]["c++"] = "unknown"; #endif @@ -21249,7 +21249,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); + JSON_THROW(out_of_range::create(401, detail::concat("array index ", geode::utils::numToString(idx), " is out of range"), this)); } } else @@ -21272,7 +21272,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); + JSON_THROW(out_of_range::create(401, detail::concat("array index ", geode::utils::numToString(idx), " is out of range"), this)); } } else @@ -21928,7 +21928,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { if (JSON_HEDLEY_UNLIKELY(idx >= size())) { - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); + JSON_THROW(out_of_range::create(401, detail::concat("array index ", geode::utils::numToString(idx), " is out of range"), this)); } m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast(idx)); @@ -24080,7 +24080,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) { // avoid undefined behavior - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent)); + JSON_THROW(out_of_range::create(401, detail::concat("array index ", geode::utils::numToString(idx), " is out of range"), &parent)); } // default case: insert add offset @@ -24310,7 +24310,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec while (i < source.size() && i < target.size()) { // recursive call to compare array values at index i - auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', std::to_string(i))); + auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', geode::utils::numToString(i))); result.insert(result.end(), temp_diff.begin(), temp_diff.end()); ++i; } @@ -24327,7 +24327,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec result.insert(result.begin() + end_index, object( { {"op", "remove"}, - {"path", detail::concat(path, '/', std::to_string(i))} + {"path", detail::concat(path, '/', geode::utils::numToString(i))} })); ++i; } diff --git a/src/global.cpp b/src/global.cpp index 83f896ae..c8594fbd 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -391,8 +391,8 @@ PauseLayer* Global::getPauseLayer() { auto & g = Global::get(); if (!g.mod->setSavedValue("defaults_set_14", true)) { - g.mod->setSavedValue("render_fade_in_video", std::to_string(2)); - g.mod->setSavedValue("render_fade_out_video", std::to_string(2)); + g.mod->setSavedValue("render_fade_in_video", geode::utils::numToString(2)); + g.mod->setSavedValue("render_fade_out_video", geode::utils::numToString(2)); } if (!g.mod->setSavedValue("defaults_set_12", true)) { @@ -414,12 +414,12 @@ PauseLayer* Global::getPauseLayer() { g.mod->setSettingValue("restore_page", true); g.mod->setSavedValue("autosave_interval_enabled", false); - g.mod->setSavedValue("autosave_interval", std::to_string(10)); + g.mod->setSavedValue("autosave_interval", geode::utils::numToString(10)); g.mod->setSavedValue("autosave_checkpoint_enabled", true); g.mod->setSavedValue("autosave_levelend_enabled", true); - g.mod->setSavedValue("render_fade_in_video", std::to_string(2)); - g.mod->setSavedValue("render_fade_out_video", std::to_string(2)); + g.mod->setSavedValue("render_fade_in_video", geode::utils::numToString(2)); + g.mod->setSavedValue("render_fade_out_video", geode::utils::numToString(2)); g.mod->setSavedValue("macro_auto_stop_playing", false); g.mod->setSavedValue("macro_tps", 240.f); @@ -434,7 +434,7 @@ PauseLayer* Global::getPauseLayer() { g.mod->setSavedValue("trajectory_color1", ccc3(74, 226, 85)); g.mod->setSavedValue("trajectory_color2", ccc3(130, 8, 8)); - g.mod->setSavedValue("trajectory_length", std::to_string(240)); + g.mod->setSavedValue("trajectory_length", geode::utils::numToString(240)); } @@ -444,16 +444,16 @@ PauseLayer* Global::getPauseLayer() { g.mod->setSavedValue("render_sfx_volume", 1.f); g.mod->setSavedValue("render_music_volume", 1.f); g.mod->setSavedValue("respawn_time", 0.5f); - g.mod->setSavedValue("render_seconds_after", std::to_string(2)); + g.mod->setSavedValue("render_seconds_after", geode::utils::numToString(2)); g.mod->setSavedValue("render_record_audio", true); g.mod->setSavedValue("render_args", std::string("-pix_fmt yuv420p")); g.mod->setSavedValue("macro_noclip_p1", true); g.mod->setSavedValue("macro_noclip_p2", true); - g.mod->setSavedValue("render_width2", std::to_string(1920)); - g.mod->setSavedValue("render_height", std::to_string(1080)); - g.mod->setSavedValue("render_bitrate", std::to_string(12)); - g.mod->setSavedValue("render_fps", std::to_string(60)); + g.mod->setSavedValue("render_width2", geode::utils::numToString(1920)); + g.mod->setSavedValue("render_height", geode::utils::numToString(1080)); + g.mod->setSavedValue("render_bitrate", geode::utils::numToString(12)); + g.mod->setSavedValue("render_fps", geode::utils::numToString(60)); g.mod->setSavedValue("render_video_args", std::string("colorspace=all=bt709:iall=bt470bg:fast=1")); g.mod->setSavedValue("render_codec", std::string("libx264")); @@ -464,7 +464,7 @@ PauseLayer* Global::getPauseLayer() { g.mod->setSavedValue("render_record_audio", true); g.mod->setSavedValue("render_hide_labels", true); - g.mod->setSavedValue("macro_seed", std::to_string(1)); + g.mod->setSavedValue("macro_seed", geode::utils::numToString(1)); g.mod->setSavedValue("macro_speedhack", std::string("0.5")); g.mod->setSavedValue("macro_fps", 3); @@ -524,5 +524,5 @@ PauseLayer* Global::getPauseLayer() { g.macro.author = "N/A"; g.macro.description = "N/A"; - g.macro.gameVersion = geode::utils::numFromString(geode::Loader::get()->getGameVersion()).unwrapOr(0.0f); + g.macro.gameVersion = GEODE_GD_VERSION; }; diff --git a/src/macro.cpp b/src/macro.cpp index dc99850b..422bbfd8 100644 --- a/src/macro.cpp +++ b/src/macro.cpp @@ -160,11 +160,11 @@ int Macro::save(std::string author, std::string desc, std::string path, bool jso iterations++; if (iterations > 1) { - int length = 3 + std::to_string(iterations - 1).length(); + int length = 3 + geode::utils::numToString(iterations - 1).length(); path.erase(path.length() - length, length); } - path += fmt::format(" ({})", std::to_string(iterations)); + path += fmt::format(" ({})", geode::utils::numToString(iterations)); } path += extension; diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 266623da..b1382c52 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -262,7 +262,7 @@ void Renderer::start() { auto duration = now.time_since_epoch(); auto timestamp = std::chrono::duration_cast(duration).count(); - std::string filename = fmt::format("render_{}_{}{}", std::string_view(pl->m_level->m_levelName), std::to_string(timestamp), extension); + std::string filename = fmt::format("render_{}_{}{}", std::string_view(pl->m_level->m_levelName), geode::utils::numToString(timestamp), extension); #ifdef GEODE_IS_IOS std::string path = geode::utils::string::pathToString(Mod::get()->getSaveDir() / "renders" / filename); #else @@ -368,9 +368,9 @@ void Renderer::start() { command = fmt::format( "\"{}\" -y -f rawvideo -pix_fmt rgb24 -s {}x{} -r {} -i - {}{}{} -vf \"vflip,{}{}\" -an \"{}\" ", ffmpegPath, - std::to_string(width), - std::to_string(height), - std::to_string(fps), + geode::utils::numToString(width), + geode::utils::numToString(height), + geode::utils::numToString(fps), codec, bitrate, extraArgs, @@ -479,7 +479,7 @@ void Renderer::start() { float fadeOutStart = totalTime - fadeOutTime; if (fadeOutVideo) { - command = fmt::format("\"{}\" -i \"{}\" -vf \"fade=t=out:st={}:d={}\" {}{}-c:a copy \"{}\"", ffmpegPath, path, fadeOutStart, std::to_string(fadeOutTime), codec, bitrate, path + "_temp" + extension); + command = fmt::format("\"{}\" -i \"{}\" -vf \"fade=t=out:st={}:d={}\" {}{}-c:a copy \"{}\"", ffmpegPath, path, fadeOutStart, geode::utils::numToString(fadeOutTime), codec, bitrate, path + "_temp" + extension); log::info("Executing (Fade Out): {}", command); process = subprocess::Popen(command); @@ -513,13 +513,13 @@ void Renderer::start() { std::string fadeInString; if ((fadeIn && audioMode == AudioMode::Song) || fadeInVideo) - fadeInString = fmt::format(", afade=t=in:d={}", fadeInVideo ? std::to_string(fadeInTime) : "2"); + fadeInString = fmt::format(", afade=t=in:d={}", fadeInVideo ? geode::utils::numToString(fadeInTime) : "2"); std::string fadeOutString; if ((fadeOut && audioMode == AudioMode::Song) || fadeOutVideo) fadeOutString = fmt::format( ", afade=t=out:d={}:st={}", - fadeOutVideo ? std::to_string(fadeOutTime) : "2", + fadeOutVideo ? geode::utils::numToString(fadeOutTime) : "2", fadeOutVideo ? fadeOutStart : totalTime - timeAfter - 3.5f ); diff --git a/src/ui/autoclicker_settings_layer.hpp b/src/ui/autoclicker_settings_layer.hpp index a246ed3d..1aab8890 100644 --- a/src/ui/autoclicker_settings_layer.hpp +++ b/src/ui/autoclicker_settings_layer.hpp @@ -82,7 +82,7 @@ class AutoclickerLayer : public geode::Popup, public TextInputDelegate { holdInput = TextInput::create(50, "Frames", "chatFont.fnt"); holdInput->setPosition({72, 150}); - holdInput->setString(std::to_string(Mod::get()->getSavedValue("autoclicker_hold_for")).c_str()); + holdInput->setString(geode::utils::numToString(Mod::get()->getSavedValue("autoclicker_hold_for")).c_str()); holdInput->getInputNode()->setDelegate(this); holdInput->getInputNode()->setAllowedChars("0123456789"); holdInput->getInputNode()->setMaxLabelLength(4); @@ -90,7 +90,7 @@ class AutoclickerLayer : public geode::Popup, public TextInputDelegate { releaseInput = TextInput::create(50, "Frames", "chatFont.fnt"); releaseInput->setPosition({x, 150}); - releaseInput->setString(std::to_string(Mod::get()->getSavedValue("autoclicker_release_for")).c_str()); + releaseInput->setString(geode::utils::numToString(Mod::get()->getSavedValue("autoclicker_release_for")).c_str()); releaseInput->getInputNode()->setDelegate(this); releaseInput->getInputNode()->setAllowedChars("0123456789"); releaseInput->getInputNode()->setMaxLabelLength(4); @@ -127,7 +127,7 @@ class AutoclickerLayer : public geode::Popup, public TextInputDelegate { holdInput2 = TextInput::create(50, "Frames", "chatFont.fnt"); holdInput2->setPosition({72, 70}); - holdInput2->setString(std::to_string(Mod::get()->getSavedValue("autoclicker_hold_for2")).c_str()); + holdInput2->setString(geode::utils::numToString(Mod::get()->getSavedValue("autoclicker_hold_for2")).c_str()); holdInput2->getInputNode()->setDelegate(this); holdInput2->getInputNode()->setAllowedChars("0123456789"); holdInput2->getInputNode()->setMaxLabelLength(4); @@ -135,7 +135,7 @@ class AutoclickerLayer : public geode::Popup, public TextInputDelegate { releaseInput2 = TextInput::create(50, "Frames", "chatFont.fnt"); releaseInput2->setPosition({x, 70}); - releaseInput2->setString(std::to_string(Mod::get()->getSavedValue("autoclicker_release_for2")).c_str()); + releaseInput2->setString(geode::utils::numToString(Mod::get()->getSavedValue("autoclicker_release_for2")).c_str()); releaseInput2->getInputNode()->setDelegate(this); releaseInput2->getInputNode()->setAllowedChars("0123456789"); releaseInput2->getInputNode()->setMaxLabelLength(4); diff --git a/src/ui/clickbot_layer.cpp b/src/ui/clickbot_layer.cpp index a5f9edb7..2156de92 100644 --- a/src/ui/clickbot_layer.cpp +++ b/src/ui/clickbot_layer.cpp @@ -226,7 +226,7 @@ bool ClickbotLayer::init() { volumeSlider->setValue(volume / 300.f); menu->addChild(volumeSlider); - volumeLabel = CCLabelBMFont::create(("Master Volume (" + std::to_string(volume) + "%)").c_str(), "goldFont.fnt"); + volumeLabel = CCLabelBMFont::create(("Master Volume (" + geode::utils::numToString(volume) + "%)").c_str(), "goldFont.fnt"); volumeLabel->setPosition(ccp(128, 35)); volumeLabel->setScale(0.35f); menu->addChild(volumeLabel); @@ -350,7 +350,7 @@ bool ClickSettingsLayer::init(std::string button, geode::Popup* layer) { volumeSlider->setValue(settings.volume / 300.f); menu->addChild(volumeSlider); - volumeLabel = CCLabelBMFont::create(("Volume (" + std::to_string(settings.volume) + "%)").c_str(), "goldFont.fnt"); + volumeLabel = CCLabelBMFont::create(("Volume (" + geode::utils::numToString(settings.volume) + "%)").c_str(), "goldFont.fnt"); volumeLabel->setPosition(ccp(-42, -9)); volumeLabel->setScale(0.45f); menu->addChild(volumeLabel); diff --git a/src/ui/clickbot_layer.hpp b/src/ui/clickbot_layer.hpp index 5cd91369..3a29bb5b 100644 --- a/src/ui/clickbot_layer.hpp +++ b/src/ui/clickbot_layer.hpp @@ -52,7 +52,7 @@ class ClickSettingsLayer : public geode::Popup { void updateVolume(CCObject*) { settings.volume = static_cast(volumeSlider->getThumb()->getValue() * 300.f); - volumeLabel->setString(("Volume (" + std::to_string(settings.volume) + "%)").c_str()); + volumeLabel->setString(("Volume (" + geode::utils::numToString(settings.volume) + "%)").c_str()); saveSettings(); } @@ -108,7 +108,7 @@ class ClickbotLayer : public geode::Popup { void updateVolume(CCObject*) { int volume = static_cast(volumeSlider->getThumb()->getValue() * 300.f); - volumeLabel->setString(("Master Volume (" + std::to_string(volume) + "%)").c_str()); + volumeLabel->setString(("Master Volume (" + geode::utils::numToString(volume) + "%)").c_str()); Mod::get()->setSavedValue("clickbot_volume", volume); } diff --git a/src/ui/game_ui.cpp b/src/ui/game_ui.cpp index a543ce92..011e22cf 100644 --- a/src/ui/game_ui.cpp +++ b/src/ui/game_ui.cpp @@ -15,11 +15,11 @@ class $modify(PlayLayer) { #ifdef GEODE_IS_WINDOWS if (g.state != state::none && g.frameLabel && !g.renderer.recording) { - m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); + m_fields->frameLabel->setString(("Frame: " + geode::utils::numToString(Global::getCurrentFrame())).c_str()); } #else if (g.state != state::none && g.frameLabel) { - m_fields->frameLabel->setString(("Frame: " + std::to_string(Global::getCurrentFrame())).c_str()); + m_fields->frameLabel->setString(("Frame: " + geode::utils::numToString(Global::getCurrentFrame())).c_str()); } #endif } diff --git a/src/ui/load_macro_layer.cpp b/src/ui/load_macro_layer.cpp index ffd4cce2..ce56d0e2 100644 --- a/src/ui/load_macro_layer.cpp +++ b/src/ui/load_macro_layer.cpp @@ -108,7 +108,7 @@ void LoadMacroLayer::deleteSelected(CCObject*) { geode::createQuickPopup( "Warning", - "Are you sure you want to delete " + std::to_string(amount) + " " + (isAutosaves ? "autosave" : "macro") + "(s)?", + "Are you sure you want to delete " + geode::utils::numToString(amount) + " " + (isAutosaves ? "autosave" : "macro") + "(s)?", "Cancel", "Yes", [this, amount](auto, bool btn2) { if (btn2) { @@ -147,12 +147,21 @@ LoadMacroLayer* LoadMacroLayer::create(geode::Popup* layer, geode::Popup* layer2 } void LoadMacroLayer::onImportMacro(CCObject*) { + if (isPickingFile) return; file::FilePickOptions fileOptions; fileOptions.filters.push_back({"Macro Files", { "*.gdr", "*.xd", "*.json" }}); + auto weakThis = geode::WeakRef(this); + isPickingFile = true; - m_importTask.spawn(file::pick(file::PickMode::OpenFile, fileOptions), [this](auto res) { - if (!res.isOk()) return; + m_importTask.spawn(file::pick(file::PickMode::OpenFile, fileOptions), [weakThis](auto res) { + + auto self = weakThis.lock(); + if (!self) return; + + self->isPickingFile = false; + if (!res.isOk()) return; + auto pathOpt = res.unwrap(); if (!pathOpt) return; @@ -186,12 +195,13 @@ void LoadMacroLayer::onImportMacro(CCObject*) { } if (geode::utils::file::writeBinary(finalPath, tempMacro.exportData(true))) { - this->reloadList(0); + self->reloadList(0); if (path.extension() == ".xd") { FLAlertLayer::create("Warning", "Legacy .xd macros may be unstable.", "OK")->show(); } Notification::create("Macro Imported", NotificationIcon::Success)->show(); + self->isPickingFile = false; } }); } @@ -426,7 +436,7 @@ void LoadMacroLayer::addList(bool refresh, float prevScroll) { cells->addObject(cell); } - macroCountLbl->setString(fmt::format("{} Macros", std::to_string(cells->count())).c_str()); + macroCountLbl->setString(fmt::format("{} Macros", geode::utils::numToString(cells->count())).c_str()); if (cells->count() == 0) { CCLabelBMFont* lbl = CCLabelBMFont::create(isAutosaves ? "No Autosaves" : "No Macros", "bigFont.fnt"); @@ -746,7 +756,7 @@ void MacroCell::onLoad(CCObject*) { geode::createQuickPopup( "Warning", - "Replace the current " + std::to_string(Global::get().macro.inputs.size()) + " macro actions?", + "Replace the current " + geode::utils::numToString(Global::get().macro.inputs.size()) + " macro actions?", "Cancel", "Yes", [this](auto, bool btn2) { if (btn2) { diff --git a/src/ui/load_macro_layer.hpp b/src/ui/load_macro_layer.hpp index b13f9343..b90a77b7 100644 --- a/src/ui/load_macro_layer.hpp +++ b/src/ui/load_macro_layer.hpp @@ -66,6 +66,7 @@ class LoadMacroLayer : public geode::Popup, TextInputDelegate { bool isAutosaves = false; bool isMerge = false; bool invertSort = false; + bool isPickingFile = false; async::TaskHolder>> m_importTask; diff --git a/src/ui/macro_editor.cpp b/src/ui/macro_editor.cpp index d11e6b80..c735876b 100644 --- a/src/ui/macro_editor.cpp +++ b/src/ui/macro_editor.cpp @@ -395,7 +395,7 @@ bool MacroEditLayer::init() { void MacroEditLayer::loadPage(int page) { currentPage = page; - pageInput->setString(std::to_string(currentPage).c_str()); + pageInput->setString(geode::utils::numToString(currentPage).c_str()); if (pageMenu) pageMenu->removeFromParentAndCleanup(true); @@ -510,8 +510,8 @@ void MacroEditLayer::loadPage(int page) { InputText MacroEditLayer::getInputText(input input) { InputText ret = { - std::to_string(input.frame), - btnNames.contains(input.button) ? btnNames.at(input.button) : std::to_string(input.button), + geode::utils::numToString(input.frame), + btnNames.contains(input.button) ? btnNames.at(input.button) : geode::utils::numToString(input.button), input.player2 ? "Two" : "One", input.down ? "Hold" : "Release" }; @@ -931,7 +931,7 @@ void MacroEditLayer::onClear(CCObject*) { geode::createQuickPopup( "Clear", - "Clear " + std::to_string(inputs.size()) + " macro actions?", + "Clear " + geode::utils::numToString(inputs.size()) + " macro actions?", "Cancel", "Yes", [this](auto, bool btn2) { if (btn2) { diff --git a/src/ui/macro_info_layer.hpp b/src/ui/macro_info_layer.hpp index 40087bf0..2e8da7b8 100644 --- a/src/ui/macro_info_layer.hpp +++ b/src/ui/macro_info_layer.hpp @@ -3,9 +3,9 @@ #include class MacroInfoLayer : public geode::Popup { - -public: - + + public: + static MacroInfoLayer* create() { MacroInfoLayer* ret = new MacroInfoLayer(); if (ret->init()) { @@ -15,19 +15,19 @@ class MacroInfoLayer : public geode::Popup { delete ret; return nullptr; } - -private: - + + private: + bool init() { if (!Popup::init(417, 268, "square01_001.png", CCRectZero)) return false; setTitle("Current Macro"); auto& g = Global::get(); - + int playerInputs[2][3][2] = { { { 0, 0 }, { 0, 0 }, { 0, 0 } }, { { 0, 0 }, { 0, 0 }, { 0, 0 } } }; - + for (const auto& input : g.macro.inputs) - playerInputs[input.player2][input.button - 1][input.down]++; - + playerInputs[input.player2][input.button - 1][input.down]++; + CCScale9Sprite* bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); bg->setColor({ 0,0,0 }); bg->setOpacity(75); @@ -35,7 +35,7 @@ class MacroInfoLayer : public geode::Popup { bg->setAnchorPoint({ 0, 1 }); bg->setContentSize({ 162, 202 }); m_mainLayer->addChild(bg); - + bg = CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 }); bg->setColor({ 0,0,0 }); bg->setOpacity(75); @@ -43,96 +43,96 @@ class MacroInfoLayer : public geode::Popup { bg->setAnchorPoint({ 0, 1 }); bg->setContentSize({ 162, 202 }); m_mainLayer->addChild(bg); - + CCLabelBMFont* lbl = CCLabelBMFont::create("General Info", "goldFont.fnt"); lbl->setScale(0.55f); lbl->setPosition({ 108, 211 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Inputs Info", "goldFont.fnt"); lbl->setScale(0.55f); lbl->setPosition({ 308, 211 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create(g.macro.author.c_str(), "chatFont.fnt"); lbl->setScale(0.7f); lbl->setPosition({ 108, 184 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("____________________________", "chatFont.fnt"); lbl->setScale(0.55f); lbl->setPosition({ 108, 177 }); lbl->setOpacity(136); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Author", "chatFont.fnt"); lbl->setScale(0.5f); lbl->setPosition({ 108, 166 }); lbl->setOpacity(137); m_mainLayer->addChild(lbl); - + MDTextArea* desc = MDTextArea::create((g.macro.description == "" ? "N/A" : g.macro.description).c_str(), { 140, 30 }); desc->setPosition({ 108, 141 }); m_mainLayer->addChild(desc); - + lbl = CCLabelBMFont::create("Description", "chatFont.fnt"); lbl->setScale(0.5f); lbl->setPosition({ 108, 118 }); lbl->setOpacity(137); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Framerate:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.475f); lbl->setPosition({ 36, 100 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Duration:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.475f); lbl->setPosition({ 36, 89 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Game version:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.475f); lbl->setPosition({ 36, 78 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Seed:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.475f); lbl->setPosition({ 36, 67 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Used LDM:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.475f); lbl->setPosition({ 36, 56 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Level:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.475f); lbl->setPosition({ 36, 45 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Bot:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.475f); lbl->setPosition({ 36, 34 }); m_mainLayer->addChild(lbl); - - lbl = CCLabelBMFont::create(std::to_string(g.macro.framerate).c_str(), "chatFont.fnt"); + + lbl = CCLabelBMFont::create(geode::utils::numToString(g.macro.framerate).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->limitLabelWidth(221.f, 0.475, 0.01f); lbl->updateLabel(); lbl->setPosition({ 76, 100 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - - std::string duration = g.macro.inputs.empty() ? std::string("0s") : (std::to_string(g.macro.inputs.back().frame / g.macro.framerate) + "s"); - + + std::string duration = g.macro.inputs.empty() ? std::string("0s") : (geode::utils::numToString(g.macro.inputs.back().frame / g.macro.framerate) + "s"); + lbl = CCLabelBMFont::create(duration.c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->limitLabelWidth(231.f, 0.475, 0.01f); @@ -140,9 +140,9 @@ class MacroInfoLayer : public geode::Popup { lbl->setPosition({ 70.6, 89 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - - std::string version = g.macro.gameVersion != 0 ? std::to_string(g.macro.gameVersion) : std::string("N/A"); - + + std::string version = g.macro.gameVersion != 0 ? fmt::format("{:g}", static_cast(g.macro.gameVersion)) : "N/A"; + lbl = CCLabelBMFont::create(version.c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->limitLabelWidth(198.f, 0.475, 0.01f); @@ -150,9 +150,9 @@ class MacroInfoLayer : public geode::Popup { lbl->setPosition({ 88, 78 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - - std::string seed = g.macro.seed != 0 ? std::to_string(g.macro.seed) : std::string("N/A"); - + + std::string seed = g.macro.seed != 0 ? geode::utils::numToString(g.macro.seed) : std::string("N/A"); + lbl = CCLabelBMFont::create(seed.c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->limitLabelWidth(257.f, 0.475, 0.01f); @@ -160,17 +160,17 @@ class MacroInfoLayer : public geode::Popup { lbl->setPosition({ 58, 67 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create(g.macro.ldm ? "true" : "false", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.475f); lbl->setPosition({ 75.5, 56 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - + std::string levelName = g.macro.levelInfo.name != "" ? g.macro.levelInfo.name : "N/A"; - std::string levelID = g.macro.levelInfo.id != 0 ? std::to_string(g.macro.levelInfo.id) : ""; - + std::string levelID = g.macro.levelInfo.id != 0 ? geode::utils::numToString(g.macro.levelInfo.id) : ""; + lbl = CCLabelBMFont::create(fmt::format("{} ({})", levelName, levelID).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->limitLabelWidth(257.f, 0.475, 0.01f); @@ -178,7 +178,7 @@ class MacroInfoLayer : public geode::Popup { lbl->setPosition({ 59.3, 45 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create((g.macro.botInfo.name + " " + g.macro.botInfo.version).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->limitLabelWidth(271.f, 0.475, 0.01f); @@ -186,135 +186,135 @@ class MacroInfoLayer : public geode::Popup { lbl->setPosition({ 52.3, 34 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Total actions:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 233, 189 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("____________________________", "chatFont.fnt"); lbl->setScale(0.55f); lbl->setPosition({ 308, 177 }); lbl->setOpacity(136); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("P1 Holds / Releases", "chatFont.fnt"); lbl->setAnchorPoint({ 0.5, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 308, 163 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("____________________________", "chatFont.fnt"); lbl->setScale(0.55f); lbl->setPosition({ 308, 156 }); lbl->setOpacity(136); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Click:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 233, 138 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Left:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 233, 125 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Right:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 233, 112 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("____________________________", "chatFont.fnt"); lbl->setScale(0.55f); lbl->setPosition({ 308, 101 }); lbl->setOpacity(136); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("P2 Holds / Releases", "chatFont.fnt"); lbl->setAnchorPoint({ 0.5, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 308, 87 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("____________________________", "chatFont.fnt"); lbl->setScale(0.55f); lbl->setPosition({ 308, 80 }); lbl->setOpacity(136); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Click:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 233, 62 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Left:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 233, 49 }); m_mainLayer->addChild(lbl); - + lbl = CCLabelBMFont::create("Right:", "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 233, 36 }); m_mainLayer->addChild(lbl); - - lbl = CCLabelBMFont::create(std::to_string(g.macro.inputs.size()).c_str(), "chatFont.fnt"); + + lbl = CCLabelBMFont::create(geode::utils::numToString(g.macro.inputs.size()).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 286, 189 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - - lbl = CCLabelBMFont::create((std::to_string(playerInputs[0][0][0]) + " / " + std::to_string(playerInputs[0][0][1])).c_str(), "chatFont.fnt"); + + lbl = CCLabelBMFont::create((geode::utils::numToString(playerInputs[0][0][0]) + " / " + geode::utils::numToString(playerInputs[0][0][1])).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 258.5, 138 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - - lbl = CCLabelBMFont::create((std::to_string(playerInputs[0][1][0]) + " / " + std::to_string(playerInputs[0][1][1])).c_str(), "chatFont.fnt"); + + lbl = CCLabelBMFont::create((geode::utils::numToString(playerInputs[0][1][0]) + " / " + geode::utils::numToString(playerInputs[0][1][1])).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 256, 125 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - - lbl = CCLabelBMFont::create((std::to_string(playerInputs[0][2][0]) + " / " + std::to_string(playerInputs[0][2][1])).c_str(), "chatFont.fnt"); + + lbl = CCLabelBMFont::create((geode::utils::numToString(playerInputs[0][2][0]) + " / " + geode::utils::numToString(playerInputs[0][2][1])).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 260, 112 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - - lbl = CCLabelBMFont::create((std::to_string(playerInputs[1][0][0]) + " / " + std::to_string(playerInputs[1][0][1])).c_str(), "chatFont.fnt"); + + lbl = CCLabelBMFont::create((geode::utils::numToString(playerInputs[1][0][0]) + " / " + geode::utils::numToString(playerInputs[1][0][1])).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 258.5, 62 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - - lbl = CCLabelBMFont::create((std::to_string(playerInputs[1][1][0]) + " / " + std::to_string(playerInputs[1][1][1])).c_str(), "chatFont.fnt"); + + lbl = CCLabelBMFont::create((geode::utils::numToString(playerInputs[1][1][0]) + " / " + geode::utils::numToString(playerInputs[1][1][1])).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 256, 49 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - - lbl = CCLabelBMFont::create((std::to_string(playerInputs[1][2][0]) + " / " + std::to_string(playerInputs[1][2][1])).c_str(), "chatFont.fnt"); + + lbl = CCLabelBMFont::create((geode::utils::numToString(playerInputs[1][2][0]) + " / " + geode::utils::numToString(playerInputs[1][2][1])).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->setScale(0.55f); lbl->setPosition({ 260, 36 }); lbl->setOpacity(150); m_mainLayer->addChild(lbl); - + return true; } - + }; \ No newline at end of file diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 0e0e08ef..6c6bf86c 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -104,7 +104,7 @@ class $modify(PauseLayer) { g.frameOffset = value; if (g.layer) { - static_cast(g.layer)->warningLabel->setString(("WARNING: Currently recording / playing macros with a frame offset of " + std::to_string(value)).c_str()); + static_cast(g.layer)->warningLabel->setString(("WARNING: Currently recording / playing macros with a frame offset of " + geode::utils::numToString(value)).c_str()); static_cast(g.layer)->warningLabel->setVisible(value != 0); static_cast(g.layer)->warningSprite->setVisible(value != 0); } @@ -319,7 +319,7 @@ class $modify(PauseLayer) { if (node == seedInput) { if (auto num = numFromString(seedInput->getString())) { - mod->setSavedValue("macro_seed", std::to_string(num.unwrap())); + mod->setSavedValue("macro_seed", geode::utils::numToString(num.unwrap())); return; } else { @@ -574,7 +574,7 @@ class $modify(PauseLayer) { warningSprite->setPosition({ 82, 307 }); m_mainLayer->addChild(warningSprite); - warningLabel = CCLabelBMFont::create(("WARNING: Currently recording / playing macros with a frame offset of " + std::to_string(g.frameOffset)).c_str(), "bigFont.fnt"); + warningLabel = CCLabelBMFont::create(("WARNING: Currently recording / playing macros with a frame offset of " + geode::utils::numToString(g.frameOffset)).c_str(), "bigFont.fnt"); warningLabel->setAnchorPoint({ 0, 0.5 }); warningLabel->setPosition({ 92, 307 }); warningLabel->setScale(0.275f); @@ -647,7 +647,7 @@ class $modify(PauseLayer) { menu->addChild(recording); menu->addChild(playing); - actionsLabel = CCLabelBMFont::create(("Actions: " + std::to_string(g.macro.inputs.size())).c_str(), "chatFont.fnt"); + actionsLabel = CCLabelBMFont::create(("Actions: " + geode::utils::numToString(g.macro.inputs.size())).c_str(), "chatFont.fnt"); actionsLabel->limitLabelWidth(57.f, 0.6f, 0.01f); actionsLabel->updateLabel(); actionsLabel->setAnchorPoint({ 0, 0.5 }); diff --git a/src/ui/render_presets_layer.hpp b/src/ui/render_presets_layer.hpp index 2421e118..924d3c5a 100644 --- a/src/ui/render_presets_layer.hpp +++ b/src/ui/render_presets_layer.hpp @@ -22,9 +22,9 @@ class RenderPresetsLayer : public geode::Popup { for (int i = 0; i < 5; i++) { float height = 170.f - 26.5f * i; - std::string id = "render_slot_" + std::to_string(i + 1); + std::string id = "render_slot_" + geode::utils::numToString(i + 1); - CCLabelBMFont* lbl = CCLabelBMFont::create(("Slot " + std::to_string(i + 1)).c_str(), "bigFont.fnt"); + CCLabelBMFont* lbl = CCLabelBMFont::create(("Slot " + geode::utils::numToString(i + 1)).c_str(), "bigFont.fnt"); lbl->setPosition({63, height + 5.f}); lbl->setScale(0.425f); m_mainLayer->addChild(lbl); diff --git a/src/ui/render_settings_layer.cpp b/src/ui/render_settings_layer.cpp index 5c2882c2..64c9ec1d 100644 --- a/src/ui/render_settings_layer.cpp +++ b/src/ui/render_settings_layer.cpp @@ -59,8 +59,8 @@ void RenderSettingsLayer::onDefaults(CCObject*) { g.mod->setSavedValue("render_file_extension", std::string(".mp4")); g.mod->setSavedValue("render_fade_in", false); g.mod->setSavedValue("render_fade_out", false); - g.mod->setSavedValue("render_fade_in_time", std::to_string(2)); - g.mod->setSavedValue("render_fade_out_time", std::to_string(2)); + g.mod->setSavedValue("render_fade_in_time", geode::utils::numToString(2)); + g.mod->setSavedValue("render_fade_out_time", geode::utils::numToString(2)); g.mod->setSavedValue("render_hide_endscreen", false); g.mod->setSavedValue("render_hide_levelcomplete", false); @@ -100,7 +100,7 @@ bool RenderSettingsLayer::init() { Utils::setBackgroundColor(m_bgSprite); if (mod->getSavedValue("render_seconds_after") == "") - mod->setSavedValue("render_seconds_after", std::to_string(0)); + mod->setSavedValue("render_seconds_after", geode::utils::numToString(0)); cocos2d::CCSize center = cocos2d::CCDirector::sharedDirector()->getWinSize() / 2; diff --git a/src/ui/save_macro_layer.hpp b/src/ui/save_macro_layer.hpp index 49f81a2c..95c3b374 100644 --- a/src/ui/save_macro_layer.hpp +++ b/src/ui/save_macro_layer.hpp @@ -109,7 +109,7 @@ class SaveMacroLayer : public geode::Popup { int result = Macro::save(author, desc, geode::utils::string::pathToString(path), jsonToggle->isToggled()); if (result != 0) - return FLAlertLayer::create("Error", "There was an error saving the macro. ID: " + std::to_string(result), "OK")->show(); + return FLAlertLayer::create("Error", "There was an error saving the macro. ID: " + geode::utils::numToString(result), "OK")->show(); this->keyBackClicked(); Notification::create("Macro Saved", NotificationIcon::Success)->show(); From ee64272251e9442b00cc482c75eabf88d1be582f Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:34:39 +0300 Subject: [PATCH 100/211] fix compiling --- src/gdr/json.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gdr/json.hpp b/src/gdr/json.hpp index 9e0d267a..43e90e28 100644 --- a/src/gdr/json.hpp +++ b/src/gdr/json.hpp @@ -5179,7 +5179,7 @@ template void int_to_string( string_type& target, std::size_t value ) { // For ADL - using geode::utils::numToString; + using std::to_string; target = to_string(value); } template class iteration_proxy_value From 743db55ddbe4736921d4610821b679ac6b8d78f9 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 24 Feb 2026 04:45:38 +0300 Subject: [PATCH 101/211] fix intel mac --- mod.json | 2 +- src/hacks/autoclicker.cpp | 44 ++++++++++++++++++++++++- src/main.cpp | 69 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 112 insertions(+), 3 deletions(-) diff --git a/mod.json b/mod.json index a7d8a22a..b4a5eebf 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "5.0.0-beta.4", + "geode": "5.0.1", "gd": { "win": "2.2081", "mac": "2.2081", diff --git a/src/hacks/autoclicker.cpp b/src/hacks/autoclicker.cpp index 59a940f8..7e6f1e4c 100644 --- a/src/hacks/autoclicker.cpp +++ b/src/hacks/autoclicker.cpp @@ -11,6 +11,7 @@ class $modify(GJBaseGameLayer) { bool holding[2] = {false, false}; }; + #ifndef GEODE_IS_MACOS void processCommands(float dt, bool isHalfTick, bool isLastTick) { GJBaseGameLayer::processCommands(dt, isHalfTick, isLastTick); @@ -52,6 +53,47 @@ class $modify(GJBaseGameLayer) { } } + #else + void processQueuedButtons(float dt, bool clearInputQueue) { + GJBaseGameLayer::processQueuedButtons(dt, clearInputQueue); + + auto& g = Global::get(); + + if (!g.autoclicker) return; + if (!PlayLayer::get()) return; + + auto& f = m_fields; + const int holdFor[2] = {g.holdFor, g.holdFor2}; + const int releaseFor[2] = {g.releaseFor, g.releaseFor2}; + + for (int i = 0; i < 2; i++) { // check 2 player mode + bool isPlayer1 = (i == 0); + if ((!g.autoclickerP1 && isPlayer1) || (!g.autoclickerP2 && !isPlayer1)) continue; + + if (f->framesReleasing[i] < (releaseFor[i] - 1) / (f->holding[i] ? 2.f : 1.f)) { + f->framesReleasing[i]++; + continue; + } + + if (f->framesHolding[i] < holdFor[i]) { + if (f->framesHolding[i] == 0) { + f->autoclick[i] = true; + GJBaseGameLayer::handleButton(true, 1, Macro::flipControls() ? !isPlayer1 : isPlayer1); + f->autoclick[i] = false; + } + + f->framesHolding[i]++; + } + else { + f->autoclick[i] = true; + GJBaseGameLayer::handleButton(false, 1, Macro::flipControls() ? !isPlayer1 : isPlayer1); + f->autoclick[i] = false; + + f->framesReleasing[i] = 0; + f->framesHolding[i] = 0; + } + } + #endif void handleButton(bool hold, int button, bool player1) { if (button != 1) return GJBaseGameLayer::handleButton(hold, button, player1); @@ -75,4 +117,4 @@ class $modify(GJBaseGameLayer) { } -}; \ No newline at end of file +}; diff --git a/src/main.cpp b/src/main.cpp index b0909861..bfe48bcc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -196,7 +196,7 @@ class $modify(BGLHook, GJBaseGameLayer) { struct Fields { bool macroInput = false; }; - + #ifndef GEODE_IS_MACOS void processCommands(float dt, bool isHalfTick, bool isLastTick) { auto& g = Global::get(); PlayLayer* pl = PlayLayer::get(); @@ -262,6 +262,73 @@ class $modify(BGLHook, GJBaseGameLayer) { if (g.state == state::playing) handlePlaying(Global::getCurrentFrame()); } + #else + void processQueuedButtons(float dt, bool clearInputQueue) { + auto& g = Global::get(); + PlayLayer* pl = PlayLayer::get(); + + if (!pl) { + return GJBaseGameLayer::processQueuedButtons(dt, clearInputQueue); + } + + Global::updateSeed(); + + bool rendering = false; + #ifdef GEODE_IS_WINDOWS + rendering = g.renderer.recording || g.renderer.recordingAudio; + #endif + + if (g.state != state::none || rendering) { + #ifdef GEODE_IS_WINDOWS + if (!g.firstAttempt) { + g.renderer.dontRender = false; + g.renderer.dontRecordAudio = false; + } + #endif + int frame = Global::getCurrentFrame(); + if (frame > 2 && g.firstAttempt && g.macro.xdBotMacro) { + g.firstAttempt = false; + #ifndef GEODE_IS_MOBILE + if ((m_levelSettings->m_platformerMode || rendering) && !m_levelEndAnimationStarted) + return pl->resetLevelFromStart(); + else if (!m_levelEndAnimationStarted) + return pl->resetLevel(); + #endif + } + + if (g.previousFrame == frame && frame != 0 && g.macro.xdBotMacro) + return GJBaseGameLayer::processQueuedButtons(dt, clearInputQueue); + } + + GJBaseGameLayer::processQueuedButtons(dt, clearInputQueue); + + if (g.state == state::none) + return; + + int frame = Global::getCurrentFrame(); + g.previousFrame = frame; + + if (g.macro.xdBotMacro && g.restart && !m_levelEndAnimationStarted) { + #ifndef GEODE_IS_MOBILE + if ((m_levelSettings->m_platformerMode && g.state != state::none) /*|| g.renderer.recordingAudio*/) + return pl->resetLevelFromStart(); + else + return pl->resetLevel(); + #else + if (m_levelSettings->m_platformerMode && g.state != state::none) + return pl->resetLevelFromStart(); + else + return pl->resetLevel(); + #endif + } + + if (g.state == state::recording) + handleRecording(frame); + + if (g.state == state::playing) + handlePlaying(Global::getCurrentFrame()); + } + #endif void handleRecording(int frame) { auto& g = Global::get(); From 1023f3130821b4fb94fd08ebabfd318eb9ddc878 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 24 Feb 2026 04:52:29 +0300 Subject: [PATCH 102/211] fix syntax inshallah --- src/hacks/autoclicker.cpp | 55 +++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/hacks/autoclicker.cpp b/src/hacks/autoclicker.cpp index 7e6f1e4c..5a0a49df 100644 --- a/src/hacks/autoclicker.cpp +++ b/src/hacks/autoclicker.cpp @@ -3,118 +3,117 @@ #include class $modify(GJBaseGameLayer) { - + struct Fields { int framesHolding[2] = {0, 0}; int framesReleasing[2] = {0, 0}; bool autoclick[2] = {false, false}; bool holding[2] = {false, false}; }; - + #ifndef GEODE_IS_MACOS void processCommands(float dt, bool isHalfTick, bool isLastTick) { GJBaseGameLayer::processCommands(dt, isHalfTick, isLastTick); - + auto& g = Global::get(); - + if (!g.autoclicker) return; if (!PlayLayer::get()) return; - + auto& f = m_fields; const int holdFor[2] = {g.holdFor, g.holdFor2}; const int releaseFor[2] = {g.releaseFor, g.releaseFor2}; - + for (int i = 0; i < 2; i++) { // check 2 player mode bool isPlayer1 = (i == 0); if ((!g.autoclickerP1 && isPlayer1) || (!g.autoclickerP2 && !isPlayer1)) continue; - + if (f->framesReleasing[i] < (releaseFor[i] - 1) / (f->holding[i] ? 2.f : 1.f)) { f->framesReleasing[i]++; continue; } - + if (f->framesHolding[i] < holdFor[i]) { if (f->framesHolding[i] == 0) { f->autoclick[i] = true; GJBaseGameLayer::handleButton(true, 1, Macro::flipControls() ? !isPlayer1 : isPlayer1); f->autoclick[i] = false; } - + f->framesHolding[i]++; } else { f->autoclick[i] = true; GJBaseGameLayer::handleButton(false, 1, Macro::flipControls() ? !isPlayer1 : isPlayer1); f->autoclick[i] = false; - + f->framesReleasing[i] = 0; f->framesHolding[i] = 0; } } - - } + }; #else void processQueuedButtons(float dt, bool clearInputQueue) { GJBaseGameLayer::processQueuedButtons(dt, clearInputQueue); - + auto& g = Global::get(); - + if (!g.autoclicker) return; if (!PlayLayer::get()) return; - + auto& f = m_fields; const int holdFor[2] = {g.holdFor, g.holdFor2}; const int releaseFor[2] = {g.releaseFor, g.releaseFor2}; - + for (int i = 0; i < 2; i++) { // check 2 player mode bool isPlayer1 = (i == 0); if ((!g.autoclickerP1 && isPlayer1) || (!g.autoclickerP2 && !isPlayer1)) continue; - + if (f->framesReleasing[i] < (releaseFor[i] - 1) / (f->holding[i] ? 2.f : 1.f)) { f->framesReleasing[i]++; continue; } - + if (f->framesHolding[i] < holdFor[i]) { if (f->framesHolding[i] == 0) { f->autoclick[i] = true; GJBaseGameLayer::handleButton(true, 1, Macro::flipControls() ? !isPlayer1 : isPlayer1); f->autoclick[i] = false; } - + f->framesHolding[i]++; } else { f->autoclick[i] = true; GJBaseGameLayer::handleButton(false, 1, Macro::flipControls() ? !isPlayer1 : isPlayer1); f->autoclick[i] = false; - + f->framesReleasing[i] = 0; f->framesHolding[i] = 0; } + } } #endif - + void handleButton(bool hold, int button, bool player1) { if (button != 1) return GJBaseGameLayer::handleButton(hold, button, player1); - + auto& g = Global::get(); if (!g.autoclicker) return GJBaseGameLayer::handleButton(hold, button, player1); - + auto& f = m_fields; bool realPlayer1 = Macro::flipControls() ? !player1 : player1; int i = realPlayer1 ? 0 : 1; - + if (f->autoclick[i] || (realPlayer1 && !g.autoclickerP1) || (!realPlayer1 && !g.autoclickerP2)) return GJBaseGameLayer::handleButton(hold, button, player1); - + f->holding[i] = hold; - + if (!hold) { f->framesHolding[i] = 0; f->framesReleasing[i] = 0; GJBaseGameLayer::handleButton(hold, button, player1); } - + } - }; From dcf0609ddae828f9d8503a4153278a858b71b6ca Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 25 Feb 2026 04:47:56 +0300 Subject: [PATCH 103/211] ditch CCKeyboardDispatcher --- mod.json | 17 +++-------------- src/keybinds.cpp | 31 ++++++++++++++++++++++++------- src/renderer/renderer.cpp | 15 ++++++++++++--- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/mod.json b/mod.json index b4a5eebf..ce92fccd 100644 --- a/mod.json +++ b/mod.json @@ -96,7 +96,6 @@ "description": "The keybind to start and stop recording a macro.", "type": "keybind", "default": "Alt+G", - "platforms": ["win", "mac"], "category": "gameplay", "migrate-from": "zilko.xdbot/toggle_recording" }, @@ -105,7 +104,6 @@ "description": "The keybind to start and stop playing a macro.", "type": "keybind", "default": "Alt+H", - "platforms": ["win", "mac"], "category": "gameplay", "migrate-from": "zilko.xdbot/toggle_playing" }, @@ -114,7 +112,6 @@ "description": "The keybind to toggle speedhack.", "type": "keybind", "default": "Alt+S", - "platforms": ["win", "mac"], "category": "gameplay", "migrate-from": "zilko.xdbot/toggle_speedhack" }, @@ -123,7 +120,6 @@ "description": "The keybind to toggle noclip.", "type": "keybind", "default": "Alt+N", - "platforms": ["win", "mac"], "category": "gameplay", "migrate-from": "zilko.xdbot/toggle_noclip" }, @@ -132,7 +128,6 @@ "description": "The keybind to toggle the frame stepper.", "type": "keybind", "default": "Alt+C", - "platforms": ["win", "mac"], "category": "gameplay", "migrate-from": "zilko.xdbot/toggle_frame_stepper" }, @@ -141,7 +136,6 @@ "description": "The keybind to step a frame when the frame stepper is enabled.", "type": "keybind", "default": "V", - "platforms": ["win", "mac"], "category": "gameplay", "migrate-from": "zilko.xdbot/step_frame" }, @@ -150,7 +144,6 @@ "description": "The keybind to toggle the trajectory while recording a macro.", "type": "keybind", "default": "Alt+T", - "platforms": ["win", "mac"], "category": "gameplay", "migrate-from": "zilko.xdbot/show_trajectory" }, @@ -159,7 +152,6 @@ "description": "The keybind to start and stop the renderer.", "type": "keybind", "default": "Alt+P", - "platforms": ["win", "mac"], "category": "gameplay", "migrate-from": "zilko.xdbot/toggle_render" }, @@ -172,22 +164,19 @@ "name": "Keybinds on editor", "description": "Enables keybinds while on the level editor.", "type": "bool", - "default": false, - "platforms": ["win", "mac"] + "default": false }, "disable_keybinds": { "name": "Disable keybinds", "description": "Disables all keybinds.", "type": "bool", - "default": false, - "platforms": ["win", "mac"] + "default": false }, "recording_only_keybinds": { "name": "Keybinds only while recording", "description": "Keybinds only work while recording a macro.", "type": "bool", - "default": false, - "platforms": ["win", "mac"] + "default": false }, "level_settings_button": { "name": "Show Button At Settings", diff --git a/src/keybinds.cpp b/src/keybinds.cpp index b6050a69..26007daa 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -1,14 +1,12 @@ -#ifdef GEODE_IS_DESKTOP #include "includes.hpp" #include "ui/record_layer.hpp" #include "hacks/show_trajectory.hpp" -#include -#include #include #include +#include -class $modify(CCKeyboardDispatcher) { +/* class $modify(CCKeyboardDispatcher) { bool dispatchKeyboardMSG(enumKeyCodes key, bool isKeyDown, bool isKeyRepeat, double time) { auto& g = Global::get(); @@ -37,7 +35,27 @@ class $modify(CCKeyboardDispatcher) { return CCKeyboardDispatcher::dispatchKeyboardMSG(key, isKeyDown, isKeyRepeat, time); } -}; +};*/ + +$on_mod(Loaded) { + KeyboardInputEvent().listen([](KeyboardInputData& data) { + auto& g = Global::get(); + int keyInt = static_cast(data.key); + + bool isKeyRepeat = (data.action == KeyboardInputData::Action::Repeat); + bool isKeyDown = (data.action == KeyboardInputData::Action::Press); + + if (g.allKeybinds.contains(keyInt) && !isKeyRepeat) { + for (size_t i = 0; i < 6; i++) { + if (std::find(g.keybinds[i].begin(), g.keybinds[i].end(), keyInt) != g.keybinds[i].end()) { + g.heldButtons[i] = isKeyDown; + } + } + } + + return ListenerResult::Propagate; + }).leak(); +} void handleKeybind(std::string const& id, bool down, bool repeat, double time) { auto& g = Global::get(); @@ -139,5 +157,4 @@ void handleKeybind(std::string const& id, bool down, bool repeat, double time) { listenForKeybindSettingPresses("toggle_noclip_keybind", [](Keybind const&, bool down, bool repeat, double time) { handleKeybind("toggle_noclip_keybind", down, false, time); }); -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index b1382c52..7ff97f06 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -792,12 +792,21 @@ bool Renderer::tryPause() { } void Renderer::startAudio(PlayLayer* pl) { - EndLevelLayer* endLevelLayer = pl->getChildByType(0); + Ref endLevelLayer = pl->getChildByType(0); if (dontRecordAudio) return; if (pl->m_levelEndAnimationStarted && endLevelLayer != nullptr) { - CCKeyboardDispatcher::get()->dispatchKeyboardMSG(enumKeyCodes::KEY_Space, true, false, 0.0); - CCKeyboardDispatcher::get()->dispatchKeyboardMSG(enumKeyCodes::KEY_Space, false, false, 0.0); + Loader::get()->queueInMainThread([endLevelLayer] { + auto retryBtn = endLevelLayer->getChildByIDRecursive("retry-button"); + if (!retryBtn) { + endLevelLayer->onReplay(nullptr); + // log::info("Passed nullptr to onReplay because retry-button doesn't exist"); + } + else { + endLevelLayer->onReplay(retryBtn); + // log::info("Passed retry-button to onReplay"); + } + }); } else if (!pl->m_levelEndAnimationStarted) { From 25d658b955d1ff4b7019648f534e412c854eda0f Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Thu, 26 Feb 2026 20:38:04 +0300 Subject: [PATCH 104/211] how did i forget open menu keybind --- mod.json | 1 - 1 file changed, 1 deletion(-) diff --git a/mod.json b/mod.json index ce92fccd..a391a031 100644 --- a/mod.json +++ b/mod.json @@ -87,7 +87,6 @@ "description": "The keybind to open the xdBot menu.", "type": "keybind", "default": "Alt+F", - "platforms": ["win", "mac"], "category": "universal", "migrate-from": "zilko.xdbot/open_menu" }, From 5a30a9ca112eb609e2b2b724a60ffc15cb66f63b Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 27 Feb 2026 00:27:21 +0300 Subject: [PATCH 105/211] allow click on steps --- src/global.cpp | 3 --- src/macro.cpp | 4 ++-- src/renderer/renderer.cpp | 18 +++++++----------- src/ui/game_ui.cpp | 8 ++++---- 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/global.cpp b/src/global.cpp index c8594fbd..7f0af14d 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -158,9 +158,6 @@ bool Global::enabledIncompatibleGDSettings() { if (GameManager::sharedState()->getGameVariable(GameVar::ClickBetweenSteps)) settingsToDisable.push_back("Click Between Steps"); - if (GameManager::sharedState()->getGameVariable(GameVar::ClickOnSteps)) - settingsToDisable.push_back("Click On Steps"); - #ifdef GEODE_IS_MOBILE if (auto pl = PlayLayer::get()) { if (pl->m_level->m_cbsOverride == 1) diff --git a/src/macro.cpp b/src/macro.cpp index 422bbfd8..9ec66e14 100644 --- a/src/macro.cpp +++ b/src/macro.cpp @@ -40,9 +40,9 @@ void Macro::recordFrameFix(int frame, PlayerObject* p1, PlayerObject* p2) { bool Macro::flipControls() { PlayLayer* pl = PlayLayer::get(); - if (!pl) return GameManager::get()->getGameVariable("0010"); + if (!pl) return GameManager::get()->getGameVariable(GameVar::Flip2PlayerControls); - return pl->m_levelSettings->m_platformerMode ? false : GameManager::get()->getGameVariable("0010"); + return pl->m_levelSettings->m_platformerMode ? false : GameManager::get()->getGameVariable(GameVar::Flip2PlayerControls); } void Macro::autoSave(GJGameLevel* level, int number) { diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 7ff97f06..c04e0eee 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -159,19 +159,15 @@ bool Renderer::toggle() { } #ifdef GEODE_IS_WINDOWS - std::vector incompatSettings; - if (GameManager::sharedState()->getGameVariable(GameVar::ClickBetweenSteps)) incompatSettings.push_back("Click Between Steps"); - if (GameManager::sharedState()->getGameVariable(GameVar::ClickOnSteps)) incompatSettings.push_back("Click On Steps"); - - if (!incompatSettings.empty()) { - geode::utils::StringBuffer incompatString; - - for (const std::string& name : incompatSettings) { - incompatString.append("{}{}", name, (name != incompatSettings.back() ? "," : "")); - - FLAlertLayer::create("Render", "Disable incompatible GD settings to render a level: \n" + incompatString.str(), "OK")->show(); + auto scene = CCScene::get(); + if (GameManager::sharedState()->getGameVariable(GameVar::ClickBetweenSteps)) { + if (scene && !scene->getChildByID("render-alert"_spr)) { + auto alert = FLAlertLayer::create("Render", "Disable Click Between Steps to render a level.", "OK"); + alert->setID("render-alert"_spr); + alert->show(); } + return false; } #endif diff --git a/src/ui/game_ui.cpp b/src/ui/game_ui.cpp index 011e22cf..c901704e 100644 --- a/src/ui/game_ui.cpp +++ b/src/ui/game_ui.cpp @@ -154,10 +154,10 @@ void Interface::updateButtons() { auto& g = Global::get(); - #ifdef GEODE_IS_WINDOWS - bool isWindows = true; + #ifdef GEODE_IS_DESKTOP + bool isDesktop = true; #else - bool isWindows = false; + bool isDesktop = false; #endif CCNode* disableStepperBtn = menu->getChildByID("disable-stepper-btn"); @@ -209,7 +209,7 @@ void Interface::updateButtons() { size = sprite->getContentSize(); speedhackBtn->setContentSize({ size.width * scale, size.height * scale }); - if ((g.state != state::recording && !g.mod->getSavedValue("macro_always_show_buttons")) || isWindows) { + if ((g.state != state::recording && !g.mod->getSavedValue("macro_always_show_buttons")) || isDesktop) { disableStepperBtn->setVisible(false); stepFrameBtn->setVisible(false); speedhackBtn->setVisible(false); From ff011af661a315f966c55ab65b95b0cb0dd15bb9 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 27 Feb 2026 03:47:56 +0300 Subject: [PATCH 106/211] gdr2 support (bismillah) --- CMakeLists.txt | 5 + changelog.md | 16 +++ mod.json | 13 ++- src/gdr/gdr.hpp | 11 +- src/global.cpp | 2 +- src/macro.cpp | 204 ++++++++++++++++++++++++++++++++---- src/macro.hpp | 59 ++++++++++- src/ui/load_macro_layer.cpp | 31 +++--- src/ui/macro_info_layer.hpp | 4 +- src/ui/save_macro_layer.hpp | 103 +++++++++++++++--- src/utils/utils.cpp | 3 - 11 files changed, 381 insertions(+), 70 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5aa5d412..91707945 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,4 +50,9 @@ endif() add_subdirectory($ENV{GEODE_SDK} ${CMAKE_CURRENT_BINARY_DIR}/geode) +CPMAddPackage("gh:prevter/msgpack-for-matjson#16a7957") +CPMAddPackage("gh:maxnut/GDReplayFormat#72078e5") +CPMAddPackage("gh:maxnut/GDR-converter#71104a9") +target_link_libraries(${PROJECT_NAME} libGDR GDRconverter) + setup_geode_mod(${PROJECT_NAME}) diff --git a/changelog.md b/changelog.md index 79d482fb..46611253 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,19 @@ +# v2.5.0 +* Geode v5 support. +* Cross-platform support. (Windows, macOS, Android, iOS, renderer is Windows only, mobile coming soon) +* GDR2 support. +* Rewrote Layout Mode. (Levels now load significantly faster and triggers do not break) +* Fix seed freezing and crashing. (Switched to Geode's generator for seeds) +* Fix iOS related filesystem crashes. (Switched to Geode utilities for filesystem operations, temporarily removed macros/renders/autosaves location settings in More Settings due to issues with Geode, where those settings would crash.) +* Beautify game version display in macro information popup. (Used to have trailing zeros) +* Port keybinds to Geode's keybind system (cross-platform keybinds, including mobile if connected to a Bluetooth/USB keyboard.) +* Fix a bug where if a popup is open in xdBot, the keybinds would still be clickable, causing unexpected behavior like being able to close the xdBot menu via keybinds. +* Added a setting to More Settings to open the xdBot menu instantly. +* Added a setting to More Settings to choose the default macro format. (GDR2, GDR, JSON) +* Made xdBot detect and prevent you from recording/playing a macro or rendering a level if you have Click Between Steps enabled in Geometry Dash settings. +* Fix capitalization of 'OK' across UIs. (blame Zilko) +* Removed Herobrine. + # v2.4.1 * Added Auto Clicker keybind. diff --git a/mod.json b/mod.json index a391a031..96ccec86 100644 --- a/mod.json +++ b/mod.json @@ -1,12 +1,12 @@ { - "geode": "5.0.1", + "geode": "5.1.0", "gd": { "win": "2.2081", "mac": "2.2081", "android": "2.2081", "ios": "2.2081" }, - "version": "2.4.1", + "version": "2.5.0", "id": "zilko.xdbot", "name": "xdBot", "developer": "Zilko", @@ -22,9 +22,16 @@ "default": "Frame Fixes", "one-of": ["Vanilla", "Input Fixes", "Frame Fixes"] }, + "default_save_format": { + "type": "string", + "name": "Default Save Format", + "description": "Default format for saving macros.", + "default": "GDR2", + "one-of": ["GDR2", "GDR", "JSON"] + }, "frame_offset": { "name": "Frame Offset", - "description": "Adds a frame offset when recording or playing macros", + "description": "Adds a frame offset when recording or playing macros.", "type": "int", "default": 0, "min": -8, diff --git a/src/gdr/gdr.hpp b/src/gdr/gdr.hpp index b1dab91a..ec17e407 100644 --- a/src/gdr/gdr.hpp +++ b/src/gdr/gdr.hpp @@ -16,7 +16,7 @@ std::vector splitByChar(std::string str, char splitChar); const std::string xdBotVersion = "v2.3.11"; -namespace gdr { +namespace gdr_legacy { using namespace nlohmann; @@ -133,12 +133,6 @@ namespace gdr { if (replayJson.is_discarded()) return replay; } - // try { - // replayJson = json::from_msgpack(data); - // } catch(std::exception& e) { - // replayJson = json::parse(data); - // } - if (!replayJson["gameVersion"].is_null()) replay.gameVersion = replayJson["gameVersion"]; if (!replayJson["description"].is_null()) replay.description = replayJson["description"]; if (!replayJson["version"].is_null()) replay.version = replayJson["version"]; @@ -161,7 +155,6 @@ namespace gdr { bool rotation = ver.find("beta.") == std::string::npos && ver.find("alpha.") == std::string::npos; if (replay.botInfo.name == "xdBot" && ver == "v2.0.0") rotation = true; - // bool offset = false; int offset = replay.botInfo.name == "xdBot" ? 1 : 0; if (offset == 1) { @@ -317,4 +310,4 @@ namespace gdr { } }; -} \ No newline at end of file +} diff --git a/src/global.cpp b/src/global.cpp index 7f0af14d..84ebc7e0 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -521,5 +521,5 @@ PauseLayer* Global::getPauseLayer() { g.macro.author = "N/A"; g.macro.description = "N/A"; - g.macro.gameVersion = GEODE_GD_VERSION; + g.macro.gameVersion = static_cast(std::round(static_cast(GEODE_GD_VERSION) * 1000.0)); }; diff --git a/src/macro.cpp b/src/macro.cpp index 9ec66e14..9888e223 100644 --- a/src/macro.cpp +++ b/src/macro.cpp @@ -86,7 +86,7 @@ void Macro::tryAutosave(GJGameLevel* level, CheckpointObject* cp) { std::string levelname = level->m_levelName; std::filesystem::path path = autoSavesPath / fmt::format("autosave_{}_{}", levelname, g.currentSession); std::error_code ec; - std::filesystem::remove(geode::utils::string::pathToString(path) + ".gdr", ec); // Remove previous save + std::filesystem::remove(geode::utils::string::pathToString(path) + ".gdr", ec); if (ec) log::warn("Failed to remove previous autosave"); autoSave(level, g.currentSession); @@ -103,7 +103,7 @@ void Macro::updateInfo(PlayLayer* pl) { g.macro.ldm = level->m_lowDetailModeToggled; int id = level->m_levelID.value(); - if (id != g.macro.levelInfo.id) + if (static_cast(g.macro.levelInfo.id) != id) g.macro.levelInfo.id = id; std::string name = level->m_levelName; @@ -118,7 +118,7 @@ void Macro::updateInfo(PlayLayer* pl) { g.macro.author = "N/A"; g.macro.botInfo.name = "xdBot"; - g.macro.botInfo.version = xdBotVersion; + g.macro.botInfo.version = 1; g.macro.xdBotMacro = true; } @@ -147,12 +147,167 @@ void Macro::updateTPS() { if (g.layer) static_cast(g.layer)->updateTPS(); } -int Macro::save(std::string author, std::string desc, std::string path, bool json) { +LegacyMacro Macro::toLegacy() const { + LegacyMacro legacy; + legacy.author = author; + legacy.description = description; + legacy.duration = duration; + legacy.gameVersion = static_cast(gameVersion) / 1000.0f; + legacy.framerate = framerate; + legacy.seed = seed; + legacy.coins = coins; + legacy.ldm = ldm; + legacy.botInfo.name = botInfo.name; + legacy.botInfo.version = xdBotVersion; + legacy.levelInfo.id = levelInfo.id; + legacy.levelInfo.name = levelInfo.name; + + for (const auto& inp : inputs) { + legacy.inputs.push_back(legacy_input( + static_cast(inp.frame), + inp.button, + inp.player2, + inp.down + )); + } + + legacy.frameFixes = frameFixes; + + return legacy; +} + +Macro Macro::fromLegacy(const LegacyMacro& legacy) { + Macro macro; + macro.author = legacy.author; + macro.description = legacy.description; + macro.duration = legacy.duration; + macro.gameVersion = static_cast(std::round(legacy.gameVersion * 1000.0f)); + macro.framerate = legacy.framerate; + macro.seed = legacy.seed; + macro.coins = legacy.coins; + macro.ldm = legacy.ldm; + macro.botInfo.name = legacy.botInfo.name; + macro.botInfo.version = 1; + macro.levelInfo.id = legacy.levelInfo.id; + macro.levelInfo.name = legacy.levelInfo.name; + macro.frameFixes = legacy.frameFixes; + + for (const auto& inp : legacy.inputs) { + macro.inputs.push_back(input( + static_cast(inp.frame), + static_cast(inp.button), + inp.player2, + inp.down + )); + } + + macro.xdBotMacro = legacy.botInfo.name == "xdBot"; + + return macro; +} + +gdr::Result> Macro::exportGDR2() { + return gdr::Replay::exportData(); +} + +std::vector Macro::exportGDR1() { + LegacyMacro legacy = toLegacy(); + return legacy.exportData(false); +} + +std::vector Macro::exportJSON() { + LegacyMacro legacy = toLegacy(); + return legacy.exportData(true); +} + +void Macro::saveExtension(binary_writer& writer) const { + writer << static_cast(frameFixes.size()); + + for (const auto& fix : frameFixes) { + writer << static_cast(fix.frame); + writer << fix.p1.pos.x; + writer << fix.p1.pos.y; + writer << fix.p1.rotation; + writer << fix.p1.rotate; + writer << fix.p2.pos.x; + writer << fix.p2.pos.y; + writer << fix.p2.rotation; + writer << fix.p2.rotate; + } +} + +void Macro::parseExtension(binary_reader& reader) { + uint64_t count = 0; + reader >> count; + + frameFixes.clear(); + frameFixes.reserve(count); + + for (uint64_t i = 0; i < count; i++) { + gdr_legacy::FrameFix fix; + uint64_t frame = 0; + reader >> frame; + fix.frame = static_cast(frame); + + reader >> fix.p1.pos.x; + reader >> fix.p1.pos.y; + reader >> fix.p1.rotation; + reader >> fix.p1.rotate; + reader >> fix.p2.pos.x; + reader >> fix.p2.pos.y; + reader >> fix.p2.rotation; + reader >> fix.p2.rotate; + + frameFixes.push_back(fix); + } +} + +Macro Macro::importData(std::vector& data) { + if (data.size() >= 3 && data[0] == 'G' && data[1] == 'D' && data[2] == 'R') { + std::span span(data.data(), data.size()); + auto result = gdr::Replay::importData(span); + if (result.isOk()) { + Macro macro = std::move(result).unwrap(); + macro.xdBotMacro = macro.botInfo.name == "xdBot"; + return macro; + } + log::warn("GDR2 import failed: {}", result.unwrapErr()); + } + + { + std::span span(data.data(), data.size()); + auto result = gdr::convert(span); + if (result.isOk()) { + Macro macro = std::move(result).unwrap(); + macro.xdBotMacro = macro.botInfo.name == "xdBot"; + return macro; + } + log::warn("GDR converter import failed: {}", result.unwrapErr()); + } + + { + LegacyMacro legacy = LegacyMacro::importData(data); + if (!legacy.inputs.empty() || !legacy.botInfo.name.empty()) { + Macro macro = fromLegacy(legacy); + return macro; + } + } + + log::error("Failed to import macro data in any format"); + return Macro(); +} + +int Macro::save(std::string author, std::string desc, std::string path, SaveFormat format) { auto& g = Global::get(); if (g.macro.inputs.empty()) return 31; - std::string extension = json ? ".gdr.json" : ".gdr"; + std::string extension; + switch (format) { + case SaveFormat::GDR2: extension = ".gdr2"; break; + case SaveFormat::GDR1: extension = ".gdr"; break; + case SaveFormat::JSON: extension = ".gdr.json"; break; + } int iterations = 0; @@ -180,7 +335,25 @@ int Macro::save(std::string author, std::string desc, std::string path, bool jso if (!f.is_open()) return 20; - auto data = g.macro.exportData(json); + std::vector data; + + switch (format) { + case SaveFormat::GDR2: { + auto result = g.macro.exportGDR2(); + if (result.isErr()) { + log::error("GDR2 export failed: {}", result.unwrapErr()); + return 23; + } + data = std::move(result).unwrap(); + break; + } + case SaveFormat::GDR1: + data = g.macro.exportGDR1(); + break; + case SaveFormat::JSON: + data = g.macro.exportJSON(); + break; + } if (data.empty()) return 23; @@ -212,7 +385,7 @@ Macro Macro::XDtoGDR(std::filesystem::path path) { Macro newMacro; newMacro.author = "N/A"; newMacro.description = "N/A"; - newMacro.gameVersion = GEODE_GD_VERSION; + newMacro.gameVersion = static_cast(std::round(static_cast(GEODE_GD_VERSION) * 1000.0)); std::ifstream file(path, std::ios::binary); std::string line; @@ -339,20 +512,5 @@ bool Macro::shouldStep() { if (g.stepFrame) return true; if (Global::getCurrentFrame() == 0) return true; - // if (g.ignoreFrame != -1) return true; - // if (g.ignoreJumpButton != -1) return true; - - // if (g.delayedFrameReleaseMain[0] != -1) return true; - // if (g.delayedFrameReleaseMain[1] != -1) return true; - - // if (g.delayedFrameInput[0] != -1) return true; - // if (g.delayedFrameInput[1] != -1) return true; - - // for (int x = 0; x < 2; x++) { - // for (int y = 0; y < 2; y++) { - // if (g.delayedFrameRelease[x][y] != -1) return true; - // } - // } - return false; -} \ No newline at end of file +} diff --git a/src/macro.hpp b/src/macro.hpp index 0bd78a7c..ebe3c141 100644 --- a/src/macro.hpp +++ b/src/macro.hpp @@ -4,6 +4,9 @@ #include "gdr/gdr.hpp" #include "utils/utils.hpp" +#include +#include + using namespace geode::prelude; #define DIF(a, b) (std::fabs((a) - (b)) > 0.001f) @@ -21,10 +24,16 @@ enum state { playing }; -struct input : gdr::Input { +enum class SaveFormat { + GDR2, + GDR1, + JSON +}; + +struct input : gdr::Input<> { input() = default; - input(int frame, int button, bool player2, bool down) + input(uint64_t frame, uint8_t button, bool player2, bool down) : Input(frame, button, player2, down) {} bool operator==(const input& other) const { @@ -33,11 +42,28 @@ struct input : gdr::Input { button == other.button && down == other.down; } + + bool operator<(const input& other) const { + return frame < other.frame; + } +}; + +struct legacy_input : gdr_legacy::Input { + legacy_input() = default; + + legacy_input(int frame, int button, bool player2, bool down) + : Input(frame, button, player2, down) {} +}; + +struct LegacyMacro : gdr_legacy::Replay { + LegacyMacro() : Replay("xdBot", xdBotVersion.c_str()) {} }; struct Macro : gdr::Replay { - Macro() : Replay("xdBot", xdBotVersion.c_str()) {} + Macro() : Replay("xdBot", 1) { + botInfo.name = "xdBot"; + } public: @@ -45,11 +71,36 @@ struct Macro : gdr::Replay { uintptr_t seed = 0; bool xdBotMacro = true; + std::vector frameFixes; + + bool shouldParseExtension() const override { + return botInfo.name == "xdBot"; + } + + void parseExtension(binary_reader& reader) override; + void saveExtension(binary_writer& writer) const override; + + std::string getBotVersionString() const { + return xdBotVersion; + } + + LegacyMacro toLegacy() const; + + static Macro fromLegacy(const LegacyMacro& legacy); + + gdr::Result> exportGDR2(); + + std::vector exportGDR1(); + + std::vector exportJSON(); + + static Macro importData(std::vector& data); + static void recordAction(int frame, int button, bool player2, bool hold); static void recordFrameFix(int frame, PlayerObject* p1, PlayerObject* p2); - static int save(std::string author, std::string desc, std::string path, bool json = false); + static int save(std::string author, std::string desc, std::string path, SaveFormat format = SaveFormat::GDR2); static void autoSave(GJGameLevel* level, int number); diff --git a/src/ui/load_macro_layer.cpp b/src/ui/load_macro_layer.cpp index ce56d0e2..b1cef503 100644 --- a/src/ui/load_macro_layer.cpp +++ b/src/ui/load_macro_layer.cpp @@ -149,7 +149,7 @@ LoadMacroLayer* LoadMacroLayer::create(geode::Popup* layer, geode::Popup* layer2 void LoadMacroLayer::onImportMacro(CCObject*) { if (isPickingFile) return; file::FilePickOptions fileOptions; - fileOptions.filters.push_back({"Macro Files", { "*.gdr", "*.xd", "*.json" }}); + fileOptions.filters.push_back({"Macro Files", { "*.gdr", "*.gdr2", "*.xd", "*.json" }}); auto weakThis = geode::WeakRef(this); isPickingFile = true; @@ -177,7 +177,8 @@ void LoadMacroLayer::onImportMacro(CCObject*) { } else { auto dataRes = geode::utils::file::readBinary(path); if (!dataRes) return; - tempMacro = Macro::importData(dataRes.unwrap()); + auto data = dataRes.unwrap(); + tempMacro = Macro::importData(data); } std::string name = path.stem().string(); @@ -188,20 +189,26 @@ void LoadMacroLayer::onImportMacro(CCObject*) { std::filesystem::path folder = Mod::get()->getSettingValue("macros_folder"); #endif - std::filesystem::path finalPath = folder / (name + ".gdr.json"); + // Save imported macros as GDR2 binary + std::filesystem::path finalPath = folder / (name + ".gdr2"); int iterations = 1; while (std::filesystem::exists(finalPath)) { - finalPath = folder / fmt::format("{} ({}).gdr.json", name, iterations++); + finalPath = folder / fmt::format("{} ({}).gdr2", name, iterations++); } - if (geode::utils::file::writeBinary(finalPath, tempMacro.exportData(true))) { - self->reloadList(0); - - if (path.extension() == ".xd") { - FLAlertLayer::create("Warning", "Legacy .xd macros may be unstable.", "OK")->show(); + auto exportResult = tempMacro.exportGDR2(); + if (exportResult.isOk()) { + if (geode::utils::file::writeBinary(finalPath, exportResult.unwrap())) { + self->reloadList(0); + + if (path.extension() == ".xd") { + FLAlertLayer::create("Warning", "Legacy .xd macros may be unstable.", "OK")->show(); + } + Notification::create("Macro Imported", NotificationIcon::Success)->show(); + self->isPickingFile = false; } - Notification::create("Macro Imported", NotificationIcon::Success)->show(); - self->isPickingFile = false; + } else { + FLAlertLayer::create("Error", "Failed to export imported macro.", "OK")->show(); } }); } @@ -417,7 +424,7 @@ void LoadMacroLayer::addList(bool refresh, float prevScroll) { for (int i = invertSort ? macros.size() - 1 : 0; invertSort ? i >= 0 : i < macros.size(); invertSort ? --i : ++i) { - if (macros[i].extension() != ".gdr" && macros[i].extension() != ".xd" && macros[i].extension() != ".json") continue; + if (macros[i].extension() != ".gdr" && macros[i].extension() != ".gdr2" && macros[i].extension() != ".xd" && macros[i].extension() != ".json") continue; std::string name = geode::utils::string::pathToString(macros[i].filename()).substr(0, geode::utils::string::pathToString(macros[i].filename()).find_last_of('.')); diff --git a/src/ui/macro_info_layer.hpp b/src/ui/macro_info_layer.hpp index 2e8da7b8..ecfc4d6d 100644 --- a/src/ui/macro_info_layer.hpp +++ b/src/ui/macro_info_layer.hpp @@ -141,7 +141,7 @@ class MacroInfoLayer : public geode::Popup { lbl->setOpacity(150); m_mainLayer->addChild(lbl); - std::string version = g.macro.gameVersion != 0 ? fmt::format("{:g}", static_cast(g.macro.gameVersion)) : "N/A"; + std::string version = g.macro.gameVersion != 0 ? fmt::format("{:g}", static_cast(g.macro.gameVersion) / 1000.0) : "N/A"; lbl = CCLabelBMFont::create(version.c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); @@ -179,7 +179,7 @@ class MacroInfoLayer : public geode::Popup { lbl->setOpacity(150); m_mainLayer->addChild(lbl); - lbl = CCLabelBMFont::create((g.macro.botInfo.name + " " + g.macro.botInfo.version).c_str(), "chatFont.fnt"); + lbl = CCLabelBMFont::create((g.macro.botInfo.name + " v" + geode::utils::numToString(g.macro.botInfo.version)).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->limitLabelWidth(271.f, 0.475, 0.01f); lbl->updateLabel(); diff --git a/src/ui/save_macro_layer.hpp b/src/ui/save_macro_layer.hpp index 95c3b374..50a02021 100644 --- a/src/ui/save_macro_layer.hpp +++ b/src/ui/save_macro_layer.hpp @@ -7,12 +7,28 @@ class SaveMacroLayer : public geode::Popup { TextInput* descInput = nullptr; TextInput* nameInput = nullptr; + CCMenuItemToggler* gdr1Toggle = nullptr; CCMenuItemToggler* jsonToggle = nullptr; + SaveFormat selectedFormat = SaveFormat::GDR2; + SaveFormat defaultFormat = SaveFormat::GDR2; + private: bool init() override { - if (!Popup::init(285, 194, Utils::getTexture().c_str())) return false; + std::string defaultFormatStr = Mod::get()->getSettingValueString("default_save_format"); + if (defaultFormatStr == "GDR") { + defaultFormat = SaveFormat::GDR1; + selectedFormat = SaveFormat::GDR1; + } else if (defaultFormatStr == "JSON") { + defaultFormat = SaveFormat::JSON; + selectedFormat = SaveFormat::JSON; + } else { + defaultFormat = SaveFormat::GDR2; + selectedFormat = SaveFormat::GDR2; + } + + if (!Popup::init(285, 210, Utils::getTexture().c_str())) return false; Utils::setBackgroundColor(m_bgSprite); setTitle("Save Macro"); @@ -27,48 +43,109 @@ class SaveMacroLayer : public geode::Popup { m_mainLayer->addChild(menu); authorInput = TextInput::create(104, "Author", "chatFont.fnt"); - authorInput->setPosition({ 61, 42 }); + authorInput->setPosition({ 61, 50 }); authorInput->setString(GJAccountManager::sharedState()->m_username.c_str()); menu->addChild(authorInput); CCLabelBMFont* lbl = CCLabelBMFont::create("(optional)", "chatFont.fnt"); - lbl->setPosition({ 61, 20 }); + lbl->setPosition({ 61, 28 }); lbl->setOpacity(73); lbl->setScale(0.575); menu->addChild(lbl); nameInput = TextInput::create(104, "Name", "chatFont.fnt"); - nameInput->setPosition({ -61, 42 }); + nameInput->setPosition({ -61, 50 }); nameInput->setString(Global::get().macro.levelInfo.name); menu->addChild(nameInput); descInput = TextInput::create(226, "Description (optional)", "chatFont.fnt"); - descInput->setPositionY(-8); + descInput->setPositionY(0); menu->addChild(descInput); ButtonSprite* spr = ButtonSprite::create("Save"); spr->setScale(0.725f); CCMenuItemSpriteExtra* btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(SaveMacroLayer::onSave)); - btn->setPositionY(-56); + btn->setPositionY(-48); menu->addChild(btn); CCSprite* spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); CCSprite* spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); - jsonToggle = CCMenuItemToggler::create(spriteOff, spriteOn, this, nullptr); - jsonToggle->setPosition({ -124, -78 }); - jsonToggle->setScale(0.575); + gdr1Toggle = CCMenuItemToggler::create(spriteOff, spriteOn, this, menu_selector(SaveMacroLayer::onGDR1Toggle)); + gdr1Toggle->setPosition({ -124, -86 }); + gdr1Toggle->setScale(0.525); + menu->addChild(gdr1Toggle); + + lbl = CCLabelBMFont::create("GDR", "bigFont.fnt"); + lbl->setPosition({ -97, -85.5 }); + lbl->setScale(0.35); + menu->addChild(lbl); + + spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); + spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); + jsonToggle = CCMenuItemToggler::create(spriteOff, spriteOn, this, menu_selector(SaveMacroLayer::onJSONToggle)); + jsonToggle->setPosition({ -50, -86 }); + jsonToggle->setScale(0.525); menu->addChild(jsonToggle); lbl = CCLabelBMFont::create("JSON", "bigFont.fnt"); - lbl->setPosition({ -97, -77.5 }); - lbl->setScale(0.375); + lbl->setPosition({ -23, -85.5 }); + lbl->setScale(0.35); + menu->addChild(lbl); + + if (selectedFormat == SaveFormat::GDR1) { + gdr1Toggle->toggle(true); + } else if (selectedFormat == SaveFormat::JSON) { + jsonToggle->toggle(true); + } + + lbl = CCLabelBMFont::create("Default: GDR2", "chatFont.fnt"); + lbl->setPosition({ 110, -85.5 }); + lbl->setScale(0.5); + lbl->setOpacity(100); + lbl->setID("format-label"); menu->addChild(lbl); return true; } + void updateFormatLabel() { + CCLabelBMFont* lbl = static_cast(m_mainLayer->getChildByType(0)->getChildByID("format-label")); + if (!lbl) return; + + bool isDefault = (selectedFormat == defaultFormat); + const char* prefix = isDefault ? "Default" : "Format"; + + switch (selectedFormat) { + case SaveFormat::GDR2: lbl->setString(fmt::format("{}: GDR2", prefix).c_str()); break; + case SaveFormat::GDR1: lbl->setString(fmt::format("{}: GDR1", prefix).c_str()); break; + case SaveFormat::JSON: lbl->setString(fmt::format("{}: JSON", prefix).c_str()); break; + } + } + + void onGDR1Toggle(CCObject*) { + bool toggled = !gdr1Toggle->isToggled(); + if (toggled) { + selectedFormat = SaveFormat::GDR1; + jsonToggle->toggle(false); + } else { + selectedFormat = defaultFormat; + } + updateFormatLabel(); + } + + void onJSONToggle(CCObject*) { + bool toggled = !jsonToggle->isToggled(); + if (toggled) { + selectedFormat = SaveFormat::JSON; + gdr1Toggle->toggle(false); + } else { + selectedFormat = defaultFormat; + } + updateFormatLabel(); + } + public: STATIC_CREATE(SaveMacroLayer) @@ -106,7 +183,7 @@ class SaveMacroLayer : public geode::Popup { std::string author = authorInput->getString(); std::string desc = descInput->getString(); - int result = Macro::save(author, desc, geode::utils::string::pathToString(path), jsonToggle->isToggled()); + int result = Macro::save(author, desc, geode::utils::string::pathToString(path), selectedFormat); if (result != 0) return FLAlertLayer::create("Error", "There was an error saving the macro. ID: " + geode::utils::numToString(result), "OK")->show(); @@ -115,4 +192,4 @@ class SaveMacroLayer : public geode::Popup { Notification::create("Macro Saved", NotificationIcon::Success)->show(); } -}; \ No newline at end of file +}; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index d01e13ae..f82da102 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -41,7 +41,6 @@ std::string Utils::narrow(const wchar_t *str) { #endif #endif - // ✅ Fallback return (fixes error) return ""; } @@ -80,7 +79,6 @@ std::wstring Utils::widen(const char *str) { #endif #endif - // ✅ Fallback return return L""; } @@ -113,7 +111,6 @@ std::time_t Utils::getFileCreationTime(const std::filesystem::path &path) { return ull.QuadPart / 10000000ULL - 11644473600ULL; #else - // ✅ Safe fallback for other platforms return 0; #endif } From fe023dd637446a289bb1056927a790c91153784b Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 27 Feb 2026 03:50:55 +0300 Subject: [PATCH 107/211] ok --- src/ui/save_macro_layer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/save_macro_layer.hpp b/src/ui/save_macro_layer.hpp index 50a02021..24548f48 100644 --- a/src/ui/save_macro_layer.hpp +++ b/src/ui/save_macro_layer.hpp @@ -16,7 +16,7 @@ class SaveMacroLayer : public geode::Popup { private: bool init() override { - std::string defaultFormatStr = Mod::get()->getSettingValueString("default_save_format"); + std::string defaultFormatStr = Mod::get()->getSettingValue("default_save_format"); if (defaultFormatStr == "GDR") { defaultFormat = SaveFormat::GDR1; selectedFormat = SaveFormat::GDR1; From 799a319a079289359a14773986af1436ceb11b31 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Fri, 27 Feb 2026 23:01:09 +0300 Subject: [PATCH 108/211] make load macro layer call onClose --- src/ui/load_macro_layer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/load_macro_layer.cpp b/src/ui/load_macro_layer.cpp index b1cef503..fd7fac4f 100644 --- a/src/ui/load_macro_layer.cpp +++ b/src/ui/load_macro_layer.cpp @@ -711,7 +711,7 @@ void MacroCell::handleLoad() { if (mergeLayer) { typeinfo_cast(mergeLayer)->mergeMacro(newMacro.inputs, players, static_cast(loadLayer)->owToggle->isToggled()); - loadLayer->keyBackClicked(); + loadLayer->onClose(nullptr); } return; @@ -725,7 +725,7 @@ void MacroCell::handleLoad() { g.macro.xdBotMacro = g.macro.botInfo.name == "xdBot"; - loadLayer->keyBackClicked(); + loadLayer->onClose(nullptr); RecordLayer* newLayer = nullptr; From efb50f5d295836d8ccc0d888a0db7b3f68255100 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sat, 28 Feb 2026 04:05:53 +0300 Subject: [PATCH 109/211] Revert "make load macro layer call onClose" This reverts commit 799a319a079289359a14773986af1436ceb11b31. --- src/ui/load_macro_layer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/load_macro_layer.cpp b/src/ui/load_macro_layer.cpp index fd7fac4f..b1cef503 100644 --- a/src/ui/load_macro_layer.cpp +++ b/src/ui/load_macro_layer.cpp @@ -711,7 +711,7 @@ void MacroCell::handleLoad() { if (mergeLayer) { typeinfo_cast(mergeLayer)->mergeMacro(newMacro.inputs, players, static_cast(loadLayer)->owToggle->isToggled()); - loadLayer->onClose(nullptr); + loadLayer->keyBackClicked(); } return; @@ -725,7 +725,7 @@ void MacroCell::handleLoad() { g.macro.xdBotMacro = g.macro.botInfo.name == "xdBot"; - loadLayer->onClose(nullptr); + loadLayer->keyBackClicked(); RecordLayer* newLayer = nullptr; From 8b1fdbe3904a7bb27567f7041d203373588210d4 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Sun, 1 Mar 2026 22:39:55 +0300 Subject: [PATCH 110/211] renderer on mobile --- .gitignore | 5 ++++- src/gdr/gdr.hpp | 12 ++++++++++-- src/global.cpp | 2 +- src/macro.cpp | 6 +++--- src/macro.hpp | 4 ++-- src/renderer/renderer.cpp | 24 +++++++++++++++++------- src/ui/macro_info_layer.hpp | 2 +- src/ui/record_layer.cpp | 25 ++++++++++++++----------- 8 files changed, 52 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index 2ffc61a4..d6a55daa 100644 --- a/.gitignore +++ b/.gitignore @@ -67,4 +67,7 @@ build-*/ # CLion /cmake-build-*/ -build.sh \ No newline at end of file +build.sh + +eclipsemenu/ +ffmpeg-api/ \ No newline at end of file diff --git a/src/gdr/gdr.hpp b/src/gdr/gdr.hpp index ec17e407..e16c3484 100644 --- a/src/gdr/gdr.hpp +++ b/src/gdr/gdr.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -8,14 +10,20 @@ #include +inline std::string getModVersionString() { + return geode::Mod::get()->getVersion().toVString(); +} + +inline int getModVersionInt() { + return static_cast(geode::Mod::get()->getVersion().getMajor()); +} + geode::prelude::VersionInfo getVersion(std::vector nums); cocos2d::CCPoint dataFromString(std::string dataString); std::vector splitByChar(std::string str, char splitChar); -const std::string xdBotVersion = "v2.3.11"; - namespace gdr_legacy { using namespace nlohmann; diff --git a/src/global.cpp b/src/global.cpp index 84ebc7e0..52cfcc41 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -403,7 +403,7 @@ PauseLayer* Global::getPauseLayer() { g.mod->setSavedValue("render_video_args", std::string("")); if (!g.mod->setSavedValue("defaults_set_11", true)) - g.mod->setSavedValue("render_codec", std::string("libx264")); + g.mod->setSavedValue("render_codec", std::string("h264_mediacodec")); #endif diff --git a/src/macro.cpp b/src/macro.cpp index 9888e223..bedd6dc4 100644 --- a/src/macro.cpp +++ b/src/macro.cpp @@ -118,7 +118,7 @@ void Macro::updateInfo(PlayLayer* pl) { g.macro.author = "N/A"; g.macro.botInfo.name = "xdBot"; - g.macro.botInfo.version = 1; + g.macro.botInfo.version = getModVersionInt(); g.macro.xdBotMacro = true; } @@ -158,7 +158,7 @@ LegacyMacro Macro::toLegacy() const { legacy.coins = coins; legacy.ldm = ldm; legacy.botInfo.name = botInfo.name; - legacy.botInfo.version = xdBotVersion; + legacy.botInfo.version = getModVersionString(); legacy.levelInfo.id = levelInfo.id; legacy.levelInfo.name = levelInfo.name; @@ -187,7 +187,7 @@ Macro Macro::fromLegacy(const LegacyMacro& legacy) { macro.coins = legacy.coins; macro.ldm = legacy.ldm; macro.botInfo.name = legacy.botInfo.name; - macro.botInfo.version = 1; + macro.botInfo.version = std::stoi(legacy.botInfo.version); macro.levelInfo.id = legacy.levelInfo.id; macro.levelInfo.name = legacy.levelInfo.name; macro.frameFixes = legacy.frameFixes; diff --git a/src/macro.hpp b/src/macro.hpp index ebe3c141..1d13dcea 100644 --- a/src/macro.hpp +++ b/src/macro.hpp @@ -56,7 +56,7 @@ struct legacy_input : gdr_legacy::Input { }; struct LegacyMacro : gdr_legacy::Replay { - LegacyMacro() : Replay("xdBot", xdBotVersion.c_str()) {} + LegacyMacro() : Replay("xdBot", getModVersionString()) {} }; struct Macro : gdr::Replay { @@ -81,7 +81,7 @@ struct Macro : gdr::Replay { void saveExtension(binary_writer& writer) const override; std::string getBotVersionString() const { - return xdBotVersion; + return getModVersionString(); } LegacyMacro toLegacy() const; diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index c04e0eee..b2be200a 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -146,9 +146,15 @@ class $modify(CCScheduler) { }; bool Renderer::shouldUseAPI() { - // ffmpeg api is not ported - return false; - + #ifdef GEODE_IS_WINDOWS + bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); + std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); + bool foundExe = std::filesystem::exists(ffmpegPath) && geode::utils::string::pathToString(ffmpegPath.filename()) == "ffmpeg.exe"; + + return !foundExe && foundApi; + #else + return true; + #endif } bool Renderer::toggle() { @@ -176,7 +182,7 @@ bool Renderer::toggle() { std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); bool foundExe = std::filesystem::exists(ffmpegPath) && geode::utils::string::pathToString(ffmpegPath.filename()) == "ffmpeg.exe"; - g.renderer.usingApi = false; + g.renderer.usingApi = Renderer::shouldUseAPI(); if (g.renderer.recording || g.renderer.recordingAudio) { g.renderer.recordingAudio ? g.renderer.stopAudio() : g.renderer.stop(Global::getCurrentFrame()); @@ -201,8 +207,12 @@ bool Renderer::toggle() { g.renderer.ffmpegPath = geode::utils::string::pathToString(ffmpegPath); #else - FLAlertLayer::create("Error", "Rendering is not supported on this platform yet.", "OK")->show(); - return false; + bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); + if (!foundApi) { + FLAlertLayer::create("Error", "FFmpeg API is required for rendering on this platform.", "OK")->show(); + return false; + } + g.renderer.usingApi = true; #endif if (!PlayLayer::get()) { @@ -239,7 +249,7 @@ void Renderer::start() { Mod* mod = Mod::get(); fmod = FMODAudioEngine::sharedEngine(); - fps = geode::utils::numFromString(mod->getSavedValue("render_fps")).unwrap(); + fps = geode::utils::numFromString(mod->getSavedValue("render_fps")).unwrapOr(60); codec = mod->getSavedValue("render_codec"); bitrate = mod->getSavedValue("render_bitrate") + "M"; extraArgs = mod->getSavedValue("render_args"); diff --git a/src/ui/macro_info_layer.hpp b/src/ui/macro_info_layer.hpp index ecfc4d6d..1c7fdba6 100644 --- a/src/ui/macro_info_layer.hpp +++ b/src/ui/macro_info_layer.hpp @@ -179,7 +179,7 @@ class MacroInfoLayer : public geode::Popup { lbl->setOpacity(150); m_mainLayer->addChild(lbl); - lbl = CCLabelBMFont::create((g.macro.botInfo.name + " v" + geode::utils::numToString(g.macro.botInfo.version)).c_str(), "chatFont.fnt"); + lbl = CCLabelBMFont::create((g.macro.botInfo.name + " " + getModVersionString()).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->limitLabelWidth(271.f, 0.475, 0.01f); lbl->updateLabel(); diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 6c6bf86c..5b7441d7 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -7,6 +7,7 @@ #include "autoclicker_settings_layer.hpp" #include "trajectory_settings_layer.hpp" #include "mirror_settings_layer.hpp" +#include "../gdr/gdr.hpp" #include "../hacks/coin_finder.hpp" #include "../hacks/show_trajectory.hpp" @@ -260,17 +261,17 @@ class $modify(PauseLayer) { } void RecordLayer::toggleRender(CCObject* btn) { -#ifdef GEODE_IS_WINDOWS + #ifdef GEODE_IS_WINDOWS if (!Renderer::toggle()) - static_cast(btn)->toggle(true); - + static_cast(btn)->toggle(true); + if (Global::get().renderer.recordingAudio) - static_cast(btn)->toggle(false); -#else + static_cast(btn)->toggle(false); + #else toggleRender2(btn); -#endif + #endif } - + void RecordLayer::toggleRender2(CCObject* btn) { FLAlertLayer::create("Info", "Rendering is not supported on your platform due to technical limitations.", "OK")->show(); } @@ -520,7 +521,9 @@ class $modify(PauseLayer) { } void RecordLayer::showCodecPopup(CCObject*) { + #ifdef GEODE_IS_WINDOWS FLAlertLayer::create("Codec", "AMD: h264_amf\nNVIDIA: h264_nvenc\nINTEL: h264_qsv\nI don't know: libx264", "OK")->show(); + #endif } void RecordLayer::updateDots() { @@ -586,7 +589,7 @@ class $modify(PauseLayer) { CCSprite* spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); CCSprite* spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); - CCLabelBMFont* versionLabel = CCLabelBMFont::create(("xdBot " + xdBotVersion).c_str(), "chatFont.fnt"); + CCLabelBMFont* versionLabel = CCLabelBMFont::create(("xdBot " + getModVersionString()).c_str(), "chatFont.fnt"); versionLabel->setOpacity(63); versionLabel->setPosition(ccp(-217, -125)); versionLabel->setAnchorPoint({ 0, 0.5 }); @@ -913,12 +916,12 @@ class $modify(PauseLayer) { bg->setZOrder(29); menu->addChild(bg); - #ifdef GEODE_IS_WINDOWS + #ifndef GEODE_IS_IOS ButtonSprite* spriteOn2 = ButtonSprite::create("Stop"); spriteOn2->setScale(0.74f); ButtonSprite* spriteOff2 = ButtonSprite::create("Start"); spriteOff2->setScale(0.74f); - + renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRender)); renderToggle->toggle(g.renderer.recording || g.renderer.recordingAudio); renderToggle->setPosition(ccp(-65.5, -100)); @@ -928,7 +931,7 @@ class $modify(PauseLayer) { spriteOn2->setScale(0.74f); ButtonSprite* spriteOff2 = ButtonSprite::create("N/A"); spriteOff2->setScale(0.74f); - + renderToggle = CCMenuItemToggler::create(spriteOn2, spriteOff2, this, menu_selector(RecordLayer::toggleRender2)); renderToggle->setPosition(ccp(-65.5, -100)); menu->addChild(renderToggle); From f4017e7c2f43db8a289d7099748ffe5d326b5304 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 3 Mar 2026 00:43:00 +0300 Subject: [PATCH 111/211] tps bypass but it's now physics bypass --- CMakeLists.txt | 3 +- src/hacks/tps_bypass.cpp | 399 ++++++++++++++++++++++--- src/includes.hpp | 19 ++ src/macro.cpp | 13 +- src/ui/record_layer.cpp | 19 +- src/utils/assembler.hpp | 612 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 1001 insertions(+), 64 deletions(-) create mode 100644 src/utils/assembler.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 91707945..626431b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,8 +51,9 @@ endif() add_subdirectory($ENV{GEODE_SDK} ${CMAKE_CURRENT_BINARY_DIR}/geode) CPMAddPackage("gh:prevter/msgpack-for-matjson#16a7957") +CPMAddPackage("gh:prevter/sinaps#b9c3434") CPMAddPackage("gh:maxnut/GDReplayFormat#72078e5") CPMAddPackage("gh:maxnut/GDR-converter#71104a9") -target_link_libraries(${PROJECT_NAME} libGDR GDRconverter) +target_link_libraries(${PROJECT_NAME} sinaps libGDR GDRconverter) setup_geode_mod(${PROJECT_NAME}) diff --git a/src/hacks/tps_bypass.cpp b/src/hacks/tps_bypass.cpp index a8f8ab22..24544bf4 100644 --- a/src/hacks/tps_bypass.cpp +++ b/src/hacks/tps_bypass.cpp @@ -1,66 +1,373 @@ #include "../includes.hpp" -#include +#include "../utils/assembler.hpp" -class $modify(GJBaseGameLayer) { +#include +#include - void update(float dt) { - auto& g = Global::get(); +#include - if (!g.tpsEnabled) return GJBaseGameLayer::update(dt); - if (Global::getTPS() == 240.f) return GJBaseGameLayer::update(dt); - if (!PlayLayer::get()) return GJBaseGameLayer::update(dt); - - float newDt = 1.f / Global::getTPS(); +#ifdef GEODE_IS_WINDOWS +#include +#endif - if (g.frameStepper) return GJBaseGameLayer::update(newDt); +#ifdef GEODE_IS_MACOS +#define REQUIRE_MODIFIED_DELTA_PATCH +#elif defined(GEODE_IS_ANDROID) +#include +#endif - float realDt = dt + g.leftOver; - if (realDt > dt && newDt < dt) realDt = dt; +using TicksType = +GEODE_WINDOWS(uint32_t) +GEODE_ANDROID64(uint32_t) +GEODE_ANDROID32(float) +GEODE_IOS(float) +GEODE_ARM_MAC(float) +GEODE_INTEL_MAC(float); - auto startTime = std::chrono::high_resolution_clock::now(); - int mult = static_cast(realDt / newDt); +static TicksType g_expectedTicks = 0; +#ifdef GEODE_IS_IOS +// iOS launcher has a secret space to store data, and it's located at 0x8b8000 +// 8 bytes are reserved for geode itself, so we can just skip 8 bytes +constexpr uintptr_t g_jitlessSpace = 0x8c4008; // omg boob :o +static TicksType* g_expectedTicksPtr = &g_expectedTicks; - for (int i = 0; i < mult; ++i) { - GJBaseGameLayer::update(newDt); - if (std::chrono::high_resolution_clock::now() - startTime > std::chrono::duration(16.666f)) { - mult = i + 1; - break; - } - } +TicksType& expectedTicks() { return *g_expectedTicksPtr; } +#else +TicksType& expectedTicks() { return g_expectedTicks; } +#endif - g.leftOver += (dt - newDt * mult); - +size_t getBaseSize() { + #ifdef GEODE_IS_WINDOWS + MODULEINFO info; + if (GetModuleInformation(GetCurrentProcess(), GetModuleHandle(nullptr), &info, sizeof(info))) { + return info.SizeOfImage; } + #endif + return 0x8000000; // 128MB fallback +} - float getModifiedDelta(float dt) { - if (!Global::get().tpsEnabled) return GJBaseGameLayer::getModifiedDelta(dt); - if (Global::getTPS() == 240.f) return GJBaseGameLayer::getModifiedDelta(dt); - if (!PlayLayer::get()) return GJBaseGameLayer::getModifiedDelta(dt); +double getActualProgress(PlayLayer* pl) { + if (!pl->m_level) return 0.0; + if (pl->m_level->m_timestamp <= 0) return 0.0; + + double totalTime = pl->m_level->m_timestamp / 240.0; + if (totalTime == 0.0) return 0.0; + + return (pl->m_gameState.m_levelTime / totalTime) * 100.0; +} - double dVar1; - float fVar2; - float fVar3; - double dVar4; +#ifdef REQUIRE_MODIFIED_DELTA_PATCH - float newDt = 1.f / Global::getTPS(); +// function to quickly get the bytes for the patch +[[nodiscard]] static std::vector TPStoBytes() { + return geode::toBytes(1.0 / static_cast(Global::get().getTPS())); +} + +geode::Result<> setupModifiedDeltaPatches() { + auto base = reinterpret_cast(geode::base::get()); + auto moduleSize = getBaseSize(); + + using namespace sinaps::mask; + + #ifdef GEODE_IS_INTEL_MAC + // on x86, we need to replace two values that are used in GJBaseGameLayer::getModifiedDelta + // pretty simple, just find original values and replace them with raw bytes + // UPD 2.2081: float value is no longer there, so only patch double value + + auto addr = sinaps::find>(base, moduleSize); + if (addr == sinaps::not_found) { + return geode::Err("failed to find getModifiedDelta patch address"); + } + + auto patchRes = geode::Mod::get()->patch(addr + base, TPStoBytes()); + if (!patchRes) return geode::Err(fmt::format("failed to patch address: {}", patchRes.unwrapErr())); + auto patch = patchRes.unwrap(); + (void) patch->disable(); + + // update bytes on value change + Global::get().onTpsChanged = [patch](double) { + patch->updateBytes(TPStoBytes()); + }; + + auto setState = [patch](bool state) { (void) patch->toggle(state); }; + + #elif defined(GEODE_IS_ARM_MAC) + // on ARM, the value is stored as immediate, with some encoding: + // 0x0000000100122C54: E9 E3 00 B2 orr x9, xzr, #0x1111111111111111 + // 0x0000000100122C58: 29 EE E7 F2 movk x9, #0x3f71, lsl #48 + // + // this makes it kinda hard to inject any value we want, so instead we're going to store it + // in a GJBaseGameLayer member, load it with one instruction and then restore it in the closest hook + // + // i'm using `GJGameLoadingLayer* m_loadingLayer`, because it's not used anywhere apart from open/exit sequence, + // and should be fine for our use case. since it's a pointer, we can store double right in it + // (good luck whoever's going to dereference it lol) + + auto addr = sinaps::find<"E9 E3 00 B2 29 EE E7 F2">(base, moduleSize); + if (addr == sinaps::not_found) { + return geode::Err("failed to find getModifiedDelta patch address"); + } + + using namespace assembler::arm64; + auto bytes = Builder(addr) + .ldr(Register::x9, Register::x19, offsetof(GJBaseGameLayer, m_loadingLayer)) + .nop() + .build(); + + auto patchRes = geode::Mod::get()->patch(addr + base, std::move(bytes)); + if (!patchRes) return geode::Err(fmt::format("failed to patch address: {}", patchRes.unwrapErr())); + auto patch = patchRes.unwrap(); + (void) patch->disable(); + + auto setState = [patch](bool state) { (void) patch->toggle(state); }; + #endif + + // update patches on enable/disable + Global::get().onTpsEnabledChanged = [setState](bool enabled) { + setState(enabled); + }; + + // apply initial state + setState(Global::get().tpsEnabled); + + return geode::Ok(); +} +#endif + +void applyPatches() { + #ifdef GEODE_IS_IOS + if (geode::Loader::get()->isPatchless()) { + using namespace assembler::arm64; + g_expectedTicksPtr = std::bit_cast(geode::base::get() + g_jitlessSpace); + static_assert(GEODE_COMP_GD_VERSION == 22081, "TPS Bypass: JIT-less patch is only supported for GD 2.2081"); + #define PATCH_ADDR 0x1fe724 + GEODE_MOD_STATIC_PATCH(PATCH_ADDR, Builder() + .adrp(Register::x9, g_jitlessSpace - ((PATCH_ADDR >> 12) << 12)) + .ldr(FloatRegister::s0, Register::x9, 0x8) + .pad_nops(40) + .build_array<40>()); + } else { + // we can do normal patches with JIT + #endif + + auto base = reinterpret_cast(geode::base::get()); + auto baseSize = getBaseSize(); - if (0 < m_resumeTimer) { - // cocos2d::CCDirector::sharedDirector(); - m_resumeTimer--; - dt = 0.0; + // this patch allows us to manually set the expected amount of ticks per update call + intptr_t addr = sinaps::not_found; + std::vector bytes; + #ifdef GEODE_IS_WINDOWS + { + using namespace x86_64; + // 2.2074: 0x232294 + // 2.2081: 0x237a55 + addr = sinaps::find<"FF 90 ? ? ? ? ^ F3 0F 10 ? ? ? ? ? F3 44 0F 10 ? ? ? ? 00 F3 41 0F 5D">(base, baseSize); + if (addr != sinaps::not_found) { + bytes = Builder(addr) + .movabs(x86_64::Register64::rax, std::bit_cast(&g_expectedTicks)) + .mov(Register32::r11d, Register64::rax) + .jmp(addr + 0x43, true) + .nop(4) + .build(); + } } - - fVar2 = 1.0; - if (m_gameState.m_timeWarp <= 1.0) { - fVar2 = m_gameState.m_timeWarp; + #elif defined(GEODE_IS_ANDROID64) + { + using namespace arm64; + // 2.2074: 0x87dA40 (google) / 0x87be28 (amazon) + // 2.2081: 0x89d9f4 + auto func = dlsym(RTLD_DEFAULT, "_ZN15GJBaseGameLayer6updateEf"); + addr = sinaps::find<"AB 19 60 1E 0A 10 62 1E 6A 09 6A 1E">(static_cast(func), 0x500); + if (addr != sinaps::not_found) { + addr += reinterpret_cast(func) - reinterpret_cast(base); // we need offset from the base + bytes = Builder(addr) + .mov(Register::x9, std::bit_cast(&g_expectedTicks)) + .ldr(Register::w0, Register::x9) + .b(addr + 0x28, true) + .build(); + } + } + #elif defined(GEODE_IS_ANDROID32) + { + using namespace armv7; + // 2.2074: 0x4841bc (google) / 0x483f0c (amazon) + // 2.2081: 0x49725c + auto func = dlsym(RTLD_DEFAULT, "_ZN15GJBaseGameLayer6updateEf"); + addr = sinaps::find<"EE ? ? ? EE ? ? ^ F7 EE ? 7B 17 EE 90 0A">(static_cast(func), 0x500); + if (addr != sinaps::not_found) { + addr += reinterpret_cast(func) - reinterpret_cast(base); // we need offset from the base + bytes = Builder(addr) + .mov(Register::r1, std::bit_cast(&g_expectedTicks)) + .ldr_t(Register::r0, Register::r1) + .nop_t() + .build(); + } + } + #elif defined(GEODE_IS_IOS) || defined(GEODE_IS_ARM_MAC) // lucky me, they're virtually the same + { + using namespace arm64; + // 2.2074: 0x200c30 (iOS) / 0x119454 (macOS) + // 2.2081: 0x1fe724 (iOS) / 0x122d44 (macOS) + addr = sinaps::find<"01 10 2E 1E 00 20 21 1E 20 AC 20 1E">(base, baseSize); + if (addr != sinaps::not_found) { + bytes = Builder(addr) + .mov(Register::x9, std::bit_cast(&g_expectedTicks)) + .ldr(FloatRegister::s0, Register::x9) + .pad_nops(40) // we need to replace 40 bytes, but mov can take 3-4 instructions depending on address + .build(); + } + } + #elif defined(GEODE_IS_INTEL_MAC) + { + using namespace x86_64; + // 2.2074: 0x14233e + // 2.2081: 0x1516c4 + addr = sinaps::find<"0F 28 ? F3 0F 5D 83 ? ? ? ? F3 0F ? ? F2 0F 10">(base, baseSize); + if (addr != sinaps::not_found) { + bytes = Builder(addr) + .movabs(Register64::rax, std::bit_cast(&g_expectedTicks)) + .movss(XmmRegister::xmm0, Register64::rax) + .jmp(addr + 0x49, true) + .build(); + } } + #endif + + if (addr == sinaps::not_found || bytes.empty()) { + geode::log::error("TPS Bypass: Failed to find patch address or bytes"); + return; + } + + geode::Patch* patch = nullptr; + if (auto res = geode::Mod::get()->patch(reinterpret_cast(addr + base), bytes)) { + patch = res.unwrap(); + geode::log::info("TPS Bypass: Patch enabled at offset 0x{:X}", addr); + } else { + geode::log::error("TPS Bypass: Failed to patch GJBaseGameLayer::update: {}", res.unwrapErr()); + return; + } + + // patch toggler + if (patch) { + // toggle the patch if enabled + Global::get().onTpsEnabledChanged = [patch](bool enabled) { + (void)patch->toggle(enabled); + }; + + // set the initial state of the patch + (void)patch->toggle(Global::get().tpsEnabled); + } + + // on macOS, we also have to patch instructions in GJBaseGameLayer::getModifiedDelta because it's inlined + #ifdef REQUIRE_MODIFIED_DELTA_PATCH + auto res = setupModifiedDeltaPatches(); + if (!res) { + geode::log::error("TPSBypass: {}", res.unwrapErr()); + } + #endif + + #ifdef GEODE_IS_IOS + } // closes the `if (geode::Loader::get()->isPatchless()) { ... } else {` block + #endif +} - dVar1 = dt + m_extraDelta; - fVar3 = std::round(dVar1 / (fVar2 * newDt)); - dVar4 = fVar3 * fVar2 * newDt; - m_extraDelta = dVar1 - dVar4; +$execute { + applyPatches(); +} - return dVar4; +class $modify(TPSBypassGJBGLHook, GJBaseGameLayer) { + + struct Fields { + double m_extraDelta = 0.0; + }; + + double getCustomDelta(float dt, double tps, bool applyExtraDelta = true) { + auto spt = 1.0 / tps; + + if (applyExtraDelta && m_resumeTimer > 0) { + --m_resumeTimer; + dt = 0.f; + } + + auto totalDelta = dt + m_fields->m_extraDelta; + auto timestep = std::min(m_gameState.m_timeWarp, 1.f) * spt; + auto steps = std::round(totalDelta / timestep); + auto newDelta = steps * timestep; + if (applyExtraDelta) m_fields->m_extraDelta = totalDelta - newDelta; + return newDelta; } + + #ifndef REQUIRE_MODIFIED_DELTA_PATCH + double getModifiedDelta(float dt) { + return getCustomDelta(dt, static_cast(Global::get().getTPS())); + } + #endif + + void update(float dt) override { + auto fields = m_fields.self(); + fields->m_extraDelta += dt; + + // calculate number of steps based on the new TPS + auto timeWarp = std::min(m_gameState.m_timeWarp, 1.f); + + auto newTPS = static_cast(Global::get().getTPS()) / timeWarp; + + auto spt = 1.0 / newTPS; + auto steps = std::round(fields->m_extraDelta / spt); + auto totalDelta = steps * spt; + fields->m_extraDelta -= totalDelta; + expectedTicks() = static_cast(steps); + + #ifdef GEODE_IS_ARM_MAC + // we're a bit silly here: + auto originalLoadingLayer = m_loadingLayer; + this->m_loadingLayer = std::bit_cast(1.0 / static_cast(Global::get().getTPS())); + #endif + + GJBaseGameLayer::update(totalDelta); + + #ifdef GEODE_IS_ARM_MAC + this->m_loadingLayer = originalLoadingLayer; + #endif + } +}; -}; \ No newline at end of file +class $modify(TPSBypassPLHook, PlayLayer) { + + // we would like to fix the percentage calculation, which uses constant 240 TPS to determine the progress + int calculationFix() { + auto timestamp = m_level->m_timestamp; + auto currentProgress = m_gameState.m_currentProgress; + // this is only an issue for 2.2+ levels (with TPS greater than 240) + if (timestamp > 0 && Global::get().getTPS() != 240.f) { + // recalculate m_currentProgress based on the actual time passed + auto progress = getActualProgress(this); + m_gameState.m_currentProgress = timestamp * progress / 100.f; + } + return currentProgress; + } + + void updateProgressbar() { + auto currentProgress = calculationFix(); + PlayLayer::updateProgressbar(); + m_gameState.m_currentProgress = currentProgress; + } + + void destroyPlayer(PlayerObject* player, GameObject* object) override { + auto currentProgress = calculationFix(); + PlayLayer::destroyPlayer(player, object); + m_gameState.m_currentProgress = currentProgress; + } + + void levelComplete() { + // levelComplete uses m_gameState.m_unkUint2 to store the timestamp + // also we can't rely on m_level->m_timestamp, because it might not be updated yet + auto oldTimestamp = m_gameState.m_commandIndex; + if (Global::get().getTPS() != 240.f) { + auto ticks = static_cast(std::round(m_gameState.m_levelTime * 240)); + m_gameState.m_commandIndex = ticks; + } + PlayLayer::levelComplete(); + m_gameState.m_commandIndex = oldTimestamp; + } +}; diff --git a/src/includes.hpp b/src/includes.hpp index 6e95ec05..d56219f7 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "renderer/renderer.hpp" #include "macro.hpp" @@ -137,6 +138,24 @@ class Global { bool stopPlaying = false; bool tpsEnabled = false; float tps = 240.f; + + // Callbacks for TPS settings changes (used instead of listenForSettingChanges) + std::function onTpsEnabledChanged; + std::function onTpsChanged; + + // Setters that trigger callbacks + void setTpsEnabled(bool enabled) { + tpsEnabled = enabled; + mod->setSavedValue("macro_tps_enabled", enabled); + if (onTpsEnabledChanged) onTpsEnabledChanged(enabled); + } + + void setTps(float newTps) { + tps = newTps; + mod->setSavedValue("macro_tps", static_cast(newTps)); + if (onTpsChanged) onTpsChanged(static_cast(newTps)); + } + bool previousTpsEnabled = false; float previousTps = 0.f; bool autoclicker = false; diff --git a/src/macro.cpp b/src/macro.cpp index bedd6dc4..fc2dec92 100644 --- a/src/macro.cpp +++ b/src/macro.cpp @@ -129,19 +129,14 @@ void Macro::updateTPS() { g.previousTpsEnabled = g.tpsEnabled; g.previousTps = g.tps; - g.tpsEnabled = g.macro.framerate != 240.f; - if (g.tpsEnabled) g.tps = g.macro.framerate; - - g.mod->setSavedValue("macro_tps", g.tps); - g.mod->setSavedValue("macro_tps_enabled", g.tpsEnabled); + g.setTpsEnabled(g.macro.framerate != 240.f); + if (g.tpsEnabled) g.setTps(g.macro.framerate); } else if (g.previousTps != 0.f) { - g.tpsEnabled = g.previousTpsEnabled; - g.tps = g.previousTps; + g.setTpsEnabled(g.previousTpsEnabled); + g.setTps(g.previousTps); g.previousTps = 0.f; - g.mod->setSavedValue("macro_tps", g.tps); - g.mod->setSavedValue("macro_tps_enabled", g.tpsEnabled); } if (g.layer) static_cast(g.layer)->updateTPS(); diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 5b7441d7..9d130a5b 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -32,7 +32,7 @@ const std::vector> settings { { "Auto Safe Mode:", "macro_auto_safe_mode", InputType::None } }, { - #ifdef GEODE_IS_WINDOWS + #ifdef GEODE_IS_DESKTOP { "Force cursor on open:", "menu_show_cursor", InputType::None }, { "Button on pause menu:", "menu_show_button", InputType::None }, { "Pause on open:", "menu_pause_on_open", InputType::None }, @@ -148,10 +148,14 @@ class $modify(PauseLayer) { if (!pl->m_isPaused) pl->pauseGame(false); } - #ifdef GEODE_IS_WINDOWS - else if (pl && g.mod->getSavedValue("menu_show_cursor")) { - cursor = cocos2d::CCEGLView::sharedOpenGLView()->getShouldHideCursor(); - cocos2d::CCEGLView::sharedOpenGLView()->showCursor(true); + #ifdef GEODE_IS_DESKTOP + else if (pl) { + bool value = g.mod->getSavedValue("menu_show_cursor"); + auto gm = GameManager::sharedState(); + + if (gm->getGameVariable(GameVar::ShowCursor) != value) { + gm->setGameVariable(GameVar::ShowCursor, value); + } } #endif @@ -354,8 +358,7 @@ class $modify(PauseLayer) { if (tpsInput && node == tpsInput) { float value = geode::utils::numFromString(tpsInput->getString()).unwrapOr(0.f); if (std::string_view(tpsInput->getString()) != "" && value < 999999 && value >= 0.f) { - mod->setSavedValue("macro_tps", value); - Global::get().tps = value; + Global::get().setTps(value); Global::get().leftOver = 0.f; } } @@ -402,7 +405,7 @@ class $modify(PauseLayer) { if (id == "clickbot_enabled") g.clickbotEnabled = value; if (id == "clickbot_playing_only") g.clickbotOnlyPlaying = value; if (id == "clickbot_holding_only") g.clickbotOnlyHolding = value; - if (id == "macro_tps_enabled") g.tpsEnabled = value; + if (id == "macro_tps_enabled") g.setTpsEnabled(value); if (id == "autoclicker_enabled") g.autoclicker = value; if (id == "disable_shaders") g.disableShaders = value; if (id == "macro_auto_save") g.autosaveEnabled = value; diff --git a/src/utils/assembler.hpp b/src/utils/assembler.hpp new file mode 100644 index 00000000..1d356ac0 --- /dev/null +++ b/src/utils/assembler.hpp @@ -0,0 +1,612 @@ +#pragma once +#include +#include +#include + +namespace x86_64 { + enum class Register64 : uint8_t { + rax = 0, rcx = 1, rdx = 2, rbx = 3, + rsp = 4, rbp = 5, rsi = 6, rdi = 7, + r8 = 8, r9 = 9, r10 = 10, r11 = 11, + r12 = 12, r13 = 13, r14 = 14, r15 = 15 + }; + + enum class Register32 : uint8_t { + eax = 0, ecx = 1, edx = 2, ebx = 3, + esp = 4, ebp = 5, esi = 6, edi = 7, + r8d = 8, r9d = 9, r10d = 10, r11d = 11, + r12d = 12, r13d = 13, r14d = 14, r15d = 15 + }; + + enum class XmmRegister : uint8_t { + xmm0 = 0, xmm1 = 1, xmm2 = 2, xmm3 = 3, + xmm4 = 4, xmm5 = 5, xmm6 = 6, xmm7 = 7, + xmm8 = 8, xmm9 = 9, xmm10 = 10, xmm11 = 11, + xmm12 = 12, xmm13 = 13, xmm14 = 14, xmm15 = 15, + }; + + /// @brief movabs r64, imm64: Move a 64-bit immediate value to a register. + constexpr std::array movabs(Register64 dst, uint64_t imm) { + uint8_t rex = 0x48; + if (static_cast(dst) >= 8) + rex |= 0x01; + + uint8_t opcode = 0xB8 + (static_cast(dst) & 0x7); + return { + rex, + opcode, + static_cast(imm & 0xFF), + static_cast((imm >> 8) & 0xFF), + static_cast((imm >> 16) & 0xFF), + static_cast((imm >> 24) & 0xFF), + static_cast((imm >> 32) & 0xFF), + static_cast((imm >> 40) & 0xFF), + static_cast((imm >> 48) & 0xFF), + static_cast((imm >> 56) & 0xFF), + }; + } + + /// @brief mov r32, dword ptr [reg]: Load a 32-bit value from address stored in a register. + constexpr std::array mov(Register32 dst, Register64 src) { + uint8_t rex = 0x40; + if (static_cast(dst) >= 8) + rex |= 0x04; + if (static_cast(src) >= 8) + rex |= 0x01; + + uint8_t modrm = (static_cast(dst) & 0x7) << 3; + modrm |= (static_cast(src) & 0x7); + + return {rex, 0x8B, modrm}; + } + + /// @brief jmp rel32: Jump to a relative address. + constexpr std::array jmp(int32_t rel) { + return { + 0xE9, + static_cast(rel & 0xFF), + static_cast((rel >> 8) & 0xFF), + static_cast((rel >> 16) & 0xFF), + static_cast((rel >> 24) & 0xFF) + }; + } + + /// @brief movss xmm, dword ptr [r64]: Move scalar single-precision floating-point from memory to XMM register + constexpr std::array movss(XmmRegister dst, Register64 src) { + uint8_t rex = 0x40; + if (static_cast(dst) >= 8) + rex |= 0x04; // REX.R bit for destination register extension + if (static_cast(src) >= 8) + rex |= 0x01; // REX.B bit for source register extension + + uint8_t modrm = (static_cast(dst) & 0x7) << 3; + modrm |= (static_cast(src) & 0x7); + + return {0xF3, rex, 0x0F, 0x10, modrm}; + } + + class Builder { + public: + constexpr Builder() = default; + explicit constexpr Builder(uintptr_t baseAddress) : m_baseAddress(baseAddress) {} + + constexpr Builder& movabs(Register64 dst, uint64_t imm) { + auto bytes = x86_64::movabs(dst, imm); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr Builder& mov(Register32 dst, Register64 src) { + auto bytes = x86_64::mov(dst, src); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr Builder& jmp(int32_t offset, bool relative = false) { + // If relative is true, offset is the absolute address, and we calculate the relative jump. + if (relative) offset -= m_baseAddress + m_bytes.size() + 5; // 5 is the size of the jmp instruction + auto bytes = x86_64::jmp(offset); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr Builder& nop(size_t count = 1) { + m_bytes.insert(m_bytes.end(), count, 0x90); + return *this; + } + + constexpr Builder& movss(XmmRegister dst, Register64 src) { + auto bytes = x86_64::movss(dst, src); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr std::vector build() { return std::move(m_bytes); } + + template + consteval std::array build_array() { + if (m_bytes.size() != N) throw std::runtime_error("Size mismatch!"); + + std::array result{}; + std::copy(m_bytes.begin(), m_bytes.end(), result.begin()); + return result; + } + + private: + uintptr_t m_baseAddress = 0; + std::vector m_bytes; + }; +} + +namespace arm64 { + enum class Register { + x0 = 0b00000, w0 = 0b100000, + x1 = 0b00001, w1 = 0b100001, + x2 = 0b00010, w2 = 0b100010, + x3 = 0b00011, w3 = 0b100011, + x4 = 0b00100, w4 = 0b100100, + x5 = 0b00101, w5 = 0b100101, + x6 = 0b00110, w6 = 0b100110, + x7 = 0b00111, w7 = 0b100111, + x8 = 0b01000, w8 = 0b101000, + x9 = 0b01001, w9 = 0b101001, + x10 = 0b01010, w10 = 0b101010, + x11 = 0b01011, w11 = 0b101011, + x12 = 0b01100, w12 = 0b101100, + x13 = 0b01101, w13 = 0b101101, + x14 = 0b01110, w14 = 0b101110, + x15 = 0b01111, w15 = 0b101111, + x16 = 0b10000, w16 = 0b110000, + x17 = 0b10001, w17 = 0b110001, + x18 = 0b10010, w18 = 0b110010, + x19 = 0b10011, w19 = 0b110011, + x20 = 0b10100, w20 = 0b110100, + x21 = 0b10101, w21 = 0b110101, + x22 = 0b10110, w22 = 0b110110, + x23 = 0b10111, w23 = 0b110111, + x24 = 0b11000, w24 = 0b111000, + x25 = 0b11001, w25 = 0b111001, + x26 = 0b11010, w26 = 0b111010, + x27 = 0b11011, w27 = 0b111011, + x28 = 0b11100, w28 = 0b111100, + x29 = 0b11101, w29 = 0b111101, + x30 = 0b11110, w30 = 0b111110, + x31 = 0b11111, w31 = 0b111111, + + pc = 0b11110, + sp = 0b11111 + }; + + enum class FloatRegister { + s0 = 0b00000, d0 = 0b100000, + s1 = 0b00001, d1 = 0b100001, + s2 = 0b00010, d2 = 0b100010, + s3 = 0b00011, d3 = 0b100011, + s4 = 0b00100, d4 = 0b100100, + s5 = 0b00101, d5 = 0b100101, + s6 = 0b00110, d6 = 0b100110, + s7 = 0b00111, d7 = 0b100111, + s8 = 0b01000, d8 = 0b101000, + s9 = 0b01001, d9 = 0b101001, + s10 = 0b01010, d10 = 0b101010, + s11 = 0b01011, d11 = 0b101011, + s12 = 0b01100, d12 = 0b101100, + s13 = 0b01101, d13 = 0b101101, + s14 = 0b01110, d14 = 0b101110, + s15 = 0b01111, d15 = 0b101111, + s16 = 0b10000, d16 = 0b110000, + s17 = 0b10001, d17 = 0b110001, + s18 = 0b10010, d18 = 0b110010, + s19 = 0b10011, d19 = 0b110011, + s20 = 0b10100, d20 = 0b110100, + s21 = 0b10101, d21 = 0b110101, + s22 = 0b10110, d22 = 0b110110, + s23 = 0b10111, d23 = 0b110111, + s24 = 0b11000, d24 = 0b111000, + s25 = 0b11001, d25 = 0b111001, + s26 = 0b11010, d26 = 0b111010, + s27 = 0b11011, d27 = 0b111011, + s28 = 0b11100, d28 = 0b111100, + s29 = 0b11101, d29 = 0b111101, + s30 = 0b11110, d30 = 0b111110, + s31 = 0b11111, d31 = 0b111111 + }; + + constexpr bool is_w(Register reg) { return static_cast(reg) & 0b100000; } + constexpr int operator&(Register dst, int rhs) { return static_cast(dst) & rhs; } + constexpr int operator|(int lhs, Register dst) { return lhs | static_cast(dst); } + + constexpr bool is_d(FloatRegister reg) { return static_cast(reg) & 0b100000; } + constexpr int operator&(FloatRegister dst, int rhs) { return static_cast(dst) & rhs; } + constexpr int operator|(int lhs, FloatRegister dst) { return lhs | static_cast(dst); } + + /// @brief Form PC Relative Address: + /// Adds an immediate that is shifted left by 12 bits to the PC value. + constexpr std::array adrp(Register dst, uint64_t addr) { + uint32_t page = static_cast(addr >> 12); + uint32_t immlo = page & 0x3; + uint32_t immhi = (page >> 2) & 0x7FFFF; + uint8_t rd = dst & 0x1F; + + return { + static_cast(rd | ((immhi & 0x7) << 5)), + static_cast((immhi >> 3) & 0xFF), + static_cast((immhi >> 11) & 0xFF), + static_cast(0x90 | ((immlo & 0x3) << 5)) + }; + } + + /// @brief Add + /// Adds an immediate value to a register and stores the result in a destination register. + constexpr std::array add(Register dst, Register src, uint64_t imm) { + uint8_t rn = src & 0b11111; + uint8_t sf = is_w(dst) ? 0 : 1; + uint8_t sh = 0; + uint16_t imm12; + + if (imm <= 0xFFF) { + // number fits in 12 bits + imm12 = static_cast(imm); + sh = 0; + } else if ((imm & 0xFFF) == 0 && (imm >> 12) <= 0xFFF) { + // number can be represented as a 12-bit immediate with a shift + imm12 = static_cast(imm >> 12); + sh = 1; + } else { + // number doesn't fit, idk just use the lower 12 bits for now + imm12 = static_cast(imm & 0xFFF); + sh = 0; + } + + return { + static_cast((dst & 0b11111) | (rn << 5)), + static_cast((rn >> 3) | ((imm12 & 0x3F) << 2)), + static_cast(((imm12 >> 6) & 0x3F) | (sh << 6)), + static_cast(0x91 | (sf << 7)) + }; + } + + /// @brief Move with Zero: + /// Move a 16-bit immediate value to a register, with a left shift. + constexpr std::array movz(Register dst, uint16_t imm, uint8_t shift = 0) { + uint8_t sf = is_w(dst) ? 0 : 1; + uint8_t hw = shift / 16; + + return { + static_cast(((imm & 0b111) << 5) | (dst & 0b11111)), + static_cast(imm >> 3), + static_cast(0b10000000 | (hw << 5) | imm >> 11), + static_cast((sf << 7) | 0b1010010) + }; + } + + /// @brief Move wide with keep: + /// Move a 16-bit immediate value to a register, with a left shift, keeping the rest of the register. + constexpr std::array movk(Register dst, uint16_t imm, uint8_t shift = 0) { + uint8_t sf = is_w(dst) ? 0 : 1; + uint8_t hw = shift / 16; + + return { + static_cast(((imm & 0b111) << 5) | (dst & 0b11111)), + static_cast(imm >> 3), + static_cast(0b10000000 | (hw << 5) | imm >> 11), + static_cast((sf << 7) | 0b1110010) + }; + } + + /// @brief Load SIMD&FP Register with Immediate Offset: + /// LDR , [{, #}] - 32-bit variant + /// LDR
, [{, #}] - 64-bit variant + constexpr std::array ldr(FloatRegister rt, Register rn, uint16_t imm = 0) { + uint8_t size, opc; + uint8_t scale; + if (is_d(rt)) { + // Double precision (D register) - 64-bit + size = 0b11; + opc = 0b01; + scale = 3; + } else { + // Single precision (S register) - 32-bit + size = 0b10; + opc = 0b01; + scale = 2; + } + + uint16_t imm12 = imm >> scale; + uint8_t rt_bits = rt & 0b11111; + uint8_t rn_bits = rn & 0b11111; + + return { + static_cast(rt_bits | ((rn_bits & 0b111) << 5)), + static_cast((rn_bits >> 3) | ((imm12 & 0b1111111) << 2)), + static_cast(0b01000000 | ((imm12 >> 6) & 0b111111)), + static_cast((size << 6) | 0b111000 | (opc << 2) | 0b1) + }; + } + + /// @brief Load General Purpose Register with Immediate Offset: + /// LDR , [{, #}] - 32-bit variant + /// LDR , [{, #}] - 64-bit variant + constexpr std::array ldr(Register rt, Register rn, uint16_t imm = 0) { + uint8_t size, opc; + uint8_t scale; + + if (is_w(rt)) { + // 32-bit W register + size = 0b10; + opc = 0b00; + scale = 2; + } else { + // 64-bit X register + size = 0b11; + opc = 0b00; + scale = 3; + } + + uint16_t imm12 = imm >> scale; + uint8_t rt_bits = rt & 0b11111; + uint8_t rn_bits = rn & 0b11111; + + return { + static_cast(rt_bits | ((rn_bits & 0b111) << 5)), + static_cast((rn_bits >> 3) | ((imm12 & 0b1111111) << 2)), + static_cast(0b01000000 | ((imm12 >> 6) & 0b111111)), + static_cast((size << 6) | 0b111000 | (opc << 2) | 0b1) + }; + } + + /// @brief Branch with Immediate: + /// Branch to a relative address, with a signed 26-bit immediate value. + constexpr std::array b(int32_t offset) { + int32_t word_offset = offset >> 2; + uint32_t imm26 = static_cast(word_offset) & 0x3FFFFFF; + uint32_t instr = (0b000101 << 26) | imm26; + + return { + static_cast(instr & 0xFF), + static_cast((instr >> 8) & 0xFF), + static_cast((instr >> 16) & 0xFF), + static_cast((instr >> 24) & 0xFF) + }; + } + + /// @brief No Operation: + /// Instruction that does nothing, used for padding. + constexpr std::array nop() { + return {0x1F, 0x20, 0x03, 0xD5}; + } + + /// @brief Helper function to move a float to a register as an immediate value. Generates 2 instructions. + [[nodiscard]] inline std::array mov_float(Register dst, float imm) { + auto bytes = reinterpret_cast(&imm); + auto instr1 = movz(dst, *reinterpret_cast(bytes)); + auto instr2 = movk(dst, *reinterpret_cast(bytes + 2), 16); + return { + instr1[0], instr1[1], instr1[2], instr1[3], + instr2[0], instr2[1], instr2[2], instr2[3] + }; + } + + /// @brief Helper function to move a double value to a register as an immediate value. Generates 3 instructions. + [[nodiscard]] inline std::array mov_double(Register dst, double imm) { + uint64_t bits = *reinterpret_cast(&imm); + auto instr1 = movz(dst, static_cast(bits >> 16), 16); + auto instr2 = movk(dst, static_cast(bits >> 32), 32); + auto instr3 = movk(dst, static_cast(bits >> 48), 48); + return { + instr1[0], instr1[1], instr1[2], instr1[3], + instr2[0], instr2[1], instr2[2], instr2[3], + instr3[0], instr3[1], instr3[2], instr3[3] + }; + } + + class Builder { + public: + constexpr Builder() = default; + explicit constexpr Builder(uintptr_t baseAddress) : m_baseAddress(baseAddress) {} + + constexpr Builder& adrp(Register dst, uint64_t addr) { + auto bytes = arm64::adrp(dst, addr); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr Builder& add(Register dst, Register src, uint64_t imm) { + auto bytes = arm64::add(dst, src, imm); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr Builder& movz(Register dst, uint16_t imm, uint8_t shift = 0) { + auto bytes = arm64::movz(dst, imm, shift); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr Builder& movk(Register dst, uint16_t imm, uint8_t shift = 0) { + auto bytes = arm64::movk(dst, imm, shift); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr Builder& mov(Register dst, uint64_t imm) { + auto bytes = arm64::movz(dst, static_cast(imm & 0xFFFF)); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + if (imm > 0xFFFF) { + bytes = arm64::movk(dst, static_cast((imm >> 16) & 0xFFFF), 16); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + } + if (imm > 0xFFFFFFFF) { + bytes = arm64::movk(dst, static_cast((imm >> 32) & 0xFFFF), 32); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + } + if (imm > 0xFFFFFFFFFFFF) { + bytes = arm64::movk(dst, static_cast((imm >> 48) & 0xFFFF), 48); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + } + return *this; + } + + constexpr Builder& ldr(FloatRegister rt, Register rn, uint16_t imm = 0) { + auto bytes = arm64::ldr(rt, rn, imm); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr Builder& ldr(Register rt, Register rn, uint16_t imm = 0) { + auto bytes = arm64::ldr(rt, rn, imm); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr Builder& b(int32_t offset, bool relative = false) { + // If relative is true, offset is the absolute address, and we calculate the relative jump. + if (relative) offset -= m_baseAddress + m_bytes.size() + 4; + auto bytes = arm64::b(offset); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr Builder& nop(size_t count = 1) { + for (size_t i = 0; i < count; ++i) { + auto bytes = arm64::nop(); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + } + return *this; + } + + /// @brief Adds NOP instructions to make the total size of bytes equal to `byteCount`. + constexpr Builder& pad_nops(size_t byteCount) { + size_t currentSize = m_bytes.size(); + if (currentSize < byteCount) { + size_t nopsToAdd = (byteCount - currentSize + 3) / 4; // Each NOP is 4 bytes + this->nop(nopsToAdd); + } + return *this; + } + + constexpr std::vector build() { return std::move(m_bytes); } + + template + consteval std::array build_array() { + if (m_bytes.size() != N) throw std::runtime_error("Size mismatch!"); + + std::array result{}; + std::copy(m_bytes.begin(), m_bytes.end(), result.begin()); + return result; + } + + private: + uintptr_t m_baseAddress = 0; + std::vector m_bytes; + }; +} + +namespace armv7 { + enum class Register : uint8_t { + r0 = 0, r1 = 1, r2 = 2, r3 = 3, + r4 = 4, r5 = 5, r6 = 6, r7 = 7, + r8 = 8, r9 = 9, r10 = 10, r11 = 11, + r12 = 12, sp = 13, lr = 14, pc = 15 + }; + + /// @brief NOP instruction for Thumb-2 (ARMv7). 2 bytes. + constexpr std::array nop_t() { + return {0x00, 0xBF}; + } + + /// @brief NOP instruction for ARMv7. 4 bytes. + constexpr std::array nop() { + return {0x00, 0x00, 0xA0, 0xE3}; + } + + /// @brief MOV immediate (Thumb-2, 32-bit instruction) + /// MOVW , # - Move 16-bit immediate to register + constexpr std::array movw(Register rd, uint16_t imm16) { + uint8_t rd_bits = static_cast(rd) & 0xF; + uint8_t imm4 = (imm16 >> 12) & 0xF; + uint8_t i = (imm16 >> 11) & 1; + uint8_t imm3 = (imm16 >> 8) & 0x7; + uint8_t imm8 = imm16 & 0xFF; + + return { + static_cast(0x40 | imm4), + static_cast(0xF2 | (i << 2)), + imm8, + static_cast((imm3 << 4) | rd_bits), + }; + } + + /// @brief MOVT (Move Top) - Move 16-bit immediate to top half of register (Thumb-2, 32-bit instruction) + /// MOVT , # - Move immediate to bits [31:16], keeping bits [15:0] + constexpr std::array movt(Register rd, uint16_t imm16) { + uint8_t rd_bits = static_cast(rd) & 0xF; + uint8_t imm4 = (imm16 >> 12) & 0xF; + uint8_t i = (imm16 >> 11) & 1; + uint8_t imm3 = (imm16 >> 8) & 0x7; + uint8_t imm8 = imm16 & 0xFF; + + return { + static_cast(0xC0 | imm4), + static_cast(0xF2 | (i << 2)), + imm8, + static_cast((imm3 << 4) | rd_bits), + }; + } + + /// @brief LDR immediate (Thumb, 16-bit instruction) + /// LDR , [] - Load register from memory + constexpr std::array ldr(Register rt, Register rn) { + uint8_t rt_bits = static_cast(rt) & 0x7; + uint8_t rn_bits = static_cast(rn) & 0x7; + + return { + static_cast(rn_bits << 3), + static_cast(0x68 | rt_bits) + }; + } + + class Builder { + public: + constexpr Builder() = default; + constexpr explicit Builder(uintptr_t baseAddress) : m_baseAddress(baseAddress) {} + + constexpr Builder& mov(Register dst, uint32_t imm) { + auto bytes = armv7::movw(dst, static_cast(imm & 0xFFFF)); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + if (imm > 0xFFFF) { + bytes = armv7::movt(dst, static_cast((imm >> 16) & 0xFFFF)); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + } + return *this; + } + + constexpr Builder& ldr_t(Register rt, Register rn, uint16_t imm = 0) { + auto bytes = armv7::ldr(rt, rn); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + return *this; + } + + constexpr Builder& nop(size_t count = 1) { + for (size_t i = 0; i < count; ++i) { + auto bytes = armv7::nop(); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + } + return *this; + } + + constexpr Builder& nop_t(size_t count = 1) { + for (size_t i = 0; i < count; ++i) { + auto bytes = armv7::nop_t(); + m_bytes.insert(m_bytes.end(), bytes.begin(), bytes.end()); + } + return *this; + } + + std::vector build() { return std::move(m_bytes); } + + private: + uintptr_t m_baseAddress = 0; + std::vector m_bytes; + }; +} \ No newline at end of file From a4614a3cc98b63f0c107725d2333390c0880b525 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 3 Mar 2026 00:44:08 +0300 Subject: [PATCH 112/211] Revert "renderer on mobile" This reverts commit 8b1fdbe3904a7bb27567f7041d203373588210d4. --- .gitignore | 5 +---- src/gdr/gdr.hpp | 12 ++---------- src/global.cpp | 2 +- src/macro.cpp | 6 +++--- src/macro.hpp | 4 ++-- src/renderer/renderer.cpp | 24 +++++++----------------- src/ui/macro_info_layer.hpp | 2 +- src/ui/record_layer.cpp | 25 +++++++++++-------------- 8 files changed, 28 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index d6a55daa..2ffc61a4 100644 --- a/.gitignore +++ b/.gitignore @@ -67,7 +67,4 @@ build-*/ # CLion /cmake-build-*/ -build.sh - -eclipsemenu/ -ffmpeg-api/ \ No newline at end of file +build.sh \ No newline at end of file diff --git a/src/gdr/gdr.hpp b/src/gdr/gdr.hpp index e16c3484..ec17e407 100644 --- a/src/gdr/gdr.hpp +++ b/src/gdr/gdr.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include #include #include @@ -10,20 +8,14 @@ #include -inline std::string getModVersionString() { - return geode::Mod::get()->getVersion().toVString(); -} - -inline int getModVersionInt() { - return static_cast(geode::Mod::get()->getVersion().getMajor()); -} - geode::prelude::VersionInfo getVersion(std::vector nums); cocos2d::CCPoint dataFromString(std::string dataString); std::vector splitByChar(std::string str, char splitChar); +const std::string xdBotVersion = "v2.3.11"; + namespace gdr_legacy { using namespace nlohmann; diff --git a/src/global.cpp b/src/global.cpp index 52cfcc41..84ebc7e0 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -403,7 +403,7 @@ PauseLayer* Global::getPauseLayer() { g.mod->setSavedValue("render_video_args", std::string("")); if (!g.mod->setSavedValue("defaults_set_11", true)) - g.mod->setSavedValue("render_codec", std::string("h264_mediacodec")); + g.mod->setSavedValue("render_codec", std::string("libx264")); #endif diff --git a/src/macro.cpp b/src/macro.cpp index fc2dec92..d1835e02 100644 --- a/src/macro.cpp +++ b/src/macro.cpp @@ -118,7 +118,7 @@ void Macro::updateInfo(PlayLayer* pl) { g.macro.author = "N/A"; g.macro.botInfo.name = "xdBot"; - g.macro.botInfo.version = getModVersionInt(); + g.macro.botInfo.version = 1; g.macro.xdBotMacro = true; } @@ -153,7 +153,7 @@ LegacyMacro Macro::toLegacy() const { legacy.coins = coins; legacy.ldm = ldm; legacy.botInfo.name = botInfo.name; - legacy.botInfo.version = getModVersionString(); + legacy.botInfo.version = xdBotVersion; legacy.levelInfo.id = levelInfo.id; legacy.levelInfo.name = levelInfo.name; @@ -182,7 +182,7 @@ Macro Macro::fromLegacy(const LegacyMacro& legacy) { macro.coins = legacy.coins; macro.ldm = legacy.ldm; macro.botInfo.name = legacy.botInfo.name; - macro.botInfo.version = std::stoi(legacy.botInfo.version); + macro.botInfo.version = 1; macro.levelInfo.id = legacy.levelInfo.id; macro.levelInfo.name = legacy.levelInfo.name; macro.frameFixes = legacy.frameFixes; diff --git a/src/macro.hpp b/src/macro.hpp index 1d13dcea..ebe3c141 100644 --- a/src/macro.hpp +++ b/src/macro.hpp @@ -56,7 +56,7 @@ struct legacy_input : gdr_legacy::Input { }; struct LegacyMacro : gdr_legacy::Replay { - LegacyMacro() : Replay("xdBot", getModVersionString()) {} + LegacyMacro() : Replay("xdBot", xdBotVersion.c_str()) {} }; struct Macro : gdr::Replay { @@ -81,7 +81,7 @@ struct Macro : gdr::Replay { void saveExtension(binary_writer& writer) const override; std::string getBotVersionString() const { - return getModVersionString(); + return xdBotVersion; } LegacyMacro toLegacy() const; diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index b2be200a..c04e0eee 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -146,15 +146,9 @@ class $modify(CCScheduler) { }; bool Renderer::shouldUseAPI() { - #ifdef GEODE_IS_WINDOWS - bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); - std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); - bool foundExe = std::filesystem::exists(ffmpegPath) && geode::utils::string::pathToString(ffmpegPath.filename()) == "ffmpeg.exe"; - - return !foundExe && foundApi; - #else - return true; - #endif + // ffmpeg api is not ported + return false; + } bool Renderer::toggle() { @@ -182,7 +176,7 @@ bool Renderer::toggle() { std::filesystem::path ffmpegPath = Mod::get()->getSettingValue("ffmpeg_path"); bool foundExe = std::filesystem::exists(ffmpegPath) && geode::utils::string::pathToString(ffmpegPath.filename()) == "ffmpeg.exe"; - g.renderer.usingApi = Renderer::shouldUseAPI(); + g.renderer.usingApi = false; if (g.renderer.recording || g.renderer.recordingAudio) { g.renderer.recordingAudio ? g.renderer.stopAudio() : g.renderer.stop(Global::getCurrentFrame()); @@ -207,12 +201,8 @@ bool Renderer::toggle() { g.renderer.ffmpegPath = geode::utils::string::pathToString(ffmpegPath); #else - bool foundApi = Loader::get()->isModLoaded("eclipse.ffmpeg-api"); - if (!foundApi) { - FLAlertLayer::create("Error", "FFmpeg API is required for rendering on this platform.", "OK")->show(); - return false; - } - g.renderer.usingApi = true; + FLAlertLayer::create("Error", "Rendering is not supported on this platform yet.", "OK")->show(); + return false; #endif if (!PlayLayer::get()) { @@ -249,7 +239,7 @@ void Renderer::start() { Mod* mod = Mod::get(); fmod = FMODAudioEngine::sharedEngine(); - fps = geode::utils::numFromString(mod->getSavedValue("render_fps")).unwrapOr(60); + fps = geode::utils::numFromString(mod->getSavedValue("render_fps")).unwrap(); codec = mod->getSavedValue("render_codec"); bitrate = mod->getSavedValue("render_bitrate") + "M"; extraArgs = mod->getSavedValue("render_args"); diff --git a/src/ui/macro_info_layer.hpp b/src/ui/macro_info_layer.hpp index 1c7fdba6..ecfc4d6d 100644 --- a/src/ui/macro_info_layer.hpp +++ b/src/ui/macro_info_layer.hpp @@ -179,7 +179,7 @@ class MacroInfoLayer : public geode::Popup { lbl->setOpacity(150); m_mainLayer->addChild(lbl); - lbl = CCLabelBMFont::create((g.macro.botInfo.name + " " + getModVersionString()).c_str(), "chatFont.fnt"); + lbl = CCLabelBMFont::create((g.macro.botInfo.name + " v" + geode::utils::numToString(g.macro.botInfo.version)).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->limitLabelWidth(271.f, 0.475, 0.01f); lbl->updateLabel(); diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 9d130a5b..0e02b2c4 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -7,7 +7,6 @@ #include "autoclicker_settings_layer.hpp" #include "trajectory_settings_layer.hpp" #include "mirror_settings_layer.hpp" -#include "../gdr/gdr.hpp" #include "../hacks/coin_finder.hpp" #include "../hacks/show_trajectory.hpp" @@ -265,17 +264,17 @@ class $modify(PauseLayer) { } void RecordLayer::toggleRender(CCObject* btn) { - #ifdef GEODE_IS_WINDOWS +#ifdef GEODE_IS_WINDOWS if (!Renderer::toggle()) - static_cast(btn)->toggle(true); - + static_cast(btn)->toggle(true); + if (Global::get().renderer.recordingAudio) - static_cast(btn)->toggle(false); - #else + static_cast(btn)->toggle(false); +#else toggleRender2(btn); - #endif +#endif } - + void RecordLayer::toggleRender2(CCObject* btn) { FLAlertLayer::create("Info", "Rendering is not supported on your platform due to technical limitations.", "OK")->show(); } @@ -524,9 +523,7 @@ class $modify(PauseLayer) { } void RecordLayer::showCodecPopup(CCObject*) { - #ifdef GEODE_IS_WINDOWS FLAlertLayer::create("Codec", "AMD: h264_amf\nNVIDIA: h264_nvenc\nINTEL: h264_qsv\nI don't know: libx264", "OK")->show(); - #endif } void RecordLayer::updateDots() { @@ -592,7 +589,7 @@ class $modify(PauseLayer) { CCSprite* spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); CCSprite* spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); - CCLabelBMFont* versionLabel = CCLabelBMFont::create(("xdBot " + getModVersionString()).c_str(), "chatFont.fnt"); + CCLabelBMFont* versionLabel = CCLabelBMFont::create(("xdBot " + xdBotVersion).c_str(), "chatFont.fnt"); versionLabel->setOpacity(63); versionLabel->setPosition(ccp(-217, -125)); versionLabel->setAnchorPoint({ 0, 0.5 }); @@ -919,12 +916,12 @@ class $modify(PauseLayer) { bg->setZOrder(29); menu->addChild(bg); - #ifndef GEODE_IS_IOS + #ifdef GEODE_IS_WINDOWS ButtonSprite* spriteOn2 = ButtonSprite::create("Stop"); spriteOn2->setScale(0.74f); ButtonSprite* spriteOff2 = ButtonSprite::create("Start"); spriteOff2->setScale(0.74f); - + renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRender)); renderToggle->toggle(g.renderer.recording || g.renderer.recordingAudio); renderToggle->setPosition(ccp(-65.5, -100)); @@ -934,7 +931,7 @@ class $modify(PauseLayer) { spriteOn2->setScale(0.74f); ButtonSprite* spriteOff2 = ButtonSprite::create("N/A"); spriteOff2->setScale(0.74f); - + renderToggle = CCMenuItemToggler::create(spriteOn2, spriteOff2, this, menu_selector(RecordLayer::toggleRender2)); renderToggle->setPosition(ccp(-65.5, -100)); menu->addChild(renderToggle); From 70f26dd060afc7ea102b05e56a72e1e90f1df056 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 3 Mar 2026 00:58:35 +0300 Subject: [PATCH 113/211] i hope i didnt break anything --- src/gdr/gdr.hpp | 12 ++++++++++-- src/global.cpp | 2 +- src/hacks/tps_bypass.cpp | 2 ++ src/includes.hpp | 2 -- src/macro.cpp | 6 +++--- src/macro.hpp | 4 ++-- src/renderer/renderer.cpp | 5 ++--- src/ui/load_macro_layer.cpp | 3 +-- src/ui/macro_info_layer.hpp | 2 +- src/ui/record_layer.cpp | 23 ++++++++++++----------- src/utils/assembler.hpp | 2 ++ 11 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/gdr/gdr.hpp b/src/gdr/gdr.hpp index ec17e407..e16c3484 100644 --- a/src/gdr/gdr.hpp +++ b/src/gdr/gdr.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -8,14 +10,20 @@ #include +inline std::string getModVersionString() { + return geode::Mod::get()->getVersion().toVString(); +} + +inline int getModVersionInt() { + return static_cast(geode::Mod::get()->getVersion().getMajor()); +} + geode::prelude::VersionInfo getVersion(std::vector nums); cocos2d::CCPoint dataFromString(std::string dataString); std::vector splitByChar(std::string str, char splitChar); -const std::string xdBotVersion = "v2.3.11"; - namespace gdr_legacy { using namespace nlohmann; diff --git a/src/global.cpp b/src/global.cpp index 84ebc7e0..52cfcc41 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -403,7 +403,7 @@ PauseLayer* Global::getPauseLayer() { g.mod->setSavedValue("render_video_args", std::string("")); if (!g.mod->setSavedValue("defaults_set_11", true)) - g.mod->setSavedValue("render_codec", std::string("libx264")); + g.mod->setSavedValue("render_codec", std::string("h264_mediacodec")); #endif diff --git a/src/hacks/tps_bypass.cpp b/src/hacks/tps_bypass.cpp index 24544bf4..9095653a 100644 --- a/src/hacks/tps_bypass.cpp +++ b/src/hacks/tps_bypass.cpp @@ -1,3 +1,5 @@ +// credits to Eclipse Menu + #include "../includes.hpp" #include "../utils/assembler.hpp" diff --git a/src/includes.hpp b/src/includes.hpp index d56219f7..528a3f3b 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -139,11 +139,9 @@ class Global { bool tpsEnabled = false; float tps = 240.f; - // Callbacks for TPS settings changes (used instead of listenForSettingChanges) std::function onTpsEnabledChanged; std::function onTpsChanged; - // Setters that trigger callbacks void setTpsEnabled(bool enabled) { tpsEnabled = enabled; mod->setSavedValue("macro_tps_enabled", enabled); diff --git a/src/macro.cpp b/src/macro.cpp index d1835e02..f5ab0a55 100644 --- a/src/macro.cpp +++ b/src/macro.cpp @@ -118,7 +118,7 @@ void Macro::updateInfo(PlayLayer* pl) { g.macro.author = "N/A"; g.macro.botInfo.name = "xdBot"; - g.macro.botInfo.version = 1; + g.macro.botInfo.version = getModVersionInt(); g.macro.xdBotMacro = true; } @@ -153,7 +153,7 @@ LegacyMacro Macro::toLegacy() const { legacy.coins = coins; legacy.ldm = ldm; legacy.botInfo.name = botInfo.name; - legacy.botInfo.version = xdBotVersion; + legacy.botInfo.version = getModVersionString(); legacy.levelInfo.id = levelInfo.id; legacy.levelInfo.name = levelInfo.name; @@ -182,7 +182,7 @@ Macro Macro::fromLegacy(const LegacyMacro& legacy) { macro.coins = legacy.coins; macro.ldm = legacy.ldm; macro.botInfo.name = legacy.botInfo.name; - macro.botInfo.version = 1; + macro.botInfo.version = geode::utils::numFromString(legacy.botInfo.version).unwrap(); macro.levelInfo.id = legacy.levelInfo.id; macro.levelInfo.name = legacy.levelInfo.name; macro.frameFixes = legacy.frameFixes; diff --git a/src/macro.hpp b/src/macro.hpp index ebe3c141..1d13dcea 100644 --- a/src/macro.hpp +++ b/src/macro.hpp @@ -56,7 +56,7 @@ struct legacy_input : gdr_legacy::Input { }; struct LegacyMacro : gdr_legacy::Replay { - LegacyMacro() : Replay("xdBot", xdBotVersion.c_str()) {} + LegacyMacro() : Replay("xdBot", getModVersionString()) {} }; struct Macro : gdr::Replay { @@ -81,7 +81,7 @@ struct Macro : gdr::Replay { void saveExtension(binary_writer& writer) const override; std::string getBotVersionString() const { - return xdBotVersion; + return getModVersionString(); } LegacyMacro toLegacy() const; diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index c04e0eee..c7eb9ada 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -146,9 +146,8 @@ class $modify(CCScheduler) { }; bool Renderer::shouldUseAPI() { - // ffmpeg api is not ported - return false; - + // not using it for now + return true; } bool Renderer::toggle() { diff --git a/src/ui/load_macro_layer.cpp b/src/ui/load_macro_layer.cpp index b1cef503..f2e850ae 100644 --- a/src/ui/load_macro_layer.cpp +++ b/src/ui/load_macro_layer.cpp @@ -181,7 +181,7 @@ void LoadMacroLayer::onImportMacro(CCObject*) { tempMacro = Macro::importData(data); } - std::string name = path.stem().string(); + std::string name = geode::utils::string::pathToString(path.stem()); #ifdef GEODE_IS_IOS std::filesystem::path folder = Mod::get()->getSaveDir() / "macros"; @@ -189,7 +189,6 @@ void LoadMacroLayer::onImportMacro(CCObject*) { std::filesystem::path folder = Mod::get()->getSettingValue("macros_folder"); #endif - // Save imported macros as GDR2 binary std::filesystem::path finalPath = folder / (name + ".gdr2"); int iterations = 1; while (std::filesystem::exists(finalPath)) { diff --git a/src/ui/macro_info_layer.hpp b/src/ui/macro_info_layer.hpp index ecfc4d6d..1c7fdba6 100644 --- a/src/ui/macro_info_layer.hpp +++ b/src/ui/macro_info_layer.hpp @@ -179,7 +179,7 @@ class MacroInfoLayer : public geode::Popup { lbl->setOpacity(150); m_mainLayer->addChild(lbl); - lbl = CCLabelBMFont::create((g.macro.botInfo.name + " v" + geode::utils::numToString(g.macro.botInfo.version)).c_str(), "chatFont.fnt"); + lbl = CCLabelBMFont::create((g.macro.botInfo.name + " " + getModVersionString()).c_str(), "chatFont.fnt"); lbl->setAnchorPoint({ 0, 0.5 }); lbl->limitLabelWidth(271.f, 0.475, 0.01f); lbl->updateLabel(); diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 0e02b2c4..5c4e7af9 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -7,6 +7,7 @@ #include "autoclicker_settings_layer.hpp" #include "trajectory_settings_layer.hpp" #include "mirror_settings_layer.hpp" +#include "../gdr/gdr.hpp" #include "../hacks/coin_finder.hpp" #include "../hacks/show_trajectory.hpp" @@ -264,17 +265,17 @@ class $modify(PauseLayer) { } void RecordLayer::toggleRender(CCObject* btn) { -#ifdef GEODE_IS_WINDOWS + #ifdef GEODE_IS_WINDOWS if (!Renderer::toggle()) - static_cast(btn)->toggle(true); - + static_cast(btn)->toggle(true); + if (Global::get().renderer.recordingAudio) - static_cast(btn)->toggle(false); -#else + static_cast(btn)->toggle(false); + #else toggleRender2(btn); -#endif + #endif } - + void RecordLayer::toggleRender2(CCObject* btn) { FLAlertLayer::create("Info", "Rendering is not supported on your platform due to technical limitations.", "OK")->show(); } @@ -589,7 +590,7 @@ class $modify(PauseLayer) { CCSprite* spriteOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); CCSprite* spriteOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); - CCLabelBMFont* versionLabel = CCLabelBMFont::create(("xdBot " + xdBotVersion).c_str(), "chatFont.fnt"); + CCLabelBMFont* versionLabel = CCLabelBMFont::create(("xdBot " + getModVersionString()).c_str(), "chatFont.fnt"); versionLabel->setOpacity(63); versionLabel->setPosition(ccp(-217, -125)); versionLabel->setAnchorPoint({ 0, 0.5 }); @@ -916,12 +917,12 @@ class $modify(PauseLayer) { bg->setZOrder(29); menu->addChild(bg); - #ifdef GEODE_IS_WINDOWS + #ifndef GEODE_IS_IOS ButtonSprite* spriteOn2 = ButtonSprite::create("Stop"); spriteOn2->setScale(0.74f); ButtonSprite* spriteOff2 = ButtonSprite::create("Start"); spriteOff2->setScale(0.74f); - + renderToggle = CCMenuItemToggler::create(spriteOff2, spriteOn2, this, menu_selector(RecordLayer::toggleRender)); renderToggle->toggle(g.renderer.recording || g.renderer.recordingAudio); renderToggle->setPosition(ccp(-65.5, -100)); @@ -931,7 +932,7 @@ class $modify(PauseLayer) { spriteOn2->setScale(0.74f); ButtonSprite* spriteOff2 = ButtonSprite::create("N/A"); spriteOff2->setScale(0.74f); - + renderToggle = CCMenuItemToggler::create(spriteOn2, spriteOff2, this, menu_selector(RecordLayer::toggleRender2)); renderToggle->setPosition(ccp(-65.5, -100)); menu->addChild(renderToggle); diff --git a/src/utils/assembler.hpp b/src/utils/assembler.hpp index 1d356ac0..decedc0e 100644 --- a/src/utils/assembler.hpp +++ b/src/utils/assembler.hpp @@ -3,6 +3,8 @@ #include #include +// credits to Eclipse Menu + namespace x86_64 { enum class Register64 : uint8_t { rax = 0, rcx = 1, rdx = 2, rbx = 3, From 6db8991eae98c255001c9a82f43bf3756696560f Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 3 Mar 2026 01:08:21 +0300 Subject: [PATCH 114/211] gg UB! --- src/hacks/tps_bypass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hacks/tps_bypass.cpp b/src/hacks/tps_bypass.cpp index 9095653a..9cfb34c0 100644 --- a/src/hacks/tps_bypass.cpp +++ b/src/hacks/tps_bypass.cpp @@ -110,7 +110,7 @@ geode::Result<> setupModifiedDeltaPatches() { return geode::Err("failed to find getModifiedDelta patch address"); } - using namespace assembler::arm64; + using namespace arm64; auto bytes = Builder(addr) .ldr(Register::x9, Register::x19, offsetof(GJBaseGameLayer, m_loadingLayer)) .nop() @@ -139,7 +139,7 @@ geode::Result<> setupModifiedDeltaPatches() { void applyPatches() { #ifdef GEODE_IS_IOS if (geode::Loader::get()->isPatchless()) { - using namespace assembler::arm64; + using namespace arm64; g_expectedTicksPtr = std::bit_cast(geode::base::get() + g_jitlessSpace); static_assert(GEODE_COMP_GD_VERSION == 22081, "TPS Bypass: JIT-less patch is only supported for GD 2.2081"); #define PATCH_ADDR 0x1fe724 From 8c0be41b204d27473dbc2e66d8bd5b0db7af0268 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Tue, 3 Mar 2026 01:13:33 +0300 Subject: [PATCH 115/211] asdlasdld --- src/ui/record_layer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/record_layer.cpp b/src/ui/record_layer.cpp index 5c4e7af9..95381298 100644 --- a/src/ui/record_layer.cpp +++ b/src/ui/record_layer.cpp @@ -917,7 +917,7 @@ class $modify(PauseLayer) { bg->setZOrder(29); menu->addChild(bg); - #ifndef GEODE_IS_IOS + #ifdef GEODE_IS_WINDOWS ButtonSprite* spriteOn2 = ButtonSprite::create("Stop"); spriteOn2->setScale(0.74f); ButtonSprite* spriteOff2 = ButtonSprite::create("Start"); From 4ea9f9a7e578602d7740c35e66b71efb7fa7c6f9 Mon Sep 17 00:00:00 2001 From: slideglide <68702247+slideglide@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:01:09 +0300 Subject: [PATCH 116/211] rewrite practice fixes --- CMakeLists.txt | 33 +- mod.json | 2 +- src/includes.hpp | 1 + src/macro.hpp | 3 +- src/main.cpp | 7 +- src/practice_fixes/GameCheckpoint.hpp | 112 ++++++ src/practice_fixes/checkpoint.cpp | 84 +++++ src/practice_fixes/input.cpp | 148 -------- src/practice_fixes/play_layer.cpp | 141 ------- src/practice_fixes/player.cpp | 518 -------------------------- src/practice_fixes/practice_fixes.hpp | 70 +++- src/ui/macro_editor.cpp | 8 +- src/ui/record_layer.cpp | 3 + 13 files changed, 270 insertions(+), 860 deletions(-) create mode 100644 src/practice_fixes/GameCheckpoint.hpp create mode 100644 src/practice_fixes/checkpoint.cpp delete mode 100644 src/practice_fixes/input.cpp delete mode 100644 src/practice_fixes/play_layer.cpp delete mode 100644 src/practice_fixes/player.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 626431b7..2952559b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,38 +9,9 @@ endif() set(CMAKE_CXX_VISIBILITY_PRESET hidden) project(xdBot2 VERSION 1.0.0) - -add_library(${PROJECT_NAME} SHARED - src/main.cpp - src/global.cpp - src/macro.cpp - src/keybinds.cpp - src/utils/utils.cpp - src/gdr/gdr.cpp - src/renderer/renderer.cpp - src/hacks/other.cpp - src/hacks/tps_bypass.cpp - src/hacks/frame_stepper.cpp - src/hacks/layout_mode.cpp - src/hacks/show_trajectory.cpp - src/hacks/coin_finder.cpp - src/hacks/clickbot.cpp - src/hacks/autoclicker.cpp - - src/ui/macro_editor.cpp - src/ui/button_edit_layer.cpp - src/ui/game_ui.cpp - src/ui/record_layer.cpp - src/ui/render_settings_layer.cpp - src/ui/load_macro_layer.cpp - src/ui/clickbot_layer.cpp - src/ui/button_setting.cpp - - src/practice_fixes/input.cpp - src/practice_fixes/player.cpp - src/practice_fixes/play_layer.cpp -) +file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.cpp) +add_library(${PROJECT_NAME} SHARED ${SOURCES}) if (NOT DEFINED ENV{GEODE_SDK}) message(FATAL_ERROR "Unable to find Geode SDK! Please define GEODE_SDK environment variable to point to Geode") diff --git a/mod.json b/mod.json index 96ccec86..736097d0 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "5.1.0", + "geode": "5.3.0", "gd": { "win": "2.2081", "mac": "2.2081", diff --git a/src/includes.hpp b/src/includes.hpp index 528a3f3b..aedfae7d 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -158,6 +158,7 @@ class Global { float previousTps = 0.f; bool autoclicker = false; bool autoclickerP1 = false; + bool alwaysPracticeFixes = false; bool autoclickerP2 = false; int holdFor = 0; int releaseFor = 0; diff --git a/src/macro.hpp b/src/macro.hpp index 1d13dcea..3b458bc7 100644 --- a/src/macro.hpp +++ b/src/macro.hpp @@ -1,6 +1,5 @@ #pragma once -#include "includes.hpp" #include "gdr/gdr.hpp" #include "utils/utils.hpp" @@ -137,7 +136,7 @@ struct button { struct PlayerData { #ifdef GEODE_IS_WINDOWS std::unordered_map m_rotateObjectsRelated; - std::unordered_map m_maybeRotatedObjectsMap; + std::unordered_map m_potentialSlopeMap; std::unordered_set m_touchedRings; std::unordered_set m_ringRelatedSet; std::map m_jumpPadRelated; diff --git a/src/main.cpp b/src/main.cpp index bfe48bcc..e0fa07e5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -152,7 +152,7 @@ class $modify(PlayLayer) { if (g.state == state::recording) Macro::updateInfo(this); - if ((!m_isPracticeMode || frame <= 1 || g.checkpoints.empty()) && g.state == state::recording) { + if ((!m_isPracticeMode || frame <= 1 || (g.checkpoints.empty() && m_checkpointArray->count() <= 0)) && g.state == state::recording) { g.macro.inputs.clear(); g.macro.frameFixes.clear(); g.checkpoints.clear(); @@ -163,7 +163,8 @@ class $modify(PlayLayer) { PlayerData p1Data = PlayerPracticeFixes::saveData(m_player1); PlayerData p2Data = PlayerPracticeFixes::saveData(m_player2); - InputPracticeFixes::applyFixes(this, p1Data, p2Data, frame); + PlayerPracticeFixes::applyData(m_player1, p1Data, false, false); + PlayerPracticeFixes::applyData(m_player2, p2Data, true, false); Macro::resetVariables(); m_player1->m_holdingRight = false; @@ -177,7 +178,7 @@ class $modify(PlayLayer) { m_player2->m_holdingButtons[3] = false; } - if (!m_levelSettings->m_platformerMode || (!g.mod->getSavedValue("macro_always_practice_fixes") && g.state != state::recording)) return; + if (!m_levelSettings->m_platformerMode || (!g.alwaysPracticeFixes && g.state != state::recording)) return; g.ignoreRecordAction = true; for (int i = 0; i < 4; i++) { diff --git a/src/practice_fixes/GameCheckpoint.hpp b/src/practice_fixes/GameCheckpoint.hpp new file mode 100644 index 00000000..34a0e3f8 --- /dev/null +++ b/src/practice_fixes/GameCheckpoint.hpp @@ -0,0 +1,112 @@ +#pragma once +#include +#include +#include +#include + +using namespace geode::prelude; + +class FixPlayerCheckpoint { +public: + FixPlayerCheckpoint() = default; + + FixPlayerCheckpoint(PlayerObject* player) { + if (!player) return; + + auto cp = PlayerCheckpoint::create(); + if (!cp) return; + + m_checkpoint = cp; + m_isValid = true; + player->saveToCheckpoint(m_checkpoint.data()); + + // Full physics capture + m_yVelocityRelated = player->m_yVelocityRelated; + m_groundYVelocity = player->m_groundYVelocity; + m_scaleXRelated2 = player->m_scaleXRelated2; + m_scaleXRelated3 = player->m_scaleXRelated3; + m_scaleXRelated4 = player->m_scaleXRelated4; + m_scaleXRelated5 = player->m_scaleXRelated5; + m_currentSlope = player->m_currentSlope; + m_currentSlope2 = player->m_currentSlope2; + m_slopeAngle = player->m_slopeAngle; + m_slopeAngleRadians = player->m_slopeAngleRadians; + m_slopeFlipGravityRelated = player->m_slopeFlipGravityRelated; + m_slopeSlidingMaybeRotated = player->m_slopeSlidingMaybeRotated; + m_currentSlopeYVelocity = player->m_currentSlopeYVelocity; + m_slopeRotation = player->m_slopeRotation; + m_isCollidingWithSlope = player->m_isCollidingWithSlope; + m_collidingWithSlopeId = player->m_collidingWithSlopeId; + m_maybeUpsideDownSlope = player->m_maybeUpsideDownSlope; + m_isOnSlope = player->m_isOnSlope; + m_wasOnSlope = player->m_wasOnSlope; + m_physDeltaRelated = player->m_physDeltaRelated; + } + + void apply(PlayerObject* player) { + if (!player || !m_checkpoint || !m_isValid) return; + + player->loadFromCheckpoint(m_checkpoint.data()); + + player->m_yVelocityRelated = m_yVelocityRelated; + player->m_groundYVelocity = m_groundYVelocity; + player->m_scaleXRelated2 = m_scaleXRelated2; + player->m_scaleXRelated3 = m_scaleXRelated3; + player->m_scaleXRelated4 = m_scaleXRelated4; + player->m_scaleXRelated5 = m_scaleXRelated5; + player->m_currentSlope = m_currentSlope; + player->m_currentSlope2 = m_currentSlope2; + player->m_slopeAngle = m_slopeAngle; + player->m_slopeAngleRadians = m_slopeAngleRadians; + player->m_slopeFlipGravityRelated = m_slopeFlipGravityRelated; + player->m_slopeSlidingMaybeRotated = m_slopeSlidingMaybeRotated; + player->m_currentSlopeYVelocity = m_currentSlopeYVelocity; + player->m_slopeRotation = m_slopeRotation; + player->m_isCollidingWithSlope = m_isCollidingWithSlope; + player->m_collidingWithSlopeId = m_collidingWithSlopeId; + player->m_maybeUpsideDownSlope = m_maybeUpsideDownSlope; + player->m_isOnSlope = m_isOnSlope; + player->m_wasOnSlope = m_wasOnSlope; + player->m_physDeltaRelated = m_physDeltaRelated; + } + +private: + bool m_isValid = false; + Ref m_checkpoint = nullptr; + + double m_yVelocityRelated, m_groundYVelocity, m_scaleXRelated2, m_scaleXRelated3; + double m_scaleXRelated4, m_scaleXRelated5, m_currentSlopeYVelocity, m_slopeRotation, m_physDeltaRelated; + GameObject *m_currentSlope, *m_currentSlope2; + float m_slopeAngle, m_slopeAngleRadians; + bool m_slopeFlipGravityRelated, m_slopeSlidingMaybeRotated, m_isCollidingWithSlope; + bool m_maybeUpsideDownSlope, m_isOnSlope, m_wasOnSlope; + int m_collidingWithSlopeId; +}; + +class FixPlayLayerCheckpoint { +public: + FixPlayLayerCheckpoint() = default; + FixPlayLayerCheckpoint(PlayLayer* playLayer) { + if (!playLayer) return; + m_player1CollisionBlock = playLayer->m_player1CollisionBlock; + m_player2CollisionBlock = playLayer->m_player2CollisionBlock; + m_extraDelta = playLayer->m_extraDelta; + m_currentStep = playLayer->m_currentStep; + m_unk3380 = playLayer->m_unk3380; + } + + void apply(PlayLayer* playLayer) { + if (!playLayer) return; + playLayer->m_player1CollisionBlock = m_player1CollisionBlock; + playLayer->m_player2CollisionBlock = m_player2CollisionBlock; + playLayer->m_extraDelta = m_extraDelta; + playLayer->m_currentStep = m_currentStep; + playLayer->m_unk3380 = m_unk3380; + } + +private: + GameObject *m_player1CollisionBlock, *m_player2CollisionBlock; + double m_extraDelta; + int m_currentStep; + float m_unk3380; +}; \ No newline at end of file diff --git a/src/practice_fixes/checkpoint.cpp b/src/practice_fixes/checkpoint.cpp new file mode 100644 index 00000000..1ff4f6d4 --- /dev/null +++ b/src/practice_fixes/checkpoint.cpp @@ -0,0 +1,84 @@ +#include "GameCheckpoint.hpp" +#include "practice_fixes.hpp" +#include + +class PracticeCheckpointData { +public: + PracticeCheckpointData() = default; + PracticeCheckpointData(PlayerObject* p1, PlayerObject* p2, PlayLayer* pl) { + if (!pl || !p1) return; + m_checkpointPlayLayer = FixPlayLayerCheckpoint(pl); + m_checkpointPlayer1 = FixPlayerCheckpoint(p1); + if (p2) m_checkpointPlayer2 = FixPlayerCheckpoint(p2); + } + + void apply(PlayerObject* p1, PlayerObject* p2, PlayLayer* pl) { + if (!pl) return; + m_checkpointPlayLayer.apply(pl); + if (p1) m_checkpointPlayer1.apply(p1); + if (p2) m_checkpointPlayer2.apply(p2); + } + +private: + FixPlayerCheckpoint m_checkpointPlayer1, m_checkpointPlayer2; + FixPlayLayerCheckpoint m_checkpointPlayLayer; +}; + +class $modify(FixPlayLayer, PlayLayer) { + struct Fields { + std::unordered_map m_checkpoints; + std::unordered_map> m_checkpointInputs; + std::unordered_map> m_checkpointFrameFixes; + std::unordered_map m_checkpointFrames; + }; + + void loadFromCheckpoint(CheckpointObject* checkpoint) { + PlayLayer::loadFromCheckpoint(checkpoint); + + if (PracticeFix::shouldEnable()) { + auto fields = m_fields.self(); + if (fields->m_checkpoints.contains(checkpoint)) { + auto& data = fields->m_checkpoints[checkpoint]; + data.apply(m_player1, m_gameState.m_isDualMode ? m_player2 : nullptr, this); + } + + auto& g = Global::get(); + if (g.state == state::recording && fields->m_checkpointInputs.contains(checkpoint)) { + g.ignoreRecordAction = true; + g.macro.inputs = fields->m_checkpointInputs[checkpoint]; + g.macro.frameFixes = fields->m_checkpointFrameFixes[checkpoint]; + g.ignoreRecordAction = false; + } + } + } + + CheckpointObject* createCheckpoint() { + auto checkpoint = PlayLayer::createCheckpoint(); + if (!checkpoint || !PracticeFix::shouldEnable()) return checkpoint; + + PracticeCheckpointData data(m_player1, m_gameState.m_isDualMode ? m_player2 : nullptr, this); + m_fields->m_checkpoints[checkpoint] = data; + + auto& g = Global::get(); + if (g.state == state::recording) { + g.ignoreRecordAction = true; + m_fields->m_checkpointInputs[checkpoint] = g.macro.inputs; + m_fields->m_checkpointFrameFixes[checkpoint] = g.macro.frameFixes; + m_fields->m_checkpointFrames[checkpoint] = Global::getCurrentFrame(); + g.ignoreRecordAction = false; + } + + return checkpoint; + } + + void resetLevel() { + if (m_checkpointArray->count() <= 0) { + m_fields->m_checkpoints.clear(); + m_fields->m_checkpointInputs.clear(); + m_fields->m_checkpointFrameFixes.clear(); + m_fields->m_checkpointFrames.clear(); + } + PlayLayer::resetLevel(); + if (m_checkpointArray->count() > 0) m_resumeTimer = 0; + } +}; \ No newline at end of file diff --git a/src/practice_fixes/input.cpp b/src/practice_fixes/input.cpp deleted file mode 100644 index 9fa6bbb0..00000000 --- a/src/practice_fixes/input.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include "practice_fixes.hpp" - -void InputPracticeFixes::applyFixes(PlayLayer* pl, PlayerData p1Data, PlayerData p2Data, int frame) { - if (!pl) return; - - auto& g = Global::get(); - bool twoPlayers = pl->m_levelSettings->m_twoPlayerMode; - - eraseActions(frame); - - std::vector