diff --git a/changelog.md b/changelog.md index 123f079..f77bd4f 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,6 @@ # Changelog ## v1.3.8 (2024-08-06) +* Added Pointercrate & AreDL setting for demon placement. * Added GDUtils GFX and GD Awards badges. * Added setting to show buttons for previewing icons colors when they are not unlocked. * Changed badges for GDUtils Developer and GDUtils collaborator badges. diff --git a/mod.json b/mod.json index ec39fd7..00169a3 100644 --- a/mod.json +++ b/mod.json @@ -229,6 +229,11 @@ "type": "bool", "default": true }, + "demonListSelection": { + "name": "Demon List Selection", + "description": "Whether or not to select between Pointercrate or AreDL for placements.", + "type": "custom" + }, "levelsProtocol": { "name": "Allow Levels Protocol", "description": "Whether or not to allow Geometry Dash to redirect to a level if you were to use a https://gdutils.com/ url, or gdutils: protocol.", diff --git a/src/Settings/CustomSettings.cpp b/src/Settings/CustomSettings.cpp index 32ba063..54f5522 100644 --- a/src/Settings/CustomSettings.cpp +++ b/src/Settings/CustomSettings.cpp @@ -17,6 +17,9 @@ SettingNode* SettingAppValue::createNode(float width) { SettingNode* SettingPosValue::createNode(float width) { return SettingPosNode::create(this, width); } +SettingNode* SettingDLPosValue::createNode(float width) { + return SettingDLNode::create(this, width); +} SettingNode* SettingCreditsValue::createNode(float width) { return SettingCreditsNode::create(this, width); } diff --git a/src/Settings/CustomSettings.hpp b/src/Settings/CustomSettings.hpp index dec5a6f..93a24f8 100644 --- a/src/Settings/CustomSettings.hpp +++ b/src/Settings/CustomSettings.hpp @@ -186,6 +186,176 @@ class SettingSectionNode : public SettingNode { } }; +// Pointercrate / AreDL setting + +const int DEFAULT_DL_POS = 2; + +struct SettingDLPosStruct { + int m_pos; +}; + +class SettingDLPosValue; + +class SettingDLPosValue : public SettingValue { +protected: + int m_pos; +public: + SettingDLPosValue(std::string const& key, std::string const& modID, int const& position) + : SettingValue(key, modID), m_pos(position) {} + + bool load(matjson::Value const& json) override { + try { + m_pos = static_cast(json.as()); + return true; + } catch(...) { + return false; + } + } + bool save(matjson::Value& json) const override { + json = static_cast(m_pos); + return true; + } + SettingNode* createNode(float width) override; + void setPos(int pos) { + m_pos = pos; + } + int getPos() const { + return m_pos; + } +}; +template<> +struct SettingValueSetter { + static SettingDLPosStruct get(SettingValue* setting) { + auto posSetting = static_cast(setting); + struct SettingDLPosStruct defaultStruct = { posSetting->getPos() }; + return defaultStruct; + }; + static void set(SettingDLPosValue* setting, SettingDLPosStruct const& value) { + setting->setPos(value.m_pos); + }; +}; + +class SettingDLNode : public SettingNode { + protected: + int m_currentPos; + CCMenuItemToggler* pcBtn; + CCMenuItemToggler* aredlBtn; + + int getActiveCornerTag(int corner) { + switch (corner) { + case 1: // AreDL + return 2008; + case 2: // Pointercrate + default: + return 2009; + } + } + + int tagToCorner(int tag) { + switch (tag) { + case 2008: // AreDL + return 1; + default: + case 2009: // Pointercrate + return 2; + } + } + + bool init(SettingDLPosValue* value, float width) { + if (!SettingNode::init(value)) + return false; + + auto pointercrate_text = CCLabelBMFont::create("Pointercrate", "goldFont.fnt"); + pointercrate_text->setScale(.6F); + pointercrate_text->setPosition(161, 16); + this->addChild(pointercrate_text); + + auto aredl_text = CCLabelBMFont::create("AreDL", "goldFont.fnt"); + aredl_text->setScale(.6F); + aredl_text->setPosition(276, 16); + this->addChild(aredl_text); + + m_currentPos = value->getPos(); + this->setContentSize({ width, 30.f }); + auto menu = CCMenu::create(); + CCSprite* toggleOn = CCSprite::createWithSpriteFrameName("GJ_checkOn_001.png"); + CCSprite* toggleOff = CCSprite::createWithSpriteFrameName("GJ_checkOff_001.png"); + toggleOn->setScale(.7F); + toggleOff->setScale(.7F); + menu->setPosition(width / 2, 23.f); + pcBtn = CCMenuItemToggler::create( + toggleOn, + toggleOff, + this, + menu_selector(SettingDLNode::onCornerClick) + ); + aredlBtn = CCMenuItemToggler::create( + toggleOn, + toggleOff, + this, + menu_selector(SettingDLNode::onCornerClick) + ); + pcBtn->setPosition({ -80, -8 }); + aredlBtn->setPosition({ 60, -8 }); + + pcBtn->setTag(getActiveCornerTag(2)); + aredlBtn->setTag(getActiveCornerTag(1)); + int currentCorner = m_currentPos; + pcBtn->toggle(!(pcBtn->getTag() == getActiveCornerTag(currentCorner))); + aredlBtn->toggle(!(aredlBtn->getTag() == getActiveCornerTag(currentCorner))); + + menu->addChild(pcBtn); + menu->addChild(aredlBtn); + + this->addChild(menu); + return true; + } + + void onCornerClick(CCObject* sender) { + pcBtn->toggle(true); + aredlBtn->toggle(true); + m_currentPos = tagToCorner(sender->getTag()); + this->dispatchChanged(); + }; + + void onInfoBtn(CCObject* sender) { + FLAlertLayer::create( + Mod::get()->getSettingDefinition(this->m_value->getKey())->get()->json->get("name").c_str(), + Mod::get()->getSettingDefinition(this->m_value->getKey())->get()->json->get("description").c_str(), + "OK" + )->show(); + } + public: + void commit() override { + static_cast(m_value)->setPos(m_currentPos); + this->dispatchCommitted(); + } + + bool hasUncommittedChanges() override { + return m_currentPos != static_cast(m_value)->getPos(); + } + + bool hasNonDefaultValue() override { + return m_currentPos != DEFAULT_DL_POS; + } + + void resetToDefault() override { + pcBtn->toggle(true); + aredlBtn->toggle(false); + m_currentPos = DEFAULT_DL_POS; + } + + static SettingDLNode* create(SettingDLPosValue* value, float width) { + auto ret = new SettingDLNode; + if (ret && ret->init(value, width)) { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; + } +}; + /* Notification Position */ diff --git a/src/Utils/DemonList.cpp b/src/Utils/DemonList.cpp index a2ce403..695e098 100644 --- a/src/Utils/DemonList.cpp +++ b/src/Utils/DemonList.cpp @@ -2,6 +2,7 @@ #include #include #include +#include "../Settings/CustomSettings.hpp" // demon list @@ -103,33 +104,54 @@ class $modify(LevelInfoLayer) { const geode::utils::MiniFunction)> then = [this, level, levelID, loading_circle, positionLabel, demonSpr, winSize](Result const& result_json) { matjson::Value json = result_json.value(); - if (loading_circle != nullptr) { - loading_circle->fadeAndRemove(); - } - auto scene = CCDirector::sharedDirector()->getRunningScene(); - if (json.dump() == "[]") { //idk how to check size, doing .count crashes - log::info("Level not found in pointercrate."); - this->release(); + int listId = Mod::get()->getSettingValue("demonListSelection").m_pos; + + if (listId == 2) { + if (loading_circle != nullptr) { + loading_circle->fadeAndRemove(); + } + auto scene = CCDirector::sharedDirector()->getRunningScene(); + if (json.dump() == "[]") { //idk how to check size, doing .count crashes + log::info("Level not found in Pointercrate."); + this->release(); + } else { + auto info = json.get(0); + auto position = info.get("position"); + positionLabel->setString(fmt::format("#{}", position).c_str()); + positionLabel->setScale(getScaleBasedPos(position)); + positionLabel->setVisible(true); + demonSpr->setVisible(true); + set(levelID, position); + log::info("Level found in Pointercrate! {} at #{}", level->m_levelName.c_str(), position); + this->release(); + } } else { - auto info = json.get(0); - auto position = info.get("position"); - positionLabel->setString(fmt::format("#{}", position).c_str()); - positionLabel->setScale(getScaleBasedPos(position)); - positionLabel->setVisible(true); - demonSpr->setVisible(true); - set(levelID, position); - log::info("Level found in Pointercrate! {} at #{}", level->m_levelName.c_str(), position); - this->release(); + if (loading_circle != nullptr) { + loading_circle->fadeAndRemove(); + } + auto scene = CCDirector::sharedDirector()->getRunningScene(); + if (json.contains("code")) { + this->release(); + } else { + auto position = json.get("position"); + positionLabel->setString(fmt::format("#{}", position).c_str()); + positionLabel->setScale(getScaleBasedPos(position)); + positionLabel->setVisible(true); + demonSpr->setVisible(true); + set(levelID, position); + log::info("Level found in AREDL! {} at #{}", level->m_levelName.c_str(), position); + this->release(); + } } }; const geode::utils::MiniFunction expect = [this, loading_circle](std::string const& error) { if (loading_circle != nullptr) { loading_circle->fadeAndRemove(); } - log::error("Error while sending a request to Pointercrate: {}", error); + log::error("Error while sending a request to Demon List: {}", error); FLAlertLayer::create(nullptr, "Error", - "Failed to make a request to Pointercrate. Please either try again later, look at the error logs to see what might have happened, or report this to the developers.", + "Failed to make a request to Demon List. Please either try again later, look at the error logs to see what might have happened, or report this to the developers.", "OK", nullptr, 350.0F @@ -137,11 +159,19 @@ class $modify(LevelInfoLayer) { this->release(); }; + int listId = Mod::get()->getSettingValue("demonListSelection").m_pos; + std::string url = ""; + if (listId == 2) { + url = fmt::format("https://pointercrate.com/api/v2/demons/listed/?name={}", url_encode(level->m_levelName).c_str()); + } else { + url = fmt::format("https://api.aredl.net/api/aredl/levels/{}", levelID); + } + geode::utils::web::WebRequest request = web::WebRequest(); const std::lock_guard lock(lock_var); RUNNING_REQUESTS.emplace( "@loaderDemonListLevelInfo", - request.get(fmt::format("https://pointercrate.com/api/v2/demons/listed/?name={}", url_encode(level->m_levelName).c_str())).map( + request.get(url.c_str()).map( [expect = std::move(expect), then = std::move(then)](web::WebResponse* response) { const std::lock_guard lock(lock_var); if (response->ok()) { diff --git a/src/main.cpp b/src/main.cpp index a233c97..c2e475b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -452,6 +452,7 @@ class $modify(MenuLayer) { Mod::get()->addCustomSetting("test-notification", "none"); Mod::get()->addCustomSetting("notificationPlacement", 4); + Mod::get()->addCustomSetting("demonListSelection", 2); // Sections Mod::get()->addCustomSetting("notification-section", "none"); Mod::get()->addCustomSetting("notification-placement-section", "none");