Overview
Hooks allow scripts to intercept and modify data as it flows through Lich. There are two types:- UpstreamHook: Intercepts commands going from the client to the game server
- DownstreamHook: Intercepts data coming from the game server to the client
lib/common/upstreamhook.rb, lib/common/downstreamhook.rb
UpstreamHook
Intercepts and modifies commands before they’re sent to the game server.Class Methods
add
Register a new upstream hook with a unique name.Unique identifier for this hook
Proc that takes a string (the command) and returns a modified string or
nil to block the commandReturns
false if action is not a Proc, otherwise implicitly true- The Proc receives the command string as its argument
- Return a modified string to change the command
- Return
nilto block the command entirely - Hook is associated with the current script
- Overwrites any existing hook with the same name
remove
Remove a hook by name.Name of the hook to remove
The removed hook Proc, or
nil if not foundrun
Execute all registered hooks on a command string (called by framework).The command string to process through all hooks
The modified command string, or
nil if any hook blocked it- Runs hooks in order of registration
- Each hook receives the output of the previous hook
- If any hook returns
nil, processing stops andnilis returned - If a hook raises an exception, it’s automatically removed and an error is logged
list
Get names of all registered hooks.Array of hook names
sources
Display a formatted table of hooks and their source scripts.- Displays a table with columns “Hook” and “Source”
- Output is sent to the game client via
Lich::Messaging.mono
hook_sources
Get the raw mapping of hook names to source scripts.Hash mapping hook names to script names
DownstreamHook
Intercepts and modifies game server data before it reaches the client.Class Methods
add
Register a new downstream hook with a unique name.Unique identifier for this hook
Proc that takes a string (server data) and returns a modified string or
nil to block itReturns
false if action is not a Proc, otherwise implicitly true- The Proc receives a duplicate of the server string
- Return a modified string to change what the client sees
- Return
nilto block the data from reaching the client - Hook is associated with the current script
- Overwrites any existing hook with the same name
remove
Remove a hook by name.Name of the hook to remove
The removed hook Proc, or
nil if not foundrun
Execute all registered hooks on server data (called by framework).The server data to process through all hooks
The modified server string, or
nil if any hook blocked it- Runs hooks in order of registration
- Each hook receives the output of the previous hook (as a duplicate)
- If any hook returns
nilat any point, processing stops andnilis returned - If a hook raises an exception, it’s automatically removed and an error is logged
- Only processes string data (skips non-string server messages)
list
Get names of all registered hooks.Array of hook names
sources
Display a formatted table of hooks and their source scripts.- Displays a table with columns “Hook” and “Source”
- Output is sent to the game client via
Lich::Messaging.mono
hook_sources
Get the raw mapping of hook names to source scripts.Hash mapping hook names to script names
Examples
Upstream Hook: Command Logging
Upstream Hook: Command Aliasing
Upstream Hook: Blocking Commands
Downstream Hook: Highlighting
Downstream Hook: Filtering
Downstream Hook: Trigger Actions
Managing Hooks
Chaining Multiple Hooks
Hook Lifecycle
Registration
When you calladd, the hook is:
- Validated (must be a Proc)
- Associated with the current script name
- Stored with the given name (overwrites if exists)
Execution
When data flows through:- Framework calls
.run()with the data - Each hook processes the data in registration order
- Output of one hook becomes input to the next
- If any hook returns
nil, the chain stops
Error Handling
If a hook raises an exception:- The hook is automatically removed
- An error message is logged with the exception and first backtrace line
- Processing continues without that hook
Cleanup
Hooks should be removed when your script exits:Best Practices
Use Descriptive Names
Always Return or Explicitly Block
Clean Up on Exit
Don’t Modify the Original (Downstream)
DownstreamHook automatically passes a duplicate to your Proc, but avoid relying on mutation:Differences Between Upstream and Downstream
| Aspect | UpstreamHook | DownstreamHook |
|---|---|---|
| Data source | Client commands | Game server output |
| Data type | Always strings | Usually strings (skips non-strings) |
| Duplication | Receives original | Receives .dup |
| nil behavior | Stops chain immediately | Checks for nil before each hook |
| Use cases | Command aliasing, blocking, logging | Filtering, highlighting, triggers |
