Working with events#
Petrichor mods can exchange custom signals through Petrichor.Events, a shared pub/sub bus inside the single Luau VM. One mod publishes, and another subscribes without importing each other's files.
API details: Petrichor.Events. Mod helpers live on Script entry point.
Event names#
Publisher events are namespaced as <mod_id>:<event>:
mod("hello-cow")withself:fire("ready")fireshello-cow:ready.- A listener uses
self:on("ready", "hello-cow", fn)orEvents.on("hello-cow:ready", fn).
Use the id from mod.json as mod_id so load order and folder names do not matter.
Publisher#
Subscriber#
Register listeners from init so they are in place before other mods finish loading. Mod load order under mods/ is filesystem-dependent, so if you must react to another mod's startup event, subscribe early and handle a missed fire in tick or use a handshake event.
import * as Log from "Petrichor.Log"
declare function mod(name: string): any
const CowWatcher = mod("cow-watcher")
CowWatcher.init = function () {
this.once("ready", "hello-cow", (data: { version?: number }) => {
Log.info("cow-watcher", `hello-cow ready, version ${data.version}`)
})
}
export = CowWatcher
CReact panel actions#
When a mod panel calls emit("save", { value = 42 }), the host forwards it to Luau as Petrichor.Events on <modId>:save with the optional data table. Register listeners the same way as any other event:
Panel emits are delivered on the main Luau thread when the UI dispatches them. See Courage.UI and User Interfaces with CReact.
Direct module use#
When you need a custom channel or already know the full event string:
One-shot and cleanup#
once removes the listener after the first delivery. Use it for handshakes or single-use notifications.
off needs the same function reference you passed to on or once. Store the callback in self if you unsubscribe from shutdown:
Events vs hooks#
| Events | Hooks (before / after / replace) | |
|---|---|---|
| Purpose | Mod-to-mod messages | Intercept game functions |
| Registration | on / once on a string | before(sym, fn) on a symbol |
| Callback args | data only | self, ctx with hook context |
| Timing | When a mod calls fire | When the game calls the hooked function |
Use hooks to change game behavior. Use events to coordinate between your mods.
Limitations#
- All delivery runs on the main Luau thread during
fire. Keep listeners short. - No delivery guarantee across restarts, so pair with Petrichor.Storage if you need durable state.
- Host lifecycle callbacks (
pre_frame,post_frame,scene_load) exist on the C++PetrichorEventsAPI but are not yet exposed to Luau throughPetrichor.Events. Usetickand hooks for frame- and scene-level logic today.