From d7f8a0248ab58a6dce2f6f3d8a7e9852e6da8925 Mon Sep 17 00:00:00 2001 From: hjfod Date: Mon, 20 Mar 2023 18:10:20 +0200 Subject: [PATCH 01/70] bindins --- bindings/GeometryDash.bro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index d7281efb..972d4d33 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -3644,7 +3644,8 @@ class LevelEditorLayer : GJBaseGameLayer, LevelSettingsDelegate { bool hasAction(bool) = mac 0x96ff0; void handleAction(bool, cocos2d::CCArray*) = mac 0x97020, win 0x162010; bool init(GJGameLevel*) = mac 0x91010, win 0x15EE00; - void objectAtPosition(cocos2d::CCPoint) = mac 0x960c0, win 0x161300; + GameObject* objectAtPosition(cocos2d::CCPoint position) = mac 0x960c0, win 0x161300; + cocos2d::CCArray* objectsAtPosition(cocos2d::CCPoint position) = win 0x1614d0; void objectMoved(GameObject*) = mac 0x999f0, win 0x162d40; cocos2d::CCArray* objectsInRect(cocos2d::CCRect rect, bool ignoreLayer) = mac 0x95e60, win 0x161ad0; void onPlaytest() = mac 0xa06b0, win 0x1695A0; From 94138f32ad02e2d9b52cb0217555875d8d76dc52 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Mon, 20 Mar 2023 19:08:42 +0200 Subject: [PATCH 02/70] fix hooking callback functions --- bindings/GeometryDash.bro | 2 +- codegen/src/Shared.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 972d4d33..6cd5c72e 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -3692,7 +3692,7 @@ class LevelEditorLayer : GJBaseGameLayer, LevelSettingsDelegate { } void updateOptions() = mac 0x91ed0, win 0x15fcc0; void updateToggledGroups() = mac 0x9bb10; - void updateVisibility(float) = mac 0x92c70, win 0x1632b0; + callback void updateVisibility(float delta) = mac 0x92c70, win 0x1632b0; void groupStickyObjects(cocos2d::CCArray* objects) = mac 0x99dd0, win 0x164860; void ungroupStickyObjects(cocos2d::CCArray* objects) = mac 0x99ee0, win 0x164950; diff --git a/codegen/src/Shared.hpp b/codegen/src/Shared.hpp index 371d868d..d6e414a8 100644 --- a/codegen/src/Shared.hpp +++ b/codegen/src/Shared.hpp @@ -184,7 +184,7 @@ namespace codegen { if (status == BindStatus::Binded) return "tulip::hook::CdeclConvention"; else return "tulip::hook::OptcallConvention"; } - else if (fn->is_virtual) { + else if (fn->is_virtual || fn->is_callback) { return "tulip::hook::ThiscallConvention"; } else { @@ -205,7 +205,7 @@ namespace codegen { if (status == BindStatus::Binded) return "Cdecl"; else return "Optcall"; } - else if (fn->is_virtual) { + else if (fn->is_virtual || fn->is_callback) { return "Thiscall"; } else { From 33a2883058ce0fb7f27df9246dded65c941af239 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Mon, 20 Mar 2023 15:42:01 -0300 Subject: [PATCH 03/70] remove duplicate code for codegen calling convention --- codegen/src/Shared.hpp | 54 ++++++++++-------------------------------- 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/codegen/src/Shared.hpp b/codegen/src/Shared.hpp index d6e414a8..e8279f2d 100644 --- a/codegen/src/Shared.hpp +++ b/codegen/src/Shared.hpp @@ -153,48 +153,6 @@ namespace codegen { return fmt::format("{}", fmt::join(parameters, ", ")); } - inline std::string getConvention(Field& f) { - if (codegen::platform != Platform::Windows) return "DefaultConv"; - - if (auto fn = f.get_fn()) { - auto status = getStatus(f); - - if (fn->is_static) { - if (status == BindStatus::Binded) return "x86::Cdecl"; - else return "x86::Optcall"; - } - else if (fn->is_virtual || fn->is_callback) { - return "x86::Thiscall"; - } - else { - if (status == BindStatus::Binded) return "x86::Thiscall"; - else return "x86::Membercall"; - } - } - else throw codegen::error("Tried to get convention of non-function"); - } - - inline std::string getModifyConvention(Field& f) { - if (codegen::platform != Platform::Windows) return "tulip::hook::DefaultConvention"; - - if (auto fn = f.get_fn()) { - auto status = getStatus(f); - - if (fn->is_static) { - if (status == BindStatus::Binded) return "tulip::hook::CdeclConvention"; - else return "tulip::hook::OptcallConvention"; - } - else if (fn->is_virtual || fn->is_callback) { - return "tulip::hook::ThiscallConvention"; - } - else { - if (status == BindStatus::Binded) return "tulip::hook::ThiscallConvention"; - else return "tulip::hook::MembercallConvention"; - } - } - else throw codegen::error("Tried to get convention of non-function"); - } - inline std::string getModifyConventionName(Field& f) { if (codegen::platform != Platform::Windows) return "Default"; @@ -216,6 +174,18 @@ namespace codegen { else throw codegen::error("Tried to get convention of non-function"); } + inline std::string getConvention(Field& f) { + if (codegen::platform != Platform::Windows) return "DefaultConv"; + + return std::string("x86::") + getModifyConventionName(f); + } + + inline std::string getModifyConvention(Field& f) { + if (codegen::platform != Platform::Windows) return "tulip::hook::DefaultConvention"; + + return std::string("tulip::hook::") + getModifyConventionName(f) + "Convention"; + } + inline std::string getUnqualifiedClassName(std::string const& s) { auto index = s.rfind("::"); if (index == std::string::npos) return s; From 7686c85e4f7f9861520d5b8dd6066a83f7dc735e Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Mon, 20 Mar 2023 21:01:55 +0200 Subject: [PATCH 04/70] editor binding --- bindings/GeometryDash.bro | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 6cd5c72e..09d69200 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -1239,6 +1239,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ void setupCreateMenu() = mac 0xcb50, win 0x7caf0; void undoLastAction(cocos2d::CCObject*) = mac 0xb830, win 0x87070; void updateButtons() = mac 0x1a300, win 0x78280; + void updateEditMenu() = win 0x8b010; void updateObjectInfoLabel() = mac 0x1cb10, win 0x793b0; void updateSlider() = mac 0x18a90, win 0x78f10; void updateZoom(float) = mac 0x248c0, win 0x878a0; From 7d953793e2455b0e61dd6f23f5de933ba9d1a634 Mon Sep 17 00:00:00 2001 From: qimiko <25387744+qimiko@users.noreply.github.com> Date: Mon, 20 Mar 2023 14:23:32 -0700 Subject: [PATCH 05/70] fix target arch on arm mac --- cmake/Platform.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/Platform.cmake b/cmake/Platform.cmake index ae69001a..0bb025ca 100644 --- a/cmake/Platform.cmake +++ b/cmake/Platform.cmake @@ -30,6 +30,9 @@ elseif (GEODE_TARGET_PLATFORM STREQUAL "MacOS") APPLE_SILICON_PROCESSOR x86_64 ) + # this should be set globally + set(CMAKE_OSX_ARCHITECTURES "x86_64") + # only exists as a global property set(CMAKE_OSX_DEPLOYMENT_TARGET 10.14) From 4318a8d53e1982a2666eaaac461b34f5f73ea82b Mon Sep 17 00:00:00 2001 From: hjfod Date: Tue, 21 Mar 2023 08:54:11 +0200 Subject: [PATCH 06/70] fix setup_geode_mod not linking sdk if cli calls are disabled --- cmake/GeodeFile.cmake | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/GeodeFile.cmake b/cmake/GeodeFile.cmake index eddcc445..c77cba41 100644 --- a/cmake/GeodeFile.cmake +++ b/cmake/GeodeFile.cmake @@ -53,6 +53,13 @@ function(setup_geode_mod proname) set(multiValueArgs EXTERNALS) cmake_parse_arguments(SETUP_GEODE_MOD "${options}" "" "${multiValueArgs}" ${ARGN}) + # Add package target + make output name the mod id + set_target_properties(${proname} PROPERTIES PREFIX "") + set_target_properties(${proname} PROPERTIES OUTPUT_NAME ${MOD_ID}) + + # Link Geode to the mod + target_link_libraries(${proname} geode-sdk) + if (GEODE_DISABLE_CLI_CALLS) message("Skipping setting up geode mod ${proname}") return() @@ -124,10 +131,6 @@ function(setup_geode_mod proname) set(HAS_HEADERS Off) endif() - # Add package target + make output name the mod id - set_target_properties(${proname} PROPERTIES PREFIX "") - set_target_properties(${proname} PROPERTIES OUTPUT_NAME ${MOD_ID}) - # todo: figure out how to either not make cmake shit itself and print out --binary path/to/dll "" or # make cli not shit itself when it sees that if (HAS_HEADERS) @@ -199,9 +202,6 @@ function(setup_geode_mod proname) endif() - # Link Geode to the mod - target_link_libraries(${proname} geode-sdk) - endfunction() function(create_geode_file proname) From 2ddbb2d72db148e100de983c979610483b5c62d2 Mon Sep 17 00:00:00 2001 From: hjfod Date: Tue, 21 Mar 2023 08:55:13 +0200 Subject: [PATCH 07/70] MOD_ID is not known at that point whoops --- cmake/GeodeFile.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/GeodeFile.cmake b/cmake/GeodeFile.cmake index c77cba41..2d8770cc 100644 --- a/cmake/GeodeFile.cmake +++ b/cmake/GeodeFile.cmake @@ -53,10 +53,6 @@ function(setup_geode_mod proname) set(multiValueArgs EXTERNALS) cmake_parse_arguments(SETUP_GEODE_MOD "${options}" "" "${multiValueArgs}" ${ARGN}) - # Add package target + make output name the mod id - set_target_properties(${proname} PROPERTIES PREFIX "") - set_target_properties(${proname} PROPERTIES OUTPUT_NAME ${MOD_ID}) - # Link Geode to the mod target_link_libraries(${proname} geode-sdk) @@ -202,6 +198,10 @@ function(setup_geode_mod proname) endif() + # Add package target + make output name the mod id + set_target_properties(${proname} PROPERTIES PREFIX "") + set_target_properties(${proname} PROPERTIES OUTPUT_NAME ${MOD_ID}) + endfunction() function(create_geode_file proname) From 7ca9959b1b8653a78a801e4e766ab502ac8591a6 Mon Sep 17 00:00:00 2001 From: hjfod Date: Tue, 21 Mar 2023 09:19:19 +0200 Subject: [PATCH 08/70] add GEODE_DONT_INSTALL_MODS --- cmake/GeodeFile.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/GeodeFile.cmake b/cmake/GeodeFile.cmake index 2d8770cc..a5389ef4 100644 --- a/cmake/GeodeFile.cmake +++ b/cmake/GeodeFile.cmake @@ -112,7 +112,7 @@ function(setup_geode_mod proname) endif() # Check if --install should be passed - if (SETUP_GEODE_MOD_DONT_INSTALL) + if (SETUP_GEODE_MOD_DONT_INSTALL OR GEODE_DONT_INSTALL_MODS) message(STATUS "Skipping installing ${proname}") set(INSTALL_ARG "") else() From f2d683a9318d1eb6b9e8b3f5a949a1289dd57fcf Mon Sep 17 00:00:00 2001 From: hjfod Date: Tue, 21 Mar 2023 09:23:26 +0200 Subject: [PATCH 09/70] pass CLI_PATH through PATHS instead of global variable --- cmake/GeodeFile.cmake | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cmake/GeodeFile.cmake b/cmake/GeodeFile.cmake index a5389ef4..2110d809 100644 --- a/cmake/GeodeFile.cmake +++ b/cmake/GeodeFile.cmake @@ -1,13 +1,8 @@ set(GEODE_CLI_MINIMUM_VERSION 1.0.5) -# for passing CLI through CMake arguments -if (DEFINED CLI_PATH) - list(APPEND CMAKE_PROGRAM_PATH ${CLI_PATH}) -endif() - # Find Geode CLI if (NOT DEFINED GEODE_CLI) - find_program(GEODE_CLI NAMES geode.exe geode-cli.exe geode geode-cli) + find_program(GEODE_CLI NAMES geode.exe geode-cli.exe geode geode-cli PATHS ${CLI_PATH}) endif() # Check if CLI was found From 93fd396ed9278e844fceb8c7e4ca0153c9119883 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Tue, 21 Mar 2023 22:01:10 +0200 Subject: [PATCH 10/70] ensure mod events are only posted in gd thread --- loader/include/Geode/cocos/cocoa/CCObject.h | 15 +++++++-------- loader/src/loader/ModImpl.cpp | 21 ++++++++++++++++----- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/loader/include/Geode/cocos/cocoa/CCObject.h b/loader/include/Geode/cocos/cocoa/CCObject.h index daeb19bf..baeb8bf9 100644 --- a/loader/include/Geode/cocos/cocoa/CCObject.h +++ b/loader/include/Geode/cocos/cocoa/CCObject.h @@ -47,14 +47,13 @@ NS_CC_BEGIN * @{ */ -RT_ADD( - // please someone tell we why in higher being(s)'s name rob did this - enum class CCObjectType { - PlayLayer = 5, - LevelEditorLayer = 6, - MenuLayer = 15, - }; -) +// please someone tell we why in higher being(s)'s name rob did this +enum class CCObjectType { + PlayLayer = 5, + LevelEditorLayer = 6, + GameObject = 13, + MenuLayer = 15, +}; class CCZone; class CCObject; diff --git a/loader/src/loader/ModImpl.cpp b/loader/src/loader/ModImpl.cpp index dc51c84a..4bb01c95 100644 --- a/loader/src/loader/ModImpl.cpp +++ b/loader/src/loader/ModImpl.cpp @@ -116,7 +116,9 @@ std::vector Mod::Impl::getHooks() const { // Settings and saved values Result<> Mod::Impl::loadData() { - ModStateEvent(m_self, ModEventType::DataLoaded).post(); + Loader::get()->queueInGDThread([&]() { + ModStateEvent(m_self, ModEventType::DataLoaded).post(); + }); // Settings // Check if settings exist @@ -182,6 +184,7 @@ Result<> Mod::Impl::loadData() { } Result<> Mod::Impl::saveData() { + // saveData is expected to be synchronous, and always called from GD thread ModStateEvent(m_self, ModEventType::DataSaved).post(); // Data saving should be fully fail-safe @@ -308,7 +311,9 @@ Result<> Mod::Impl::loadBinary() { LoaderImpl::get()->releaseNextMod(); - ModStateEvent(m_self, ModEventType::Loaded).post(); + Loader::get()->queueInGDThread([&]() { + ModStateEvent(m_self, ModEventType::Loaded).post(); + }); Loader::get()->updateAllDependencies(); @@ -329,7 +334,9 @@ Result<> Mod::Impl::unloadBinary() { GEODE_UNWRAP(this->saveData()); GEODE_UNWRAP(this->disable()); - ModStateEvent(m_self, ModEventType::Unloaded).post(); + Loader::get()->queueInGDThread([&]() { + ModStateEvent(m_self, ModEventType::Unloaded).post(); + }); // Disabling unhooks and unpatches already for (auto const& hook : m_hooks) { @@ -367,7 +374,9 @@ Result<> Mod::Impl::enable() { } } - ModStateEvent(m_self, ModEventType::Enabled).post(); + Loader::get()->queueInGDThread([&]() { + ModStateEvent(m_self, ModEventType::Enabled).post(); + }); m_enabled = true; return Ok(); @@ -381,7 +390,9 @@ Result<> Mod::Impl::disable() { return Err("Mod does not support disabling"); } - ModStateEvent(m_self, ModEventType::Disabled).post(); + Loader::get()->queueInGDThread([&]() { + ModStateEvent(m_self, ModEventType::Disabled).post(); + }); for (auto const& hook : m_hooks) { GEODE_UNWRAP(this->disableHook(hook)); From 72728464bba9eebab01f981b5806955c19dfca0d Mon Sep 17 00:00:00 2001 From: hjfod Date: Wed, 22 Mar 2023 17:31:47 +0200 Subject: [PATCH 11/70] editor stuff --- bindings/GeometryDash.bro | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 09d69200..dee0eff2 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -1111,6 +1111,12 @@ class EditButtonBar : cocos2d::CCNode { } void loadFromItems(cocos2d::CCArray* buttons, int rowCount, int columnCount, bool idk) = mac 0x351010, win 0x6e5e0, ios 0x2dd060; + static EditButtonBar* create( + cocos2d::CCArray* buttons, + cocos2d::CCPoint point, + int idk, bool idk0, + int rowCount, int columnCount + ) = win 0x6e450; cocos2d::CCPoint m_position; int m_unknown; @@ -1249,6 +1255,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ void selectAll() = win 0x86c40; void selectAllWithDirection(bool left) = win 0x86d80; cocos2d::CCPoint getTouchPoint(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) = win 0x90620; + cocos2d::CCPoint getGridSnappedPos(cocos2d::CCPoint pos) = win 0x90550; void onSelectBuildTab(cocos2d::CCObject* sender) = win 0x887f0; void onCreateButton(cocos2d::CCObject* sender) = win 0x854f0; CCMenuItemSpriteExtra* getSpriteButton(const char* sprite, cocos2d::SEL_MenuHandler callback, cocos2d::CCMenu* menu, float scale) = mac 0xb500, win 0x78bf0; @@ -3640,7 +3647,7 @@ class LevelEditorLayer : GJBaseGameLayer, LevelSettingsDelegate { void getNextFreeBlockID(cocos2d::CCArray*) = mac 0x9a4e0; int getNextFreeGroupID(cocos2d::CCArray*) = mac 0x9a1b0, win 0x164ae0; void getNextFreeItemID(cocos2d::CCArray*) = mac 0x9a390; - void getObjectRect(GameObject*, bool) = mac 0x96240, win 0x1616b0; + cocos2d::CCRect getObjectRect(GameObject* obj, bool updateRect) = mac 0x96240, win 0x1616b0; void getRelativeOffset(GameObject*) = mac 0x96840; bool hasAction(bool) = mac 0x96ff0; void handleAction(bool, cocos2d::CCArray*) = mac 0x97020, win 0x162010; From 11299df20cd4ed82dd0c8b460afff51c0561375d Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Wed, 22 Mar 2023 21:49:29 +0200 Subject: [PATCH 12/70] remove uses of RT_ADD + more bindings --- bindings/GeometryDash.bro | 1 + loader/include/Geode/cocos/cocoa/CCArray.h | 20 ++++++++------------ loader/include/Geode/utils/cocos.hpp | 2 +- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index dee0eff2..693923cf 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -1327,6 +1327,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ virtual void scrollWheel(float vertical, float horizontal) = win 0x921d0, mac 0x31370, ios 0x2c4884; void createMoveMenu() = mac 0x275e0, win 0x8c0d0; void sliderChanged(cocos2d::CCObject* slider) = win 0x78cc0; + void repositionObjectsToCenter(cocos2d::CCArray* objs, cocos2d::CCPoint center, bool ignoreGroupParent) = win 0x88410; virtual void draw() = win 0x8fbe0; bool m_isPlayingMusic; diff --git a/loader/include/Geode/cocos/cocoa/CCArray.h b/loader/include/Geode/cocos/cocoa/CCArray.h index f6d53a8b..282d804c 100644 --- a/loader/include/Geode/cocos/cocoa/CCArray.h +++ b/loader/include/Geode/cocos/cocoa/CCArray.h @@ -177,12 +177,10 @@ public: unsigned int indexOfObject(CCObject* object) const; /** Returns an element with a certain index */ CCObject* objectAtIndex(unsigned int index); - RT_ADD( - /** - * Rob modification - * Returns an element with a certain index casted to CCString */ - CCString* stringAtIndex(unsigned int index); - ); + /** + * Rob modification + * Returns an element with a certain index casted to CCString */ + CCString* stringAtIndex(unsigned int index); /** * Returns first element, or null if empty @@ -202,12 +200,10 @@ public: /** Add a certain object */ void addObject(CCObject* object); - RT_ADD( - /** - * Rob modification - * Add a certain object */ - void addObjectNew(CCObject* object); - ); + /** + * Rob modification + * Add a certain object */ + void addObjectNew(CCObject* object); /** Add all elements of an existing array */ void addObjectsFromArray(CCArray* otherArray); /** Insert a certain object at a certain index */ diff --git a/loader/include/Geode/utils/cocos.hpp b/loader/include/Geode/utils/cocos.hpp index 2090cc7b..ba469853 100644 --- a/loader/include/Geode/utils/cocos.hpp +++ b/loader/include/Geode/utils/cocos.hpp @@ -25,7 +25,7 @@ struct json::Serialize { }; // operators for CC geometry -namespace geode { +namespace cocos2d { static cocos2d::CCPoint& operator*=(cocos2d::CCPoint& pos, float mul) { pos.x *= mul; pos.y *= mul; From dc4f029bf3773fc95350cf366f908bea061fd95b Mon Sep 17 00:00:00 2001 From: hjfod Date: Thu, 23 Mar 2023 18:01:10 +0200 Subject: [PATCH 13/70] add CCEGLView::setupWindow --- bindings/Cocos2d.bro | 1 + loader/include/Geode/cocos/platform/win32/CCEGLView.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 25995ed0..0c8dbc67 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -176,6 +176,7 @@ class cocos2d::CCEGLView { static cocos2d::CCEGLView* sharedOpenGLView() = mac 0x295320; virtual void swapBuffers() = mac 0x295510; void updateWindow(int width, int height); + void setupWindow(cocos2d::CCRect); void toggleFullScreen(bool fullscreen); void pollEvents(); void onGLFWCharCallback(GLFWwindow* window, unsigned int entered); diff --git a/loader/include/Geode/cocos/platform/win32/CCEGLView.h b/loader/include/Geode/cocos/platform/win32/CCEGLView.h index 15a0f65f..556e3c7d 100644 --- a/loader/include/Geode/cocos/platform/win32/CCEGLView.h +++ b/loader/include/Geode/cocos/platform/win32/CCEGLView.h @@ -63,6 +63,8 @@ public: protected: RT_REMOVE( virtual bool Create(); ) + void setupWindow(cocos2d::CCRect rect); + public: bool initGL(); void destroyGL(); From a5e33668aaea315bc5c007effdf8bd6cdf1a121d Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Thu, 23 Mar 2023 19:14:09 +0200 Subject: [PATCH 14/70] add filter to EventListenerNode --- loader/include/Geode/utils/cocos.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/loader/include/Geode/utils/cocos.hpp b/loader/include/Geode/utils/cocos.hpp index ba469853..c22eae53 100644 --- a/loader/include/Geode/utils/cocos.hpp +++ b/loader/include/Geode/utils/cocos.hpp @@ -375,8 +375,8 @@ namespace geode { return nullptr; } - static EventListenerNode* create(typename Filter::Callback callback) { - auto ret = new EventListenerNode(EventListener(callback)); + static EventListenerNode* create(typename Filter::Callback callback, Filter filter = Filter()) { + auto ret = new EventListenerNode(EventListener(callback, filter)); if (ret && ret->init()) { ret->autorelease(); return ret; @@ -385,7 +385,6 @@ namespace geode { return nullptr; } - template static EventListenerNode* create( C* cls, typename EventListener::template MemberFn callback From 9bdd9fc52689356f00c71d0e98df41a04c23f86b Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Thu, 23 Mar 2023 21:42:01 +0200 Subject: [PATCH 15/70] add event listener stuff --- loader/include/Geode/cocos/base_nodes/CCNode.h | 9 +++++++++ loader/include/Geode/loader/Event.hpp | 5 +++-- loader/src/hooks/GeodeNodeMetadata.cpp | 8 ++++++++ loader/src/loader/Event.cpp | 11 ++++++----- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index 7f602de7..d3c8d102 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -39,6 +39,7 @@ #include "../include/CCProtocols.h" #include "Layout.hpp" #include +#include "../../loader/Event.hpp" NS_CC_BEGIN @@ -851,6 +852,7 @@ private: GEODE_DLL geode::modifier::FieldContainer* getFieldContainer(); GEODE_DLL std::optional getAttributeInternal(std::string const& attribute); + GEODE_DLL void addEventListenerInternal(geode::EventListenerProtocol* protocol); public: /** @@ -986,6 +988,13 @@ public: * @note Geode addition */ GEODE_DLL void swapChildIndices(CCNode* first, CCNode* second); + + template + void addEventListener(Filter::Callback listener, Args&&... args) { + this->addEventListenerInternal(new geode::EventListener( + listener, Filter(this, std::forward(args)...) + )); + } /// @{ /// @name Shader Program diff --git a/loader/include/Geode/loader/Event.hpp b/loader/include/Geode/loader/Event.hpp index 7fb0d901..5c5a02eb 100644 --- a/loader/include/Geode/loader/Event.hpp +++ b/loader/include/Geode/loader/Event.hpp @@ -1,6 +1,7 @@ #pragma once #include "../utils/casts.hpp" +#include "../utils/MiniFunction.hpp" #include #include @@ -126,7 +127,7 @@ namespace geode { class GEODE_DLL [[nodiscard]] Event { private: - static std::unordered_set& listeners(); + static std::vector& listeners(); friend EventListenerProtocol; public: @@ -137,7 +138,7 @@ namespace geode { void post() { postFrom(getMod()); } - + virtual ~Event(); }; } diff --git a/loader/src/hooks/GeodeNodeMetadata.cpp b/loader/src/hooks/GeodeNodeMetadata.cpp index 6300960f..84a418fd 100644 --- a/loader/src/hooks/GeodeNodeMetadata.cpp +++ b/loader/src/hooks/GeodeNodeMetadata.cpp @@ -22,6 +22,7 @@ private: Ref m_layout = nullptr; std::unique_ptr m_layoutOptions = nullptr; std::unordered_map m_attributes; + std::vector m_eventListeners; friend class ProxyCCNode; friend class cocos2d::CCNode; @@ -30,6 +31,9 @@ private: virtual ~GeodeNodeMetadata() { delete m_fieldContainer; + for (auto& listener : m_eventListeners) { + delete listener; + } } public: @@ -177,4 +181,8 @@ std::optional CCNode::getAttributeInternal(std::string const& attr) { return std::nullopt; } +void CCNode::addEventListenerInternal(EventListenerProtocol* protocol) { + GeodeNodeMetadata::set(this)->m_eventListeners.push_back(protocol); +} + #pragma warning(pop) diff --git a/loader/src/loader/Event.cpp b/loader/src/loader/Event.cpp index 92ebcf3c..adc29542 100644 --- a/loader/src/loader/Event.cpp +++ b/loader/src/loader/Event.cpp @@ -1,13 +1,14 @@ #include +#include using namespace geode::prelude; void EventListenerProtocol::enable() { - Event::listeners().insert(this); + Event::listeners().push_back(this); } void EventListenerProtocol::disable() { - Event::listeners().erase(this); + ranges::remove(Event::listeners(), this); } EventListenerProtocol::~EventListenerProtocol() { @@ -19,7 +20,7 @@ Event::~Event() {} void Event::postFrom(Mod* m) { if (m) this->sender = m; - std::unordered_set listeners_copy = Event::listeners(); + std::vector listeners_copy = Event::listeners(); for (auto h : listeners_copy) { if (h->passThrough(this) == ListenerResult::Stop) { @@ -28,7 +29,7 @@ void Event::postFrom(Mod* m) { } } -std::unordered_set& Event::listeners() { - static std::unordered_set listeners; +std::vector& Event::listeners() { + static std::vector listeners; return listeners; } From e962d5b89fecf598d41dc94cef4b0aaffb04efa1 Mon Sep 17 00:00:00 2001 From: hjfod Date: Fri, 24 Mar 2023 09:43:46 +0200 Subject: [PATCH 16/70] fix mac build --- loader/include/Geode/cocos/base_nodes/CCNode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index d3c8d102..7a076c31 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -990,7 +990,7 @@ public: GEODE_DLL void swapChildIndices(CCNode* first, CCNode* second); template - void addEventListener(Filter::Callback listener, Args&&... args) { + void addEventListener(typename Filter::Callback listener, Args&&... args) { this->addEventListenerInternal(new geode::EventListener( listener, Filter(this, std::forward(args)...) )); From 52c308e65dbd787031935d2ee625d127bf49721a Mon Sep 17 00:00:00 2001 From: hjfod Date: Sat, 25 Mar 2023 18:22:34 +0200 Subject: [PATCH 17/70] event stuff --- loader/include/Geode/cocos/base_nodes/CCNode.h | 9 ++++++--- loader/include/Geode/loader/Event.hpp | 8 +++++++- loader/src/hooks/GeodeNodeMetadata.cpp | 8 ++++++-- loader/src/loader/Event.cpp | 4 ++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index 7a076c31..485c1966 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -990,11 +990,14 @@ public: GEODE_DLL void swapChildIndices(CCNode* first, CCNode* second); template - void addEventListener(typename Filter::Callback listener, Args&&... args) { - this->addEventListenerInternal(new geode::EventListener( + geode::EventListenerProtocol* addEventListener(typename Filter::Callback listener, Args&&... args) { + auto listener = new geode::EventListener( listener, Filter(this, std::forward(args)...) - )); + ); + this->addEventListenerInternal(listener); + return listener; } + GEODE_DLL void removeEventListener(geode::EventListenerProtocol* listener); /// @{ /// @name Shader Program diff --git a/loader/include/Geode/loader/Event.hpp b/loader/include/Geode/loader/Event.hpp index 5c5a02eb..8dfc33c0 100644 --- a/loader/include/Geode/loader/Event.hpp +++ b/loader/include/Geode/loader/Event.hpp @@ -127,7 +127,6 @@ namespace geode { class GEODE_DLL [[nodiscard]] Event { private: - static std::vector& listeners(); friend EventListenerProtocol; public: @@ -140,5 +139,12 @@ namespace geode { } virtual ~Event(); + + static std::vector& listeners(); + /** + * Move an event listener to the front of the queue so it is always hit + * first + */ + static void prioritize(EventListenerProtocol* listener); }; } diff --git a/loader/src/hooks/GeodeNodeMetadata.cpp b/loader/src/hooks/GeodeNodeMetadata.cpp index 84a418fd..e642b205 100644 --- a/loader/src/hooks/GeodeNodeMetadata.cpp +++ b/loader/src/hooks/GeodeNodeMetadata.cpp @@ -181,8 +181,12 @@ std::optional CCNode::getAttributeInternal(std::string const& attr) { return std::nullopt; } -void CCNode::addEventListenerInternal(EventListenerProtocol* protocol) { - GeodeNodeMetadata::set(this)->m_eventListeners.push_back(protocol); +void CCNode::addEventListenerInternal(EventListenerProtocol* listener) { + GeodeNodeMetadata::set(this)->m_eventListeners.push_back(listener); +} + +void CCNode::removeEventListener(EventListenerProtocol* listener) { + ranges::remove(GeodeNodeMetadata::set(this)->m_eventListeners, listener); } #pragma warning(pop) diff --git a/loader/src/loader/Event.cpp b/loader/src/loader/Event.cpp index adc29542..0c78cc58 100644 --- a/loader/src/loader/Event.cpp +++ b/loader/src/loader/Event.cpp @@ -33,3 +33,7 @@ std::vector& Event::listeners() { static std::vector listeners; return listeners; } + +void Event::prioritize(EventListenerProtocol* listener) { + ranges::move(Event::listeners(), listener, 0); +} From 8c969a86284c9191b737f1a8720d66c952160619 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sat, 25 Mar 2023 20:31:11 +0200 Subject: [PATCH 18/70] fix codegen base classes not all being public + CCApplication members --- bindings/GeometryDash.bro | 3 ++ codegen/src/BindingGen.cpp | 2 +- .../include/Geode/cocos/base_nodes/CCNode.h | 4 +-- .../cocos/platform/win32/CCApplication.h | 35 ++++++++++++------- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 693923cf..6e09aee2 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -97,7 +97,10 @@ class AppDelegate : cocos2d::CCApplication, cocos2d::CCSceneDelegate { void resumeSound() = win 0x3d4d0; void setupGLView() = win 0x3c950; + PAD = win 0x4; cocos2d::CCScene* m_runningScene; + bool m_loadingFinished; + // there's 0x18 more on Windows } class ArtistCell : TableViewCell { diff --git a/codegen/src/BindingGen.cpp b/codegen/src/BindingGen.cpp index 17f8de11..9422965a 100644 --- a/codegen/src/BindingGen.cpp +++ b/codegen/src/BindingGen.cpp @@ -168,7 +168,7 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl } std::string supers = str_if( - fmt::format(" : public {}", fmt::join(cls.superclasses, ", ")), + fmt::format(" : public {}", fmt::join(cls.superclasses, ", public ")), !cls.superclasses.empty() ); diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index 485c1966..c411f2f9 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -990,9 +990,9 @@ public: GEODE_DLL void swapChildIndices(CCNode* first, CCNode* second); template - geode::EventListenerProtocol* addEventListener(typename Filter::Callback listener, Args&&... args) { + geode::EventListenerProtocol* addEventListener(typename Filter::Callback callback, Args&&... args) { auto listener = new geode::EventListener( - listener, Filter(this, std::forward(args)...) + callback, Filter(this, std::forward(args)...) ); this->addEventListenerInternal(listener); return listener; diff --git a/loader/include/Geode/cocos/platform/win32/CCApplication.h b/loader/include/Geode/cocos/platform/win32/CCApplication.h index dd5152da..682e0ebe 100644 --- a/loader/include/Geode/cocos/platform/win32/CCApplication.h +++ b/loader/include/Geode/cocos/platform/win32/CCApplication.h @@ -42,14 +42,11 @@ public: */ virtual TargetPlatform getTargetPlatform(); - RT_ADD( - virtual void openURL(const char* url); - virtual int run(); - virtual void setupGLView(); - virtual void platformShutdown(); - void toggleVerticalSync(bool); - bool getVerticalSyncEnabled() const; - ) + virtual void openURL(const char* url); + virtual int run(); + virtual void setupGLView(); + virtual void platformShutdown(); + void toggleVerticalSync(bool); /** * Sets the Resource root path. @@ -65,8 +62,6 @@ public: void setStartupScriptFilename(const gd::string& startupScriptFile); - bool getControllerConnected() const; - const gd::string& getStartupScriptFilename(void) { return m_startupScriptFilename; @@ -76,8 +71,24 @@ protected: HINSTANCE m_hInstance; HACCEL m_hAccelTable; LARGE_INTEGER m_nAnimationInterval; - gd::string m_resourceRootPath; - gd::string m_startupScriptFilename; + PAD(4); + std::string m_resourceRootPath; + std::string m_startupScriptFilename; + void* m_pUnknown; + bool m_bUpdateController; + CC_SYNTHESIZE_NV(bool, m_bShutdownCalled, ShutdownCalled); + INPUT m_iInput; + CCPoint m_obUnknown1; + CCPoint m_obUnknown2; + bool m_bMouseControl; + float m_fOldAnimationInterval; + float m_fAnimationInterval; + CC_SYNTHESIZE_READONLY_NV(bool, m_bVerticalSyncEnabled, VerticalSyncEnabled); + CC_SYNTHESIZE_READONLY_NV(bool, m_bControllerConnected, ControllerConnected); + CC_SYNTHESIZE_NV(bool, m_bSleepMode, SleepMode); + CC_SYNTHESIZE_NV(bool, m_bForceTimer, ForceTimer); + CC_SYNTHESIZE_NV(bool, m_bSmoothFix, SmoothFix); + CC_SYNTHESIZE_NV(bool, m_bFullscreen, Fullscreen); static CCApplication * sm_pSharedApplication; }; From 7e60770c9b7b77520cd04c05416f1afa1d55a7b1 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Sat, 25 Mar 2023 19:28:55 -0300 Subject: [PATCH 19/70] some members --- bindings/GeometryDash.bro | 26 +++++++++++++++++++++----- loader/test/members/Windows.cpp | 3 +++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 693923cf..a1cd6265 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -531,6 +531,10 @@ class CCScrollLayerExtDelegate { virtual void scrollViewTouchEnd(CCScrollLayerExt*) {} } +class CCSpritePart : CCSpritePlus { + +} + class CCSpritePlus : cocos2d::CCSprite { bool initWithSpriteFrameName(const char*) = mac 0x248670, win 0x1c1e0; void setScaleX(float scale) = win 0x1c440; @@ -2424,8 +2428,16 @@ class GJRobotSprite : CCAnimatedSprite { void updateFrame(int) = mac 0x34bdd0, win 0x146700; void hideGlow() = mac 0x34b860; - PAD = win 0x8; + cocos2d::CCArray* m_unk244; + bool m_unk248; + cocos2d::ccColor3B m_mainColor; cocos2d::ccColor3B m_secondaryColor; + cocos2d::CCArray* m_unk250; + cocos2d::CCSprite* m_glowSprite; + cocos2d::CCSprite* m_unk258; + PAD = win 0x4; + cocos2d::CCSprite* m_flameSprite; + CCSpritePart* m_headSpritePart; } class GJRotationControl : cocos2d::CCLayer { @@ -3415,6 +3427,7 @@ class GameToolbox { static void alignItemsHorisontally(cocos2d::CCArray* array, bool idk, cocos2d::CCPoint start, float pad) = win 0x25b20; static cocos2d::_ccHSVValue hsvFromString(gd::string, char const*) = mac 0x28cc30, win 0x26da0; static gd::map stringSetupToMap(gd::string, char const*) = mac 0x28d4c0; + static cocos2d::ccColor3B multipliedColorValue(cocos2d::ccColor3B color1, cocos2d::ccColor3B color2, float factor) = win 0x26CE0; } class GaragePage : cocos2d::CCLayer, ListButtonBarDelegate { @@ -3465,7 +3478,7 @@ class HardStreak : cocos2d::CCDrawNode { // ~HardStreak() = mac 0x5bf00; inlined on windows virtual bool init() = mac 0x5c090, win 0x14e430; void addPoint(cocos2d::CCPoint) = mac 0x5c950, win 0x14ebc0; - void clearBehindXPos(float) = mac 0x5cb40; + void clearBehindXPos(float) = mac 0x5cb40, win 0x14ec00; static HardStreak* create() = mac 0x5bfd0, win 0x14e390; void firstSetup() = mac 0x5c160, win 0x14e490; double normalizeAngle(double) = mac 0x5cbe0; @@ -4649,7 +4662,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate { void convertToClosestRotation(float) = mac 0x21c860, win 0x1e9ac0; void copyAttributes(PlayerObject*) = mac 0x22dc70, win 0x1f93f0; static PlayerObject* create(int, int, cocos2d::CCLayer*) = mac 0x217260, win 0x1e6cf0; - void deactivateParticle() = mac 0x21a540; + void deactivateParticle() = mac 0x21a540, win 0x1e8f50; void deactivateStreak(bool) = mac 0x218b30; void fadeOutStreak2(float) = mac 0x225890, win 0x1f9110; void flashPlayer(float, float, cocos2d::_ccColor3B, cocos2d::_ccColor3B) = mac 0x221c80; @@ -4671,7 +4684,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate { void isSafeMode(float) = mac 0x2209b0; void isSafeSpiderFlip(float) = mac 0x221be0; void levelFlipFinished() = mac 0x21b060, win 0x1e8e70; - void levelFlipping() = mac 0x21a510, win 0x1f6820; + bool levelFlipping() = mac 0x21a510, win 0x1f6820; void levelWillFlip() = mac 0x21b020; void loadFromCheckpoint(PlayerCheckpoint*) = mac 0x22e420, win 0x1fa080; void lockPlayer() = mac 0x22d680; @@ -4741,7 +4754,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate { void updateCollide(bool, int) = mac 0x220f10; void updateCollideBottom(float, int) = mac 0x221790; void updateCollideTop(float, int) = mac 0x221c20; - void updateDashAnimation() = mac 0x21a570; + void updateDashAnimation() = mac 0x21a570, win 0x1eea80; void updateDashArt() = mac 0x222520, win 0x1ee3c0; void updateGlowColor() = mac 0x22cf10; void updateJump(float) = mac 0x219680, win 0x1e8f80; @@ -4854,6 +4867,8 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate { bool m_hasJustHeld; bool m_isHolding2; bool m_hasJustHeld2; + bool m_unk615; + bool m_unk616; int m_unk618; float m_unk61C; int m_unk620; @@ -4869,6 +4884,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate { bool m_isRobot; bool m_isSpider; bool m_isUpsideDown; + bool m_unk63F; bool m_isOnGround; bool m_isDashing; float m_vehicleSize; diff --git a/loader/test/members/Windows.cpp b/loader/test/members/Windows.cpp index a516a93e..501c7e41 100644 --- a/loader/test/members/Windows.cpp +++ b/loader/test/members/Windows.cpp @@ -4,10 +4,13 @@ GEODE_MEMBER_CHECK(GameObject, m_effectPlistName, 0x278); GEODE_MEMBER_CHECK(GameObject, m_effectManager, 0x454); +GEODE_MEMBER_CHECK(GameObject, m_firstPosition, 0x424); GEODE_MEMBER_CHECK(PlayerObject, m_unk484, 0x484); GEODE_MEMBER_CHECK(PlayerObject, m_ghostTrail, 0x4E4); GEODE_MEMBER_CHECK(PlayerObject, m_waveTrail, 0x514); +GEODE_MEMBER_CHECK(PlayerObject, m_isDart, 0x63b); +GEODE_MEMBER_CHECK(PlayerObject, m_isDashing, 0x641); GEODE_MEMBER_CHECK(EditorUI, m_buttonBar, 0x134); GEODE_MEMBER_CHECK(EditorUI, m_hideableUIElementArray, 0x13c); From 22a6745b747b919a6d749423a111bd9ab154b215 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 26 Mar 2023 10:39:40 +0200 Subject: [PATCH 20/70] make Mod::getResourcesDir return `resources/{mod.id}` --- loader/src/loader/Mod.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/src/loader/Mod.cpp b/loader/src/loader/Mod.cpp index 3af20ee0..c8917e1d 100644 --- a/loader/src/loader/Mod.cpp +++ b/loader/src/loader/Mod.cpp @@ -73,7 +73,7 @@ ghc::filesystem::path Mod::getBinaryPath() const { } ghc::filesystem::path Mod::getResourcesDir() const { - return dirs::getModRuntimeDir() / this->getID() / "resources"; + return dirs::getModRuntimeDir() / this->getID() / "resources" / this->getID(); } Result<> Mod::saveData() { From 704e6ba0db3184c403652335a2cf8fc8cb05a4d5 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 26 Mar 2023 19:58:01 +0200 Subject: [PATCH 21/70] more bindings --- bindings/GeometryDash.bro | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 6e09aee2..d23be472 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -2354,7 +2354,12 @@ class GJGroundLayer : cocos2d::CCLayer { void updateGroundWidth() = mac 0x356790, win 0x12dda0; } -class GJItemIcon { +class GJItemIcon : cocos2d::CCSprite { + bool init( + UnlockType, int, cocos2d::ccColor3B, cocos2d::ccColor3B, + bool, bool, bool, cocos2d::ccColor3B + ) = win 0x12ccf0; + GJItemIcon* createBrowserIcon(UnlockType _type, int _id) { return GJItemIcon::create(_type, _id, { 0xaf, 0xaf, 0xaf }, { 0xff, 0xff, 0xff }, @@ -3378,6 +3383,7 @@ class GameStatsManager : cocos2d::CCNode { void storePendingUserCoin(char const*) = mac 0x42940; void storeSecretCoin(char const*) = mac 0x42a10; void storeUserCoin(char const*) = mac 0x42890; + bool isItemUnlocked(UnlockType type, int id) = win 0xfbb80; PAD = win 0x28; cocos2d::CCDictionary* m_dailyChests; From 5cdfbc3e67f9aafa1d39fc30266456abca370300 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Mon, 27 Mar 2023 21:22:18 +0300 Subject: [PATCH 22/70] add EventListener::getFilter --- bindings/Cocos2d.bro | 6 +++--- loader/include/Geode/cocos/base_nodes/CCNode.h | 13 ++++++++++++- loader/include/Geode/loader/Event.hpp | 4 ++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 0c8dbc67..7152624e 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -408,12 +408,12 @@ class cocos2d::CCMenu { virtual auto registerWithTouchDispatcher() = mac 0x438cd0, ios 0x131f8c; virtual auto onExit() = mac 0x438bd0, ios 0x131ed4; virtual auto removeChild(cocos2d::CCNode*, bool) = mac 0x438c20, ios 0x15e630; - auto initWithArray(cocos2d::CCArray*) = mac 0x4389f0, ios 0x131d04; - auto itemForTouch(cocos2d::CCTouch*) = mac 0x438dd0; + bool initWithArray(cocos2d::CCArray*) = mac 0x4389f0, ios 0x131d04; + cocos2d::CCMenuItem* itemForTouch(cocos2d::CCTouch*) = mac 0x438dd0; } class cocos2d::CCMenuItem { - auto initWithTarget(cocos2d::CCObject*, cocos2d::SEL_MenuHandler) = mac 0x1fb7f0; + bool initWithTarget(cocos2d::CCObject*, cocos2d::SEL_MenuHandler) = mac 0x1fb7f0; virtual ~CCMenuItem() = mac 0x1fb8e0, ios 0x2cdf4; virtual auto activate() = mac 0x1fba70, ios 0x2ceb0; virtual auto selected() = mac 0x1fb9e0, ios 0x2ce2e; diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index c411f2f9..335ea8a6 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -990,13 +990,24 @@ public: GEODE_DLL void swapChildIndices(CCNode* first, CCNode* second); template - geode::EventListenerProtocol* addEventListener(typename Filter::Callback callback, Args&&... args) { + geode::EventListenerProtocol* addEventListener( + geode::utils::MiniFunction callback, Args&&... args + ) { auto listener = new geode::EventListener( callback, Filter(this, std::forward(args)...) ); this->addEventListenerInternal(listener); return listener; } + template + geode::EventListenerProtocol* addEventListener( + geode::utils::MiniFunction callback, + Args&&... args + ) { + return this->template addEventListener( + callback, std::forward(args)... + ); + } GEODE_DLL void removeEventListener(geode::EventListenerProtocol* listener); /// @{ diff --git a/loader/include/Geode/loader/Event.hpp b/loader/include/Geode/loader/Event.hpp index 8dfc33c0..91c2a341 100644 --- a/loader/include/Geode/loader/Event.hpp +++ b/loader/include/Geode/loader/Event.hpp @@ -120,6 +120,10 @@ namespace geode { m_filter = filter; } + T getFilter() const { + return m_filter; + } + protected: utils::MiniFunction m_callback = nullptr; T m_filter; From 7305445f0548f687e90e8c03802ced7c635e2554 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Tue, 28 Mar 2023 22:17:22 +0300 Subject: [PATCH 23/70] add vector log --- loader/include/Geode/loader/Log.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/loader/include/Geode/loader/Log.hpp b/loader/include/Geode/loader/Log.hpp index 11ae26e8..9df171cb 100644 --- a/loader/include/Geode/loader/Log.hpp +++ b/loader/include/Geode/loader/Log.hpp @@ -71,6 +71,24 @@ namespace geode { return "nullopt"; } + template + requires requires(T t) { + parse(t); + } + std::string parse(std::vector const& thing) { + std::string res = "["; + bool first = true; + for (auto& t : thing) { + if (!first) { + res += ", "; + } + first = false; + res += parse(t); + } + res += "]"; + return res; + } + template requires requires(A a, B b) { parse(a); From 38575ac825f660c0d556389597612338dad958d0 Mon Sep 17 00:00:00 2001 From: hjfod Date: Wed, 29 Mar 2023 11:11:22 +0300 Subject: [PATCH 24/70] add CCScene::get + CCScheduler::get + CCNode::hasAncestor --- loader/include/Geode/cocos/CCScheduler.h | 6 ++++++ loader/include/Geode/cocos/base_nodes/CCNode.h | 12 ++++++++++++ .../layers_scenes_transitions_nodes/CCScene.h | 18 ++++++++++-------- loader/src/cocos2d-ext/Getters.cpp | 8 ++++++++ loader/src/cocos2d-ext/Layout.cpp | 13 +++++++++++++ 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/loader/include/Geode/cocos/CCScheduler.h b/loader/include/Geode/cocos/CCScheduler.h index 59547521..a83bf045 100644 --- a/loader/include/Geode/cocos/CCScheduler.h +++ b/loader/include/Geode/cocos/CCScheduler.h @@ -285,6 +285,12 @@ public: */ void resumeTargets(CCSet* targetsToResume); + /** + * Get the shared scheduler from CCDirector + * @note Geode addition + */ + static GEODE_DLL CCScheduler* get(); + private: void removeHashElement(struct _hashSelectorEntry *pElement); void removeUpdateFromHash(struct _listEntry *entry); diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index 335ea8a6..0becc811 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -894,6 +894,7 @@ public: * @param before The child the node is added before of. If this is null or * not a child of this node, the new child will be placed at the start of the * child list + * @note Geode addition */ GEODE_DLL void insertBefore(CCNode* child, CCNode* before); @@ -904,9 +905,20 @@ public: * @param after The child the node is added after of. If this is null or * not a child of this node, the new child will be placed at the end of the * child list + * @note Geode addition */ GEODE_DLL void insertAfter(CCNode* child, CCNode* after); + /** + * Check if this node's parent or its parents' parent is the given node + * @param ancestor The node whose child or subchild this node should be. If + * nullptr, returns true if the node is in the current scene, otherwise + * false. + * @returns True if ancestor is an ancestor of this node + * @note Geode addition + */ + GEODE_DLL bool hasAncestor(CCNode* ancestor); + /** * Set an attribute on a node. Attributes are a system added by Geode, * where a node may have any sort of extra data associated with it. Used diff --git a/loader/include/Geode/cocos/layers_scenes_transitions_nodes/CCScene.h b/loader/include/Geode/cocos/layers_scenes_transitions_nodes/CCScene.h index 433cb390..41086f39 100644 --- a/loader/include/Geode/cocos/layers_scenes_transitions_nodes/CCScene.h +++ b/loader/include/Geode/cocos/layers_scenes_transitions_nodes/CCScene.h @@ -71,17 +71,19 @@ public: virtual ~CCScene(); bool init(); - static CCScene *create(void); + static CCScene* create(void); + /** + * Get the running scene + * @note Geode addition + */ + static GEODE_DLL CCScene* get(); - RT_ADD( - CCScene(const CCScene&); - - CCScene& operator=(const CCScene&); + CCScene(const CCScene&); + CCScene& operator=(const CCScene&); - int getHighestChildZ(void); + int getHighestChildZ(void); - CCSceneDelegate* m_pDelegate; - ) + CCSceneDelegate* m_pDelegate; }; // end of scene group diff --git a/loader/src/cocos2d-ext/Getters.cpp b/loader/src/cocos2d-ext/Getters.cpp index 7bf91692..682a9afd 100644 --- a/loader/src/cocos2d-ext/Getters.cpp +++ b/loader/src/cocos2d-ext/Getters.cpp @@ -37,4 +37,12 @@ CCTextureCache* CCTextureCache::get() { return CCTextureCache::sharedTextureCache(); } +CCScene* CCScene::get() { + return CCDirector::get()->getRunningScene(); +} + +CCScheduler* CCScheduler::get() { + return CCDirector::get()->getScheduler(); +} + #pragma warning(pop) diff --git a/loader/src/cocos2d-ext/Layout.cpp b/loader/src/cocos2d-ext/Layout.cpp index 1ba151a2..d64fd437 100644 --- a/loader/src/cocos2d-ext/Layout.cpp +++ b/loader/src/cocos2d-ext/Layout.cpp @@ -37,6 +37,19 @@ void CCNode::insertAfter(CCNode* child, CCNode* after) { } } +bool CCNode::hasAncestor(CCNode* ancestor) { + if (!ancestor) { + ancestor = CCScene::get(); + } + if (m_pParent == ancestor) { + return true; + } + if (m_pParent) { + return m_pParent->hasAncestor(ancestor); + } + return false; +} + CCArray* Layout::getNodesToPosition(CCNode* on) { if (!on->getChildren()) { return CCArray::create(); From 7963469f1e37e3443ed76ab6232b3c1a0619db78 Mon Sep 17 00:00:00 2001 From: hjfod Date: Wed, 29 Mar 2023 15:23:57 +0300 Subject: [PATCH 25/70] make attributes use json::Value instead of std::any --- CMakeLists.txt | 2 +- loader/include/Geode/cocos/base_nodes/CCNode.h | 8 ++++---- loader/src/hooks/GeodeNodeMetadata.cpp | 6 +++--- loader/test/members/CMakeLists.txt | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 240a4be5..f2963fe5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,7 +146,7 @@ endif() add_library(GeodeCodegenSources ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp ${GEODE_CODEGEN_PATH}/Geode/GeneratedAddress.cpp) target_link_directories(GeodeCodegenSources PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/loader/include/link) -target_link_libraries(GeodeCodegenSources PRIVATE ghc_filesystem GeodeFilesystemImpl fmt TulipHookInclude) +target_link_libraries(GeodeCodegenSources PRIVATE ghc_filesystem GeodeFilesystemImpl fmt TulipHookInclude mat-json) target_include_directories(GeodeCodegenSources PRIVATE ${GEODE_CODEGEN_PATH} ${GEODE_LOADER_PATH}/include diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index 0becc811..d376e294 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -38,8 +38,8 @@ #include "../script_support/CCScriptSupport.h" #include "../include/CCProtocols.h" #include "Layout.hpp" -#include #include "../../loader/Event.hpp" +#include NS_CC_BEGIN @@ -851,7 +851,7 @@ private: friend class geode::modifier::FieldContainer; GEODE_DLL geode::modifier::FieldContainer* getFieldContainer(); - GEODE_DLL std::optional getAttributeInternal(std::string const& attribute); + GEODE_DLL std::optional getAttributeInternal(std::string const& attribute); GEODE_DLL void addEventListenerInternal(geode::EventListenerProtocol* protocol); public: @@ -931,7 +931,7 @@ public: * @param value The value of the attribute * @note Geode addition */ - GEODE_DLL void setAttribute(std::string const& attribute, std::any value); + GEODE_DLL void setAttribute(std::string const& attribute, json::Value const& value); /** * Get an attribute from the node. Attributes may be anything * @param attribute The attribute key @@ -943,7 +943,7 @@ public: std::optional getAttribute(std::string const& attribute) { if (auto value = this->getAttributeInternal(attribute)) { try { - return std::any_cast(value.value()); + return value.value().template as(); } catch(...) { return std::nullopt; } diff --git a/loader/src/hooks/GeodeNodeMetadata.cpp b/loader/src/hooks/GeodeNodeMetadata.cpp index e642b205..64cb94ba 100644 --- a/loader/src/hooks/GeodeNodeMetadata.cpp +++ b/loader/src/hooks/GeodeNodeMetadata.cpp @@ -21,7 +21,7 @@ private: std::string m_id = ""; Ref m_layout = nullptr; std::unique_ptr m_layoutOptions = nullptr; - std::unordered_map m_attributes; + std::unordered_map m_attributes; std::vector m_eventListeners; friend class ProxyCCNode; @@ -169,11 +169,11 @@ void CCNode::updateLayout(bool updateChildOrder) { } } -void CCNode::setAttribute(std::string const& attr, std::any value) { +void CCNode::setAttribute(std::string const& attr, json::Value const& value) { GeodeNodeMetadata::set(this)->m_attributes[attr] = value; } -std::optional CCNode::getAttributeInternal(std::string const& attr) { +std::optional CCNode::getAttributeInternal(std::string const& attr) { auto meta = GeodeNodeMetadata::set(this); if (meta->m_attributes.count(attr)) { return meta->m_attributes.at(attr); diff --git a/loader/test/members/CMakeLists.txt b/loader/test/members/CMakeLists.txt index 436055db..c7a518f4 100644 --- a/loader/test/members/CMakeLists.txt +++ b/loader/test/members/CMakeLists.txt @@ -17,6 +17,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE target_compile_definitions(${PROJECT_NAME} PRIVATE -DGEODE_DONT_WARN_INCORRECT_MEMBERS) -target_link_libraries(${PROJECT_NAME} PRIVATE ghc_filesystem) +target_link_libraries(${PROJECT_NAME} PRIVATE ghc_filesystem mat-json) add_dependencies(${PROJECT_NAME} CodegenRun) \ No newline at end of file From 69bd0d99efdefda9b4fd7c0c8c4646c1d8a8db0c Mon Sep 17 00:00:00 2001 From: hjfod Date: Wed, 29 Mar 2023 16:05:20 +0300 Subject: [PATCH 26/70] add AttributeSetEvent --- .../include/Geode/cocos/base_nodes/CCNode.h | 23 +++++++++++++++++++ loader/src/hooks/GeodeNodeMetadata.cpp | 16 ++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index d376e294..30f5c46b 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -1725,4 +1725,27 @@ protected: NS_CC_END +namespace geode { + struct GEODE_DLL AttributeSetEvent : public Event { + cocos2d::CCNode* node; + const std::string id; + json::Value& value; + + AttributeSetEvent(cocos2d::CCNode* node, std::string const& id, json::Value& value); + }; + + class GEODE_DLL AttributeSetFilter : public EventFilter { + public: + using Callback = void(AttributeSetEvent*); + + protected: + std::string m_targetID; + + public: + ListenerResult handle(utils::MiniFunction fn, AttributeSetEvent* event); + + AttributeSetFilter(std::string const& id); + }; +} + #endif // __PLATFORM_CCNODE_H__ diff --git a/loader/src/hooks/GeodeNodeMetadata.cpp b/loader/src/hooks/GeodeNodeMetadata.cpp index 64cb94ba..beef927b 100644 --- a/loader/src/hooks/GeodeNodeMetadata.cpp +++ b/loader/src/hooks/GeodeNodeMetadata.cpp @@ -169,8 +169,22 @@ void CCNode::updateLayout(bool updateChildOrder) { } } +AttributeSetEvent::AttributeSetEvent(CCNode* node, std::string const& id, json::Value& value) + : node(node), id(id), value(value) {} + +ListenerResult AttributeSetFilter::handle(MiniFunction fn, AttributeSetEvent* event) { + if (event->id == m_targetID) { + fn(event); + } + return ListenerResult::Propagate; +} + +AttributeSetFilter::AttributeSetFilter(std::string const& id) : m_targetID(id) {} + void CCNode::setAttribute(std::string const& attr, json::Value const& value) { - GeodeNodeMetadata::set(this)->m_attributes[attr] = value; + auto meta = GeodeNodeMetadata::set(this); + meta->m_attributes[attr] = value; + AttributeSetEvent(this, attr, meta->m_attributes.at(attr)).post(); } std::optional CCNode::getAttributeInternal(std::string const& attr) { From 35f7f86e6dbf0d5af36898decdac902f270dbab0 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Wed, 29 Mar 2023 22:07:33 +0300 Subject: [PATCH 27/70] add optional ids to node event listeners + properly clean them up --- .../include/Geode/cocos/base_nodes/CCNode.h | 21 ++++++--- loader/src/hooks/GeodeNodeMetadata.cpp | 44 ++++++++++++++++--- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index 30f5c46b..fc69fee3 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -852,7 +852,10 @@ private: GEODE_DLL geode::modifier::FieldContainer* getFieldContainer(); GEODE_DLL std::optional getAttributeInternal(std::string const& attribute); - GEODE_DLL void addEventListenerInternal(geode::EventListenerProtocol* protocol); + GEODE_DLL void addEventListenerInternal( + std::string const& id, + geode::EventListenerProtocol* protocol + ); public: /** @@ -1003,24 +1006,28 @@ public: template geode::EventListenerProtocol* addEventListener( - geode::utils::MiniFunction callback, Args&&... args + std::string const& id, + geode::utils::MiniFunction callback, + Args&&... args ) { auto listener = new geode::EventListener( callback, Filter(this, std::forward(args)...) ); - this->addEventListenerInternal(listener); + this->addEventListenerInternal(id, listener); return listener; } - template + template geode::EventListenerProtocol* addEventListener( - geode::utils::MiniFunction callback, + geode::utils::MiniFunction callback, Args&&... args ) { - return this->template addEventListener( - callback, std::forward(args)... + return this->template addEventListener( + "", callback, std::forward(args)... ); } GEODE_DLL void removeEventListener(geode::EventListenerProtocol* listener); + GEODE_DLL void removeEventListener(std::string const& id); + GEODE_DLL geode::EventListenerProtocol* getEventListener(std::string const& id); /// @{ /// @name Shader Program diff --git a/loader/src/hooks/GeodeNodeMetadata.cpp b/loader/src/hooks/GeodeNodeMetadata.cpp index beef927b..0e97ef2d 100644 --- a/loader/src/hooks/GeodeNodeMetadata.cpp +++ b/loader/src/hooks/GeodeNodeMetadata.cpp @@ -22,7 +22,8 @@ private: Ref m_layout = nullptr; std::unique_ptr m_layoutOptions = nullptr; std::unordered_map m_attributes; - std::vector m_eventListeners; + std::unordered_set> m_eventListeners; + std::unordered_map> m_idEventListeners; friend class ProxyCCNode; friend class cocos2d::CCNode; @@ -31,9 +32,6 @@ private: virtual ~GeodeNodeMetadata() { delete m_fieldContainer; - for (auto& listener : m_eventListeners) { - delete listener; - } } public: @@ -195,12 +193,44 @@ std::optional CCNode::getAttributeInternal(std::string const& attr) return std::nullopt; } -void CCNode::addEventListenerInternal(EventListenerProtocol* listener) { - GeodeNodeMetadata::set(this)->m_eventListeners.push_back(listener); +void CCNode::addEventListenerInternal(std::string const& id, EventListenerProtocol* listener) { + auto meta = GeodeNodeMetadata::set(this); + if (id.size()) { + if (meta->m_idEventListeners.contains(id)) { + meta->m_idEventListeners.at(id).reset(listener); + } + else { + meta->m_idEventListeners.emplace(id, listener); + } + } + else { + std::erase_if(meta->m_eventListeners, [=](auto& l) { + return l.get() == listener; + }); + meta->m_eventListeners.emplace(listener); + } } void CCNode::removeEventListener(EventListenerProtocol* listener) { - ranges::remove(GeodeNodeMetadata::set(this)->m_eventListeners, listener); + auto meta = GeodeNodeMetadata::set(this); + std::erase_if(meta->m_eventListeners, [=](auto& l) { + return l.get() == listener; + }); + std::erase_if(meta->m_idEventListeners, [=](auto& l) { + return l.second.get() == listener; + }); +} + +void CCNode::removeEventListener(std::string const& id) { + GeodeNodeMetadata::set(this)->m_idEventListeners.erase(id); +} + +EventListenerProtocol* CCNode::getEventListener(std::string const& id) { + auto meta = GeodeNodeMetadata::set(this); + if (meta->m_idEventListeners.contains(id)) { + return meta->m_idEventListeners.at(id).get(); + } + return nullptr; } #pragma warning(pop) From e2e1da069ddee6b09a115104173f6d3e196ec9e5 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Thu, 30 Mar 2023 16:50:38 +0300 Subject: [PATCH 28/70] give a name to the touch type enum aswell as explicit values --- .../Geode/cocos/touch_dispatcher/CCTouchDispatcher.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/loader/include/Geode/cocos/touch_dispatcher/CCTouchDispatcher.h b/loader/include/Geode/cocos/touch_dispatcher/CCTouchDispatcher.h index 05f0eb88..3365f20d 100644 --- a/loader/include/Geode/cocos/touch_dispatcher/CCTouchDispatcher.h +++ b/loader/include/Geode/cocos/touch_dispatcher/CCTouchDispatcher.h @@ -47,13 +47,13 @@ typedef enum } ccTouchSelectorFlag; -enum { - CCTOUCHBEGAN, - CCTOUCHMOVED, - CCTOUCHENDED, - CCTOUCHCANCELLED, +enum ccTouchType { + CCTOUCHBEGAN = 0, + CCTOUCHMOVED = 1, + CCTOUCHENDED = 2, + CCTOUCHCANCELLED = 3, - ccTouchMax, + ccTouchMax = 4, }; class CCSet; From 585a9de18d44065cea2e5126127565a208abdaee Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Thu, 30 Mar 2023 18:45:27 +0300 Subject: [PATCH 29/70] fix scrollbar hitbox being goofy due to ignoring anchor point position --- loader/src/ui/nodes/Scrollbar.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/loader/src/ui/nodes/Scrollbar.cpp b/loader/src/ui/nodes/Scrollbar.cpp index 850525e3..6f4658b8 100644 --- a/loader/src/ui/nodes/Scrollbar.cpp +++ b/loader/src/ui/nodes/Scrollbar.cpp @@ -6,8 +6,6 @@ using namespace geode::prelude; bool Scrollbar::ccTouchBegan(CCTouch* touch, CCEvent* event) { // hitbox auto rect = this->boundingBox(); - // since anchor point is 0.5, 0.5 it's offset - rect.origin -= this->getScaledContentSize() / 2; if (!m_target || !rect.containsPoint(touch->getLocation())) return false; // trigger scrollbar thumb move @@ -40,7 +38,7 @@ void Scrollbar::ccTouchMoved(CCTouch* touch, CCEvent*) { auto thumbHeight = m_resizeThumb ? std::min(p, 1.f) * targetHeight / .4f : 0; auto posY = h * - ((-pos.y - targetHeight / 2 + thumbHeight / 4 - 5) / (targetHeight - thumbHeight / 2 + 10)); + ((-pos.y + thumbHeight / 4 - 5) / (targetHeight - thumbHeight / 2 + 10)); if (posY > 0.0f) posY = 0.0f; if (posY < -h) posY = -h; @@ -73,7 +71,7 @@ void Scrollbar::draw() { m_track->setContentSize({ m_width / m_track->getScale(), targetHeight / m_track->getScale() }); } - m_track->setPosition(.0f, .0f); + m_track->setPosition(m_obContentSize / 2); this->setContentSize({ m_width, targetHeight }); @@ -121,7 +119,7 @@ void Scrollbar::draw() { thumbPosY -= fHeightBottom(); } - m_thumb->setPosition(0.f, thumbPosY); + m_thumb->setPosition(m_obContentSize / 2 + ccp(0.f, thumbPosY)); if (m_resizeThumb) { m_thumb->setContentSize({ m_width, thumbHeight }); } @@ -134,6 +132,8 @@ void Scrollbar::setTarget(CCScrollLayerExt* target) { bool Scrollbar::init(CCScrollLayerExt* target) { if (!this->CCLayer::init()) return false; + this->ignoreAnchorPointForPosition(false); + m_target = target; if (cocos::fileExistsInSearchPaths("scrollbar.png"_spr)) { From 83b0850878c72c0d97d2f2e3665f1a5a18844819 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Thu, 30 Mar 2023 19:20:17 +0300 Subject: [PATCH 30/70] fix scrollbar going funky on DevTools description --- loader/src/ui/nodes/Scrollbar.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/loader/src/ui/nodes/Scrollbar.cpp b/loader/src/ui/nodes/Scrollbar.cpp index 6f4658b8..a3731919 100644 --- a/loader/src/ui/nodes/Scrollbar.cpp +++ b/loader/src/ui/nodes/Scrollbar.cpp @@ -111,11 +111,17 @@ void Scrollbar::draw() { if (fHeightTop() > 0.0f) { thumbHeight -= fHeightTop(); + if (thumbHeight < 15.f) { + thumbHeight = 15.f; + } thumbPosY -= fHeightTop(); } if (fHeightBottom() < 0.f) { thumbHeight += fHeightBottom(); + if (thumbHeight < 15.f) { + thumbHeight = 15.f; + } thumbPosY -= fHeightBottom(); } From e92541a655b16e80dc780d66a0393a9e5b284c4c Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Thu, 30 Mar 2023 22:07:57 +0300 Subject: [PATCH 31/70] add WeakRef --- loader/include/Geode/cocos/cocoa/CCObject.h | 8 +- loader/include/Geode/utils/cocos.hpp | 145 ++++++++++++++++++++ loader/src/utils/cocos.cpp | 26 ++++ 3 files changed, 174 insertions(+), 5 deletions(-) diff --git a/loader/include/Geode/cocos/cocoa/CCObject.h b/loader/include/Geode/cocos/cocoa/CCObject.h index baeb8bf9..829cc8a4 100644 --- a/loader/include/Geode/cocos/cocoa/CCObject.h +++ b/loader/include/Geode/cocos/cocoa/CCObject.h @@ -100,16 +100,14 @@ public: int m_nLuaID; protected: // the object's tag - RT_ADD( int m_nTag; ) + int m_nTag; // count of references unsigned int m_uReference; // count of autorelease unsigned int m_uAutoReleaseCount; - RT_ADD( - CCObjectType m_eObjType; - int m_nUnknown; - ) + CCObjectType m_eObjType; + int m_nUnknown; public: GEODE_CUSTOM_CONSTRUCTOR_BEGIN(CCObject) CCObject(void); diff --git a/loader/include/Geode/utils/cocos.hpp b/loader/include/Geode/utils/cocos.hpp index c22eae53..cc287d59 100644 --- a/loader/include/Geode/utils/cocos.hpp +++ b/loader/include/Geode/utils/cocos.hpp @@ -356,6 +356,151 @@ namespace geode { } }; + class GEODE_DLL WeakRefPool { + std::unordered_set m_pool; + + public: + static WeakRefPool* get(); + + bool isManaged(cocos2d::CCObject* obj); + void manage(cocos2d::CCObject* obj); + void check(cocos2d::CCObject* obj); + }; + + /** + * A smart pointer to a managed CCObject-deriving class. Like Ref, except + * only holds a weak reference to the targeted object. When all non-weak + * references (Refs, manual retain() calls) to the object are dropped, so + * are all weak references. + * + * In essence, WeakRef is like a raw pointer, except that you can know if + * the pointer is still valid or not, as WeakRef::lock() returns nullptr if + * the pointed-to-object has already been freed. + * + * Note that an object pointed to by WeakRef is only released once some + * WeakRef pointing to it checks for it after all other references to the + * object have been dropped. If you store WeakRefs in a global map, you may + * want to periodically lock all of them to make sure any memory that should + * be freed is freed. + * + * @tparam T A type that inherits from CCObject. + */ + template + class WeakRef final { + static_assert( + std::is_base_of_v, + "WeakRef can only be used with a CCObject-inheriting class!" + ); + + T* m_obj = nullptr; + + public: + /** + * Construct a WeakRef of an object. A weak reference is one that will + * be valid as long as the object is referenced by other strong + * references (such as Ref or manual retain calls), but once all strong + * references are dropped, so are all weak references. The object is + * freed once no strong references exist to it, and any WeakRef pointing + * to it is freed or locked + * @param obj Object to construct the WeakRef from + */ + WeakRef(T* obj) : m_obj(obj) { + WeakRefPool::get()->manage(obj); + } + + WeakRef(WeakRef const& other) : WeakRef(other.m_obj) {} + + WeakRef(WeakRef&& other) : m_obj(other.m_obj) { + other.m_obj = nullptr; + } + + /** + * Construct an empty WeakRef (the object will be null) + */ + WeakRef() = default; + ~WeakRef() { + WeakRefPool::get()->check(m_obj); + } + + /** + * Lock the WeakRef, returning a Ref if the pointed object is valid or + * a null Ref if the object has been freed + */ + Ref lock() const { + if (WeakRefPool::get()->isManaged(m_obj)) { + return Ref(m_obj); + } + return Ref(nullptr); + } + + /** + * Check if the WeakRef points to a valid object + */ + bool valid() const { + return WeakRefPool::get()->isManaged(m_obj); + } + + /** + * Swap the managed object with another object. The managed object + * will be released, and the new object retained + * @param other The new object to swap to + */ + void swap(T* other) { + WeakRefPool::get()->check(m_obj); + m_obj = other; + WeakRefPool::get()->manage(other); + } + + Ref operator=(T* obj) { + this->swap(obj); + return this->lock(); + } + + WeakRef& operator=(WeakRef const& other) { + this->swap(other.m_obj); + return *this; + } + + WeakRef& operator=(WeakRef&& other) { + this->swap(other.m_obj); + return *this; + } + + explicit operator bool() const noexcept { + return this->valid(); + } + + bool operator==(T* other) const { + return m_obj == other; + } + + bool operator==(WeakRef const& other) const { + return m_obj == other.m_obj; + } + + bool operator!=(T* other) const { + return m_obj != other; + } + + bool operator!=(WeakRef const& other) const { + return m_obj != other.m_obj; + } + + // for containers + bool operator<(WeakRef const& other) const { + return m_obj < other.m_obj; + } + bool operator<=(WeakRef const& other) const { + return m_obj <= other.m_obj; + } + bool operator>(WeakRef const& other) const { + return m_obj > other.m_obj; + } + bool operator>=(WeakRef const& other) const { + return m_obj >= other.m_obj; + } + }; + template class EventListenerNode : public cocos2d::CCNode { protected: diff --git a/loader/src/utils/cocos.cpp b/loader/src/utils/cocos.cpp index 977d4c1f..2ead3eef 100644 --- a/loader/src/utils/cocos.cpp +++ b/loader/src/utils/cocos.cpp @@ -233,6 +233,32 @@ std::string geode::cocos::cc4bToHexString(ccColor4B const& color) { return output; } +WeakRefPool* WeakRefPool::get() { + static auto inst = new WeakRefPool(); + return inst; +} + +void WeakRefPool::check(CCObject* obj) { + // if this object's only reference is the WeakRefPool aka only weak + // references exist to it, then release it + if (m_pool.contains(obj) && obj->retainCount() == 1) { + obj->release(); + m_pool.erase(obj); + } +} + +bool WeakRefPool::isManaged(CCObject* obj) { + this->check(obj); + return m_pool.contains(obj); +} + +void WeakRefPool::manage(CCObject* obj) { + if (obj) { + obj->retain(); + m_pool.insert(obj); + } +} + CCRect geode::cocos::calculateNodeCoverage(std::vector const& nodes) { CCRect coverage; for (auto child : nodes) { From 0e4636284b057fd9096b607497e1c4cafca07883 Mon Sep 17 00:00:00 2001 From: hjfod Date: Fri, 31 Mar 2023 11:36:54 +0300 Subject: [PATCH 32/70] fix multiple weak refs causing a memory leak --- loader/src/utils/cocos.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/src/utils/cocos.cpp b/loader/src/utils/cocos.cpp index 2ead3eef..cc43087a 100644 --- a/loader/src/utils/cocos.cpp +++ b/loader/src/utils/cocos.cpp @@ -253,7 +253,7 @@ bool WeakRefPool::isManaged(CCObject* obj) { } void WeakRefPool::manage(CCObject* obj) { - if (obj) { + if (obj && !m_pool.contains(obj)) { obj->retain(); m_pool.insert(obj); } From eabb68bbcff2c0817abb38ba86c8830eaa5bea8a Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sat, 1 Apr 2023 17:20:49 +0300 Subject: [PATCH 33/70] fix circle button sprite size --- bindings/GeometryDash.bro | 6 +++--- loader/include/Geode/ui/BasedButtonSprite.hpp | 1 + loader/src/ui/nodes/BasedButtonSprite.cpp | 4 ++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index d23be472..5b744070 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -1244,7 +1244,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ virtual void scaleChanged(float) = mac 0x25490, win 0x88df0; virtual void scaleChangeEnded() = win 0x88de0; void scaleObjects(cocos2d::CCArray*, float, cocos2d::CCPoint) = mac 0x252e0, win 0x8f150; - void selectObjects(cocos2d::CCArray*, bool) = mac 0x23940, win 0x864a0; + void selectObjects(cocos2d::CCArray* objs, bool ignoreFilters) = mac 0x23940, win 0x864a0; void setupCreateMenu() = mac 0xcb50, win 0x7caf0; void undoLastAction(cocos2d::CCObject*) = mac 0xb830, win 0x87070; void updateButtons() = mac 0x1a300, win 0x78280; @@ -3179,8 +3179,8 @@ class GameObject : CCSpritePlus { bool m_isEffectObject; bool m_randomisedAnimStart; float m_animSpeed; - bool m_blackChild; - bool m_unkOutlineMaybe; + bool m_isBlackObject; + bool m_isBlackObjectWithOutline; float m_blackChildOpacity; bool field_21C; bool m_editor; diff --git a/loader/include/Geode/ui/BasedButtonSprite.hpp b/loader/include/Geode/ui/BasedButtonSprite.hpp index dc59a580..6c741d5e 100644 --- a/loader/include/Geode/ui/BasedButtonSprite.hpp +++ b/loader/include/Geode/ui/BasedButtonSprite.hpp @@ -203,6 +203,7 @@ namespace geode { CircleBaseColor color = CircleBaseColor::Green, CircleBaseSize size = CircleBaseSize::Medium ); + cocos2d::CCSize getMaxTopSize() const override; }; /** diff --git a/loader/src/ui/nodes/BasedButtonSprite.cpp b/loader/src/ui/nodes/BasedButtonSprite.cpp index 861b5dc7..96d22ed8 100644 --- a/loader/src/ui/nodes/BasedButtonSprite.cpp +++ b/loader/src/ui/nodes/BasedButtonSprite.cpp @@ -303,6 +303,10 @@ DECL_BASED_CREATE_FUNS(Leaderboard); DECL_BASED_CREATE_FUNS(Editor); DECL_BASED_CREATE_FUNS(Category); +CCSize CircleButtonSprite::getMaxTopSize() const { + return m_obContentSize * .65f; +} + CCSize EditorButtonSprite::getMaxTopSize() const { return m_obContentSize - CCSize { 8.f, 8.f }; } From 57947a9a2751f5e07c98e2a2b2855704c91a09a2 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sat, 1 Apr 2023 17:28:53 +0300 Subject: [PATCH 34/70] impl retainCount to fix macos build --- loader/include/Geode/cocos/cocoa/CCObject.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/loader/include/Geode/cocos/cocoa/CCObject.h b/loader/include/Geode/cocos/cocoa/CCObject.h index 829cc8a4..02e5757c 100644 --- a/loader/include/Geode/cocos/cocoa/CCObject.h +++ b/loader/include/Geode/cocos/cocoa/CCObject.h @@ -121,7 +121,9 @@ public: CCObject* autorelease(void); CCObject* copy(void); bool isSingleReference(void) const; - inline unsigned int retainCount(void) const; + inline unsigned int retainCount(void) const { + return m_uReference; + } virtual bool isEqual(const CCObject* pObject); virtual void acceptVisitor(CCDataVisitor &visitor); From 72448e1be078119c911deea0879ffa440a14355a Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sat, 1 Apr 2023 17:36:54 +0300 Subject: [PATCH 35/70] remove definition of retainCount in Cocos2d.bro --- bindings/Cocos2d.bro | 3 --- 1 file changed, 3 deletions(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 7152624e..528f0dfa 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -636,9 +636,6 @@ class cocos2d::CCObject { auto isEqual(cocos2d::CCObject const*) = mac 0x250f20, ios 0x439e4; auto release() = mac 0x250ea0, ios 0x43984; auto retain() = mac 0x250ec0, ios 0x439a8; - unsigned int retainCount() const { - return m_uReference; - } virtual auto setTag(int) = mac 0x250f60, ios 0x43a10; ~CCObject() = mac 0x250d20, ios 0x6ac0; From 4e2267f020774b3fcd6717970fb71e932a49f618 Mon Sep 17 00:00:00 2001 From: hjfod Date: Sun, 2 Apr 2023 09:54:59 +0300 Subject: [PATCH 36/70] some static functions on mac --- bindings/Cocos2d.bro | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 528f0dfa..78aa1c6b 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -1040,6 +1040,9 @@ class cocos2d { static auto ccDrawSolidRect(cocos2d::CCPoint, cocos2d::CCPoint, cocos2d::_ccColor4F) = mac 0xecf00; static auto ccGLEnableVertexAttribs(unsigned int) = mac 0x1ae740; static auto ccGLBindTexture2D(GLuint) = mac 0x1ae610; + static float ccpDistance(cocos2d::CCPoint const&, cocos2d::CCPoint const&) = mac 0x1aaf90; + static void ccDrawPoly(cocos2d::CCPoint const*, unsigned int, bool) = mac 0xed0a0; + static void ccDrawColor4B(GLubyte, GLubyte, GLubyte, GLubyte) = mac 0xeddd0; } // class DS_Dictionary { From 40a6b53f63226f61cd367a0d5743e85e75dea4be Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 10:03:04 +0300 Subject: [PATCH 37/70] make TextArea::create parameter name more clear --- bindings/GeometryDash.bro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 5b744070..d85d60d2 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -5435,7 +5435,7 @@ class TextArea : cocos2d::CCSprite { virtual void draw() {} virtual void setOpacity(unsigned char) = mac 0x19f760, win 0x33800; bool init(gd::string str, char const* font, float width, float height, cocos2d::CCPoint anchor, float scale, bool disableColor) = mac 0x19ec70, win 0x33370, ios 0x92444; - static TextArea* create(gd::string str, char const* font, float scale, float width, cocos2d::CCPoint anchor, float height, bool disableColor) = mac 0x19eb40, win 0x33270; + static TextArea* create(gd::string str, char const* font, float scale, float width, cocos2d::CCPoint anchor, float lineHeight, bool disableColor) = mac 0x19eb40, win 0x33270; void colorAllCharactersTo(cocos2d::ccColor3B color) = win 0x33830; void setString(gd::string str) = mac 0x19eda0, win 0x33480; From 13e41ee059b315e9e92745380c930ef3153f9cb9 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 11:02:47 +0300 Subject: [PATCH 38/70] buncha mac addresses for betteredit *slurp* :3 --- bindings/Cocos2d.bro | 23 +++++++++++++++-- loader/include/Geode/cocos/cocoa/CCObject.h | 28 ++++++++++----------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 78aa1c6b..5d4ef494 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -64,9 +64,14 @@ class cocos2d::CCCallFuncO { static auto create(cocos2d::CCObject*, cocos2d::SEL_CallFuncO, cocos2d::CCObject*) = mac 0x455940; } -class cocos2d::CCClippingNode { +class cocos2d::CCClippingNode : CCNode { + inline CCClippingNode() : CCNode(), m_pStencil(nullptr), m_fAlphaThreshold(1.f), m_bInverted(false) {} static cocos2d::CCClippingNode* create() = mac 0x4192a0; static cocos2d::CCClippingNode* create(cocos2d::CCNode*) = mac 0x419330; + // Inlined in create() call + virtual bool init() = mac 0x4193e0; + // Inlined in create() call + virtual bool init(cocos2d::CCNode* stencil) = mac 0x419400; auto getAlphaThreshold() const = mac 0x419a10; auto getStencil() const = mac 0x4199c0; auto isInverted() const = mac 0x419a30; @@ -77,7 +82,7 @@ class cocos2d::CCClippingNode { auto setAlphaThreshold(float) = mac 0x419a20; auto setInverted(bool) = mac 0x419a40; auto setStencil(cocos2d::CCNode*) = mac 0x4199d0; - auto visit() = mac 0x419530; + void visit() = mac 0x419530; } class cocos2d::CCDelayTime { @@ -151,6 +156,20 @@ class cocos2d::CCDrawNode { virtual ~CCDrawNode() = mac 0x378cc0; } +class cocos2d::CCAction { + CCAction() = mac 0x35b610; + virtual ~CCAction() = mac 0x35b6b0; + virtual void stop() = mac 0x35b860; +} + +class cocos2d::CCActionInterval { + virtual cocos2d::CCObject* copyWithZone(cocos2d::CCZone* zone) = mac 0x1f2550; + virtual bool isDone() = mac 0x1f2640; + virtual void startWithTarget(CCNode* pTarget) = mac 0x1f2700; + virtual void step(float dt) = mac 0x1f2660; + bool initWithDuration(float d) = mac 0x1f2510; +} + class cocos2d::CCEaseBackIn { static cocos2d::CCEaseBackIn* create(cocos2d::CCActionInterval*) = mac 0x2a41b0; } diff --git a/loader/include/Geode/cocos/cocoa/CCObject.h b/loader/include/Geode/cocos/cocoa/CCObject.h index 02e5757c..632b2b6d 100644 --- a/loader/include/Geode/cocos/cocoa/CCObject.h +++ b/loader/include/Geode/cocos/cocoa/CCObject.h @@ -130,23 +130,23 @@ public: virtual void update(float dt) {CC_UNUSED_PARAM(dt);}; - RT_ADD( - virtual void encodeWithCoder(DS_Dictionary*); + virtual void encodeWithCoder(DS_Dictionary*); - static CCObject* createWithCoder(DS_Dictionary*); - - virtual bool canEncode(); + static CCObject* createWithCoder(DS_Dictionary*); + + virtual bool canEncode(); - CCObjectType getObjType() const; - - virtual int getTag() const; + inline CCObjectType getObjType() const { + return m_eObjType; + } + + virtual int getTag() const; - virtual void setTag(int nTag); - - inline void setObjType(CCObjectType type) { - m_eObjType = type; - } - ) + virtual void setTag(int nTag); + + inline void setObjType(CCObjectType type) { + m_eObjType = type; + } friend class CCAutoreleasePool; }; From a2b7573bdc38a630f20850878634281560d25d62 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 11:05:47 +0300 Subject: [PATCH 39/70] add cocos2d:: namespace in front of CCNode to fix build --- bindings/Cocos2d.bro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 5d4ef494..718092d1 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -64,8 +64,8 @@ class cocos2d::CCCallFuncO { static auto create(cocos2d::CCObject*, cocos2d::SEL_CallFuncO, cocos2d::CCObject*) = mac 0x455940; } -class cocos2d::CCClippingNode : CCNode { - inline CCClippingNode() : CCNode(), m_pStencil(nullptr), m_fAlphaThreshold(1.f), m_bInverted(false) {} +class cocos2d::CCClippingNode : cocos2d::CCNode { + inline CCClippingNode() : cocos2d::CCNode(), m_pStencil(nullptr), m_fAlphaThreshold(1.f), m_bInverted(false) {} static cocos2d::CCClippingNode* create() = mac 0x4192a0; static cocos2d::CCClippingNode* create(cocos2d::CCNode*) = mac 0x419330; // Inlined in create() call From 064de3350e2a5af7d811849ea707e5ee205521e5 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 11:16:36 +0300 Subject: [PATCH 40/70] missing a fully qualified name there --- bindings/Cocos2d.bro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 718092d1..7214f3e7 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -165,7 +165,7 @@ class cocos2d::CCAction { class cocos2d::CCActionInterval { virtual cocos2d::CCObject* copyWithZone(cocos2d::CCZone* zone) = mac 0x1f2550; virtual bool isDone() = mac 0x1f2640; - virtual void startWithTarget(CCNode* pTarget) = mac 0x1f2700; + virtual void startWithTarget(cocos2d::CCNode* pTarget) = mac 0x1f2700; virtual void step(float dt) = mac 0x1f2660; bool initWithDuration(float d) = mac 0x1f2510; } From f90ca9edd5eae46de7fc386da8194b3e15fd91a4 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 11:31:27 +0300 Subject: [PATCH 41/70] ok now it should build? --- bindings/Cocos2d.bro | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 7214f3e7..e9594136 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -64,14 +64,18 @@ class cocos2d::CCCallFuncO { static auto create(cocos2d::CCObject*, cocos2d::SEL_CallFuncO, cocos2d::CCObject*) = mac 0x455940; } -class cocos2d::CCClippingNode : cocos2d::CCNode { - inline CCClippingNode() : cocos2d::CCNode(), m_pStencil(nullptr), m_fAlphaThreshold(1.f), m_bInverted(false) {} +class cocos2d::CCClippingNode { + CCClippingNode() { + m_pStencil = nullptr; + m_fAlphaThreshold = 1.f; + m_bInverted = false; + } static cocos2d::CCClippingNode* create() = mac 0x4192a0; static cocos2d::CCClippingNode* create(cocos2d::CCNode*) = mac 0x419330; // Inlined in create() call - virtual bool init() = mac 0x4193e0; + auto init() = mac 0x4193e0; // Inlined in create() call - virtual bool init(cocos2d::CCNode* stencil) = mac 0x419400; + auto init(cocos2d::CCNode* stencil) = mac 0x419400; auto getAlphaThreshold() const = mac 0x419a10; auto getStencil() const = mac 0x4199c0; auto isInverted() const = mac 0x419a30; @@ -159,14 +163,14 @@ class cocos2d::CCDrawNode { class cocos2d::CCAction { CCAction() = mac 0x35b610; virtual ~CCAction() = mac 0x35b6b0; - virtual void stop() = mac 0x35b860; + auto stop() = mac 0x35b860; } class cocos2d::CCActionInterval { - virtual cocos2d::CCObject* copyWithZone(cocos2d::CCZone* zone) = mac 0x1f2550; - virtual bool isDone() = mac 0x1f2640; - virtual void startWithTarget(cocos2d::CCNode* pTarget) = mac 0x1f2700; - virtual void step(float dt) = mac 0x1f2660; + auto copyWithZone(cocos2d::CCZone* zone) = mac 0x1f2550; + auto isDone() = mac 0x1f2640; + auto startWithTarget(cocos2d::CCNode* pTarget) = mac 0x1f2700; + auto step(float dt) = mac 0x1f2660; bool initWithDuration(float d) = mac 0x1f2510; } From cd3c09637bf7b78f1ed27d6686bb95dd1bb548b4 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 12:46:37 +0300 Subject: [PATCH 42/70] add custom constructors to CCClippingNode and CCAction --- loader/include/Geode/cocos/actions/CCAction.h | 1 + loader/include/Geode/cocos/misc_nodes/CCClippingNode.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/loader/include/Geode/cocos/actions/CCAction.h b/loader/include/Geode/cocos/actions/CCAction.h index 721e9ddf..b9ee7bca 100644 --- a/loader/include/Geode/cocos/actions/CCAction.h +++ b/loader/include/Geode/cocos/actions/CCAction.h @@ -54,6 +54,7 @@ public: * @js ctor */ CCAction(void); + GEODE_CUSTOM_CONSTRUCTOR_COCOS(CCAction, CCObject); /** * @js NA * @lua NA diff --git a/loader/include/Geode/cocos/misc_nodes/CCClippingNode.h b/loader/include/Geode/cocos/misc_nodes/CCClippingNode.h index 1e9ca2f6..f9940d83 100644 --- a/loader/include/Geode/cocos/misc_nodes/CCClippingNode.h +++ b/loader/include/Geode/cocos/misc_nodes/CCClippingNode.h @@ -115,6 +115,8 @@ public: bool isInverted() const; void setInverted(bool bInverted); + GEODE_CUSTOM_CONSTRUCTOR_COCOS(CCClippingNode, CCNode); + protected: CCClippingNode(); }; From cae9a67b15af1429b0d02d4fd56932243c3da7ba Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 13:04:31 +0300 Subject: [PATCH 43/70] add a bunch CCAction addresses --- bindings/Cocos2d.bro | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index e9594136..e57e2e9f 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -86,7 +86,7 @@ class cocos2d::CCClippingNode { auto setAlphaThreshold(float) = mac 0x419a20; auto setInverted(bool) = mac 0x419a40; auto setStencil(cocos2d::CCNode*) = mac 0x4199d0; - void visit() = mac 0x419530; + auto visit() = mac 0x419530; } class cocos2d::CCDelayTime { @@ -164,6 +164,12 @@ class cocos2d::CCAction { CCAction() = mac 0x35b610; virtual ~CCAction() = mac 0x35b6b0; auto stop() = mac 0x35b860; + auto copyWithZone(cocos2d::CCZone* zone) = mac 0x35b7a0; + auto reverse() = 0x1f2720; + auto startWithTarget(cocos2d::CCNode* target) = mac 0x35b850; + auto step(float dt) = mac 0x35b880; + auto isDone() = mac 0x35b870; + auto update() = mac 0x35b890; } class cocos2d::CCActionInterval { From 2f982197dbd981ad190a89fe21c632643966c7c9 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 13:07:21 +0300 Subject: [PATCH 44/70] missing a "mac" --- bindings/Cocos2d.bro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index e57e2e9f..7667e039 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -165,7 +165,7 @@ class cocos2d::CCAction { virtual ~CCAction() = mac 0x35b6b0; auto stop() = mac 0x35b860; auto copyWithZone(cocos2d::CCZone* zone) = mac 0x35b7a0; - auto reverse() = 0x1f2720; + auto reverse() = mac 0x1f2720; auto startWithTarget(cocos2d::CCNode* target) = mac 0x35b850; auto step(float dt) = mac 0x35b880; auto isDone() = mac 0x35b870; From c4064d75263a1bedc4bdd708c358838aff0fdf92 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 13:15:03 +0300 Subject: [PATCH 45/70] reverse is part of CCActionInterval and not CCAction --- bindings/Cocos2d.bro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 7667e039..4f7f9722 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -165,7 +165,6 @@ class cocos2d::CCAction { virtual ~CCAction() = mac 0x35b6b0; auto stop() = mac 0x35b860; auto copyWithZone(cocos2d::CCZone* zone) = mac 0x35b7a0; - auto reverse() = mac 0x1f2720; auto startWithTarget(cocos2d::CCNode* target) = mac 0x35b850; auto step(float dt) = mac 0x35b880; auto isDone() = mac 0x35b870; @@ -177,6 +176,7 @@ class cocos2d::CCActionInterval { auto isDone() = mac 0x1f2640; auto startWithTarget(cocos2d::CCNode* pTarget) = mac 0x1f2700; auto step(float dt) = mac 0x1f2660; + auto reverse() = mac 0x1f2720; bool initWithDuration(float d) = mac 0x1f2510; } From 9032285d067fb935d349bac255b4159ab9b2b971 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 13:19:49 +0300 Subject: [PATCH 46/70] fix CCAction::update parameter --- bindings/Cocos2d.bro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 4f7f9722..30deb9be 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -168,7 +168,7 @@ class cocos2d::CCAction { auto startWithTarget(cocos2d::CCNode* target) = mac 0x35b850; auto step(float dt) = mac 0x35b880; auto isDone() = mac 0x35b870; - auto update() = mac 0x35b890; + auto update(float time) = mac 0x35b890; } class cocos2d::CCActionInterval { From 21173311c14b31848c6f55ee13a08f25ee81b29a Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 13:38:06 +0300 Subject: [PATCH 47/70] add mac stuff --- bindings/Cocos2d.bro | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 30deb9be..b0ed083d 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -70,6 +70,7 @@ class cocos2d::CCClippingNode { m_fAlphaThreshold = 1.f; m_bInverted = false; } + ~CCClippingNode() = mac 0x4191e0; static cocos2d::CCClippingNode* create() = mac 0x4192a0; static cocos2d::CCClippingNode* create(cocos2d::CCNode*) = mac 0x419330; // Inlined in create() call @@ -171,6 +172,11 @@ class cocos2d::CCAction { auto update(float time) = mac 0x35b890; } +class cocos2d::CCFiniteTimeAction { + // same as CCActionInterval::reverse i think + auto reverse() = mac 0x1f2720; +} + class cocos2d::CCActionInterval { auto copyWithZone(cocos2d::CCZone* zone) = mac 0x1f2550; auto isDone() = mac 0x1f2640; From 152f90cf6765c44bf1538f58845ebd32b8b42735 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 14:43:39 +0300 Subject: [PATCH 48/70] add option to ignore invisible children to Layout --- .../include/Geode/cocos/base_nodes/Layout.hpp | 7 ++++++- loader/src/cocos2d-ext/Layout.cpp | 17 ++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/loader/include/Geode/cocos/base_nodes/Layout.hpp b/loader/include/Geode/cocos/base_nodes/Layout.hpp index c1dcd908..c78cb76a 100644 --- a/loader/include/Geode/cocos/base_nodes/Layout.hpp +++ b/loader/include/Geode/cocos/base_nodes/Layout.hpp @@ -23,7 +23,9 @@ class CCNode; */ class GEODE_DLL Layout : public CCObject { protected: - static CCArray* getNodesToPosition(CCNode* forNode); + CCArray* getNodesToPosition(CCNode* forNode); + + bool m_ignoreInvisibleChildren = false; public: /** @@ -35,6 +37,9 @@ public: */ virtual void apply(CCNode* on) = 0; + void ignoreInvisibleChildren(bool ignore); + bool isIgnoreInvisibleChildren() const; + virtual ~Layout() = default; }; diff --git a/loader/src/cocos2d-ext/Layout.cpp b/loader/src/cocos2d-ext/Layout.cpp index d64fd437..efa61493 100644 --- a/loader/src/cocos2d-ext/Layout.cpp +++ b/loader/src/cocos2d-ext/Layout.cpp @@ -51,10 +51,21 @@ bool CCNode::hasAncestor(CCNode* ancestor) { } CCArray* Layout::getNodesToPosition(CCNode* on) { - if (!on->getChildren()) { - return CCArray::create(); + auto arr = CCArray::create(); + for (auto child : CCArrayExt(on->getChildren())) { + if (!m_ignoreInvisibleChildren || child->isVisible()) { + arr->addObject(child); + } } - return on->getChildren()->shallowCopy(); + return arr; +} + +void Layout::ignoreInvisibleChildren(bool ignore) { + m_ignoreInvisibleChildren = ignore; +} + +bool Layout::isIgnoreInvisibleChildren() const { + return m_ignoreInvisibleChildren; } static AxisLayoutOptions const* axisOpts(CCNode* node) { From 9fb5051f80852f10729a231dd736d1039838278f Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 16:00:17 +0300 Subject: [PATCH 49/70] fix mod resources not being updated when a mod is enabled at runtime --- loader/src/loader/ModImpl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/src/loader/ModImpl.cpp b/loader/src/loader/ModImpl.cpp index 4bb01c95..fe33adf2 100644 --- a/loader/src/loader/ModImpl.cpp +++ b/loader/src/loader/ModImpl.cpp @@ -316,6 +316,7 @@ Result<> Mod::Impl::loadBinary() { }); Loader::get()->updateAllDependencies(); + Loader::get()->updateResources(); GEODE_UNWRAP(this->enable()); From 21ee6894cff4f50c88ede74476990aa2203e0843 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 16:14:31 +0300 Subject: [PATCH 50/70] fix EditLevelLayer not properly handling the id and layout of desc btn --- loader/src/ids/EditLevelLayer.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/loader/src/ids/EditLevelLayer.cpp b/loader/src/ids/EditLevelLayer.cpp index 86ec5632..49cf171e 100644 --- a/loader/src/ids/EditLevelLayer.cpp +++ b/loader/src/ids/EditLevelLayer.cpp @@ -31,9 +31,29 @@ $register_ids(EditLevelLayer) { ); auto winSize = CCDirector::get()->getWinSize(); + auto descBG = this->getChildByID("description-background"); + + auto descMenu = CCMenu::create(); + descMenu->setID("description-menu"); + descMenu->setLayout(ColumnLayout::create()); + descMenu->setPosition( + descBG->getPositionX() - descBG->getScaledContentSize().width / 2 - 35.f, + descBG->getPositionY() + ); + descMenu->setContentSize({ 40.f, 80.f }); + this->addChild(descMenu); if (auto menu = this->getChildByID("level-edit-menu")) { setIDs(menu, 0, "edit-button", "play-button", "share-button"); + if (menu->getChildrenCount() == 4) { + auto btn = static_cast(menu->getChildren()->objectAtIndex(3)); + btn->setID("update-desc-button"); + btn->retain(); + btn->removeFromParent(); + descMenu->addChild(btn); + btn->release(); + descMenu->updateLayout(); + } menu->setContentSize({ winSize.width - 160.f, 100.f }); menu->setLayout(RowLayout::create()->setGap(25.f)); } From 7d744a91890dc14d8c164dd78c850d61c39f05a2 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 17:22:03 +0300 Subject: [PATCH 51/70] add DS_Dictionary addresses on mac --- bindings/Cocos2d.bro | 15 ++++++++++----- codegen/src/AddressGen.cpp | 2 +- codegen/src/BindingGen.cpp | 4 ++-- codegen/src/Main.cpp | 2 +- codegen/src/ModifyGen.cpp | 2 +- codegen/src/PredeclareGen.cpp | 2 +- codegen/src/Shared.hpp | 10 ++++++++-- codegen/src/SourceGen.cpp | 6 +++--- 8 files changed, 27 insertions(+), 16 deletions(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index b0ed083d..b810ea5e 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -964,6 +964,7 @@ class cocos2d::CCTransitionFade { class cocos2d::ZipUtils { static auto compressString(gd::string, bool, int) = mac 0xe9a50; static auto decompressString(gd::string, bool, int) = mac 0xea380; + static int ccDeflateMemory(unsigned char*, unsigned int, unsigned char**) = mac 0xe9cf0; } class cocos2d::extension::CCControl { @@ -1080,10 +1081,14 @@ class cocos2d { static void ccDrawColor4B(GLubyte, GLubyte, GLubyte, GLubyte) = mac 0xeddd0; } -// class DS_Dictionary { -// DS_Dictionary() = mac 0xbe9a0; -// int getIntegerForKey(char const*) = mac 0xc1610; -// void setIntegerForKey(char const*, int) = mac 0xc26b0; -// } +class DS_Dictionary { + DS_Dictionary() = mac 0xbe9a0; + ~DS_Dictionary() = mac 0x393c30; + bool saveRootSubDictToString() = mac 0xc09c0; + bool loadRootSubDictFromString(gd::string) = mac 0xbfd80; + bool stepIntoSubDictWithKey(char const*) = mac 0xc0cd0; + int getIntegerForKey(char const*) = mac 0xc1610; + void setIntegerForKey(char const*, int) = mac 0xc26b0; +} // clang-format on \ No newline at end of file diff --git a/codegen/src/AddressGen.cpp b/codegen/src/AddressGen.cpp index 9fd0f4b0..8ae64619 100644 --- a/codegen/src/AddressGen.cpp +++ b/codegen/src/AddressGen.cpp @@ -103,7 +103,7 @@ std::string generateAddressHeader(Root& root) { ); } else if (codegen::getStatus(field) == BindStatus::NeedsBinding) { - if (field.parent.rfind("cocos2d::", 0) == 0 && codegen::platform == Platform::Windows) { + if (is_cocos_class(field.parent) && codegen::platform == Platform::Windows) { address_str = fmt::format("base::getCocos() + 0x{:x}", codegen::platformNumber(fn->binds)); } else { diff --git a/codegen/src/BindingGen.cpp b/codegen/src/BindingGen.cpp index 9422965a..4346fa32 100644 --- a/codegen/src/BindingGen.cpp +++ b/codegen/src/BindingGen.cpp @@ -144,7 +144,7 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl std::string output; for (auto& cls : root.classes) { - if (can_find(cls.name, "cocos2d")) + if (is_cocos_class(cls.name)) continue; std::string filename = (codegen::getUnqualifiedClassName(cls.name) + ".hpp"); @@ -180,7 +180,7 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl // what. if (!cls.superclasses.empty()) { single_output += fmt::format( - can_find(cls.superclasses[0], "cocos2d") + is_cocos_class(cls.superclasses[0]) ? format_strings::custom_constructor_cutoff : format_strings::custom_constructor, fmt::arg("class_name", cls.name), diff --git a/codegen/src/Main.cpp b/codegen/src/Main.cpp index 53d2f941..c78f2dd1 100644 --- a/codegen/src/Main.cpp +++ b/codegen/src/Main.cpp @@ -25,7 +25,7 @@ int main(int argc, char** argv) try { for (auto cls : root.classes) { for (auto dep : cls.depends) { - if(!can_find(dep, "cocos2d::") && std::find(root.classes.begin(), root.classes.end(), dep) == root.classes.end()) { + if(!is_cocos_class(dep) && std::find(root.classes.begin(), root.classes.end(), dep) == root.classes.end()) { throw codegen::error("Class {} depends on unknown class {}", cls.name, dep); } } diff --git a/codegen/src/ModifyGen.cpp b/codegen/src/ModifyGen.cpp index f976b7a9..ae96df3b 100644 --- a/codegen/src/ModifyGen.cpp +++ b/codegen/src/ModifyGen.cpp @@ -74,7 +74,7 @@ std::string generateModifyHeader(Root& root, ghc::filesystem::path const& single if (c.name.find("cocos2d::extension") != std::string::npos) { class_include = "#include "; } - else if (c.name.find("cocos2d") != std::string::npos) { + else if (is_cocos_class(c.name)) { class_include = "#include "; } else { diff --git a/codegen/src/PredeclareGen.cpp b/codegen/src/PredeclareGen.cpp index 75ae69e0..e7de1cf2 100644 --- a/codegen/src/PredeclareGen.cpp +++ b/codegen/src/PredeclareGen.cpp @@ -10,7 +10,7 @@ std::string generatePredeclareHeader(Root& root) { std::string output("#pragma once\n"); for (auto& cls : root.classes) { - if (can_find(cls.name, "cocos2d")) + if (is_cocos_class(cls.name)) continue; output += fmt::format(::format_strings::class_predeclare, diff --git a/codegen/src/Shared.hpp b/codegen/src/Shared.hpp index e8279f2d..bacd1a54 100644 --- a/codegen/src/Shared.hpp +++ b/codegen/src/Shared.hpp @@ -51,6 +51,10 @@ inline bool can_find(std::string const& str, char const* text) { return str.find(text) != std::string::npos; } +inline bool is_cocos_class(std::string const& str) { + return can_find(str, "cocos2d") || str == "DS_Dictionary"; +} + enum class BindStatus { Binded, NeedsBinding, @@ -112,8 +116,10 @@ namespace codegen { if (fb->type == FunctionType::Normal) { if (field.parent.rfind("fmod::", 0) == 0) return BindStatus::Binded; - if (field.parent.rfind("cocos2d::", 0) == 0 && p == Platform::Windows) - return BindStatus::Binded; + if ( + (field.parent.rfind("cocos2d::", 0) == 0 || field.parent == "DS_Dictionary") && + p == Platform::Windows + ) return BindStatus::Binded; } return BindStatus::Unbindable; diff --git a/codegen/src/SourceGen.cpp b/codegen/src/SourceGen.cpp index 1881dc12..7936870e 100644 --- a/codegen/src/SourceGen.cpp +++ b/codegen/src/SourceGen.cpp @@ -126,7 +126,7 @@ std::string generateBindingSource(Root& root) { for (auto& f : c.fields) { if (auto i = f.get_as()) { if (codegen::platform == Platform::Mac || codegen::platform == Platform::iOS) { - if (can_find(c.name, "cocos2d")) + if (is_cocos_class(c.name)) output += i->inner + "\n"; } } else if (auto fn = f.get_as()) { @@ -134,7 +134,7 @@ std::string generateBindingSource(Root& root) { continue; // no cocos2d definitions on windows - if (codegen::platform == Platform::Windows && f.parent.rfind("cocos2d::", 0) == 0) { + if (codegen::platform == Platform::Windows && is_cocos_class(f.parent)) { continue; } @@ -166,7 +166,7 @@ std::string generateBindingSource(Root& root) { continue; // no cocos2d definitions on windows - if (codegen::platform == Platform::Windows && f.parent.rfind("cocos2d::", 0) == 0) { + if (codegen::platform == Platform::Windows && is_cocos_class(f.parent)) { continue; } From ca3bf6516c3d6bb067ecd63d6b4897c96770f202 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 17:30:53 +0300 Subject: [PATCH 52/70] add geode custom ctor to DS_Dictionary --- loader/include/Geode/cocos/robtop/xml/DS_Dictionary.h | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/include/Geode/cocos/robtop/xml/DS_Dictionary.h b/loader/include/Geode/cocos/robtop/xml/DS_Dictionary.h index c08f1637..c280cb74 100644 --- a/loader/include/Geode/cocos/robtop/xml/DS_Dictionary.h +++ b/loader/include/Geode/cocos/robtop/xml/DS_Dictionary.h @@ -21,6 +21,7 @@ public: public: DS_Dictionary(); ~DS_Dictionary(); + GEODE_CUSTOM_CONSTRUCTOR_BEGIN(DS_Dictionary) static void copyFile(const char*, const char*); From 95fb3c60c6978d9e216ca5ba3fd4e638abfe2165 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 17:41:19 +0300 Subject: [PATCH 53/70] add xml_document ctor and dtor --- bindings/Cocos2d.bro | 5 +++++ codegen/src/Shared.hpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index b810ea5e..c70ec8f4 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -1091,4 +1091,9 @@ class DS_Dictionary { void setIntegerForKey(char const*, int) = mac 0xc26b0; } +class pugi::xml_document { + xml_document() = mac 0x393a80; + ~xml_document() = mac 0x393b50; +} + // clang-format on \ No newline at end of file diff --git a/codegen/src/Shared.hpp b/codegen/src/Shared.hpp index bacd1a54..82e6ffcb 100644 --- a/codegen/src/Shared.hpp +++ b/codegen/src/Shared.hpp @@ -52,7 +52,7 @@ inline bool can_find(std::string const& str, char const* text) { } inline bool is_cocos_class(std::string const& str) { - return can_find(str, "cocos2d") || str == "DS_Dictionary"; + return can_find(str, "cocos2d") || can_find(str, "pugi::") || str == "DS_Dictionary"; } enum class BindStatus { From 5e6efa911266b3fca939bf6d4d4dec24b1d6881a Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 17:47:28 +0300 Subject: [PATCH 54/70] add xml custom ctors --- loader/include/Geode/cocos/robtop/xml/pugixml.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/include/Geode/cocos/robtop/xml/pugixml.hpp b/loader/include/Geode/cocos/robtop/xml/pugixml.hpp index f574b11d..b7ae4af0 100644 --- a/loader/include/Geode/cocos/robtop/xml/pugixml.hpp +++ b/loader/include/Geode/cocos/robtop/xml/pugixml.hpp @@ -371,6 +371,7 @@ namespace pugi public: // Default constructor. Constructs an empty node. xml_node(); + GEODE_CUSTOM_CONSTRUCTOR_BEGIN(xml_node); // Constructs node from internal pointer explicit xml_node(xml_node_struct* p); @@ -852,6 +853,7 @@ namespace pugi { private: char_t* _buffer; + GEODE_CUSTOM_CONSTRUCTOR_COCOS(xml_document, xml_node); char _memory[192]; From bf2c3da9baf843ddda26380fe6a884cbfd00f6f1 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 2 Apr 2023 19:27:21 +0300 Subject: [PATCH 55/70] bump version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a38ac3a3..1bc145e2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0-beta.10 \ No newline at end of file +1.0.0-beta.11 \ No newline at end of file From ab2abcdae30fbe5a4ee41c6adb2ee891841aed47 Mon Sep 17 00:00:00 2001 From: alk <45172705+altalk23@users.noreply.github.com> Date: Mon, 3 Apr 2023 01:01:40 +0300 Subject: [PATCH 56/70] remove GEODE_DEBUG ifdef from log::debug --- loader/include/Geode/loader/Log.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/loader/include/Geode/loader/Log.hpp b/loader/include/Geode/loader/Log.hpp index 9df171cb..73f23fa7 100644 --- a/loader/include/Geode/loader/Log.hpp +++ b/loader/include/Geode/loader/Log.hpp @@ -205,9 +205,7 @@ namespace geode { template void debug(Args... args) { -#ifdef GEODE_DEBUG internalLog(Severity::Debug, getMod(), args...); -#endif } template From f662251d98401abcf6897c5ae6fab7c8d9139589 Mon Sep 17 00:00:00 2001 From: hjfod Date: Mon, 3 Apr 2023 08:21:23 +0300 Subject: [PATCH 57/70] add mac addresses + link fmod dylib on mac --- bindings/Cocos2d.bro | 2 ++ cmake/Platform.cmake | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index c70ec8f4..696ceb3b 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -734,6 +734,8 @@ class cocos2d::CCScheduler { auto scheduleUpdateForTarget(cocos2d::CCObject*, int, bool) = mac 0x2438d0; auto unscheduleAllForTarget(cocos2d::CCObject*) = mac 0x243e40; auto unscheduleUpdateForTarget(cocos2d::CCObject const*) = mac 0x243c60; + auto resumeTargets(cocos2d::CCSet*) = mac 0x244680; + auto pauseAllTargets() = mac 0x244550; virtual void update(float delta) = mac 0x2446d0; } diff --git a/cmake/Platform.cmake b/cmake/Platform.cmake index 0bb025ca..d57d05a5 100644 --- a/cmake/Platform.cmake +++ b/cmake/Platform.cmake @@ -36,7 +36,10 @@ elseif (GEODE_TARGET_PLATFORM STREQUAL "MacOS") # only exists as a global property set(CMAKE_OSX_DEPLOYMENT_TARGET 10.14) - target_link_libraries(${PROJECT_NAME} INTERFACE curl "-framework Cocoa") + target_link_libraries(${PROJECT_NAME} INTERFACE + curl "-framework Cocoa" + ${GEODE_LOADER_PATH}/include/link/libfmod.dylib + ) target_compile_options(${PROJECT_NAME} INTERFACE -fms-extensions #[[-Wno-deprecated]] -Wno-ignored-attributes -Os #[[-flto]] #[[-fvisibility=internal]]) set(GEODE_PLATFORM_BINARY "Geode.dylib") From 2efe7723293fecb3c2bdfe7897f7e28a8a4ff5fa Mon Sep 17 00:00:00 2001 From: hjfod Date: Mon, 3 Apr 2023 09:36:38 +0300 Subject: [PATCH 58/70] fix crash if event listener is destroyed while they are being iterated --- loader/include/Geode/loader/Event.hpp | 8 ++++++++ loader/src/loader/Event.cpp | 11 ++++++++++- loader/src/ui/internal/info/ModInfoPopup.cpp | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/loader/include/Geode/loader/Event.hpp b/loader/include/Geode/loader/Event.hpp index 91c2a341..ae9688b7 100644 --- a/loader/include/Geode/loader/Event.hpp +++ b/loader/include/Geode/loader/Event.hpp @@ -133,6 +133,8 @@ namespace geode { private: friend EventListenerProtocol; + static std::unordered_set& removedListeners(); + public: Mod* sender; @@ -144,6 +146,12 @@ namespace geode { virtual ~Event(); + /** + * Get all active event listeners. You may use this to sort listeners + * that have an explicit order. You should never add/remove listeners + * manually however - use the enable() and disable() functions for that + * @warning Do not add/remove listeners manually + */ static std::vector& listeners(); /** * Move an event listener to the front of the queue so it is always hit diff --git a/loader/src/loader/Event.cpp b/loader/src/loader/Event.cpp index 0c78cc58..719fecd8 100644 --- a/loader/src/loader/Event.cpp +++ b/loader/src/loader/Event.cpp @@ -8,6 +8,7 @@ void EventListenerProtocol::enable() { } void EventListenerProtocol::disable() { + Event::removedListeners().insert(this); ranges::remove(Event::listeners(), this); } @@ -21,12 +22,20 @@ void Event::postFrom(Mod* m) { if (m) this->sender = m; std::vector listeners_copy = Event::listeners(); - for (auto h : listeners_copy) { + // if an event listener gets destroyed in the middle of this loop, we + // need to handle that + if (Event::removedListeners().count(h)) continue; if (h->passThrough(this) == ListenerResult::Stop) { break; } } + Event::removedListeners().clear(); +} + +std::unordered_set& Event::removedListeners() { + static std::unordered_set listeners; + return listeners; } std::vector& Event::listeners() { diff --git a/loader/src/ui/internal/info/ModInfoPopup.cpp b/loader/src/ui/internal/info/ModInfoPopup.cpp index 08359f33..a1d5d861 100644 --- a/loader/src/ui/internal/info/ModInfoPopup.cpp +++ b/loader/src/ui/internal/info/ModInfoPopup.cpp @@ -559,7 +559,7 @@ bool IndexItemInfoPopup::init(IndexItemHandle item, ModListLayer* list) { void IndexItemInfoPopup::onInstallProgress(ModInstallEvent* event) { std::visit(makeVisitor { - [&](UpdateFinished) { + [&](UpdateFinished const&) { this->setInstallStatus(std::nullopt); FLAlertLayer::create( From f8b32cdc885e9fe68ce444aaddcdc80fb69ed288 Mon Sep 17 00:00:00 2001 From: hjfod Date: Mon, 3 Apr 2023 10:04:56 +0300 Subject: [PATCH 59/70] add event tests --- VERSION | 2 +- loader/test/dependency/main.cpp | 20 +++++++++++++++++--- loader/test/dependency/main.hpp | 32 ++++++++++++++++++++++++++++++++ loader/test/dependency/mod.json | 2 +- loader/test/main/CMakeLists.txt | 1 + loader/test/main/main.cpp | 8 ++++++++ 6 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 loader/test/dependency/main.hpp diff --git a/VERSION b/VERSION index 1bc145e2..e521dc4f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0-beta.11 \ No newline at end of file +1.0.0-beta.12 \ No newline at end of file diff --git a/loader/test/dependency/main.cpp b/loader/test/dependency/main.cpp index 323766f3..2f6bd35d 100644 --- a/loader/test/dependency/main.cpp +++ b/loader/test/dependency/main.cpp @@ -1,12 +1,25 @@ #include - -using namespace geode::prelude; - #include #include #include #include #include +#include "main.hpp" + +using namespace geode::prelude; + +std::string TestEvent::getData() const { + return data; +} + +TestEvent::TestEvent(std::string const& data) : data(data) {} + +ListenerResult TestEventFilter::handle(utils::MiniFunction fn, TestEvent* event) { + fn(event); + return ListenerResult::Propagate; +} + +TestEventFilter::TestEventFilter() {} enum class Icon { Steve, @@ -137,6 +150,7 @@ SettingNode* MySettingValue::createNode(float width) { struct MyMenuLayer : Modify { void onMoreGames(CCObject*) { + TestEvent("Event system works!").post(); if (Mod::get()->getSettingValue("its-raining-after-all")) { FLAlertLayer::create("Damn", ":(", "OK")->show(); } diff --git a/loader/test/dependency/main.hpp b/loader/test/dependency/main.hpp new file mode 100644 index 00000000..583d81f1 --- /dev/null +++ b/loader/test/dependency/main.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +using namespace geode::prelude; + +#ifdef GEODE_IS_WINDOWS + #ifdef EXPORTING_MOD + #define GEODE_TESTDEP_DLL __declspec(dllexport) + #else + #define GEODE_TESTDEP_DLL __declspec(dllimport) + #endif +#else + #define GEODE_TESTDEP_DLL +#endif + +class GEODE_TESTDEP_DLL TestEvent : public Event { +protected: + std::string data; + +public: + std::string getData() const; + TestEvent(std::string const& data); +}; + +class GEODE_TESTDEP_DLL TestEventFilter : public EventFilter { +public: + using Callback = void(TestEvent*); + + ListenerResult handle(utils::MiniFunction fn, TestEvent* event); + TestEventFilter(); +}; diff --git a/loader/test/dependency/mod.json b/loader/test/dependency/mod.json index 27faa634..934cfc86 100644 --- a/loader/test/dependency/mod.json +++ b/loader/test/dependency/mod.json @@ -1,5 +1,5 @@ { - "geode": "0.6.1", + "geode": "1.0.0", "version": "1.0.0", "id": "geode.testdep", "name": "Geode Test Dependency", diff --git a/loader/test/main/CMakeLists.txt b/loader/test/main/CMakeLists.txt index 5a52ec17..ecf72046 100644 --- a/loader/test/main/CMakeLists.txt +++ b/loader/test/main/CMakeLists.txt @@ -9,5 +9,6 @@ target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20) set(GEODE_LINK_SOURCE ON) set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") +target_link_libraries(TestMod TestDependency) setup_geode_mod(${PROJECT_NAME} DONT_INSTALL) diff --git a/loader/test/main/main.cpp b/loader/test/main/main.cpp index 188524dc..3c6cd553 100644 --- a/loader/test/main/main.cpp +++ b/loader/test/main/main.cpp @@ -1,6 +1,7 @@ #include #include #include +#include "../dependency/main.hpp" using namespace geode::prelude; @@ -23,6 +24,13 @@ $on_mod(Unloaded) { log::info("Unloaded"); } +// Events +$execute { + new EventListener(+[](TestEvent* event) { + log::info("Received event: {}", event->getData()); + }); +} + // Modify #include From a7cea743472c42a9b346f1572c239b0a79e2bae0 Mon Sep 17 00:00:00 2001 From: hjfod Date: Mon, 3 Apr 2023 10:18:17 +0300 Subject: [PATCH 60/70] update changelog --- CHANGELOG.md | 74 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 879594fb..dca7bb73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,46 @@ # Geode Changelog +## v1.0.0-beta.12 + * Fix crash when installing mods (2efe772) + * FMOD is now linked on MacOS (f662251) + * `GEODE_DEBUG` on longer needs to be defined for `log::debug` to work (ab2abcd) + +## v1.0.0-beta.11 + * New `geode::prelude` namespace to replace the old `USE_GEODE_NAMESPACE()` macro (5af15fb) + * Add `CCNode::removeChildByID` (5f3c658) + * Add `CCNode::hasAncestor` (38575ac) + * Add `CCScene::get` and `CCScheduler::get` (38575ac) + * Add `geode::cocos::getMousePos` (306fde7) + * Add `GEODE_DONT_INSTALL_MODS` option to CMake (7ca9959) + * Add logging `std::vector` with `log::` functions (7305445) + * Add `EventListener::getFilter` (5cdfbc3) + * Add `AttributeSetEvent` for detecting when attributes are added to nodes (69bd0d9) + * Add `CCNode::addEventListener` (along with other related functions) as convenience methods for adding event listeners that target nodes (35f7f86) + * Add `WeakRef` as a weak pointer alternative to `Ref` (see [the docs](https://docs.geode-sdk.org/tutorials/memory#weakref) for a tutorial) (e92541a, 0e46362) + * Add option to ignore invisible children to `Layout` (152f90c) + * `CCNode` attributes now use `json::Value` over `std::any` for ABI compatability (7963469) + * Implement file picker on Mac (d7b0e09) + * Define `CCNode::retainCount` inline (57947a9, 72448e1) + * `Layout` now inherits from `CCObject`, allowing you to share layouts across multiple nodes (81472c9) + * Update TulipHook version (3d339ef) + * Make sure mod load/enable/etc. events are only ever posted in the GD thread (93fd396) + * `Mod::getResourcesDir` now returns `geode/unzipped/{mod.id}/resources/{mod.id}` in conjunction with [CLI v2.1.0](https://github.com/geode-sdk/cli/releases/tag/v2.1.1) (22a6745) + * Give a name to `ccTouchType` (e2e1da0) + * Fix `Scrollbar` being funky sometimes (585a9de, 83b0850) + * Fix mod resources not being loaded if the mod is enabled at runtime (9fb5051) + * Fix `EditLevelLayer` description update button ID & layout (21ee689) + * Fix hooking functions with unpredictable calling conventions (94138f3, 33a2883) + * Fix `setup_geode_mod` not linking to Geode if CLI calls are disabled (4318a8d) + * Fix code editors showing a ton of warnings with `$modify` (cf1371f) + * Fix top sprite sizes of `CircleButtonSprite` and `EditorButtonSprite` (0a37b01, eabb68b) + * Fix `Mod::enableHook` error message (162979c) + * Lots of bindings on both Windows & Mac (50+ commits related to bindings) + +## v1.0.0-beta.10 + * Fix loader minimum mod version preventing the loader itself from loading (ebfa7b2) + * Fix recursive comparison in VersionTag (1b2c760) + * `geode/unzipped` is now deleted on startup if it exists (eb0e4b6) + ## v1.0.0-beta.9 * Fix multiple modifiers not being able to have fields on same class due to having same field index (7710fa9) * Add `Result::ok` and `Result::err` for converting the `Result` into `std::optional` (4a15afc) @@ -24,7 +65,6 @@ * Fix `EditorPauseLayer` info labels on the top left being too big (f5983a2) ## v1.0.0-beta.6 - * Reworked layouts from the ground up - see [the docs page](https://docs.geode-sdk.org/tutorials/layouts) for more information about how the new system works (#137) * Update the IDs for a bunch of layers, aswell as adding some predefined layouts (3f64b98, ef9e741, a78bc0c, cb1a6f1, ea037a9, f7ddf0a, ...) * Add IDs & layouts to `EditorPauseLayer` (12d88ae) @@ -45,7 +85,6 @@ * Other fixes & improvements (cb00c21) ## v1.0.0-beta.5 - - Make ModInfo Pimpl 51990ad89b25cecbabaf748a5bcb279227fce090 - Fix crash with event listeners 1f7d50a9b9140d02f6a9afb97734eb9761b6a0d4 - Some bindings 4a9f6ba52a3d756d9bc28c1809afc92479783673 @@ -54,12 +93,10 @@ - Fix not following thunks 65f2cbb286cc1e5af57e43451862a2233d66453e ## v1.0.0-beta.4 - -- add some bindings -- fix macOS libzstd crash +- Add some bindings +- Fix macOS libzstd crash ## v1.0.0-beta.3 - - Better support for dependencies with [Geode CLI v1.4.x](https://github.com/geode-sdk/cli/releases/latest): mod dependencies are now automatically installed from the mods index by simply declaring them in your `mod.json`. See [the tutorial page in docs](https://docs.geode-sdk.org/mods/dependencies/) for more (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - The `create_geode_file` CMake function has been replaced by `setup_geode_mod`. The old `create_geode_file` function is still available, but will be deprecated in the future (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - `Result::except` now works with non-copyable types (f32aaa8b124bdd040a453bc25d31a4e463cf1309) @@ -73,12 +110,10 @@ - MacOS minimum version bumped to 10.14 (916f54063008c6bdf892d02f8bcd92b58606817e) ## v1.0.0-beta.2 - * Fixed bug where `Mod::getSavedValue` would cause a crash due to trying operator on a null JSON value (5bbd34c) * Fixed bug where loading would crash if one of the mods' binaries failed to load (ef86ae0) ## v1.0.0-beta.1 - * Switched to [a new custom-built JSON library](https://github.com/geode-sdk/json) to replace `nlohmann::json` for compile-time improvements; if you were using the old JSON library, you can add & link to `nlohmann::json` in your own project, or update to use the new API. (deab672) * Fix resources not being downloaded automatically by using a fallback to latest release (a418828) * Add a new clear instruction popup in case downloading still fails (30dc9ad) @@ -87,7 +122,6 @@ ## v1.0.0-alpha - - Major rework of the entire framework; most notable changes include switching to a whole new hooking framework (TulipHook), simplifying many parts of the framework, and making it production-ready. ## v0.7.0 @@ -105,7 +139,6 @@ - Add more bindings ## v0.6.0 - - Mod resource loading has been reworked again, with the intent of adding support for texture pack loaders - Added `Loader::addTexturePath` and `Loader::removeTexturePath` to work with additional resource paths - Mods that work with Cocos2d search paths directly should convert to using the above functions @@ -121,7 +154,6 @@ - Add IDs to `LevelSearchLayer` (thank you @Jollycistaken) ## v0.5.0 - - Added `CCFileUtils::get` - Fix crashes related to setting IDs in `MenuLayer` - Remove `Loader::updateModResourcePaths` and `Loader::updateResourcePaths`. The minimum mod target version is still v0.4.0 however, as you should never have been using these functions. @@ -130,17 +162,14 @@ - Finally added a license to Geode! The framework is now licensed under BSL v1.0. ## v0.4.8 - - CLI issues fixed in v1.0.6 so loader again verifies if loader resources are missing / corrupt on startup - Resource download text is no longer a popup on top of the title but instead just replaces the loading text - Add delegates to `EditLevelLayer` ## v0.4.7 - - Loader resources check would always fail due to CLI issues, so for now loader just checks if the resources folder exists ## v0.4.6 - - Automatically checks & downloads loader resources if they are missing / corrupt on startup - CMake rework; `GeodeFile.cmake` now checks and verifies CLI version - Add optional `DONT_INSTALL` parameter to `create_geode_file` @@ -150,7 +179,6 @@ - Change `CCArrayExt` to use `Ref` ## v0.4.5 - - Rework bindings and codegen to improve compile times, now individual bindings can be included with `` - Modify has also been separated, you can now include individual modifiers with `` - Various other fixes to improve compile times @@ -175,25 +203,21 @@ - Remove automatic mod updating for now, however automatic update checking for mods is still there ## v0.4.4 - - New `listenForSettingChanges` API for more ergonomically listening for setting changes - Fixed bug where GD was unopenable through Steam - Various other internal fixes ## v0.4.3 - - Simplified the minimum and maximum loader versions, loader will now load any mod whose target version major and minor match. In practice, this means that for example mods whose target version is v0.4.8 can be loaded by loader of version v0.4.6. - Add `Geode/ui/GeodeUI.hpp` header for exposing some access to internal Geode UI like opening a mod's settings popup - Fix crash with settings that could have a slider control ## v0.4.2 - - Moved SDK version to its own file so CLI can query it - md4c is now linked statically on MacOS - Fix log filenames ## v0.4.1 - - Initial dev release of Geode. --- @@ -201,51 +225,39 @@ Note that from here on, changes to the framework were not tracked by versions as the framework was still considered to be in heavy development and not released. Instead, major changes are listed by dates. ## 2022/10/10 - - Geode released for developers ## 2022/10/08 - - `ui` branch merged to `main` ## 2022/10/03 - - New CLI finished - `ui` branch finished ## 2022/08/01 - - CLI redesign started ## 2022/07/30 - - `sdk`, `loader` and `api` repos all merged into one `geode` repo ## 2022/05/24 - - Geode announced to be merging with Hyperdash, later on it turned out we were all pathological liars ## 2022/05/02 - - Installer on Windows ## 2022/04/30 - - Installing mods in-game works ## 2022/01/23 - - CLI started ## 2022/01/19 - - Lilac and Cacao merged and renamed to Geode ## 2021/07/30 - - Lilac started by Mat, HJfod and Pie ## 2021/01/25 - - CacaoSDK started by Camila, based on CappuccinoSDK From 75580a01ae2cff2c3de773d643dbc1a11af76fb5 Mon Sep 17 00:00:00 2001 From: hjfod Date: Mon, 3 Apr 2023 10:43:52 +0300 Subject: [PATCH 61/70] changelog stuff - make changelog visible in-game - fix issues with the changelog in ModInfoPopup & scrollbar --- .gitignore | 1 + CHANGELOG.md | 181 ++++++++++--------- CMakeLists.txt | 1 + loader/CMakeLists.txt | 1 + loader/src/internal/about.hpp.in | 1 + loader/src/loader/ModImpl.cpp | 1 + loader/src/ui/internal/info/ModInfoPopup.cpp | 26 ++- loader/src/ui/internal/info/ModInfoPopup.hpp | 2 +- loader/src/ui/nodes/Scrollbar.cpp | 4 + 9 files changed, 120 insertions(+), 98 deletions(-) diff --git a/.gitignore b/.gitignore index 78fb94ee..e54eeeac 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ loader/src/internal/about.hpp loader/src/internal/resources.hpp loader/resources/mod.json loader/resources/blanks/rename.js +loader/resources/changelog.md fods-catgirl-hideout.txt # krita files too because alk is funny diff --git a/CHANGELOG.md b/CHANGELOG.md index dca7bb73..f0b86c97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,124 +1,125 @@ # Geode Changelog ## v1.0.0-beta.12 - * Fix crash when installing mods (2efe772) - * FMOD is now linked on MacOS (f662251) - * `GEODE_DEBUG` on longer needs to be defined for `log::debug` to work (ab2abcd) + * Fix crash when installing mods + * FMOD is now linked on MacOS + * `GEODE_DEBUG` on longer needs to be defined for `log::debug` to work + * Make Geode changelog visible in-game ## v1.0.0-beta.11 - * New `geode::prelude` namespace to replace the old `USE_GEODE_NAMESPACE()` macro (5af15fb) - * Add `CCNode::removeChildByID` (5f3c658) - * Add `CCNode::hasAncestor` (38575ac) - * Add `CCScene::get` and `CCScheduler::get` (38575ac) - * Add `geode::cocos::getMousePos` (306fde7) - * Add `GEODE_DONT_INSTALL_MODS` option to CMake (7ca9959) - * Add logging `std::vector` with `log::` functions (7305445) - * Add `EventListener::getFilter` (5cdfbc3) - * Add `AttributeSetEvent` for detecting when attributes are added to nodes (69bd0d9) - * Add `CCNode::addEventListener` (along with other related functions) as convenience methods for adding event listeners that target nodes (35f7f86) - * Add `WeakRef` as a weak pointer alternative to `Ref` (see [the docs](https://docs.geode-sdk.org/tutorials/memory#weakref) for a tutorial) (e92541a, 0e46362) - * Add option to ignore invisible children to `Layout` (152f90c) - * `CCNode` attributes now use `json::Value` over `std::any` for ABI compatability (7963469) - * Implement file picker on Mac (d7b0e09) - * Define `CCNode::retainCount` inline (57947a9, 72448e1) - * `Layout` now inherits from `CCObject`, allowing you to share layouts across multiple nodes (81472c9) - * Update TulipHook version (3d339ef) - * Make sure mod load/enable/etc. events are only ever posted in the GD thread (93fd396) - * `Mod::getResourcesDir` now returns `geode/unzipped/{mod.id}/resources/{mod.id}` in conjunction with [CLI v2.1.0](https://github.com/geode-sdk/cli/releases/tag/v2.1.1) (22a6745) - * Give a name to `ccTouchType` (e2e1da0) - * Fix `Scrollbar` being funky sometimes (585a9de, 83b0850) - * Fix mod resources not being loaded if the mod is enabled at runtime (9fb5051) - * Fix `EditLevelLayer` description update button ID & layout (21ee689) - * Fix hooking functions with unpredictable calling conventions (94138f3, 33a2883) - * Fix `setup_geode_mod` not linking to Geode if CLI calls are disabled (4318a8d) - * Fix code editors showing a ton of warnings with `$modify` (cf1371f) - * Fix top sprite sizes of `CircleButtonSprite` and `EditorButtonSprite` (0a37b01, eabb68b) - * Fix `Mod::enableHook` error message (162979c) + * New `geode::prelude` namespace to replace the old `USE_GEODE_NAMESPACE()` macro + * Add `CCNode::removeChildByID` + * Add `CCNode::hasAncestor` + * Add `CCScene::get` and `CCScheduler::get` + * Add `geode::cocos::getMousePos` + * Add `GEODE_DONT_INSTALL_MODS` option to CMake + * Add logging `std::vector` with `log::` functions + * Add `EventListener::getFilter` + * Add `AttributeSetEvent` for detecting when attributes are added to nodes + * Add `CCNode::addEventListener` (along with other related functions) as convenience methods for adding event listeners that target nodes + * Add `WeakRef` as a weak pointer alternative to `Ref` (see [the docs](https://docs.geode-sdk.org/tutorials/memory#weakref) for a tutorial) + * Add option to ignore invisible children to `Layout` + * `CCNode` attributes now use `json::Value` over `std::any` for ABI compatability + * Implement file picker on Mac + * Define `CCNode::retainCount` inline + * `Layout` now inherits from `CCObject`, allowing you to share layouts across multiple nodes + * Update TulipHook version + * Make sure mod load/enable/etc. events are only ever posted in the GD thread + * `Mod::getResourcesDir` now returns `geode/unzipped/{mod.id}/resources/{mod.id}` in conjunction with [CLI v2.1.0](https://github.com/geode-sdk/cli/releases/tag/v2.1.1) + * Give a name to `ccTouchType` + * Fix `Scrollbar` being funky sometimes + * Fix mod resources not being loaded if the mod is enabled at runtime + * Fix `EditLevelLayer` description update button ID & layout + * Fix hooking functions with unpredictable calling conventions + * Fix `setup_geode_mod` not linking to Geode if CLI calls are disabled + * Fix code editors showing a ton of warnings with `$modify` + * Fix top sprite sizes of `CircleButtonSprite` and `EditorButtonSprite` + * Fix `Mod::enableHook` error message * Lots of bindings on both Windows & Mac (50+ commits related to bindings) ## v1.0.0-beta.10 - * Fix loader minimum mod version preventing the loader itself from loading (ebfa7b2) - * Fix recursive comparison in VersionTag (1b2c760) - * `geode/unzipped` is now deleted on startup if it exists (eb0e4b6) + * Fix loader minimum mod version preventing the loader itself from loading + * Fix recursive comparison in VersionTag + * `geode/unzipped` is now deleted on startup if it exists ## v1.0.0-beta.9 - * Fix multiple modifiers not being able to have fields on same class due to having same field index (7710fa9) - * Add `Result::ok` and `Result::err` for converting the `Result` into `std::optional` (4a15afc) + * Fix multiple modifiers not being able to have fields on same class due to having same field index + * Add `Result::ok` and `Result::err` for converting the `Result` into `std::optional` ## v1.0.0-beta.8 - * Unload the mod even when first time warning pops up (63b4774) - * Error when address of a function returns nullptr when hooking (724a9d3) - * Add support for Geode CLI v2.0.0 (which has not been released yet) (088ac7b, deadb58) - * Logging no longer causes a crash on invalid formats, but instead just warns (6aba7cf) - * `file::pickFile` now uses the last item in the default path as the default filename to save/open (5c9ee08) - * Fix `EditorPauseLayer` crashing constantly due to some members being accidentally set to `nullptr` (33a91d6) + * Unload the mod even when first time warning pops up + * Error when address of a function returns nullptr when hooking + * Add support for Geode CLI v2.0.0 (which has not been released yet) + * Logging no longer causes a crash on invalid formats, but instead just warns + * `file::pickFile` now uses the last item in the default path as the default filename to save/open + * Fix `EditorPauseLayer` crashing constantly due to some members being accidentally set to `nullptr` ## v1.0.0-beta.7 - * Add `Mod::getResourcesDir` for getting the mod resources directory (0055032) - * Deprecate `file::listFiles` for `file::readDirectory` (9f60091) - * Fix getting virtual function addresses for CCFileUtils (c183a35) - * Rename `BasedButtonSprite` sprite names to be more expressive (4d2daec) - * Fix `typeinfo_cast` causing a crash if passed a `nullptr` on MacOS (d024dbb) - * Fix settings not getting broadcasted (7089194) - * Make `Loader::getLoadedMod` and `Loader::isModLoaded` also check if mod is enabled (3222097) - * Display Geode commit hash in the bottom right of the mod info layer (1dfa907) - * Fix `EditorPauseLayer` info labels on the top left being too big (f5983a2) + * Add `Mod::getResourcesDir` for getting the mod resources directory + * Deprecate `file::listFiles` for `file::readDirectory` + * Fix getting virtual function addresses for CCFileUtils + * Rename `BasedButtonSprite` sprite names to be more expressive + * Fix `typeinfo_cast` causing a crash if passed a `nullptr` on MacOS + * Fix settings not getting broadcasted + * Make `Loader::getLoadedMod` and `Loader::isModLoaded` also check if mod is enabled + * Display Geode commit hash in the bottom right of the mod info layer + * Fix `EditorPauseLayer` info labels on the top left being too big ## v1.0.0-beta.6 * Reworked layouts from the ground up - see [the docs page](https://docs.geode-sdk.org/tutorials/layouts) for more information about how the new system works (#137) * Update the IDs for a bunch of layers, aswell as adding some predefined layouts (3f64b98, ef9e741, a78bc0c, cb1a6f1, ea037a9, f7ddf0a, ...) - * Add IDs & layouts to `EditorPauseLayer` (12d88ae) - * Add `CCNode::insertBefore` and `CCNode::insertAfter` for adding children before/after existing ones (eb10eca, 4613af6) + * Add IDs & layouts to `EditorPauseLayer` + * Add `CCNode::insertBefore` and `CCNode::insertAfter` for adding children before/after existing ones * Add `CCSize::aspect` convenience method - * Add `Mod::getResourcesDir` for getting a mod's runtime resources directory (where `[mod.json].resources.files` are placed) (0055032) - * Add `Mod::addCustomSetting` for convenience in registering custom settings (7089194) - * Add `file::readDirectory` as a sanely named alternative to `file::listFiles` (9f60091) - * Move `GEODE_DLL` to the structs themselves in `JsonValidation` (06bc6fd) - * Versions now support tag numbers & version tags are now used in comparisons. This change does not affect old betas, which still internally report their version as just `v1.0.0-beta`, but starting with this beta the version is correctly reported as `v1.0.0-beta.6` and correctly compared against other versions (bbbf332) - * `Loader::getLoadedMod` and `Loader::isModLoaded` now only return if the mod is also enabled (3222097) - * Geode's internal mod representation is now included in the loader's loaded mods list (4261e99) - * Fix settings value changes not being broadcast. This causes an API break relating to custom settings; `SettingValue` now requires the owner mod ID in its constructor (7089194) - * Fix some warnings (9c9706b, f7bfa21) - * Fix `CCNode::swapChildIndices` (ba0851e) - * Fix `typeinfo_cast` causing a crash if passed a `nullptr` (f4a3258) - * Fix `ranges::reverse` causing UB (ffd50eb) - * Other fixes & improvements (cb00c21) + * Add `Mod::getResourcesDir` for getting a mod's runtime resources directory (where `[mod.json].resources.files` are placed) + * Add `Mod::addCustomSetting` for convenience in registering custom settings + * Add `file::readDirectory` as a sanely named alternative to `file::listFiles` + * Move `GEODE_DLL` to the structs themselves in `JsonValidation` + * Versions now support tag numbers & version tags are now used in comparisons. This change does not affect old betas, which still internally report their version as just `v1.0.0-beta`, but starting with this beta the version is correctly reported as `v1.0.0-beta.6` and correctly compared against other versions + * `Loader::getLoadedMod` and `Loader::isModLoaded` now only return if the mod is also enabled + * Geode's internal mod representation is now included in the loader's loaded mods list + * Fix settings value changes not being broadcast. This causes an API break relating to custom settings; `SettingValue` now requires the owner mod ID in its constructor + * Fix some warnings + * Fix `CCNode::swapChildIndices` + * Fix `typeinfo_cast` causing a crash if passed a `nullptr` + * Fix `ranges::reverse` causing UB + * Other fixes & improvements ## v1.0.0-beta.5 -- Make ModInfo Pimpl 51990ad89b25cecbabaf748a5bcb279227fce090 -- Fix crash with event listeners 1f7d50a9b9140d02f6a9afb97734eb9761b6a0d4 -- Some bindings 4a9f6ba52a3d756d9bc28c1809afc92479783673 -- Make mods binaries not silently fail to load 0eb5f01ca81435cb90f2bc9d8d97a86405dadd1c -- Assume dependency version is >= comparison by default 41aef57758d7b858d5fa7cb22ab1ffe603ff365f -- Fix not following thunks 65f2cbb286cc1e5af57e43451862a2233d66453e +- Make ModInfo Pimpl +- Fix crash with event listeners +- Some bindings +- Make mods binaries not silently fail to load +- Assume dependency version is >= comparison by default +- Fix not following thunks ## v1.0.0-beta.4 - Add some bindings - Fix macOS libzstd crash ## v1.0.0-beta.3 - - Better support for dependencies with [Geode CLI v1.4.x](https://github.com/geode-sdk/cli/releases/latest): mod dependencies are now automatically installed from the mods index by simply declaring them in your `mod.json`. See [the tutorial page in docs](https://docs.geode-sdk.org/mods/dependencies/) for more (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - - The `create_geode_file` CMake function has been replaced by `setup_geode_mod`. The old `create_geode_file` function is still available, but will be deprecated in the future (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - - `Result::except` now works with non-copyable types (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - - `Zip` and `Unzip` now support in-memory ZIP extraction and creation (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - - `ComparableVersionInfo::compare` now always returns false if the major versions are different (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - - `ComparableVersionInfo` parsing now expects equal to be marked with a single `=` instead of two (`==v1.2.3` => `=v1.2.3`) (6d3847d9e13fdf69cea0b9a69376ebcd88e71725) - - Fix `DS_Dictionary`-related `gd::string` Cocos2d functions not being linked (ab0030136ab8c20731fe768ef5f3b16ae4245583) - - `CC_DLL` no longer expands to dllexport/dllimport (ab0030136ab8c20731fe768ef5f3b16ae4245583) - - The JSON lib now default constructs to object, hopefully fixing uncaught bugs (30101fc0b5112317aac3c9eeea0aab888ca8b30d) - - Something related to codegen and addresser? I have no clue what it does, so you probably won't have either (ae1eb8bb7162342f598e047a459e3808801f731a, 1e9faac5aa5a32b0cb5e6ffaac0c5cbfc217e9cb, fea049cca069a08181ab66cacda6f2417c006a2f, ad261846919e503cc3faf75d777ab2f2882bc6bb, ...) - - MacOS minimum version bumped to 10.14 (916f54063008c6bdf892d02f8bcd92b58606817e) + - Better support for dependencies with [Geode CLI v1.4.x](https://github.com/geode-sdk/cli/releases/latest): mod dependencies are now automatically installed from the mods index by simply declaring them in your `mod.json`. See [the tutorial page in docs](https://docs.geode-sdk.org/mods/dependencies/) for more + - The `create_geode_file` CMake function has been replaced by `setup_geode_mod`. The old `create_geode_file` function is still available, but will be deprecated in the future + - `Result::except` now works with non-copyable types + - `Zip` and `Unzip` now support in-memory ZIP extraction and creation + - `ComparableVersionInfo::compare` now always returns false if the major versions are different + - `ComparableVersionInfo` parsing now expects equal to be marked with a single `=` instead of two (`==v1.2.3` => `=v1.2.3`) + - Fix `DS_Dictionary`-related `gd::string` Cocos2d functions not being linked + - `CC_DLL` no longer expands to dllexport/dllimport + - The JSON lib now default constructs to object, hopefully fixing uncaught bugs + - Something related to codegen and addresser? I have no clue what it does, so you probably won't have either + - MacOS minimum version bumped to 10.14 ## v1.0.0-beta.2 - * Fixed bug where `Mod::getSavedValue` would cause a crash due to trying operator on a null JSON value (5bbd34c) - * Fixed bug where loading would crash if one of the mods' binaries failed to load (ef86ae0) + * Fixed bug where `Mod::getSavedValue` would cause a crash due to trying operator on a null JSON value + * Fixed bug where loading would crash if one of the mods' binaries failed to load ## v1.0.0-beta.1 - * Switched to [a new custom-built JSON library](https://github.com/geode-sdk/json) to replace `nlohmann::json` for compile-time improvements; if you were using the old JSON library, you can add & link to `nlohmann::json` in your own project, or update to use the new API. (deab672) - * Fix resources not being downloaded automatically by using a fallback to latest release (a418828) - * Add a new clear instruction popup in case downloading still fails (30dc9ad) - * String ID hooks now have higher priority, so they should always be applied regardless of if you call `NodeIDs::provideFor` or not (though it can still be called to absolutely ensure the IDs are there!) (b6a6e4d) - * Various internal bugfixes & improvements (ceb02e9, a90b3e1, b00ab40, c644b43) + * Switched to [a new custom-built JSON library](https://github.com/geode-sdk/json) to replace `nlohmann::json` for compile-time improvements; if you were using the old JSON library, you can add & link to `nlohmann::json` in your own project, or update to use the new API. + * Fix resources not being downloaded automatically by using a fallback to latest release + * Add a new clear instruction popup in case downloading still fails + * String ID hooks now have higher priority, so they should always be applied regardless of if you call `NodeIDs::provideFor` or not (though it can still be called to absolutely ensure the IDs are there!) + * Various internal bugfixes & improvements ## v1.0.0-alpha diff --git a/CMakeLists.txt b/CMakeLists.txt index f2963fe5..28afb440 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ target_compile_definitions(${PROJECT_NAME} INTERFACE -DPROJECT_NAME=${CMAKE_PROJ set(GEODE_CODEGEN_PATH ${CMAKE_CURRENT_BINARY_DIR}/codegenned) set(GEODE_BIN_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin) set(GEODE_LOADER_PATH ${CMAKE_CURRENT_SOURCE_DIR}/loader) +set(GEODE_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) include(cmake/GeodeFile.cmake) include(cmake/Platform.cmake) diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index f19f0a20..e079e4d8 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -30,6 +30,7 @@ execute_process( configure_file(resources/mod.json.in ${CMAKE_CURRENT_SOURCE_DIR}/resources/mod.json) file(READ resources/mod.json LOADER_MOD_JSON) file(READ resources/about.md LOADER_ABOUT_MD) +file(READ ${GEODE_ROOT_PATH}/CHANGELOG.md LOADER_CHANGELOG_MD) configure_file(src/internal/about.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/src/internal/about.hpp) # Source files diff --git a/loader/src/internal/about.hpp.in b/loader/src/internal/about.hpp.in index 6f15b842..40dbf1b5 100644 --- a/loader/src/internal/about.hpp.in +++ b/loader/src/internal/about.hpp.in @@ -3,6 +3,7 @@ #include static constexpr const char* LOADER_ABOUT_MD = R"MD_SEPARATOR(@LOADER_ABOUT_MD@)MD_SEPARATOR"; +static constexpr const char* LOADER_CHANGELOG_MD = R"MD_SEPARATOR(@LOADER_CHANGELOG_MD@)MD_SEPARATOR"; static constexpr const char* LOADER_VERSION_STR = "@PROJECT_VERSION@@PROJECT_VERSION_SUFFIX@"; static constexpr int LOADER_VERSION_MAJOR = @PROJECT_VERSION_MAJOR@; static constexpr int LOADER_VERSION_MINOR = @PROJECT_VERSION_MINOR@; diff --git a/loader/src/loader/ModImpl.cpp b/loader/src/loader/ModImpl.cpp index fe33adf2..41ca17cc 100644 --- a/loader/src/loader/ModImpl.cpp +++ b/loader/src/loader/ModImpl.cpp @@ -694,6 +694,7 @@ static ModInfo getModImplInfo() { } auto info = infoRes.unwrap(); info.details() = LOADER_ABOUT_MD; + info.changelog() = LOADER_CHANGELOG_MD; info.supportInfo() = SUPPORT_INFO; info.supportsDisabling() = false; return info; diff --git a/loader/src/ui/internal/info/ModInfoPopup.cpp b/loader/src/ui/internal/info/ModInfoPopup.cpp index a1d5d861..6b1d79f0 100644 --- a/loader/src/ui/internal/info/ModInfoPopup.cpp +++ b/loader/src/ui/internal/info/ModInfoPopup.cpp @@ -112,12 +112,8 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) { // changelog if (info.changelog()) { - m_changelogArea = MDTextArea::create(info.changelog().value(), { 350.f, 137.5f }); - m_changelogArea->setPosition( - -5000.f, winSize.height / 2 - m_changelogArea->getScaledContentSize().height / 2 - 20.f - ); - m_changelogArea->setVisible(false); - m_mainLayer->addChild(m_changelogArea); + // m_changelogArea is only created if the changelog button is clicked + // because changelogs can get really long and take a while to load auto changelogBtnOffSpr = ButtonSprite::create( CCSprite::createWithSpriteFrameName("changelog.png"_spr), @@ -225,9 +221,19 @@ void ModInfoPopup::onInfo(CCObject*) { } void ModInfoPopup::onChangelog(CCObject* sender) { - auto toggle = static_cast(sender); auto winSize = CCDirector::get()->getWinSize(); + if (!m_changelogArea) { + m_changelogArea = MDTextArea::create(Mod::get()->getModInfo().changelog().value(), { 350.f, 137.5f }); + m_changelogArea->setPosition( + -5000.f, winSize.height / 2 - m_changelogArea->getScaledContentSize().height / 2 - 20.f + ); + m_changelogArea->setVisible(false); + m_mainLayer->addChild(m_changelogArea); + } + + auto toggle = static_cast(sender); + m_detailsArea->setVisible(toggle->isToggled()); // as it turns out, cocos2d is stupid and still passes touch // events to invisible nodes @@ -243,6 +249,12 @@ void ModInfoPopup::onChangelog(CCObject* sender) { !toggle->isToggled() ? winSize.width / 2 - m_changelogArea->getScaledContentSize().width / 2 : -5000.f ); + + m_scrollbar->setTarget( + toggle->isToggled() ? + m_detailsArea->getScrollLayer() : + m_changelogArea->getScrollLayer() + ); } void ModInfoPopup::keyDown(enumKeyCodes key) { diff --git a/loader/src/ui/internal/info/ModInfoPopup.hpp b/loader/src/ui/internal/info/ModInfoPopup.hpp index 9a6ac92f..aed289ed 100644 --- a/loader/src/ui/internal/info/ModInfoPopup.hpp +++ b/loader/src/ui/internal/info/ModInfoPopup.hpp @@ -35,7 +35,7 @@ protected: CCMenuItemSpriteExtra* m_infoBtn; CCLabelBMFont* m_updateVersionLabel = nullptr; MDTextArea* m_detailsArea; - MDTextArea* m_changelogArea; + MDTextArea* m_changelogArea = nullptr; Scrollbar* m_scrollbar; void onChangelog(CCObject*); diff --git a/loader/src/ui/nodes/Scrollbar.cpp b/loader/src/ui/nodes/Scrollbar.cpp index a3731919..406fe80c 100644 --- a/loader/src/ui/nodes/Scrollbar.cpp +++ b/loader/src/ui/nodes/Scrollbar.cpp @@ -99,6 +99,10 @@ void Scrollbar::draw() { auto y = m_target->m_contentLayer->getPositionY(); auto thumbHeight = m_resizeThumb ? std::min(p, 1.f) * targetHeight / .4f : 0; + if (thumbHeight < 15.f) { + thumbHeight = 15.f; + } + auto thumbPosY = -targetHeight / 2 + thumbHeight / 4 - 5.0f + (h ? (-y) / h : 1.f) * (targetHeight - thumbHeight / 2 + 10.0f); From 4801f6725fbee0ca926cacd9503e7df702740cfa Mon Sep 17 00:00:00 2001 From: hjfod Date: Mon, 3 Apr 2023 10:45:41 +0300 Subject: [PATCH 62/70] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0b86c97..62fd91e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ * FMOD is now linked on MacOS * `GEODE_DEBUG` on longer needs to be defined for `log::debug` to work * Make Geode changelog visible in-game + * Make the changelog only be loaded once the changelog button is pressed in ModInfoPopup + * Fix the scrollbar not working for the changelog in ModInfoPopup + * Fix visual issues with scrollbars ## v1.0.0-beta.11 * New `geode::prelude` namespace to replace the old `USE_GEODE_NAMESPACE()` macro From c1d4a89f8b989d41829761de39423f987e8d977b Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Mon, 3 Apr 2023 21:04:56 +0300 Subject: [PATCH 63/70] fix event listeners vector containing freed listeners --- loader/src/loader/Event.cpp | 16 +++++++++++++--- loader/src/utils/cocos.cpp | 8 ++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/loader/src/loader/Event.cpp b/loader/src/loader/Event.cpp index 719fecd8..52410c5b 100644 --- a/loader/src/loader/Event.cpp +++ b/loader/src/loader/Event.cpp @@ -4,7 +4,9 @@ using namespace geode::prelude; void EventListenerProtocol::enable() { - Event::listeners().push_back(this); + if (!ranges::contains(Event::listeners(), this)) { + Event::listeners().push_back(this); + } } void EventListenerProtocol::disable() { @@ -20,7 +22,16 @@ Event::~Event() {} void Event::postFrom(Mod* m) { if (m) this->sender = m; - + auto& listeners = Event::listeners(); + listeners.erase(std::remove_if( + listeners.begin(), + listeners.end(), + [](auto& a) { + return Event::removedListeners().contains(a); + } + ), listeners.end()); + Event::removedListeners().clear(); + std::vector listeners_copy = Event::listeners(); for (auto h : listeners_copy) { // if an event listener gets destroyed in the middle of this loop, we @@ -30,7 +41,6 @@ void Event::postFrom(Mod* m) { break; } } - Event::removedListeners().clear(); } std::unordered_set& Event::removedListeners() { diff --git a/loader/src/utils/cocos.cpp b/loader/src/utils/cocos.cpp index cc43087a..82a5c070 100644 --- a/loader/src/utils/cocos.cpp +++ b/loader/src/utils/cocos.cpp @@ -328,8 +328,12 @@ void geode::cocos::limitNodeSize(cocos2d::CCNode* spr, cocos2d::CCSize const& si } bool geode::cocos::nodeIsVisible(cocos2d::CCNode* node) { - if (!node->isVisible()) return false; - if (node->getParent()) return nodeIsVisible(node->getParent()); + if (!node->isVisible()) { + return false; + } + if (node->getParent()) { + return nodeIsVisible(node->getParent()); + } return true; } From b44b5d3cd3f6580e8f7cdafe631a9aefef7d62c8 Mon Sep 17 00:00:00 2001 From: hjfod Date: Tue, 4 Apr 2023 17:44:49 +0300 Subject: [PATCH 64/70] add SpacerNode & bring back Dispatch --- .../include/Geode/cocos/base_nodes/Layout.hpp | 8 +- .../Geode/cocos/base_nodes/SpacerNode.hpp | 59 ++++++++++++++ loader/include/Geode/cocos/include/cocos2d.h | 1 + loader/include/Geode/loader/Dispatch.hpp | 65 ++++++++-------- loader/src/cocos2d-ext/Layout.cpp | 78 ++++++++++++++++++- 5 files changed, 176 insertions(+), 35 deletions(-) create mode 100644 loader/include/Geode/cocos/base_nodes/SpacerNode.hpp diff --git a/loader/include/Geode/cocos/base_nodes/Layout.hpp b/loader/include/Geode/cocos/base_nodes/Layout.hpp index c78cb76a..7d8ab0f6 100644 --- a/loader/include/Geode/cocos/base_nodes/Layout.hpp +++ b/loader/include/Geode/cocos/base_nodes/Layout.hpp @@ -23,7 +23,7 @@ class CCNode; */ class GEODE_DLL Layout : public CCObject { protected: - CCArray* getNodesToPosition(CCNode* forNode); + CCArray* getNodesToPosition(CCNode* forNode) const; bool m_ignoreInvisibleChildren = false; @@ -37,6 +37,11 @@ public: */ virtual void apply(CCNode* on) = 0; + /** + * Get how much space this layout would like to take up for a given target + */ + virtual CCSize getSizeHint(CCNode* on) const = 0; + void ignoreInvisibleChildren(bool ignore); bool isIgnoreInvisibleChildren() const; @@ -262,6 +267,7 @@ public: static AxisLayout* create(Axis axis = Axis::Row); void apply(CCNode* on) override; + CCSize getSizeHint(CCNode* on) const override; Axis getAxis() const; AxisAlignment getAxisAlignment() const; diff --git a/loader/include/Geode/cocos/base_nodes/SpacerNode.hpp b/loader/include/Geode/cocos/base_nodes/SpacerNode.hpp new file mode 100644 index 00000000..2e153611 --- /dev/null +++ b/loader/include/Geode/cocos/base_nodes/SpacerNode.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include "CCNode.h" + +NS_CC_BEGIN + +#pragma warning(push) +#pragma warning(disable: 4275) + +/** + * A node for controlling spacing in Layouts. When a Layout is applied, if + * space is left over, the remaining space is divided among all SpacerNodes in + * the Layout. The space each node gets is the proprotion between its growth + * factor and the sum of all the SpacerNodes' growth factors in the Layout + * @example + * node->addChild(SpacerNode::create(1)); + * node->addChild(SpacerNode::create(2)); + * node->addChild(SpacerNode::create(1)); + * node->updateLayout(); + * // Total SpacerNode growth sum is 1 + 2 + 1 = 4 + * // So s1 and s3 get 1/4 of the remaining space and s2 gets 2/4 + * @note If you want to specify a minimum width for a SpacerNode, add + * AxisLayoutOptions for it and use setLength + */ +class GEODE_DLL SpacerNode : public CCNode { +protected: + size_t m_grow; + + bool init(size_t grow); + +public: + /** + * Create a new spacer node. When the layout is applied, + * if there is space left over the remaining space is distributed among + * all spacer nodes in proportion to the sum of all the spacers' grow + * factors (akin to CSS flew grow) + * @param grow The grow factor for this node. Default is 1 + */ + static SpacerNode* create(size_t grow = 1); + + /** + * Set the grow factor for this spacer node. When the layout is applied, + * if there is space left over the remaining space is distributed among + * all spacer nodes in proportion to the sum of all the spacers' grow + * factors (akin to CSS flew grow) + * @param grow The new grow factor for this node. Default is 1 + * @note Make sure to call updateLayout on the spacer's parent afterwards + */ + void setGrow(size_t grow); + + /** + * Get the grow factor for this spacer node + */ + size_t getGrow() const; +}; + +#pragma warning(pop) + +NS_CC_END diff --git a/loader/include/Geode/cocos/include/cocos2d.h b/loader/include/Geode/cocos/include/cocos2d.h index b4303995..f984a172 100644 --- a/loader/include/Geode/cocos/include/cocos2d.h +++ b/loader/include/Geode/cocos/include/cocos2d.h @@ -59,6 +59,7 @@ THE SOFTWARE. // base_nodes #include "../base_nodes/CCNode.h" #include "../base_nodes/CCAtlasNode.h" +#include "../base_nodes/SpacerNode.hpp" // cocoa #include "../cocoa/CCAffineTransform.h" diff --git a/loader/include/Geode/loader/Dispatch.hpp b/loader/include/Geode/loader/Dispatch.hpp index dec81ba5..9f8a4c39 100644 --- a/loader/include/Geode/loader/Dispatch.hpp +++ b/loader/include/Geode/loader/Dispatch.hpp @@ -9,42 +9,41 @@ namespace geode { // Mod interoperability - // todo: update to new event system + template + class DispatchEvent : public Event { + protected: + std::string m_id; + std::tuple m_args; + + public: + DispatchEvent(std::string const& id, Args&&... args) + : m_id(id), m_args(std::make_tuple(args...)) {} + + std::tuple getArgs() const { + return m_args; + } - // template - // class DispatchEvent : public Event { - // std::string m_selector; - // std::tuple m_args; + std::string getID() const { + return m_id; + } + }; - // public: - // DispatchEvent(std::string const& name, Args... args) : - // m_selector(name), m_args(std::make_tuple(args...)) {} + template + class DispatchFilter : public EventFilter> { + protected: + std::string m_id; - // std::string const& selector() { - // return m_selector; - // } - // }; + public: + using Ev = DispatchEvent; + using Callback = ListenerResult(Args...); - // template - // class DispatchHandler : public EventHandler> { - // std::string m_selector; - // utils::MiniFunction m_callback; + ListenerResult handle(utils::MiniFunction fn, Ev* event) { + if (event->getID() == m_id) { + return std::apply(fn, event->getArgs()); + } + return ListenerResult::Propagate; + } - // DispatchHandler(std::string const& name, utils::MiniFunction callback) : - // m_selector(name), m_callback(callback) {} - - // public: - // bool handle(DispatchEvent* ev) { - // if (ev->name() == m_selector) { - // std::apply(m_callback, ev->m_args); - // } - // return true; - // } - - // static DispatchHandler* create( - // std::string const& name, utils::MiniFunction callback - // ) { - // return new DispatchHandler(name, callback); - // } - // }; + DispatchFilter(std::string const& id) : m_id(id) {} + }; } \ No newline at end of file diff --git a/loader/src/cocos2d-ext/Layout.cpp b/loader/src/cocos2d-ext/Layout.cpp index efa61493..f0358121 100644 --- a/loader/src/cocos2d-ext/Layout.cpp +++ b/loader/src/cocos2d-ext/Layout.cpp @@ -50,7 +50,7 @@ bool CCNode::hasAncestor(CCNode* ancestor) { return false; } -CCArray* Layout::getNodesToPosition(CCNode* on) { +CCArray* Layout::getNodesToPosition(CCNode* on) const { auto arr = CCArray::create(); for (auto child : CCArrayExt(on->getChildren())) { if (!m_ignoreInvisibleChildren || child->isVisible()) { @@ -176,6 +176,32 @@ struct AxisLayout::Row : public CCObject { { this->autorelease(); } + + void accountSpacers(Axis axis, float availableLength) { + std::vector spacers; + for (auto& node : CCArrayExt(nodes)) { + if (auto spacer = typeinfo_cast(node)) { + spacers.push_back(spacer); + } + } + if (spacers.size()) { + auto unusedSpace = availableLength - this->axisLength; + size_t sum = 0; + for (auto& spacer : spacers) { + sum += spacer->getGrow(); + } + for (auto& spacer : spacers) { + auto size = unusedSpace * spacer->getGrow() / static_cast(sum); + if (axis == Axis::Row) { + spacer->setContentSize({ size, this->crossLength }); + } + else { + spacer->setContentSize({ this->crossLength, size }); + } + } + this->axisLength = availableLength; + } + } }; struct AxisPosition { @@ -195,6 +221,9 @@ static AxisPosition nodeAxis(CCNode* node, Axis axis, float scale) { if (auto toggle = typeinfo_cast(node)) { scaledSize = toggle->m_offButton->getScaledContentSize(); } + if (auto spacer = typeinfo_cast(node)) { + scaledSize = CCSizeZero; + } auto anchor = node->getAnchorPoint(); if (axis == Axis::Row) { return AxisPosition { @@ -611,6 +640,8 @@ void AxisLayout::tryFitLayout( float rowEvenSpace = available.crossLength / rows->count(); for (auto row : CCArrayExt(rows)) { + row->accountSpacers(m_axis, available.axisLength); + if (m_crossAlignment == AxisAlignment::Even) { rowCrossPos -= rowEvenSpace / 2 + row->crossLength / 2; } @@ -756,6 +787,24 @@ void AxisLayout::apply(CCNode* on) { ); } +CCSize AxisLayout::getSizeHint(CCNode* on) const { + // Ideal is single row / column with no scaling + auto nodes = getNodesToPosition(on); + float length = 0.f; + float cross = 0.f; + for (auto& node : CCArrayExt(nodes)) { + auto axis = nodeAxis(node, m_axis, 1.f); + length += axis.axisLength; + cross += axis.crossLength; + } + if (m_axis == Axis::Row) { + return { length, cross }; + } + else { + return { cross, length }; + } +} + AxisLayout::AxisLayout(Axis axis) : m_axis(axis) {} Axis AxisLayout::getAxis() const { @@ -969,3 +1018,30 @@ AxisLayoutOptions* AxisLayoutOptions::setScalePriority(int priority) { m_scalePriority = priority; return this; } + +bool SpacerNode::init(size_t grow) { + if (!CCNode::init()) + return false; + + m_grow = grow; + + return true; +} + +SpacerNode* SpacerNode::create(size_t grow) { + auto ret = new SpacerNode; + if (ret && ret->init(grow)) { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; +} + +void SpacerNode::setGrow(size_t grow) { + m_grow = grow; +} + +size_t SpacerNode::getGrow() const { + return m_grow; +} From ed8d230733927efc74683dace86272911a09caa9 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Tue, 4 Apr 2023 21:56:18 +0300 Subject: [PATCH 65/70] add EventFilter::getCallback --- VERSION | 2 +- loader/include/Geode/loader/Event.hpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e521dc4f..dd5d5f2f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0-beta.12 \ No newline at end of file +1.0.0-beta.13 \ No newline at end of file diff --git a/loader/include/Geode/loader/Event.hpp b/loader/include/Geode/loader/Event.hpp index ae9688b7..d8674cb6 100644 --- a/loader/include/Geode/loader/Event.hpp +++ b/loader/include/Geode/loader/Event.hpp @@ -124,6 +124,10 @@ namespace geode { return m_filter; } + utils::MiniFunction& getCallback() { + return m_callback; + } + protected: utils::MiniFunction m_callback = nullptr; T m_filter; From 530551ec9512a62a22081ee71230fc57ce26438e Mon Sep 17 00:00:00 2001 From: Fleeym <61891787+Fleeym@users.noreply.github.com> Date: Tue, 4 Apr 2023 09:42:57 +0300 Subject: [PATCH 66/70] add bindings and ids for CustomSongWidget --- bindings/GeometryDash.bro | 1 + loader/src/ids/CustomSongWidget.cpp | 40 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 loader/src/ids/CustomSongWidget.cpp diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index b925b16b..1e0ecfe5 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -939,6 +939,7 @@ class CustomSongLayer : FLAlertLayer, FLAlertLayerProtocol, TextInputDelegate, G } class CustomSongWidget : cocos2d::CCNode, MusicDownloadDelegate, FLAlertLayerProtocol { + bool init(SongInfoObject*, LevelSettingsObject*, bool, bool, bool, bool, bool hideBackground) = mac 0x37be20, win 0x685b0; void FLAlert_Clicked(FLAlertLayer*, bool) {} void loadSongInfoFinished(SongInfoObject*) {} diff --git a/loader/src/ids/CustomSongWidget.cpp b/loader/src/ids/CustomSongWidget.cpp new file mode 100644 index 00000000..1917cf3d --- /dev/null +++ b/loader/src/ids/CustomSongWidget.cpp @@ -0,0 +1,40 @@ +#include "AddIDs.hpp" + +#include +#include +#include + +using namespace geode::prelude; + +$register_ids(CustomSongWidget) { + setIDSafe(this, 0, "bg"); + setIDSafe(this, 0, "loading-bar"); + setIDSafe(this, 0, "song-name-label"); + setIDSafe(this, 1, "author-name-label"); + setIDSafe(this, 2, "id-and-size-label"); + setIDSafe(this, 3, "error-label"); + setIDSafe(this, 0, "buttons-menu"); + auto customSongWidgetMenu = this->getChildByID("buttons-menu"); + setIDSafe(customSongWidgetMenu, 0, "download-button"); + setIDSafe(customSongWidgetMenu, 1, "cancel-button"); + setIDSafe(customSongWidgetMenu, 2, "use-button"); + setIDSafe(customSongWidgetMenu, 3, "refresh-button"); + setIDSafe(customSongWidgetMenu, 4, "play-song-button"); + setIDSafe(customSongWidgetMenu, 5, "more-button"); +}; + +struct CustomSongWidgetIDs : Modify { + static void onModify(auto& self) { + if (!self.setHookPriority("CustomSongWidget::init", GEODE_ID_PRIORITY)) { + log::warn("Failed to set CustomSongWidget::init hook priority, node IDs may not work properly"); + } + } + + bool init(SongInfoObject* s, LevelSettingsObject* l, bool b1, bool b2, bool b3, bool b4, bool hideBackground) { + if (!CustomSongWidget::init(s, l, b1, b2, b3, b4, hideBackground)) return false; + + NodeIDs::get()->provide(this); + + return true; + } +}; \ No newline at end of file From 993cd6fd7ed1d028e31d7a9d157d726b0d6a0848 Mon Sep 17 00:00:00 2001 From: hjfod Date: Wed, 5 Apr 2023 18:17:53 +0300 Subject: [PATCH 67/70] rework event listeners to add different queues for listeners --- loader/include/Geode/loader/Event.hpp | 64 +++++++++++----- loader/src/loader/Event.cpp | 102 ++++++++++++++++---------- 2 files changed, 109 insertions(+), 57 deletions(-) diff --git a/loader/include/Geode/loader/Event.hpp b/loader/include/Geode/loader/Event.hpp index d8674cb6..22702e0b 100644 --- a/loader/include/Geode/loader/Event.hpp +++ b/loader/include/Geode/loader/Event.hpp @@ -10,6 +10,7 @@ namespace geode { class Mod; class Event; + class EventListenerProtocol; Mod* getMod(); @@ -18,10 +19,40 @@ namespace geode { Stop }; + struct GEODE_DLL EventListenerPool { + virtual bool add(EventListenerProtocol* listener) = 0; + virtual void remove(EventListenerProtocol* listener) = 0; + virtual void handle(Event* event) = 0; + virtual ~EventListenerPool() = default; + + EventListenerPool() = default; + EventListenerPool(EventListenerPool const&) = delete; + EventListenerPool(EventListenerPool&&) = delete; + + static EventListenerPool* getDefault(); + }; + + class GEODE_DLL DefaultEventListenerPool : public EventListenerPool { + protected: + std::atomic_size_t m_locked = 0; + std::vector m_listeners; + std::unordered_set m_toAdd; + std::unordered_set m_toRemove; + + public: + bool add(EventListenerProtocol* listener) override; + void remove(EventListenerProtocol* listener) override; + void handle(Event* event) override; + + static DefaultEventListenerPool* get(); + }; + struct GEODE_DLL EventListenerProtocol { - virtual void enable(); - virtual void disable(); - virtual ListenerResult passThrough(Event*) = 0; + bool enable(); + void disable(); + + virtual EventListenerPool* getPool() const; + virtual ListenerResult handle(Event*) = 0; virtual ~EventListenerProtocol(); }; @@ -45,6 +76,10 @@ namespace geode { ListenerResult handle(utils::MiniFunction fn, T* e) { return fn(e); } + + EventListenerPool* getPool() const { + return EventListenerPool::getDefault(); + } }; template @@ -61,9 +96,8 @@ namespace geode { requires std::is_class_v using MemberFn = typename to_member::value; - ListenerResult passThrough(Event* e) override { + ListenerResult handle(Event* e) override { if (m_callback) { - // it is so silly to use dynamic cast in an interbinary context if (auto myev = cast::typeinfo_cast(e)) { return m_filter.handle(m_callback, myev); } @@ -71,6 +105,10 @@ namespace geode { return ListenerResult::Propagate; } + EventListenerPool* getPool() const override { + return m_filter.getPool(); + } + EventListener(T filter = T()) { this->enable(); } @@ -137,7 +175,8 @@ namespace geode { private: friend EventListenerProtocol; - static std::unordered_set& removedListeners(); + protected: + virtual EventListenerPool* getPool() const; public: Mod* sender; @@ -149,18 +188,5 @@ namespace geode { } virtual ~Event(); - - /** - * Get all active event listeners. You may use this to sort listeners - * that have an explicit order. You should never add/remove listeners - * manually however - use the enable() and disable() functions for that - * @warning Do not add/remove listeners manually - */ - static std::vector& listeners(); - /** - * Move an event listener to the front of the queue so it is always hit - * first - */ - static void prioritize(EventListenerProtocol* listener); }; } diff --git a/loader/src/loader/Event.cpp b/loader/src/loader/Event.cpp index 52410c5b..6f7238e4 100644 --- a/loader/src/loader/Event.cpp +++ b/loader/src/loader/Event.cpp @@ -1,17 +1,71 @@ #include #include +#include using namespace geode::prelude; -void EventListenerProtocol::enable() { - if (!ranges::contains(Event::listeners(), this)) { - Event::listeners().push_back(this); +bool DefaultEventListenerPool::add(EventListenerProtocol* listener) { + if (m_locked) { + m_toAdd.insert(listener); + } + else { + m_listeners.push_back(listener); + } + return true; +} + +void DefaultEventListenerPool::remove(EventListenerProtocol* listener) { + if (m_locked) { + m_toRemove.insert(listener); + } + else { + ranges::remove(m_listeners, listener); } } +void DefaultEventListenerPool::handle(Event* event) { + m_locked += 1; + for (auto h : m_listeners) { + // if an event listener gets destroyed in the middle of this loop, we + // need to handle that + if (m_toRemove.contains(h)) continue; + if (h->handle(event) == ListenerResult::Stop) { + break; + } + } + m_locked -= 1; + // only clear listeners once nothing is iterating (if there are recursive handle calls) + if (m_locked == 0) { + for (auto listener : m_toAdd) { + m_listeners.push_back(listener); + } + for (auto listener : m_toRemove) { + ranges::remove(m_listeners, listener); + } + m_toAdd.clear(); + m_toRemove.clear(); + } +} + +DefaultEventListenerPool* DefaultEventListenerPool::get() { + static auto inst = new DefaultEventListenerPool(); + return inst; +} + +EventListenerPool* EventListenerPool::getDefault() { + return DefaultEventListenerPool::get(); +} + +EventListenerPool* EventListenerProtocol::getPool() const { + return EventListenerPool::getDefault(); +} + +bool EventListenerProtocol::enable() { + return this->getPool()->add(this); +} + void EventListenerProtocol::disable() { - Event::removedListeners().insert(this); - ranges::remove(Event::listeners(), this); + this->getPool()->remove(this); } EventListenerProtocol::~EventListenerProtocol() { @@ -20,39 +74,11 @@ EventListenerProtocol::~EventListenerProtocol() { Event::~Event() {} +EventListenerPool* Event::getPool() const { + return EventListenerPool::getDefault(); +} + void Event::postFrom(Mod* m) { if (m) this->sender = m; - auto& listeners = Event::listeners(); - listeners.erase(std::remove_if( - listeners.begin(), - listeners.end(), - [](auto& a) { - return Event::removedListeners().contains(a); - } - ), listeners.end()); - Event::removedListeners().clear(); - - std::vector listeners_copy = Event::listeners(); - for (auto h : listeners_copy) { - // if an event listener gets destroyed in the middle of this loop, we - // need to handle that - if (Event::removedListeners().count(h)) continue; - if (h->passThrough(this) == ListenerResult::Stop) { - break; - } - } -} - -std::unordered_set& Event::removedListeners() { - static std::unordered_set listeners; - return listeners; -} - -std::vector& Event::listeners() { - static std::vector listeners; - return listeners; -} - -void Event::prioritize(EventListenerProtocol* listener) { - ranges::move(Event::listeners(), listener, 0); + this->getPool()->handle(this); } From 6ba91482a6b1352a1c6555f458745197c0c6dbbd Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Wed, 5 Apr 2023 18:59:25 +0300 Subject: [PATCH 68/70] fix event listeners not being removed from the right queue --- loader/include/Geode/loader/Event.hpp | 13 +++---- loader/include/Geode/loader/Log.hpp | 1 + loader/src/loader/Event.cpp | 49 ++++++++++++++------------- 3 files changed, 34 insertions(+), 29 deletions(-) diff --git a/loader/include/Geode/loader/Event.hpp b/loader/include/Geode/loader/Event.hpp index 22702e0b..ad6aae75 100644 --- a/loader/include/Geode/loader/Event.hpp +++ b/loader/include/Geode/loader/Event.hpp @@ -28,16 +28,13 @@ namespace geode { EventListenerPool() = default; EventListenerPool(EventListenerPool const&) = delete; EventListenerPool(EventListenerPool&&) = delete; - - static EventListenerPool* getDefault(); }; class GEODE_DLL DefaultEventListenerPool : public EventListenerPool { protected: std::atomic_size_t m_locked = 0; std::vector m_listeners; - std::unordered_set m_toAdd; - std::unordered_set m_toRemove; + std::vector m_toAdd; public: bool add(EventListenerProtocol* listener) override; @@ -47,7 +44,11 @@ namespace geode { static DefaultEventListenerPool* get(); }; - struct GEODE_DLL EventListenerProtocol { + class GEODE_DLL EventListenerProtocol { + private: + EventListenerPool* m_pool = nullptr; + + public: bool enable(); void disable(); @@ -78,7 +79,7 @@ namespace geode { } EventListenerPool* getPool() const { - return EventListenerPool::getDefault(); + return DefaultEventListenerPool::get(); } }; diff --git a/loader/include/Geode/loader/Log.hpp b/loader/include/Geode/loader/Log.hpp index 73f23fa7..7eafaaf9 100644 --- a/loader/include/Geode/loader/Log.hpp +++ b/loader/include/Geode/loader/Log.hpp @@ -1,6 +1,7 @@ #pragma once #include "Types.hpp" +#include "../utils/Result.hpp" #include #include diff --git a/loader/src/loader/Event.cpp b/loader/src/loader/Event.cpp index 6f7238e4..15e3f161 100644 --- a/loader/src/loader/Event.cpp +++ b/loader/src/loader/Event.cpp @@ -6,7 +6,7 @@ using namespace geode::prelude; bool DefaultEventListenerPool::add(EventListenerProtocol* listener) { if (m_locked) { - m_toAdd.insert(listener); + m_toAdd.push_back(listener); } else { m_listeners.push_back(listener); @@ -15,35 +15,31 @@ bool DefaultEventListenerPool::add(EventListenerProtocol* listener) { } void DefaultEventListenerPool::remove(EventListenerProtocol* listener) { - if (m_locked) { - m_toRemove.insert(listener); - } - else { - ranges::remove(m_listeners, listener); + for (size_t i = 0; i < m_listeners.size(); i++) { + if (m_listeners[i] == listener) { + m_listeners[i] = nullptr; + } } } void DefaultEventListenerPool::handle(Event* event) { m_locked += 1; for (auto h : m_listeners) { - // if an event listener gets destroyed in the middle of this loop, we - // need to handle that - if (m_toRemove.contains(h)) continue; - if (h->handle(event) == ListenerResult::Stop) { + // if an event listener gets destroyed in the middle of this loop, it + // gets set to null + if (h && h->handle(event) == ListenerResult::Stop) { break; } } m_locked -= 1; - // only clear listeners once nothing is iterating (if there are recursive handle calls) + // only mutate listeners once nothing is iterating + // (if there are recursive handle calls) if (m_locked == 0) { + ranges::remove(m_listeners, nullptr); for (auto listener : m_toAdd) { m_listeners.push_back(listener); } - for (auto listener : m_toRemove) { - ranges::remove(m_listeners, listener); - } m_toAdd.clear(); - m_toRemove.clear(); } } @@ -52,20 +48,27 @@ DefaultEventListenerPool* DefaultEventListenerPool::get() { return inst; } -EventListenerPool* EventListenerPool::getDefault() { +EventListenerPool* EventListenerProtocol::getPool() const { return DefaultEventListenerPool::get(); } -EventListenerPool* EventListenerProtocol::getPool() const { - return EventListenerPool::getDefault(); -} - bool EventListenerProtocol::enable() { - return this->getPool()->add(this); + // virtual calls from destructors always call the base class so we gotta + // store the subclass' pool in a member to be able to access it in disable + // this is actually better because now regardless of what getPool() does + // we can always be assured that whatever pool it returns this listener + // will be removed from that pool and can't be in multiple pools at once + if (m_pool || !(m_pool = this->getPool())) { + return false; + } + return m_pool->add(this); } void EventListenerProtocol::disable() { - this->getPool()->remove(this); + if (m_pool) { + m_pool->remove(this); + m_pool = nullptr; + } } EventListenerProtocol::~EventListenerProtocol() { @@ -75,7 +78,7 @@ EventListenerProtocol::~EventListenerProtocol() { Event::~Event() {} EventListenerPool* Event::getPool() const { - return EventListenerPool::getDefault(); + return DefaultEventListenerPool::get(); } void Event::postFrom(Mod* m) { From 3dd6d55b49834840a11ce9d6c194536261fe9656 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Wed, 5 Apr 2023 19:26:46 +0300 Subject: [PATCH 69/70] add CCNode::getEventListenerCount --- loader/include/Geode/cocos/base_nodes/CCNode.h | 1 + loader/src/hooks/GeodeNodeMetadata.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index fc69fee3..51817e3c 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -1028,6 +1028,7 @@ public: GEODE_DLL void removeEventListener(geode::EventListenerProtocol* listener); GEODE_DLL void removeEventListener(std::string const& id); GEODE_DLL geode::EventListenerProtocol* getEventListener(std::string const& id); + GEODE_DLL size_t getEventListenerCount(); /// @{ /// @name Shader Program diff --git a/loader/src/hooks/GeodeNodeMetadata.cpp b/loader/src/hooks/GeodeNodeMetadata.cpp index 0e97ef2d..3daa411b 100644 --- a/loader/src/hooks/GeodeNodeMetadata.cpp +++ b/loader/src/hooks/GeodeNodeMetadata.cpp @@ -233,4 +233,9 @@ EventListenerProtocol* CCNode::getEventListener(std::string const& id) { return nullptr; } +size_t CCNode::getEventListenerCount() { + return GeodeNodeMetadata::set(this)->m_idEventListeners.size() + + GeodeNodeMetadata::set(this)->m_eventListeners.size(); +} + #pragma warning(pop) From 5924901d2d728e03591e685f33b69458ff8d8d1e Mon Sep 17 00:00:00 2001 From: alk <45172705+altalk23@users.noreply.github.com> Date: Wed, 5 Apr 2023 21:01:32 +0300 Subject: [PATCH 70/70] Make SentAsyncWebRequest dllexported --- loader/include/Geode/utils/web.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/include/Geode/utils/web.hpp b/loader/include/Geode/utils/web.hpp index 286142ae..4bf2d140 100644 --- a/loader/include/Geode/utils/web.hpp +++ b/loader/include/Geode/utils/web.hpp @@ -65,7 +65,7 @@ namespace geode::utils::web { * A handle to an in-progress sent asynchronous web request. Use this to * cancel the request / query information about it */ - class SentAsyncWebRequest { + class GEODE_DLL SentAsyncWebRequest { private: class Impl; std::shared_ptr m_impl;