Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/geode-sdk/docs into main
Browse files Browse the repository at this point in the history
  • Loading branch information
HJfod committed Mar 16, 2023
2 parents 8a8b174 + 6d0e8ee commit e79a8bf
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 54 deletions.
12 changes: 6 additions & 6 deletions handbook/vol1/chap1_7.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ class $modify(MenuLayer) {
};
```

Everything Cocos2d-related lies in the `cocos2d` namespace, so we must prefix our usage of `CCLabelBMFont::create` with it. However, as you keep modding, having to stick `cocos2d::` everywhere gets annoying really fast. In addition, Geode comes with a bunch of namespaces you probably also don't want to rewrite every time. For this reason, Geode comes with a `USE_GEODE_NAMESPACE` macro that automatically brings all Cocos2d and Geode-related namespaces to scope:
Everything Cocos2d-related lies in the `cocos2d` namespace, so we must prefix our usage of `CCLabelBMFont::create` with it. However, as you keep modding, having to stick `cocos2d::` everywhere gets annoying really fast. In addition, Geode comes with a bunch of namespaces you probably also don't want to rewrite every time. For this reason, Geode provides a `geode::prelude` namespace that automatically brings all Cocos2d and Geode-related namespaces to scope:

```cpp
#include <Geode/modify/MenuLayer.hpp>

USE_GEODE_NAMESPACE();
using namespace geode::prelude;

class $modify(MenuLayer) {
bool init() {
Expand All @@ -81,7 +81,7 @@ Now, the label isn't currently a child of any layer, so it won't show up anywher
```cpp
#include <Geode/modify/MenuLayer.hpp>

USE_GEODE_NAMESPACE();
using namespace geode::prelude;

class $modify(MenuLayer) {
bool init() {
Expand All @@ -103,7 +103,7 @@ The default position for any node is (0, 0) which is at bottom left of the scree
```cpp
#include <Geode/modify/MenuLayer.hpp>

USE_GEODE_NAMESPACE();
using namespace geode::prelude;

class $modify(MenuLayer) {
bool init() {
Expand All @@ -125,7 +125,7 @@ Next, to actually position our label, we call the `setPosition` method on it, pl
```cpp
#include <Geode/modify/MenuLayer.hpp>

USE_GEODE_NAMESPACE();
using namespace geode::prelude;

class $modify(MenuLayer) {
bool init() {
Expand Down Expand Up @@ -157,7 +157,7 @@ And with that, **we have completed our Hello, World! mod**. Here's what the fina
```cpp
#include <Geode/modify/MenuLayer.hpp>
USE_GEODE_NAMESPACE();
using namespace geode::prelude;
class $modify(MenuLayer) {
bool init() {
Expand Down
4 changes: 2 additions & 2 deletions mods/savedata.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ template<>
struct json::Serialize<MyCustomSaveData> {
static MyCustomSaveData from_json(json::Value const& value) {
return MyCustomSaveData {
.x = value.as_object()["x"],
.y = value.as_object()["y"]
.x = value["x"].as_int(),
.y = value["y"].as_int()
};
}

Expand Down
4 changes: 2 additions & 2 deletions mods/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ First, to declare a custom setting, the mod should specify that the setting's ty
The first class that the mod needs to provide for the setting is one that inherits [SettingValue](/classes/geode/SettingValue). This class manages the current value of the setting as well as saving and loading that value.

```cpp
USE_GEODE_NAMESPACE();
using namespace geode::prelude;

class MySettingValue : public SettingValue {
// store the current value in some form.
Expand Down Expand Up @@ -151,7 +151,7 @@ The setting node is provided the current width of the setting layer available in
Whenever the value of the setting is changed using the node's controls, the node should call the `dispatchChanged` method to let Geode's UI know.
```cpp
USE_GEODE_NAMESPACE();
using namespace geode::prelude;
class MySettingNode : public SettingNode {
protected:
Expand Down
4 changes: 2 additions & 2 deletions tutorials/fetch.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Example:
```cpp
#include <Geode/utils/fetch.hpp>

USE_GEODE_NAMESPACE();
using namespace geode::prelude;

// download a- uh...
auto res = web::fetch("https://pastebin.com/raw/vNi1WHNF");
Expand All @@ -37,7 +37,7 @@ Creating an async web request is really simple:
```cpp
#include <Geode/utils/fetch.hpp>
USE_GEODE_NAMESPACE();
using namespace geode::prelude;
web::AsyncWebRequest()
.fetch("https://pastebin.com/raw/vNi1WHNF")
Expand Down
11 changes: 6 additions & 5 deletions tutorials/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,11 @@ This code works even if you have multiple `PlayerObject`s, and the counter is in

**Fields must be accessed through the `m_fields` member**. If you access them directly through `this`, you will get **undefined behaviour** (most likely a crash).

Fields are declared just like normal member variables, except that **default values must be applied in the constructor**.
Fields are declared just like normal member variables, even constructors and destructors work\*.

```cpp
class $modify(MyPlayerObject, PlayerObject) {
int m_totalJumps;

MyPlayerObject() : m_totalJumps(13) {}
class $modify(PlayerObject) {
int m_totalJumps = 13;

void pushButton(PlayerButton button) {
log::info("the player has jumped {} times !", m_fields->m_totalJumps);
Expand All @@ -51,3 +49,6 @@ class $modify(MyPlayerObject, PlayerObject) {
}
};
```

\* Fields are constructed and destructed in a different address than they exist normally (yes I know ub but we kinda need the space optimization), so if you have a class that depends on the value of this inside the constructor/destructor, I would recommend using `std::unique_ptr` to contain the said object. One such example would be Geode's events, since they are registered to a global map in their constructor.

98 changes: 68 additions & 30 deletions tutorials/modify.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class $modify(MyAwesomeModification, MenuLayer) {
};
```

The syntax for this is `class $modify(MyClassName, ClassToModify)`. It looks cool.
The syntax for this is `class $modify(MyClassName, ClassToModify)`.

Creating a `CCMenuItemSpriteExtra` takes a `SEL_MenuHandler`, which is a type alias for `void(cocos2d::CCObject::*)(cocos2d::CCObject*)` (which means a pointer to a member function that has a single parameter of CCObject\*). In order to supply this we need to get access to our function address, which requires us to know the class name. When we don't supply a class name, the macro generates a class which is guaranteed to not create any collision problems. [Read more about menu selectors here](/tutorials/buttons.md)

Expand All @@ -102,19 +102,12 @@ You still need to call the base destructor itself for calling the original.
**This pattern is the same for constructors.**
# Adding members
Geode allows you to add members to your modified classes to extend GD classes nearly seamlessly. [Learn more about fields](/tutorials/fields.md)
# Advanced usage
## Using without macros
Creating a modification uses the `$modify` macro but if you are a cool kid you can not use it. Here is how:
If you need to refrain from using the `$modify` macro (clang-format really cries when it sees the macro so), here is how you would do it:
```cpp
class MyCoolModification : public MenuLayer {
public:
struct MyCoolModification : Modify<MyCoolModification, MenuLayer> {
void onMoreGames(CCObject* target) {
FLAlertLayer::create(
"Geode",
Expand All @@ -123,34 +116,80 @@ public:
)->show();
}
};
Modify<MyCoolModification, MenuLayer> someDummyName;
```

It wasn't that bad was it?
Yeah we improved the clean usage a lot, and honestly I prefer this over the macro. But who am I to judge?

## Adding delegates
# Adding members

Geode allows you to add members to your modified classes to extend GD classes nearly seamlessly. [Learn more about fields](/tutorials/fields.md)

We currently don't have a shortcut way of implementing this, sorry. But if you need it for some reason here is how you would do it:
# Advanced usage

## Accessing the hooks

Even with this ~~sugary~~ (wow i hate that word) clean syntax hooking, there are still some stuff we can't do without a way of interacting with the hooks, like giving it a priority, manually enabling/disabling even though I'm against it. That's why there is the `onModify` function. This function is called when the hooks are registered to Geode, more specifically the static constructor time of the mod load. Here is how:

```cpp
class $modify(MyComplicatedClass, MenuLayer) {
struct TextInput : TextInputDelegate {
TextInput(MyComplicatedClass* ptr) : self(ptr) {}
MyComplicatedClass* self;
void textChanged(CCTextInputNode* node) {
self->m_fields->myString = node->getString();
class $modify(MenuLayer) {
static void onModify(auto& self) {
auto res = self.getHook("MenuLayer::init");
if (!res) {
log::error("Something went horribly wrong");
return;
}
log::info("I hooked {}!", res.unwrap()->getDisplayName());
}

TextInput input;
bool init() {
if (!MenuLayer::init()) return false;
log::debug("Hi mom I made a modding framework with some friends!")
return true;
}
};
```

See the ModifyBase<ModifyDerived> class to see what functions are available (there aren't much to be honest). Also please don't manually enable/disable hooks unless you need to. Oh also did I tell you to never manually enable/disable hooks? Do you still need it? Well, you will need to use `Hook::setAutoEnable` for Geode to not automatically enable your hooks when the mod is enabled, so have fun with that I guess. Just one more thing: please don't manually enable/disable your hooks unless you have to.

## Setting hook priority

You might want to do this because your code may need to run before others ([Geode string id system](/tutorials/nodetree.md) for example). Or you don't call the original so you might want your function to get called last. This is where the priority system is helpful. Here is how you use it:

```cpp
class $modify(GJGarageLayer) {
static void onModify(auto& self) {
self.setHookPriority("GJGarageLayer::init", 1024);
}

bool init() {
if (!GJGarageLayer::init()) return false;
NodeIDs::get()->provide(this);
return true;
}
};
```

## Adding delegates

Even though it is kinda inconvenient, this is how you would do it. Be careful about that comment!

```cpp
struct MyDelegateClass : Modify<MyDelegateClass, MenuLayer>, TextInputDelegate {
MenuLayer* self;
std::string myString;

void textChanged(CCTextInputNode* node) override {
// here, this points to m_fields, so you will need that self
// variable in order to access the MenuLayer itself
myString = node->getString();
}

bool init() {
if (!MenuLayer::init()) return false;
m_fields->input = this;
m_fields->self = this;

auto input = CCTextInputNode::create(250, 20, "Enter text", "bigFont.fnt");
input->setDelegate(&m_fields->input);
input->setDelegate(m_fields.self());
input->setPosition(100, 100);
this->addChild(input);

Expand All @@ -169,13 +208,12 @@ class $modify(MyComplicatedClass, MenuLayer) {
## Adding new virtual functions
We currently don't support this yet, but here is how you *would* do it anyway:
We currently don't support this yet, but here is how you *would* do it anyway (I promise I will add this soon :tm:):
```cpp
class $modify(CopyPlayerObject, PlayerObject) {
template <class Modify>
void onApplyModification(Modify modify) {
modify.registerVirtualFunction(&CopyPlayerObject::copyWithZone);
static void onModify(auto& self) {
self.registerVirtual(&CopyPlayerObject::copyWithZone);
}
CCObject* copyWithZone(CCZone* zone) {
Expand Down Expand Up @@ -203,7 +241,7 @@ class $modify(MenuLayer) {
};
```
This will result in an infinite loop, because `this->` calls the $modified MenuLayer's `onMoreGames` instead of the original's. Name the class you're calling the function from instead (`MenuLayer::onMoreGames`).
This will result in an infinite loop, because `this->` calls the modified MenuLayer's `onMoreGames` instead of the original's. Name the class you're calling the function from instead (`MenuLayer::onMoreGames`).
## Accidental not recursion
Expand Down Expand Up @@ -251,7 +289,7 @@ class $modify(MyBrokenClass, MenuLayer) {
};
```

This will result in the modification getting called twice when you press the newly created button, then the original function will be called.
This will result in the modification getting called twice when you press the newly created button, then the original function will be called. (MyBrokenClass::onMoreGames -> handler -> MyBrokenClass::onMoreGames -> handler -> MenuLayer::onMoreGames)

## Not supplying the correct signature

Expand All @@ -268,4 +306,4 @@ class $modify(MenuLayer) {
};
```
This will result in not modifying the intended function at all, because `onMoreGames` has return type `void` in MenuLayer, not `bool`.
This will result in not modifying the intended function at all, because `onMoreGames` has return type `void` in MenuLayer, not `bool`. I previously tried to implement a check for this in the old version of the modify, but failed miserably. I should honestly try again, but I'm kinda scared that it may increase compile times.
11 changes: 4 additions & 7 deletions usagein10steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,11 @@ In order for mods to do something, they need to place hooks. If you are new to m
```cpp
// this magical syntax is basically just the entry point, like int main()
$on_mod(Loaded) {
Mod::get()->addHook(Hook::create(
Mod::get(),
reinterpret_cast<void*>(geode::base::get() + address),
Mod::get()->addHook<tulip::hook::ThiscallConvention>(
reinterpret_cast<void*>(base::get() + address),
&myAwesomeHook,
"My awesome hook!",
{},
{}
));
"My awesome hook!"
);
}
```
However, as this is quite verbose and having to manually specify all of your hooks kinda blows, Geode comes with incredibly magical syntactic sugar known as **`$modify`**:
Expand Down

0 comments on commit e79a8bf

Please sign in to comment.