Skip to content

Server globals serverside ​

Everything available to serverside scripts, weapon server halves, classes and serverside NPC code (globals.d.ts).

Source

Generated from templates/server/data/scripts/globals.d.ts. To change this page, edit the JSDoc in that file.

Overview ​

Ambient declarations for host functions injected by the ClearScript V8 runtime (see GServer). These are available to every script in this folder without needing an import.

Fire-and-forget host calls (like echo) are batched: they queue JS-side and are delivered to the server in one batch at the next flush point (end of the current server tick at the latest, 50ms at 20 TPS). Ordering between batched calls is preserved, but their arguments must be JSON-serializable and they cannot return values. Calls that return values or take callbacks (sleep, setTimeout, ...) reach the server directly instead.

Declarations ​

echo function ​

ts
declare function echo(msg: string): void

Prints a message to the server console. Batched: delivered at the next flush point (end of the current server tick at the latest). The argument must be JSON-serializable.

sleep function ​

ts
declare function sleep(seconds: number): Promise<void>

Cooperatively pauses the calling (async) script for the given number of seconds. Other scripts keep running while this one is suspended. Resolution is tied to server ticks, so resume timing is rounded up to the next tick (50ms at 20 TPS).

setTimeout function ​

ts
declare function setTimeout(handler: (...args: any[]) => void, ms?: number, ...args: any[]): number

Runs handler once after ms milliseconds (rounded up to the next server tick). Returns an id usable with clearTimeout. Extra args are forwarded to the handler.

clearTimeout function ​

ts
declare function clearTimeout(id: number): void

Cancels a pending setTimeout by id.

setInterval function ​

ts
declare function setInterval(handler: (...args: any[]) => void, ms?: number, ...args: any[]): number

Runs handler repeatedly every ms milliseconds (fires at most once per server tick). Returns an id usable with clearInterval. Extra args are forwarded to the handler.

clearInterval function ​

ts
declare function clearInterval(id: number): void

Cancels a running setInterval by id.

triggerClient function ​

ts
declare function triggerClient(scriptType: 'weapon', scriptName: string, ...params: any[]): void

Sends an action to the CURRENT player's client, invoking onActionClientSide(...params) on their copy of the named weapon. Batched; params must be JSON-serializable.

"Current player" is the player whose event is being handled — valid inside onActionServerSide, onPlayerJoined and onPlayerLeft. There is no current player after an await or inside timer callbacks; calls made there are dropped (with a server-console log). scriptType is "weapon" for now (clients run nothing else); scriptName is the weapon's name — in a weapon's serverside half, this.name reaches its own clientside half:

ts
export function onActionServerSide(this: ScriptThis, player: Player, action: string) {
    triggerClient('weapon', this.name, 'reply', 'hi ' + player.account)
}

sendPM function ​

ts
declare function sendPM(target: string | Player, text: string): void

Sends a SYSTEM private message to a player on any server, via GSocial. The client receives it as onPMReceived({ account: <this server's name>, server: <this server's name>, system: true }, text). Online-only: dropped if they aren't connected anywhere. Text max 200 characters. Accepts an account name or a Player. Unlike triggerClient, needs no player context.

ts
sendPM(player, 'Welcome back!')
sendPM('SomeAccount', 'Server restarts in 5 minutes')

createlevel function ​

ts
declare function createlevel(name: string, fillTile: number, width?: number, height?: number): string

Creates a new blank level named <name>.glvl, width x height tiles (8-512 per side, default 64x64), filled with fillTile on layer 0 (65535 = empty). Names are 1-32 characters (letters, digits, _ or -) WITHOUT extension; creation fails if any level (saved or unsaved) already uses the name. The level lives in server memory and is served to players immediately, but its .glvl file is only written when someone saves it ("update level") — unsaved levels vanish on server restart. Returns '' on success or a player-presentable error message. Direct call: the result is available immediately.

setleveltile function ​

ts
declare function setleveltile(levelName: string, layer: number, x: number, y: number, tileId: number): boolean

Sets one tile of a level's in-memory copy: tileId is a row-major tileset index (65535 = empty/erase). Every player in the level — the initiating player included — receives the change immediately; nothing touches the .glvl file until the level is saved ("update level"). No-op repaints don't broadcast. Returns false for unknown levels or out-of-range arguments. Direct call.

gmaptolevel function ​

ts
declare function gmaptolevel(gmapName: string, gx: number, gy: number): { level: string; x: number; y: number } | null

Converts gmap-global tile coordinates to the member level under them and its member-local coordinates. Null when the gmap doesn't exist or (gx, gy) is outside its grid. On a gmap, player.x/y are already gmap-global, so gmaptolevel(player.level, player.x, player.y) tells you which member level a player is standing in. Direct call: reads live data.

leveltogmap function ​

ts
declare function leveltogmap(levelName: string, x: number, y: number): { gmap: string; x: number; y: number } | null

Converts member-level-local tile coordinates to gmap-global. Null when the level belongs to no gmap. Warps already auto-translate member destinations; use this when you need the numbers yourself. Direct call: reads live data.

ScriptThis interface ​

ts
interface ScriptThis

Every handler in a server script runs with this bound to the script's own object: this.name is the script's name (file name without .ts; a weapon's serverside half gets the bare weapon name, matching its clientside this.name). Scripts may stash extra state on this between calls. Only function declarations see it — arrow functions ignore this.

export is optional: every top-level function is exported by the build (so function onCreated() is a handler), and the script's own functions and joined class exports are callable on this too. Inside a top-level function this is always the script: a bare helper(...) call from a handler falls back to the running script's self instead of JS's undefined.

this types as any in handlers (noImplicitThis is off in tsconfig.json); annotate a handler with this: ScriptThis if you want it typed:

ts
export function onActionServerSide(this: ScriptThis, player: Player) { ... }

ScriptThis.name ​

ts
name: string

The script's name, e.g. "test" for test.ts or weapons/test.ts.

ScriptThis.join ​

ts
join(name: string): boolean

Joins this script to a class (scripts/classes/<name>.ts): the class's exported handlers fire after this script's own, its exported helpers become callable on this, and its onCreated runs now with this script as this. A serverside join also joins the class's clientside half (<name>.client.ts, when one exists) on every client. Re-joining re-checks the class version and re-fires its onCreated. Returns false when the class doesn't exist.

ScriptThis.leave ​

ts
leave(name: string): boolean

Removes a joined class's handlers from this script.

ScriptThis.joinedclasses ​

ts
readonly joinedclasses: readonly string[]

Currently joined class names, in join order.

ScriptThis.[key] ​

ts
[key: string]: any

Scripts may keep arbitrary state on this.

serverOptions global ​

ts
declare const serverOptions: { … }

The server's configuration from serveroptions.json (next to the server binary), available from onInitialized onward. Beyond the typed options below, every extra top-level key an admin adds to the file shows up here verbatim — e.g. a "motd": "..." line is read as serverOptions.motd. The object is deep-frozen; writes are silently ignored.

serverOptions.name ​

ts
readonly name: string

Display name of the server.

serverOptions.startLevel ​

ts
readonly startLevel: string

Level new accounts start in; returning players resume their saved level.

serverOptions.startX ​

ts
readonly startX: number

Start position for new accounts, in tiles.

serverOptions.startY ​

ts
readonly startY: number

Start position for new accounts, in tiles.

serverOptions.maxPlayers ​

ts
readonly maxPlayers: number

Maximum simultaneous logged-in players; 0 or less means unlimited.

serverOptions.[key] ​

ts
readonly [key: string]: any

Admin-defined custom properties.

server global ​

ts
declare const server: Record<string, any>

Server-only global flags, persisted in data/flags.json across restarts. Values can be anything JSON-serializable (strings, numbers, booleans, arrays, plain objects); flag names are 1-128 characters, values up to 8192 characters of JSON. Assigning null or undefined deletes a flag, as does delete server.foo. Reads return a fresh copy per access — mutating a nested value does NOT store it; reassign to write:

ts
const inv = server.inventory ?? []; inv.push('sword');
server.inventory = inv;

Direct calls (not batched): a write is readable back immediately. Never sent to clients — for server-visible state, see serverr.

serverr global ​

ts
declare const serverr: Record<string, any>

Global flags mirrored to EVERY client, persisted in data/flags.json. Same value rules and reassign-to-write caveat as server. Each write (or delete) is broadcast immediately and readable in clientside scripts as serverr.foo (read-only there); clients also get the full set at login.

Player interface ​

ts
interface Player

Snapshot of a player's state at the moment an event fired (backed by ScriptPlayer on the host side). chat is live rather than a snapshot: reads see the player's current chat bubble, and assigning it sets the bubble for everyone in their level (the player's own client included). client and clientr are the player's live flag bags.

Player.id ​

ts
id: number

Server-assigned player id, unique per login.

Player.account ​

ts
account: string

Account name the player logged in with.

Player.nick ​

ts
nick: string

Display name rendered under the player, for everyone in their level. Defaults to the account name; players change it with the setnick chat command. Assigning '' resets it to the account name. Sanitized like chat and trimmed to 40 chars.

Player.level ​

ts
level: ServerLevel | null

The level (or gmap) the player is in, as a level object — use player.level.name for the file name, player.level.putnpc(...) etc. to act on it. Null until they enter their first level.

Player.x ​

ts
x: number

Position in tiles. Read-only in practice: move players with warpto.

Player.y ​

ts
y: number

Position in tiles. Read-only in practice: move players with warpto.

Player.chat ​

ts
chat: string

Chat bubble above the player's head. Assigning shows it to everyone in their level ('' clears it); it fades 5s after the player moves. Text is trimmed to 200 chars and control characters become spaces.

Player.setAni ​

ts
setAni(name: string): void

Plays a .gan animation on the player, visible to everyone in their level (equivalent to assigning ani). Pass the animation name without the extension, e.g. player.setAni('sword').

Player.ani ​

ts
ani: string

Current animation name (without the .gan extension).

Player.head ​

ts
head: string

Head image, e.g. 'head0.png'. '' means the client default.

Player.body ​

ts
body: string

Body image, e.g. 'body.png'. '' means the client default.

Player.colors ​

ts
colors: string[]

Body colors as 'r,g,b' strings, recoloring the body's reserved key colors: [0] skin, [1] coat, [2] sleeves, [3] shoes, [4] belt. Always five entries. Assigning an index (player.colors[1] = '255,0,0') updates everyone in the level and persists; invalid indices or values are ignored. Assigning an array sets each slot it provides.

Player.hasright ​

ts
hasright(mode: 'r' | 'w' | 'rw', path: string): boolean

Whether this player's staff rights grant folder access on a data/-relative path: mode 'r' (read), 'w' (write) or 'rw' (requires both), e.g. player.hasright('w', 'levels/town.glvl'). Staff-list accounts with no rights record have full access; everyone else without a record has none. Serverside only.

Player.warpto ​

ts
warpto(level: string, x: number, y: number): boolean

Warps this player to a level (or gmap) at tile (x, y) — the same path link touches and RC warps take, so warps to a gmap member land on the gmap with translated coordinates. The client transitions once it has fully downloaded the destination. Serverside only; false when the level doesn't exist.

Player.addWeapon ​

ts
addWeapon(name: string): boolean

Grants a weapon (scripts/weapons/<name>) to this player; their client downloads and runs its clientside half immediately. No-op if they already have it. Serverside only; false when no such weapon exists.

Player.removeWeapon ​

ts
removeWeapon(name: string): boolean

Takes a weapon away from this player; their client unloads it immediately. Serverside only; false (and a no-op) when they don't have it.

Player.hasWeapon ​

ts
hasWeapon(name: string): boolean

Whether this player currently has the named weapon. (Clientside scripts have the same check on their local player.)

Player.client ​

ts
client: Record<string, any>

Per-player flags, readable AND writable both here and in the player's clientside scripts (as client.foo there); persisted in the account file. Values must be JSON-serializable; names 1-128 chars, values up to 8192 chars of JSON. Assigning null/undefined (or delete) removes a flag. Server writes sync to the client immediately; reads return a fresh copy per access, so mutate-then-reassign nested values.

Player.clientr ​

ts
clientr: Record<string, any>

Per-player flags only the server can write; the player's clientside scripts see them read-only (as clientr.foo). Persisted in the account file. Same value rules and reassign-to-write caveat as client.

Event handlers. Scripts subscribe by exporting a function with the matching name; the server invokes it on every script that exports one:

  • export function onCreated(): void
    Fired every time the script loads: at server startup and again on every hot reload (RC script update). Put (re)initialization here — including this.join() calls, which must be re-made after an update.

  • export function onInitialized(): void
    Fired once at server startup, after onCreated. NOT re-fired when the script is updated — use it for boot-only work.

  • export function onPlayerJoined(player: Player): void
    Fired when a player logs in to the server.

  • export function onPlayerLeft(player: Player): void
    Fired when a logged-in player disconnects from the server.

  • export function onActionServerSide(player: Player, ...params: any[]): void
    Fired when a client calls triggerServer targeting this script. player is the triggering player; the client's params follow (JSON round-tripped). triggerClient inside answers that same player.

ServerLevel interface ​

ts
interface ServerLevel

A reference to a specific level (or gmap) — what player.level returns. Same API shape as an NPC script's this.level, but bound to the named level-or-gmap context: on a gmap, all coordinates are gmap-global tiles. Snapshot semantics: taken when the event fired; a player kept across an await may have moved on.

ServerLevel.name ​

ts
readonly name: string

The level's file name, e.g. "start.glvl" (or "world.gmap").

ServerLevel.putnpc ​

ts
putnpc(x: number, y: number, serverScript: string, clientScript?: string): NpcThis | null

Spawns a LOCAL NPC at (x, y) in this level. The script arguments are inline TypeScript SOURCE strings (Graal putnpc2-style); the first compile of a novel script briefly blocks the server tick, identical sources are cached. Never saved to the level file: lives until destroy() or server restart, surviving hot reloads (/clearnpcs in RC clears strays). On a gmap, (x, y) are gmap-global and the NPC lands in the member level under them. Returns the NPC's full this-style handle, or null when the level can't be resolved.

ServerLevel.onwall ​

ts
onwall(x: number, y: number, w?: number, h?: number): boolean

True when a blocking collision tile intersects [x, x+w) × [y, y+h), in tile units (fractions allowed). Omit w/h to test the single tile containing (x, y). Tiles outside the level count as blocked, and so do blocking NPCs (see NpcThis.dontblock); players don't.

ServerLevel.tiletype ​

ts
tiletype(x: number, y: number): number

Collision type of the tile containing (x, y); -1 when out of range.

ServerLevel.shoot ​

ts
shoot(x: number, y: number, gan: string, angle: number, speed: number,
          lifetime: number, data?: any): Projectile | null

Spawns a projectile with its CENTER at (x, y) in this level's space — same semantics and arguments as the player-scoped level.shoot. Returns null on bad arguments.

Projectile interface ​

ts
interface Projectile

A live projectile spawned by level.shoot.

Projectile.id ​

ts
readonly id: number

Unique id for this server run.

Projectile.destroy ​

ts
destroy(): boolean

Removes the projectile mid-flight, silently: no onShotAt/onShot fires anywhere. Safe to call after it already stopped (returns false then).

level global ​

ts
declare const level: { … }

The CURRENT player's level. Like triggerClient, "current player" only exists synchronously inside a player-scoped handler (onActionServerSide, onPlayerJoined, ...) — after an await or inside timer callbacks there is none, and level.name is '' / level.shoot returns null.

NPC scripts: use this.level instead — it is the NPC's own level and also accepts member-local coordinates; this global is player-scoped.

level.name ​

ts
readonly name: string

The current player's level (or gmap) name; '' outside a player-scoped handler.

level.shoot ​

ts
shoot(x: number, y: number, gan: string, angle: number, speed: number,
          lifetime: number, data?: any): Projectile | null

Spawns a projectile with its CENTER at (x, y), in the current player's coordinate space: level tiles, or gmap-global tiles when they are on a gmap (where it crosses member seams). gan is the animation it renders (e.g. 'arrow'; the flight angle picks the gani direction). angle is radians, Graal-style: 0=right, PI/2=up, PI=left, 3*PI/2=down. speed is tiles/sec (max 100), lifetime seconds (max 60). data is any JSON-serializable payload, delivered to every callback.

The projectile stops on the first blocking tile (onShotAt on clientside scripts and the level's serverside NPCs), on lifetime expiry (same), on an NPC shape (onShot(data) on that NPC, server + client) or on a player (onShot(data) on the HIT player's clientside weapon scripts). Returns null outside a player-scoped handler or on bad arguments.

level.putnpc ​

ts
putnpc(x: number, y: number, serverScript: string, clientScript?: string): NpcThis | null

Spawns a LOCAL NPC at (x, y) in the current player's coordinate space: level tiles, or gmap-global tiles when they are on a gmap (the NPC lands in the member level under the point; off-grid returns null). The script arguments are inline TypeScript SOURCE strings (Graal putnpc2-style), compiled like level NPC scripts — the first compile of a novel script briefly blocks the server tick; identical sources are cached.

The NPC is never saved to the level file: it lives until destroy() or server restart, surviving level hot reloads (/clearnpcs <level> in RC clears strays). Returns the NPC's full this-style handle (see NpcThis) or null — like shoot, also null outside a player-scoped handler.

SqlRow type ​

ts
type SqlRow = Record<string, number | string | null | { $blob: string }>

A row returned by Database.query: column name -> value. SQLite INTEGERs arrive as JS numbers (values beyond 2^53 lose precision), REALs as numbers, TEXT as strings, NULL as null, and BLOBs wrapped as { $blob: base64 }. Duplicate column names collide in the object form — use AS aliases.

SqlParam type ​

ts
type SqlParam = number | string | boolean | null

A value bindable to a ? placeholder. Booleans store as SQLite's 1/0.

Database interface ​

ts
interface Database

A server-side SQLite database handle from opendatabase(). The database file is created lazily on the first query/exec. All SQL runs serialized on one server-wide worker thread; each statement is atomic (no cross-statement transaction API). Multi-statement SQL is allowed — all statements execute and the last result set with columns is returned.

Database.name ​

ts
readonly name: string

The database name this handle was opened with.

Database.query ​

ts
query(sql: string, params?: SqlParam[]): Promise<SqlRow[]>

Runs SQL and resolves with its rows. Parameters bind to bare ? placeholders in order.

Database.exec ​

ts
exec(sql: string, params?: SqlParam[]): Promise<{ rowsAffected: number; lastInsertRowId: number }>

Runs SQL and resolves with change counts: rowsAffected (rows inserted/updated/deleted) and lastInsertRowId (this connection's most recent INSERT rowid).

opendatabase function ​

ts
declare function opendatabase(name: string): Database

Opens a named server-side SQLite database (data/databases/<name>.db), creating it on first use. Names: 1-64 chars of letters, digits, _ and -; an invalid name throws synchronously. Pending queries of an unloaded script park unresolved across a hot reload, like cancelled sleeps.

CollectionQueryRow interface ​

ts
interface CollectionQueryRow

A record's replicated query() result row.

CollectionQueryRow.key ​

ts
key: string

CollectionQueryRow.record ​

ts
record: any

CollectionBag interface ​

ts
interface CollectionBag

One scope's records of a collection: key → JSON value. Reads and writes are synchronous against server memory; changes are delta-synced to the audience once per tick and persisted in the background. Record keys are 1-128 chars, record values up to 64 KB of JSON. Collections flagged read-only in RC's Collections tool reject set/patch/delete with a throw — their records are edited in RC (item catalogs); reads and query() still work. A collection may also carry a record SCHEMA (defined in RC): writes must then be objects with every required field present, matching types, and no fields outside the schema — violations throw with a precise message (patch is judged by the record it produces, not the fields passed).

CollectionBag.get ​

ts
get(key: string): any

The record's parsed value, or undefined. Returns a fresh copy — reassign via set/patch to write.

CollectionBag.keys ​

ts
keys(): string[]

All record keys, sorted.

CollectionBag.set ​

ts
set(key: string, value: any): void

Stores a record (whole-value replacement).

CollectionBag.patch ​

ts
patch(key: string, fields: Record<string, any>): void

Shallow-merges fields into the record — a targeted server-side op with no read-modify-write race. Patching a missing (or non-object) record replaces it wholesale.

CollectionBag.delete ​

ts
delete(key: string): void

Removes a record. Removing a missing key is a no-op.

CollectionBag.query ​

ts
query(opts?: { where?: string; params?: SqlParam[]; limit?: number; offset?: number }):
        Promise<CollectionQueryRow[]>

Paged SELECT against the collection's table (sql backing only). where addresses record fields by (dotted) name — 'itemId = ?' or 'ench.level > ?' — with params bound to ? in order. Default limit 100, max 1000. Pending writes flush first, so the query sees them.

Collection interface ​

ts
interface Collection extends CollectionBag

A collection handle. Global collections expose the record methods directly; account/level/group collections require .for(target) to pick the scope. The handle is stateless and resolves at use time.

Collection.name ​

ts
readonly name: string

Collection.for ​

ts
for(target: Player | string): CollectionBag

One scope's record set. The target depends on the collection's scope axis: a Player or bare account name (account — works for offline accounts), a member-level name (level), or a group id string (group).

Collection.subscribe ​

ts
subscribe(player: Player, scope?: string): void

Delivers a replica to an online player: for LAZY owner/all collections ("nothing ships until a script subscribes"), and for GROUP collections of either timing — there, subscription IS membership, so this is how a player joins a guild/party/trade audience. scope is required for group collections and must be omitted otherwise. Idempotent. The delivery is a snapshot, or a cheap catch-up when the client still has a cached copy. Throws for eager owner/all (delivered at login), level replicas (managed by level presence), audience 'none', and replicate 'cache' (clients pull records per-key with the clientside fetch()).

Collection.unsubscribe ​

ts
unsubscribe(player: Player, scope?: string): void

Revokes a subscribed replica: the client's mirror empties (its cached copy is kept for a later catch-up). No-op when not subscribed.

collection function ​

ts
declare function collection(name: string): Collection

A stateless handle on a collection: a server-authoritative, delta-synced, keyed record store. Collections are DEFINED BY STAFF in RC's Collections tool (persisted in data/collections.json, loaded at boot) — scripts can read and write records but deliberately cannot create collections or change their scope/audience/backing. Using an undefined collection throws at the call site, not here.

WeaponHandle interface ​

ts
interface WeaponHandle

A handle on another loaded weapon script, from findweapon().

WeaponHandle.name ​

ts
readonly name: string

The weapon's bare name, e.g. "gun".

WeaponHandle.trigger ​

ts
trigger(event: string, ...params: any[]): boolean

Invokes the named exported handler on that script RIGHT NOW (its own export, then any joined classes), with this bound to that script and the params passed as live values — a Player object arrives intact, no JSON round trip. The triggerClient player context is inherited. Returns false when the script has since unloaded or its handler threw (the error is logged); true otherwise, including when it exports no such handler.

findweapon function ​

ts
declare function findweapon(name: string): WeaponHandle | null

Finds the LOADED serverside half of a weapon (scripts/weapons/<name>.ts) so one script can call into another — the item system uses it to deliver onEquipped / onUnequipped / onItemUsed to an item's weapon script:

ts
findweapon('gun')?.trigger('onEquipped', player, entry)

null when no such weapon script is loaded. Names never contain '/'.

findWeapon function ​

ts
declare function findWeapon(name: string): WeaponHandle | null

Alias of findweapon.