@uzuhq/code-sdk 0.7.6 → 0.8.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/README.md +52 -9
- package/dist/dev-globals.d.ts +12 -27
- package/dist/dev-globals.js +0 -15
- package/dist/dev-hooks-D6CbhPDP.d.ts +715 -0
- package/dist/index.d.ts +158 -66
- package/dist/index.js +2178 -416
- package/package.json +8 -5
- package/dist/action-types.test-d.d.ts +0 -11
- package/dist/action-types.test-d.js +0 -101
- package/dist/dev-hooks.d.ts +0 -241
- package/dist/dev-hooks.js +0 -132
- package/dist/dev-hooks.test.d.ts +0 -1
- package/dist/dev-hooks.test.js +0 -294
- package/dist/dev-prediction-traps.d.ts +0 -32
- package/dist/dev-prediction-traps.js +0 -0
- package/dist/dev-prediction-traps.test.d.ts +0 -1
- package/dist/dev-prediction-traps.test.js +0 -178
- package/dist/dev-state-patch.d.ts +0 -81
- package/dist/dev-state-patch.js +0 -295
- package/dist/dev-state-patch.test.d.ts +0 -1
- package/dist/dev-state-patch.test.js +0 -333
- package/dist/json-patch.d.ts +0 -7
- package/dist/json-patch.js +0 -78
- package/dist/random.d.ts +0 -11
- package/dist/random.js +0 -34
- package/dist/reconnectable-ws.d.ts +0 -60
- package/dist/reconnectable-ws.js +0 -229
- package/dist/room.d.ts +0 -23
- package/dist/room.js +0 -36
- package/dist/roster-params.test.d.ts +0 -1
- package/dist/roster-params.test.js +0 -86
- package/dist/run/local-server-action.d.ts +0 -16
- package/dist/run/local-server-action.js +0 -217
- package/dist/run/local-server-action.test.d.ts +0 -1
- package/dist/run/local-server-action.test.js +0 -242
- package/dist/run/optimistic-action-client.d.ts +0 -68
- package/dist/run/optimistic-action-client.js +0 -209
- package/dist/run/optimistic-action-client.test.d.ts +0 -1
- package/dist/run/optimistic-action-client.test.js +0 -430
- package/dist/run/server-action.d.ts +0 -16
- package/dist/run/server-action.js +0 -181
- package/dist/run/server-action.test.d.ts +0 -1
- package/dist/run/server-action.test.js +0 -105
- package/dist/server-clock.d.ts +0 -29
- package/dist/server-clock.js +0 -40
- package/dist/server-only.d.ts +0 -33
- package/dist/server-only.js +0 -21
- package/dist/sync/local.d.ts +0 -8
- package/dist/sync/local.js +0 -50
- package/dist/sync/online.d.ts +0 -5
- package/dist/sync/online.js +0 -165
- package/dist/types.d.ts +0 -345
- package/dist/types.js +0 -8
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
//#region src/dev-state-patch.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* @docs
|
|
4
|
+
* - 外部 automation API: docs/docs/uzu_code/sdk-guide/dev-hooks.md
|
|
5
|
+
*
|
|
6
|
+
* `__uzu_dev.mergeRawState` / `__uzu_dev.patchRawState` の中身。
|
|
7
|
+
* scenario state を「object 階層の部分更新 (RFC 7396)」と「array 要素単体の書換
|
|
8
|
+
* 含む path-based ops (RFC 6902)」で書き換えるための utility。
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* RFC 7396 風 Merge Patch。
|
|
12
|
+
*
|
|
13
|
+
* RFC 7396 strict との差分:
|
|
14
|
+
* - `null` は target 側の **削除ではなく** null をセットする (`timerEndsAt: null`
|
|
15
|
+
* のような nullable field を狙い撃ちするユースケースを優先)
|
|
16
|
+
* - 値を削除したいときは {@link JsonPatchOp} の `remove` を使う
|
|
17
|
+
*
|
|
18
|
+
* Generic は使い手側の type を残すための shape ヒントで、ランタイム上は
|
|
19
|
+
* `Record<string, unknown>` と等価。
|
|
20
|
+
*/
|
|
21
|
+
type JsonMergePatch<S = unknown> = Partial<{ [K in keyof S]: S[K] extends unknown[] ? S[K] : S[K] extends object ? JsonMergePatch<S[K]> : S[K] | null; }> & Record<string, unknown>;
|
|
22
|
+
/**
|
|
23
|
+
* RFC 6902 JSON Patch operation。
|
|
24
|
+
*
|
|
25
|
+
* - `add` / `replace` / `test`: `value` 必須
|
|
26
|
+
* - `remove`: `value` / `from` 不要
|
|
27
|
+
* - `move` / `copy`: `from` 必須 (JSON Pointer)
|
|
28
|
+
* - `path` は JSON Pointer (例: `/board/1/4`、root は空文字)
|
|
29
|
+
*/
|
|
30
|
+
type JsonPatchOp = {
|
|
31
|
+
op: 'add';
|
|
32
|
+
path: string;
|
|
33
|
+
value: unknown;
|
|
34
|
+
} | {
|
|
35
|
+
op: 'remove';
|
|
36
|
+
path: string;
|
|
37
|
+
} | {
|
|
38
|
+
op: 'replace';
|
|
39
|
+
path: string;
|
|
40
|
+
value: unknown;
|
|
41
|
+
} | {
|
|
42
|
+
op: 'move';
|
|
43
|
+
path: string;
|
|
44
|
+
from: string;
|
|
45
|
+
} | {
|
|
46
|
+
op: 'copy';
|
|
47
|
+
path: string;
|
|
48
|
+
from: string;
|
|
49
|
+
} | {
|
|
50
|
+
op: 'test';
|
|
51
|
+
path: string;
|
|
52
|
+
value: unknown;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* RFC 7396 (Merge Patch) を target に in-place 適用する。
|
|
56
|
+
*
|
|
57
|
+
* 規則:
|
|
58
|
+
* - `undefined` は no-op (key 自体を patch から落としたのと同じ)
|
|
59
|
+
* - `null` は **null をセット** (RFC 7396 strict と異なる、deletion はしない)
|
|
60
|
+
* - patch が object かつ target も object → 再帰 merge
|
|
61
|
+
* - patch が array → atomic replace (要素単位 merge なし、RFC 7396 spec 通り)
|
|
62
|
+
* - patch が primitive → overwrite
|
|
63
|
+
* - **target が array で patch が non-array object** → throw (silent な
|
|
64
|
+
* `[..., ...]` → `{ "0": ..., "1": ... }` 化を防ぐ)
|
|
65
|
+
*
|
|
66
|
+
* 型 mismatch (例: object → primitive) は overwrite で許可する。
|
|
67
|
+
*/
|
|
68
|
+
declare function applyJsonMergePatch(target: Record<string, unknown>, patch: JsonMergePatch): void;
|
|
69
|
+
/**
|
|
70
|
+
* RFC 6902 (JSON Patch) operations を target に in-place 適用する。
|
|
71
|
+
*
|
|
72
|
+
* 1 op でも失敗したら **その時点で throw** する (RFC 6902 spec: operations は
|
|
73
|
+
* sequentially evaluate、失敗時の rollback は規定なし)。caller が atomic に
|
|
74
|
+
* したいなら state を事前に snapshot しておく。
|
|
75
|
+
*
|
|
76
|
+
* root pointer (`''`) は本実装では `add` / `replace` のみ許可し、
|
|
77
|
+
* doc のフィールドを丸ごと差し替える形で動く (= 結局 `setRawState` で十分な
|
|
78
|
+
* ケースなので、わざわざ `patchRawState` で使うことはほぼない)。
|
|
79
|
+
*/
|
|
80
|
+
declare function applyJsonPatch(target: Record<string, unknown>, ops: JsonPatchOp[]): void;
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region ../engine-core/src/game-time.d.ts
|
|
83
|
+
/**
|
|
84
|
+
* @docs
|
|
85
|
+
* - 緊急停止とゲーム内時計: docs/docs/uzu_code/emergency-stop.md
|
|
86
|
+
*
|
|
87
|
+
* ゲーム内時刻。ゲーム開始からの ms で、停止中は進まない。**Unix epoch ではない。**
|
|
88
|
+
*
|
|
89
|
+
* 実行時はただの number。brand はコンパイル時だけの区別なので、state は素の JSON の
|
|
90
|
+
* まま保たれる (structuredClone / json-patch / JSON.stringify がそのまま通る)。
|
|
91
|
+
* 値を作れるのは `ctx.after` / `plus` だけになるので、`Date.now()` を混ぜると型で落ちる。
|
|
92
|
+
*
|
|
93
|
+
* 型が効くのは TypeScript を書いているシナリオだけだが、JS のシナリオでも epoch が
|
|
94
|
+
* 違うぶんは残る (`Date.now()` を混ぜれば締切が 56,000 日後になって初回で気付く)。
|
|
95
|
+
*/
|
|
96
|
+
declare const gameTimeBrand: unique symbol;
|
|
97
|
+
/** ゲーム内時刻 (ゲーム開始からの ms)。停止中は進まない。 */
|
|
98
|
+
type GameTime = number & {
|
|
99
|
+
readonly [gameTimeBrand]: 'GameTime';
|
|
100
|
+
};
|
|
101
|
+
/** 長さ (ms)。差や間隔はこちら。 */
|
|
102
|
+
type Duration = number;
|
|
103
|
+
/**
|
|
104
|
+
* `GameTime` に長さを足す。
|
|
105
|
+
*
|
|
106
|
+
* 算術をすると brand が落ちる (`number + number = number`) ので、`GameTime` を
|
|
107
|
+
* 作り直す道はこの関数と `ctx.after` に限られる。
|
|
108
|
+
*/
|
|
109
|
+
declare const plus: (t: GameTime, d: Duration) => GameTime;
|
|
110
|
+
/** 2 つの `GameTime` の差 (ms)。 */
|
|
111
|
+
declare const minus: (a: GameTime, b: GameTime) => Duration;
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region ../engine-core/src/types.d.ts
|
|
114
|
+
/**
|
|
115
|
+
* roster に載る席。
|
|
116
|
+
*
|
|
117
|
+
* roster は配役を受け取る参加者だけで構成される。観測者 (GM 席・観戦席) は roster に
|
|
118
|
+
* 載らないまま接続してくるので、シナリオは「roster に居ない = 観測者」で判別する。
|
|
119
|
+
* 席種別は roster エントリではなく自分の `SeatKind` として渡る。
|
|
120
|
+
*/
|
|
121
|
+
interface Seat {
|
|
122
|
+
id: string;
|
|
123
|
+
nickname: string;
|
|
124
|
+
iconUrl: string;
|
|
125
|
+
/** ホスト(mobile / emulator)から渡される、選択済みキャラクターの ID。未選択時は undefined。 */
|
|
126
|
+
characterId?: string;
|
|
127
|
+
}
|
|
128
|
+
type Emit = (eventName: string, data?: Record<string, unknown>) => void;
|
|
129
|
+
/** dev harness で観測される 1 件の emit。`data` は `emit(name)` 省略時に空 object になる。 */
|
|
130
|
+
interface ServerEvent {
|
|
131
|
+
name: string;
|
|
132
|
+
data: Record<string, unknown>;
|
|
133
|
+
}
|
|
134
|
+
interface SeededRandom {
|
|
135
|
+
float(): number;
|
|
136
|
+
int(max: number): number;
|
|
137
|
+
pick<T>(array: T[]): T;
|
|
138
|
+
shuffle<T>(array: T[]): T[];
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 素の action handler の実行文脈。空なのは意図的。
|
|
142
|
+
*
|
|
143
|
+
* 素の handler はサーバーとクライアント先読みの両方で走る。クライアントが自力で
|
|
144
|
+
* 再現できない値 (tick / 乱数) をここで配ると、サーバー・ソロ・dev では本物が入るのに
|
|
145
|
+
* オンラインの先読みだけ値がズレる、という一番気付きにくい形で壊れる。
|
|
146
|
+
* そういう値が要る処理は `serverActions` 側に書く。
|
|
147
|
+
*/
|
|
148
|
+
interface ActionContext {
|
|
149
|
+
/**
|
|
150
|
+
* 現在のゲーム内時刻。先読みではクロックオフセットからの推定値。
|
|
151
|
+
*
|
|
152
|
+
* 推定なのでサーバーとは数十 ms ずれる。時刻での分岐に使うと境界で判定が割れるので、
|
|
153
|
+
* 分岐は `update()` / `deadlines` (サーバー専用) へ寄せる。
|
|
154
|
+
*
|
|
155
|
+
* 同じ action を再適用しても値は変わらない (初回予測時の値を使い回す)。
|
|
156
|
+
*/
|
|
157
|
+
time: GameTime;
|
|
158
|
+
/** 今から `d` ms 後のゲーム内時刻。締切を state へ置くときに使う。 */
|
|
159
|
+
after(d: Duration): GameTime;
|
|
160
|
+
emit: Emit;
|
|
161
|
+
}
|
|
162
|
+
/** `deadlines` handler の実行文脈。サーバーでしか走らないので tick 以外を渡せる。 */
|
|
163
|
+
interface DeadlineContext {
|
|
164
|
+
/** 発火時点のゲーム内時刻。サーバー専用なので常に正確。 */
|
|
165
|
+
time: GameTime;
|
|
166
|
+
/** 今から `d` ms 後のゲーム内時刻。次の締切を state へ置き直すときに使う。 */
|
|
167
|
+
after(d: Duration): GameTime;
|
|
168
|
+
random: SeededRandom;
|
|
169
|
+
emit: Emit;
|
|
170
|
+
}
|
|
171
|
+
/** `deadlines` handler の引数。 */
|
|
172
|
+
interface DeadlineArgs<S> {
|
|
173
|
+
state: S;
|
|
174
|
+
ctx: DeadlineContext;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* サーバー権威の締切。
|
|
178
|
+
*
|
|
179
|
+
* 「state のこの時刻を過ぎたらこれをする」を宣言する。サーバーが `at` の最も早いものに
|
|
180
|
+
* 合わせて自分で起き、過ぎた締切の `handler` を呼ぶ。`tickRate` で毎秒ポーリングする
|
|
181
|
+
* 必要が無くなり、その間 Durable Object は hibernate できる。
|
|
182
|
+
*
|
|
183
|
+
* 締切は state から導出するので、予約を張り替える処理を書かなくてよい。action が
|
|
184
|
+
* throw して state が巻き戻れば、締切も一緒に巻き戻る。
|
|
185
|
+
*/
|
|
186
|
+
interface Deadline<S> {
|
|
187
|
+
/**
|
|
188
|
+
* 締切のゲーム内時刻。締切が無いときは null / undefined。
|
|
189
|
+
*
|
|
190
|
+
* `state.timer?.endsAt` のような optional chain の結果をそのまま返せるよう
|
|
191
|
+
* undefined も受ける。数値以外は「締切なし」として同じに扱う。
|
|
192
|
+
*
|
|
193
|
+
* 戻り値が `GameTime` なのは強制点。`Date.now() + 尺` も素の number も返せないので、
|
|
194
|
+
* 値を得る道が `ctx.after()` / `plus()` に限られ、state の時刻フィールドを
|
|
195
|
+
* `GameTime` で持つ動機が自動的に生まれる。
|
|
196
|
+
*
|
|
197
|
+
* state が変わるたびに呼ばれるので、state だけから決まる軽い純関数にすること。
|
|
198
|
+
* ここで実時刻や乱数を読むと、呼ばれるたびに答えが変わって予約が暴れる。
|
|
199
|
+
*/
|
|
200
|
+
at(args: {
|
|
201
|
+
state: S;
|
|
202
|
+
}): GameTime | null | undefined;
|
|
203
|
+
/**
|
|
204
|
+
* `at` の時刻を過ぎたときにサーバーで呼ばれる。
|
|
205
|
+
*
|
|
206
|
+
* 発火は at-least-once だが、SDK が発火直前に `at` を評価し直して過ぎているものだけを
|
|
207
|
+
* 呼ぶので、handler 側で二重発火を弾く必要は無い。
|
|
208
|
+
*/
|
|
209
|
+
handler(args: DeadlineArgs<S>): void;
|
|
210
|
+
}
|
|
211
|
+
/** `serverActions` handler の実行文脈。サーバーでしか走らないので tick と乱数を渡せる。 */
|
|
212
|
+
interface ServerActionContext {
|
|
213
|
+
tick: number;
|
|
214
|
+
random: SeededRandom;
|
|
215
|
+
/** 現在のゲーム内時刻。同じ dispatch の `actions` に渡る `ctx.time` と同一値。 */
|
|
216
|
+
time: GameTime;
|
|
217
|
+
/** 今から `d` ms 後のゲーム内時刻。 */
|
|
218
|
+
after(d: Duration): GameTime;
|
|
219
|
+
emit: Emit;
|
|
220
|
+
}
|
|
221
|
+
/** @deprecated `ServerActionContext` を使う。 */
|
|
222
|
+
type ServerOnlyActionContext = ServerActionContext;
|
|
223
|
+
/**
|
|
224
|
+
* action handler の引数。
|
|
225
|
+
*
|
|
226
|
+
* オブジェクトなのは使うものだけ書けるようにするため。`ctx` を入れ子で残しているのは、
|
|
227
|
+
* 実行環境が与えるものをひとまとまりで helper へ渡せるようにするため。
|
|
228
|
+
*/
|
|
229
|
+
interface ActionArgs<S, P = any> {
|
|
230
|
+
state: S;
|
|
231
|
+
payload: P;
|
|
232
|
+
playerId: string;
|
|
233
|
+
ctx: ActionContext;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* `P` は既定が `any` なので、 注釈のない handler はそのまま動く。 payload の形を
|
|
237
|
+
* 書いた handler だけが検査され、 送信側もその型で縛られる。 全部に注釈しないと
|
|
238
|
+
* 恩恵が無い、 という移行にならないようにするための既定値。
|
|
239
|
+
*/
|
|
240
|
+
type ActionHandler<S, P = any> = (args: ActionArgs<S, P>) => void;
|
|
241
|
+
/** `serverActions` handler の引数。`ctx` にサーバー限定の tick / random が入る。 */
|
|
242
|
+
interface ServerActionArgs<S, P = any> {
|
|
243
|
+
state: S;
|
|
244
|
+
payload: P;
|
|
245
|
+
playerId: string;
|
|
246
|
+
ctx: ServerActionContext;
|
|
247
|
+
}
|
|
248
|
+
type ServerActionHandler<S, P = any> = (args: ServerActionArgs<S, P>) => Promise<void> | void;
|
|
249
|
+
/** @deprecated `ServerActionHandler` を使う。 */
|
|
250
|
+
type ServerOnlyActionHandlerFn<S> = ServerActionHandler<S>;
|
|
251
|
+
/**
|
|
252
|
+
* @deprecated `serverActions` フィールドに直接書く。
|
|
253
|
+
* `serverOnly()` で wrap された handler。`__serverOnly` brand で識別する。
|
|
254
|
+
*/
|
|
255
|
+
type ServerOnlyAction<S> = ServerActionHandler<S> & {
|
|
256
|
+
readonly __serverOnly: true;
|
|
257
|
+
};
|
|
258
|
+
/** `update()` の ctx。サーバーでしか走らないので tick / random / playerInputs を持つ。 */
|
|
259
|
+
interface UpdateContext {
|
|
260
|
+
random: SeededRandom;
|
|
261
|
+
tick: number;
|
|
262
|
+
/** 現在のゲーム内時刻。update はサーバーでしか走らないので常に正確。 */
|
|
263
|
+
time: GameTime;
|
|
264
|
+
/** 今から `d` ms 後のゲーム内時刻。 */
|
|
265
|
+
after(d: Duration): GameTime;
|
|
266
|
+
emit: Emit;
|
|
267
|
+
playerInputs: Record<string, Record<string, any>>;
|
|
268
|
+
}
|
|
269
|
+
interface UpdateArgs<S> {
|
|
270
|
+
state: S;
|
|
271
|
+
ctx: UpdateContext;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* `setup()` の実行文脈。サーバーでしか走らないので実時刻をそのまま渡せる。
|
|
275
|
+
*
|
|
276
|
+
* `emit` は無い。まだ誰も購読していない時点なので、鳴らしても届かない。
|
|
277
|
+
*/
|
|
278
|
+
interface SetupContext {
|
|
279
|
+
random: SeededRandom;
|
|
280
|
+
/** ゲーム内時刻。setup は時計の起点なので必ず `0`。 */
|
|
281
|
+
time: GameTime;
|
|
282
|
+
/** 今から `d` ms 後のゲーム内時刻。setup では `d` そのものになる。 */
|
|
283
|
+
after(d: Duration): GameTime;
|
|
284
|
+
}
|
|
285
|
+
/** `setup()` の引数。 */
|
|
286
|
+
interface SetupArgs {
|
|
287
|
+
/** 配役を受け取る参加者。観測者は含まれない。 */
|
|
288
|
+
players: Seat[];
|
|
289
|
+
ctx: SetupContext;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* `actions` の形だけを見る緩い制約。
|
|
293
|
+
*
|
|
294
|
+
* `Record<string, ActionHandler<S>>` (payload: any) を制約に使うと、 推論時に
|
|
295
|
+
* handler 型がそちらへ広げられ payload の型が取り出せなくなる。 payload を
|
|
296
|
+
* `any` のままにしてキーと引数の形だけ縛る。
|
|
297
|
+
*/
|
|
298
|
+
type ActionMap<S> = Record<string, (args: ActionArgs<S, any>) => void>;
|
|
299
|
+
/** `serverActions` 用。 ActionMap と同じ理由で payload は any のままにする。 */
|
|
300
|
+
type ServerActionMap<S> = Record<string, (args: ServerActionArgs<S, any>) => Promise<void> | void>;
|
|
301
|
+
interface GameLogic<S, A extends ActionMap<S> = ActionMap<S>, SA extends ServerActionMap<S> = ServerActionMap<S>> {
|
|
302
|
+
setup(args: SetupArgs): S;
|
|
303
|
+
/**
|
|
304
|
+
* クライアント先読みとサーバーの両方で走る handler。決定的でなければならない。
|
|
305
|
+
*
|
|
306
|
+
* `serverActions` に同名のキーを置くと、同じ action の「サーバーだけで走る続き」に
|
|
307
|
+
* なる。1 つの action を「即座に反映していい部分」と「サーバーが決める部分」へ
|
|
308
|
+
* 分けられる (例: 駒の移動は先読み、持ち時間の減算はサーバー)。
|
|
309
|
+
*/
|
|
310
|
+
actions: A;
|
|
311
|
+
/**
|
|
312
|
+
* サーバーでのみ走る handler。実時刻 / 乱数 / fetch など、クライアント先読みで
|
|
313
|
+
* 再現できない処理をここに書く。async 可。
|
|
314
|
+
*
|
|
315
|
+
* `actions` と同名でも別名でもよい。別名だけに置けば「先読みしない action」
|
|
316
|
+
* (旧 `serverOnly()` 相当) になる。
|
|
317
|
+
*/
|
|
318
|
+
serverActions?: SA;
|
|
319
|
+
update(args: UpdateArgs<S>): void;
|
|
320
|
+
/**
|
|
321
|
+
* state 由来の締切。サーバーが `at` の時刻に自分で起きて `handler` を呼ぶ。
|
|
322
|
+
*
|
|
323
|
+
* 時刻をきっかけに何かを起こすなら `tickRate` で毎秒ポーリングせずこちらを使う。
|
|
324
|
+
* ポーリング中は Durable Object が hibernate できない。
|
|
325
|
+
*/
|
|
326
|
+
deadlines?: Record<string, Deadline<S>>;
|
|
327
|
+
tickRate?: number;
|
|
328
|
+
}
|
|
329
|
+
/** Sentinel value — patch の value にセットすると、サーバーが Date.now() に置換する */
|
|
330
|
+
declare const SERVER_TIME: "__SERVER_TIME__";
|
|
331
|
+
/** デフォルトのプレイヤーアイコン URL 一覧(dev / local モード用) */
|
|
332
|
+
declare const DEFAULT_ICON_URLS: readonly ["https://imagedelivery.net/htp-D7B2hJT5XtdWYN9e7Q/4d0da24d-bcf2-4f7b-d1a0-f1bb8c747300/original", "https://imagedelivery.net/htp-D7B2hJT5XtdWYN9e7Q/8c75fccb-41d6-429d-e943-06c728a72a00/original", "https://imagedelivery.net/htp-D7B2hJT5XtdWYN9e7Q/43f45d11-da38-4d6e-637d-3df78e583500/original"];
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region ../engine-core/src/json-patch.d.ts
|
|
335
|
+
/**
|
|
336
|
+
* @docs
|
|
337
|
+
* - SyncRoom仕様: docs/docs/uzu_code/sync-room.md
|
|
338
|
+
*
|
|
339
|
+
* state 差分同期用の JSON Patch。RFC 6902 の全 op は実装せず、
|
|
340
|
+
* `compare` が生成する replace / add / remove だけを扱う。
|
|
341
|
+
*/
|
|
342
|
+
interface Operation {
|
|
343
|
+
op: 'replace' | 'add' | 'remove';
|
|
344
|
+
path: string;
|
|
345
|
+
value?: unknown;
|
|
346
|
+
}
|
|
347
|
+
//#endregion
|
|
348
|
+
//#region src/types.d.ts
|
|
349
|
+
/** @deprecated 旧フラット形式。新コードでは BridgeMessage を使用 */
|
|
350
|
+
type PlayScreenMessage = {
|
|
351
|
+
type: string;
|
|
352
|
+
[key: string]: unknown;
|
|
353
|
+
};
|
|
354
|
+
/** ブリッジメッセージのチャンネル */
|
|
355
|
+
type BridgeChannel = 'sdk' | 'game';
|
|
356
|
+
/** ワイヤーフォーマット: { channel, type, payload, playerId? } */
|
|
357
|
+
interface BridgeMessage {
|
|
358
|
+
channel: BridgeChannel;
|
|
359
|
+
type: string;
|
|
360
|
+
payload: Record<string, unknown>;
|
|
361
|
+
/**
|
|
362
|
+
* 送信元プレイヤーの ID(ゲーム → ホスト方向のみ)。
|
|
363
|
+
* Web エミュレータでは複数プレイヤーの iframe が同一オリジンになり
|
|
364
|
+
* postMessage の送信元 iframe を区別できないため、ホストはこの値で
|
|
365
|
+
* 自分宛メッセージかを判定する。
|
|
366
|
+
*
|
|
367
|
+
* Flutter ホスト(QueryParamsBuilder)と dev ハーネスは URL に必ず
|
|
368
|
+
* playerId を付与するため、ゲーム → ホスト方向では常に存在する。
|
|
369
|
+
* optional なのはホスト → ゲーム方向のメッセージが持たないため
|
|
370
|
+
* (受信側は playerId 無し = 旧 SDK ビルドとして扱う)。
|
|
371
|
+
*/
|
|
372
|
+
playerId?: string;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* 自分の席種別。ホストが iframe URL の `?seatKind=` で伝える。
|
|
376
|
+
*
|
|
377
|
+
* roster に載るのは `player` だけ。観測者 (`spectator` / `admin`) は roster 外の接続として
|
|
378
|
+
* 開くので、「player か観測者か」は `state.players` の空振りで分かる。一方 **`spectator` と
|
|
379
|
+
* `admin` の区別は state から導けない**ため、この値で分ける。seatId の命名規約
|
|
380
|
+
* (`admin_0` 等) をシナリオに見せると、規約が変わった瞬間に静かに壊れる。
|
|
381
|
+
*
|
|
382
|
+
* 自己申告なので権限の根拠にはならない。表示の分岐にだけ使うこと。
|
|
383
|
+
*/
|
|
384
|
+
type SeatKind = 'player' | 'spectator' | 'admin';
|
|
385
|
+
/** プレイヤーごとのリアルタイム状態 */
|
|
386
|
+
interface PlayerVoiceState {
|
|
387
|
+
/** 音声状態。音声通話に未接続の場合は null */
|
|
388
|
+
audioStatus: 'speaking' | 'listening' | 'muted' | 'unstable' | null;
|
|
389
|
+
}
|
|
390
|
+
/** @deprecated 旧形式。新コードでは onPlayersChanged() と PlayerVoiceState を使用 */
|
|
391
|
+
interface PlayersChangedMessage {
|
|
392
|
+
players: Record<string, PlayerVoiceState>;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* events handler。
|
|
396
|
+
*
|
|
397
|
+
* `emit(name, data)` の `data` をそのまま受け取る。先読み中か確定後かは渡さない
|
|
398
|
+
* (どちらで呼ばれても同じ処理をする前提。 `predict` で宣言済みなので分岐の必要がない)。
|
|
399
|
+
*/
|
|
400
|
+
type EventHandler = (data: Record<string, unknown>) => void;
|
|
401
|
+
/**
|
|
402
|
+
* events の購読宣言。
|
|
403
|
+
*
|
|
404
|
+
* 先読みは外れることがあり、実行してしまったものは取り消せない。取り消せない副作用
|
|
405
|
+
* (analytics / 実績解除 / 長い演出) は必ず `predict: false` にすること。
|
|
406
|
+
*/
|
|
407
|
+
interface EventSubscription {
|
|
408
|
+
/** 先読み時点で実行してよいか。宣言必須。 */
|
|
409
|
+
predict: boolean;
|
|
410
|
+
handler: EventHandler;
|
|
411
|
+
}
|
|
412
|
+
/** action 名から payload 型を引く表。 注釈のない handler は `any` になる。 */
|
|
413
|
+
type PayloadMap<A> = { [K in keyof A]: A[K] extends ((args: infer G) => any) ? G extends {
|
|
414
|
+
payload: infer P;
|
|
415
|
+
} ? P : never : never; };
|
|
416
|
+
/**
|
|
417
|
+
* `inputs` が受け取る送信関数。 action 名と payload の両方が型で縛られる。
|
|
418
|
+
*
|
|
419
|
+
* payload を一律 optional にすると、 形が必須の action でも省略が通ってしまう。
|
|
420
|
+
* payload 型が undefined を含むとき (= 注釈なしの any や明示的に optional) だけ
|
|
421
|
+
* 省略できるようにする。
|
|
422
|
+
*/
|
|
423
|
+
type SendAction<A> = <K extends keyof A & string>(...args: undefined extends PayloadMap<A>[K] ? [type: K, payload?: PayloadMap<A>[K]] : [type: K, payload: PayloadMap<A>[K]]) => void;
|
|
424
|
+
interface GameConfig<S, A extends ActionMap<S> = ActionMap<S>, SA extends ServerActionMap<S> = ServerActionMap<S>> extends ConnectionCallbacks {
|
|
425
|
+
logic: GameLogic<S, A, SA>;
|
|
426
|
+
/**
|
|
427
|
+
* `mySeatKind` は自分の席種別。roster に自分が居ない (= 観測者) ときに、GM ビューと
|
|
428
|
+
* 観戦ビューを出し分けるために使う。他プレイヤーの席種別は渡らない。
|
|
429
|
+
*/
|
|
430
|
+
onState: (state: S, myPlayerId: string, mySeatKind: SeatKind) => void;
|
|
431
|
+
inputs: (sendAction: SendAction<A & SA>) => void;
|
|
432
|
+
/**
|
|
433
|
+
* `emit(name, data)` の購読。 キーごとに `predict` の宣言が必須。
|
|
434
|
+
*
|
|
435
|
+
* 同じ出来事が二重に実行されないよう、SDK は「先読みで実行した記録」を持ち、
|
|
436
|
+
* サーバーから同一の event (name と data が完全一致) が届いたら実行を抑止する。
|
|
437
|
+
* したがって `data` には**クライアントとサーバーで必ず同じ値になるもの**だけを
|
|
438
|
+
* 入れること。`ctx.now` や乱数 ID を混ぜると一致せず二重実行になる。
|
|
439
|
+
*/
|
|
440
|
+
events?: Record<string, EventSubscription>;
|
|
441
|
+
playerCount: number;
|
|
442
|
+
/** Dev harness のデフォルト向き。manifest.json の `orientation` を渡す。 */
|
|
443
|
+
orientation?: 'portrait' | 'landscape';
|
|
444
|
+
/**
|
|
445
|
+
* Dev harness で各 iframe inner viewport 短辺の下限 (CSS px)。
|
|
446
|
+
* default 360。狭い viewport では親 frame に `body { zoom: N }` を当てて
|
|
447
|
+
* iframe 内部の `window.innerWidth/Height` を保証する。
|
|
448
|
+
*/
|
|
449
|
+
devMinIframeShortEdge?: number;
|
|
450
|
+
}
|
|
451
|
+
type PatchFn = (ops: Operation[]) => void;
|
|
452
|
+
type SetFn = (path: string, value: unknown) => void;
|
|
453
|
+
interface SyncConfig<S = any> extends ConnectionCallbacks {
|
|
454
|
+
initialState: (players: Seat[]) => S;
|
|
455
|
+
onState: (state: S, myPlayerId: string, serverTime: number) => void;
|
|
456
|
+
inputs: (patch: PatchFn, set: SetFn) => void;
|
|
457
|
+
events?: Record<string, (data: Record<string, unknown>) => void>;
|
|
458
|
+
playerCount: number;
|
|
459
|
+
/** Dev harness のデフォルト向き。manifest.json の `orientation` を渡す。 */
|
|
460
|
+
orientation?: 'portrait' | 'landscape';
|
|
461
|
+
/**
|
|
462
|
+
* Dev harness で各 iframe inner viewport 短辺の下限 (CSS px)。
|
|
463
|
+
* default 360。狭い viewport では親 frame に `body { zoom: N }` を当てて
|
|
464
|
+
* iframe 内部の `window.innerWidth/Height` を保証する。
|
|
465
|
+
*/
|
|
466
|
+
devMinIframeShortEdge?: number;
|
|
467
|
+
}
|
|
468
|
+
type ConnectionState = 'connecting' | 'connected' | 'reconnecting' | 'disconnected';
|
|
469
|
+
interface ConnectionCallbacks {
|
|
470
|
+
/** WebSocket 接続状態が変化した時に呼ばれる */
|
|
471
|
+
onConnectionStateChange?: (state: ConnectionState) => void;
|
|
472
|
+
/** サーバーで patch 適用が失敗した時に呼ばれる (sync モード専用) */
|
|
473
|
+
onPatchFailed?: (reason: string) => void;
|
|
474
|
+
}
|
|
475
|
+
//#endregion
|
|
476
|
+
//#region src/host-globals.d.ts
|
|
477
|
+
declare global {
|
|
478
|
+
interface Window {
|
|
479
|
+
__ps?: {
|
|
480
|
+
onMessage: (msg: BridgeMessage) => void;
|
|
481
|
+
};
|
|
482
|
+
FlutterHost?: {
|
|
483
|
+
postMessage: (message: string) => void;
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region src/dev-prediction-traps.d.ts
|
|
489
|
+
interface PredictionWarning {
|
|
490
|
+
/** 呼び出した action 名。描画経路では `'(render)'`。 */
|
|
491
|
+
action: string;
|
|
492
|
+
/** 呼ばれた API 名 (`'Date.now()'` など) */
|
|
493
|
+
api: string;
|
|
494
|
+
}
|
|
495
|
+
/** 検出済みの警告一覧。`__uzu_dev.getPredictionWarnings()` から E2E で assert する用。 */
|
|
496
|
+
declare const getPredictionWarnings: () => readonly PredictionWarning[];
|
|
497
|
+
//#endregion
|
|
498
|
+
//#region src/dev-hooks.d.ts
|
|
499
|
+
interface UzuDevHooks<S = unknown> {
|
|
500
|
+
/** 現在の per-player 視点 snapshot (onState コールバックの最新値)。未初期化なら null。 */
|
|
501
|
+
getSnapshot(): unknown;
|
|
502
|
+
/** 生 server-side state (dev/local mode のみ。online ServerAction では null)。 */
|
|
503
|
+
getRawState(): S | null;
|
|
504
|
+
playerId(): string | null;
|
|
505
|
+
/**
|
|
506
|
+
* 親 frame で virtual server を実体化した時の seed。
|
|
507
|
+
* 親 frame の `runDevHarness({ server })` 経由でしか attach されず、子 iframe の
|
|
508
|
+
* dev hooks 側では undefined。bug report 用に `?__dev_seed=<value>` として
|
|
509
|
+
* 貼り付けやすい uint32 を返す。
|
|
510
|
+
*/
|
|
511
|
+
getSeed?(): number;
|
|
512
|
+
/**
|
|
513
|
+
* 素の action handler が先読み実行中に実時刻 / 乱数を読んだ記録。
|
|
514
|
+
*
|
|
515
|
+
* 先読みはサーバーと同じ結果を再現できることが前提なので、ここに何か入っていたら
|
|
516
|
+
* そのシナリオはオンラインでだけ予測がズレる。E2E で `[]` を assert すると回帰を防げる。
|
|
517
|
+
*/
|
|
518
|
+
getPredictionWarnings(): readonly PredictionWarning[];
|
|
519
|
+
/**
|
|
520
|
+
* Server-side で action を直接 dispatch する。
|
|
521
|
+
*
|
|
522
|
+
* **run devHarness の親 frame のみ** で attach される。それ以外 (runLocal /
|
|
523
|
+
* sync / online) では `undefined`。
|
|
524
|
+
* 非 parent モードで action を投げたい時は scenario 側の bridge
|
|
525
|
+
* (`window.__uzu.sendAction`) や実 UI 操作を使う。
|
|
526
|
+
*
|
|
527
|
+
* `args.as` は **必須**。server-side dispatch の `from` をこの値で指定する
|
|
528
|
+
* (バリデーションはしないので、未登録 ID で投げて action handler に弾かせる
|
|
529
|
+
* 運用も可)。turn-based の E2E (将棋・人狼・カードゲーム) で「先手 → 後手」
|
|
530
|
+
* を 1 frame から打ち分けたい時に使う。
|
|
531
|
+
*/
|
|
532
|
+
send?(args: {
|
|
533
|
+
as: string;
|
|
534
|
+
type: string;
|
|
535
|
+
payload?: Record<string, unknown>;
|
|
536
|
+
}): Promise<void>;
|
|
537
|
+
/**
|
|
538
|
+
* 生 state を **全置換** する。state owner の frame (= dev/local) のみ。
|
|
539
|
+
*
|
|
540
|
+
* `setup` 後の任意の構造を流し込めるので、`getRawState()` の dump を読み込んで
|
|
541
|
+
* バグ再現する用途や、scenario の途中 state を JSON で復元する用途に使う。
|
|
542
|
+
* 部分更新は {@link mergeRawState} を、array 要素単体の書換は
|
|
543
|
+
* {@link patchRawState} を使うこと。
|
|
544
|
+
*/
|
|
545
|
+
setRawState?(state: S): Promise<void>;
|
|
546
|
+
/**
|
|
547
|
+
* RFC 7396 風 JSON Merge Patch で生 state を部分更新する (dev/local のみ)。
|
|
548
|
+
*
|
|
549
|
+
* - object 階層は recursive merge
|
|
550
|
+
* - **array field は atomic replace のみ** (要素単位の merge 不可、RFC 7396 仕様)
|
|
551
|
+
* - `undefined` は no-op、`null` は明示セット (RFC 7396 strict と異なる)
|
|
552
|
+
* - array 内の cell 単体を書き換えたい場合は {@link patchRawState} を使う
|
|
553
|
+
*
|
|
554
|
+
* array が pure object に化ける silent な破壊を防ぐため、`array に
|
|
555
|
+
* non-array object patch を当てる`と **throw** する。
|
|
556
|
+
*/
|
|
557
|
+
mergeRawState?(patch: JsonMergePatch<S>): Promise<void>;
|
|
558
|
+
/**
|
|
559
|
+
* RFC 6902 JSON Patch (path-based ops) で生 state を更新する (dev/local のみ)。
|
|
560
|
+
*
|
|
561
|
+
* - JSON Pointer (`/board/1/4`) で array index 単体の書換が可能
|
|
562
|
+
* - サポートする op: `add` / `remove` / `replace` / `move` / `copy` / `test`
|
|
563
|
+
* - 1 op でも失敗するとその場で throw する (atomic ではない)
|
|
564
|
+
*
|
|
565
|
+
* 局面の部分更新 (将棋の一手・盤面の cell 単体書換など) に使う。
|
|
566
|
+
*/
|
|
567
|
+
patchRawState?(ops: JsonPatchOp[]): Promise<void>;
|
|
568
|
+
/**
|
|
569
|
+
* snapshot 更新を event-driven に listen する。返り値は unsubscribe 関数。
|
|
570
|
+
*
|
|
571
|
+
* `waitForSnapshot` が「特定条件まで待つ」のに対し、こちらは「state 変化を全部
|
|
572
|
+
* 取って trace test を書く」「deterministic record を作る」「sequence assert」
|
|
573
|
+
* のような用途で使う canonical な listener。
|
|
574
|
+
*
|
|
575
|
+
* cb には authoritative state の生参照 (run devHarness 親では `getRawState()` と
|
|
576
|
+
* 同一) が渡るので mutate しない。
|
|
577
|
+
*/
|
|
578
|
+
subscribeSnapshot(cb: (snapshot: unknown) => void): () => void;
|
|
579
|
+
/** snapshot が predicate を満たすまで待つ。default 10 秒 timeout。 */
|
|
580
|
+
waitForSnapshot(predicate: (snapshot: unknown) => boolean, options?: {
|
|
581
|
+
timeoutMs?: number;
|
|
582
|
+
}): Promise<unknown>;
|
|
583
|
+
/**
|
|
584
|
+
* action handler / `logic.update` の `emit` を listen する。callback には 1 回の
|
|
585
|
+
* dispatch / tick 内で発火した event を batch でまとめて渡す。**run devHarness 親
|
|
586
|
+
* frame のみ** で attach され、それ以外 (runLocal ソロ /
|
|
587
|
+
* sync / online) では `undefined`。
|
|
588
|
+
*
|
|
589
|
+
* `getSnapshot()` に乗らない raw payload (`gameover` の `reason` 等) を assert
|
|
590
|
+
* したい場合に使う。`config.events` callback とは独立経路で、scenario callback の
|
|
591
|
+
* throw も subscriber 通知を止めない。unsubscribe 関数を返す。
|
|
592
|
+
*/
|
|
593
|
+
subscribeEvents?(cb: (events: readonly ServerEvent[]) => void): () => void;
|
|
594
|
+
/**
|
|
595
|
+
* tick loop を pause する (run() devHarness 親 frame のみ)。
|
|
596
|
+
* 時間駆動の `logic.update` が走らなくなり、shogi の持ち時間減算等の自動進行を
|
|
597
|
+
* 止められる。pause 中も `send` (action dispatch) と state 書換 API は通る。
|
|
598
|
+
* tick loop を持たない frame (子 iframe / sync 単独 frame / online) と
|
|
599
|
+
* `tickRate <= 0` の scenario では undefined / no-op。
|
|
600
|
+
*/
|
|
601
|
+
pauseTick?(): void;
|
|
602
|
+
/** pauseTick を解除する。 */
|
|
603
|
+
resumeTick?(): void;
|
|
604
|
+
/** 手動で n tick 進める。default n = 1。 */
|
|
605
|
+
stepTick?(n?: number): void;
|
|
606
|
+
/** 現在の tick 値を返す。tick loop を持たない frame では undefined。 */
|
|
607
|
+
getCurrentTick?(): number;
|
|
608
|
+
/** pauseTick で止まっているかどうか。 */
|
|
609
|
+
isTickPaused?(): boolean;
|
|
610
|
+
/**
|
|
611
|
+
* `logic.setup` を再実行して virtual server を fresh start させる。
|
|
612
|
+
* run() devHarness の親 frame のみ attach される (state owner でしか reset 不可)。
|
|
613
|
+
*
|
|
614
|
+
* - `seed` 省略時は現在の seed を再利用 (= 決定論的同一初期化)
|
|
615
|
+
* - 数値を渡すとその seed で再初期化、`getSeed()` の戻り値も更新
|
|
616
|
+
* - `'random'` で新 seed (uint32) を生成
|
|
617
|
+
*
|
|
618
|
+
* pause 状態は維持される。`logic.setup` が副作用を持つ場合は再呼出で副作用が再発火する。
|
|
619
|
+
*/
|
|
620
|
+
reset?(opts?: {
|
|
621
|
+
seed?: number | 'random';
|
|
622
|
+
}): void;
|
|
623
|
+
}
|
|
624
|
+
declare global {
|
|
625
|
+
interface Window {
|
|
626
|
+
__uzu_dev?: UzuDevHooks;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* run/* モジュール (run/local-server-action / run/dev-server-action) が
|
|
631
|
+
* dev hooks に state を expose するための handle。
|
|
632
|
+
* online (server-action) モードでは handle 自体を返さない。
|
|
633
|
+
*
|
|
634
|
+
* state 書き換え API は state owner frame のみ提供する。
|
|
635
|
+
*/
|
|
636
|
+
interface RunHandle<S = unknown> {
|
|
637
|
+
/** 内部 state の getter (dev hooks 用)。host iframe を持たない側では undefined */
|
|
638
|
+
getRawState?(): S | null;
|
|
639
|
+
/** 生 state 全置換。host iframe を持たない側では undefined */
|
|
640
|
+
setRawState?(state: S): Promise<void>;
|
|
641
|
+
/** RFC 7396 風 Merge Patch。host iframe を持たない側では undefined */
|
|
642
|
+
mergeRawState?(patch: JsonMergePatch<S>): Promise<void>;
|
|
643
|
+
/** RFC 6902 JSON Patch。host iframe を持たない側では undefined */
|
|
644
|
+
patchRawState?(ops: JsonPatchOp[]): Promise<void>;
|
|
645
|
+
/** 既存 inputs と同等の action 送信 (dev hooks 用) */
|
|
646
|
+
sendAction(type: string, payload?: Record<string, unknown>): void;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* sync/* モジュール (sync/dev / sync/local) が dev hooks に state を expose
|
|
650
|
+
* するための handle。online sync では handle 自体を返さない。
|
|
651
|
+
*/
|
|
652
|
+
interface SyncHandle<S = unknown> {
|
|
653
|
+
/** 内部 state の getter (dev hooks 用) */
|
|
654
|
+
getRawState?(): S | null;
|
|
655
|
+
/** 生 state 全置換 */
|
|
656
|
+
setRawState?(state: S): Promise<void>;
|
|
657
|
+
/** RFC 7396 風 Merge Patch */
|
|
658
|
+
mergeRawState?(patch: JsonMergePatch<S>): Promise<void>;
|
|
659
|
+
/** RFC 6902 JSON Patch */
|
|
660
|
+
patchRawState?(ops: JsonPatchOp[]): Promise<void>;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* dev-hooks.ts から見た「SDK 内部のコンテキスト」。
|
|
664
|
+
* 各 run/* / sync/* モジュールがこの形の handle を組み立てて attachDevHooks に渡す。
|
|
665
|
+
*/
|
|
666
|
+
interface DevHooksCtx<S = unknown> {
|
|
667
|
+
/** 最新 snapshot (per-player view)。未初期化なら null。 */
|
|
668
|
+
getSnapshot(): unknown;
|
|
669
|
+
/** 生 state getter (dev/local mode のみ)。 */
|
|
670
|
+
getRawState?: () => S | null;
|
|
671
|
+
/** 生 state 全置換 (dev/local mode のみ)。 */
|
|
672
|
+
setRawState?: (state: S) => Promise<void>;
|
|
673
|
+
/** RFC 7396 風 Merge Patch (dev/local mode のみ)。 */
|
|
674
|
+
mergeRawState?: (patch: JsonMergePatch<S>) => Promise<void>;
|
|
675
|
+
/** RFC 6902 JSON Patch (dev/local mode のみ)。 */
|
|
676
|
+
patchRawState?: (ops: JsonPatchOp[]) => Promise<void>;
|
|
677
|
+
/** 現在の player ID (URL クエリ or runtime 解決)。 */
|
|
678
|
+
playerId(): string | null;
|
|
679
|
+
/**
|
|
680
|
+
* Action 送信。run devHarness 親 frame の `DevHostHandle` のみが
|
|
681
|
+
* 提供する。それ以外のモードでは省略 (= `__uzu_dev.send` も生えない)。
|
|
682
|
+
* `args.as` で server-side dispatch の `from` を指定する (必須)。
|
|
683
|
+
*/
|
|
684
|
+
sendAction?(args: {
|
|
685
|
+
as: string;
|
|
686
|
+
type: string;
|
|
687
|
+
payload?: Record<string, unknown>;
|
|
688
|
+
}): Promise<void>;
|
|
689
|
+
/** snapshot 更新を listen する。unsubscribe 関数を返す。 */
|
|
690
|
+
subscribeSnapshot(cb: (snapshot: unknown) => void): () => void;
|
|
691
|
+
/**
|
|
692
|
+
* action handler / `logic.update` 由来の emit を listen する。run devHarness 親
|
|
693
|
+
* frame の `DevHostHandle` のみが提供する。それ以外のモードでは省略
|
|
694
|
+
* (= `__uzu_dev.subscribeEvents` も生えない)。
|
|
695
|
+
*/
|
|
696
|
+
subscribeEvents?(cb: (events: readonly ServerEvent[]) => void): () => void;
|
|
697
|
+
/** dev harness 親 frame の virtual server seed。親 attach 経路のみ。 */
|
|
698
|
+
getSeed?: () => number;
|
|
699
|
+
pauseTick?: () => void;
|
|
700
|
+
resumeTick?: () => void;
|
|
701
|
+
stepTick?: (n?: number) => void;
|
|
702
|
+
getCurrentTick?: () => number;
|
|
703
|
+
isTickPaused?: () => boolean;
|
|
704
|
+
/**
|
|
705
|
+
* run() devHarness 親 frame の `DevHostHandle.reset` を expose する。
|
|
706
|
+
* state owner でしか fresh start できないので、それ以外の mode では undefined。
|
|
707
|
+
*/
|
|
708
|
+
reset?: (opts?: {
|
|
709
|
+
seed?: number | 'random';
|
|
710
|
+
}) => void;
|
|
711
|
+
}
|
|
712
|
+
declare function createDevHooks<S>(ctx: DevHooksCtx<S>): UzuDevHooks<S>;
|
|
713
|
+
declare function attachDevHooks<S>(ctx: DevHooksCtx<S>): void;
|
|
714
|
+
//#endregion
|
|
715
|
+
export { minus as $, DEFAULT_ICON_URLS as A, ServerActionContext as B, SetFn as C, ActionContext as D, ActionArgs as E, GameLogic as F, ServerOnlyActionContext as G, ServerActionMap as H, SERVER_TIME as I, SetupContext as J, ServerOnlyActionHandlerFn as K, Seat as L, DeadlineArgs as M, DeadlineContext as N, ActionHandler as O, Emit as P, GameTime as Q, SeededRandom as R, SendAction as S, Operation as T, ServerEvent as U, ServerActionHandler as V, ServerOnlyAction as W, UpdateContext as X, UpdateArgs as Y, Duration as Z, PayloadMap as _, attachDevHooks as a, PlayersChangedMessage as b, getPredictionWarnings as c, ConnectionCallbacks as d, plus as et, ConnectionState as f, PatchFn as g, GameConfig as h, UzuDevHooks as i, applyJsonPatch as it, Deadline as j, ActionMap as k, BridgeChannel as l, EventSubscription as m, RunHandle as n, JsonPatchOp as nt, createDevHooks as o, EventHandler as p, SetupArgs as q, SyncHandle as r, applyJsonMergePatch as rt, PredictionWarning as s, DevHooksCtx as t, JsonMergePatch as tt, BridgeMessage as u, PlayScreenMessage as v, SyncConfig as w, SeatKind as x, PlayerVoiceState as y, ServerActionArgs as z };
|