diff --git a/handbook/vol4/chap4_2.md b/handbook/vol4/chap4_2.md new file mode 100644 index 00000000..2f663dde --- /dev/null +++ b/handbook/vol4/chap4_2.md @@ -0,0 +1,32 @@ +# 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](https://github.com/geode-sdk/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()) { + // This code will only run if you are in a level + // level is a pointer to your current 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 diff --git a/tutorials/custom-layers.md b/tutorials/custom-layers.md new file mode 100644 index 00000000..7adfbfb5 --- /dev/null +++ b/tutorials/custom-layers.md @@ -0,0 +1,180 @@ +# 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 { + + if (!CCLayer::init()) { + // Something very bad happened + return false; + } + + 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; + } + 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 Buttons should be added to here. + auto menu = CCMenu::create(); + + // Using geode's built in utils for creating side art and background makes it easier for other mods to modify & change them. + // It is recommended to use these instead of manually adding them some other way. + + // Add side art to the layer + geode::addSideArt(this, SideArt::All, SideArtStyle::Layer); + + // And a background to the layer + auto background = geode::createLayerBG(); + background->setID("background"); + this->addChild(background); + return true; +} +``` + +The rest of the buttons and UI can be created the same way you would in a hook. + +> :warning: Button elements must be in 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 whose 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) + ); + + // Not adding this function will disable keyBackClicked from being called. + // This makes it impossible to exit levels with the backspace key. + this->setKeypadEnabled(true); + + // 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! +void keyBackClicked() override { + this->onBack(nullptr); +} + +void 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); + 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())); + } + +} + +class $modify(MenuLayer) { + void onMoreGames(CCObject* target) { + MyVeryOriginalLayer::scene(); + } +}; +``` diff --git a/tutorials/utils.md b/tutorials/utils.md index 934ada32..aa7d4c28 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::dirs + +```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. @@ -304,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.