Core runtime API
Lua uses nil, boolean, number, string, function, and table. Signatures in this reference put optional arguments in brackets. A call that violates its type, range, permission, phase, or resource budget raises a Lua error unless stated otherwise.
Runtime identity
| Value | Type | Meaning |
|---|---|---|
samp.api.version | string | Active Plugin API version, currently "1.1". |
samp.plugin.id | string | Stable ID from the installed manifest. |
samp.plugin.version | string | Installed plugin version. |
samp.api.has(name [, minimumVersion])
Returns boolean. name is a capability string up to 128 bytes. minimumVersion, when present, is a numeric API version such as "1.1". The result is true only when both the capability and version are supported. Use this for optional behavior, not as a replacement for manifest permissions.
Logging
samp.log.debug(message)
samp.log.info(message)
samp.log.warn(message)
samp.log.error(message)message is a string of at most 2,048 bytes. The host attaches the plugin ID and selected severity. The functions return nothing.
Subscriptions
samp.events.on(name, callback [, options])
Registers callback(event) and returns a subscription handle:
local subscription = samp.events.on("player.spawned", callback, {
priority = 100,
once = true
})
subscription:unsubscribe()| Argument | Type | Rules |
|---|---|---|
name | string | Non-empty, at most 96 bytes. |
callback | function | Receives one event table. |
options.priority | integer | Optional, -1000..1000, default 0; higher runs first. |
options.once | boolean | Optional, default false; removes the subscription after its first dispatch. |
A plugin may hold at most 256 subscriptions. Event-specific permissions are checked when subscribing. unsubscribe() is idempotent and returns nothing. See Event payloads.
Modules
require(name)
Loads modules/<name>.lua and returns the module result. Dots map to directories: require("ui.colors") loads modules/ui/colors.lua.
name is at most 128 bytes and may contain letters, digits, _, and .; leading, trailing, or repeated dots are rejected. Modules are cached by name. If a module returns nil, callers receive true. Plugins cannot load native modules or files outside their own modules/ directory.
Timers and managed tasks
samp.timer.after(delayMs, callback)
Schedules a one-shot callback and returns { cancel = function }. delayMs is an integer from 0 to 86,400,000. A plugin may have at most 256 timers. cancel() is idempotent.
samp.task.spawn(callback)
Starts a managed coroutine and returns { cancel = function }. A plugin may have at most 256 tasks. The callback has no arguments. Cancelling is idempotent; cancelling the currently executing task stops it safely.
samp.task.sleep(delayMs)
Suspends the current managed task for 0..86,400,000 milliseconds. It returns no value and raises an error outside a task created by samp.task.spawn. Ordinary event callbacks and mutable interception callbacks cannot yield.
Private storage
All storage calls require plugin.storage. Values are private to the plugin ID.
local value = samp.storage.get(key [, default])
samp.storage.set(key, value)
samp.storage.remove(key)| Item | Contract |
|---|---|
key | 1–64 ASCII characters; starts with a letter or digit; remaining characters may also use _, -, .. |
value | string, boolean, or finite number. |
| Missing key | get returns the supplied default, or nil. |
| String size | At most 16 KiB per value. |
| Plugin quota | At most 128 entries and 1 MiB encoded data. |
set and remove return nothing. Removing a missing key succeeds. The current session uses an in-memory cache; disk writes are handled by a bounded asynchronous queue. A plugin may queue at most 64 distinct-key writes, and unload waits for that plugin's pending writes. Temporary and backup files allow the host to recover a value after an interrupted write.
Formatting
samp.format.number(value [, precision])
Returns a locale-independent decimal string. value must be finite and have absolute value at most 9,000,000,000,000. precision is an integer 0..6, default 0. The result is rounded to the requested fixed precision.
Game state
samp.game.state()
Requires game.state.read and returns:
| Field | Type | Meaning |
|---|---|---|
sessionId | integer | Current runtime session identity. |
playerGeneration | integer | Current local-player generation. |
ready | boolean | Game services are available. |
paused | boolean | The game is paused. |
multiplayer | boolean | A multiplayer runtime exists. |
localPlayerAvailable | boolean | A local-player Handle can currently be acquired. |
interior | integer | Active interior ID, or 0 when unavailable. |
The table is a snapshot; call again for fresh state.
Current server
samp.server.current()
Requires server.state.read. Returns nil without a multiplayer runtime; otherwise returns:
| Field | Type | Meaning |
|---|---|---|
sessionId | integer | Session to which this snapshot belongs. |
address | string | Server host or IP. |
port | integer | Server port. |
name | string | UTF-8 server name; may be empty before it is known. |
state | string | waiting, connecting, connected, joining, restarting, or unknown. |
connected | boolean | Fully connected. |
connecting | boolean | Connection or join is in progress. |
lan | boolean | LAN mode flag. |
World, checkpoint, and camera snapshots
samp.world.time()
Requires game.state.read. Returns { hour, minute } when the game clock is available and valid, otherwise nil. The value is a snapshot of the current game clock; it is not a promise that the server will apply a setting on the next frame.
samp.world.weather()
Requires game.state.read. Returns { weather, holdTime } or nil when the network world settings are unavailable. holdTime reports whether the server has locked world time.
samp.checkpoint.state()
Requires game.state.read. Returns { normal, race }, where each present checkpoint contains its position and shape-specific fields (extent for a normal checkpoint, or radius and raceType for a race checkpoint). Missing checkpoints are nil.
samp.camera.state()
Requires game.state.read. Returns nil when the camera is unavailable; otherwise it returns a snapshot:
{
position = Vector3,
direction = Vector3,
up = Vector3,
mode = integer,
fov = number
}The snapshot is read-only. Camera control is exposed separately through the managed camera.follow effect.
Network statistics
samp.network.stats()
Requires network.stats.read and returns a read-only transport snapshot:
{
queuedPackets = integer,
queueHighWatermark = integer,
receivedPackets = integer,
receivedBytes = integer,
sentPackets = integer,
sentBytes = integer,
droppedRealtime = integer,
rejectedMalformed = integer,
maxDispatchAgeMs = integer,
droppedInspectionEvents = integer,
interceptionBypasses = integer
}droppedRealtime is local client queue pressure, not an Internet packet-loss measurement. Network event payloads are bounded and are delivered on the next managed frame; they cannot be used to synchronously rewrite packet contents.
Audio
samp.audio.play(url), samp.audio.stop(), and samp.audio.state()
These functions require audio.playback. A successful play gives the calling plugin ownership of the current stream; a later play replaces it. Plugins can stop only the stream they currently own, and unload automatically stops streams owned by that plugin.
samp.audio.play("https://example.com/stream.ogg")
local state = samp.audio.state()
if state and state.playing then
samp.audio.stop()
endstate() returns { playing, owned, url }.
Chat, commands, and clipboard
samp.chat.notify(message [, color])
Requires ui.chat. Shows a local-only notification and never sends a server message. color is an optional ARGB integer; messages must be valid UTF-8 and are limited to 1,024 bytes.
samp.chat.send(message) and samp.command.send(command)
Require chat.send. Requests use the same bounded queue as user input and are still passed through the corresponding outgoing interception events. Chat text must not start with /; commands must start with / and contain another character. NUL, CR, and LF are rejected.
samp.clipboard.get() and samp.clipboard.set(text)
get() requires ui.clipboard.read; set() requires ui.clipboard.write. Reads return the current UTF-8 clipboard snapshot or nil when unavailable. Writes are delivered asynchronously to the UI thread; each value is limited to 16 KiB.