Fix small issues, update example in modding.md to show scoped hooks

This commit is contained in:
jdflyer
2026-08-07 15:27:23 -07:00
parent 4aa3b647a3
commit ce6850acd3
3 changed files with 44 additions and 22 deletions
+29 -15
View File
@@ -648,40 +648,54 @@ dusklight when their condition is met.
Note: for any gamemode wishing to use the vanilla set of savefiles, use `gczelda2` as the save file name.
```cpp
// An example that shows registering a gamemode with function hooks that are scoped to the gamemode being active
IMPORT_SERVICE(LogService, svc_log);
IMPORT_SERVICE(HookService, svc_hook);
IMPORT_SERVICE(GamemodeService, svc_gamemode);
#define MY_GAMEMODE_ID "gamemodeid"
#define ONLY_GAMEMODE(ctx, id) \
{ \
bool isGamemodeActive; \
svc_gamemode->is_active(ctx, id, &isGamemodeActive); \
if (!isGamemodeActive) { \
return HOOK_CONTINUE; \
} \
}
#define ONLY_GAMEMODE_MYGAMEMODE ONLY_GAMEMODE(ctx, MY_GAMEMODE_ID)
static HookAction myFunctionHook(ModContext *ctx, void *args, void *, void *) {
// Note: normal function hooks will need to check if the gamemode is active
ONLY_GAMEMODE_MYGAMEMODE // A macro like this can make it easy
// Code that runs when only the Gamemode is active
// If we wish to have this hook only run while the gamemode is registered, we need to hook the function from the
// gamemode's onActivatedFunction, and uninstall the hook during the onDeactivatedFunction. An example is given below
return HOOK_CONTINUE;
}
DEFINE_HOOK(fopAcM_createItem, CreateItem);
void onGamemodeActivated() {
// Setup the gamemode, Add any hooks that are gamemode specific
// Overlay any files that are gamemode specific
ModResult result = mods::hook_add_pre<CreateItem>(svc_hook, myFunctionHook);
if (result != MOD_OK) {
svc_log->error(mod_ctx, "failed to install hook to fopAcM_createItem");
}
}
void onGamemodeDeactivated() {
// Uninstall any hooks that are gamemode specific
// Remove overlays to any files that are gamemode specific
ModResult result = mods::hook_uninstall<CreateItem>();
if (result != MOD_OK) {
svc_log->error(mod_ctx, "failed to uninstall CreateItem hook");
}
}
void onSaveLoaded() {
// This function will be invoked by the game as a save is loaded
}
// Register the gamemode when the mod is initialized
const GamemodeDesc gamemodeDesc = {
.gamemodeId = MY_GAMEMODE_ID,
.fullName = "Gamemode Name",
// The save name should be something that other gamemodes will not try to use, so appending your name to it
// is reccomended
.saveName = "my-unique-save-name_developer-name",
.onActivatedFunction = nullptr, // Called when the gamemode is selected on the prelaunch menu (or is launched)
.onDeactivatedFunction = nullptr, // Called when the gamemode is deselected on the prelaunch menu (or the mod is disabled)
.onActivatedFunction = onGamemodeActivated, // Called when the gamemode is selected on the prelaunch menu (or is launched)
.onDeactivatedFunction = onGamemodeDeactivated, // Called when the gamemode is deselected on the prelaunch menu (or the mod is disabled)
.onPlayFunction = nullptr, // Called when "Play" is pressed on the prelaunch menu
.onSaveLoadedFunction = onSaveLoaded, // Called when a save is loaded
.onNewSaveFunction = nullptr, // Called after a new savefile is created
+4 -2
View File
@@ -95,13 +95,15 @@ MenuBar::MenuBar()
dismiss(modal);
return;
}
dismiss(modal);
if (gamemode::getGamemodeManager().getRegisteredGamemodes().size() > 1) {
// If we have gamemodes registered, show pre-launch on a menubar reset
prelaunch_state().showPrelaunchOnReset = true;
Document::hide(true);
}else {
hide(false);
}
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
dismiss(modal);
Document::hide(true);
},
},
},
+11 -5
View File
@@ -728,6 +728,8 @@ int game_main(int argc, char* argv[]) {
saveConfigBeforePrelaunch = true;
}
bool skipPreLaunchUI = dusk::getSettings().backend.skipPreLaunchUI.getValue();
std::string dvd_path = dusk::getSettings().backend.isoPath;
bool dvd_opened = false;
if (parsed_arg_options.count("dvd")) {
@@ -744,6 +746,7 @@ int game_main(int argc, char* argv[]) {
dusk::DiscVerificationState::Unknown);
dusk::config::save();
dusk::IsGameLaunched = true;
skipPreLaunchUI = true;
}
} else {
DuskLog.warn("DVD image from command line failed validation: {}, opening prelaunch UI", dvd_path);
@@ -751,8 +754,6 @@ int game_main(int argc, char* argv[]) {
}
}
bool skipPreLaunchUI = dusk::getSettings().backend.skipPreLaunchUI.getValue();
// If we can't load right into the game, stop requesting to load a stage or save
if (forcePreLaunchUI || dvd_path.empty()) {
if (dusk::StageRequested.set) {
@@ -907,9 +908,14 @@ int game_main(int argc, char* argv[]) {
dusk::speedrun::registerSpeedrunGamemode();
}
if (skipPreLaunchUI == true && dusk::gamemode::getGamemodeManager().getRegisteredGamemodes().size() > 1 && dusk::getSettings().backend.skipPreLaunchUI.getValue()) {
// Force pre-launch if we have registered gamemodes that we need to choose from
dusk::ui::push_document(std::make_unique<dusk::ui::Prelaunch>(), true);
if (skipPreLaunchUI == true) {
if (dusk::gamemode::getGamemodeManager().getRegisteredGamemodes().size() > 1 && dusk::getSettings().backend.skipPreLaunchUI.getValue()) {
// Force pre-launch if we have registered gamemodes that we need to choose from
dusk::ui::push_document(std::make_unique<dusk::ui::Prelaunch>(), true);
} else {
// If we get back to prelaunch later, tell it that we've already started the game
dusk::ui::prelaunch_state().firstLaunch = false;
}
}
OSReport("Starting main01 (Game Loop)...\n");