From c5550a67c252c9129ea817647c15580a4622f476 Mon Sep 17 00:00:00 2001 From: ConfiG Date: Tue, 21 Nov 2023 20:34:59 +0300 Subject: [PATCH 01/21] log geode version on startup --- entry.cpp | 2 +- loader/src/load.cpp | 2 +- loader/src/loader/ModImpl.cpp | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/entry.cpp b/entry.cpp index cf19cb70..0ce0b571 100644 --- a/entry.cpp +++ b/entry.cpp @@ -16,5 +16,5 @@ namespace geode { namespace { // to make sure the instance is set into the sharedMod<> in load time - static auto mod = geode::getMod(); + static auto mod = geode::getMod(); } diff --git a/loader/src/load.cpp b/loader/src/load.cpp index ba849912..b02001e2 100644 --- a/loader/src/load.cpp +++ b/loader/src/load.cpp @@ -60,7 +60,7 @@ $execute { int geodeEntry(void* platformData) { log::Logger::setup(); - log::info("Entry"); + log::info("Running {} {}", Mod::get()->getName(), Mod::get()->getVersion()); auto begin = std::chrono::high_resolution_clock::now(); diff --git a/loader/src/loader/ModImpl.cpp b/loader/src/loader/ModImpl.cpp index 67058a5b..a24724b0 100644 --- a/loader/src/loader/ModImpl.cpp +++ b/loader/src/loader/ModImpl.cpp @@ -627,6 +627,11 @@ Mod* Loader::Impl::getInternalMod() { auto& mod = Mod::sharedMod<>; if (mod) return mod; + if (m_mods.contains("geode.loader")) { + log::warn("Something went wrong and Mod::sharedMod<> got unset after the internal mod was created! Setting sharedMod back..."); + mod = m_mods["geode.loader"]; + return mod; + } auto infoRes = getModImplInfo(); if (!infoRes) { LoaderImpl::get()->platformMessageBox( @@ -643,7 +648,6 @@ Mod* Loader::Impl::getInternalMod() { } mod->m_impl->m_enabled = true; m_mods.insert({ mod->getID(), mod }); - log::debug("Created internal mod {}", mod->getName()); return mod; } From f7962246ec5def74199a7b007a0f31fd75afe126 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Tue, 21 Nov 2023 20:38:13 +0300 Subject: [PATCH 02/21] set time for updating index notif --- loader/src/hooks/MenuLayer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/src/hooks/MenuLayer.cpp b/loader/src/hooks/MenuLayer.cpp index 869d1bce..27975ad7 100644 --- a/loader/src/hooks/MenuLayer.cpp +++ b/loader/src/hooks/MenuLayer.cpp @@ -174,6 +174,7 @@ struct CustomMenuLayer : Modify { INDEX_UPDATE_NOTIF = Notification::create( "Updating Index", NotificationIcon::Loading, 0 ); + INDEX_UPDATE_NOTIF->setTime(NOTIFICATION_LONG_TIME); INDEX_UPDATE_NOTIF->show(); Index::get()->update(); } From 164185621e12c8bf7be12172d7fb1abfb70ededc Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Tue, 21 Nov 2023 21:20:06 +0300 Subject: [PATCH 03/21] easy fix of the web error crash !!! (not rly) --- loader/src/loader/Index.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/loader/src/loader/Index.cpp b/loader/src/loader/Index.cpp index 5cc68c1b..553e1a35 100644 --- a/loader/src/loader/Index.cpp +++ b/loader/src/loader/Index.cpp @@ -781,7 +781,11 @@ void Index::Impl::installNext(size_t index, IndexInstallList const& list) { item->setIsInstalled(true); // Install next item in queue - this->installNext(index + 1, list); + // this is in next frame cause otherwise + // it seems to deadlock and havent figured out why + Loader::get()->queueInMainThread([&]{ + this->installNext(index + 1, list); + }); }) .expect([postError, list, item](std::string const& err) { postError(fmt::format( From c8392e92f529cf539e8843c46c9f582eaccab6f0 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Tue, 21 Nov 2023 22:03:07 +0300 Subject: [PATCH 04/21] im tired --- loader/src/loader/Index.cpp | 14 ++++++++------ loader/src/utils/web.cpp | 16 ++++++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/loader/src/loader/Index.cpp b/loader/src/loader/Index.cpp index 553e1a35..84b7c565 100644 --- a/loader/src/loader/Index.cpp +++ b/loader/src/loader/Index.cpp @@ -673,7 +673,10 @@ Result Index::getInstallList(IndexItemHandle item) const { } // recursively add dependencies GEODE_UNWRAP_INTO(auto deps, this->getInstallList(depItem)); - ranges::push(list.list, deps.list); + for (auto& dep : deps.list) { + if (ranges::contains(list.list, dep)) continue; + list.list.push_back(dep); + } } // otherwise user must get this dependency manually from somewhere else { @@ -745,6 +748,7 @@ void Index::Impl::installNext(size_t index, IndexInstallList const& list) { auto item = list.list.at(index); auto tempFile = dirs::getTempDir() / (item->getMetadata().getID() + ".index"); + log::debug("Installing {}", item->getMetadata().getID()); m_runningInstallations[list.target] = web::AsyncWebRequest() .join("install_item_" + item->getMetadata().getID()) .fetch(item->getDownloadURL()) @@ -780,12 +784,10 @@ void Index::Impl::installNext(size_t index, IndexInstallList const& list) { item->setIsInstalled(true); + log::debug("Installed {}", item->getMetadata().getID()); + // Install next item in queue - // this is in next frame cause otherwise - // it seems to deadlock and havent figured out why - Loader::get()->queueInMainThread([&]{ - this->installNext(index + 1, list); - }); + this->installNext(index + 1, list); }) .expect([postError, list, item](std::string const& err) { postError(fmt::format( diff --git a/loader/src/utils/web.cpp b/loader/src/utils/web.cpp index 04759dee..a2ba3beb 100644 --- a/loader/src/utils/web.cpp +++ b/loader/src/utils/web.cpp @@ -297,9 +297,11 @@ SentAsyncWebRequest::Impl::Impl(SentAsyncWebRequest* self, AsyncWebRequest const return 1; } Loader::get()->queueInMainThread([self = data->self, now, total]() { - std::lock_guard _(self->m_mutex); + std::unique_lock l(self->m_mutex); for (auto& prog : self->m_progresses) { + l.unlock(); prog(*self->m_self, now, total); + l.lock(); } }); return 0; @@ -327,9 +329,11 @@ SentAsyncWebRequest::Impl::Impl(SentAsyncWebRequest* self, AsyncWebRequest const m_finished = true; Loader::get()->queueInMainThread([this, ret]() { - std::lock_guard _(m_mutex); + std::unique_lock l(m_mutex); for (auto& then : m_thens) { + l.unlock(); then(*m_self, ret); + l.lock(); } std::lock_guard __(RUNNING_REQUESTS_MUTEX); RUNNING_REQUESTS.erase(m_id); @@ -354,9 +358,11 @@ void SentAsyncWebRequest::Impl::doCancel() { } Loader::get()->queueInMainThread([this]() { - std::lock_guard _(m_mutex); + std::unique_lock l(m_mutex); for (auto& canc : m_cancelleds) { + l.unlock(); canc(*m_self); + l.lock(); } }); @@ -392,9 +398,11 @@ void SentAsyncWebRequest::Impl::error(std::string const& error, int code) { }); Loader::get()->queueInMainThread([this, error, code]() { { - std::lock_guard _(m_mutex); + std::unique_lock l(m_mutex); for (auto& expect : m_expects) { + l.unlock(); expect(error, code); + l.lock(); } } std::lock_guard _(RUNNING_REQUESTS_MUTEX); From 1e654387b9437add410cfcff283d999824961a5f Mon Sep 17 00:00:00 2001 From: alk <45172705+altalk23@users.noreply.github.com> Date: Tue, 21 Nov 2023 22:10:50 +0300 Subject: [PATCH 05/21] Update test-offsets.yml --- .github/workflows/test-offsets.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-offsets.yml b/.github/workflows/test-offsets.yml index 23403f67..a4066463 100644 --- a/.github/workflows/test-offsets.yml +++ b/.github/workflows/test-offsets.yml @@ -2,6 +2,7 @@ name: Test Offsets on: workflow_dispatch: + pull_request: push: paths: - 'bindings/**' # only when adjusting bindings From 89e410b5ab350b813536559959741c36d6e97e13 Mon Sep 17 00:00:00 2001 From: dankmeme01 <42031238+dankmeme01@users.noreply.github.com> Date: Tue, 21 Nov 2023 20:41:36 +0100 Subject: [PATCH 06/21] add GameLevelManager::deleteComment --- bindings/GeometryDash.bro | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index de6aab93..5b3a1ee2 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -2894,6 +2894,7 @@ class GameLevelManager : cocos2d::CCNode { void uploadAccountComment(gd::string text) = win 0xb3250; void uploadLevelComment(int levelID, gd::string text, int unk) = win 0xb31c0; void uploadComment(gd::string text, CommentType type, int levelID, int unk) = win 0xb32e0; + void deleteComment(int commentID, CommentType type, int levelID) = win 0xb41a0; void downloadLevel(int id, bool downloadData) = win 0xaa730; bool hasDownloadedLevel(int id) = win 0xab830; GJGameLevel* getSavedLevel(int id) = win 0xa2ee0; From 4c6a5074c8bba595e8e2b353ad1ee161f4f17743 Mon Sep 17 00:00:00 2001 From: mat <26722564+matcool@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:32:22 -0300 Subject: [PATCH 07/21] update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29281b57..77daf589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Geode Changelog +## v1.3.7 +* Fix web download deadlock (16418562) +* Set max time for updating index notification (f7962246) +* Log geode version on startup (c5550a67) +* Fix logic error in addHook (5cf0f3c2) +* Improve logging + minor refactors (5083017b) +* Some bindings changes + ## v1.3.6 * Allow error responses in our WebRequest classes (237128bf) * Display unhandled C++ exceptions in crash log (fdd78aca, 0d091626, 52421d8c, 0472075f) From 445b5cdf38c22f89baeb3d450a781117d748c616 Mon Sep 17 00:00:00 2001 From: mat <26722564+matcool@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:32:35 -0300 Subject: [PATCH 08/21] forgot the space --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77daf589..c08eb8ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,12 @@ # Geode Changelog ## v1.3.7 -* Fix web download deadlock (16418562) -* Set max time for updating index notification (f7962246) -* Log geode version on startup (c5550a67) -* Fix logic error in addHook (5cf0f3c2) -* Improve logging + minor refactors (5083017b) -* Some bindings changes + * Fix web download deadlock (16418562) + * Set max time for updating index notification (f7962246) + * Log geode version on startup (c5550a67) + * Fix logic error in addHook (5cf0f3c2) + * Improve logging + minor refactors (5083017b) + * Some bindings changes ## v1.3.6 * Allow error responses in our WebRequest classes (237128bf) From 5641c05f49276bed7f0dcd75f0595c60130ddd59 Mon Sep 17 00:00:00 2001 From: Capeling <113705504+Capeling@users.noreply.github.com> Date: Tue, 28 Nov 2023 22:44:43 +1030 Subject: [PATCH 09/21] add windows addresses for LevelTools::getAudioFileName, LevelTools::getAudioTitle, LevelTools::artistForAudio and LevelTools::urlForAudio (#358) --- bindings/GeometryDash.bro | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 5b3a1ee2..37cefce2 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -5970,9 +5970,9 @@ class LevelTools { static bool verifyLevelIntegrity(gd::string, int) = mac 0x294360, win 0x18b180; static float xPosForTime(float, cocos2d::CCArray*, int) = mac 0x293d90, win 0x18acd0; static float timeForXPos(float, cocos2d::CCArray*, int) = mac 0x293eb0, win 0x18ae70; - static gd::string getAudioFileName(int) = mac 0x292840; - static gd::string getAudioTitle(int) = mac 0x2922f0; - static gd::string artistForAudio(int) = mac 0x292d90; - static gd::string urlForAudio(int) = mac 0x292f10; + static gd::string getAudioFileName(int) = mac 0x292840, win 0x189FA0; + static gd::string getAudioTitle(int) = mac 0x2922f0, win 0x189C60; + static gd::string artistForAudio(int) = mac 0x292d90, win 0x18A2D0; + static gd::string urlForAudio(int) = mac 0x292f10, win 0x18A4A0; } // clang-format on From 8f60e24686a1b650e248662d76647889b6998f12 Mon Sep 17 00:00:00 2001 From: Capeling <113705504+Capeling@users.noreply.github.com> Date: Wed, 29 Nov 2023 09:33:01 +1030 Subject: [PATCH 10/21] Update GeometryDash.bro added more LevelTools functions, removed windows address for artistForAudio due to issues --- bindings/GeometryDash.bro | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 37cefce2..155df79a 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -5970,9 +5970,14 @@ class LevelTools { static bool verifyLevelIntegrity(gd::string, int) = mac 0x294360, win 0x18b180; static float xPosForTime(float, cocos2d::CCArray*, int) = mac 0x293d90, win 0x18acd0; static float timeForXPos(float, cocos2d::CCArray*, int) = mac 0x293eb0, win 0x18ae70; - static gd::string getAudioFileName(int) = mac 0x292840, win 0x189FA0; - static gd::string getAudioTitle(int) = mac 0x2922f0, win 0x189C60; - static gd::string artistForAudio(int) = mac 0x292d90, win 0x18A2D0; - static gd::string urlForAudio(int) = mac 0x292f10, win 0x18A4A0; + static gd::string getAudioFileName(int) = mac 0x292840, win 0x189fa0; + static gd::string getAudioTitle(int) = mac 0x2922f0, win 0x189c60; + static gd::string artistForAudio(int) = mac 0x292d90; + static gd::string urlForAudio(int) = mac 0x292f10, win 0x18a4a0; + static gd::string nameForArtist(int) = win 0x18A3A0; + static gd::string ngURLForArtist(int) = win 0x18A7C0; + static gd::string ytURLForArtist(int) = win 0x18A8C0; + static gd::string fbURLForArtist(int) = win 0x18A9B0; + static gd::string getAudioString(int) = win 0x18AAA0; } // clang-format on From 385897c08e4aff7506c73569b0b053be8737ea67 Mon Sep 17 00:00:00 2001 From: Capeling <113705504+Capeling@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:17:10 +1030 Subject: [PATCH 11/21] Update GeometryDash.bro changed artistForAudio into an int, since thats what it is --- bindings/GeometryDash.bro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 155df79a..052c192c 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -5972,7 +5972,7 @@ class LevelTools { static float timeForXPos(float, cocos2d::CCArray*, int) = mac 0x293eb0, win 0x18ae70; static gd::string getAudioFileName(int) = mac 0x292840, win 0x189fa0; static gd::string getAudioTitle(int) = mac 0x2922f0, win 0x189c60; - static gd::string artistForAudio(int) = mac 0x292d90; + static int artistForAudio(int) = mac 0x292d90, win 0x18A2D0; static gd::string urlForAudio(int) = mac 0x292f10, win 0x18a4a0; static gd::string nameForArtist(int) = win 0x18A3A0; static gd::string ngURLForArtist(int) = win 0x18A7C0; From e8a326f7cb9621f64e98faeda40f96dbfac17af0 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Thu, 14 Dec 2023 21:31:54 -0300 Subject: [PATCH 12/21] make crashlog messagebox always appear, instead of only on GEODE_DEBUG --- loader/src/platform/windows/crashlog.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/loader/src/platform/windows/crashlog.cpp b/loader/src/platform/windows/crashlog.cpp index 57e137fa..ba2b8851 100644 --- a/loader/src/platform/windows/crashlog.cpp +++ b/loader/src/platform/windows/crashlog.cpp @@ -264,10 +264,7 @@ static LONG WINAPI exceptionHandler(LPEXCEPTION_POINTERS info) { auto text = crashlog::writeCrashlog(faultyMod, getInfo(info, faultyMod), getStacktrace(info->ContextRecord), getRegisters(info->ContextRecord)); - // show message box on debug mode - #ifdef GEODE_DEBUG MessageBoxA(nullptr, text.c_str(), "Geode Crashed", MB_ICONERROR); - #endif return EXCEPTION_CONTINUE_SEARCH; } From 44a018cdf98b541b96f4021a5f8351d2f23e52d1 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Thu, 14 Dec 2023 21:32:19 -0300 Subject: [PATCH 13/21] recursively follow jumps in followThunkFunction --- loader/src/utils/addresser.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/loader/src/utils/addresser.cpp b/loader/src/utils/addresser.cpp index 9fd65c2f..277084fc 100644 --- a/loader/src/utils/addresser.cpp +++ b/loader/src/utils/addresser.cpp @@ -68,12 +68,19 @@ Addresser::MultipleInheritance* Addresser::instance() { intptr_t Addresser::followThunkFunction(intptr_t address) { #ifdef GEODE_IS_WINDOWS - // check if first instruction is a jmp dword ptr [....], i.e. if the func is a thunk - if (*reinterpret_cast(address) == 0xFF && *reinterpret_cast(address + 1) == 0x25) { - // read where the jmp reads from - address = *reinterpret_cast(address + 2); - // that then contains the actual address of the func - address = *reinterpret_cast(address); + for (int limit = 0; limit < 100; ++limit) { + // check if first instruction is a jmp dword ptr [....], i.e. if the func is a thunk + if (*reinterpret_cast(address) == 0xFF && *reinterpret_cast(address + 1) == 0x25) { + // read where the jmp reads from + address = *reinterpret_cast(address + 2); + // that then contains the actual address of the func + address = *reinterpret_cast(address); + } else if (*reinterpret_cast(address) == 0xE9) { + auto relative = *reinterpret_cast(address + 1); + address = address + relative + 5; + } else { + break; + } } #endif return address; From 391f63edeecfdc5369798e6497ab36fa768f4abb Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Thu, 14 Dec 2023 21:37:29 -0300 Subject: [PATCH 14/21] implement a save file fix thank you chloe for a basis for the rewritten function Co-authored-by: qimiko <25387744+qimiko@users.noreply.github.com> --- bindings/Cocos2d.bro | 1 + loader/src/hooks/SaveFileFix.cpp | 64 ++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 loader/src/hooks/SaveFileFix.cpp diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 900aae67..b927c15f 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -1154,6 +1154,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 auto decompressString2(unsigned char* data, bool decrypt, int size, int decryptionKey); static int ccDeflateMemory(unsigned char*, unsigned int, unsigned char**) = mac 0xe9cf0; } diff --git a/loader/src/hooks/SaveFileFix.cpp b/loader/src/hooks/SaveFileFix.cpp new file mode 100644 index 00000000..6681c34e --- /dev/null +++ b/loader/src/hooks/SaveFileFix.cpp @@ -0,0 +1,64 @@ +#include + +#if defined(GEODE_IS_WINDOWS) || defined(GEODE_IS_ANDROID) + +using namespace geode::prelude; + +#include + +// This function is well known for crashing on certain save files, +// causing the game to crash at startup, known as the infamous save file bug. +// +// The exact reason for why this fails is still a bit fuzzy, but I believe it's because +// rob doesn't use the base64/inflated size correctly, and ends up relying on a null +// terminator being there when it shouldnt. +// +// To fix this, we just rewrite the function. +gd::string decompressString2(unsigned char* data, bool decrypt, int size, int decryptionKey) { + if (data == nullptr || size == 0 || *data == 0) { + return {}; + } + + if (decrypt) { + for (int i = 0; i < size; i++) { + data[i] ^= decryptionKey; + } + } + + // TODO: maybe not use cocos's base64 and inflateMemory.. + + unsigned char* out = nullptr; + auto const decodedSize = cocos2d::base64Decode(data, size, &out); + std::unique_ptr b64decoded { out }; + + if (decodedSize <= 0) { + return {}; + } + + out = nullptr; + auto const inflatedSize = cocos2d::ZipUtils::ccInflateMemory(b64decoded.get(), decodedSize, &out); + + std::unique_ptr inflated { out }; + + if (inflatedSize <= 0) { + return {}; + } + + return std::string(reinterpret_cast(inflated.get()), inflatedSize); +} + +// Modify doesnt want to work for some reason! +$execute { + Mod::get()->addHook( + reinterpret_cast( + geode::addresser::getNonVirtual( + &cocos2d::ZipUtils::decompressString2 + ) + ), + &decompressString2, + "cocos2d::ZipUtils::decompressString2", + tulip::hook::TulipConvention::Cdecl + ); +} + +#endif \ No newline at end of file From d295fc95468f51dfcccdeb65afbec1a1a1c3dddc Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Thu, 14 Dec 2023 21:45:24 -0300 Subject: [PATCH 15/21] update comment --- loader/src/hooks/SaveFileFix.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/loader/src/hooks/SaveFileFix.cpp b/loader/src/hooks/SaveFileFix.cpp index 6681c34e..65241b65 100644 --- a/loader/src/hooks/SaveFileFix.cpp +++ b/loader/src/hooks/SaveFileFix.cpp @@ -9,9 +9,8 @@ using namespace geode::prelude; // This function is well known for crashing on certain save files, // causing the game to crash at startup, known as the infamous save file bug. // -// The exact reason for why this fails is still a bit fuzzy, but I believe it's because -// rob doesn't use the base64/inflated size correctly, and ends up relying on a null -// terminator being there when it shouldnt. +// Rob ends up relying on strlen for knowing the size of `data`, instead of just using the passed in `size`. +// Its a miracle this works most of the time, considering `data` is just binary data // // To fix this, we just rewrite the function. gd::string decompressString2(unsigned char* data, bool decrypt, int size, int decryptionKey) { From 2077a238d35a2212022604ab7edb1be9a2e12ec3 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Fri, 15 Dec 2023 10:58:46 -0300 Subject: [PATCH 16/21] bump version and update changelog --- CHANGELOG.md | 6 ++++++ VERSION | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c08eb8ee..9d65d30a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Geode Changelog +## v1.3.8 +* Implement a save file fix for Windows (391f63ed) +* Recursively follow jumps in followThunkFunction (44a018cd) +* Remove need for GEODE_DEBUG for crashlogs (e8a326f7) +* Some bindings (f18335fa) + ## v1.3.7 * Fix web download deadlock (16418562) * Set max time for updating index notification (f7962246) diff --git a/VERSION b/VERSION index 3336003d..e05cb332 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.7 +1.3.8 From 4b7663015a3dc2f987f01f6ada85353b78862a25 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Fri, 15 Dec 2023 11:59:11 -0300 Subject: [PATCH 17/21] (urgent) fix followThunkFunction it was following hooks for cocos functions, causing bad crashes. instead, now only follow jmp and then jmp dword ptr --- VERSION | 2 +- loader/src/hooks/SaveFileFix.cpp | 2 +- loader/src/utils/addresser.cpp | 30 ++++++++++++++++++------------ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/VERSION b/VERSION index e05cb332..d4c4950a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.8 +1.3.9 diff --git a/loader/src/hooks/SaveFileFix.cpp b/loader/src/hooks/SaveFileFix.cpp index 65241b65..2ed63e25 100644 --- a/loader/src/hooks/SaveFileFix.cpp +++ b/loader/src/hooks/SaveFileFix.cpp @@ -48,7 +48,7 @@ gd::string decompressString2(unsigned char* data, bool decrypt, int size, int de // Modify doesnt want to work for some reason! $execute { - Mod::get()->addHook( + (void) Mod::get()->addHook( reinterpret_cast( geode::addresser::getNonVirtual( &cocos2d::ZipUtils::decompressString2 diff --git a/loader/src/utils/addresser.cpp b/loader/src/utils/addresser.cpp index 277084fc..ab2c172f 100644 --- a/loader/src/utils/addresser.cpp +++ b/loader/src/utils/addresser.cpp @@ -68,20 +68,26 @@ Addresser::MultipleInheritance* Addresser::instance() { intptr_t Addresser::followThunkFunction(intptr_t address) { #ifdef GEODE_IS_WINDOWS - for (int limit = 0; limit < 100; ++limit) { - // check if first instruction is a jmp dword ptr [....], i.e. if the func is a thunk - if (*reinterpret_cast(address) == 0xFF && *reinterpret_cast(address + 1) == 0x25) { - // read where the jmp reads from - address = *reinterpret_cast(address + 2); - // that then contains the actual address of the func - address = *reinterpret_cast(address); - } else if (*reinterpret_cast(address) == 0xE9) { - auto relative = *reinterpret_cast(address + 1); - address = address + relative + 5; - } else { - break; + // if theres a jmp at the start + if (*reinterpret_cast(address) == 0xE9) { + auto relative = *reinterpret_cast(address + 1); + auto newAddress = address + relative + 5; + // and if that jmp leads to a jmp dword ptr, only then follow it, + // because otherwise its just a hook. + // For some reason this [jmp -> jmp dword ptr] chain happens with a few cocos functions, + // but not all. For example: cocos2d::ZipUtils::decompressString2 + if (*reinterpret_cast(newAddress) == 0xFF && *reinterpret_cast(newAddress + 1) == 0x25) { + address = newAddress; } } + + // check if first instruction is a jmp dword ptr [....], i.e. if the func is a thunk + if (*reinterpret_cast(address) == 0xFF && *reinterpret_cast(address + 1) == 0x25) { + // read where the jmp reads from + address = *reinterpret_cast(address + 2); + // that then contains the actual address of the func + address = *reinterpret_cast(address); + } #endif return address; } \ No newline at end of file From 458248bfd61b189d4df3671b0e1b87ba9952d3ee Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Fri, 15 Dec 2023 12:00:20 -0300 Subject: [PATCH 18/21] update changelog --- CHANGELOG.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d65d30a..25beccf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,13 @@ # Geode Changelog +## v1.3.9 + * Fix followThunkFunction (4b766301) + ## v1.3.8 -* Implement a save file fix for Windows (391f63ed) -* Recursively follow jumps in followThunkFunction (44a018cd) -* Remove need for GEODE_DEBUG for crashlogs (e8a326f7) -* Some bindings (f18335fa) + * Implement a save file fix for Windows (391f63ed) + * Recursively follow jumps in followThunkFunction (44a018cd) + * Remove need for GEODE_DEBUG for crashlogs (e8a326f7) + * Some bindings (f18335fa) ## v1.3.7 * Fix web download deadlock (16418562) From c7a471660e7e934e585793567494689dc21aeef5 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Sat, 16 Dec 2023 10:30:42 -0300 Subject: [PATCH 19/21] fix garage node ids being shifted when asking for name --- loader/src/ids/GJGarageLayer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/loader/src/ids/GJGarageLayer.cpp b/loader/src/ids/GJGarageLayer.cpp index b4ea8425..020ce5a5 100644 --- a/loader/src/ids/GJGarageLayer.cpp +++ b/loader/src/ids/GJGarageLayer.cpp @@ -9,9 +9,13 @@ using namespace geode::prelude; $register_ids(GJGarageLayer) { // the lock does not exist for not logged in users auto loggedInOffset = GJAccountManager::get()->m_accountID == GJAccountManager::get()->m_playerID ? -1 : 0; + if (loggedInOffset == -1 && !GameManager::get()->m_clickedName) { + // adjusts for the sprite asking for your name + loggedInOffset++; + } - setIDSafe(this, 2, "username-label"); - setIDSafe(this, 6 + loggedInOffset, "player-icon"); + setIDSafe(this, 0, "username-label"); + setIDSafe(this, 0, "player-icon"); auto winSize = CCDirector::get()->getWinSize(); From 0787b8f450d421d9c81f0782a1d70ec8128b9266 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Sun, 17 Dec 2023 22:33:32 -0300 Subject: [PATCH 20/21] message for a bug i cant recreate --- VERSION | 2 +- loader/src/hooks/SaveFileFix.cpp | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index d4c4950a..0c00f610 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.9 +1.3.10 diff --git a/loader/src/hooks/SaveFileFix.cpp b/loader/src/hooks/SaveFileFix.cpp index 2ed63e25..45b220b8 100644 --- a/loader/src/hooks/SaveFileFix.cpp +++ b/loader/src/hooks/SaveFileFix.cpp @@ -5,6 +5,17 @@ using namespace geode::prelude; #include +#include "../loader/LoaderImpl.hpp" + +void panic(std::string reason) { + LoaderImpl::get()->platformMessageBox("Critical", fmt::format( + "Your save file failed to load (reason: {})\n" + "As to not lose all of your data, the game will now abort.\n" + "Please backup your save files and try opening the game again, it might work.\n" + "Please contact the Geode Team about this", reason + )); + std::abort(); +} // This function is well known for crashing on certain save files, // causing the game to crash at startup, known as the infamous save file bug. @@ -14,23 +25,26 @@ using namespace geode::prelude; // // To fix this, we just rewrite the function. gd::string decompressString2(unsigned char* data, bool decrypt, int size, int decryptionKey) { - if (data == nullptr || size == 0 || *data == 0) { + log::debug("decompressString2 data={} size={}", reinterpret_cast(data), size); + if (data == nullptr || size == 0) { return {}; } + std::vector copiedData(data, data + size); if (decrypt) { for (int i = 0; i < size; i++) { - data[i] ^= decryptionKey; + copiedData[i] ^= decryptionKey; } } // TODO: maybe not use cocos's base64 and inflateMemory.. unsigned char* out = nullptr; - auto const decodedSize = cocos2d::base64Decode(data, size, &out); + auto const decodedSize = cocos2d::base64Decode(copiedData.data(), size, &out); std::unique_ptr b64decoded { out }; if (decodedSize <= 0) { + panic(fmt::format("base64 (size={}) (data={} size={})", decodedSize, reinterpret_cast(data), size)); return {}; } @@ -40,6 +54,7 @@ gd::string decompressString2(unsigned char* data, bool decrypt, int size, int de std::unique_ptr inflated { out }; if (inflatedSize <= 0) { + panic(fmt::format("inflate (size={}) (data={} size={})", inflatedSize, reinterpret_cast(data), size)); return {}; } From 0387314e35503a481c608900e166546f7436c104 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Sun, 17 Dec 2023 22:35:29 -0300 Subject: [PATCH 21/21] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25beccf2..d6e7a22f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Geode Changelog +## v1.3.10 + * Panic if decompressString2 fails, to prevent data loss (0787b8f4) + ## v1.3.9 * Fix followThunkFunction (4b766301)