diff --git a/.gitmodules b/.gitmodules index 2029bf88..062479c6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,6 +4,3 @@ [submodule "loader/minhook"] path = loader/minhook url = https://github.com/TsudaKageyu/minhook -[submodule "loader/include/Geode/external/scnlib"] - path = loader/include/Geode/external/scnlib - url = https://github.com/eliaskosunen/scnlib diff --git a/CMakeLists.txt b/CMakeLists.txt index ebb53660..4491b65c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,7 +83,6 @@ add_definitions(-DFMT_CONSTEVAL=) add_subdirectory(loader/include/Geode/external/filesystem) add_subdirectory(loader/include/Geode/external/fmt) -add_subdirectory(loader/include/Geode/external/scnlib) target_link_libraries(${PROJECT_NAME} INTERFACE filesystem fmt) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index f4003cec..cfd1b3e1 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -237,8 +237,8 @@ class cocos2d::CCIMEDispatcher { static auto sharedDispatcher() = mac 0x2773f0, ios 0x12d170; auto addDelegate(cocos2d::CCIMEDelegate*) = mac 0x277480, ios 0x12d204; auto removeDelegate(cocos2d::CCIMEDelegate*) = mac 0x2775f0, ios 0x12d2c4; - void dispatchInsertText(const char* text, int len); - void dispatchDeleteBackward(); + void dispatchInsertText(const char* text, int len) = mac 0x277ac0; + void dispatchDeleteBackward() = mac 0x277af0; } class cocos2d::CCImage { diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index d9da60d6..d93f7444 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -129,7 +129,7 @@ target_link_libraries(${PROJECT_NAME} md4c) # Lilac (hooking) add_subdirectory(lilac) -target_link_libraries(${PROJECT_NAME} z lilac_hook geode-sdk scn::scn) +target_link_libraries(${PROJECT_NAME} z lilac_hook geode-sdk) # Use precompiled headers for faster builds target_precompile_headers(${PROJECT_NAME} PRIVATE diff --git a/loader/include/Geode/UI.hpp b/loader/include/Geode/UI.hpp index 1c9c39cd..2330064c 100644 --- a/loader/include/Geode/UI.hpp +++ b/loader/include/Geode/UI.hpp @@ -6,7 +6,7 @@ #include "ui/BasedButtonSprite.hpp" #include "ui/IconButtonSprite.hpp" #include "ui/InputNode.hpp" -#include "ui/LayerBG.hpp" +#include "ui/General.hpp" #include "ui/ListView.hpp" #include "ui/MDPopup.hpp" #include "ui/MDTextArea.hpp" diff --git a/loader/include/Geode/external/scnlib b/loader/include/Geode/external/scnlib deleted file mode 160000 index 72a4bab9..00000000 --- a/loader/include/Geode/external/scnlib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 72a4bab9e32f2b44593137fba40c54710e20a623 diff --git a/loader/include/Geode/meta/membercall.hpp b/loader/include/Geode/meta/membercall.hpp index 334509cb..6a70a241 100644 --- a/loader/include/Geode/meta/membercall.hpp +++ b/loader/include/Geode/meta/membercall.hpp @@ -196,7 +196,7 @@ namespace geode::core::meta::x86 { class Membercall { protected: - using Sequences = Membercall::Sequences; + using Sequences = typename Membercall::Sequences; // Where all the logic is actually implemented. template diff --git a/loader/include/Geode/platform/platform.hpp b/loader/include/Geode/platform/platform.hpp index 88164d28..109aa893 100644 --- a/loader/include/Geode/platform/platform.hpp +++ b/loader/include/Geode/platform/platform.hpp @@ -27,6 +27,8 @@ #define GEODE_API extern "C" __declspec(dllexport) #define GEODE_EXPORT __declspec(dllexport) + static_assert(sizeof(void*) == 4, "Geode must be compiled in 32-bit for Windows!"); + #include "windows.hpp" #elif defined(GEODE_IS_MACOS) diff --git a/loader/include/Geode/ui/LayerBG.hpp b/loader/include/Geode/ui/General.hpp similarity index 60% rename from loader/include/Geode/ui/LayerBG.hpp rename to loader/include/Geode/ui/General.hpp index 123a4f52..941e2dbf 100644 --- a/loader/include/Geode/ui/LayerBG.hpp +++ b/loader/include/Geode/ui/General.hpp @@ -10,4 +10,13 @@ namespace geode { * packs the ability to override this function. */ GEODE_DLL cocos2d::CCSprite* createLayerBG(); + + /** + * Add the rounded comment borders to a node + */ + GEODE_DLL void addListBorders( + cocos2d::CCNode* to, + cocos2d::CCPoint const& center, + cocos2d::CCSize const& size + ); } diff --git a/loader/include/Geode/utils/VersionInfo.hpp b/loader/include/Geode/utils/VersionInfo.hpp index 8f6c5468..99183860 100644 --- a/loader/include/Geode/utils/VersionInfo.hpp +++ b/loader/include/Geode/utils/VersionInfo.hpp @@ -4,6 +4,7 @@ #include #include "../external/json/json.hpp" #include +#include "../utils/Result.hpp" namespace geode { enum class VersionCompare { @@ -55,8 +56,8 @@ namespace geode { m_patch = patch; m_tag = tag; } - VersionInfo(std::string const& versionString); - static bool validate(std::string const& string); + + static Result parse(std::string const& string); constexpr size_t getMajor() const { return m_major; @@ -114,8 +115,8 @@ namespace geode { VersionInfo const& version, VersionCompare const& compare ) : m_version(version), m_compare(compare) {} - ComparableVersionInfo(std::string const& versionString); - static bool validate(std::string const& string); + + static Result parse(std::string const& string); constexpr bool compare(VersionInfo const& version) const { switch (m_compare) { diff --git a/loader/launcher/windows/proxyLoader.c b/loader/launcher/windows/proxyLoader.c index 6070af7a..9f35c4c4 100644 --- a/loader/launcher/windows/proxyLoader.c +++ b/loader/launcher/windows/proxyLoader.c @@ -32,4 +32,4 @@ BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID _) { return FALSE; } return TRUE; -} \ No newline at end of file +} diff --git a/loader/src/loader/ModInfo.cpp b/loader/src/loader/ModInfo.cpp index 3dad5578..ec4f51ae 100644 --- a/loader/src/loader/ModInfo.cpp +++ b/loader/src/loader/ModInfo.cpp @@ -48,7 +48,7 @@ Result ModInfo::createFromSchemaV010(ModJson const& rawJson) { using nlohmann::detail::value_t; root.needs("id").validate(&ModInfo::validateID).into(info.id); - root.needs("version").validate(&VersionInfo::validate).into(info.version); + root.needs("version").into(info.version); root.needs("name").into(info.name); root.needs("developer").into(info.developer); root.has("description").into(info.description); @@ -62,9 +62,7 @@ Result ModInfo::createFromSchemaV010(ModJson const& rawJson) { auto depobj = Dependency {}; obj.needs("id").validate(&ModInfo::validateID).into(depobj.id); - obj.needs("version") - .validate(&ComparableVersionInfo::validate) - .into(depobj.version); + obj.needs("version").into(depobj.version); obj.has("required").into(depobj.required); obj.checkUnknownKeys(); @@ -116,16 +114,10 @@ Result ModInfo::create(ModJson const& json) { // Check mod.json target version auto schema = LOADER_VERSION; if (json.contains("geode") && json["geode"].is_string()) { - auto ver = json["geode"]; - if (VersionInfo::validate(ver)) { - schema = VersionInfo(ver); - } - else { - return Err( - "[mod.json] has no target loader version " - "specified, or it is invalidally formatted (required: \"[v]X.X.X\")!" - ); - } + GEODE_UNWRAP_INTO( + schema, VersionInfo::parse(json["geode"]) + .expect("[mod.json] has invalid target loader version: {error}") + ); } else { return Err( diff --git a/loader/src/ui/internal/info/DevProfilePopup.cpp b/loader/src/ui/internal/info/DevProfilePopup.cpp new file mode 100644 index 00000000..3f5285ef --- /dev/null +++ b/loader/src/ui/internal/info/DevProfilePopup.cpp @@ -0,0 +1,55 @@ +#include "DevProfilePopup.hpp" +#include +#include +#include +#include "../list/ModListCell.hpp" +#include "../list/ModListLayer.hpp" + +bool DevProfilePopup::setup(std::string const& developer) { + m_noElasticity = true; + + this->setTitle("Mods by " + developer); + + auto winSize = CCDirector::get()->getWinSize(); + + auto items = CCArray::create(); + + // installed mods + for (auto& mod : Loader::get()->getAllMods()) { + if (mod->getDeveloper() == developer) { + items->addObject(ModCell::create( + mod, nullptr, ModListDisplay::Concise, { 358.f, 40.f } + )); + } + } + + // index mods + for (auto& item : Index::get()->getItemsByDeveloper(developer)) { + if (Loader::get()->isModInstalled(item->info.id)) { + continue; + } + items->addObject(IndexItemCell::create( + item, nullptr, ModListDisplay::Concise, { 358.f, 40.f } + )); + } + + // mods list + auto listSize = CCSize { 358.f, 160.f }; + auto list = ListView::create(items, 40.f, listSize.width, listSize.height); + list->setPosition(winSize / 2 - listSize / 2); + m_mainLayer->addChild(list); + + addListBorders(m_mainLayer, winSize / 2, listSize); + + return true; +} + +DevProfilePopup* DevProfilePopup::create(std::string const& developer) { + auto ret = new DevProfilePopup(); + if (ret && ret->init(420.f, 260.f, developer)) { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; +} diff --git a/loader/src/ui/internal/info/DevProfilePopup.hpp b/loader/src/ui/internal/info/DevProfilePopup.hpp new file mode 100644 index 00000000..054cc172 --- /dev/null +++ b/loader/src/ui/internal/info/DevProfilePopup.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +USE_GEODE_NAMESPACE(); + +class DevProfilePopup : public Popup { +protected: + bool setup(std::string const& developer) override; + +public: + static DevProfilePopup* create(std::string const& developer); +}; diff --git a/loader/src/ui/internal/info/ModInfoPopup.cpp b/loader/src/ui/internal/info/ModInfoPopup.cpp index 8f02f941..195cde78 100644 --- a/loader/src/ui/internal/info/ModInfoPopup.cpp +++ b/loader/src/ui/internal/info/ModInfoPopup.cpp @@ -423,7 +423,9 @@ void LocalModInfoPopup::onEnableMod(CCObject* sender) { "need to restart the game to have it fully unloaded.", "OK" )->show(); - if (m_layer) m_layer->updateAllStates(nullptr); + if (m_layer) { + m_layer->updateAllStates(nullptr); + } return; } if (as(sender)->isToggled()) { @@ -438,7 +440,9 @@ void LocalModInfoPopup::onEnableMod(CCObject* sender) { FLAlertLayer::create(nullptr, "Error Disabling Mod", res.unwrapErr(), "OK", nullptr)->show(); } } - if (m_layer) m_layer->updateAllStates(nullptr); + if (m_layer) { + m_layer->updateAllStates(nullptr); + } as(sender)->toggle(m_mod->isEnabled()); } @@ -477,7 +481,9 @@ void LocalModInfoPopup::FLAlert_Clicked(FLAlertLayer* layer, bool btn2) { FLAlertLayer::create("Error", "Unable to delete mod's save directory!", "OK")->show(); } } - if (m_layer) m_layer->reloadList(); + if (m_layer) { + m_layer->reloadList(); + } this->onClose(nullptr); } break; } diff --git a/loader/src/ui/internal/list/ModListCell.cpp b/loader/src/ui/internal/list/ModListCell.cpp index 606f484d..f2fa5687 100644 --- a/loader/src/ui/internal/list/ModListCell.cpp +++ b/loader/src/ui/internal/list/ModListCell.cpp @@ -1,7 +1,7 @@ + #include "ModListCell.hpp" #include "ModListLayer.hpp" #include "../info/ModInfoPopup.hpp" - #include #include #include @@ -10,6 +10,7 @@ #include #include "../../../loader/LoaderImpl.hpp" // how should i include this src/loader/LoaderImpl.hpp #include "../info/TagNode.hpp" +#include "../info/DevProfilePopup.hpp" template static bool tryOrAlert(Result const& res, char const* title) { @@ -27,7 +28,11 @@ float ModListCell::getLogoSize() const { return m_height / 1.5f; } -void ModListCell::setupInfo(ModInfo const& info, bool spaceForTags) { +void ModListCell::setupInfo( + ModInfo const& info, + bool spaceForTags, + ModListDisplay display +) { m_menu = CCMenu::create(); m_menu->setPosition(m_width - 40.f, m_height / 2); this->addChild(m_menu); @@ -39,7 +44,7 @@ void ModListCell::setupInfo(ModInfo const& info, bool spaceForTags) { this->addChild(logoSpr); bool hasDesc = - m_layer->getDisplay() == ModListDisplay::Expanded && + display == ModListDisplay::Expanded && info.description.has_value(); auto titleLabel = CCLabelBMFont::create(info.name.c_str(), "bigFont.fnt"); @@ -135,8 +140,7 @@ void ModListCell::setupInfo(ModInfo const& info, bool spaceForTags) { } void ModListCell::onViewDev(CCObject*) { - m_layer->getQuery().developer = this->getDeveloper(); - m_layer->reloadList(); + DevProfilePopup::create(this->getDeveloper())->show(); } bool ModListCell::init(ModListLayer* list, CCSize const& size) { @@ -153,10 +157,11 @@ bool ModListCell::init(ModListLayer* list, CCSize const& size) { ModCell* ModCell::create( Mod* mod, ModListLayer* list, + ModListDisplay display, CCSize const& size ) { auto ret = new ModCell(); - if (ret && ret->init(mod, list, size)) { + if (ret && ret->init(mod, list, display, size)) { return ret; } CC_SAFE_DELETE(ret); @@ -173,7 +178,9 @@ void ModCell::onEnable(CCObject* sender) { "need to restart the game to have it fully unloaded.", "OK" )->show(); - m_layer->updateAllStates(this); + if (m_layer) { + m_layer->updateAllStates(this); + } return; } if (!as(sender)->isToggled()) { @@ -182,7 +189,9 @@ void ModCell::onEnable(CCObject* sender) { else { tryOrAlert(m_mod->disable(), "Error disabling mod"); } - m_layer->updateAllStates(this); + if (m_layer) { + m_layer->updateAllStates(this); + } } void ModCell::onUnresolvedInfo(CCObject*) { @@ -220,6 +229,7 @@ void ModCell::updateState() { bool ModCell::init( Mod* mod, ModListLayer* list, + ModListDisplay display, CCSize const& size ) { if (!ModListCell::init(list, size)) @@ -227,7 +237,7 @@ bool ModCell::init( m_mod = mod; - this->setupInfo(mod->getModInfo(), false); + this->setupInfo(mod->getModInfo(), false, display); auto viewSpr = ButtonSprite::create("View", "bigFont.fnt", "GJ_button_01.png", .8f); viewSpr->setScale(.65f); @@ -285,10 +295,11 @@ void IndexItemCell::onInfo(CCObject*) { IndexItemCell* IndexItemCell::create( IndexItemHandle item, ModListLayer* list, + ModListDisplay display, CCSize const& size ) { auto ret = new IndexItemCell(); - if (ret && ret->init(item, list, size)) { + if (ret && ret->init(item, list, display, size)) { return ret; } CC_SAFE_DELETE(ret); @@ -298,6 +309,7 @@ IndexItemCell* IndexItemCell::create( bool IndexItemCell::init( IndexItemHandle item, ModListLayer* list, + ModListDisplay display, CCSize const& size ) { if (!ModListCell::init(list, size)) @@ -305,7 +317,7 @@ bool IndexItemCell::init( m_item = item; - this->setupInfo(item->info, item->tags.size()); + this->setupInfo(item->info, item->tags.size(), display); auto viewSpr = ButtonSprite::create( "View", "bigFont.fnt", "GJ_button_01.png", .8f @@ -384,13 +396,16 @@ void InvalidGeodeFileCell::FLAlert_Clicked(FLAlertLayer*, bool btn2) { ->show(); } Loader::get()->refreshModsList(); - m_layer->reloadList(); + if (m_layer) { + m_layer->reloadList(); + } } } bool InvalidGeodeFileCell::init( InvalidGeodeFile const& info, ModListLayer* list, + ModListDisplay display, CCSize const& size ) { if (!ModListCell::init(list, size)) @@ -431,10 +446,11 @@ bool InvalidGeodeFileCell::init( InvalidGeodeFileCell* InvalidGeodeFileCell::create( InvalidGeodeFile const& file, ModListLayer* list, + ModListDisplay display, CCSize const& size ) { auto ret = new InvalidGeodeFileCell(); - if (ret && ret->init(file, list, size)) { + if (ret && ret->init(file, list, display, size)) { ret->autorelease(); return ret; } diff --git a/loader/src/ui/internal/list/ModListCell.hpp b/loader/src/ui/internal/list/ModListCell.hpp index bf521651..783633ed 100644 --- a/loader/src/ui/internal/list/ModListCell.hpp +++ b/loader/src/ui/internal/list/ModListCell.hpp @@ -25,7 +25,7 @@ protected: CCMenuItemSpriteExtra* m_unresolvedExMark; bool init(ModListLayer* list, CCSize const& size); - void setupInfo(ModInfo const& info, bool spaceForTags); + void setupInfo(ModInfo const& info, bool spaceForTags, ModListDisplay display); void draw() override; float getLogoSize() const; @@ -47,6 +47,7 @@ protected: bool init( Mod* mod, ModListLayer* list, + ModListDisplay display, CCSize const& size ); @@ -58,6 +59,7 @@ public: static ModCell* create( Mod* mod, ModListLayer* list, + ModListDisplay display, CCSize const& size ); @@ -76,6 +78,7 @@ protected: bool init( IndexItemHandle item, ModListLayer* list, + ModListDisplay display, CCSize const& size ); @@ -85,6 +88,7 @@ public: static IndexItemCell* create( IndexItemHandle item, ModListLayer* list, + ModListDisplay display, CCSize const& size ); @@ -103,6 +107,7 @@ protected: bool init( InvalidGeodeFile const& file, ModListLayer* list, + ModListDisplay display, CCSize const& size ); @@ -113,6 +118,7 @@ public: static InvalidGeodeFileCell* create( InvalidGeodeFile const& file, ModListLayer* list, + ModListDisplay display, CCSize const& size ); diff --git a/loader/src/ui/internal/list/ModListLayer.cpp b/loader/src/ui/internal/list/ModListLayer.cpp index b8648551..5ba9386e 100644 --- a/loader/src/ui/internal/list/ModListLayer.cpp +++ b/loader/src/ui/internal/list/ModListLayer.cpp @@ -73,12 +73,9 @@ static std::optional queryMatchKeywords( } static std::optional queryMatch(ModListQuery const& query, Mod* mod) { - // Only checking keywords and developer makes sense for mods since their + // Only checking keywords makes sense for mods since their // platform always matches, they are always visible and they don't // currently list their tags - if (query.developer && query.developer.value() != mod->getDeveloper()) { - return std::nullopt; - } return queryMatchKeywords(query, mod->getModInfo()); } @@ -88,10 +85,6 @@ static std::optional queryMatch(ModListQuery const& query, IndexItemHandle if (!query.forceVisibility && Loader::get()->isModInstalled(item->info.id)) { return std::nullopt; } - // make sure developer matches - if (query.developer && query.developer.value() != item->info.developer) { - return std::nullopt; - } // make sure all tags match for (auto& tag : query.tags) { if (!item->tags.count(tag)) { @@ -127,7 +120,6 @@ static std::optional queryMatch(ModListQuery const& query, IndexItemHandle static std::optional queryMatch(ModListQuery const& query, InvalidGeodeFile const& info) { // if any explicit filters were provided, no match if ( - query.developer.has_value() || query.tags.size() || query.keywords.has_value() ) { @@ -144,7 +136,9 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer // failed mods first for (auto const& mod : Loader::get()->getFailedMods()) { if (!queryMatch(query, mod)) continue; - mods->addObject(InvalidGeodeFileCell::create(mod, this, this->getCellSize())); + mods->addObject(InvalidGeodeFileCell::create( + mod, this, m_display, this->getCellSize() + )); } // sort the mods by match score @@ -173,7 +167,9 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer // add the mods sorted for (auto& [score, mod] : ranges::reverse(sorted)) { - mods->addObject(ModCell::create(mod, this, this->getCellSize())); + mods->addObject(ModCell::create( + mod, this, m_display, this->getCellSize() + )); } } break; @@ -189,7 +185,9 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer // add the mods sorted for (auto& [score, item] : ranges::reverse(sorted)) { - mods->addObject(IndexItemCell::create(item, this, this->getCellSize())); + mods->addObject(IndexItemCell::create( + item, this, m_display, this->getCellSize() + )); } } break; @@ -205,7 +203,9 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer // add the mods sorted for (auto& [score, item] : ranges::reverse(sorted)) { - mods->addObject(IndexItemCell::create(item, this, this->getCellSize())); + mods->addObject(IndexItemCell::create( + item, this, m_display, this->getCellSize() + )); } } break; } @@ -489,8 +489,7 @@ void ModListLayer::reloadList(std::optional const& query) { // and show visual indicator if so auto hasQuery = (m_searchInput->getString() && - strlen(m_searchInput->getString())) || - m_query.developer; + strlen(m_searchInput->getString())); m_searchBtn->setVisible(!hasQuery); m_searchClearBtn->setVisible(hasQuery); @@ -606,8 +605,6 @@ void ModListLayer::onOpenFolder(CCObject*) { } void ModListLayer::onResetSearch(CCObject*) { - // todo: remove when implementing more reasonable developer view - m_query.developer = std::nullopt; m_searchInput->setString(""); } diff --git a/loader/src/ui/internal/list/ModListLayer.hpp b/loader/src/ui/internal/list/ModListLayer.hpp index 323ea6a3..b78d3b98 100644 --- a/loader/src/ui/internal/list/ModListLayer.hpp +++ b/loader/src/ui/internal/list/ModListLayer.hpp @@ -34,10 +34,6 @@ struct ModListQuery { */ std::unordered_set platforms = { GEODE_PLATFORM_TARGET }; std::unordered_set tags; - /** - * Used to filter by dev if you click their name - */ - std::optional developer; }; class ModListLayer : public CCLayer, public TextInputDelegate { diff --git a/loader/src/ui/internal/settings/ModSettingsPopup.cpp b/loader/src/ui/internal/settings/ModSettingsPopup.cpp index 55873826..931572fc 100644 --- a/loader/src/ui/internal/settings/ModSettingsPopup.cpp +++ b/loader/src/ui/internal/settings/ModSettingsPopup.cpp @@ -5,6 +5,7 @@ #include #include #include +#include bool ModSettingsPopup::setup(Mod* mod) { m_noElasticity = true; @@ -77,29 +78,7 @@ bool ModSettingsPopup::setup(Mod* mod) { // layer borders - auto layerTopSpr = CCSprite::createWithSpriteFrameName("GJ_commentTop_001.png"); - layerTopSpr->setPosition({ winSize.width / 2, winSize.height / 2 + layerSize.height / 2 - 5.f } - ); - m_mainLayer->addChild(layerTopSpr); - - auto layerBottomSpr = CCSprite::createWithSpriteFrameName("GJ_commentTop_001.png"); - layerBottomSpr->setFlipY(true); - layerBottomSpr->setPosition({ winSize.width / 2, - winSize.height / 2 - layerSize.height / 2 + 5.f }); - m_mainLayer->addChild(layerBottomSpr); - - auto layerLeftSpr = CCSprite::createWithSpriteFrameName("GJ_commentSide_001.png"); - layerLeftSpr->setScaleY(6.3f); - layerLeftSpr->setPosition({ winSize.width / 2 - layerSize.width / 2 - .5f, winSize.height / 2 } - ); - m_mainLayer->addChild(layerLeftSpr); - - auto layerRightSpr = CCSprite::createWithSpriteFrameName("GJ_commentSide_001.png"); - layerRightSpr->setScaleY(6.3f); - layerRightSpr->setFlipX(true); - layerRightSpr->setPosition({ winSize.width / 2 + layerSize.width / 2 + .5f, winSize.height / 2 } - ); - m_mainLayer->addChild(layerRightSpr); + addListBorders(m_mainLayer, winSize / 2, layerSize); // buttons diff --git a/loader/src/ui/nodes/General.cpp b/loader/src/ui/nodes/General.cpp new file mode 100644 index 00000000..b73b9423 --- /dev/null +++ b/loader/src/ui/nodes/General.cpp @@ -0,0 +1,91 @@ +#include +#include + +USE_GEODE_NAMESPACE(); + +CCSprite* geode::createLayerBG() { + auto winSize = CCDirector::get()->getWinSize(); + + auto bg = CCSprite::create("GJ_gradientBG.png"); + auto bgSize = bg->getTextureRect().size; + + bg->setAnchorPoint({ 0.0f, 0.0f }); + bg->setScaleX((winSize.width + 10.0f) / bgSize.width); + bg->setScaleY((winSize.height + 10.0f) / bgSize.height); + bg->setPosition({ -5.0f, -5.0f }); + bg->setColor({ 0, 102, 255 }); // todo: let mods customize this + + return bg; +} + +void geode::addListBorders(CCNode* to, CCPoint const& center, CCSize const& size) { + // if the size is 346.f, the top aligns perfectly by default :3 + if (size.width == 346.f) { + auto layerTopSpr = CCSprite::createWithSpriteFrameName("GJ_commentTop_001.png"); + layerTopSpr->setPosition({ + center.x, + center.y + size.height / 2 - 5.f + }); + to->addChild(layerTopSpr); + + auto layerBottomSpr = CCSprite::createWithSpriteFrameName("GJ_commentTop_001.png"); + layerBottomSpr->setFlipY(true); + layerBottomSpr->setPosition({ + center.x, + center.y - size.height / 2 + 5.f + }); + to->addChild(layerBottomSpr); + } + // otherwise stretch using CCScale9Sprite + else { + auto layerTopSpr = CCScale9Sprite::createWithSpriteFrameName( + "GJ_commentTop_001.png", + { 0, 0, 240, 20 } + ); + layerTopSpr->setContentSize({ + size.width + 9.f, + layerTopSpr->getContentSize().height, + }); + layerTopSpr->setPosition({ + center.x, + center.y + size.height / 2 - 5.f + }); + to->addChild(layerTopSpr); + + auto layerBottomSpr = CCScale9Sprite::createWithSpriteFrameName( + "GJ_commentTop_001.png", + { 0, 0, 240, 20 } + ); + layerBottomSpr->setScaleY(-1); + layerBottomSpr->setContentSize({ + size.width + 9.f, + layerBottomSpr->getContentSize().height, + }); + layerBottomSpr->setPosition({ + center.x, + center.y - size.height / 2 + 5.f + }); + to->addChild(layerBottomSpr); + } + + auto layerLeftSpr = CCSprite::createWithSpriteFrameName("GJ_commentSide_001.png"); + layerLeftSpr->setScaleY( + (size.height - 30.f) / layerLeftSpr->getScaledContentSize().height + ); + layerLeftSpr->setPosition({ + center.x - size.width / 2 - .5f, + center.y + }); + to->addChild(layerLeftSpr); + + auto layerRightSpr = CCSprite::createWithSpriteFrameName("GJ_commentSide_001.png"); + layerRightSpr->setScaleY( + (size.height - 30.f) / layerRightSpr->getScaledContentSize().height + ); + layerRightSpr->setFlipX(true); + layerRightSpr->setPosition({ + center.x + size.width / 2 + .5f, + center.y + }); + to->addChild(layerRightSpr); +} diff --git a/loader/src/ui/nodes/LayerBG.cpp b/loader/src/ui/nodes/LayerBG.cpp deleted file mode 100644 index 18b6f326..00000000 --- a/loader/src/ui/nodes/LayerBG.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include - -USE_GEODE_NAMESPACE(); - -CCSprite* geode::createLayerBG() { - auto winSize = CCDirector::get()->getWinSize(); - - auto bg = CCSprite::create("GJ_gradientBG.png"); - auto bgSize = bg->getTextureRect().size; - - bg->setAnchorPoint({ 0.0f, 0.0f }); - bg->setScaleX((winSize.width + 10.0f) / bgSize.width); - bg->setScaleY((winSize.height + 10.0f) / bgSize.height); - bg->setPosition({ -5.0f, -5.0f }); - bg->setColor({ 0, 102, 255 }); // todo: let mods customize this - - return bg; -} diff --git a/loader/src/utils/VersionInfo.cpp b/loader/src/utils/VersionInfo.cpp index b8b5dd61..c564a737 100644 --- a/loader/src/utils/VersionInfo.cpp +++ b/loader/src/utils/VersionInfo.cpp @@ -4,16 +4,9 @@ #include #include -#include USE_GEODE_NAMESPACE(); -#ifdef GEODE_IS_WINDOWS - #define GEODE_SSCANF sscanf_s -#else - #define GEODE_SSCANF sscanf -#endif - // VersionTag std::optional geode::versionTagFromString(std::string const& str) { @@ -45,37 +38,57 @@ std::string geode::versionTagToString(VersionTag tag) { // VersionInfo -bool VersionInfo::validate(std::string const& string) { - std::string copy = string; - if (copy.starts_with("v")) { - copy = string.substr(1); - } - - int buf0, buf1, buf2; - std::string bufT; - if (scn::scan(copy, "{}.{}.{}-{}", buf0, buf1, buf2, bufT)) { - return versionTagFromString(bufT).has_value(); - } - if (scn::scan(copy, "{}.{}.{}", buf0, buf1, buf2)) { - return true; +Result VersionInfo::parse(std::string const& string) { + std::stringstream str (string); + + // allow leading v + if (str.peek() == 'v') { + str.get(); } - return false; -} - -VersionInfo::VersionInfo(std::string const& string) { - std::string copy = string; - if (copy.starts_with("v")) { - copy = string.substr(1); + size_t major; + str >> major; + if (str.fail()) { + return Err("Unable to parse major"); } - std::string tag; - scn::scan(copy, "{}.{}.{}-{}", m_major, m_minor, m_patch, tag) || - scn::scan(copy, "{}.{}.{}", m_major, m_minor, m_patch); - if (tag.size()) { - if (auto t = versionTagFromString(tag)) { - m_tag = t; + + if (str.get() != '.') { + return Err("Minor version missing"); + } + + size_t minor; + str >> minor; + if (str.fail()) { + return Err("Unable to parse minor"); + } + + if (str.get() != '.') { + return Err("Patch version missing"); + } + + size_t patch; + str >> patch; + if (str.fail()) { + return Err("Unable to parse patch"); + } + + // tag + std::optional tag; + if (str.peek() == '-') { + str.get(); + std::string iden; + str >> iden; + if (str.fail()) { + return Err("Unable to parse tag"); + } + if (auto t = versionTagFromString(iden)) { + tag = t; + } + else { + return Err("Invalid tag \"" + iden + "\""); } } + return Ok(VersionInfo(major, minor, patch, tag)); } std::string VersionInfo::toString(bool includeTag) const { @@ -94,7 +107,13 @@ void geode::to_json(nlohmann::json& json, VersionInfo const& info) { } void geode::from_json(nlohmann::json const& json, VersionInfo& info) { - info = VersionInfo(json.template get()); + auto ver = VersionInfo::parse(json.template get()); + if (!ver) { + throw nlohmann::json::type_error::create( + 0, "Invalid version format: " + ver.unwrapErr(), json + ); + } + info = ver.unwrap(); } std::ostream& geode::operator<<(std::ostream& stream, VersionInfo const& version) { @@ -103,35 +122,23 @@ std::ostream& geode::operator<<(std::ostream& stream, VersionInfo const& version // ComparableVersionInfo -ComparableVersionInfo::ComparableVersionInfo(std::string const& rawStr) { - auto version = rawStr; - if (version.starts_with("<=")) { - m_compare = VersionCompare::LessEq; - version.erase(0, 2); +Result ComparableVersionInfo::parse(std::string const& rawStr) { + VersionCompare compare; + auto string = rawStr; + if (string.starts_with("<=")) { + compare = VersionCompare::LessEq; + string.erase(0, 2); } - else if (version.starts_with(">=")) { - m_compare = VersionCompare::MoreEq; - version.erase(0, 2); + else if (string.starts_with(">=")) { + compare = VersionCompare::MoreEq; + string.erase(0, 2); } - else if (version.starts_with("==")) { - m_compare = VersionCompare::Exact; - version.erase(0, 2); + else if (string.starts_with("==")) { + compare = VersionCompare::Exact; + string.erase(0, 2); } - m_version = VersionInfo(version); -} - -bool ComparableVersionInfo::validate(std::string const& rawStr) { - auto version = rawStr; - // remove prefix - if ( - version.starts_with("<=") || - version.starts_with(">=") || - version.starts_with("==") - ) { - version.erase(0, 2); - } - // otherwise there's no prefix or it's invalid - return VersionInfo::validate(version); + GEODE_UNWRAP_INTO(auto version, VersionInfo::parse(string)); + return Ok(ComparableVersionInfo(version, compare)); } std::string ComparableVersionInfo::toString() const { @@ -149,7 +156,13 @@ void geode::to_json(nlohmann::json& json, ComparableVersionInfo const& info) { } void geode::from_json(nlohmann::json const& json, ComparableVersionInfo& info) { - info = ComparableVersionInfo(json.template get()); + auto ver = ComparableVersionInfo::parse(json.template get()); + if (!ver) { + throw nlohmann::json::type_error::create( + 0, "Invalid version format: " + ver.unwrapErr(), json + ); + } + info = ver.unwrap(); } std::ostream& geode::operator<<(std::ostream& stream, ComparableVersionInfo const& version) {