Lifecycle Hooks

Audience: Foundry module developers augmenting SoHL actor/item behavior broadly — across many items or actors — without modifying SoHL source.

SoHL fires cancellable Foundry hooks around each phase of its data-preparation lifecycle. From a module you can listen to augment behavior, or return false from a pre* hook to replace a phase. For behavior on one specific item, prefer a Script Action instead — see Macros and Actions.

This page is the module-author entry point; the details live with the code that defines them:

  • The hook contract — the hook names, cancellable semantics, arguments, and worked Hooks.on(...) examples (listen and cancel) — is documented on SohlActor, which fires the hooks during data preparation.
  • The type strings in the hook names (sohl.<itemType>.… and sohl.actor.<actorType>.…) are ITEM_KIND and ACTOR_KIND.
  • The phase model — the three phases (initializeevaluatefinalize) and the barrier guarantees — is in SohlLogic; for the concept overview see Phase-batched lifecycle.

Minimal example

Hook names are sohl.<itemType>.<phase> (and sohl.actor.<actorType>.<phase>), where <phase> is preInitialize/postInitialize, preEvaluate/postEvaluate, or preFinalize/postFinalize.

// Augment: run after every mystical ability finishes evaluating.
Hooks.on("sohl.mysticalability.postEvaluate", (item, ctx) => {
  // item = the mysticalability item; ctx = SohlActionContext
  // read/adjust derived state here (not persisted)
});

// Replace: cancel the default initialize phase for a specific item.
Hooks.on("sohl.mysticalability.preInitialize", (item, ctx) => {
  if (item.system.shortcode !== "curse") return; // leave others alone
  // ...do the replacement work...
  return false; // returning false from a pre* hook cancels the phase
});

For persistent writes, guard them (next section). For a fuller worked example including a world-setting toggle, see House Rules Cookbook — Recipe 2.

Guarding persistent side effects

When a hook writes persistent state (documents, world settings), gate it behind a world-setting toggle and a GM-only check, so it runs under a single authority rather than once per connected client. See the worked recipe in House Rules Cookbook — guard pattern.

See also