Graces: telling Bastrel about a legitimate state
Some things your scripts do look like cheating to a server-side check: teleporting a player to the hospital, making them invincible during a cutscene, hiding them while a character is created. A grace is how your own server scripts tell Bastrel “I did this, it is expected”. Only server scripts can grant one: the client SDK never can (a cheat would use it to excuse itself).
The state checks (see state.md) and the movement checks (see movement.md) read these graces. The exports and the grace table are in place so your scripts can call them now.
The exports
Section titled “The exports”Call them from a server script of yours (bastrel must be started):
-- the player is moved to these coordinates; expected for 5 secondsexports.bastrel:allowTeleport(src, vector3(298.6, -584.4, 43.3), 5000)
exports.bastrel:allowState(src, 'invincible', 10000) -- cutscene, character creationexports.bastrel:allowState(src, 'invisible', 0) -- 0 = until you revoke itexports.bastrel:revokeState(src, 'invisible')Each export answers true when it did something and false otherwise; it never raises an error. The reason of a refusal is in the log (below).
| State | Duration | Notes |
|---|---|---|
teleport (allowTeleport) |
ttlMs from 1 |
coords is the expected destination and must be finite numbers. 0 is refused. |
invincible, invisible |
ttlMs from 1, or 0 = until revokeState |
|
weapon, weaponModifier, health, camera |
ttlMs from 1 only |
Outside the base spec, see below. weapon needs the exact hash: exports.bastrel:allowState(src, 'weapon', 3000, { hash = GetHashKey('WEAPON_PISTOL') }). Never a wildcard. |
srcis the server id of a player Bastrel tracks; an unknown id is refused.- A duration above
grants.maxTtlMs(10 minutes by default) is cut to it, and the log says so. - Each resource has its own grace per player and state, with its own duration and data (destination, weapon hash). The player is covered as long as one of them is. Granting again never shortens your own grace, and never replaces another resource’s. Revoking removes all of your own entries for that state (every weapon hash you granted). A resource may hold at most
grants.maxWeaponHashes(16) weapon hashes per player. - Graces are forgotten when the player leaves and when the resource restarts.
Limiting who can grant: grants.allowedResources
Section titled “Limiting who can grant: grants.allowedResources”config/modules.lua, block grants:
grants = { allowedResources = { 'qbx_ambulance', 'my_cutscenes' }, maxTtlMs = 600000, logMs = 60000,},- Empty list (default): any server resource may grant
teleport,invincibleandinvisible. The statesweapon,weaponModifier,healthandcameraare refused. - With names: only these resources may grant or revoke, and only then can the four extra states be granted. A compromised resource that is not in the list cannot excuse a cheater.
Bastrel’s own inventory adapter is the one exception: it may grant a short weapon grace itself while the list is empty (finite duration, logged). A script of yours can only revoke a grace it granted itself.
We recommend filling the list as soon as you use graces.
What is logged
Section titled “What is logged”Every grace granted, refused or revoked is written to the Bastrel log with the calling resource, the state and the player (grants.granted, grants.refused, grants.revoked). The first of each (resource, state) in a minute is written at once; the repeats are summed in one grants.summary line when the minute ends, so a script that calls the export in a loop cannot flood the log.
Refusal reasons: bad_src, unknown_player, unknown_kind, no_caller, resource_refused, not_owner (revoking a grace another resource granted), cap_reached (too many weapon hashes), bad_ttl, bad_coords, bad_hash.
Settings
Section titled “Settings”| Setting | Default | Meaning |
|---|---|---|
grants.allowedResources |
{} |
Resources allowed to grant or revoke. |
grants.maxTtlMs |
600000 |
Longest grace, in ms (1 to 3600000). |
grants.maxWeaponHashes |
16 |
Weapon hashes one resource may hold at once per player (1 to 64). |
grants.maxTeleports |
4 |
Teleport destinations one resource may have declared at once per player (1 to 64); each is used up by one teleport. Past it, the oldest one of that resource is dropped. |
grants.logMs |
60000 |
Window over which repeated log lines are summed (1000 to 3600000). |
sampler.tickMs |
500 |
Period of the scheduler tick, in ms (500 to 2000). |
sampler.intervalMs |
1500 |
Every player is read once per interval (1000 to 2000, a multiple of tickMs). |
sampler.maxPerTick |
64 |
Players read in one tick at most (1 to 1024). |
An invalid value never stops Bastrel: the invalid field takes its default and a warning is logged. If allowedResources itself is invalid, every external resource is refused until you fix it (Bastrel’s own grace for weapon still works).
The scheduler
Section titled “The scheduler”All the periodic reads of the state of players share one scheduler (sampler). Players are read in equal slices spread over the interval, so the cost has no peak, and a player who joins is read from the next interval. Nothing to configure unless you want a slower rhythm.