Skip to content

Optional API v1

Cheeseworks edited this page May 16, 2026 · 1 revision

Are you a developer looking to partially integrate your mod into Horrible Menu's interface without the need of a required dependency? Well, you found the right place! The following guide teaches you how to register the metadata and handle toggling for your options.

Let's start off by adding this mod as a dependency in your mod.json!

"dependencies": {
    "cubicstudios.horriblemenu": {
        "version": ">=1.0.0",
        "required": false
    }
}

Tip

We recommend shortening include paths in your code by adding the the full path as a private include directory through your project's CMakeLists.txt file. The rest of the documentation will use this practice in its code samples.

target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/geode-deps/cubicstudios.horriblemenu/include)

You can directly access the Horrible Menu mod menu optional API by including the OptionalAPI.hpp file in your code. Make sure to include the horrible namespace to directly access all needed classes and methods.

#include <horrible/OptionalAPI.hpp>

using namespace horrible;

Options

The purpose of this mod is primarily focused on its huge list of togglable troll options. To create the metadata for an option, create a new horrible::OptionV2 object.

It's recommended to include all this logic inside an $on_game(Loaded) block due to optional dependency load order, and how this mod works with OptionV2 objects.

using namespace horrible;

$on_game(Loaded) {
    auto const myOption = OptionV2{
        .id="my-option"_spr,
        .name="My Very Cool Option",
        .description="A very detailed description about what this option does...",
        .category="My Stuff!",
        .silly=SillyTier::Low,
    };
};

Registering

To register an option via this version of the API, call OptionManagerV2::registerOption with your created option on game load.

using namespace horrible;

$on_game(Loaded) {
    auto const myOption = OptionV2{
        .id="my-option"_spr,
        .name="My Very Cool Option",
        .description="A very detailed description about what this option does...",
        .category="My Stuff!",
        .silly=SillyTier::Low,
    };

    OptionManagerV2::registerOption(myOption);
};

Handling

So, your options should now be registered. Great! Now, we can move to actually handling them functionally by listening to when they're being toggled.

Events

Option toggling can be listened to via the provided thread-safe, global event class, horrible::OptionEvent - which you can listen for on any thread, with or without a filter.

Filtering

Normally, you'd only want to filter through events that actually have to do with one option in some places. The event allows you to add ID for the option you would like to listen to specifically.

OptionEvent("my-option"_spr);

If you need to listen for global events, which will involve other mods' options, simply provide no ID to make it listen for every single toggle.

OptionEvent();

Listening on a Node

Listening to option events under a node is pretty straightforward.

    this->addEventListener(
        OptionEvent("my-option"_spr),
        [](HorribleOptionSave data) {
            log::info("{} is set to: {}", "my-option"_spr, data.enabled);
        });
    this->addEventListener(
        OptionEvent(),
        [](std::string_view id, HorribleOptionSave data) {
            log::info("{} is set to: {}", id, data.enabled);
        });

Utilities

There are a couple of utility functions you can use to conveniently listen for option toggle events globally.

listenForHorribleOptionChanges

Creates a listener for option toggles for one specific option.

using namespace horrible;

listenForHorribleOptionChanges(
    "my-option"_spr,
    [](HorribleOptionSave data) {
        log::info("{} is set to: {}", "my-option"_spr, data.enabled);
    }
);

Notice

Due to some quirks, if you'd like to immediately check for the state of your option on load, add a listener for your option right before you register it.

using namespace horrible;

$on_game(Loaded) {
    auto const myOption = OptionV2{
        .id="my-option"_spr,
        .name="My Very Cool Option",
        .description="A very detailed description about what this option does...",
        .category="My Stuff!",
        .silly=SillyTier::Low,
    };

    listenForHorribleOptionChanges(
        "my-option"_spr,
        [](HorribleOptionSave data) {
            // handle it here!
        }
    );

    OptionManagerV2::registerOption(myOption);
};

Conclusion

That should be all! Hopefully you got the gist of it! If not, feel free to join our Discord server and ask about anything that was potentially missing from here or that you did not fully understand. Happy modding!


API

v1

Planning

Clone this wiki locally