Shared
Last updated on
The OPX.* runtime on both sides — module registry and lifecycle, contracts, event names, time, the scheduler, runtime values and the boot order.
The core is opx_infinity/core/. It loads before every module and gives them one shared OPX table. Everything on this page exists in both VMs. Server-only functions are on Server, client-only ones on Client; the lib/ helpers (OPX.Result, OPX.Storage, OPX.Hooks, OPX.Locale…) on Shared library.
Values
| Name | Side | Type | Notes |
|---|---|---|---|
OPX.VERSION | both | string | The manifest version, read from the host (Open77.resource.version() on the client, the manifest metadata on the server). Falls back to the literal in core/shared/main.lua. |
OPX.IsServer | both | boolean | true in the server VM (TriggerClientEvent exists). |
OPX.IsClient | both | boolean | true in the client VM (TriggerServerEvent exists). |
OPX.Config | both | table | SHARED, MODULES, and SERVER (server only) or CLIENT (client only). See Configuration. |
OPX.Channel | both | table | { NET = 'net', LOCAL = 'on', INTERNAL = 'in' }. Pass one to OPX.Event. |
OPX.Host | both | table | Host event names. See Host events. |
OPX.Glyphs | both | table<string, true> | The closed set of icon names the page can draw (interact, person, vehicle, lock, money, warning, …). Toasts, refusals and command notices only accept these. |
Server-only values (OPX.Booted, OPX.BootError, OPX.Sessions): Server. Client-only OPX.Lib: Client.
Modules
A module declares itself in modules/<id>/module.lua and hangs Init, Api, Start and Stop on the table it gets back (Modules and contracts).
Module states: declared, started, failed, disabled, absent, unavailable, stopped.
OPX.Modules.Declare
Declares a module and returns its namespace.
OPX.Modules.Declare(spec)Parameters
- spec:
table- id:
string - side?:
'server' | 'client' | 'both'— default'both' - requires?:
string[] - optional?:
string[] - fatal?:
boolean
- id:
Returns
-
table— the module namespace (M) -
Raises on a missing id, a duplicate id, an unknown side, or a call after the modules were resolved.
-
A module with
enabled = falsein its config is markeddisabled; one for the other side isabsent.
local M = OPX.Modules.Declare{ id = 'thing', side = 'server', requires = { 'character' } }OPX.Modules.Get
The module's namespace (what its files write into).
OPX.Modules.Get(id)Parameters
- id:
string
Returns
table?
OPX.Modules.Record
The runtime's record of a module, separate from its namespace.
OPX.Modules.Record(id)Parameters
- id:
string
Returns
table?—Id,Side,Requires,Optional,Fatal,Provides,Module,State,Reason
OPX.Modules.All
Every record, in declaration order.
OPX.Modules.All()Returns
table[]
OPX.Modules.IsRunning
true only when the module's state is started in this VM.
OPX.Modules.IsRunning(id)Parameters
- id:
string
Returns
boolean
OPX.Modules.Settings
OPX.Config.MODULES[id], read now.
OPX.Modules.Settings(id)Parameters
- id:
string
Returns
table— nevernil({}when the module has no config)
OPX.Modules.Rebind
Points every module's Settings field at its live config. Called once by Resolve.
OPX.Modules.Rebind()OPX.Modules.Resolve
Orders the modules by dependency. Memoised. Raises on a dependency cycle. Marks disabled and unavailable modules.
OPX.Modules.Resolve()Returns
table[]— records in dependency order
OPX.Modules.Resolved
Whether Resolve has run.
OPX.Modules.Resolved()Returns
boolean
OPX.Modules.Run
Runs Init, Api, Start over every runnable module. Yields between modules: call it from a thread. Boot calls it; a module never does.
OPX.Modules.Run(between)Parameters
- between?:
function— runs afterApiand beforeStart; if it raises,Runanswersfalse, <error>.
Returns
- ok:
boolean - failure?:
string—'already ran'on a second call, or the id of a fatal module that failed
OPX.Modules.Stop
Calls Stop on every started or failed module, newest dependency first. A module is marked stopped before its Stop runs, so a second stop cannot run it twice. A Stop that raises is logged.
OPX.Modules.Stop(yielding)Parameters
- yielding?:
boolean—truewaits a frame after eachStopwhen the caller can yield, so each module gets a fresh instruction budget. The client passestrue; the server passes nothing.
OPX.Modules.Report
One line per module: id, state, reason.
OPX.Modules.Report()Returns
string[]
Contracts
OPX.Api.Provide
Publishes a contract. Call from a module's Api phase.
OPX.Api.Provide(name, version, implementation)Parameters
- name:
string - version:
integer - implementation:
table
Raises on bad arguments, or if two modules provide the same name.
function M.Api()
OPX.Api.Provide('thing', 1, { DoIt = function(source) end })
endOPX.Api.Get
Reads a contract. Use it for an optional dependency.
OPX.Api.Get(name, minimum)Parameters
- name:
string - minimum?:
integer
Returns
table?—nilwhen nobody provides it, or the version is belowminimum- version?:
integer
local downed = OPX.Api.Get('downed')
if downed then ... endOPX.Api.Require
Like Get but raises when absent. For a module that lists the provider in requires.
OPX.Api.Require(name, minimum)Parameters
- name:
string - minimum?:
integer
Returns
table
OPX.Api.Versions
Every published contract.
OPX.Api.Versions()Returns
table<string, integer>— name → version
OPX.Api.Withdraw
Withdraws every contract a module published. Called by the lifecycle when a module fails.
OPX.Api.Withdraw(owner)Parameters
- owner:
string— module id
Returns
string[]— names withdrawn
Events
OPX.Event
Builds opx:<channel>:<module>:<verb> (Events and channels).
OPX.Event(channel, module, verb)Parameters
- channel:
'net' | 'on' | 'in'— useOPX.Channel; anything else raises - module:
string - verb:
string
Returns
string
local SAY = OPX.Event(OPX.Channel.NET, 'chat', 'say') -- 'opx:net:chat:say'OPX.Publish (server) raises public events: Server.
Time
OPX.Now
Monotonic milliseconds: GetGameTimer() when present, else Open77.time.monotonic() * 1000. Not wall-clock time.
OPX.Now()Returns
integer— ms
Scheduler
Same names on both sides, different behaviour (The scheduler). OPX.Scheduler.Start is client only: Client.
OPX.Scheduler.Every
Runs step repeatedly.
OPX.Scheduler.Every(name, intervalMs, step)Parameters
- name:
string— for log lines,<module>.<purpose> - intervalMs:
number | function - step:
function
Returns
-
integer— handle -
Server: one thread per job;
intervalMsis a number or a function re-read every pass; floor 50 ms; first pass one interval after registration; a raising job is logged once per run of failures and never suspended. -
Client: one shared loop, at most 4 due jobs per pass;
intervalMsmust be a number>= 0(a function or bad value raises;0= every pass); a job that raises 3 times in a row is suspended.
M.sweep = OPX.Scheduler.Every('thing.sweep', 1000, function() ... end)OPX.Scheduler.Cancel
Stops a job. Safe on a handle already cancelled.
OPX.Scheduler.Cancel(handle)Parameters
- handle:
integer
OPX.Scheduler.Report
One line per job: name, interval, state.
OPX.Scheduler.Report()Returns
string[]
OPX.Scheduler.Stop
Stops every job and drops the list. Boot calls it on resource stop.
OPX.Scheduler.Stop()Creator export gate
core/shared/exports.lua, both sides. The scaffolding the server and client creator exports share: who is calling, whether they are admitted, and the answer shape. One copy, so the two halves cannot disagree about who may call. Use it only if you add an export to core/*/exports.lua.
OPX.Export.Ok
OPX.Export.Ok(value)Returns
{ ok = true, value }—valuemay be nil
OPX.Export.Refuse
OPX.Export.Refuse(code)Returns
{ ok = false, error = code }
OPX.Export.Answered
A contract Result as the export answer: the value on success, the code on a refusal, error.unavailable for anything that is not a Result.
OPX.Export.Answered(result)Returns
{ ok, value | error }
return OPX.Export.Answered(OPX.Api.Get('weather').SetWeather(name))OPX.Export.Admits
Whether an allowlist admits a caller.
OPX.Export.Admits(list, caller)Parameters
- list:
'*' | table—'*', a set ({ my_res = true }) or an array of names - caller:
string
Returns
boolean
OPX.Export.IsResourceName
Whether a string could be a resource name: [%w_%-%.], 1 to 64 characters.
OPX.Export.IsResourceName(name)Returns
boolean
OPX.Export.Caller
The calling resource as the host reports it (GetInvokingResource), or nil when that is not a valid name. Never take a caller name from an argument.
OPX.Export.Caller()Returns
string?
OPX.Export.Available
Whether the host offers exports. On Open77 exports is a callable table, so a function, a table or userdata all count. (Before PR #58 only a function counted, and no creator export was published.)
OPX.Export.Available()Returns
boolean
Boot order
| Side | Sequence |
|---|---|
| server | Placement-conflict warning → database probe (OPX.Storage.Ready) → Init → Api → OPX.Tune.Publish and OPX.Schema.Apply (skipped with no database) → Start → OPX.Booted = true → module report in the log. On resource stop: OPX.Scheduler.Stop, OPX.Modules.Stop, then every player is released from a selection bucket. |
| client | On onClientResourceStart: OPX.UI.Surface, OPX.Toast.Attach → OPX.Modules.Run → OPX.Scheduler.Start → module report. Boot yields between the surface build and Modules.Run. On stop: OPX.UI.ReleaseAllFocus first, then OPX.Scheduler.Stop, OPX.Modules.Stop(true), OPX.UI.Teardown. |
Core
The opx_infinity API that no single module owns — the OPX.* runtime, its configuration, runtime events, the lib/ helpers and the shared error codes.
Server
The server-only OPX.* runtime — public events, chat commands and aliases, answers and refusals, the readiness gate, sessions, routing buckets, tunables and the schema.