diff --git a/loader/include/Geode/ui/MDTextArea.hpp b/loader/include/Geode/ui/MDTextArea.hpp index 82b62697..86937af3 100644 --- a/loader/include/Geode/ui/MDTextArea.hpp +++ b/loader/include/Geode/ui/MDTextArea.hpp @@ -26,7 +26,7 @@ namespace geode { * - Lists * * Note that links also have some special protocols. - * Use `user:<id>` or `user:<name>` to link to a GD + * Use `user:<accountID>` to link to a GD * account; `level:<id>` to link to a GD level and * `mod:<id>` to link to another Geode mod. */ @@ -48,6 +48,8 @@ namespace geode { void onLink(CCObject*); void onGDProfile(CCObject*); + void onGDLevel(CCObject*); + void onGeodeMod(CCObject*); void FLAlert_Clicked(FLAlertLayer*, bool btn) override; friend struct ::MDParser; diff --git a/loader/src/ui/internal/GeodeUI.cpp b/loader/src/ui/internal/GeodeUI.cpp index a0cd1ccf..ad584ca4 100644 --- a/loader/src/ui/internal/GeodeUI.cpp +++ b/loader/src/ui/internal/GeodeUI.cpp @@ -1,4 +1,3 @@ - #include "info/ModInfoPopup.hpp" #include "list/ModListLayer.hpp" #include "settings/ModSettingsPopup.hpp" diff --git a/loader/src/ui/internal/info/ModInfoPopup.cpp b/loader/src/ui/internal/info/ModInfoPopup.cpp index 8e9740e1..131620c6 100644 --- a/loader/src/ui/internal/info/ModInfoPopup.cpp +++ b/loader/src/ui/internal/info/ModInfoPopup.cpp @@ -606,7 +606,8 @@ IndexItemInfoPopup::IndexItemInfoPopup() bool IndexItemInfoPopup::init(IndexItemHandle item, ModListLayer* list) { m_item = item; - m_installListener.setFilter(m_item->getMetadata().getID()); + auto metadata = m_item->getMetadata(); + m_installListener.setFilter(metadata.getID()); auto winSize = CCDirector::sharedDirector()->getWinSize(); diff --git a/loader/src/ui/nodes/MDTextArea.cpp b/loader/src/ui/nodes/MDTextArea.cpp index 1d9228c2..e2470daf 100644 --- a/loader/src/ui/nodes/MDTextArea.cpp +++ b/loader/src/ui/nodes/MDTextArea.cpp @@ -1,6 +1,10 @@ #include <Geode/binding/ProfilePage.hpp> +#include <Geode/binding/LevelTools.hpp> +#include <Geode/binding/LevelInfoLayer.hpp> #include <Geode/binding/CCContentLayer.hpp> #include <Geode/loader/Mod.hpp> +#include <Geode/loader/Loader.hpp> +#include <Geode/loader/Index.hpp> #include <Geode/ui/MDTextArea.hpp> #include <Geode/utils/casts.hpp> #include <Geode/utils/cocos.hpp> @@ -10,6 +14,7 @@ #include <md4c.h> #include <charconv> #include <Geode/loader/Log.hpp> +#include "../internal/info/ModInfoPopup.hpp" using namespace geode::prelude; @@ -192,7 +197,7 @@ void MDTextArea::onGDProfile(CCObject* pSender) { "Error", "Invalid profile ID: <cr>" + profile + "</c>. This is " - "probably the modder's fault, report the bug to them.", + "probably the mod developer's fault, report the bug to them.", "OK" ) ->show(); @@ -201,6 +206,67 @@ void MDTextArea::onGDProfile(CCObject* pSender) { ProfilePage::create(id, false)->show(); } +void MDTextArea::onGDLevel(CCObject* pSender) { + auto href = as<CCString*>(as<CCNode*>(pSender)->getUserObject()); + auto level = std::string(href->getCString()); + level = level.substr(level.find(":") + 1); + int id = 0; + auto res = std::from_chars(level.data(), level.data() + level.size(), id); + if (res.ec != std::errc()) { + FLAlertLayer::create( + "Error", + "Invalid level ID: <cr>" + level + + "</c>. This is " + "probably the mod developers's fault, report the bug to them.", + "OK" + ) + ->show(); + return; + } + auto searchObject = GJSearchObject::create(SearchType::Type19, fmt::format("{}&gameVersion=22", id)); + auto scene = LevelBrowserLayer::scene(searchObject); + CCDirector::sharedDirector()->replaceScene(CCTransitionFade::create(0.5f, scene)); +} + +void MDTextArea::onGeodeMod(CCObject* pSender) { + auto href = as<CCString*>(as<CCNode*>(pSender)->getUserObject()); + auto modString = std::string(href->getCString()); + modString = modString.substr(modString.find(":") + 1); + auto loader = Loader::get(); + auto index = Index::get(); + Mod* mod; + bool success = false; + IndexItemHandle indexItem; + bool isIndexMod = !loader->isModInstalled(modString); + + if (isIndexMod) { + auto indexSearch = index->getItemsByModID(modString); + if (indexSearch.size() != 0) { + indexItem = indexSearch.back(); + Mod mod2 = Mod(indexItem->getMetadata()); + mod = &mod2; + auto item = Index::get()->getItem(mod); + IndexItemInfoPopup::create(item, nullptr)->show(); + success = true; + } + } else { + mod = loader->getLoadedMod(modString); + LocalModInfoPopup::create(mod, nullptr)->show(); + success = true; + } + + if (!success) { + FLAlertLayer::create( + "Error", + "Invalid mod ID: <cr>" + modString + + "</c>. This is " + "probably the mod developers's fault, report the bug to them.", + "OK" + ) + ->show(); + } +} + void MDTextArea::FLAlert_Clicked(FLAlertLayer* layer, bool btn) { if (btn) { web::openLinkInBrowser(as<CCString*>(layer->getUserObject())->getCString()); @@ -256,7 +322,11 @@ struct MDParser { text, textarea, utils::string::startsWith(s_lastLink, "user:") ? menu_selector(MDTextArea::onGDProfile) - : menu_selector(MDTextArea::onLink) + : utils::string::startsWith(s_lastLink, "level:") + ? menu_selector(MDTextArea::onGDLevel) + : utils::string::startsWith(s_lastLink, "mod:") + ? menu_selector(MDTextArea::onGeodeMod) + : menu_selector(MDTextArea::onLink) ); for (auto const& label : rendered) { label.m_node->setUserObject(CCString::create(s_lastLink));