From 39f2cf8da276571f4c20276e21f8622d05813926 Mon Sep 17 00:00:00 2001 From: Igbalabanov <101612094+Chs000-00@users.noreply.github.com> Date: Sun, 26 Jan 2025 11:22:33 -0800 Subject: [PATCH 1/7] Create custom-layers.md --- tutorials/custom-layers.md | 155 +++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 tutorials/custom-layers.md diff --git a/tutorials/custom-layers.md b/tutorials/custom-layers.md new file mode 100644 index 0000000..c477902 --- /dev/null +++ b/tutorials/custom-layers.md @@ -0,0 +1,155 @@ +# Custom Layers + +At some point a modder may want to create a custom layer for their mod, for one reason or another. + + +Creating a new scene is easy. You must create a new class extending `cocos2d:::CCLayer`, and add additional UI (such as buttons, popups, or even a level) by overriding the the `*::init` function. + +```cpp +class MyVeryOriginalLayer : public CCLayer { +protected: + bool init() override { + log::info("Hi from my very original layer"); + } + +public: + static MyVeryOriginalLayer* create() { + auto ret = new MyVeryOriginalLayer; + if (ret->init()) { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; + } +} +``` + +This code will create a new layer called MyVeryOriginalLayer. When we start up the game, we will not see the layer as we do transition to it. Calling `MyVeryOriginalLayer::create()` will not transition to the layer, as it only creates it, not replaces the current layer. To be able to transition to the layer, we can use `switchToScene(layer)`. We can create a static function to easily create and switch to the scene: + +```cpp +static MyVeryOriginalLayer* scene() { + auto layer = MyVeryOriginalLayer::create(); + switchToScene(layer); + return layer; +} +``` + +## UI + +Running this code and calling `MyVeryOriginalLayer::scene()` will transition the current scene to MyVeryOriginalLayer, however it is currently very barren. Geode provides utility functions to create background and side art. + +``` +#include + +bool init() override { + log::info("Hi from my very original layer"); + + // Create a new menu. UI elemnts should be added to here! + menu = CCMenu::create(); + + // Add side art to the layer + addSideArt(this, SideArt::All, SideArtStyle::Layer); + + // And a background to the layer + auto background = createLayerBG(); + background->setID("background"); + this->addChild(background); +} +``` + +The rest of the buttons and UI can be created the same way you would in a hook. + +> :warning: UI elements should **always** be added to a CCMenu object! + + +## Back button + +Now the biggest problem with this layer is that you are stuck in it. To go back you would want to create a button whoes callback transitions to another scene. + +```cpp + +bool init() override { + + // Create a back button with the back button sprites + auto backBtn = CCMenuItemSpriteExtra::create( + CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"), + this, + menu_selector(MyVeryOriginalLayer::onBack) + ); + + + // Add a back button the the top-left corner of the screen with a small offset. + menu->addChildAtPosition(backBtn, Anchor::TopLeft, {25, -25}); + this->addChild(menu); +} + +// This function is called when the escape key is pressed! +void LobbiesLayer::keyBackClicked() override { + this->onBack(nullptr); +} + +void LobbiesLayer::onBack(CCObject* sender) { + CCDirector::get()->replaceScene(CCTransitionFade::create(0.5, MenuLayer::scene())); +} + +``` + +> :information_source: You can also create a back button with `GameToolbox::addBackButton` + +> :warning: Pressing escape will **not transition the layer** back unless you override `keyBackClicked()`! + + + +## Example + +This code will transition to the MyVeryOriginalLayer when clicking the on more games button. + +```cpp +#include +#include +#include +using namespace geode::prelude; + +class MyVeryOriginalLayer : public CCLayer { +protected: + bool init() override { + log::info("Hi from my very original layer"); + + // Create a new menu. UI elemnts should be added to here! + menu = CCMenu::create(); + + // Add side art to the layer + addSideArt(this, SideArt::All, SideArtStyle::Layer); + + // And a background to the layer + auto background = createLayerBG(); + background->setID("background"); + this->addChild(background); + } + +public: + static MyVeryOriginalLayer* create() { + auto ret = new MyVeryOriginalLayer; + if (ret->init()) { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; + } + + static MyVeryOriginalLayer* MyVeryOriginalLayer::scene() { + auto layer = MyVeryOriginalLayer::create(); + switchToScene(layer); + return layer; + } + +} + +class $modify(MenuLayer) { + void onMoreGames(CCObject* target) { + MyVeryOriginalLayer::scene(); + } +}; +``` \ No newline at end of file From ed037bd855598b594f4d90a1bcc50e46dd7eea76 Mon Sep 17 00:00:00 2001 From: Igbalabanov <101612094+Chs000-00@users.noreply.github.com> Date: Sun, 26 Jan 2025 12:09:36 -0800 Subject: [PATCH 2/7] Sort of chap4_2? --- handbook/vol4/chap4_2.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 handbook/vol4/chap4_2.md diff --git a/handbook/vol4/chap4_2.md b/handbook/vol4/chap4_2.md new file mode 100644 index 0000000..80be007 --- /dev/null +++ b/handbook/vol4/chap4_2.md @@ -0,0 +1,31 @@ +# Chapter 4.2: Searching through the docs + +At some point or another, you will need to find a class to hook or a function to call. This chapter explains how to search through the geode classes tab. + +## Seaching for classes +Geode docs have a useful "classes" tab to search for classes. If you do not know what class something is, it is best to search through devtools first, then search it up the docs. However, if devtools does not tell you the classname, then you would have to find the class yourself. + +## I found a class! What now? +Congrats! You can now hook the object by copying the signiture of the function! [Geode's vscode](https://marketplace.visualstudio.com/items?itemName=GeodeSDK.geode) extension provides autocomplete for function signatures, so it is recommended to use that. + +## But what if I want to get said object from another object? +Most objects have either a `::get()` or a `::sharedState()` (or even both [Note 1]!) static function. Most of the time, this function will return the object, however if the object does not exist, it will return a nullptr. +c++ lets you check if an object is nullptr and run code if it does exist. + +```cpp +if (auto level = GJBaseGameLayer::get()) { + // If you are in a level, run this code with level being the level +} + +else { + // Otherwise, run this code. +} +``` + +If the object does not have a `::get()` method, you would need to find another way to get it. + +> :warning: Enums do not appear in the search! You would need to find them some other way! + +> :warning: Some functions may be inlined on some platforms! Hooking them would cause a compilation error. You would need to find some other function to hook. + +> [Note 1] `::get()` and `::sharedState()` methods act the **exact same** on most classes with both of them From 936086a6770f78ca5a5283e6abe73bd82a36896f Mon Sep 17 00:00:00 2001 From: Igbalabanov <101612094+Chs000-00@users.noreply.github.com> Date: Sun, 26 Jan 2025 12:25:31 -0800 Subject: [PATCH 3/7] geode::dirs::* --- tutorials/utils.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tutorials/utils.md b/tutorials/utils.md index 934ada3..56c313a 100644 --- a/tutorials/utils.md +++ b/tutorials/utils.md @@ -109,6 +109,27 @@ auto hook1 = GEODE_UNWRAP(ObjcHook::create("EAGLView", "initWithFrame:", &MyFunc auto hook2 = GEODE_UNWRAP(ObjcHook::create("EAGLView", "initWithFrame:", &MyFunc, &emptyFunc)); ``` +### geode::dir + +```cpp +// This is where geode is located! +auto geodeDir = dirs::getGeodeDir(); + +// This is where geodes resources are stored! +auto geodeResourcesDir = dirs::getGeodeResourcesDir(); + +// This is where geodes saves its files! +auto geodeSaveDir = dirs::getGeodeSaveDir(); + +// This is where mod's save files are! +auto modSaveDir = dirs::getModsSaveDir(); + +// This is where GD saves its files! +auto saveDir = dirs::getSaveDir(); + +// Other directories also exist +``` + ## Tasks Visit the [tasks](tasks.md) page for more information. From f58ee1deeede480b797af2a3f24740b7b553caac Mon Sep 17 00:00:00 2001 From: Igbalabanov <101612094+Chs000-00@users.noreply.github.com> Date: Sun, 26 Jan 2025 12:41:26 -0800 Subject: [PATCH 4/7] whoops --- tutorials/custom-layers.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tutorials/custom-layers.md b/tutorials/custom-layers.md index c477902..36745ff 100644 --- a/tutorials/custom-layers.md +++ b/tutorials/custom-layers.md @@ -85,11 +85,11 @@ bool init() override { } // This function is called when the escape key is pressed! -void LobbiesLayer::keyBackClicked() override { +void keyBackClicked() override { this->onBack(nullptr); } -void LobbiesLayer::onBack(CCObject* sender) { +void onBack(CCObject* sender) { CCDirector::get()->replaceScene(CCTransitionFade::create(0.5, MenuLayer::scene())); } @@ -127,6 +127,11 @@ protected: background->setID("background"); this->addChild(background); } + + // This function is called when the escape key is pressed! + void keyBackClicked() override { + this->onBack(nullptr); + } public: static MyVeryOriginalLayer* create() { @@ -144,6 +149,11 @@ public: switchToScene(layer); return layer; } + + + void onBack(CCObject* sender) { + CCDirector::get()->replaceScene(CCTransitionFade::create(0.5, MenuLayer::scene())); + } } From ecf0772741e3c4ba158bef9ca4f60c2dd02d06bc Mon Sep 17 00:00:00 2001 From: Igbalabanov <101612094+Chs000-00@users.noreply.github.com> Date: Sat, 22 Feb 2025 08:36:22 -0800 Subject: [PATCH 5/7] Update custom-layers.md Fix no return statement --- tutorials/custom-layers.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tutorials/custom-layers.md b/tutorials/custom-layers.md index 36745ff..56acb03 100644 --- a/tutorials/custom-layers.md +++ b/tutorials/custom-layers.md @@ -10,6 +10,7 @@ class MyVeryOriginalLayer : public CCLayer { protected: bool init() override { log::info("Hi from my very original layer"); + return true; } public: @@ -52,9 +53,10 @@ bool init() override { addSideArt(this, SideArt::All, SideArtStyle::Layer); // And a background to the layer - auto background = createLayerBG(); - background->setID("background"); - this->addChild(background); + auto background = createLayerBG(); + background->setID("background"); + this->addChild(background); + return true; } ``` @@ -82,6 +84,7 @@ bool init() override { // Add a back button the the top-left corner of the screen with a small offset. menu->addChildAtPosition(backBtn, Anchor::TopLeft, {25, -25}); this->addChild(menu); + return true; } // This function is called when the escape key is pressed! @@ -126,6 +129,7 @@ protected: auto background = createLayerBG(); background->setID("background"); this->addChild(background); + return true; } // This function is called when the escape key is pressed! From 8d0aa8baa7639f3730aba2290818de58db3ad5d1 Mon Sep 17 00:00:00 2001 From: Igbalabanov <101612094+Chs000-00@users.noreply.github.com> Date: Mon, 3 Mar 2025 13:54:15 -0800 Subject: [PATCH 6/7] Update utils.md --- tutorials/utils.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tutorials/utils.md b/tutorials/utils.md index 56c313a..aa7d4c2 100644 --- a/tutorials/utils.md +++ b/tutorials/utils.md @@ -109,7 +109,7 @@ auto hook1 = GEODE_UNWRAP(ObjcHook::create("EAGLView", "initWithFrame:", &MyFunc auto hook2 = GEODE_UNWRAP(ObjcHook::create("EAGLView", "initWithFrame:", &MyFunc, &emptyFunc)); ``` -### geode::dir +### geode::dirs ```cpp // This is where geode is located! @@ -325,4 +325,4 @@ timePointAsString` ### ColorProvider -No idea how to use this one. \ No newline at end of file +No idea how to use this one. From 47bc30cb23e91a2904e6dbf778d887653c1e746c Mon Sep 17 00:00:00 2001 From: Igbalabanov <101612094+Chs000-00@users.noreply.github.com> Date: Mon, 3 Mar 2025 13:57:53 -0800 Subject: [PATCH 7/7] Fix indentation --- tutorials/custom-layers.md | 167 ++++++++++++++++++------------------- 1 file changed, 83 insertions(+), 84 deletions(-) diff --git a/tutorials/custom-layers.md b/tutorials/custom-layers.md index 56acb03..37bd594 100644 --- a/tutorials/custom-layers.md +++ b/tutorials/custom-layers.md @@ -8,21 +8,21 @@ Creating a new scene is easy. You must create a new class extending `cocos2d:::C ```cpp class MyVeryOriginalLayer : public CCLayer { protected: - bool init() override { - log::info("Hi from my very original layer"); - return true; - } + bool init() override { + log::info("Hi from my very original layer"); + return true; + } public: - static MyVeryOriginalLayer* create() { - auto ret = new MyVeryOriginalLayer; - if (ret->init()) { - ret->autorelease(); - return ret; - } - CC_SAFE_DELETE(ret); - return nullptr; - } + static MyVeryOriginalLayer* create() { + auto ret = new MyVeryOriginalLayer; + if (ret->init()) { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; + } } ``` @@ -44,19 +44,19 @@ Running this code and calling `MyVeryOriginalLayer::scene()` will transition the #include bool init() override { - log::info("Hi from my very original layer"); - - // Create a new menu. UI elemnts should be added to here! - menu = CCMenu::create(); - - // Add side art to the layer - addSideArt(this, SideArt::All, SideArtStyle::Layer); - - // And a background to the layer - auto background = createLayerBG(); - background->setID("background"); - this->addChild(background); - return true; + log::info("Hi from my very original layer"); + + // Create a new menu. UI elemnts should be added to here! + menu = CCMenu::create(); + + // Add side art to the layer + addSideArt(this, SideArt::All, SideArtStyle::Layer); + + // And a background to the layer + auto background = createLayerBG(); + background->setID("background"); + this->addChild(background); + return true; } ``` @@ -72,19 +72,18 @@ Now the biggest problem with this layer is that you are stuck in it. To go back ```cpp bool init() override { - - // Create a back button with the back button sprites - auto backBtn = CCMenuItemSpriteExtra::create( - CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"), - this, - menu_selector(MyVeryOriginalLayer::onBack) - ); - - - // Add a back button the the top-left corner of the screen with a small offset. - menu->addChildAtPosition(backBtn, Anchor::TopLeft, {25, -25}); - this->addChild(menu); - return true; + // Create a back button with the back button sprites + auto backBtn = CCMenuItemSpriteExtra::create( + CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"), + this, + menu_selector(MyVeryOriginalLayer::onBack) + ); + + + // Add a back button the the top-left corner of the screen with a small offset. + menu->addChildAtPosition(backBtn, Anchor::TopLeft, {25, -25}); + this->addChild(menu); + return true; } // This function is called when the escape key is pressed! @@ -116,54 +115,54 @@ using namespace geode::prelude; class MyVeryOriginalLayer : public CCLayer { protected: - bool init() override { - log::info("Hi from my very original layer"); - - // Create a new menu. UI elemnts should be added to here! - menu = CCMenu::create(); - - // Add side art to the layer - addSideArt(this, SideArt::All, SideArtStyle::Layer); - - // And a background to the layer - auto background = createLayerBG(); - background->setID("background"); - this->addChild(background); - return true; - } - - // This function is called when the escape key is pressed! - void keyBackClicked() override { - this->onBack(nullptr); - } + bool init() override { + log::info("Hi from my very original layer"); + + // Create a new menu. UI elemnts should be added to here! + menu = CCMenu::create(); + + // Add side art to the layer + addSideArt(this, SideArt::All, SideArtStyle::Layer); + + // And a background to the layer + auto background = createLayerBG(); + background->setID("background"); + this->addChild(background); + return true; + } + + // This function is called when the escape key is pressed! + void keyBackClicked() override { + this->onBack(nullptr); + } public: - static MyVeryOriginalLayer* create() { - auto ret = new MyVeryOriginalLayer; - if (ret->init()) { - ret->autorelease(); - return ret; - } - CC_SAFE_DELETE(ret); - return nullptr; - } - - static MyVeryOriginalLayer* MyVeryOriginalLayer::scene() { - auto layer = MyVeryOriginalLayer::create(); - switchToScene(layer); - return layer; - } - - - void onBack(CCObject* sender) { - CCDirector::get()->replaceScene(CCTransitionFade::create(0.5, MenuLayer::scene())); - } - + static MyVeryOriginalLayer* create() { + auto ret = new MyVeryOriginalLayer; + if (ret->init()) { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; + } + + static MyVeryOriginalLayer* MyVeryOriginalLayer::scene() { + auto layer = MyVeryOriginalLayer::create(); + switchToScene(layer); + return layer; + } + + + void onBack(CCObject* sender) { + CCDirector::get()->replaceScene(CCTransitionFade::create(0.5, MenuLayer::scene())); + } + } class $modify(MenuLayer) { - void onMoreGames(CCObject* target) { - MyVeryOriginalLayer::scene(); - } + void onMoreGames(CCObject* target) { + MyVeryOriginalLayer::scene(); + } }; -``` \ No newline at end of file +```