Hook Points & Bus Topics
The two systems answer different questions. Hooks ask permission: handlers run in priority order (default priority 100, ties keep registration order), share one mutable context table, and any false return (or error, unless the point is FailOpen) cancels the action. Bus topics announce facts: handlers get (topic, ...), run independently, and cannot cancel anything. Both registries create points and topics on first use, so your own names cost nothing to add.
The mechanics live on Hooks and Signals & Bus. Everything below is verified against the framework source (Hooks:fire, Bus:publish call sites). Entries marked † are fired or published by the source but absent from the README’s central catalog table — each is documented on its owning module’s page.
Hook points fired by the framework
Section titled “Hook points fired by the framework”All server-side.
Core points
Section titled “Core points”| Point | Context | Mode | Fired |
|---|---|---|---|
Intent.<Channel> |
{Name, Player, Session, Args, Seq?} |
fail-closed | Before every intent handler (NetDriver). Validators may rewrite Args (clamp, normalize) — the handler receives the mutated copy |
Request.<Channel> |
{Name, Player, Session, Args} |
fail-closed | Before every request handler (NetDriver); a rejection answers the client with the channel’s RejectValue |
Intent.BusPublish.<Topic> |
{Name, Player, Session, Args} |
fail-closed | Client-to-server bus publish (BusBridge), after the exact-name whitelist and rate limit |
Session.Start / Session.End |
{Session, Player} |
observational | Player join/leave (Sessions). The kernel ignores the verdict, but handlers run synchronously before the matching bus topic — seed per-player state here and bus subscribers already see it |
Net.RateLimited |
{Player, Channel} |
fail-open | A channel’s token bucket rejected a message (Rate limiting) |
Net.FloodDetected |
{Player, Bytes, PayloadBytes, BudgetBytes} |
fail-open | The transport dropped a client that blew its byte budget (Rate limiting) |
AntiExploit.MovementViolation |
{Player, Session, Type, HorizontalSpeed, Displacement, Strikes} |
fail-open | A movement sample failed validation (Movement monitor) |
Intent.Interact |
{Session, Player, Id, Instance, Definition} |
fail-closed | Every prompt trigger (InteractionKit); the kit’s distance/line-of-sight/cooldown gate sits at priority 50 |
Kit channels are ordinary intents, so their points follow the same shape — Intent.WK_Fire, Intent.SK_Cast, Intent.Checkpoint, Intent.Settings_Set — and you prepend rules at lower priority numbers without forking the kit.
Kit gate hooks †
Section titled “Kit gate hooks †”Fail-open policy gates the kits fire before acting on an already-validated request. Fail-open here is deliberate: these carry game rules (tournament locks, safe zones, friendly fire), and a crashing rule handler should not brick the kit’s core loop. Return false to veto.
| Point | Context | Mode | Fired |
|---|---|---|---|
Inventory.CanEquip |
{Session, Id, SlotName} |
fail-open | Before an equip mutates the bag (InventoryKit) |
Inventory.CanUse |
{Session, Id, SlotIndex} |
fail-open | Before an item’s OnUse runs (InventoryKit) |
Craft.CanCraft |
{Session, RecipeId, Station} |
fail-open | Before inputs are taken — verify the claimed station here (CraftingKit) |
Companion.CanSummon |
{Session, CompanionId} |
fail-open | Before a summon — gate ownership here (CompanionKit) |
Party.CanInvite |
{From, To} |
fail-open | Before an invite is created (PartyKit) |
Melee.CanHit |
{Attacker, Victim, Attack} |
fail-open | On every hit-frame candidate — TeamKit registers friendly-fire vetoes here at priority 40 (MeleeKit) |
Weapon.CanDamage |
{Session, Attacker, Victim, WeaponId, Weapon} |
fail-open | Before a validated shot deals damage — TeamKit plugs friendly-fire policy in here (WeaponKit) |
Bus topics published by the framework
Section titled “Bus topics published by the framework”Handlers receive (topic, ...); the args below follow the topic name.
Kernel, sessions & data
Section titled “Kernel, sessions & data”| Topic | Args | Published when |
|---|---|---|
Kernel.SessionStart / Kernel.SessionEnd |
session |
Join/leave; SessionEnd fires before the session object is destroyed, so bound state is still readable (Sessions) |
Kernel.ProfileLoaded |
session, profile |
DataDriver finished loading a player’s profile |
Kernel.ProfileRestored |
session, profile |
A corrupt or unmigratable record was restored from backup — tell the player, ping your webhook (DataDriver) |
Kernel.ScriptError |
message, trace, source, count |
ErrorWatch captured (or re-counted) a script error |
Kernel.Overload |
statsSnapshot |
Diagnostics saw deferred work three windows in a row — the scheduler is saturated (Kernel & boot) |
Kernel.SoftShutdown |
playerCount |
Update migration is about to teleport everyone out (SoftShutdown) |
Commerce.PurchaseGranted |
player, productId, purchaseId |
A receipt was processed — exactly once per purchase (Receipts) |
Networking
Section titled “Networking”| Topic | Args | Published when |
|---|---|---|
Intent.<Channel> |
session, ...validatedArgs |
AFTER an accepted intent ran — the observational twin of the hook chain (NetDriver) |
Net.IntentRejected |
player, channelName |
A validator, missing guard, or crashing handler rejected an intent (NetDriver) |
Net.RateLimited |
player, channelName |
Token bucket rejection (Rate limiting) |
Net.FloodDetected |
player, bytes, payloadBytes, budgetBytes |
Transport-level flood drop (Rate limiting) |
Security
Section titled “Security”| Topic | Args | Published when |
|---|---|---|
AntiExploit.MovementViolation |
player, violationType, strikes |
A movement strike was recorded (Movement monitor) |
Gameplay systems
Section titled “Gameplay systems”| Topic | Args | Published when |
|---|---|---|
Zone.Entered / Zone.Left |
zoneName, player |
A player crossed a zone boundary — leaves fire before enters (Zones) |
Zone.EntityEntered / Zone.EntityLeft |
zoneName, entity |
A tracked entity (NPC, prop, vehicle) crossed a zone boundary (Zones) |
Effects.Applied |
player, effectName, stacks |
Effect applied or stacked (Effects) |
Effects.Expired |
player, effectName |
Effect expired or was removed (Effects) |
Effects.Blocked † |
player, effectName, byEffect |
An apply was blocked by a holding Immune ward (Effects) |
Effects.Cleansed † |
player, category?, count |
A cleanse removed count effects (Effects) |
Projectile.Hit |
ownerSession, victim, defId, position |
A server-simulated projectile landed (Projectiles) |
Config.Changed |
key, value |
LiveConfig saw a new value (local set or remote poll) |
Settings.Changed |
session, key, value |
A setting was written — client intent or server set (Player settings) |
Matchmaking.Queued / Matchmaking.Dequeued |
player, queueName |
Queue membership changed (Matchmaking) |
Matchmaking.MatchFound / Matchmaking.TeleportFailed |
queueName, members |
Match lifecycle (Matchmaking) |
Ragdoll.Started / Ragdoll.Ended |
model |
A ragdoll engaged / restored (Ragdoll) |
Leaderboard.Updated † |
boardName, entries |
A board’s cached page refreshed (Leaderboards) |
| Topic | Args | Published when |
|---|---|---|
Round.PhaseChanged |
phaseName, duration |
RoundKit advanced a phase |
Obby.Checkpoint |
player, stage |
CheckpointKit accepted a checkpoint |
Spell.Cast / Spell.Interrupted |
session, spellId |
SpellKit outcome |
Weapon.Fired / Weapon.Hit |
(session, weaponId, origin, direction) / (session, victim, weaponId, position) |
WeaponKit accepted a shot / landed a hit |
Weapon.ShotRejected |
player, reason |
WeaponKit refused a shot |
Quest.Progress |
player, questId, objectiveIndex, count, required |
An objective advanced (QuestKit) |
Quest.Completed |
player, questId |
Every objective met — Repeatable quests reset after (QuestKit) |
Interact.Triggered / Interact.Rejected |
(session, id, instance) / (player, id) |
A prompt interaction passed / failed validation (InteractionKit) |
Procedural.Spawned / Procedural.Removed |
archetypeName, model |
Runtime geometry lifecycle (ProceduralKit) |
Procedural.Updated |
archetypeName, model, appliedParams |
A parameter batch applied and the model regenerated (ProceduralKit) |
Procedural.Rejected |
archetypeName, param, error |
A parameter failed validation (ProceduralKit) |
Inventory.Granted † |
session, id, granted |
A grant landed — granted is the count that fit (InventoryKit) |
Inventory.Taken † |
session, id, count |
An all-or-nothing take succeeded (InventoryKit) |
Inventory.Equipped / Inventory.Unequipped † |
session, slotName, id |
An equip slot changed (InventoryKit) |
Inventory.Used † |
session, id, slotIndex |
An OnUse item was consumed (InventoryKit) |
Inventory.Changed † |
session |
Any bag mutation — fires alongside the owner’s INV_Sync push (InventoryKit) |
Loot.Rolled † |
tableName, items, session? |
A table was rolled — session is nil for playerless roll() (LootKit) |
Loot.Awarded † |
session, tableName, granted, overflow |
An award() granted through InventoryKit (LootKit) |
Craft.Started † |
session, recipeId, finishAt |
A timed craft queued (CraftingKit) |
Craft.Completed † |
session, recipeId, output |
A craft finished and the output granted (CraftingKit) |
Craft.Cancelled † |
session, recipeId |
A craft was cancelled — inputs refunded (CraftingKit) |
Craft.Overflow † |
session, recipeId, overflow |
Output that could not fit the bag (CraftingKit) |
Shop.Bought † |
session, shopId, itemId, granted, cost |
A buy granted and charged (ShopKit) |
Shop.Sold † |
session, shopId, itemId, count, payout |
A sell took items and paid out (ShopKit) |
Shop.Rejected † |
player, shopId, itemId, reason |
A buy/sell refused (ShopKit) |
Companion.Summoned † |
session, companionId, npc |
A companion spawned (CompanionKit) |
Companion.Dismissed † |
session, companionId |
Dismissed by the owner or replaced by a new summon (CompanionKit) |
Companion.Died † |
session, companionId |
The companion’s NPC died (CompanionKit) |
Party.Created / Party.Disbanded † |
party / partyId |
A party formed on first accept / hit zero members (PartyKit) |
Party.Joined / Party.Left † |
party, player |
Membership changed (PartyKit) |
Party.Kicked / Party.Promoted † |
party, member |
Leader action — promote also fires on leader inheritance (PartyKit) |
Party.Invited † |
from, target |
An invite was created (PartyKit) |
Team.Assigned † |
player, team, previous? |
A team assignment — auto-balance or explicit assign (TeamKit) |
Melee.Hit † |
attacker, victim, attackName, damage |
A hit frame connected (MeleeKit) |
Melee.Blocked † |
victim, attacker, attackName, chippedDamage |
A block absorbed a hit (MeleeKit) |
Melee.GuardBroken † |
victim, attacker, attackName |
A guard-break shattered a block (MeleeKit) |
Melee.Parried † |
parrier, attacker, attackName |
A timed parry killed the swing (MeleeKit) |
Melee.Staggered † |
entity, seconds |
A stagger applied (MeleeKit) |
Melee.Combo † |
entity, chainLength |
A combo chained through ComboNext (MeleeKit) |
Melee.State † |
entity, state |
A combatant’s state machine changed (MeleeKit) |
Move.Used † |
session, name, position |
MoveKit.server accepted a metered ability use (MoveKit) |
Move.Rejected † |
player, name, reason |
The server’s charge/cooldown books refused ("Charges" or "Cooldown") (MoveKit) |
Npc.Spawned / Npc.Died |
npc |
NPCKit lifecycle — Died precedes the despawn delay |
Npc.Action |
npc, actionName, target |
A moveset action executed (NPCKit) |
Npc.Heard |
npc, heardPosition, source? |
A sound survived range/occlusion for this npc — position pre-blurred by its skill (NPCKit) |
Npc.Suspicious † |
npc, target, glimpsedPosition |
Graded detection reached half charge — the npc glimpsed something (NPCKit) |
Npc.Damaged † |
npc, attacker? |
The npc registered damage — aim suppressed, unseen attackers drop into hearing memory (NPCKit) |
Npc.Reload † |
npc, actionName, seconds |
A magazine emptied and the reload pause started (NPCKit) |
Npc.Windup † |
npc, actionName, target, windupSeconds |
A telegraphed melee windup started — the dodge window (NPCKit) |
Npc.Path |
npc, waypoints |
A new route was computed (full list, own position first) — hook for path visualization (NPCKit) |
Npc.Hitscan |
npc, origin, hitPosition, victim? |
A hitscan action fired (hit or miss) — hook for tracers (NPCKit) |
Npc.Defense |
npc, reactionName, success, context |
A defensive reaction attempt — deflect flash or fumble, hook VFX here (NPCKit) |
Npc.Tactic |
npc, tactic |
Director/behavior state flip: Pressure/Flank/Suppress/Cover/Peek/Flee — hook client animation polish (NPCKit) |
Client & media
Section titled “Client & media”Published on the kernel the module is attached to — for these, typically the client.
| Topic | Args | Published when |
|---|---|---|
Input.<Action> |
state, inputObject |
Client-side — an InputDriver action changed state |
Move.Triggered † |
name, context |
Client-side — a MoveKit ability passed its context gate and ran |
Audio.Cue |
soundName, cueName, handle |
Playback crossed a registered cue time, loop-aware (AudioKit) |
Audio.Subtitle / Audio.SubtitleEnded |
(text, duration) / () |
Dialogue line started / finished — wire your subtitle UI here (AudioKit) |
Anim.Marker |
model, animName, markerName, param |
An animation marker fired on a rig (AnimKit) |
Preload.Started / Preload.Progress / Preload.Done |
(total) / (loaded, total, assetId, ok) / (loaded, total, failed) |
Asset warm-up lifecycle — wire your loading screen here (Preload) |
Device.Benchmarked † |
result |
A DeviceBench run completed (cached thereafter) |
Device.QualityChanged † |
quality, profile |
The DeviceBench governor dialed effective quality up or down (DeviceBench) |
Hair.Rigged † |
character, meshPart, boneNames |
HairKit baked a skeleton into a hair mesh |
Consumed topics
Section titled “Consumed topics”One topic is consumed rather than published: publish AntiExploit.Forgive with (player) right before a legit server-side teleport and the next movement sample is pardoned. MoveKit (abilities with Forgive = true) and TeamKit (spawn pivots) publish it for you. See Movement monitor.