Async & networking

Async & networking

s2script integrates Promises with the game frame. Timers and network I/O never block the main thread.

Timers

import { delay, nextTick, nextFrame, threadSleep } from '@s2script/timers';

await nextTick();       // after current microtasks
await nextFrame();      // next OnGameFrame
await delay(1000);      // ~1s, frame-integrated
await threadSleep(50);  // threadpool sleep, marshalled back on the frame drain

HTTP

import { fetch } from '@s2script/http';

const res = await fetch('https://example.com/api', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ steamId }),
  timeoutMs: 10_000
});

if (res.ok) {
  const data = await res.json();
}

HTTP status errors (4xx/5xx) resolve with ok: false (web-fetch parity — useful on the join path). Only network failures and timeouts reject. Bodies are buffered (10MB cap); binary deferred.

WebSocket

import { WebSocket } from '@s2script/ws';

const ws = await WebSocket.connect('wss://example.com/ws');
ws.onMessage((text) => console.log(text));
ws.onClose((code) => console.log('closed', code));
ws.send('hello');
ws.close();

Subscribe to onMessage synchronously after await connect so early frames are not missed. Connections are owner-scoped and closed on plugin unload.

Database

import { Database } from '@s2script/db';

const db = await Database.open('myplugin');
await db.execute('CREATE TABLE IF NOT EXISTS boots (id INTEGER PRIMARY KEY)');
const rows = await db.query('SELECT * FROM boots');
await db.close();

API is Promise-based (SQLite runs in-process today; the contract stays async for a future threadpool move). Handles are opaque integers, owner-scoped, and ledgered.

Browse modules: timers, http, ws, db.

s2script — Source 2 plugin framework

GitHub