From 4505b0da69c4234d03dc457d832a0282186e7429 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Mon, 22 Apr 2024 00:09:49 +0300 Subject: [PATCH 1/3] i hate concepts (alternate fields impl) --- loader/include/Geode/modify/Field.hpp | 66 +++++++++++++++++++++++++-- loader/test/main/main.cpp | 23 ++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/loader/include/Geode/modify/Field.hpp b/loader/include/Geode/modify/Field.hpp index d67d5d52..30cbe28e 100644 --- a/loader/include/Geode/modify/Field.hpp +++ b/loader/include/Geode/modify/Field.hpp @@ -51,6 +51,11 @@ namespace geode::modifier { GEODE_DLL size_t getFieldIndexForClass(char const* name); + template <class Parent> + concept HasFields = requires { + typename Parent::Fields; + }; + template <class Parent, class Base> class FieldIntermediate { using Intermediate = Modify<Parent, Base>; @@ -61,7 +66,7 @@ namespace geode::modifier { public: // the constructor that constructs the fields. // we construct the Parent first, - static void fieldConstructor(void* offsetField) { + static void fieldConstructor(void* offsetField) requires (!HasFields<Parent>) { std::array<std::byte, sizeof(Parent)> parentContainer; auto parent = new (parentContainer.data()) Parent(); @@ -75,7 +80,7 @@ namespace geode::modifier { ); } - static void fieldDestructor(void* offsetField) { + static void fieldDestructor(void* offsetField) requires (!HasFields<Parent>) { std::array<std::byte, sizeof(Parent)> parentContainer; auto parent = new (parentContainer.data()) Intermediate(); @@ -89,7 +94,7 @@ namespace geode::modifier { static_cast<Parent*>(parent)->Parent::~Parent(); } - operator Parent*() { + operator Parent*() requires (!HasFields<Parent>) { // get the this pointer of the base // field intermediate is the first member of Modify // meaning we canget the base from ourself @@ -119,11 +124,11 @@ namespace geode::modifier { ); } - Parent* self() { + Parent* self() requires (!HasFields<Parent>) { return this->operator Parent*(); } - Parent* operator->() { + Parent* operator->() requires (!HasFields<Parent>) { // workaround for "static assertion is not an integral constant expression" in CLion // while the solution in https://github.com/microsoft/STL/issues/3311 works, you can't provide // cli args to clang-tidy in clion, so we use this workaround instead @@ -135,6 +140,57 @@ namespace geode::modifier { return reinterpret_cast<Parent*>(69420); #else return this->operator Parent*(); +#endif + } + + static void fieldConstructor(void* offsetField) requires (HasFields<Parent>) { + (void) new (offsetField) Parent::Fields(); + } + + static void fieldDestructor(void* offsetField) requires (HasFields<Parent>) { + static_cast<Parent::Fields*>(offsetField)->~Fields(); + } + + auto self() requires (HasFields<Parent>) { + // get the this pointer of the base + // field intermediate is the first member of Modify + // meaning we canget the base from ourself + auto node = reinterpret_cast<Parent*>(reinterpret_cast<std::byte*>(this) - sizeof(Base)); + static_assert(sizeof(Base) == offsetof(Parent, m_fields), "offsetof not correct"); + + // generating the container if it doesn't exist + auto container = FieldContainer::from(node, typeid(Base).name()); + + // the index is global across all mods, so the + // function is defined in the loader source + static size_t index = getFieldIndexForClass(typeid(Base).name()); + + // the fields are actually offset from their original + // offset, this is done to save on allocation and space + auto offsetField = container->getField(index); + if (!offsetField) { + offsetField = container->setField( + index, sizeof(typename Parent::Fields), &FieldIntermediate::fieldDestructor + ); + + FieldIntermediate::fieldConstructor(offsetField); + } + + return reinterpret_cast<typename Parent::Fields*>(offsetField); + } + + auto operator->() requires (HasFields<Parent>) { + // workaround for "static assertion is not an integral constant expression" in CLion + // while the solution in https://github.com/microsoft/STL/issues/3311 works, you can't provide + // cli args to clang-tidy in clion, so we use this workaround instead + // https://youtrack.jetbrains.com/issue/CPP-27446/spurious-offsetof-in-staticassert-error-from-clangd#focus=Comments-27-8172811.0-0 + // update: that workaround didn't work, + // undefining and re-defining offsetof caused another error further down + // so we're doing this now +#ifdef __CLION_IDE__ + return reinterpret_cast<Parent::Fields*>(69420); +#else + return this->self(); #endif } }; diff --git a/loader/test/main/main.cpp b/loader/test/main/main.cpp index 1262dc3b..64dba2ef 100644 --- a/loader/test/main/main.cpp +++ b/loader/test/main/main.cpp @@ -114,3 +114,26 @@ struct GJGarageLayerTest : Modify<GJGarageLayerTest, GJGarageLayer> { return true; } }; + + +#include <Geode/modify/GJGarageLayer.hpp> + +struct GJGarageLayerTest2 : Modify<GJGarageLayerTest2, GJGarageLayer> { + struct Fields { + int myOtherValue = 80085; + }; + + bool init() { + if (!GJGarageLayer::init()) return false; + + if (m_fields->myOtherValue == 80085) { + auto label = CCLabelBMFont::create("Alternate Fields works!", "bigFont.fnt"); + label->setPosition(100, 60); + label->setScale(.4f); + label->setZOrder(99999); + this->addChild(label); + } + + return true; + } +}; From 8db0e3965193f3939140b3a26d9b995b46463cf8 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Mon, 22 Apr 2024 00:20:54 +0300 Subject: [PATCH 2/3] use Fields for geode fields --- loader/src/hooks/LoadingLayer.cpp | 12 +++++++----- loader/src/hooks/MenuLayer.cpp | 6 ++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/loader/src/hooks/LoadingLayer.cpp b/loader/src/hooks/LoadingLayer.cpp index 8822c4da..c633f098 100644 --- a/loader/src/hooks/LoadingLayer.cpp +++ b/loader/src/hooks/LoadingLayer.cpp @@ -11,11 +11,13 @@ using namespace geode::prelude; struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> { - bool m_menuDisabled; - CCLabelBMFont* m_smallLabel = nullptr; - CCLabelBMFont* m_smallLabel2 = nullptr; - int m_geodeLoadStep = 0; - int m_totalMods = 0; + struct Fields { + bool m_menuDisabled = false; + CCLabelBMFont* m_smallLabel = nullptr; + CCLabelBMFont* m_smallLabel2 = nullptr; + int m_geodeLoadStep = 0; + int m_totalMods = 0; + }; static void onModify(auto& self) { if (!self.setHookPriority("LoadingLayer::init", geode::node_ids::GEODE_ID_PRIORITY)) { diff --git a/loader/src/hooks/MenuLayer.cpp b/loader/src/hooks/MenuLayer.cpp index 2ff81663..b3af97a6 100644 --- a/loader/src/hooks/MenuLayer.cpp +++ b/loader/src/hooks/MenuLayer.cpp @@ -52,8 +52,10 @@ struct CustomMenuLayer : Modify<CustomMenuLayer, MenuLayer> { GEODE_FORWARD_COMPAT_DISABLE_HOOKS_INNER("MenuLayer stuff disabled") } - bool m_menuDisabled; - CCSprite* m_geodeButton; + struct Fields { + bool m_menuDisabled = false; + CCSprite* m_geodeButton = nullptr; + }; bool init() { if (!MenuLayer::init()) return false; From 0a3efd77049e88cc01ae70fb4363cc5297eeb763 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Mon, 22 Apr 2024 00:22:40 +0300 Subject: [PATCH 3/3] more typename --- loader/include/Geode/modify/Field.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/loader/include/Geode/modify/Field.hpp b/loader/include/Geode/modify/Field.hpp index 30cbe28e..ea90f4a0 100644 --- a/loader/include/Geode/modify/Field.hpp +++ b/loader/include/Geode/modify/Field.hpp @@ -144,11 +144,11 @@ namespace geode::modifier { } static void fieldConstructor(void* offsetField) requires (HasFields<Parent>) { - (void) new (offsetField) Parent::Fields(); + (void) new (offsetField) typename Parent::Fields(); } static void fieldDestructor(void* offsetField) requires (HasFields<Parent>) { - static_cast<Parent::Fields*>(offsetField)->~Fields(); + static_cast<typename Parent::Fields*>(offsetField)->~Fields(); } auto self() requires (HasFields<Parent>) { @@ -188,7 +188,7 @@ namespace geode::modifier { // undefining and re-defining offsetof caused another error further down // so we're doing this now #ifdef __CLION_IDE__ - return reinterpret_cast<Parent::Fields*>(69420); + return reinterpret_cast<typename Parent::Fields*>(69420); #else return this->self(); #endif