-
Notifications
You must be signed in to change notification settings - Fork 42
Create custom-layers.md, update utils.md, and Create chap4_2 #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
39f2cf8
ed037bd
936086a
f58ee1d
ecf0772
8d0aa8b
47bc30c
ca5338f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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"); | ||
Chs000-00 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does not replace |
||
|
|
||
| ```cpp | ||
| static MyVeryOriginalLayer* scene() { | ||
| auto layer = MyVeryOriginalLayer::create(); | ||
| switchToScene(layer); | ||
| return layer; | ||
| } | ||
|
Comment on lines
+38
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. making a function that returns the layer yet switches to it is misleading, this would be better if it just created a scene with the layer and returned it additionally, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. heck i would recommend just the geode utils There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. without this function i mean, just call switchToScene where you need it, never liked ::scene funcs anyway |
||
| ``` | ||
|
|
||
| ## 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 <Geode/ui/General.hpp> | ||
|
|
||
| bool init() override { | ||
| log::info("Hi from my very original layer"); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should still call original here |
||
|
|
||
| // 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 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should call |
||
| auto backBtn = CCMenuItemSpriteExtra::create( | ||
| CCSprite::createWithSpriteFrameName("GJ_arrow_01_001.png"), | ||
| this, | ||
| menu_selector(MyVeryOriginalLayer::onBack) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. might alao recommend just using |
||
| ); | ||
|
|
||
| // 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())); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be a |
||
| } | ||
|
|
||
| ``` | ||
|
|
||
| > :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 <Geode/Geode.hpp> | ||
| #include <Geode/ui/General.hpp> | ||
| #include <Geode/modify/MenuLayer.hpp> | ||
| 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() { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suspicious extra qualification before the function name |
||
| 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(); | ||
| } | ||
| }; | ||
|
Comment on lines
+128
to
+179
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All the same things as before, should use |
||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
| ``` | ||
|
Comment on lines
+114
to
+131
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These comments are not really useful because you can already make these conclusions from the function names. it would be much more useful if there were examples of paths, "This is where geode is located" can be interpreted as either the |
||
|
|
||
| ## Tasks | ||
|
|
||
| Visit the [tasks](tasks.md) page for more information. | ||
|
|
@@ -304,4 +325,4 @@ timePointAsString` | |
|
|
||
| ### ColorProvider | ||
|
|
||
| No idea how to use this one. | ||
| No idea how to use this one. | ||
Uh oh!
There was an error while loading. Please reload this page.