From 794dded30f95b242426e841d7a7204ea46954af1 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Fri, 18 Aug 2023 11:04:53 +0300 Subject: [PATCH 01/26] Revert "replace macos entry with objc hook" --- loader/src/platform/mac/main.mm | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/loader/src/platform/mac/main.mm b/loader/src/platform/mac/main.mm index 770dbd21..ec92b1cd 100644 --- a/loader/src/platform/mac/main.mm +++ b/loader/src/platform/mac/main.mm @@ -14,7 +14,6 @@ #include "../../loader/LoaderImpl.hpp" #include #include -#include using namespace geode::prelude; @@ -112,26 +111,38 @@ void updateGeode() { extern "C" void fake() {} -static IMP s_applicationDidFinishLaunching; -void applicationDidFinishLaunching(id self, SEL sel, NSNotification* notification) { +void applicationDidFinishLaunchingHook(void* self, SEL sel, NSNotification* notification) { updateGeode(); + std::array patchBytes = { + 0x55, + 0x48, 0x89, 0xe5, + 0x41, 0x57 + }; + + auto res = tulip::hook::writeMemory((void*)(base::get() + 0x69a0), patchBytes.data(), 6); + if (!res) + return; + int exitCode = geodeEntry(nullptr); if (exitCode != 0) return; - - using Type = decltype(&applicationDidFinishLaunching); - return reinterpret_cast(s_applicationDidFinishLaunching)(self, sel, notification); + + return reinterpret_cast(geode::base::get() + 0x69a0)(self, sel, notification); } bool loadGeode() { - Class class_ = objc_getClass("AppController"); - SEL selector = @selector(applicationDidFinishLaunching:); - IMP function = (IMP)applicationDidFinishLaunching; - using Type = decltype(&applicationDidFinishLaunching); + auto detourAddr = reinterpret_cast(&applicationDidFinishLaunchingHook) - geode::base::get() - 0x69a5; + auto detourAddrPtr = reinterpret_cast(&detourAddr); - s_applicationDidFinishLaunching = class_replaceMethod(class_, selector, function, @encode(Type)); + std::array patchBytes = { + 0xe9, detourAddrPtr[0], detourAddrPtr[1], detourAddrPtr[2], detourAddrPtr[3] + }; + + auto res = tulip::hook::writeMemory((void*)(base::get() + 0x69a0), patchBytes.data(), 5); + if (!res) + return false; return true; } From 919276977c74197951e6ca56c06136879d4fbb61 Mon Sep 17 00:00:00 2001 From: ConfiG Date: Fri, 18 Aug 2023 02:31:16 +0300 Subject: [PATCH 02/26] improve install confirmation popup --- loader/src/ui/internal/info/ModInfoPopup.cpp | 95 ++++++++++++++------ 1 file changed, 68 insertions(+), 27 deletions(-) diff --git a/loader/src/ui/internal/info/ModInfoPopup.cpp b/loader/src/ui/internal/info/ModInfoPopup.cpp index 3b30236d..4173072d 100644 --- a/loader/src/ui/internal/info/ModInfoPopup.cpp +++ b/loader/src/ui/internal/info/ModInfoPopup.cpp @@ -750,34 +750,75 @@ void IndexItemInfoPopup::onInstallProgress(ModInstallEvent* event) { } void IndexItemInfoPopup::onInstall(CCObject*) { - createQuickPopup( - "Confirm Install", - "Installing this mod requires a few other mods to be installed. " - "Would you like to continue with recommended settings or " - "customize which mods to install?", - "Customize", "Recommended", 320.f, - [&](FLAlertLayer*, bool btn2) { - if (btn2) { - auto canInstall = Index::get()->canInstall(m_item); - if (!canInstall) { - FLAlertLayer::create( - "Unable to Install", - canInstall.unwrapErr(), - "OK" - )->show(); - return; - } + auto deps = m_item->getMetadata().getDependencies(); + enum class DepState { + None, + HasOnlyRequired, + HasOptional + } depState = DepState::None; + for (auto const& item : deps) { + // resolved means it's already installed, so + // no need to ask the user whether they want to install it + if (Loader::get()->isModLoaded(item.id)) + continue; + if (item.importance != ModMetadata::Dependency::Importance::Required) { + depState = DepState::HasOptional; + break; + } + depState = DepState::HasOnlyRequired; + } + + std::string content; + char const* btn1; + char const* btn2; + switch (depState) { + case DepState::None: + content = fmt::format( + "Are you sure you want to install {}?", + m_item->getMetadata().getName() + ); + btn1 = "Info"; + btn2 = "Install"; + break; + case DepState::HasOnlyRequired: + content = + "Installing this mod requires other mods to be installed. " + "Would you like to proceed with the installation or " + "view which mods are going to be installed?"; + btn1 = "View"; + btn2 = "Proceed"; + break; + case DepState::HasOptional: + content = + "This mod recommends installing other mods alongside it. " + "Would you like to continue with recommended settings or " + "customize which mods to install?"; + btn1 = "Customize"; + btn2 = "Recommended"; + break; + } + + createQuickPopup("Confirm Install", content, btn1, btn2, 320.f, [&](FLAlertLayer*, bool btn2) { + if (btn2) { + auto canInstall = Index::get()->canInstall(m_item); + if (!canInstall) { + FLAlertLayer::create( + "Unable to Install", + canInstall.unwrapErr(), + "OK" + )->show(); + return; + } + this->preInstall(); + Index::get()->install(m_item); + } + else { + InstallListPopup::create(m_item, [&](IndexInstallList const& list) { this->preInstall(); - Index::get()->install(m_item); - } - else { - InstallListPopup::create(m_item, [&](IndexInstallList const& list) { - this->preInstall(); - Index::get()->install(list); - })->show(); - } - }, true, true - ); + Index::get()->install(list); + })->show(); + } + }, true, true); } void IndexItemInfoPopup::preInstall() { From ef1f1d15c6ed9746e958db5102f5fd58d82b5a3b Mon Sep 17 00:00:00 2001 From: ConfiG Date: Fri, 18 Aug 2023 22:52:48 +0300 Subject: [PATCH 03/26] fix search buttons not clickable over view buttons --- loader/src/ui/internal/list/ModListLayer.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/loader/src/ui/internal/list/ModListLayer.cpp b/loader/src/ui/internal/list/ModListLayer.cpp index 34478314..3ff3b930 100644 --- a/loader/src/ui/internal/list/ModListLayer.cpp +++ b/loader/src/ui/internal/list/ModListLayer.cpp @@ -428,6 +428,9 @@ void ModListLayer::createSearchControl() { inputBG->setScale(.5f); m_searchBG->addChild(inputBG); + if (m_searchInput) + return; + m_searchInput = CCTextInputNode::create(310.f - buttonSpace, 20.f, "Search Mods...", "bigFont.fnt"); m_searchInput->setLabelPlaceholderColor({ 150, 150, 150 }); @@ -457,10 +460,7 @@ void ModListLayer::reloadList(std::optional const& query) { std::nullopt; // remove old list - if (m_list) { - if (m_searchBG) m_searchBG->retain(); - m_list->removeFromParent(); - } + if (m_list) m_list->removeFromParent(); auto items = this->createModCells(g_tab, m_query); @@ -522,13 +522,7 @@ void ModListLayer::reloadList(std::optional const& query) { m_tabsGradientSprite->setPosition(m_list->getPosition() + CCPoint{179.f, 235.f}); // add search input to list - if (!m_searchInput) { - this->createSearchControl(); - } - else { - m_list->addChild(m_searchBG); - m_searchBG->release(); - } + this->createSearchControl(); // enable filter button m_filterBtn->setEnabled(g_tab != ModListType::Installed); From 108f56aa6220f6c48b9b2555bb25b4a1e07f7e91 Mon Sep 17 00:00:00 2001 From: ConfiG Date: Sat, 19 Aug 2023 00:11:17 +0300 Subject: [PATCH 04/26] improve tab textures --- .../blanks/baseTab_Normal_Selected.png | Bin 8706 -> 8838 bytes .../blanks/baseTab_Normal_Unselected.png | Bin 25844 -> 9304 bytes .../blanks/baseTab_Normal_UnselectedDark.png | Bin 30623 -> 9409 bytes loader/resources/images/tab-gradient-mask.png | Bin 6449 -> 5884 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/loader/resources/blanks/baseTab_Normal_Selected.png b/loader/resources/blanks/baseTab_Normal_Selected.png index b5363c29cbbe95890a37c07b20ceef5da9e2fb25..49e452554ac1fa8ca67e1d39f8081ea5ecbd9443 100644 GIT binary patch delta 5413 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 EKj^M9GXMYp delta 5321 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 literal 25844 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 XGpZQ0m9M*Q7f0(F>6B`nzx2NVtRDDD literal 30623 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�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 delta 3056 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 adv8`s Date: Sat, 19 Aug 2023 00:12:56 +0300 Subject: [PATCH 05/26] update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 553a0704..799109de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Geode Changelog +## v1.1.1 + * Improve installation confirmation popup (3ec44cf) + * Remove unnecessary main thread queues for mod events (38cc38c) + * Fix search and filter buttons being not clickable when over the view/restart button of a mod (e616336) + * Improve tab textures (00d30de) + * Properly align the borders + * Make the selected and unselected tabs the same height + ## v1.1.0 * Fix json library not actually being dynamically exported/imported (5f65d97) * Update TulipHook, gets rid of keystone dependency and adds stdcall support (efcbf58, 7b90903) From fa7f486c5cea91ac7494f4a767280416753c99cc Mon Sep 17 00:00:00 2001 From: ConfiG Date: Sat, 19 Aug 2023 00:14:36 +0300 Subject: [PATCH 06/26] fix updated changelog --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 799109de..4d27369f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,10 @@ # Geode Changelog ## v1.1.1 - * Improve installation confirmation popup (3ec44cf) + * Improve installation confirmation popup (9192769) * Remove unnecessary main thread queues for mod events (38cc38c) - * Fix search and filter buttons being not clickable when over the view/restart button of a mod (e616336) - * Improve tab textures (00d30de) + * Fix search and filter buttons being not clickable when over the view/restart button of a mod (ef1f1d1) + * Improve tab textures (108f56a) * Properly align the borders * Make the selected and unselected tabs the same height From dfc75c8940feae26e250cf204ee91ad27ad798ca Mon Sep 17 00:00:00 2001 From: Cvolton Date: Fri, 18 Aug 2023 23:18:36 +0200 Subject: [PATCH 07/26] fix normal percentage showing up as negative (#211) --- bindings/GeometryDash.bro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index ce03576c..c8481280 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -2330,7 +2330,7 @@ class GJGameLevel : cocos2d::CCNode { int m_chk; bool m_isChkValid; bool m_isCompletionLegitimate; - geode::SeedValueVRS m_normalPercent; + geode::SeedValueVSR m_normalPercent; geode::SeedValueRSV m_orbCompletion; geode::SeedValueRSV m_newNormalPercent2; int m_practicePercent; From a54e23606c5530f1df11ff188d97c80125e7a03f Mon Sep 17 00:00:00 2001 From: Cvolton Date: Sat, 19 Aug 2023 00:06:47 +0200 Subject: [PATCH 08/26] add LevelCell and GJScoreCell constructors to bindings --- bindings/GeometryDash.bro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index c8481280..b8b5d930 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -2597,6 +2597,7 @@ class GJScoreCell : TableViewCell { void loadFromScore(GJUserScore* score) = win 0x61440; void onViewProfile(cocos2d::CCObject* sender) = win 0x62380; void updateBGColor(int index) = win 0x5c6b0; + GJScoreCell(char const* key, float width, float height) = win 0x613C0; } class GJSearchObject : cocos2d::CCNode { @@ -3761,6 +3762,7 @@ class LevelCell : TableViewCell { void loadCustomLevelCell() = mac 0x1183b0, win 0x5a020; void updateBGColor(int index) = win 0x5c6b0; void loadFromLevel(GJGameLevel* level) = win 0x59FD0; + LevelCell(char const* key, float width, float height) = win 0x59F40; } class LevelCommentDelegate { From 69a575b84bf30fd3888939f8823a7fe542b66c37 Mon Sep 17 00:00:00 2001 From: camila314 Date: Mon, 21 Aug 2023 11:51:16 -0500 Subject: [PATCH 09/26] fix some headers --- bindings/Cocos2d.bro | 8 ++++++++ bindings/GeometryDash.bro | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 67e8c369..6dd4de12 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -7,6 +7,14 @@ class cocos2d::CCActionTween { [[link(win)]] class cocos2d::CCActionManager { + CCActionManager() { + m_pTargets = nullptr; + m_pCurrentTarget = nullptr; + m_bCurrentTargetSalvaged = false; + } + ~CCActionManager() {} + + virtual auto update(float) = mac 0x10c9a0; auto addAction(cocos2d::CCAction*, cocos2d::CCNode*, bool) = mac 0x10bed0; auto pauseTarget(cocos2d::CCObject*) = mac 0x10bc50; auto resumeTargets(cocos2d::CCSet*) = mac 0x10be80; diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index ce03576c..94258cee 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -4909,12 +4909,12 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate { void saveToCheckpoint(PlayerCheckpoint*) = mac 0x22e2f0, win 0x1f9ee0; void setSecondColor(cocos2d::_ccColor3B const&) = mac 0x219610, win 0x1f7870; void setupStreak() = mac 0x218720, win 0x1e7e90; - void spawnCircle() = mac 0x225480; + void spawnCircle() = mac 0x2251b0; void spawnCircle2() = mac 0x2252a0; void spawnDualCircle() = mac 0x2255c0; void spawnFromPlayer(PlayerObject*) = mac 0x22dde0, win 0x1f9540; void spawnPortalCircle(cocos2d::_ccColor3B, float) = mac 0x225350, win 0x1ef680; - void spawnScaleCircle() = mac 0x2251b0, win 0x1ef810; + void spawnScaleCircle() = mac 0x225480, win 0x1ef810; void specialGroundHit() = mac 0x22dbf0; void speedDown() = mac 0x22e970; void speedUp() = mac 0x22e950; From 0161c9571f159238119c6b31da01346502f5f76e Mon Sep 17 00:00:00 2001 From: mat <26722564+matcool@users.noreply.github.com> Date: Mon, 21 Aug 2023 19:25:27 -0300 Subject: [PATCH 10/26] Update CCActionManager.h --- loader/include/Geode/cocos/actions/CCActionManager.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/include/Geode/cocos/actions/CCActionManager.h b/loader/include/Geode/cocos/actions/CCActionManager.h index a385c1a1..a1dab8bc 100644 --- a/loader/include/Geode/cocos/actions/CCActionManager.h +++ b/loader/include/Geode/cocos/actions/CCActionManager.h @@ -68,6 +68,8 @@ public: */ ~CCActionManager(void); + GEODE_CUSTOM_CONSTRUCTOR_COCOS(CCActionManager, CCObject); + // actions /** Adds an action with a target. From c4e7ebf3c0c39bb85588771da8473f9085068770 Mon Sep 17 00:00:00 2001 From: mat <26722564+matcool@users.noreply.github.com> Date: Mon, 21 Aug 2023 19:31:06 -0300 Subject: [PATCH 11/26] include pdb in build artifact --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f91c5f45..bb577d19 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -143,7 +143,7 @@ jobs: - name: Zip Windows Artifacts uses: vimtor/action-zip@v1.1 with: - files: geode-win/XInput9_1_0.dll geode-win/Geode.dll geode-win/GeodeUpdater.exe geode-win/Geode.lib + files: geode-win/XInput9_1_0.dll geode-win/Geode.dll geode-win/GeodeUpdater.exe geode-win/Geode.lib geode-win/Geode.pdb dest: geode-${{ steps.ref.outputs.hash }}-win.zip # TODO change in 2.0.0 From dd167972c7621d33596dcd2da6faaa8ee5ac978c Mon Sep 17 00:00:00 2001 From: camila314 Date: Mon, 21 Aug 2023 22:20:20 -0500 Subject: [PATCH 12/26] fix for apple silicon --- loader/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index 27cd7ed8..4258f77a 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -250,7 +250,7 @@ if (APPLE) add_subdirectory(launcher/mac) - if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm" OR GEODE_TARGET_PLATFORM STREQUAL "iOS") + if(GEODE_TARGET_PLATFORM STREQUAL "iOS") add_custom_command(TARGET geode-loader POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -id \"/Library/MobileSubstrate/DynamicLibraries/Geode.dylib\" From a7e2ece0ca6e60fb76d3737f49d6cabbaad5aa59 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Tue, 22 Aug 2023 14:55:30 +0300 Subject: [PATCH 13/26] fix m_updateTimeMarkers --- bindings/GeometryDash.bro | 3 ++- loader/test/members/MacOS.cpp | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index ce03576c..91e489e1 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -1447,8 +1447,9 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ PAD = mac 0x2, win 0x2, android 0x2; bool m_freeMoveEnabled; bool m_unkSwipeRelated; - PAD = mac 0xa, win 0xa, android 0x9; + PAD = mac 0x2, win 0x2, android 0x2; bool m_updateTimeMarkers; + PAD = mac 0x8, win 0x8, android 0x2; cocos2d::CCArray* m_unknownArray2; PAD = mac 0x8, win 0x8, android 0x8; cocos2d::CCArray* m_selectedObjects; diff --git a/loader/test/members/MacOS.cpp b/loader/test/members/MacOS.cpp index 483c2d9f..befcbe6d 100644 --- a/loader/test/members/MacOS.cpp +++ b/loader/test/members/MacOS.cpp @@ -11,6 +11,10 @@ GEODE_MEMBER_CHECK(PlayerObject, m_playerColor1, 0x7c2); // EditorUI GEODE_MEMBER_CHECK(EditorUI, m_buttonBar, 0x1a0); +GEODE_MEMBER_CHECK(EditorUI, m_scaleControl, 0x208); +GEODE_MEMBER_CHECK(EditorUI, m_swipeEnabled, 0x23c); +GEODE_MEMBER_CHECK(EditorUI, m_updateTimeMarkers, 0x244); +GEODE_MEMBER_CHECK(EditorUI, m_selectedObjects, 0x260); GEODE_MEMBER_CHECK(EditorUI, m_selectedObject, 0x440); // LevelEditorLayer From e639ff318253be146c234cd95bc36353ee118474 Mon Sep 17 00:00:00 2001 From: alk <45172705+altalk23@users.noreply.github.com> Date: Tue, 22 Aug 2023 16:09:43 +0300 Subject: [PATCH 14/26] Update crashlog.mm --- loader/src/platform/mac/crashlog.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loader/src/platform/mac/crashlog.mm b/loader/src/platform/mac/crashlog.mm index d717d337..dc5434dc 100644 --- a/loader/src/platform/mac/crashlog.mm +++ b/loader/src/platform/mac/crashlog.mm @@ -330,7 +330,7 @@ static void handlerThread() { auto text = crashlog::writeCrashlog(faultyMod, getInfo(signalAddress, faultyMod), getStacktrace(), getRegisters()); - log::error("Geode crashed!\n{}" + text); + log::error("Geode crashed!\n{}", text); s_signal = 0; s_cv.notify_all(); @@ -375,4 +375,4 @@ ghc::filesystem::path crashlog::getCrashLogDirectory() { } -#endif \ No newline at end of file +#endif From 2614aa2d982e3a5ba212c31004a3d58794970945 Mon Sep 17 00:00:00 2001 From: Cvolton Date: Tue, 22 Aug 2023 20:37:54 +0200 Subject: [PATCH 15/26] add bindings for robtop bot --- bindings/GeometryDash.bro | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 0b0bcfbd..bdfd87d4 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -1226,6 +1226,9 @@ class EditLevelLayer : cocos2d::CCLayer, FLAlertLayerProtocol, TextInputDelegate static EditLevelLayer* create(GJGameLevel* level) = mac 0xe1e50, win 0x6f530, ios 0x82420; bool init(GJGameLevel* level) = mac 0xe1fd0, win 0x6f5d0; void onLevelInfo(cocos2d::CCObject*) = mac 0xe4f60, win 0x70660; + void onPlay(cocos2d::CCObject*) = mac 0xe3ae0, win 0x71700; + void onEdit(cocos2d::CCObject*) = mac 0xe3970, win 0x71ac0; + void onShare(cocos2d::CCObject*) = mac 0xe3c60, win 0x71be0; cocos2d::CCMenu* m_buttonMenu; GJGameLevel* m_level; @@ -4739,7 +4742,7 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, CurrencyRewardDelegate, bool unk42C; bool m_isPlayer2Frozen; gd::string m_previousRecords; - double unknown6a8; + cocos2d::CCArray* m_replayInputs; double m_time; int unknown6b8; int unknown6bc; From d6710315c21b248f3cc8991aea987cd7699d0b33 Mon Sep 17 00:00:00 2001 From: mat <26722564+matcool@users.noreply.github.com> Date: Wed, 23 Aug 2023 12:48:12 -0300 Subject: [PATCH 16/26] fix macos test --- loader/test/members/MacOS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/test/members/MacOS.cpp b/loader/test/members/MacOS.cpp index befcbe6d..d81a3c96 100644 --- a/loader/test/members/MacOS.cpp +++ b/loader/test/members/MacOS.cpp @@ -25,7 +25,7 @@ GEODE_MEMBER_CHECK(LevelEditorLayer, m_level, 0x618); GEODE_MEMBER_CHECK(PlayLayer, unknown518, 0x518); GEODE_MEMBER_CHECK(PlayLayer, unknown5f4, 0x5f4); GEODE_MEMBER_CHECK(PlayLayer, unknown680, 0x680); -GEODE_MEMBER_CHECK(PlayLayer, unknown6a8, 0x6a8); +GEODE_MEMBER_CHECK(PlayLayer, m_replayInputs, 0x6a8); GEODE_MEMBER_CHECK(PlayLayer, m_level, 0x728); GEODE_MEMBER_CHECK(PlayLayer, m_shouldTryToKick, 0x7a8); From 248d5f6abaddf912abbeff2be4115f3af23b6d18 Mon Sep 17 00:00:00 2001 From: mat <26722564+matcool@users.noreply.github.com> Date: Wed, 23 Aug 2023 13:24:18 -0300 Subject: [PATCH 17/26] Update VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 524cb552..45a1b3f4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.1 +1.1.2 From d14382462fb1966550455505b456c31c49d5b74c Mon Sep 17 00:00:00 2001 From: MacCraker <74224026+MacCraker@users.noreply.github.com> Date: Mon, 21 Aug 2023 18:48:48 -0700 Subject: [PATCH 18/26] change separator length the first 2 separators containing one more "=" character than the rest wasn't being very kind to my ocd so I had to change it --- EULA | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/EULA b/EULA index 38992a42..a2c560f8 100644 --- a/EULA +++ b/EULA @@ -4,9 +4,9 @@ This is the End User License Agreement for the Geode Software. By using this Software, you agree to the terms of this EULA. -=========================================== +============================================ 1.0. Definitions -=========================================== +============================================ The Software is all of the source code within the Geode (geode-sdk) Organization on GitHub that when put in a funky little blender and mashed together form the compiled Geode libraries and runtime binaries along with any additional side dishes such as the documentation website. @@ -18,9 +18,9 @@ A Modder is someone who is using Geode and its functions in order to develope th Geometry Dash is a game by RobTop Games. If you're using Geode, you probably know what it is. If you're an actual laywer or something alike looking at this text document, why? How did we end up in this situation? Can you let us off the hook if we just give you some cute photos of catgirls? -=========================================== +============================================ 1.1. Your rights as an End User -=========================================== +============================================ You are not allowed to not do anything you want to without your own written permission. You are required to stop before every step of using this Software and ponder to yourself: "Is a car with a trailer driving on railway tracks a train?" Failing to do this will result in absolutely no punishments whatsoever. Not because it isn't wrong, but because we simply do not care. @@ -48,9 +48,9 @@ There are also things you are permitted to use this Software for. These include: Any act you might use this Software for that isn't explicitly listed in any of the above lists you must consult at least yourself to decide if it's okay to do. Do note that the Developers of this Software, i.e. The Core Geode Team, may, at any time, publicly announce other cases that you may / may not use this Software for, or exceptions to previous cases. In the case that that happens, you are required to - wow did I just use 'that' twice in a row? That's so cool - comply with whatever The Core Geode Team says. Unless it's Pie telling you not to use any libraries. Don't listen to Pie. -=========================================== +============================================ 1.2. Your rights as a Modder -=========================================== +============================================ This section mostly lists types of mods that you are allowed to and not allowed to make. Creating a mod that has features which are explicitly disallowed within this document will result in your mod being publicly shamed and humiliated. Be warned. @@ -76,23 +76,23 @@ You are not allowed to create mods that: Anything not listed in the above lists may be okay to make, or it may not. Consult The Core Geode Team in case you aren't sure if a given mod is okay to make. It is also advised to communicate and discuss with other modders in the Geometry Dash modding community about any mods you are planning on creating which you are unsure about. It might be that your mod does more harm than good. -=========================================== +============================================ 1.3 Our rights -=========================================== +============================================ We reserve the right to publicly shame and humiliate you for failing to understand our perfectly reasonable and unquestionable choices in the matters of design, code, public speaking, advertising, private speaking, behaviour, protected speaking, and anything else. Our rights are your lefts. Because we are standing menacingly in front of you. Metaphorically speaking. -=========================================== +============================================ 1.4 Software -=========================================== +============================================ I am tired of writing and I don't know what to write here. It's a mod loader and a modding SDK. You didn't download it not knowing what it is, did you? -=========================================== +============================================ 1.5 Too Long; Didn't Read -=========================================== +============================================ * Geode is a mod loader & modding SDK for the game Geometry Dash. From bdf11a29c25699bae5a96ff8b30150ee84c539fa Mon Sep 17 00:00:00 2001 From: ConfiG Date: Fri, 25 Aug 2023 19:51:36 +0300 Subject: [PATCH 19/26] move and rename windows uninstaller --- installer/windows/installer.nsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer/windows/installer.nsi b/installer/windows/installer.nsi index e9aca9be..f6392847 100644 --- a/installer/windows/installer.nsi +++ b/installer/windows/installer.nsi @@ -326,7 +326,7 @@ Section "Geode" File ${BINDIR}\GeodeUpdater.exe File ${BINDIR}\XInput9_1_0.dll - WriteUninstaller "geode\Uninstall.exe" + WriteUninstaller "GeodeUninstaller.exe" CreateDirectory $INSTDIR\geode\resources\geode.loader SetOutPath $INSTDIR\geode\resources\geode.loader From 28c1bddc8cbfe8d58cfa7d33381d7ca9289d88d3 Mon Sep 17 00:00:00 2001 From: ConfiG Date: Fri, 25 Aug 2023 20:05:58 +0300 Subject: [PATCH 20/26] keep data switch support for windows uninstaller --- installer/windows/installer.nsi | 167 +++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 2 deletions(-) diff --git a/installer/windows/installer.nsi b/installer/windows/installer.nsi index f6392847..0946cc0b 100644 --- a/installer/windows/installer.nsi +++ b/installer/windows/installer.nsi @@ -189,6 +189,132 @@ Exch $R0 !macroend + ; https://nsis.sourceforge.io/StrStr + Function un.StrStr + Exch $R0 + Exch + Exch $R1 + Push $R2 + Push $R3 + Push $R4 + Push $R5 + + StrLen $R2 $R0 + StrLen $R3 $R1 + + StrCpy $R4 0 + + loop: + StrCpy $R5 $R1 $R2 $R4 + StrCmp $R5 $R0 done + IntCmp $R4 $R3 done 0 done + IntOp $R4 $R4 + 1 + Goto loop + done: + StrCpy $R0 $R1 `` $R4 + + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Pop $R1 + Exch $R0 + FunctionEnd + + ; https://nsis.sourceforge.io/Get_command_line_parameters + Function un.GetParameters + Push $R0 + Push $R1 + Push $R2 + Push $R3 + + StrCpy $R2 1 + StrLen $R3 $CMDLINE + + StrCpy $R0 $CMDLINE $R2 + StrCmp $R0 '"' 0 +3 + StrCpy $R1 '"' + Goto loop + StrCpy $R1 " " + + loop: + IntOp $R2 $R2 + 1 + StrCpy $R0 $CMDLINE 1 $R2 + StrCmp $R0 $R1 get + StrCmp $R2 $R3 get + Goto loop + + get: + IntOp $R2 $R2 + 1 + StrCpy $R0 $CMDLINE 1 $R2 + StrCmp $R0 " " get + StrCpy $R0 $CMDLINE "" $R2 + + Pop $R3 + Pop $R2 + Pop $R1 + Exch $R0 + FunctionEnd + + ; https://nsis.sourceforge.io/Get_command_line_parameter_by_name + Function un.GetParameterValue + Exch $R0 + Exch + Exch $R1 + + Push $R2 + Push $R3 + Push $R4 + Push $R5 + + Strlen $R2 $R1+2 + + Call un.GetParameters + Pop $R3 + + StrCpy $R5 '"' + Push $R3 + Push '"/$R1=' + Call un.StrStr + Pop $R4 + StrCpy $R4 $R4 "" 1 + StrCmp $R4 "" "" next + + StrCpy $R5 ' ' + Push $R3 + Push '/$R1=' + Call un.StrStr + Pop $R4 + + next: + StrCmp $R4 "" check_for_switch + StrCpy $R0 $R4 "" $R2 + Push $R0 + Push $R5 + Call un.StrStr + Pop $R4 + StrCmp $R4 "" done + StrLen $R4 $R4 + StrCpy $R0 $R0 -$R4 + goto done + + check_for_switch: + Push $R3 + Push '/$R1' + Call un.StrStr + Pop $R4 + StrCmp $R4 "" done + StrCpy $R0 "" + + done: + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Pop $R1 + Exch $R0 + FunctionEnd + ; actual code !define BINDIR ..\..\bin\nightly @@ -357,10 +483,47 @@ Function un.onInit Abort FunctionEnd Section "Uninstall" + DeleteRegKey /ifempty HKCU "Software\Geode" Delete $INSTDIR\Geode.dll Delete $INSTDIR\Geode.pdb Delete $INSTDIR\GeodeUpdater.exe Delete $INSTDIR\XInput9_1_0.dll - RMdir /r $INSTDIR\geode - DeleteRegKey /ifempty HKCU "Software\Geode" + + # default value of DATA is an empty string + # if DATA is empty, keep user data + # otherwise, delete the entire geode and DATA\geode\mods dirs + # the reason we're deleting DATA\geode\mods instead of just passing + # that dir directly to DATA is so that in case someone (either accidentally or maliciously) + # passes the wrong directory, the uninstaller doesn't just blindly clear it + # it will also check for the presence of CCGameManager.dat and CCLocalLevels.dat in DATA + + Push "DATA" + Push "" + Call un.GetParameterValue + Pop $0 + StrCmp $0 "" keep_data remove_data + + keep_data: + # keep configs, mods, logs and crash logs + RMdir /r $INSTDIR\geode\index + RMdir /r $INSTDIR\geode\resources + RMdir /r $INSTDIR\geode\temp + RMdir /r $INSTDIR\geode\unzipped + RMdir /r $INSTDIR\geode\update + Return + + remove_data: + RMdir /r $INSTDIR\geode + IfFileExists $0\CCGameManager.dat 0 invalid + IfFileExists $0\CCLocalLevels.dat 0 invalid + RMdir /r $0\geode\mods ; delete DATA\geode\mods + RMdir $0\geode ; then delete DATA\geode non-recursively, assuming mods is the only directory in DATA\geode + Return + + invalid: + # this message doesnt rly need translatable as + # its only supposed to be used internally by geode itself + MessageBox MB_ICONSTOP|MB_OK "The path passed to DATA is not a valid Geometry Dash data folder!" + Abort + SectionEnd From 4cc9164b27af751f5cf2d04690b3517463e5c5de Mon Sep 17 00:00:00 2001 From: ConfiG Date: Fri, 25 Aug 2023 21:02:38 +0300 Subject: [PATCH 21/26] add components page to windows installer --- installer/windows/installer.nsi | 54 +++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/installer/windows/installer.nsi b/installer/windows/installer.nsi index 0946cc0b..c08331d2 100644 --- a/installer/windows/installer.nsi +++ b/installer/windows/installer.nsi @@ -26,6 +26,8 @@ ; pages !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "..\..\LICENSE.txt" + !define MUI_COMPONENTSPAGE_NODESC + !insertmacro MUI_PAGE_COMPONENTS !define MUI_PAGE_CUSTOMFUNCTION_SHOW DirectoryPageShow !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES @@ -374,16 +376,6 @@ Function FindGamePath Pop $0 FunctionEnd -Function .onInit - !insertmacro MUI_LANGDLL_DISPLAY - - Call FindGamePath - IfErrors 0 +3 - StrCpy $GamePath "" - Return - StrCpy $INSTDIR "$GamePath\" -FunctionEnd - Function DirectoryPageShow System::Call 'USER32::CreateWindowEx(i${__NSD_Label_EXSTYLE}, t"${__NSD_Label_CLASS}", t"", i${__NSD_Label_STYLE}, i0, i70, i400, i40, p$mui.DirectoryPage, p0, p0, p0)p.s' Pop $geode.DirectoryPage.ErrorText @@ -435,6 +427,25 @@ Function .onVerifyInstDir Return FunctionEnd +SectionGroup "Geode" + Section "Loader" LOADER_SECTION + SetOutPath $INSTDIR + + File ${BINDIR}\Geode.dll + File ${BINDIR}\Geode.pdb + File ${BINDIR}\GeodeUpdater.exe + File ${BINDIR}\XInput9_1_0.dll + + WriteUninstaller "GeodeUninstaller.exe" + SectionEnd + + Section "Resources" + CreateDirectory $INSTDIR\geode\resources\geode.loader + SetOutPath $INSTDIR\geode\resources\geode.loader + File /r ${BINDIR}\resources\* + SectionEnd +SectionGroupEnd + ; download vc redist in compile-time !execute "pwsh -nol -noni -nop dl-vcr.ps1" Section "Visual Studio Runtime" @@ -444,21 +455,18 @@ Section "Visual Studio Runtime" Delete "$INSTDIR\VC_redist.x86.exe" SectionEnd -Section "Geode" - SetOutPath $INSTDIR +Function .onInit + !insertmacro MUI_LANGDLL_DISPLAY - File ${BINDIR}\Geode.dll - File ${BINDIR}\Geode.pdb - File ${BINDIR}\GeodeUpdater.exe - File ${BINDIR}\XInput9_1_0.dll + IntOp $0 ${SF_SELECTED} | ${SF_RO} + SectionSetFlags ${LOADER_SECTION} $0 - WriteUninstaller "GeodeUninstaller.exe" - - CreateDirectory $INSTDIR\geode\resources\geode.loader - SetOutPath $INSTDIR\geode\resources\geode.loader - - File /r ${BINDIR}\resources\* -SectionEnd + Call FindGamePath + IfErrors 0 +3 + StrCpy $GamePath "" + Return + StrCpy $INSTDIR "$GamePath\" +FunctionEnd ; uninstaller From 17421fde41ba4cb04fb13ab6a72b85e6435da576 Mon Sep 17 00:00:00 2001 From: Cvolton Date: Fri, 25 Aug 2023 21:36:53 +0200 Subject: [PATCH 22/26] Add required bindings for cvolton.robtopbot Squashed commit of the following: commit c9f82ddc4c6cbd3f784c4d152b9445aa5c64c9f0 Author: Cvolton Date: Wed Aug 23 00:11:38 2023 +0200 add some missing functions to PlayLayer --- bindings/GeometryDash.bro | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index bdfd87d4..63858154 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -3998,7 +3998,12 @@ class LevelInfoLayer : cocos2d::CCLayer, LevelDownloadDelegate, LevelUpdateDeleg void onViewProfile(cocos2d::CCObject* sender) = mac 0x1617d0, win 0x17ac90; void onLevelInfo(cocos2d::CCObject* sender) = mac 0x163880, win 0x17acf0; void setupProgressBars() = win 0x177fc0; + void setupLevelInfo() = mac 0x161C80, win 0x178680; void downloadLevel() = win 0x177d90; + void onPlay(cocos2d::CCObject* sender) = mac 0x161840, win 0x179730; + virtual void levelDownloadFinished(GJGameLevel*) = mac 0x164C00, win 0x1790C0; + virtual void levelUpdateFinished(GJGameLevel*, UpdateResponse) = mac 0x164E60, win 0x1792B0; + void showUpdateAlert(UpdateResponse) = mac 0x164ED0, win 0x179300; PAD = win 0x4, mac 0x8; cocos2d::CCMenu* m_playBtnMenu; From b7da6c2f2bc78b83b3601aba3ba7a8395a868b09 Mon Sep 17 00:00:00 2001 From: Cvolton Date: Fri, 25 Aug 2023 21:37:39 +0200 Subject: [PATCH 23/26] Add required bindings for cvolton.betterinfo Squashed commit of the following: commit 3abd7446b94391ed5c6b6b69674bc822b39719fb Author: Cvolton Date: Fri Aug 25 20:25:48 2023 +0200 add levelbrowserlayer oninfo commit 55fdc5bdda1eb861b551e953e9d0327edda64a85 Author: Cvolton Date: Fri Aug 25 19:14:18 2023 +0200 remove CCHttpRequest (it didnt work) commit 6c167b4884feedf023183c4cf8f76b623239e97d Author: Cvolton Date: Fri Aug 25 18:41:48 2023 +0200 Revert "test cchttprequest ctor if it fixes stuff lol" This reverts commit 4d4521428e9270f2ad2e2a0af0a6eec9b6c68cfa. commit 4d4521428e9270f2ad2e2a0af0a6eec9b6c68cfa Author: Cvolton Date: Fri Aug 25 18:40:04 2023 +0200 test cchttprequest ctor if it fixes stuff lol commit 1be9bb049cac592303118e1983df3c2d79569861 Author: Cvolton Date: Fri Aug 25 10:43:33 2023 +0200 fix swapped funcs commit 10d4cf9919ed350851d8c582ea36be6e06035a8a Author: Cvolton Date: Fri Aug 25 10:38:43 2023 +0200 fix dailylevelpage commit b244c7d6acfb4118ba114726ac3429f16be51929 Author: Cvolton Date: Fri Aug 25 02:04:10 2023 +0200 idk commit 7d092602a49779f9d98212a3b3659a1a813e9bcb Author: Cvolton Date: Fri Aug 25 02:01:20 2023 +0200 maybe this will align properly? commit 74317d4174e61e67bfb9bdfb573246391d255e78 Author: Cvolton Date: Fri Aug 25 01:55:07 2023 +0200 im tired commit a28471e888a27661637fc8c36acf90152f87cf45 Author: Cvolton Date: Fri Aug 25 01:51:33 2023 +0200 try fix gdbro commit 3b28cf7f85f70ddc8fc9c5bb5297ba731ab0ce2a Author: Cvolton Date: Fri Aug 25 01:47:42 2023 +0200 try fix glm commit db947db4966f6624bcad4c43e3f45993b425a681 Author: Cvolton Date: Fri Aug 25 01:10:02 2023 +0200 add LevelBrowserLayer::setupPageInfo commit 111ecc83582e38a16daffdcb0c436df789b8abb5 Author: Cvolton Date: Thu Aug 24 23:49:22 2023 +0200 add gjscorecell updatebgcolor commit ff84c6f1e52ab2f825f458348e71fdcae21fefbc Author: Cvolton Date: Thu Aug 24 23:30:13 2023 +0200 add callable levelcell updatebgcolor commit 31c15d3a0bc95367a18b9758a6591c5317dd3879 Author: Cvolton Date: Thu Aug 24 23:16:08 2023 +0200 add more glm checks commit b2a1e9febe8938c17682bac2568ba7c25a0222d1 Author: Cvolton Date: Thu Aug 24 23:13:18 2023 +0200 realign glm commit 4fcb46f531ef616d0ce4cfd4dd86ff3b72a57484 Author: Cvolton Date: Thu Aug 24 22:29:30 2023 +0200 add windows pad for mac only pad commit 9be86a63e0dbd0156716243b7be1db73a2695031 Author: Cvolton Date: Thu Aug 24 22:26:02 2023 +0200 add mac only pad commit bb754f72956ca49b834e05f9f8f63cab0588f4c1 Author: Cvolton Date: Thu Aug 24 22:14:02 2023 +0200 fix glm on mac commit c34b7086cad507f54d1d90df410debe833810459 Author: Cvolton Date: Thu Aug 24 22:10:19 2023 +0200 replace unk strs in glm with pads commit e9def523766ef8f0ab4d1dc69abfcbc86a8946f9 Author: Cvolton Date: Thu Aug 24 21:55:46 2023 +0200 add glm dict offsets on mac commit 1216c2fdfe670c16a13ec9861867cec87b054b83 Author: Cvolton Date: Thu Aug 24 21:43:47 2023 +0200 Fix DailyLevelPage::init commit 97f12c1997a5d906ded40337f552faf2b690f38b Author: Cvolton Date: Thu Aug 24 21:20:00 2023 +0200 fix windows offset for m_weekly commit 9d3198b6d174976c5f70e1b5dfd92428572467d0 Author: Cvolton Date: Thu Aug 24 21:14:58 2023 +0200 fix mac offset for m_weekly commit dfbf8243bb2819fb980ebf312213d88e48394ea7 Author: Cvolton Date: Thu Aug 24 21:13:55 2023 +0200 add GJDailyLevelDelegate commit fc589eea2e9bb81f5b70e04245c1d27ce0a17d72 Author: Cvolton Date: Thu Aug 24 21:10:34 2023 +0200 improve DailyLevelPage commit 80347e72ce5b7fec3168888cfcbd207a78c443f3 Author: Cvolton Date: Thu Aug 24 21:04:29 2023 +0200 add member check for m_weekly commit 55236908817daebd57f5d5ac8a3ce882e61254c9 Author: Cvolton Date: Thu Aug 24 20:56:29 2023 +0200 add more mac members to test commit 9f3e299755dcad413092d07a7e634eb7edac1bad Author: Cvolton Date: Thu Aug 24 20:19:16 2023 +0200 try increase gsm pad commit a492c180be667a80117dcf5c910b2f231ec35cb4 Author: Cvolton Date: Thu Aug 24 20:11:14 2023 +0200 add gsm checks commit fe94e6a3e5c3a9b1be8e27ac545f7ccddaa953ef Author: Cvolton Date: Thu Aug 24 17:25:38 2023 +0200 test commit c641cb87f11a4c9c7fd1b181ba338411999412a3 Author: Cvolton Date: Thu Aug 24 17:20:41 2023 +0200 revert the previous thing commit 3cf35829210aa974a6634bb7d830a666fe28804a Author: Cvolton Date: Thu Aug 24 17:11:42 2023 +0200 try fix glm commit e9c5c86d49558998630256989ac6c30d590701c6 Author: Cvolton Date: Thu Aug 24 16:05:52 2023 +0200 fix setDictForKey commit 934e02a75d6d2133315900f838efca9c8f4853dc Author: Cvolton Date: Thu Aug 24 16:04:54 2023 +0200 fix cchttpclient::send commit 17565121a27d10d2f3a1a78e4e1085fbae7190fa Author: Cvolton Date: Thu Aug 24 16:00:18 2023 +0200 add some mising cocos funcs commit 1833c9be2a1f2d3372b9b92e0e51aed64d7ccb3f Author: Cvolton Date: Thu Aug 24 15:18:20 2023 +0200 add GManager::setup commit 9699c4dfcf3ee569518b1bfeac85d381fdad2fc0 Author: Cvolton Date: Thu Aug 24 14:58:11 2023 +0200 add glm::2CD6F0 commit a04801153393b4b14b20ef4fe546daca5b4236b9 Author: Cvolton Date: Thu Aug 24 14:41:08 2023 +0200 add mac gjuserscore::create(ccdict*) commit 3b37ea7999c131b609573a0b8228ff120967a3c3 Author: Cvolton Date: Thu Aug 24 14:32:31 2023 +0200 inline ctor for gjuserscore commit 57509dc97d9955c15cf0c584ba9cb38d4497e125 Author: Cvolton Date: Thu Aug 24 14:13:53 2023 +0200 add gjsearchobject commit 9e9ce9d668affe98d28cc3aac92e182c9acd4395 Author: Cvolton Date: Thu Aug 24 14:09:15 2023 +0200 fix LevelCell commit ca7f12633aa02eeefe0db771d5cb619fd858fb2e Author: Cvolton Date: Thu Aug 24 14:03:05 2023 +0200 add 2C5920 commit fc77474e15e70b7db9ef2a2b2b1803bfe5f48746 Author: Cvolton Date: Thu Aug 24 13:49:16 2023 +0200 add missing gjscorecell funcs commit 79b1df35fb203d3f139147a8496b77dcb3c73f9e Author: Cvolton Date: Thu Aug 24 13:15:34 2023 +0200 add gjgamelevel::getunpackedleveldesc commit 4a9f6d24e1bfbf084b1e79baacd9b4f4476b1d68 Author: Cvolton Date: Thu Aug 24 13:12:32 2023 +0200 add statscell:updatebgcolor commit 245ad705ef26b5d4035553468e0f61807ecc194c Author: Cvolton Date: Thu Aug 24 13:07:14 2023 +0200 add more missing gsm funcs commit 203fc0a9ed6f56818c9048a312f3740299898e19 Author: Cvolton Date: Thu Aug 24 12:52:06 2023 +0200 add missing profilepage mac addresses commit cc3fd5761c68e8badebd1338cba186b7a25b4287 Author: Cvolton Date: Thu Aug 24 12:40:41 2023 +0200 fix parts of profilepage commit 99e585bce1bb1da54c3e1b87ae43717911a0b929 Author: Cvolton Date: Thu Aug 24 11:46:13 2023 +0200 add levelpage commit baffedc8c0b84fd8d4de0c495d2fc727ef22768d Author: Cvolton Date: Thu Aug 24 11:32:15 2023 +0200 fix FLAlertLayer::onClose commit 33d0b856e51665083905cc1a4cd39c60ba2c7d85 Author: Cvolton Date: Thu Aug 24 11:18:14 2023 +0200 fix levelleaderboard for mac commit edc9da076f9cf655a34b2b0e67a4182ae076cd71 Author: Cvolton Date: Thu Aug 24 11:04:40 2023 +0200 update levelbrowserlayer commit ec9b75d7cb24ff482d01f9e85b0751a310cfc860 Author: Cvolton Date: Thu Aug 24 11:00:15 2023 +0200 add leaderboardslayer::create commit efbac386fbdc8d0641dc470166657eeef96888c6 Author: Cvolton Date: Thu Aug 24 10:53:38 2023 +0200 add missing infolayer funcs commit 50f542e0a2d456b9ff6ba7e350566d7738466b42 Author: Cvolton Date: Thu Aug 24 10:43:40 2023 +0200 add a few more missing glm funcs commit 75eff6e31b5c9cd6071549e8c0251afc21609c74 Author: Cvolton Date: Thu Aug 24 10:17:52 2023 +0200 add missing glm stuff commit 1009d11bdbe763b434b3382387b468be4cfd9b1c Author: Cvolton Date: Thu Aug 24 09:58:11 2023 +0200 add some GSM funcs commit fe9a539b27171636acd9d5ae2b82bdf628b9a552 Author: Cvolton Date: Thu Aug 24 03:32:47 2023 +0200 add offset for dailylevelpage commit 9f75a8d3b288a66fc80e0645188ff2fdbb8b7751 Author: Cvolton Date: Thu Aug 24 03:19:24 2023 +0200 assume pads for glm commit 7ec9ebd21f3fc9477f76bf6be4922a3f8bae6ddd Author: Cvolton Date: Thu Aug 24 03:09:10 2023 +0200 add dailypage updatetimers commit 9a6e6b5c17e9f8f4ee7719ba3aaf2ce678a66a80 Author: Cvolton Date: Thu Aug 24 03:00:06 2023 +0200 add creatorlayer stuff commit cf2f3e9fd2f71d3f24f9d712a9003a96342e61ea Author: Cvolton Date: Thu Aug 24 02:51:32 2023 +0200 add commentcell virtuals commit c9f82ddc4c6cbd3f784c4d152b9445aa5c64c9f0 Author: Cvolton Date: Wed Aug 23 00:11:38 2023 +0200 add some missing functions to PlayLayer --- bindings/Cocos2d.bro | 2 + bindings/GeometryDash.bro | 155 ++++++++++++++++++-------------- loader/test/members/MacOS.cpp | 15 ++++ loader/test/members/Windows.cpp | 6 ++ 4 files changed, 109 insertions(+), 69 deletions(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 6dd4de12..1428dcfa 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -1258,6 +1258,8 @@ class DS_Dictionary { bool stepIntoSubDictWithKey(char const*) = mac 0xc0cd0; int getIntegerForKey(char const*) = mac 0xc1610; void setIntegerForKey(char const*, int) = mac 0xc26b0; + void setDictForKey(char const*, cocos2d::CCDictionary*) = mac 0xC4EA0; + auto getObjectForKey(char const*) = mac 0xC4BB0; } [[link(win)]] diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 63858154..4f16461e 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -887,10 +887,10 @@ class ColorSetupDelegate { class CommentCell : TableViewCell, LikeItemDelegate, FLAlertLayerProtocol { void loadFromComment(GJComment*) = mac 0x111c70, win 0x5f3d0; - void onConfirmDelete(cocos2d::CCObject* sender) = mac 0x25ec80, win 0x61140; + void onConfirmDelete(cocos2d::CCObject* sender) = mac 0x11d100, win 0x61140; void onLike(cocos2d::CCObject* sender) = mac 0x11d000, win 0x60F90; - virtual void FLAlert_Clicked(FLAlertLayer* layer, bool btn) = win 0x61260; - virtual void likedItem(LikeItemType type, int id, bool special) = win 0x61070; + virtual void FLAlert_Clicked(FLAlertLayer* layer, bool btn) = mac 0x11d540, win 0x61260; + virtual void likedItem(LikeItemType type, int id, bool special) = mac 0x11d340, win 0x61070; cocos2d::CCSprite* m_iconSprite; cocos2d::CCLabelBMFont* m_likeLabel; @@ -957,7 +957,7 @@ class CreatorLayer : cocos2d::CCLayer, cocos2d::CCSceneTransitionDelegate, Dialo void onGauntlets(cocos2d::CCObject*) = mac 0x142b20, win 0x4f0a0; void onSecretVault(cocos2d::CCObject*) = win 0x4f1d0; void onTreasureRoom(cocos2d::CCObject*) = win 0x4f540; - virtual void sceneWillResume() = win 0x4fb50; + virtual void sceneWillResume() = mac 0x1438F0, win 0x4fb50; virtual bool init() = mac 0x141c10, win 0x4de40; static CreatorLayer* create() = win 0x4dda0; } @@ -1072,13 +1072,13 @@ class CustomizeObjectLayer : FLAlertLayer, TextInputDelegate, HSVWidgetPopupDele bool m_customColorSelected; } -class DailyLevelPage : FLAlertLayer { +class DailyLevelPage : FLAlertLayer, FLAlertLayerProtocol, GJDailyLevelDelegate, LevelDownloadDelegate { static DailyLevelPage* create(bool weekly) = win 0x6a860; - bool init(bool weekly) = mac 0x10abb0, win 0x6a900; - virtual void updateTimers(float) = win 0x6bef0; + bool init(bool weekly) = mac 0x108C90, win 0x6a900; + virtual void updateTimers(float) = mac 0x109780, win 0x6bef0; virtual void show() = mac 0x10a4b0, win 0x3f360; - PAD = win 0x21; + PAD = mac 0x29, win 0x15; bool m_weekly; } @@ -1691,7 +1691,6 @@ class FLAlertLayer : cocos2d::CCLayerColor { static FLAlertLayer* create(FLAlertLayerProtocol* protocol, char const* title, gd::string content, char const* btn1, char const* btn2, float width, bool scrollable, float height) = mac 0x25dec0, win 0x227e0; void onBtn1(cocos2d::CCObject*) = mac 0x25ec20, win 0x23340; void onBtn2(cocos2d::CCObject*) = mac 0x25ec80, win 0x23380; - void onClose(cocos2d::CCObject*) = win 0x49C60; cocos2d::CCMenu* m_buttonMenu; int m_controlConnected; @@ -2036,7 +2035,10 @@ class GJCommentListLayer : cocos2d::CCLayerColor { BoomListView* m_list; } -class GJDailyLevelDelegate {} +class GJDailyLevelDelegate { + virtual void dailyStatusFinished(bool) {} + virtual void dailyStatusFailed(bool) {} +} class GJDropDownLayer : cocos2d::CCLayerColor { virtual void customSetup() {} @@ -2282,7 +2284,7 @@ class GJGameLevel : cocos2d::CCNode { void savePercentage(int, bool, int, int, bool) = mac 0x2db700; void dataLoaded(DS_Dictionary* dict) = mac 0x2dc0e0, win 0xbded0, ios 0x6fca4; GJDifficulty getAverageDifficulty() = win 0xbd9b0; - gd::string getUnpackedLevelDescription() = win 0xbf890; + gd::string getUnpackedLevelDescription() = mac 0x2DDB50, win 0xbf890; gd::string lengthKeyToString(int key) = win 0xbd910; static GJGameLevel* getCurrent() { @@ -2596,12 +2598,14 @@ class GJScaleControlDelegate { virtual void scaleChanged(float) {} } -class GJScoreCell : TableViewCell { - virtual void FLAlert_Clicked(FLAlertLayer*, bool) = win 0x624a0; - void loadFromScore(GJUserScore* score) = win 0x61440; +class GJScoreCell : TableViewCell, FLAlertLayerProtocol { + virtual void FLAlert_Clicked(FLAlertLayer*, bool) = mac 0x11D8E0, win 0x624a0; + void loadFromScore(GJUserScore* score) = mac 0x113AA0, win 0x61440; void onViewProfile(cocos2d::CCObject* sender) = win 0x62380; - void updateBGColor(int index) = win 0x5c6b0; - GJScoreCell(char const* key, float width, float height) = win 0x613C0; + void updateBGColor(int index) = mac 0x113A40, win 0x5c6b0; + inline GJScoreCell(char const* identifier, float parentHeight, float height) : TableViewCell(identifier, parentHeight, height) {} + + GJUserScore* m_score; } class GJSearchObject : cocos2d::CCNode { @@ -2611,8 +2615,8 @@ class GJSearchObject : cocos2d::CCNode { static GJSearchObject* create(SearchType nID) = win 0xc2b90, mac 0x2df120; static GJSearchObject* create(SearchType nID, gd::string str) = win 0xc2c80, mac 0x2df310; - static GJSearchObject* createFromKey(const char* key) = win 0xC2760; - const char* getKey() = win 0xC30A0; + static GJSearchObject* createFromKey(const char* key) = mac 0x2C0620, win 0xC2760; + const char* getKey() = mac 0x2C6A40, win 0xC30A0; const char* getNextPageKey() = win 0xC31F0; SearchType m_searchType; @@ -2714,8 +2718,19 @@ class GJUserScore : cocos2d::CCNode { gd::string getPlayerName() const { return m_userName; } - static GJUserScore* create() = win 0xc1660; - static GJUserScore* create(cocos2d::CCDictionary*) = win 0xc0750; + static GJUserScore* create() { + auto pRet = new GJUserScore(); + + if (pRet) { + pRet->autorelease(); + return pRet; + } + + CC_SAFE_DELETE(pRet); + return nullptr; + } + inline GJUserScore() : CCNode() {} + static GJUserScore* create(cocos2d::CCDictionary*) = mac 0x2BD020, win 0xc0750; gd::string m_userName; gd::string m_userUDID; @@ -2760,7 +2775,7 @@ class GJUserScore : cocos2d::CCNode { } class GManager : cocos2d::CCNode { - virtual void setup() = win 0x28F60; + virtual void setup() = mac 0x26EE20, win 0x28F60; virtual void encodeDataTo(DS_Dictionary* data) {} virtual void dataLoaded(DS_Dictionary* data) {} virtual void firstLoad() {} @@ -2793,13 +2808,13 @@ class GameLevelManager : cocos2d::CCNode { cocos2d::CCArray* createAndGetScores(gd::string, GJScoreType) = win 0xa2780; GJGameLevel* createNewLevel() = mac 0x2b8180, win 0xa0db0; static GameLevelManager* sharedState() = mac 0x2a8340, win 0x9f860; - void limitSavedLevels() = win 0xA43B0; - cocos2d::CCArray* getCompletedLevels(bool newFilter) = win 0xa2d20; - void getGJUserInfo(int) = win 0xb00b0; - void getLevelLeaderboard(GJGameLevel* level, LevelLeaderboardType leaderboardType) = win 0xAED70; - void getOnlineLevels(GJSearchObject*) = win 0xa7bc0; + void limitSavedLevels() = mac 0x2C0C30, win 0xA43B0; + cocos2d::CCArray* getCompletedLevels(bool newFilter) = mac 0x2BEEE0, win 0xa2d20; + void getGJUserInfo(int) = mac 0x2CEBB0, win 0xb00b0; + void getLevelLeaderboard(GJGameLevel* level, LevelLeaderboardType leaderboardType) = mac 0x2CD6F0, win 0xAED70; + void getOnlineLevels(GJSearchObject*) = mac 0x2C5920, win 0xa7bc0; void getPageInfo(char const*) = mac 0x2c0050; - cocos2d::CCArray* getSavedLevels(bool favorite, int levelFolder) = win 0xa2960; + cocos2d::CCArray* getSavedLevels(bool favorite, int levelFolder) = mac 0x2BE910, win 0xa2960; cocos2d::CCArray* getStoredOnlineLevels(char const*) = mac 0x2bfe80, win 0xa3a90; void getTopArtists(int, int) = mac 0x2ce3d0; void getTopArtistsKey(int) = mac 0x2ce7a0; @@ -2810,15 +2825,15 @@ class GameLevelManager : cocos2d::CCNode { callback void ProcessHttpRequest(gd::string, gd::string, gd::string, GJHttpType) = mac 0x2a8670, win 0x9f8e0; cocos2d::CCDictionary* responseToDict(gd::string response, bool comment) = win 0xbba50; void storeUserNames(gd::string) = win 0xa1840; - void storeUserName(int userID, int accountID, gd::string str) = win 0xa1a70; - gd::string userNameForUserID(int id) = win 0xa1c20; - void updateUserScore() = win 0xada60; + void storeUserName(int userID, int accountID, gd::string str) = mac 0x2B9020, win 0xa1a70; + gd::string userNameForUserID(int id) = mac 0x2B91D0, win 0xa1c20; + void updateUserScore() = mac 0x2CB6A0, win 0xada60; void downloadLevel(int id, bool downloadData) = win 0xaa730; bool hasDownloadedLevel(int id) = win 0xab830; GJGameLevel* getSavedLevel(int id) = win 0xa2ee0; void saveLevel(GJGameLevel* level) = win 0xa31c0; void deleteLevel(GJGameLevel* level) = mac 0x2b88d0, win 0xa1640; - void resetCommentTimersForLevelID(int id, bool commentHistory) = win 0xB3F10; + void resetCommentTimersForLevelID(int id, bool commentHistory) = mac 0x2D43D0, win 0xB3F10; void resetStoredUserInfo(int id) { m_storedUserInfo->removeObjectForKey(id); } @@ -2842,12 +2857,11 @@ class GameLevelManager : cocos2d::CCNode { return GameLevelManager::sharedState(); } - //cocos2d::CCDictionary* timerDict = mac 0x1e8; cocos2d::CCDictionary* m_mainLevels; cocos2d::CCDictionary* m_searchFilters; cocos2d::CCDictionary* m_onlineLevels; - PAD = win 0x4; + cocos2d::CCDictionary* m_unkDict; cocos2d::CCDictionary* m_followedCreators; cocos2d::CCDictionary* m_downloadedLevels; cocos2d::CCDictionary* m_likedLevels; @@ -2860,13 +2874,12 @@ class GameLevelManager : cocos2d::CCNode { int m_dailyTimeLeft; int m_dailyID; int m_dailyIDUnk; - PAD = win 0x4; + PAD = mac 0x10, win 0x4; int m_weeklyTimeLeft; int m_weeklyID; int m_weeklyIDUnk; cocos2d::CCDictionary* m_gauntletLevels; - cocos2d::CCDictionary* m_unkDict13; - PAD = win 0x4; + gd::map m_availableFilters; cocos2d::CCDictionary* m_timerDict; cocos2d::CCDictionary* m_knownUsers; cocos2d::CCDictionary* m_accountIDtoUserIDDict; @@ -3528,9 +3541,9 @@ class GameStatsManager : cocos2d::CCNode { void awardCurrencyForLevel(GJGameLevel*) = mac 0x43600; void awardDiamondsForLevel(GJGameLevel*) = mac 0x43c60; void awardSecretKey() = mac 0x4b1e0; - int getAwardedCurrencyForLevel(GJGameLevel*) = win 0xf83e0; - int getBaseCurrencyForLevel(GJGameLevel*) = win 0xf8530; - GJChallengeItem* getChallenge(int id) = win 0xa2fb0; + int getAwardedCurrencyForLevel(GJGameLevel*) = mac 0x432E0, win 0xf83e0; + int getBaseCurrencyForLevel(GJGameLevel*) = mac 0x43470, win 0xf8530; + GJChallengeItem* getChallenge(int id) = mac 0x451f0, win 0xa2fb0; void getSecretCoinKey(char const*) = mac 0x429f0; int getStat(char const*) = mac 0x3d310, win 0xf3580; void hasPendingUserCoin(char const*) = mac 0x42730, win 0xf7c50; @@ -3545,14 +3558,14 @@ class GameStatsManager : cocos2d::CCNode { void storeUserCoin(char const*) = mac 0x42890; bool isItemUnlocked(UnlockType type, int id) = win 0xfbb80; - PAD = win 0x28; + PAD = mac 0x50, win 0x28; cocos2d::CCDictionary* m_dailyChests; cocos2d::CCDictionary* m_worldAdvertChests; cocos2d::CCDictionary* m_activeChallenges; cocos2d::CCDictionary* m_upcomingChallenges; - PAD = win 0xc; + PAD = mac 0x18, win 0xc; cocos2d::CCDictionary* m_playerStats; - PAD = win 0x10; + PAD = mac 0x50, win 0x10; cocos2d::CCDictionary* m_completedLevels; cocos2d::CCDictionary* m_verifiedUserCoins; cocos2d::CCDictionary* m_pendingUserCoins; @@ -3661,9 +3674,9 @@ class InfoAlertButton : CCMenuItemSpriteExtra { class InfoLayer : FLAlertLayer, LevelCommentDelegate, CommentUploadDelegate, FLAlertLayerProtocol { bool init(GJGameLevel* level, GJUserScore* score) = mac 0x456850, win 0x14f5a0; void setupCommentsBrowser(cocos2d::CCArray* comments) = mac 0x458590, win 0x152270; - void onMore(cocos2d::CCObject* sender) = win 0x151500; + void onMore(cocos2d::CCObject* sender) = mac 0x459400, win 0x151500; void onLevelInfo(cocos2d::CCObject* sender) = mac 0x459400, win 0x151850; - void loadPage(int page, bool) = win 0x151e70; + void loadPage(int page, bool) = mac 0x458FB0, win 0x151e70; static InfoLayer* create(GJGameLevel* level, GJUserScore* score) = mac 0x456600, win 0x14f4f0; GJGameLevel* m_level; @@ -3718,7 +3731,7 @@ class LeaderboardManagerDelegate { } class LeaderboardsLayer : cocos2d::CCLayer { - static LeaderboardsLayer* create(LeaderboardState state) = win 0x158710; + static LeaderboardsLayer* create(LeaderboardState state) = mac 0x29F590, win 0x158710; bool init(LeaderboardState state) = mac 0x29f6d0, win 0x1587b0; } @@ -3732,9 +3745,12 @@ class LevelBrowserLayer : cocos2d::CCLayer, LevelManagerDelegate, FLAlertLayerPr } bool init(GJSearchObject* search) = mac 0x2513f0, win 0x15a040; - void loadPage(GJSearchObject* search) = win 0x15b160; + void loadPage(GJSearchObject* search) = mac 0x253650, win 0x15b160; void setupLevelBrowser(cocos2d::CCArray* levels) = win 0x15bb40; - void updateLevelsLabel() = win 0x15c350; + virtual void setupPageInfo(gd::string, char const*) = mac 0x255050, win 0x15C1C0; + void updateLevelsLabel() = mac 0x255450, win 0x15c350; + void onRefresh(cocos2d::CCObject* sender) = mac 0x253090; + void onInfo(cocos2d::CCObject* sender) = mac 0x253170, win 0x15cb00; static LevelBrowserLayer* create(GJSearchObject* search) = mac 0x251210, win 0x159fa0, ios 0x2d0a00; PAD = win 0x4, mac 0x8; @@ -3764,9 +3780,9 @@ class LevelCell : TableViewCell { void onViewProfile(cocos2d::CCObject*) = mac 0x11a4a0, win 0x5c790; void loadCustomLevelCell() = mac 0x1183b0, win 0x5a020; - void updateBGColor(int index) = win 0x5c6b0; - void loadFromLevel(GJGameLevel* level) = win 0x59FD0; - LevelCell(char const* key, float width, float height) = win 0x59F40; + void updateBGColor(int index) = mac 0x110460, win 0x5c6b0; + void loadFromLevel(GJGameLevel* level) = mac 0x110410, win 0x59FD0; + inline LevelCell(char const* identifier, float parentHeight, float height) : TableViewCell(identifier, parentHeight, height) {} } class LevelCommentDelegate { @@ -4024,28 +4040,28 @@ class LevelInfoLayer : cocos2d::CCLayer, LevelDownloadDelegate, LevelUpdateDeleg PAD = win 0x4, mac 0x8; } -class LevelLeaderboard : FLAlertLayer { - void onChangeType(cocos2d::CCObject* sender) = win 0x17d090; - void onUpdate(cocos2d::CCObject* sender) = win 0x17d1b0; +class LevelLeaderboard : FLAlertLayer, LeaderboardManagerDelegate { + void onChangeType(cocos2d::CCObject* sender) = mac 0x20e310, win 0x17d090; + void onUpdate(cocos2d::CCObject* sender) = mac 0x20e240, win 0x17d1b0; bool init(GJGameLevel* level, LevelLeaderboardType type) = mac 0x20d710, win 0x17c4f0; - static LevelLeaderboard* create(GJGameLevel* level, LevelLeaderboardType leaderboardType) = win 0x17c440; + static LevelLeaderboard* create(GJGameLevel* level, LevelLeaderboardType leaderboardType) = mac 0x20D550, win 0x17c440; + void onClose(cocos2d::CCObject*) = mac 0x20e210, win 0x49C60; - PAD = win 0x4; GJGameLevel* m_level; LevelLeaderboardType m_type; } class LevelManagerDelegate { - virtual void loadLevelsFailed(char const*) {} virtual void loadLevelsFinished(cocos2d::CCArray *,char const*) {} - virtual void setupPageInfo(std::string,char const*) {} + virtual void loadLevelsFailed(char const*) {} + virtual void setupPageInfo(gd::string,char const*) {} } -class LevelPage { - PAD = win 0x124; +class LevelPage : cocos2d::CCLayer, DialogDelegate { + PAD = mac 0x8, win 0x4; GJGameLevel* m_level; - void onInfo(cocos2d::CCObject* sender) = win 0x189070; + void onInfo(cocos2d::CCObject* sender) = mac 0x23AAE0, win 0x189070; } class LevelSearchLayer : cocos2d::CCLayer { @@ -4295,6 +4311,7 @@ class MessageListDelegate {} class MoreSearchLayer : FLAlertLayer { static MoreSearchLayer* create() = mac 0x38ab40, win 0x182520; virtual bool init() = mac 0x3896b0, win 0x1825c0; + void onClose(cocos2d::CCObject*) = mac 0x38aa40, win 0x1848f0; } class MoreOptionsLayer : FLAlertLayer, TextInputDelegate, GooglePlayDelegate { @@ -5120,18 +5137,18 @@ class PointNode : cocos2d::CCObject { class ProfilePage : FLAlertLayer, FLAlertLayerProtocol, LevelCommentDelegate, CommentUploadDelegate, UserInfoDelegate, UploadActionDelegate, UploadPopupDelegate, LeaderboardManagerDelegate { static ProfilePage* create(int accountID, bool idk) = mac 0x45eed0, win 0x20ee50; - virtual void getUserInfoFailed(int) = win 0x2133e0; - virtual void getUserInfoChanged(GJUserScore*) = win 0x213430; + virtual void getUserInfoFailed(int) = mac 0x463FB0, win 0x2133e0; + virtual void userInfoChanged(GJUserScore*) = mac 0x464070, win 0x213430; bool init(int accountID, bool idk) = mac 0x45f170, win 0x20ef00; - void onMyLevels(cocos2d::CCObject*) = win 0x211bb0; - void onUpdate(cocos2d::CCObject*) = win 0x20fa20; + void onMyLevels(cocos2d::CCObject*) = mac 0x462d70, win 0x211bb0; + void onUpdate(cocos2d::CCObject*) = mac 0x460150, win 0x20fa20; void onClose(cocos2d::CCObject*) = mac 0x45fd20, win 0x49C60; - virtual void keyBackClicked() = win 0x49C80; - void loadPageFromUserInfo(GJUserScore* score) = win 0x210040; + virtual void keyBackClicked() = mac 0x464A60, win 0x49C80; + void loadPageFromUserInfo(GJUserScore* score) = mac 0x460480, win 0x210040; GJUserScore* m_score; int m_accountID; - PAD = win 0x38, android 0x24; + PAD = mac 0x44, win 0x38, android 0x24; cocos2d::CCArray* m_buttons; } @@ -5652,7 +5669,7 @@ class TeleportPortalObject : GameObject { } class TextAlertPopup : cocos2d::CCNode { - static TextAlertPopup* create(gd::string text, float time, float scale) = win 0x1450b0; + static TextAlertPopup* create(gd::string text, float time, float scale) = mac 0x157080, win 0x1450b0; } class TextArea : cocos2d::CCSprite { @@ -5760,7 +5777,7 @@ class UploadPopupDelegate { class UserInfoDelegate { virtual void getUserInfoFinished(GJUserScore *) {} virtual void getUserInfoFailed(int) {} - virtual void getUserInfoChanged(GJUserScore *) {} + virtual void userInfoChanged(GJUserScore *) {} } class UserListDelegate { diff --git a/loader/test/members/MacOS.cpp b/loader/test/members/MacOS.cpp index d81a3c96..bbff3753 100644 --- a/loader/test/members/MacOS.cpp +++ b/loader/test/members/MacOS.cpp @@ -80,4 +80,19 @@ GEODE_MEMBER_CHECK(LevelBrowserLayer, m_itemCount, 0x208); // LocalLevelManager GEODE_MEMBER_CHECK(LocalLevelManager, m_localLevels, 0x140); +// GameStatsManager +GEODE_MEMBER_CHECK(GameStatsManager, m_dailyChests, 0x170); +GEODE_MEMBER_CHECK(GameStatsManager, m_completedLevels, 0x200); +GEODE_MEMBER_CHECK(GameStatsManager, m_weeklyChest, 0x278); + +// DailyLevelPage +GEODE_MEMBER_CHECK(DailyLevelPage, m_weekly, 0x291); + +// GameLevelManager +GEODE_MEMBER_CHECK(GameLevelManager, m_weeklyID, 0x1a8); +GEODE_MEMBER_CHECK(GameLevelManager, m_gauntletLevels, 0x1b0); +GEODE_MEMBER_CHECK(GameLevelManager, m_timerDict, 0x1e8); +GEODE_MEMBER_CHECK(GameLevelManager, m_accountIDtoUserIDDict, 0x1f8); +GEODE_MEMBER_CHECK(GameLevelManager, m_userIDtoAccountIDDict, 0x200); + #endif diff --git a/loader/test/members/Windows.cpp b/loader/test/members/Windows.cpp index 1650d337..486ad8ae 100644 --- a/loader/test/members/Windows.cpp +++ b/loader/test/members/Windows.cpp @@ -56,4 +56,10 @@ static_assert(sizeof(GJBaseGameLayer) == 0x2cc); GEODE_MEMBER_CHECK(AudioEffectsLayer, m_unk19C, 0x19c); +GEODE_MEMBER_CHECK(GameStatsManager, m_dailyChests, 0x114); +GEODE_MEMBER_CHECK(GameStatsManager, m_completedLevels, 0x144); + +GEODE_MEMBER_CHECK(DailyLevelPage, m_weekly, 0x1ed); + + #endif From 8b9860be5b2fdec250c474962f7ceee311b43305 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Sun, 27 Aug 2023 11:10:08 -0300 Subject: [PATCH 24/26] fix addresser for some cocos funcs --- bindings/Cocos2d.bro | 2 +- loader/include/Geode/utils/addresser.hpp | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 1428dcfa..d2be06dc 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -310,7 +310,7 @@ class cocos2d::CCFileUtils : cocos2d::TypeInfo { static void purgeFileUtils(); virtual void addSearchPath(const char* path); virtual void removeSearchPath(const char *path); - virtual std::string fullPathForFilename(const char* filename, bool unk); + virtual gd::string fullPathForFilename(const char* filename, bool unk); void removeAllPaths() = mac 0x241600; } diff --git a/loader/include/Geode/utils/addresser.hpp b/loader/include/Geode/utils/addresser.hpp index f8f0ffc2..08bffc10 100644 --- a/loader/include/Geode/utils/addresser.hpp +++ b/loader/include/Geode/utils/addresser.hpp @@ -91,6 +91,14 @@ namespace geode::addresser { *reinterpret_cast(reinterpret_cast(ins) + thunk) + index ); + #ifdef GEODE_IS_WINDOWS + // if the first instruction is a long jmp then this might still be a thunk + if (*reinterpret_cast(address) == 0xE9) { + auto relative = *reinterpret_cast(address + 1); + address = address + relative + 5; + } + #endif + address = followThunkFunction(address); return address; From 9875f5d5974c8a0dfcd0150b096f309b44eb61c7 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Sun, 27 Aug 2023 11:23:36 -0300 Subject: [PATCH 25/26] improve lag because of cc_2x2_white_image --- loader/src/cocos2d-ext/CCFileUtils.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/loader/src/cocos2d-ext/CCFileUtils.cpp b/loader/src/cocos2d-ext/CCFileUtils.cpp index ba4c6f49..67796df9 100644 --- a/loader/src/cocos2d-ext/CCFileUtils.cpp +++ b/loader/src/cocos2d-ext/CCFileUtils.cpp @@ -93,4 +93,18 @@ struct FileUtilsUpdatePaths : Modify { } return ret; } + + gd::string fullPathForFilename(const char* filename, bool unk) override { + using namespace std::string_literals; + using namespace std::string_view_literals; + + // this filename in particular is never cached because its not actually present anywhere. + // this is only an issue because cocos itself requests the full path for this in CCSprite, + // and with a lot of search paths (specially ones added by geode), this can cause a significant amount of lag. + if (filename == "cc_2x2_white_image"sv) { + return "cc_2x2_white_image"s; + } + + return CCFileUtils::fullPathForFilename(filename, unk); + } }; From 2386347b4789290afd4bb38a995032c4835c7af4 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Sun, 27 Aug 2023 17:50:05 +0300 Subject: [PATCH 26/26] add macos fullPathForFilename --- bindings/Cocos2d.bro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 6dd4de12..3c925554 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -310,7 +310,7 @@ class cocos2d::CCFileUtils : cocos2d::TypeInfo { static void purgeFileUtils(); virtual void addSearchPath(const char* path); virtual void removeSearchPath(const char *path); - virtual std::string fullPathForFilename(const char* filename, bool unk); + virtual gd::string fullPathForFilename(const char* filename, bool unk) = mac 0x23f940; void removeAllPaths() = mac 0x241600; }