Manual Hooks

Sometimes, you need to hook some platform specific function that would be a hassle to manually add to bindings - or you want to provide support for adding hooks through other means than $modify, such as an embedded scripting language. In this case, you can also manually add hooks in Geode using Mod::addHook.

Example

The provided example hooks MenuLayer::onNewgrounds on Windows.

⚠️ This function can be hooked normally using $modify - this is just an example! Do not do this!

void MenuLayer_onNewgrounds(MenuLayer* self, CCObject* sender) {
    log::info("Hook reached!");
    // You can call the original by calling it - in this case, since the 
    // original is in bindings, you can just call it the same way as you 
    // would with $modify
    // TODO: How to call original manually
    self->onNewgrounds(sender);
    log::info("After original!");
}

$execute {
    Mod::get()->hook(
        reinterpret_cast<void*>(geode::base::get() + 0x191E90), // address
        &MenuLayer_onNewgrounds, // detour
        "MenuLayer::onNewgrounds", // display name, shows up on the console
        tulip::hook::TulipConvention::Thiscall // calling convention
    );
}

Hooking an imported function

This example shows how to hook a function that is linked to, for example through DLL imports. Geode comes with the addresser namespace for utilities related to figuring out the addresses of linked functions, including class methods and virtual functions.

void myDrawCircle(const cocos2d::CCPoint& center, float radius, float angle, unsigned int segments, bool drawLineToCenter) {
    // Call the original
    cocos2d::ccDrawCircle(center, radius, angle, segments, drawLineToCenter);
    log::info("alright {}", radius);
}

$execute {
    Mod::get()->hook(
        reinterpret_cast<void*>(
            // All of this is to get the address of ccDrawCircle
            geode::addresser::getNonVirtual(
                // This is used because this function is overloaded,
                // otherwise just a regular function pointer would suffice (&foobar)
                geode::modifier::Resolve<const cocos2d::CCPoint&, float, float, unsigned int, bool>::func(&cocos2d::ccDrawCircle)
            )
        ),
        &myDrawCircle, // Our detour
        "cocos2d::ccDrawCircle", // Display name, shows up on the console
        tulip::hook::TulipConvention::Cdecl // Static free-standing cocos2d functions are cdecl
    );
}