The Middleware component provides a middleware layer for intercepting events, enabling logging, monitoring, data collection, and side-effects when events fire.
Overview
Middleware handlers are registered for specific events and execute in priority order when that event is triggered. They are used for:
Intercept Events Run code when events fire
Log Activity Log all event activity automatically
Collect Data Gather data from multiple handlers
Side Effects Trigger additional actions on events
Important: Middleware handlers in TriggerEvent run all registered handlers regardless of return values. Middleware does NOT block or prevent event execution — it runs side-effects alongside events.
Methods
Add
Register middleware for a specific event.
Middleware : Add ( eventName , handler , priority )
Name of the event to intercept
Middleware function to execute. Parameters:
source (number) - Player who triggered event (if applicable)
... - Additional event parameters
Execution priority (lower numbers execute first)
Example:
-- Log all player connections
Middleware : Add ( "playerConnecting" , function ( source , name , setKickReason , deferrals )
Logger : Info ( "Connections" , string.format ( "Player connecting: %s" , name ), {
console = true ,
file = true
})
end , 50 )
TriggerEvent
Trigger all middleware handlers for an event. All handlers run in priority order — errors in one handler do not stop others.
Middleware : TriggerEvent ( eventName , source , ... )
Player source (or 0 if not player-related)
Additional parameters passed to all handlers
Behavior:
Handlers are sorted by priority (lowest first)
Each handler runs via pcall — errors are caught and printed, never crash the server
All handlers run regardless — return values are ignored
Errors print to console: [Middleware] ERROR in 'eventName' handler (priority X): error message
Example:
-- Framework internally triggers middleware
Middleware : TriggerEvent ( "Characters:Spawning" , source , characterData )
TriggerEventWithData
Trigger middleware and collect return values from all handlers into a combined table. This is used when you need handlers to contribute data.
local data = Middleware : TriggerEventWithData ( eventName , source , ... )
Returns: A combined table of all handler return values. Each handler should return an array of tables. Each returned item gets an ID field assigned for ordering.
Handler return format:
-- Handler should return an array of tables
Middleware : Add ( "myEvent" , function ( source , ...)
return {
{ name = "Item 1" , value = 100 },
{ name = "Item 2" , value = 200 }
}
end )
Example — collecting menu items from multiple resources:
-- Resource A registers middleware
Middleware : Add ( "interaction:getOptions" , function ( source , targetId )
return {
{ label = "Search" , action = "search" },
{ label = "Frisk" , action = "frisk" }
}
end , 10 )
-- Resource B registers middleware
Middleware : Add ( "interaction:getOptions" , function ( source , targetId )
return {
{ label = "Give Keys" , action = "givekeys" }
}
end , 20 )
-- Triggering code collects all options
local options = Middleware : TriggerEventWithData ( "interaction:getOptions" , source , targetId )
-- options = {
-- { label = "Search", action = "search", ID = 1 },
-- { label = "Frisk", action = "frisk", ID = 2 },
-- { label = "Give Keys", action = "givekeys", ID = 3 }
-- }
Priority System
Lower priority numbers execute first:
-- Priority 1 - Executes FIRST (default)
Middleware : Add ( "event" , handler1 )
-- Priority 10 - Executes SECOND
Middleware : Add ( "event" , handler2 , 10 )
-- Priority 100 - Executes THIRD
Middleware : Add ( "event" , handler3 , 100 )
The default priority is 1 if not specified.
Recommended Priorities:
Priority Use Case Example 1-10 Critical handlers, security Anti-cheat logging 11-50 Core system handlers Permission logging 51-100 General logging, monitoring Activity logs 101+ Low-priority processing Analytics
Common Use Cases
Logging Player Actions
-- Log all admin actions
Middleware : Add ( "Admin:Action" , function ( source , action , target , details )
Logger : Info ( "Admin" , string.format (
"%s performed %s on %s" ,
GetPlayerName ( source ),
action ,
tostring ( target )
), {
console = true ,
file = true ,
discord = true
})
end , 50 )
Tracking Connections
-- Log player connections with identifiers
Middleware : Add ( "playerConnecting" , function ( source , name , setKickReason , deferrals )
Logger : Info ( "Connections" , string.format ( "Player connecting: %s (source: %s)" , name , source ), {
console = true ,
file = true ,
database = true
}, {
name = name ,
source = source ,
timestamp = os.time ()
})
end , 50 )
Economy Monitoring
-- Log money transactions
Middleware : Add ( "Finance:Transaction" , function ( source , amount , type , target )
Logger : Info ( "Economy" , string.format (
"Transaction: $%d (%s) from %s to %s" ,
amount , type , tostring ( source ), tostring ( target )
), {
console = true ,
file = true
})
end , 100 )
Anti-Cheat Detection Logging
-- Log suspicious events
Middleware : Add ( "AntiCheat:Detection" , function ( source , cheatType , details )
Logger : Critical ( "AntiCheat" , string.format (
"Detection: %s by source %s" ,
cheatType , tostring ( source )
), {
console = true ,
file = true ,
discord = {
embed = true ,
type = "critical" ,
title = "Anti-Cheat Detection" ,
content = "@here Cheater detected"
},
database = true
}, {
source = source ,
cheatType = cheatType ,
details = details ,
timestamp = os.time ()
})
end , 1 )
Collecting Data from Multiple Resources
-- Each job resource contributes its duty status
Middleware : Add ( "Jobs:GetDutyStatus" , function ( source , ...)
local policeOnDuty = GetPoliceOnDuty ()
return {
{ job = "police" , onDuty = # policeOnDuty , players = policeOnDuty }
}
end , 10 )
Middleware : Add ( "Jobs:GetDutyStatus" , function ( source , ...)
local emsOnDuty = GetEMSOnDuty ()
return {
{ job = "ems" , onDuty = # emsOnDuty , players = emsOnDuty }
}
end , 20 )
-- Collect all duty info
local dutyInfo = Middleware : TriggerEventWithData ( "Jobs:GetDutyStatus" , 0 )
-- dutyInfo contains entries from all registered handlers
Error Handling
Middleware handlers are wrapped in pcall. If a handler errors:
The error is printed to console with the event name and priority
Other handlers continue to execute — one error does not stop the chain
For TriggerEventWithData, errored handlers contribute nothing to the result
^1[Middleware] ERROR in 'playerConnecting' handler (priority 50): attempt to index a nil value^7
Resource Restart Behavior
Middleware handlers are cleared when any resource starts (except the current resource). This means:
Handlers are re-registered when resources restart
Stale handlers from stopped resources are cleaned up automatically
Best Practices
Use Appropriate Priorities
-- ✅ Good: Critical logging first
Middleware : Add ( "event" , securityLog , 1 )
Middleware : Add ( "event" , generalLog , 50 )
Middleware : Add ( "event" , analytics , 200 )
Keep Handlers Lightweight
Middleware runs on every event trigger. Keep handlers fast: -- ✅ Good: Quick logging
Middleware : Add ( "event" , function ( source , data )
Logger : Info ( "Monitor" , "Event fired" , { file = true })
end , 100 )
-- ❌ Bad: Heavy database query in middleware
Middleware : Add ( "event" , function ( source , data )
Database . Game : find ({ collection = "all_data" , query = {} }, function ( success , results )
-- This is too slow for middleware
end )
end , 100 )
Use TriggerEventWithData for Data Collection
When you need handlers to contribute data, use TriggerEventWithData: -- ✅ Good: Return data arrays for collection
Middleware : Add ( "getOptions" , function ( source , target )
return {
{ label = "Option A" , callback = "doA" },
{ label = "Option B" , callback = "doB" }
}
end )
local options = Middleware : TriggerEventWithData ( "getOptions" , source , target )
For plain side-effects (logging, notifications), use TriggerEvent instead.
Middleware Cannot Block Events
Unlike some frameworks, Mythic middleware does NOT support blocking: -- ❌ This does NOT prevent the event from firing
Middleware : Add ( "event" , function ( source , data )
return false -- Return value is IGNORED by TriggerEvent
end )
If you need to prevent an action, implement the check in the event handler itself, not in middleware.
Next Steps
Event System Understanding the event system
Base API Core framework exports
Logger API Logging component
Callbacks Request-response communication