incanto 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +30 -0
- package/README.md +36 -0
- package/THIRD-PARTY-NOTICES.md +88 -0
- package/assets/audio/attacked.mp3 +0 -0
- package/assets/audio/explosion.mp3 +0 -0
- package/assets/audio/gold_loot.mp3 +0 -0
- package/assets/audio/heal.mp3 +0 -0
- package/assets/audio/hit_metal_bang.mp3 +0 -0
- package/assets/audio/ice_spear.mp3 +0 -0
- package/assets/audio/monster_died.mp3 +0 -0
- package/assets/audio/slash.mp3 +0 -0
- package/assets/audio/smite.mp3 +0 -0
- package/assets/audio/spells_cast.mp3 +0 -0
- package/assets/audio/ui_click.wav +0 -0
- package/assets/audio/walk.mp3 +0 -0
- package/assets/catalog.json +390 -0
- package/assets/characters/2dbasic.json +41 -0
- package/assets/characters/2dbasic.png +0 -0
- package/assets/characters/ghost.json +46 -0
- package/assets/characters/ghost.png +0 -0
- package/assets/characters/goblin.json +40 -0
- package/assets/characters/goblin.png +0 -0
- package/assets/characters/medieval-knight.json +41 -0
- package/assets/characters/medieval-knight.png +0 -0
- package/assets/effects/swoosh.png +0 -0
- package/assets/items/box.png +0 -0
- package/assets/items/buff_potion.png +0 -0
- package/assets/items/coin.png +0 -0
- package/assets/items/gem.png +0 -0
- package/assets/items/gold.png +0 -0
- package/assets/items/hp_potion.png +0 -0
- package/assets/items/locked_item_box.png +0 -0
- package/assets/items/map.png +0 -0
- package/assets/items/resurrection_potion.png +0 -0
- package/assets/items/super_box.png +0 -0
- package/assets/items/trap.png +0 -0
- package/assets/tiles/floor00.jpg +0 -0
- package/assets/tiles/minecraft-tiles.png +0 -0
- package/assets/tiles/wall00.jpg +0 -0
- package/assets/vegetation/ash_color.png +0 -0
- package/assets/vegetation/aspen_color.png +0 -0
- package/assets/vegetation/bark/birch_color_1k.jpg +0 -0
- package/assets/vegetation/bark/birch_normal_1k.jpg +0 -0
- package/assets/vegetation/bark/birch_roughness_1k.jpg +0 -0
- package/assets/vegetation/bark/oak_color_1k.jpg +0 -0
- package/assets/vegetation/bark/oak_normal_1k.jpg +0 -0
- package/assets/vegetation/bark/oak_roughness_1k.jpg +0 -0
- package/assets/vegetation/bark/pine_color_1k.jpg +0 -0
- package/assets/vegetation/bark/pine_normal_1k.jpg +0 -0
- package/assets/vegetation/bark/pine_roughness_1k.jpg +0 -0
- package/assets/vegetation/ground/dirt_color.jpg +0 -0
- package/assets/vegetation/ground/dirt_normal.jpg +0 -0
- package/assets/vegetation/ground/grass.jpg +0 -0
- package/assets/vegetation/oak_color.png +0 -0
- package/assets/vegetation/pine_color.png +0 -0
- package/bin/incanto-assets.mjs +107 -0
- package/bin/incanto-check.mjs +107 -0
- package/bin/incanto-editor.mjs +343 -0
- package/bin/incanto-env.mjs +144 -0
- package/bin/incanto-model.mjs +296 -0
- package/bin/incanto-play.mjs +219 -0
- package/bin/incanto-skills.mjs +71 -0
- package/dist/2d.d.ts +642 -0
- package/dist/2d.js +44 -0
- package/dist/3d.d.ts +1860 -0
- package/dist/3d.js +5 -0
- package/dist/agent8-DzU2fFyH.js +129 -0
- package/dist/audio-player-DqUR3XFs.d.ts +110 -0
- package/dist/behavior-BAQq7HGM.d.ts +851 -0
- package/dist/create-game-BdjpTHrW.js +1725 -0
- package/dist/create-game-CZHROKcT.js +527 -0
- package/dist/debug-draw-CZmOYjL2.js +13 -0
- package/dist/debug.d.ts +66 -0
- package/dist/debug.js +658 -0
- package/dist/duplicate-DP2WPYom.js +22 -0
- package/dist/env.d.ts +430 -0
- package/dist/env.js +3152 -0
- package/dist/errors-BMFaY68Q.d.ts +33 -0
- package/dist/errors-BpWbnbb_.js +13 -0
- package/dist/gameplay-Ccruc3Wd.js +1501 -0
- package/dist/gameplay.d.ts +543 -0
- package/dist/gameplay.js +2 -0
- package/dist/heightmap-CroQPEER.js +185 -0
- package/dist/index.d.ts +305 -0
- package/dist/index.js +62 -0
- package/dist/json-BLk7H2Qa.js +30 -0
- package/dist/loader-CGs_G-r0.js +919 -0
- package/dist/loader-Mo0KghCv.d.ts +41 -0
- package/dist/net.d.ts +427 -0
- package/dist/net.js +772 -0
- package/dist/noise-CGUMx44x.js +82 -0
- package/dist/particle-sim-CbN4YUuH.d.ts +63 -0
- package/dist/particle-sim-DYuSUxvK.js +1319 -0
- package/dist/physics-2d-KuMWPTf6.js +288 -0
- package/dist/physics-3d-Dl67vOLT.js +434 -0
- package/dist/react.d.ts +65 -0
- package/dist/react.js +209 -0
- package/dist/register-BuUV1_KB.js +561 -0
- package/dist/register-CNlYAS1_.js +10634 -0
- package/dist/register-DPEV9_9t.js +851 -0
- package/dist/register-Dasmnurl.js +374 -0
- package/dist/registry-BVJ2HbCn.js +132 -0
- package/dist/rng-DP-SR7eg.js +38 -0
- package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/schema-CcoWb32N.d.ts +104 -0
- package/dist/test.d.ts +158 -0
- package/dist/test.js +275 -0
- package/dist/touch-031PxtCR.js +208 -0
- package/dist/vite.d.ts +26 -0
- package/dist/vite.js +57 -0
- package/editor/assets/GameServer-C56iOUgF.js +1 -0
- package/editor/assets/agent8-Bp7QFI7v.js +1 -0
- package/editor/assets/index-DF3tMeKJ.css +1 -0
- package/editor/assets/index-Dl2pjA8e.js +7365 -0
- package/editor/assets/rapier-CEuLKeCu.js +1 -0
- package/editor/assets/rapier-DE6a0vmv.js +1 -0
- package/editor/index.html +169 -0
- package/package.json +97 -0
- package/schemas/scene.schema.json +4254 -0
- package/skills/README.md +9 -0
- package/skills/incanto-3d-character.md +229 -0
- package/skills/incanto-3d-models.md +151 -0
- package/skills/incanto-assets.md +118 -0
- package/skills/incanto-audio.md +309 -0
- package/skills/incanto-behaviors-and-scripts.md +169 -0
- package/skills/incanto-building-2d-games.md +242 -0
- package/skills/incanto-building-3d-games.md +245 -0
- package/skills/incanto-editor.md +163 -0
- package/skills/incanto-environment.md +743 -0
- package/skills/incanto-gameplay-behaviors.md +707 -0
- package/skills/incanto-multiplayer.md +264 -0
- package/skills/incanto-node-reference.md +797 -0
- package/skills/incanto-physics-and-input.md +164 -0
- package/skills/incanto-scene-json-authoring.md +325 -0
- package/skills/incanto-verifying-your-game.md +191 -0
- package/skills/incanto-web-integration.md +96 -0
- package/templates/agent8-server.js +84 -0
- package/templates/agent8-server.ts +138 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { i as SceneJson } from "./schema-CcoWb32N.js";
|
|
2
|
+
import { v as Engine, w as Scene } from "./behavior-BAQq7HGM.js";
|
|
3
|
+
|
|
4
|
+
//#region src/core/scene/loader.d.ts
|
|
5
|
+
interface LoadSceneOptions {
|
|
6
|
+
/** Resolve a sub-scene path referenced by `{instance: '<path>'}`. */
|
|
7
|
+
resolveScene?: (path: string) => SceneJson;
|
|
8
|
+
/**
|
|
9
|
+
* Tool/preview mode (the editor's ▶ play strips behaviors — and their
|
|
10
|
+
* `static signals` with them): declare each connection's signal on its
|
|
11
|
+
* from-node instead of hard-failing with UNKNOWN_SIGNAL. Games should
|
|
12
|
+
* NOT set this — the strict default catches typos.
|
|
13
|
+
*/
|
|
14
|
+
declareConnectionSignals?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Validation/tool mode (incanto-check, structure-only validation without
|
|
17
|
+
* the game's TypeScript): scripts naming UNREGISTERED behaviors get a no-op
|
|
18
|
+
* stub — props unvalidated, handlers accepted. Registered behaviors still
|
|
19
|
+
* validate for real. Games should NOT set this.
|
|
20
|
+
*/
|
|
21
|
+
stubMissingBehaviors?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Attach the engine BEFORE onEnterTree/onReady fire, so behaviors can use
|
|
24
|
+
* `this.engine` / `this.rng` / `this.log` in onReady. `createGame` does
|
|
25
|
+
* this for you; pair it with `engine.setScene(scene)` afterwards.
|
|
26
|
+
*/
|
|
27
|
+
engine?: Engine;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build a live Scene from scene JSON.
|
|
31
|
+
*
|
|
32
|
+
* Takes `unknown` on purpose: the loader hard-validates everything at runtime,
|
|
33
|
+
* so consumers can pass an imported JSON module without TypeScript casts.
|
|
34
|
+
*
|
|
35
|
+
* Order: validate header → instantiate nodes top-down → attach to a SceneTree
|
|
36
|
+
* (enterTree/ready fire) → wire connections LAST. Every failure is a hard
|
|
37
|
+
* IncantoError naming valid alternatives — agents self-correct on hard errors.
|
|
38
|
+
*/
|
|
39
|
+
declare function loadScene(json: unknown, opts?: LoadSceneOptions): Scene;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { loadScene as n, LoadSceneOptions as t };
|
package/dist/net.d.ts
ADDED
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { c as JsonValue, i as SceneJson, s as JsonObject } from "./schema-CcoWb32N.js";
|
|
2
|
+
import { T as Node, et as Signal, l as PropSchema, v as Engine } from "./behavior-BAQq7HGM.js";
|
|
3
|
+
|
|
4
|
+
//#region src/net/types.d.ts
|
|
5
|
+
type Unsubscribe = () => void;
|
|
6
|
+
/**
|
|
7
|
+
* Incanto's pluggable multiplayer transport contract. The engine speaks ONLY
|
|
8
|
+
* this interface — any backend works by implementing it:
|
|
9
|
+
*
|
|
10
|
+
* - `LoopbackTransport` (built in): in-memory — offline dev, tests, split-screen
|
|
11
|
+
* - `createAgent8Server()` (built in): adapter for `@agent8/gameserver`
|
|
12
|
+
* - your own: Socket.IO, Colyseus, Supabase Realtime, a custom WebSocket server…
|
|
13
|
+
*
|
|
14
|
+
* The room protocol a transport's backend must answer via `remoteFunction`:
|
|
15
|
+
* `joinRoom(roomId?) → roomId` · `leaveRoom(roomId)` · `setMyState(roomId, patch)`
|
|
16
|
+
* (SHALLOW merge) · `patchRoomState(roomId, patch)` · `addEntity(roomId, coll,
|
|
17
|
+
* entity) → id` · `updateEntity(roomId, coll, id, patch)` · `removeEntity(roomId,
|
|
18
|
+
* coll, id)` · `sendEvent(roomId, type, payload)`.
|
|
19
|
+
* (The shape happens to align with @agent8/gameserver's GameServer class, so that
|
|
20
|
+
* adapter is thin — but nothing in the engine depends on that backend.)
|
|
21
|
+
*/
|
|
22
|
+
interface NetworkTransport {
|
|
23
|
+
readonly account: string;
|
|
24
|
+
readonly connected: boolean;
|
|
25
|
+
connect(): Promise<boolean>;
|
|
26
|
+
disconnect(): Promise<void>;
|
|
27
|
+
/** Calls a function defined in the game's server.js (see templates/agent8-server.js). */
|
|
28
|
+
remoteFunction(fn: string, args?: unknown[], opts?: {
|
|
29
|
+
needResponse?: boolean;
|
|
30
|
+
throttle?: number;
|
|
31
|
+
throttleKey?: string;
|
|
32
|
+
}): Promise<unknown>;
|
|
33
|
+
subscribeRoomState(roomId: string, cb: (state: JsonObject) => void): Unsubscribe;
|
|
34
|
+
subscribeRoomMyState(roomId: string, cb: (state: JsonObject) => void): Unsubscribe;
|
|
35
|
+
subscribeRoomAllUserStates(roomId: string, cb: (states: Record<string, JsonObject>) => void): Unsubscribe;
|
|
36
|
+
subscribeRoomCollection(roomId: string, collectionId: string, cb: (entities: Record<string, JsonObject>) => void): Unsubscribe;
|
|
37
|
+
onRoomMessage(roomId: string, type: string, cb: (message: JsonValue) => void): Unsubscribe;
|
|
38
|
+
onRoomUserJoin(roomId: string, cb: (account: string) => void): Unsubscribe;
|
|
39
|
+
onRoomUserLeave(roomId: string, cb: (account: string) => void): Unsubscribe;
|
|
40
|
+
/**
|
|
41
|
+
* GLOBAL (cross-room, persistent) channels — OPTIONAL. A backend that has no
|
|
42
|
+
* global tier (e.g. the fixed `LoopbackHub`) simply omits them; NetworkManager
|
|
43
|
+
* degrades gracefully (its global signals never fire). `LocalGameServer` and the
|
|
44
|
+
* agent8 adapter implement them. Each fires the current value once on subscribe.
|
|
45
|
+
*/
|
|
46
|
+
subscribeGlobalState?(cb: (state: JsonObject) => void): Unsubscribe;
|
|
47
|
+
/** The caller's own global user state. */
|
|
48
|
+
subscribeGlobalMyState?(cb: (state: JsonObject) => void): Unsubscribe;
|
|
49
|
+
subscribeGlobalUserState?(account: string, cb: (state: JsonObject) => void): Unsubscribe;
|
|
50
|
+
subscribeGlobalCollection?(collectionId: string, cb: (entities: Record<string, JsonObject>) => void): Unsubscribe;
|
|
51
|
+
/** An account's currency ledger (`$asset`). */
|
|
52
|
+
subscribeAsset?(account: string, cb: (assets: Record<string, number>) => void): Unsubscribe;
|
|
53
|
+
onGlobalMessage?(type: string, cb: (message: JsonValue) => void): Unsubscribe;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/net/agent8.d.ts
|
|
57
|
+
/**
|
|
58
|
+
* The real transport: wraps `@agent8/gameserver`'s framework-free GameServer
|
|
59
|
+
* class via a DEEP dynamic import (the package index re-exports React hooks
|
|
60
|
+
* and zustand stores we must never pull in). The SDK is an optional peer dep —
|
|
61
|
+
* games without multiplayer never load (or need) it.
|
|
62
|
+
*
|
|
63
|
+
* Adapter responsibilities beyond pass-through:
|
|
64
|
+
* 1. allUserStates shape conversion: v2 delivers a fully delta-merged ARRAY of
|
|
65
|
+
* `{...state, account, __updated}` (left users already removed from it). We
|
|
66
|
+
* convert that to incanto's account-keyed Record, stripping the v2-internal
|
|
67
|
+
* `account`/`__updated`/`__leaved` markers, and emit it as a full snapshot.
|
|
68
|
+
* 2. collection shape conversion: v2 delivers `{items: [{__id, …}], changes}`;
|
|
69
|
+
* we convert the merged `items` array to incanto's `__id`-keyed Record.
|
|
70
|
+
* 3. Reconnect: the SDK clears pending subscriptions on disconnect and never
|
|
71
|
+
* restores them — we re-issue every active subscription after reconnect.
|
|
72
|
+
*/
|
|
73
|
+
declare function createAgent8Server(config?: {
|
|
74
|
+
verse?: string;
|
|
75
|
+
account?: string;
|
|
76
|
+
auth?: string;
|
|
77
|
+
}): Promise<NetworkTransport>;
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/net/loopback.d.ts
|
|
80
|
+
interface Room {
|
|
81
|
+
users: Map<string, JsonObject>;
|
|
82
|
+
state: JsonObject;
|
|
83
|
+
collections: Map<string, Map<string, JsonObject>>;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* In-memory multiplayer hub implementing the SAME kernel contract as
|
|
87
|
+
* `templates/agent8-server.js` — local split-screen demos, offline development,
|
|
88
|
+
* and headless tests run real multi-client flows without any infrastructure.
|
|
89
|
+
*/
|
|
90
|
+
declare class LoopbackHub {
|
|
91
|
+
private readonly rooms;
|
|
92
|
+
private accountSeq;
|
|
93
|
+
private roomSeq;
|
|
94
|
+
private entitySeq;
|
|
95
|
+
/** Per-room listener registries, keyed by roomId. */
|
|
96
|
+
private readonly listeners;
|
|
97
|
+
createClient(account?: string): LoopbackTransport;
|
|
98
|
+
/** @internal */
|
|
99
|
+
_room(roomId: string): Room;
|
|
100
|
+
/** @internal The server.js kernel, in memory. */
|
|
101
|
+
_call(account: string, fn: string, args: unknown[]): unknown;
|
|
102
|
+
/** @internal */
|
|
103
|
+
_subscribe<K extends keyof LoopbackHub["listeners"]>(kind: K, roomId: string, entry: LoopbackHub["listeners"][K] extends Map<string, Set<infer E>> ? E : never): Unsubscribe;
|
|
104
|
+
/** @internal */
|
|
105
|
+
_snapshotUsers(roomId: string): Record<string, JsonObject>;
|
|
106
|
+
/** @internal */
|
|
107
|
+
_snapshotCollection(roomId: string, collectionId: string): Record<string, JsonObject>;
|
|
108
|
+
/** @internal */
|
|
109
|
+
_snapshotRoomState(roomId: string): JsonObject;
|
|
110
|
+
private fire;
|
|
111
|
+
private fireAllUsers;
|
|
112
|
+
private fireCollection;
|
|
113
|
+
}
|
|
114
|
+
/** A client on a LoopbackHub. Subscriptions fire immediately with a snapshot. */
|
|
115
|
+
declare class LoopbackTransport implements NetworkTransport {
|
|
116
|
+
private readonly hub;
|
|
117
|
+
readonly account: string;
|
|
118
|
+
connected: boolean;
|
|
119
|
+
constructor(hub: LoopbackHub, account: string);
|
|
120
|
+
connect(): Promise<boolean>;
|
|
121
|
+
disconnect(): Promise<void>;
|
|
122
|
+
remoteFunction(fn: string, args?: unknown[]): Promise<unknown>;
|
|
123
|
+
subscribeRoomState(roomId: string, cb: (state: JsonObject) => void): Unsubscribe;
|
|
124
|
+
subscribeRoomMyState(roomId: string, cb: (state: JsonObject) => void): Unsubscribe;
|
|
125
|
+
subscribeRoomAllUserStates(roomId: string, cb: (states: Record<string, JsonObject>) => void): Unsubscribe;
|
|
126
|
+
subscribeRoomCollection(roomId: string, collectionId: string, cb: (entities: Record<string, JsonObject>) => void): Unsubscribe;
|
|
127
|
+
onRoomMessage(roomId: string, type: string, cb: (message: JsonValue) => void): Unsubscribe;
|
|
128
|
+
onRoomUserJoin(roomId: string, cb: (account: string) => void): Unsubscribe;
|
|
129
|
+
onRoomUserLeave(roomId: string, cb: (account: string) => void): Unsubscribe;
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/net/local-game-server.d.ts
|
|
133
|
+
/** A user's `server/src/server.ts` `Server` class (or any class with room methods). */
|
|
134
|
+
type ServerClass = new () => object;
|
|
135
|
+
interface LocalGameServerOptions {
|
|
136
|
+
/**
|
|
137
|
+
* The game's `Server` class from `server/src/server.ts` (the v2 structured
|
|
138
|
+
* project). Omit it to fall back to the built-in kernel only — identical to a
|
|
139
|
+
* raw `LoopbackHub`.
|
|
140
|
+
*/
|
|
141
|
+
server?: ServerClass;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Run a multiplayer game's REAL agent8-sdk-v2 `Server` class **locally**, in
|
|
145
|
+
* memory, with NO cloud and NO auth — the preview/dev path.
|
|
146
|
+
*
|
|
147
|
+
* `LoopbackHub` answers only the fixed built-in room protocol (joinRoom,
|
|
148
|
+
* setMyState, collections, events). Real games add server-AUTHORITATIVE rules
|
|
149
|
+
* (`awardPoint`, `castSpell`, `$roomTick` match clocks) in `server/src/server.ts`
|
|
150
|
+
* against the v2 contexts `$sender`/`$global`/`$room`/`$lock`. LocalGameServer
|
|
151
|
+
* runs that exact class body so the whole game — client + server logic — is
|
|
152
|
+
* playable in dev before it ever touches the Agent8 platform. Swap
|
|
153
|
+
* `local.createClient(account)` for `await createAgent8Server()` to go live;
|
|
154
|
+
* nothing else changes.
|
|
155
|
+
*
|
|
156
|
+
* How it stays faithful to the isolated-vm platform:
|
|
157
|
+
* - A FRESH `Server` instance runs per request, so `this.*` never persists.
|
|
158
|
+
* - The v2 globals are injected on `globalThis` for the duration of each call
|
|
159
|
+
* (the SAME `server/src/server.ts` body that reads bare `$room`/`$sender`
|
|
160
|
+
* runs unmodified).
|
|
161
|
+
* - Calls are SERIALIZED through one queue, so a global binding can't leak across
|
|
162
|
+
* another request's `await`s (the platform isolates per request; we serialize).
|
|
163
|
+
* - `$roomTick(deltaMS, roomId)` runs only while a room has users — drive it from
|
|
164
|
+
* the engine: `engine.updated.connect((dt) => local.tick(dt * 1000))`.
|
|
165
|
+
*
|
|
166
|
+
* NOT a substitute for the cloud: no isolated-vm sandboxing, no persistence, no
|
|
167
|
+
* rate limits — a faithful FUNCTIONAL emulator for local play and tests.
|
|
168
|
+
*/
|
|
169
|
+
declare class LocalGameServer {
|
|
170
|
+
private readonly hub;
|
|
171
|
+
private readonly serverClass?;
|
|
172
|
+
/** Each client's current room — binds `$sender.roomId` on later calls. */
|
|
173
|
+
private readonly clientRooms;
|
|
174
|
+
/** All remoteFunction/tick calls run one-at-a-time so injected globals never overlap. */
|
|
175
|
+
private queue;
|
|
176
|
+
/** Per-key mutex backing `$lock`. */
|
|
177
|
+
private readonly locks;
|
|
178
|
+
/** Persistent (process-lifetime) store backing the `$global` + `$asset` contexts. */
|
|
179
|
+
private readonly g_state;
|
|
180
|
+
private readonly g_userStates;
|
|
181
|
+
private readonly g_collections;
|
|
182
|
+
private readonly g_assets;
|
|
183
|
+
private g_seq;
|
|
184
|
+
/** Client-side global/asset subscription registries (fanned out on mutation). */
|
|
185
|
+
private readonly subState;
|
|
186
|
+
private readonly subUser;
|
|
187
|
+
private readonly subColl;
|
|
188
|
+
private readonly subAsset;
|
|
189
|
+
private readonly subMsg;
|
|
190
|
+
constructor(serverClass?: ServerClass);
|
|
191
|
+
/** A client on this server. Distinct `account` per player (default auto-assigned). */
|
|
192
|
+
createClient(account?: string): LocalGameServerTransport;
|
|
193
|
+
private collectionSnapshot;
|
|
194
|
+
private assetSnapshot;
|
|
195
|
+
/** @internal */
|
|
196
|
+
subscribeGlobalState(cb: (s: JsonObject) => void): Unsubscribe;
|
|
197
|
+
/** @internal */
|
|
198
|
+
subscribeGlobalUserState(account: string, cb: (s: JsonObject) => void): Unsubscribe;
|
|
199
|
+
/** @internal */
|
|
200
|
+
subscribeGlobalCollection(id: string, cb: (r: Record<string, JsonObject>) => void): Unsubscribe;
|
|
201
|
+
/** @internal */
|
|
202
|
+
subscribeAsset(account: string, cb: (a: Record<string, number>) => void): Unsubscribe;
|
|
203
|
+
/** @internal Messages are events — no immediate snapshot. */
|
|
204
|
+
onGlobalMessage(account: string, type: string, cb: (m: JsonValue) => void): Unsubscribe;
|
|
205
|
+
private fireState;
|
|
206
|
+
private fireUser;
|
|
207
|
+
private fireColl;
|
|
208
|
+
private fireAsset;
|
|
209
|
+
private fireMsg;
|
|
210
|
+
/**
|
|
211
|
+
* Advance server-driven periodic logic. Calls the `Server`'s `$roomTick(deltaMS,
|
|
212
|
+
* roomId)` once per room that currently has users. No-op without a `$roomTick`.
|
|
213
|
+
*/
|
|
214
|
+
tick(deltaMS: number): Promise<void>;
|
|
215
|
+
/** @internal Dispatch a remoteFunction (serialized). */
|
|
216
|
+
call(account: string, fn: string, args: unknown[]): Promise<unknown>;
|
|
217
|
+
private enqueue;
|
|
218
|
+
private dispatch;
|
|
219
|
+
private runTick;
|
|
220
|
+
/** Install the v2 globals for one dispatch; returns a restorer. */
|
|
221
|
+
private bindGlobals;
|
|
222
|
+
/**
|
|
223
|
+
* The `$global` context — room membership, persistent GLOBAL state/user-state/
|
|
224
|
+
* collections, room management, and global messaging. Backed by an in-memory
|
|
225
|
+
* store that survives between requests (unlike rooms, which the hub clears when
|
|
226
|
+
* empty) — matching the platform's persistent-global / ephemeral-room split.
|
|
227
|
+
*/
|
|
228
|
+
private globalContext;
|
|
229
|
+
/**
|
|
230
|
+
* The `$asset` context — a per-account currency ledger. `burn`/`transfer` throw
|
|
231
|
+
* on an insufficient balance (the documented pattern always checks `has` first),
|
|
232
|
+
* surfacing economy bugs in preview just as the platform would.
|
|
233
|
+
*/
|
|
234
|
+
private assetContext;
|
|
235
|
+
/** The `$room` context, bound to one room — maps onto the hub's kernel primitives. */
|
|
236
|
+
private roomContext;
|
|
237
|
+
private withLock;
|
|
238
|
+
}
|
|
239
|
+
/** Firebase-style query options for `$global`/`$room` collections (preview subset). */
|
|
240
|
+
interface CollectionOptions {
|
|
241
|
+
filters?: {
|
|
242
|
+
field: string;
|
|
243
|
+
operator: string;
|
|
244
|
+
value: JsonValue;
|
|
245
|
+
}[];
|
|
246
|
+
orderBy?: {
|
|
247
|
+
field: string;
|
|
248
|
+
direction?: "asc" | "desc";
|
|
249
|
+
}[];
|
|
250
|
+
limit?: number;
|
|
251
|
+
startAfter?: JsonValue;
|
|
252
|
+
endBefore?: JsonValue;
|
|
253
|
+
}
|
|
254
|
+
/** Construct a local preview server. With no `server`, it equals a raw LoopbackHub. */
|
|
255
|
+
declare function createLocalGameServer(opts?: LocalGameServerOptions): LocalGameServer;
|
|
256
|
+
/**
|
|
257
|
+
* A client of a {@link LocalGameServer}. Subscriptions read the shared in-memory
|
|
258
|
+
* store directly (same fan-out as Loopback); `remoteFunction` routes through the
|
|
259
|
+
* server's serialized dispatch so the game's `Server` class actually runs.
|
|
260
|
+
*/
|
|
261
|
+
declare class LocalGameServerTransport implements NetworkTransport {
|
|
262
|
+
private readonly server;
|
|
263
|
+
private readonly loop;
|
|
264
|
+
readonly account: string;
|
|
265
|
+
connected: boolean;
|
|
266
|
+
constructor(server: LocalGameServer, loop: LoopbackTransport);
|
|
267
|
+
connect(): Promise<boolean>;
|
|
268
|
+
disconnect(): Promise<void>;
|
|
269
|
+
remoteFunction(fn: string, args?: unknown[]): Promise<unknown>;
|
|
270
|
+
subscribeRoomState(roomId: string, cb: (state: JsonObject) => void): Unsubscribe;
|
|
271
|
+
subscribeRoomMyState(roomId: string, cb: (state: JsonObject) => void): Unsubscribe;
|
|
272
|
+
subscribeRoomAllUserStates(roomId: string, cb: (states: Record<string, JsonObject>) => void): Unsubscribe;
|
|
273
|
+
subscribeRoomCollection(roomId: string, collectionId: string, cb: (entities: Record<string, JsonObject>) => void): Unsubscribe;
|
|
274
|
+
onRoomMessage(roomId: string, type: string, cb: (message: JsonValue) => void): Unsubscribe;
|
|
275
|
+
onRoomUserJoin(roomId: string, cb: (account: string) => void): Unsubscribe;
|
|
276
|
+
onRoomUserLeave(roomId: string, cb: (account: string) => void): Unsubscribe;
|
|
277
|
+
subscribeGlobalState(cb: (state: JsonObject) => void): Unsubscribe;
|
|
278
|
+
subscribeGlobalMyState(cb: (state: JsonObject) => void): Unsubscribe;
|
|
279
|
+
subscribeGlobalUserState(account: string, cb: (state: JsonObject) => void): Unsubscribe;
|
|
280
|
+
subscribeGlobalCollection(collectionId: string, cb: (entities: Record<string, JsonObject>) => void): Unsubscribe;
|
|
281
|
+
subscribeAsset(account: string, cb: (assets: Record<string, number>) => void): Unsubscribe;
|
|
282
|
+
onGlobalMessage(type: string, cb: (message: JsonValue) => void): Unsubscribe;
|
|
283
|
+
}
|
|
284
|
+
//#endregion
|
|
285
|
+
//#region src/net/network-manager.d.ts
|
|
286
|
+
interface NetworkManagerOptions {
|
|
287
|
+
/**
|
|
288
|
+
* The transport to speak through — `LoopbackTransport` (offline/dev/tests),
|
|
289
|
+
* `await createAgent8Server()` (agent8 platform), or any custom
|
|
290
|
+
* NetworkTransport implementation. Default: the agent8 adapter.
|
|
291
|
+
*/
|
|
292
|
+
transport?: NetworkTransport;
|
|
293
|
+
/** Room id; default: scene `multiplayer.room` ('auto' = server-assigned). */
|
|
294
|
+
room?: string;
|
|
295
|
+
/** Config for the default agent8 adapter (ignored when `transport` is injected). */
|
|
296
|
+
config?: {
|
|
297
|
+
verse?: string;
|
|
298
|
+
account?: string;
|
|
299
|
+
auth?: string;
|
|
300
|
+
};
|
|
301
|
+
/** Replication send window in ms (default 50; node `network.throttleMs` can lower it). */
|
|
302
|
+
throttleMs?: number;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Per-engine multiplayer hub: joins a room, exposes the room channels as core
|
|
306
|
+
* Signals, replicates `network: {mode:'owner'}` node props on a throttle
|
|
307
|
+
* window, and resolves registered scenes for NetworkSpawner.
|
|
308
|
+
*/
|
|
309
|
+
declare class NetworkManager {
|
|
310
|
+
readonly account: string;
|
|
311
|
+
readonly roomId: string;
|
|
312
|
+
readonly roomState: Signal<[JsonObject]>;
|
|
313
|
+
readonly allUserStates: Signal<[Record<string, JsonObject>]>;
|
|
314
|
+
readonly userJoined: Signal<[string]>;
|
|
315
|
+
readonly userLeft: Signal<[string]>;
|
|
316
|
+
/**
|
|
317
|
+
* GLOBAL (cross-room, persistent) channels — populated only when the transport
|
|
318
|
+
* supports them (`LocalGameServer`, the agent8 adapter). On a transport without a
|
|
319
|
+
* global tier they stay empty / never fire.
|
|
320
|
+
*/
|
|
321
|
+
readonly globalState: Signal<[JsonObject]>;
|
|
322
|
+
readonly globalMyState: Signal<[JsonObject]>;
|
|
323
|
+
/** The local account's `$asset` ledger. */
|
|
324
|
+
readonly asset: Signal<[Record<string, number>]>;
|
|
325
|
+
/** Latest snapshots for polling consumers (NetworkSpawner). */
|
|
326
|
+
latestUserStates: Record<string, JsonObject>;
|
|
327
|
+
latestRoomState: JsonObject;
|
|
328
|
+
latestGlobalState: JsonObject;
|
|
329
|
+
latestGlobalMyState: JsonObject;
|
|
330
|
+
latestAsset: Record<string, number>;
|
|
331
|
+
private readonly server;
|
|
332
|
+
private readonly engine;
|
|
333
|
+
private readonly throttleMs;
|
|
334
|
+
private readonly subs;
|
|
335
|
+
private readonly messageSignals;
|
|
336
|
+
private readonly collectionSignals;
|
|
337
|
+
private readonly latestCollections;
|
|
338
|
+
private readonly globalMessageSignals;
|
|
339
|
+
private readonly globalCollectionSignals;
|
|
340
|
+
private readonly latestGlobalCollections;
|
|
341
|
+
private readonly scenes;
|
|
342
|
+
private readonly lastSent;
|
|
343
|
+
private sendAccumulator;
|
|
344
|
+
private detachReplication;
|
|
345
|
+
private lastOwner;
|
|
346
|
+
private boundScene;
|
|
347
|
+
static get(engine: Engine): NetworkManager | null;
|
|
348
|
+
static create(engine: Engine, opts?: NetworkManagerOptions): Promise<NetworkManager>;
|
|
349
|
+
private constructor();
|
|
350
|
+
/** Signal for a typed room message (`sendEvent` on any client). */
|
|
351
|
+
message(type: string): Signal<[JsonValue]>;
|
|
352
|
+
/** Signal + snapshot for a room collection (spawned entities). */
|
|
353
|
+
collection(id: string): Signal<[Record<string, JsonObject>]>;
|
|
354
|
+
latestCollection(id: string): Record<string, JsonObject>;
|
|
355
|
+
/** Signal for a typed GLOBAL message (`$global.broadcastToAll`/`sendMessageToUser`). */
|
|
356
|
+
globalMessage(type: string): Signal<[JsonValue]>;
|
|
357
|
+
/** Signal + snapshot for a GLOBAL collection (persistent, cross-room). */
|
|
358
|
+
globalCollection(id: string): Signal<[Record<string, JsonObject>]>;
|
|
359
|
+
latestGlobalCollection(id: string): Record<string, JsonObject>;
|
|
360
|
+
setMyState(patch: JsonObject): Promise<unknown>;
|
|
361
|
+
patchRoomState(patch: JsonObject): Promise<unknown>;
|
|
362
|
+
addEntity(collectionId: string, entity: JsonObject): Promise<unknown>;
|
|
363
|
+
updateEntity(collectionId: string, id: string, patch: JsonObject): Promise<unknown>;
|
|
364
|
+
removeEntity(collectionId: string, id: string): Promise<unknown>;
|
|
365
|
+
sendEvent(type: string, payload: JsonValue): Promise<unknown>;
|
|
366
|
+
/**
|
|
367
|
+
* Invoke a CUSTOM server-authoritative function — a method you added to your
|
|
368
|
+
* `server/src/server.ts` `Server` class (run live on the Agent8 platform, or
|
|
369
|
+
* locally via `createLocalGameServer`). The room id is prepended automatically,
|
|
370
|
+
* matching the `(roomId, …)` shape every server method takes:
|
|
371
|
+
*
|
|
372
|
+
* `manager.call('claimCoin', coinId)` → server `claimCoin(roomId, coinId)`
|
|
373
|
+
*
|
|
374
|
+
* Returns the function's result (use it for server-validated outcomes — a
|
|
375
|
+
* rejected claim, a rolled value). This is THE entry point for game rules the
|
|
376
|
+
* client must not be trusted to compute.
|
|
377
|
+
*/
|
|
378
|
+
call(fn: string, ...args: JsonValue[]): Promise<unknown>;
|
|
379
|
+
/** Register a scene for NetworkSpawner (`"scene": "<key>"`). */
|
|
380
|
+
registerScene(key: string, json: SceneJson): void;
|
|
381
|
+
resolveScene(key: string): SceneJson;
|
|
382
|
+
dispose(): Promise<void>;
|
|
383
|
+
private replicate;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* @internal Applies a replicated flat sync patch (`{'position': …,
|
|
387
|
+
* 'Sprite.animation': …}`) onto a spawned subtree (NetworkSpawner).
|
|
388
|
+
*/
|
|
389
|
+
declare function applySyncPatch(root: Node, patch: JsonObject, setProp: (target: Node, prop: string, value: JsonValue) => void): void;
|
|
390
|
+
//#endregion
|
|
391
|
+
//#region src/net/nodes/network-spawner.d.ts
|
|
392
|
+
/**
|
|
393
|
+
* Materializes a registered scene per remote player or collection entity:
|
|
394
|
+
*
|
|
395
|
+
* - `source: 'users'` — one instance per OTHER account in the room
|
|
396
|
+
* (self is skipped; the local player is your own owned node)
|
|
397
|
+
* - `source: 'collection:<id>'` — one instance per entity (bullets, pickups…)
|
|
398
|
+
*
|
|
399
|
+
* Replicated flat `{sync: {...}}` patches apply onto each instance's root;
|
|
400
|
+
* `position` lerps toward its target when `interpolate` is on. Emits
|
|
401
|
+
* `spawned(node, key)` / `despawned(node, key)`.
|
|
402
|
+
*/
|
|
403
|
+
declare class NetworkSpawner extends Node {
|
|
404
|
+
static override readonly typeName: string;
|
|
405
|
+
static override readonly signals: readonly string[];
|
|
406
|
+
static readonly props: PropSchema;
|
|
407
|
+
source: string;
|
|
408
|
+
/** Key registered via `manager.registerScene(key, json)`. */
|
|
409
|
+
scene: string;
|
|
410
|
+
interpolate: boolean;
|
|
411
|
+
private readonly spawned;
|
|
412
|
+
private readonly positionTargets;
|
|
413
|
+
private readonly failedKeys;
|
|
414
|
+
override update(dt: number): void;
|
|
415
|
+
private currentEntries;
|
|
416
|
+
private setProp;
|
|
417
|
+
private stepInterpolation;
|
|
418
|
+
}
|
|
419
|
+
//#endregion
|
|
420
|
+
//#region src/net/register.d.ts
|
|
421
|
+
/**
|
|
422
|
+
* Register the networking node types (and the core nodes). Call once in your
|
|
423
|
+
* game entry before loading a multiplayer scene. Explicit — never a side effect.
|
|
424
|
+
*/
|
|
425
|
+
declare function registerNodesNet(): void;
|
|
426
|
+
//#endregion
|
|
427
|
+
export { type CollectionOptions, LocalGameServer, type LocalGameServerOptions, LocalGameServerTransport, LoopbackHub, LoopbackTransport, NetworkManager, type NetworkManagerOptions, NetworkSpawner, type NetworkTransport, type ServerClass, type Unsubscribe, applySyncPatch, createAgent8Server, createLocalGameServer, registerNodesNet };
|