scmJS docs

api.sync

SyncApi

Editing the map in front together with other editors: every change to it is handed out as an op for the plugin to carry to them, and theirs come back in, in the order a server puts them. The scmjs.dev plugin's shared maps are built on it; the transport, the server and who may join are the plugin's.

Members

start

start(options: SyncStartOptions): SyncSession | null;

Share the map in front. Null when no map is open or another session is running (one at a time). A session a plugin started stops when the plugin is turned off.

current

current(): SyncSession | null;

The running session, whichever plugin started it.

Types

Declarations only this group names.

WireListChangeinterface

interface WireListChange
index: number
before: T | null
after: T | null

WireLocationChangeinterface

interface WireLocationChange
index: number
after: LocationRecord
name: string | null

The name as text (after.nameIndex is resolved again where it lands); null for none.

created: boolean

The slot was empty before: a new location, which moves to a free slot if someone else took this one.

SyncEditOpinterface

interface SyncEditOp

One undo step's worth of terrain and objects. The grids are flat number lists: terrain [at, mtxm, tile, …], the others [at, value, …]. reverse marks the undo of an edit: its parts go in the reverse of the usual order, as undo walks them.

kind: "edit"
label: string
width: number

The map size the cells index; a grid part is skipped on a map of another size.

height: number
reverse?: boolean
terrain?: number[]
isom?: number[]
doodadTiles?: number[]
fog?: number[]
isomWhole?: string | null

The whole ISOM lattice (base64 of the u16 cells) the edit gave the map, or null for taking it away.

maskWhole?: string | null
units?: WireListChange<UnitRecord>[]
doodads?: WireListChange<DoodadRecord>[]
sprites?: WireListChange<SpriteRecord>[]
locations?: WireLocationChange[]

SYNC_FIELDSconst

const SYNC_FIELDS: readonly [
	"type",
	"fileVersion",
	"nameIndex",
	"descriptionIndex",
	"playerTypes",
	"editorPlayerTypes",
	"playerRaces",
	"playerColors",
	"playerRgb",
	"forces",
	"unitSettings",
	"unitAvailability",
	"upgradeSettings",
	"upgradeRestrictions",
	"techSettings",
	"techRestrictions",
	"wavs",
	"cuwp",
	"cuwpUsed",
	"triggers",
	"briefing",
	"switchNames"
]

SyncFieldtype

type SyncField = (typeof SYNC_FIELDS)[number];

SyncFieldsOpinterface

interface SyncFieldsOp
kind: "fields"
set: Partial<Record<SyncField, unknown>>

Each changed field's new value, packed (pack).

strings?: [ number, string | null, string | null ][]

String slots that changed: [index, before, after].

stringsLength?: number

The table's length afterwards (trailing blank slots are dropped).

stringsFormat?: { extended: boolean; encoding: TextEncoding; }

The table's width and text encoding, when they changed.

SyncExtrasOpinterface

interface SyncExtrasOp
kind: "extras"
set: [ string, string | null ][]

[member name, base64 bytes], or null bytes for a member taken out.

SyncResetOpinterface

interface SyncResetOp
kind: "reset"
label: string
chk: string

The whole scenario, base64.

SyncHoldtype

type SyncHold = "stroke" | "dialog" | "behind";

Why other people's changes are waiting: a stroke under way on the map, a dialog that edits the map open, another map in front.

SyncReportinterface

interface SyncReport
ops: number

Other people's ops applied.

dropped: number

Parts of them that could not be applied — the unit they moved was deleted, the map was resized…

lost: number

Parts of this editor's unconfirmed changes that no longer applied on top of theirs.

SyncStartOptionsinterface

interface SyncStartOptions
send(op: SyncOp): void

Every change made to the shared map, as a plain object JSON can carry, in the order made: commits, undo and redo, the dialogs' writes, archive files, and a resize or a tileset change (the whole scenario). Each must reach the server, and every other editor, in this order.

onEnd?(reason: "closed" | "stopped"): void

The session ended: the shared map was closed or replaced by another, or stop was called.

onApplied?(report: SyncReport): void

Other people's changes were applied to the map.

SyncSessioninterface

interface SyncSession

One shared map. The server confirms each op this editor sent (confirm, in order) and relays everyone else's (receive, in the order it gave them); the session applies them to the map when nothing is in the way (holding) and rebases this editor's unconfirmed changes on top, so every editor that has seen the same ops has the same map.

readonly documentId: number

The shared map's document.id().

receive(op: unknown): boolean

Another editor's op, in the server's order. False, and nothing done, for a value that is not an op.

confirm(): void

The server confirmed the oldest op this editor sent.

pending(): number

Ops sent and not yet confirmed.

waiting(): number

Ops and confirmations received and not yet applied.

snapshot(): Promise<Uint8Array | null>

The shared map as a file (.scx / .scm, not built), copied at this moment — for a server to hand people joining, labelled with the last op this editor applied. Null while anything is pending or waiting (the copy would not match any point in the server's order) or while another map is in front. The copy is taken before the first await, so a change made while the file is written is not in it.

holding(): SyncHold | null
stop(): void
const session = api.sync.start({ send: (op) => socket.send(JSON.stringify({ type: "op", op })) });
socket.onmessage = (m) => {
  const msg = JSON.parse(m.data);
  if (msg.type === "ack") session?.confirm();
  if (msg.type === "op") session?.receive(msg.op);
};

Seen in

scmJS 0.6.2 + main@dd79a77 · Generated from the repository. The source is under the MIT license, which does not cover what ATTRIBUTION.md lists. StarCraft and Brood War are trademarks of Blizzard Entertainment; this project ships none of their data.