Appearance
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): voidPrints 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[]): numberRuns 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): voidCancels a pending setTimeout by id.
setInterval function
ts
declare function setInterval(handler: (...args: any[]) => void, ms?: number, ...args: any[]): numberRuns 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): voidCancels a running setInterval by id.
triggerClient function
ts
declare function triggerClient(scriptType: 'weapon', scriptName: string, ...params: any[]): voidSends 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): voidSends 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): stringCreates 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): booleanSets 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 } | nullConverts 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 } | nullConverts 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 ScriptThisEvery 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: stringThe script's name, e.g. "test" for test.ts or weapons/test.ts.
ScriptThis.join
ts
join(name: string): booleanJoins 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): booleanRemoves 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]: anyScripts 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: stringDisplay name of the server.
serverOptions.startLevel
ts
readonly startLevel: stringLevel new accounts start in; returning players resume their saved level.
serverOptions.startX
ts
readonly startX: numberStart position for new accounts, in tiles.
serverOptions.startY
ts
readonly startY: numberStart position for new accounts, in tiles.
serverOptions.maxPlayers
ts
readonly maxPlayers: numberMaximum simultaneous logged-in players; 0 or less means unlimited.
serverOptions.[key]
ts
readonly [key: string]: anyAdmin-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 PlayerSnapshot 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: numberServer-assigned player id, unique per login.
Player.account
ts
account: stringAccount name the player logged in with.
Player.nick
ts
nick: stringDisplay 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 | nullThe 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: numberPosition in tiles. Read-only in practice: move players with warpto.
Player.y
ts
y: numberPosition in tiles. Read-only in practice: move players with warpto.
Player.chat
ts
chat: stringChat 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): voidPlays 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: stringCurrent animation name (without the .gan extension).
Player.head
ts
head: stringHead image, e.g. 'head0.png'. '' means the client default.
Player.body
ts
body: stringBody 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): booleanWhether 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): booleanWarps 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): booleanGrants 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): booleanTakes 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): booleanWhether 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.playeris the triggering player; the client's params follow (JSON round-tripped). triggerClient inside answers that same player.
ServerLevel interface
ts
interface ServerLevelA 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: stringThe level's file name, e.g. "start.glvl" (or "world.gmap").
ServerLevel.putnpc
ts
putnpc(x: number, y: number, serverScript: string, clientScript?: string): NpcThis | nullSpawns 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): booleanTrue 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): numberCollision 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 | nullSpawns 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 ProjectileA live projectile spawned by level.shoot.
Projectile.id
ts
readonly id: numberUnique id for this server run.
Projectile.destroy
ts
destroy(): booleanRemoves 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: stringThe 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 | nullSpawns 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 | nullSpawns 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 | nullA value bindable to a ? placeholder. Booleans store as SQLite's 1/0.
Database interface
ts
interface DatabaseA 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: stringThe 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): DatabaseOpens 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 CollectionQueryRowA record's replicated query() result row.
CollectionQueryRow.key
ts
key: stringCollectionQueryRow.record
ts
record: anyCollectionBag interface
ts
interface CollectionBagOne 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): anyThe 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): voidStores a record (whole-value replacement).
CollectionBag.patch
ts
patch(key: string, fields: Record<string, any>): voidShallow-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): voidRemoves 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 CollectionBagA 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: stringCollection.for
ts
for(target: Player | string): CollectionBagOne 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): voidDelivers 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): voidRevokes 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): CollectionA 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 WeaponHandleA handle on another loaded weapon script, from findweapon().
WeaponHandle.name
ts
readonly name: stringThe weapon's bare name, e.g. "gun".
WeaponHandle.trigger
ts
trigger(event: string, ...params: any[]): booleanInvokes 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 | nullFinds 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 | nullAlias of findweapon.