Skip to content

Developer Events Hooks Guide

Hands-on subscribing, emitting, and naming. Concepts: Core Events. Catalog: Hooks Reference.

local token = greg.on("greg.Audio.AudioManager.SetEffectsVolume", function(payload)
greg.ui.log_info("Volume changed!")
end)
greg.once("greg.PLAYER.CoinChanged", function(payload) ... end)
greg.off(token) -- unsubscribe early; otherwise auto-removed at shutdown/reload

Payload shape (via PayloadToTable): { hook_name, timestamp, cancelable, cancelled, data } — read args from payload.data.

greg.fire("my_mod.job_done", { result = "ok", count = 3 })
greg.on("my_mod.job_done", function(payload)
local n = payload.data["count"]
end)

Use your mod ID as prefix (my_mod.*) to avoid collisions. Document your custom events in your README.

greg.hooks.groups() -- all 22 groups
greg.hooks.audio.list() -- hook IDs in Audio
greg.hooks.networking.list()

Per-group sugar (generated by LuaHookBindingGenerator from game_hooks.json):

greg.hooks.<group>.on_<snake_case_method>(callback)
-- e.g. greg.hooks.audio.on_set_effects_volume(fn)
-- full ID form: "greg.Audio.AudioManager.SetEffectsVolume"
[GregHook("greg.PLAYER.CoinChanged")]
public void OnCoins(EventPayload payload) { … }
// or manually (inside a GregMod: tracked, IDisposable):
IDisposable sub = On("greg.Group.Event", payload => { /* ... */ });
// dispose in OnUnload (or DisposeSubscriptions for all at once)

Native lifecycle hooks (gregNativeEventHooks): SystemGameLoaded / SystemGameSaved, GameLoaded / GameSaved, Money / Xp / ReputationChanged, Day / MonthEnded. Numeric IDs 1001–4001 (EventIds, GetByEventId) appear in examples/ — prefer string IDs in new code.

  • Full game-hook ID: greg.{Group}.{Class}.{Method} (matches game_hooks.json rows 1:1).
  • Curated mod-level names: greg.{Domain}.{Event} (greg.PLAYER.CoinChanged, greg.RACK.*, greg.SYSTEM.ButtonCheckOut).
  • Your own: <modId>.<snake_event> with a stable payload table; never rename a shipped event — add a new one.
  • Cancelable semantics: only set cancelled where the dispatcher marks the hook cancelable; document it.
  1. Confirm game_hooks.json sits next to gregCore.dll (“No hooks found” = misplaced file).
  2. Check [DynamicPatcher] lines in the loader log — installed vs failed patches.
  3. Subscribe minimally in the F12 REPL first, then move working code into main.lua.
  4. Suspect a game update? Re-dump + regenerate (tools/GameApiGenerator, Generate-GregHooksFromIl2CppDump.ps1), then scripts/validate_contracts.py.