From d49e19b3fa7ebb13cb579ef4049bcf345bfba496 Mon Sep 17 00:00:00 2001 From: SpaghettDev <37266659+SpaghettDev@users.noreply.github.com> Date: Fri, 12 Apr 2024 22:40:29 +0000 Subject: [PATCH] GauntletNode, GauntletSelectLayer, LevelPage, LevelSelectLayer and MoreOptionsLayer (#33) * GauntletSelectLayer, LevelPage, LevelSelectLayer and MoreOptionsLayer * GauntletNode, missing GauntletSelectLayer nodeIDs and typo fixe * Fix duplicate node and MOL on android * Fix epic compiler error * sorru * GauntletSelectLayer conflict --- about.md | 5 + src/GauntletNode.cpp | 89 +++++++++++ src/GauntletSelectLayer.cpp | 72 ++++++++- src/LevelPage.cpp | 141 +++++++++++++++++ src/LevelSelectLayer.cpp | 78 ++++++++++ src/MoreOptionsLayer.cpp | 293 ++++++++++++++++++++++++++++++++++++ 6 files changed, 674 insertions(+), 4 deletions(-) create mode 100644 src/GauntletNode.cpp create mode 100644 src/LevelPage.cpp create mode 100644 src/LevelSelectLayer.cpp create mode 100644 src/MoreOptionsLayer.cpp diff --git a/about.md b/about.md index 7ff3985..20f1e47 100644 --- a/about.md +++ b/about.md @@ -16,6 +16,8 @@ Has IDs for: - EditorPauseLayer - EditorUI - FLAlertLayer +- GauntletNode +- GauntletSelectLayer - GJCommentListLayer - GJGarageLayer - GJScoreCell @@ -27,7 +29,10 @@ Has IDs for: - LevelEditorLayer - LevelInfoLayer - LevelLeaderboard +- LevelPage - LevelSearchLayer +- LevelSelectLayer +- MoreOptionsLayer - OptionsLayer - PauseLayer - PlayLayer diff --git a/src/GauntletNode.cpp b/src/GauntletNode.cpp new file mode 100644 index 0000000..0f1df2d --- /dev/null +++ b/src/GauntletNode.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +using namespace geode::prelude; +using namespace geode::node_ids; + +struct GauntletNodeIDs : Modify { + GJMapPack* m_gauntlet; + + static void onModify(auto& self) { + if (!self.setHookPriority("GauntletNode::init", GEODE_ID_PRIORITY)) { + log::warn("Failed to set GauntletNode::init hook priority, node IDs may not work properly"); + } + } + + bool init(GJMapPack* gauntlet) { + if (!GauntletNode::init(gauntlet)) return false; + + m_fields->m_gauntlet = gauntlet; + + NodeIDs::get()->provide(this); + + return true; + } +}; + +$register_ids(GauntletNode) { + const auto GSM = GameStatsManager::sharedState(); + auto self = reinterpret_cast(this); + + if (self->m_fields->m_gauntlet->hasCompletedMapPack()) { + setIDs( + this, + 0, + "gauntlet-info-node", + "empty-node", + "background", + "gauntlet-name-label", + "gauntlet-label", + "gauntlet-name-shadow-label", + "gauntlet-shadow-label", + "checkmark-sprite", + "checkmark-shadow-sprite" + ); + } else { + setIDs( + this, + 0, + "gauntlet-info-node", + "empty-node", + "background", + "gauntlet-name-label", + "gauntlet-label", + "gauntlet-name-shadow-label", + "gauntlet-shadow-label" + ); + } + + if (auto gauntletInfoNode = this->getChildByID("gauntlet-info-node")) { + if ( + self->m_fields->m_gauntlet->hasCompletedMapPack() && + GSM->isSpecialChestUnlocked(GSM->getGauntletRewardKey(self->m_fields->m_gauntlet->m_packID)) + ) { + setIDs( + gauntletInfoNode, + 0, + "gauntlet-sprite", + "gauntlet-shadow-sprite", + "gauntlet-progress-label", + "gauntlet-progress-shadow-label" + ); + } else { + setIDs( + gauntletInfoNode, + 0, + "gauntlet-sprite", + "gauntlet-shadow-sprite", + "gauntlet-progress-label", + "gauntlet-progress-shadow-label", + "reward-label", + "reward-shadow-label", + "chest-sprite", + "chest-shadow-sprite" + ); + } + } +} diff --git a/src/GauntletSelectLayer.cpp b/src/GauntletSelectLayer.cpp index b88461a..a3fb5a8 100644 --- a/src/GauntletSelectLayer.cpp +++ b/src/GauntletSelectLayer.cpp @@ -1,12 +1,17 @@ -#include +#include +#include #include -#include #include using namespace geode::prelude; using namespace geode::node_ids; $register_ids(GauntletSelectLayer) { + this->setID("main-layer"); + + getChildOfType(this, 0)->setID("background"); + getChildOfType(this, 1)->setID("title-sprite"); + setIDs( this, 0, @@ -21,6 +26,25 @@ using namespace geode::node_ids; "loading-circle", "try-again-text" ); + + if (auto arrowsMenu = this->getChildByID("scroll-buttons-menu")) { + setIDs( + arrowsMenu, + 0, + "left-button", + "right-button" + ); + } + + if (auto miscMenu = this->getChildByID("left-menu")) { + setIDs( + miscMenu, + 0, + "back-button", + "info-button", + "reload-button" + ); + } } struct GauntletSelectLayerIDs : Modify { @@ -28,13 +52,53 @@ struct GauntletSelectLayerIDs : Modifyprovide(this); return true; } + + void setupGauntlets() { + GauntletSelectLayer::setupGauntlets(); + + if (auto gauntletsList = getChildOfType(this, 0)) { + gauntletsList->setID("gauntlets-list"); + + if (auto gauntletPages = getChildOfType(gauntletsList, 0)) { + gauntletPages->setID("gauntlet-pages"); + + auto gauntletPagesArray = CCArrayExt(gauntletPages->getChildren()); + for (int i = 0; i < gauntletPagesArray.size(); i++) { + auto gauntletPage = gauntletPagesArray[i]; + gauntletPage->setID(fmt::format("gauntlet-page-{}", i + 1)); + + if (auto gauntletMenu = getChildOfType(gauntletPage, 0)) { + gauntletMenu->setID("gauntlet-menu"); + + auto gauntletButtons = CCArrayExt(gauntletMenu->getChildren()); + for (int i = 0; i < gauntletButtons.size(); i++) { + auto gauntletButton = gauntletButtons[i]; + + gauntletButton->setID(fmt::format("gauntlet-button-{}", i + 1)); + + if (auto gauntletNodeParent = getChildOfType(gauntletButton, 0)) { + gauntletNodeParent->setID("gauntlet-node-parent"); + + getChildOfType(gauntletNodeParent, 0)->setID("gauntlet-node"); + } + } + } + } + } + + getChildOfType(gauntletsList, 0)->setID("page-buttons"); + } + } }; diff --git a/src/LevelPage.cpp b/src/LevelPage.cpp new file mode 100644 index 0000000..faeb999 --- /dev/null +++ b/src/LevelPage.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include + +using namespace geode::prelude; +using namespace geode::node_ids; + +$register_ids(LevelPage) { + setIDs( + this, + 0, + "level-menu", + "normal-progress-bar", + "practice-progress-bar", + "normal-progress-label", + "practice-progress-label", + "normal-mode-label", + "practice-mode-label" + ); + + if (auto levelMenu = this->getChildByID("level-menu")) { + if (auto levelButton = getChildOfType(levelMenu, 0)) { + levelButton->setID("level-button"); + + // why in gods name does this sprite house everything + if (auto whiteSprite = getChildOfType(levelButton, 0)) { + whiteSprite->setID("white-sprite"); + + if (auto scale9Sprite = getChildOfType(whiteSprite, 0)) { + scale9Sprite->setID("scale-9-sprite"); + + setIDs( + scale9Sprite, + 0, + "background", + "level-name-label", + "difficulty-sprite", + "stars-icon", + "stars-label", + "secret-coin-icon-1", + "secret-coin-icon-2", + "secret-coin-icon-3" + ); + } + + if (auto controllerStartSprite = getChildOfType(whiteSprite, 0)) { + controllerStartSprite->setID("controller-start-sprite"); + } + } + } + } +} + +struct LevelPageIDs : Modify { + static void onModify(auto& self) { + if (!self.setHookPriority("LevelPage::create", GEODE_ID_PRIORITY)) { + log::warn("Failed to set LevelPage::create hook priority, node IDs may not work properly"); + } + } + + // LevelPage::init is half-inlined on windows + static LevelPage* create(GJGameLevel* level) { + auto layer = LevelPage::create(level); + if (!layer) return nullptr; + + NodeIDs::get()->provide(layer); + + return layer; + } + + void updateDynamicPage(GJGameLevel* level) { + LevelPage::updateDynamicPage(level); + + // can't believe im bugfixing this game + if (auto emptyMenu = getChildOfType(this, 1); emptyMenu && emptyMenu->getChildrenCount() == 0) { + emptyMenu->removeFromParent(); + } + + if (GameStatsManager::sharedState()->getStat("8") < level->m_requiredCoins) { + setIDs( + this->getChildByID("level-menu") + ->getChildByID("level-button") + ->getChildByID("white-sprite") + ->getChildByID("scale-9-sprite"), + 8, + "lock-sprite", + "secret-coin-icon", + "secret-coin-label" + ); + } else { + setIDs( + this->getChildByID("level-menu") + ->getChildByID("level-button") + ->getChildByID("white-sprite") + ->getChildByID("scale-9-sprite"), + 8, + "orbs-icon", + "orbs-label" + ); + } + + // this is how updateDynamicPage itself does it + if (level->m_levelID <= 0) { + if (level->m_levelID == -2) { + if (auto buttonMenu = getChildOfType(this, 1)) { + buttonMenu->setID("button-menu"); + + if (auto towerButton = getChildOfType(buttonMenu, 0)) { + towerButton->setID("tower-button"); + + if (auto towerSprite = getChildOfType(towerButton, 0)) { + towerSprite->setID("tower-sprite"); + + setIDs( + towerSprite, + 0, + "the-tower-sprite", + "square-particle-system", + "glow-particle-system", + "skull-particle-system" + ); + } + } + } + } else { + getChildOfType(this, 4)->setID("coming-soon-label"); + + if (auto buttonMenu = getChildOfType(this, 1)) { + buttonMenu->setID("button-menu"); + + if (auto secretDoorButton = getChildOfType(buttonMenu, 0)) { + secretDoorButton->setID("secret-door-button"); + + getChildOfType(secretDoorButton, 0)->setID("secret-door-sprite"); + } + } + } + } + } +}; diff --git a/src/LevelSelectLayer.cpp b/src/LevelSelectLayer.cpp new file mode 100644 index 0000000..310e142 --- /dev/null +++ b/src/LevelSelectLayer.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +using namespace geode::prelude; +using namespace geode::node_ids; + +$register_ids(LevelSelectLayer) { + this->setID("main-layer"); + + setIDs( + this, + 0, + "background", + "ground-layer", + "top-bar-sprite", + "bottom-left-corner", + "bottom-right-corner", + "levels-list", + "bottom-center-menu", + "arrows-menu", + "back-menu", + "info-menu" + ); + + if (auto levelsList = this->getChildByID("levels-list")) { + if (auto levelPages = getChildOfType(levelsList, 0)) { + levelPages->setID("level-pages"); + + setIDs( + levelPages, + 0, + "level-page-1", + "level-page-2", + "level-page-3" + ); + } + + getChildOfType(levelsList, 0)->setID("page-buttons"); + } + + if (auto bottomCenterMenu = this->getChildByID("bottom-center-menu")) { + if (auto soundtrackButton = getChildOfType(bottomCenterMenu, 0)) { + soundtrackButton->setID("download-soundtrack-button"); + + getChildOfType(soundtrackButton, 0)->setID("download-soundtrack-label"); + } + } + + getChildOfType(this->getChildByID("info-menu"), 0)->setID("info-button"); + getChildOfType(this->getChildByID("back-menu"), 0)->setID("back-button"); + + if (auto arrowsMenu = this->getChildByID("arrows-menu")) { + setIDs( + arrowsMenu, + 0, + "left-button", + "right-button" + ); + } +} + +struct LevelSelectLayerIDs : Modify { + static void onModify(auto& self) { + if (!self.setHookPriority("LevelSelectLayer::init", GEODE_ID_PRIORITY)) { + log::warn("Failed to set LevelSelectLayer::init hook priority, node IDs may not work properly"); + } + } + + bool init(int p0) { + if (!LevelSelectLayer::init(p0)) return false; + + NodeIDs::get()->provide(this); + + return true; + } +}; diff --git a/src/MoreOptionsLayer.cpp b/src/MoreOptionsLayer.cpp new file mode 100644 index 0000000..aa5414e --- /dev/null +++ b/src/MoreOptionsLayer.cpp @@ -0,0 +1,293 @@ +#include +#include +#include +#include + +using namespace geode::prelude; +using namespace geode::node_ids; + +$register_ids(MoreOptionsLayer) { + m_mainLayer->setID("main-layer"); + + setIDs( + m_mainLayer, + 0, + "background", + "options-label", + "togglers-menu", + "gameplay-options-layer-1", + "gameplay-options-layer-2", + "practice-options-layer", + "performance-options-layer", + "audio-options-layer", + "other-options-layer", + "music-offset-label", + "music-offset-background", + "music-offset-input" + ); + +#ifdef GEODE_IS_ANDROID + std::array gameplayMenu1NodeNames{ + "auto-retry", "enable-faster-reset", + "hide-attempts", "flip-pause-button", + "disable-portal-guide", "enable-orb-guide", + "disable-orb-scale", "disable-trigger-orb-scale", + "disable-explosion-shake", "disable-gravity-effect" + }; +#elif defined(GEODE_IS_MACOS) + std::array gameplayMenu1NodeNames{ + }; +#else + std::array gameplayMenu1NodeNames{ + "auto-retry", "enable-faster-reset", + "show-in-game-cursor", "lock-in-game-cursor", + "hide-attempts", "flip-pause-button", + "disable-portal-guide", "enable-orb-guide", + "disable-orb-scale", "disable-trigger-orb-scale" + }; +#endif + if (auto gameplayMenu1 = m_mainLayer->getChildByID("gameplay-options-layer-1")) { + auto nodes = CCArrayExt(gameplayMenu1->getChildren()); + + for (int i = 0; i < nodes.size(); i++) { + nodes[i]->setID(gameplayMenu1NodeNames.at(i) + "-label"); + } + } + +#ifdef GEODE_IS_ANDROID + std::array gameplayMenu2NodeNames{ + "default-mini-icon", "switch-spider-teleport-color", + "switch-dash-fire-color", "switch-wave-trail-color", + "flip-2-player-controls", "always-limit-controls" + }; +#elif defined(GEODE_IS_MACOS) + std::array gameplayMenu2NodeNames{ + }; +#else + std::array gameplayMenu2NodeNames{ + "disable-explosion-shake", "disable-gravity-effect", + "default-mini-icon", "switch-spider-teleport-color", + "switch-dash-fire-color", "switch-wave-trail-color", + "flip-2-player-controls", "always-limit-controls", + "disable-thumbstick", "enable-quick-keys" + }; +#endif + if (auto gameplayMenu2 = m_mainLayer->getChildByID("gameplay-options-layer-2")) { + auto nodes = CCArrayExt(gameplayMenu2->getChildren()); + + for (int i = 0; i < nodes.size(); i++) { + nodes[i]->setID(gameplayMenu2NodeNames.at(i) + "-label"); + } + } + +#ifdef GEODE_IS_ANDROID + std::array practiceMenuNodeNames{ + "hide-attempts", "enable-auto-checkpoints", + "enable-quick-checkpoints", "enable-death-effect", + "enable-normal-music-in-editor", "show-hitboxes", + "disable-player-hitbox" + }; +#elif defined(GEODE_IS_MACOS) + std::array practiceMenuNodeNames{ + }; +#else + std::array practiceMenuNodeNames{ + "hide-practice-buttons", "hide-attempts", + "enable-auto-checkpoints", "enable-quick-checkpoints", + "enable-death-effect", "enable-normal-music-in-editor", + "show-hitboxes", "disable-player-hitbox" + }; +#endif + if (auto practiceMenu = m_mainLayer->getChildByID("practice-options-layer")) { + auto nodes = CCArrayExt(practiceMenu->getChildren()); + + for (int i = 0; i < nodes.size(); i++) { + nodes[i]->setID(practiceMenuNodeNames.at(i) + "-label"); + } + } + +#ifdef GEODE_IS_ANDROID + std::array performanceMenuNodeNames{ + "enable-smooth-fix", "increase-draw-capacity", + "enable-low-detail", "disable-high-object-alert", + "enable-extra-ldm", "increase-maximum-levels", + "disable-level-saving", "save-gauntlets", + "disable-shader-anti-aliasing" + }; +#elif defined(GEODE_IS_MACOS) + std::array performanceMenuNodeNames{ + }; +#else + std::array performanceMenuNodeNames{ + "increase-draw-capacity", "enable-low-detail", + "disable-high-object-alert", "enable-extra-ldm", + "increase-maximum-levels", "disable-level-saving", + "save-gauntlets", "disable-shader-anti-aliasing" + }; +#endif + if (auto performanceMenu = m_mainLayer->getChildByID("performance-options-layer")) { + auto nodes = CCArrayExt(performanceMenu->getChildren()); + + for (int i = 0; i < nodes.size(); i++) { + nodes[i]->setID(performanceMenuNodeNames.at(i) + "-label"); + } + } + +#ifdef GEODE_IS_ANDROID + std::array audioMenuNodeNames{ + "disable-song-alert", "no-song-limit", + "reduce-quality", "audio-fix-01" + }; +#elif defined(GEODE_IS_MACOS) + std::array audioMenuNodeNames{ + }; +#else + std::array audioMenuNodeNames{ + "change-custom-songs-location", "disable-song-alert", + "no-song-limit", "reduce-quality", + "audio-fix-01" + }; +#endif + if (auto audioMenu = m_mainLayer->getChildByID("audio-options-layer")) { + auto nodes = CCArrayExt(audioMenu->getChildren()); + + for (int i = 0; i < nodes.size(); i++) { + nodes[i]->setID(audioMenuNodeNames.at(i) + "-label"); + } + } + +#ifdef GEODE_IS_ANDROID + std::array otherMenuNodeNames{ + "more-comments", "load-comments", + "new-completed-filter", "increase-local-levels-per-page", + "manual-level-order", "percentage-decimals", + "show-leaderboard-percentage", "do-not", + "confirm-exit", "fast-menu" + }; +#elif defined(GEODE_IS_MACOS) + std::array otherMenuNodeNames{ + }; +#else + std::array otherMenuNodeNames{ + "more-comments", "load-comments", + "new-completed-filter", "increase-local-levels-per-page", + "manual-level-order", "percentage-decimals", + "show-leaderboard-percentage", "do-not", + "confirm-exit", "fast-menu" + }; +#endif + if (auto otherMenu = m_mainLayer->getChildByID("other-options-layer")) { + auto nodes = CCArrayExt(otherMenu->getChildren()); + + for (int i = 0; i < nodes.size(); i++) { + nodes[i]->setID(otherMenuNodeNames.at(i) + "-label"); + } + } + + +#ifdef GEODE_IS_ANDROID + constexpr std::array, 6> pageIdxToObjectIdxStartEnd{ + std::make_pair(0, 20), // 10 togglers * 2 (multiplied by 2 to account for the toggler and the info icon) + std::make_pair(20, 32), // 6 togglers * 2 + std::make_pair(32, 46), // 7 togglers * 2 + std::make_pair(46, 64), // 9 togglers * 2 + std::make_pair(64, 72), // 4 togglers * 2 + std::make_pair(72, 91) // 10 togglers * 2 - 1 (because we are indexing by 2, in the last iteration, i == 90, so i+1 == 91, which is the last info icon) + }; +#elif defined(GEODE_IS_MACOS) + constexpr std::array, 0> pageIdxToObjectIdxStartEnd{ + + }; +#else + constexpr std::array, 6> pageIdxToObjectIdxStartEnd{ + std::make_pair(0, 20), // 10 togglers * 2 + std::make_pair(20, 40), // 10 togglers * 2 + std::make_pair(40, 56), // 8 togglers * 2 + std::make_pair(56, 72), // 8 togglers * 2 + std::make_pair(72, 82), // 5 togglers * 2 + std::make_pair(82, 101) // 10 togglers * 2 - 1 + }; +#endif + + if (auto togglersMenu = m_mainLayer->getChildByID("togglers-menu")) { + auto nodes = CCArrayExt(togglersMenu->getChildren()); + std::size_t arrayIdx = 0; + + for (int i = pageIdxToObjectIdxStartEnd[0].first; i < pageIdxToObjectIdxStartEnd[0].second; i += 2) { + nodes[i]->setID(gameplayMenu1NodeNames[arrayIdx] + "-toggler"); + nodes[i + 1]->setID(gameplayMenu1NodeNames[arrayIdx] + "-info"); + + arrayIdx++; + } + + arrayIdx = 0; + for (int i = pageIdxToObjectIdxStartEnd[1].first; i < pageIdxToObjectIdxStartEnd[1].second; i += 2) { + nodes[i]->setID(gameplayMenu2NodeNames[arrayIdx] + "-toggler"); + nodes[i + 1]->setID(gameplayMenu2NodeNames[arrayIdx] + "-info"); + + arrayIdx++; + } + + arrayIdx = 0; + for (int i = pageIdxToObjectIdxStartEnd[2].first; i < pageIdxToObjectIdxStartEnd[2].second; i += 2) { + nodes[i]->setID(practiceMenuNodeNames[arrayIdx] + "-toggler"); + nodes[i + 1]->setID(practiceMenuNodeNames[arrayIdx] + "-info"); + + arrayIdx++; + } + + arrayIdx = 0; + for (int i = pageIdxToObjectIdxStartEnd[3].first; i < pageIdxToObjectIdxStartEnd[3].second; i += 2) { + nodes[i]->setID(performanceMenuNodeNames[arrayIdx] + "-toggler"); + nodes[i + 1]->setID(performanceMenuNodeNames[arrayIdx] + "-info"); + + arrayIdx++; + } + + arrayIdx = 0; + for (int i = pageIdxToObjectIdxStartEnd[4].first; i < pageIdxToObjectIdxStartEnd[4].second; i += 2) { + nodes[i]->setID(audioMenuNodeNames[arrayIdx] + "-toggler"); + nodes[i + 1]->setID(audioMenuNodeNames[arrayIdx] + "-info"); + + arrayIdx++; + } + + arrayIdx = 0; + for (int i = pageIdxToObjectIdxStartEnd[5].first; i < pageIdxToObjectIdxStartEnd[5].second; i += 2) { + nodes[i]->setID(otherMenuNodeNames[arrayIdx] + "-toggler"); + nodes[i + 1]->setID(otherMenuNodeNames[arrayIdx] + "-info"); + + arrayIdx++; + } + + setIDs( + togglersMenu, + pageIdxToObjectIdxStartEnd[5].second + 1, + "saved-songs-button", + "fmod-debug-button", + "parental-control-button", + "close-button", + "left-arrow-button", + "right-arrow-button" +#ifndef GEODE_IS_ANDROID // sorry + , "key-bindings-button" +#endif + ); + } +} + +struct MoreOptionsLayerIDs : Modify { + static void onModify(auto& self) { + if (!self.setHookPriority("MoreOptionsLayer::init", GEODE_ID_PRIORITY)) { + log::warn("Failed to set MoreOptionsLayer::init hook priority, node IDs may not work properly"); + } + } + + bool init() { + if (!MoreOptionsLayer::init()) return false; + + NodeIDs::get()->provide(this); + + return true; + } +};