Events
Last updated on
The public opx:on:* server events any resource can listen to, the private opx:in:* events, and the client side.
On the server, TriggerEvent reaches every running resource. opx_infinity announces what happens on opx:on:<module>:<verb> names raised through OPX.Publish. Any server resource can listen; no allowlist applies.
AddEventHandler('opx:on:character:money', function(playerId, payload)
print(('%s %s %d %s (now %s)'):format(payload.citizenId, payload.action,
payload.amount, payload.moneyType, tostring(payload.balance)))
end)Every event has two arguments:
- playerId:
number?— the player the event is about;nilwhen that character is not online - payload:
table— built for the event; never a live record, never the free-formmetadata
The events are announcements: they fire after the change, and nothing a listener does can undo or veto it.
Advisory, not proof
Server TriggerEvent is host-wide in both directions: any server resource can raise an opx:on:* name with any payload. Use these events to refresh, log or react — never as proof that something happened. Before you pay, give or unlock on the strength of one, ask OPX again (a read export such as GetMoney, CountItem or GetVehicle). For a server-started bar, keep the id StartProgress answered and check owner too.
opx:on:character:loaded
Server, host-wide. A character was loaded for a player.
AddEventHandler('opx:on:character:loaded', function(playerId, payload) end)- payload:
table— the public viewsource,citizenId,userId,firstName,lastName,money,job,gang,jobs,gangs
opx:on:character:unloaded
Server, host-wide. A character left the world (logout, switch, disconnect).
AddEventHandler('opx:on:character:unloaded', function(playerId, payload) end)- payload:
{ citizenId, userId }
opx:on:character:created
Server, host-wide. A character row was made (no name and no body yet: those come in the world).
AddEventHandler('opx:on:character:created', function(playerId, payload) end)- payload:
{ citizenId, userId, slot }
opx:on:character:deleted
Server, host-wide. A character was deleted (soft: the row stays, the slot is freed). Forget whatever you keep for this citizen id.
AddEventHandler('opx:on:character:deleted', function(playerId, payload) end)- playerId?:
number— set when the character was being played - payload:
{ citizenId, userId, by }—byis the connection that asked (the player, staff),nilfor the console
opx:on:character:money
Server, host-wide. Any balance change.
AddEventHandler('opx:on:character:money', function(playerId, payload) end)- payload:
table- citizenId:
string - moneyType:
string - amount:
integer - action:
'add' | 'remove' | 'set' - reason?:
string - balance:
integer? - offline:
boolean—true(andplayerIdnil) forAddMoneyOffline
- citizenId:
opx:on:character:job
Server, host-wide. The primary job was set, its duty changed, or a job membership was removed.
AddEventHandler('opx:on:character:job', function(playerId, payload) end)- payload:
table- citizenId:
string - job:
table— the primary job after the change - removed?:
string— the job removed - offline:
boolean— the change was made to a character nobody is playing
- citizenId:
opx:on:character:gang
Server, host-wide. The same for gangs.
AddEventHandler('opx:on:character:gang', function(playerId, payload) end)- payload:
{ citizenId, gang, removed?, offline }
opx:on:inventory:changed
Server, host-wide. A container's contents were written.
AddEventHandler('opx:on:inventory:changed', function(playerId, payload) end)- payload:
tablekind,owner,container- citizenId?:
string— only for a player's bag (and thenplayerIdis set)
opx:on:inventory:used
Server, host-wide. A player used an item (already consumed; nothing can decide the use from here).
AddEventHandler('opx:on:inventory:used', function(playerId, payload) end)- payload:
{ citizenId, name, slot, consumed, metadata }
opx:on:inventory:items
Server, host-wide. What a player's bag gained and lost, by item name: a give (raised when the receiver accepts; an offer that is refused or expires moves nothing and raises nothing), a pickup, a drop, a craft, a use, an export call. A drag inside the bag moves nothing in or out and raises nothing.
AddEventHandler('opx:on:inventory:items', function(playerId, payload)
for _, change in ipairs(payload.changes) do
if change.name == 'lockpick' and change.delta > 0 then print('got a lockpick') end
end
end)- payload:
table- citizenId:
string - changes:
{ name, delta, count }[]—deltathe units that moved (negative for a loss),countwhat the bag holds now; sorted by name
- citizenId:
opx:on:downed:changed
Server, host-wide. A player went down or got up.
AddEventHandler('opx:on:downed:changed', function(playerId, payload) end)- payload when down:
{ citizenId, down = true, waiting, restored }- restored:
boolean— the down state came back after a reconnect
- restored:
- payload when up:
{ citizenId, down = false, reason, kept }- kept:
boolean— the character left the world still down; the state returns with them
- kept:
opx:on:needs:changed
Server, host-wide. A player's needs moved on the server: decay, an item used, staff, or an export.
AddEventHandler('opx:on:needs:changed', function(playerId, payload) end)- payload:
table
The first load of a character raises nothing here; read it with GetNeeds.
opx:on:vehicles:spawned
Server, host-wide. An owned vehicle was brought out.
AddEventHandler('opx:on:vehicles:spawned', function(playerId, payload) end)- payload:
tablecitizenId,plate,record,vehicleId- vehicleKey:
string— the engine id as text (safe in JSON) - recalled?:
true— it was already out and was moved
opx:on:vehicles:stored
Server, host-wide. It was put away, or the host removed it from the world.
AddEventHandler('opx:on:vehicles:stored', function(playerId, payload) end)- payload:
{ citizenId, plate, garage }, or{ citizenId, plate, removed }—removedsays why the host took it away
opx:on:vehicles:registered
Server, host-wide. A vehicle row was made for a character: bought at a dealer, given by AddVehicle or a staff command.
AddEventHandler('opx:on:vehicles:registered', function(playerId, payload) end)- payload:
{ citizenId, plate, record, garage }
opx:on:vehicles:state
Server, host-wide. A vehicle was moved to stored or impounded (SetVehicleState, the impound door).
AddEventHandler('opx:on:vehicles:state', function(playerId, payload) end)- payload:
{ citizenId, plate, state, garage }—stateis'stored'or'impounded'
opx:on:dealership:sold
Server, host-wide. A vehicle was bought at a dealer (counter) or sold player-to-player (offer).
AddEventHandler('opx:on:dealership:sold', function(playerId, payload) end)- payload (counter):
{ kind = 'counter', citizenId, plate, entry, record, dealer, garage, price, currency } - payload (offer):
{ kind = 'offer', citizenId, plate, entry, record, dealer, garage, price, currency, seller, sellerCitizenId, company, commission, banked, pending }citizenIdis the buyer;seller/sellerCitizenIdthe salesperson.- garage?:
string— the buyer's chosen garage;nil= the vehicles module default - company:
string—<kind>:<group> - commission:
integer— paid to the seller (0if it could not be paid; it then went to the company) - banked:
integer— the company's share - pending:
boolean—truewhen the company share went to the pending ledger to be paid in later; the sale is done either way
opx:on:hauling:sold
Server, host-wide. Crates were sold to a drop-off NPC.
AddEventHandler('opx:on:hauling:sold', function(playerId, payload) end)- payload:
{ citizenId, site, dropoff, count, pay, each, currency }
opx:on:doorlock:changed
Server, host-wide. A door was locked or unlocked — by a player, staff, autolock or an export.
AddEventHandler('opx:on:doorlock:changed', function(playerId, payload) end)- playerId:
number?—nilwhen no player turned it (autolock, an export) - payload:
table- id, door:
integer— the door id (the same value twice) - name:
string - state:
0 | 1—1locked - locked:
boolean - by:
string— the player id,lockpick:<id>,staff:<id>,autolockor the contract caller - item?:
string— the key item that opened it, if any
- id, door:
See doorlock.
opx:on:fuel:changed
Server, host-wide. A tank moved for any reason but driving: a refuel, a can, staff, an export, or a tank that just ran empty.
AddEventHandler('opx:on:fuel:changed', function(playerId, payload) end)- playerId:
number?— who poured, the driver forempty, the staff member;nilfor an export - payload:
table- vehicleId:
integer— the live vehicle id - vehicleKey:
string— the same id as text (exact above 2^53) - litres:
number— the tank now, in litres - previous?:
number— before, in litres - percent:
number— 0..100 - capacity:
number— litres in a full tank - reason:
'refuel' | 'can' | 'staff' | 'empty' | 'ext:<resource>'
- vehicleId:
Driving is not announced: it moves every tank every second, and the bag replicates it. See fuel.
AddEventHandler('opx:on:fuel:changed', function(playerId, payload)
if payload.reason == 'refuel' then
print(('%s filled %s to %d%%'):format(tostring(playerId), payload.vehicleKey, math.floor(payload.percent)))
end
end)opx:on:crafting:ordered
Server, host-wide. A player placed an order at a bench: materials and price already taken.
AddEventHandler('opx:on:crafting:ordered', function(playerId, payload) end)- payload:
{ citizenId, bench, recipe, item, count, seconds, price, money?, order }
opx:on:crafting:collected
Server, host-wide. A finished order was handed over.
AddEventHandler('opx:on:crafting:collected', function(playerId, payload) end)- payload:
{ citizenId, bench, recipe, item, count, order }
opx:on:progress:finished
Server, host-wide. A bar the server started ended, as the server decided it: StartProgress.
AddEventHandler('opx:on:progress:finished', function(playerId, payload) end)- payload:
table- id:
integer— the idStartProgressanswered - owner:
string— the resource (or module) that started it; filter on your own name - ending:
string—finished,stopped,cancelled,interrupted,refused(the client could not draw it),rejected(finished sooner than its duration),no_answer,left - completed:
boolean— onlytruemeans the action happened - elapsedMs:
integer— by the server's clock
- id:
The private opx:in:* events
Server opx:in:* events are visible to every server resource
Because server TriggerEvent is host-wide, the internal opx:in:* events (for example opx:in:character:loaded) also reach your resource, and your resource could raise them. They are not part of the public surface: their names and arguments change without notice. Listen to the opx:on:* events above instead, and never raise an opx: event yourself.
On the client
The client-side opx:on:* events (menu actions, inventory opened…) stay inside opx_infinity: a client TriggerEvent does not leave its resource. Answers to your own client calls reach you through the reply export, and some client events can be forwarded with Subscribe.