@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.
Files changed (53) hide show
  1. package/README.md +52 -9
  2. package/dist/dev-globals.d.ts +12 -27
  3. package/dist/dev-globals.js +0 -15
  4. package/dist/dev-hooks-D6CbhPDP.d.ts +715 -0
  5. package/dist/index.d.ts +158 -66
  6. package/dist/index.js +2178 -416
  7. package/package.json +8 -5
  8. package/dist/action-types.test-d.d.ts +0 -11
  9. package/dist/action-types.test-d.js +0 -101
  10. package/dist/dev-hooks.d.ts +0 -241
  11. package/dist/dev-hooks.js +0 -132
  12. package/dist/dev-hooks.test.d.ts +0 -1
  13. package/dist/dev-hooks.test.js +0 -294
  14. package/dist/dev-prediction-traps.d.ts +0 -32
  15. package/dist/dev-prediction-traps.js +0 -0
  16. package/dist/dev-prediction-traps.test.d.ts +0 -1
  17. package/dist/dev-prediction-traps.test.js +0 -178
  18. package/dist/dev-state-patch.d.ts +0 -81
  19. package/dist/dev-state-patch.js +0 -295
  20. package/dist/dev-state-patch.test.d.ts +0 -1
  21. package/dist/dev-state-patch.test.js +0 -333
  22. package/dist/json-patch.d.ts +0 -7
  23. package/dist/json-patch.js +0 -78
  24. package/dist/random.d.ts +0 -11
  25. package/dist/random.js +0 -34
  26. package/dist/reconnectable-ws.d.ts +0 -60
  27. package/dist/reconnectable-ws.js +0 -229
  28. package/dist/room.d.ts +0 -23
  29. package/dist/room.js +0 -36
  30. package/dist/roster-params.test.d.ts +0 -1
  31. package/dist/roster-params.test.js +0 -86
  32. package/dist/run/local-server-action.d.ts +0 -16
  33. package/dist/run/local-server-action.js +0 -217
  34. package/dist/run/local-server-action.test.d.ts +0 -1
  35. package/dist/run/local-server-action.test.js +0 -242
  36. package/dist/run/optimistic-action-client.d.ts +0 -68
  37. package/dist/run/optimistic-action-client.js +0 -209
  38. package/dist/run/optimistic-action-client.test.d.ts +0 -1
  39. package/dist/run/optimistic-action-client.test.js +0 -430
  40. package/dist/run/server-action.d.ts +0 -16
  41. package/dist/run/server-action.js +0 -181
  42. package/dist/run/server-action.test.d.ts +0 -1
  43. package/dist/run/server-action.test.js +0 -105
  44. package/dist/server-clock.d.ts +0 -29
  45. package/dist/server-clock.js +0 -40
  46. package/dist/server-only.d.ts +0 -33
  47. package/dist/server-only.js +0 -21
  48. package/dist/sync/local.d.ts +0 -8
  49. package/dist/sync/local.js +0 -50
  50. package/dist/sync/online.d.ts +0 -5
  51. package/dist/sync/online.js +0 -165
  52. package/dist/types.d.ts +0 -345
  53. package/dist/types.js +0 -8
package/README.md CHANGED
@@ -223,7 +223,7 @@ import type { GameLogic } from '@uzuhq/code-sdk';
223
223
 
224
224
  const logic: GameLogic<MyState> = {
225
225
  setup({ players, ctx }) {
226
- // 初期 state を生成。ctx.random は SeededRandom、ctx.now はサーバーの実時刻。
226
+ // 初期 state を生成。ctx.random は SeededRandom、ctx.time はゲーム内時刻 (必ず 0)。
227
227
  // players は配役を受け取る参加者だけで、観測者は含まれない
228
228
  return { players: {}, items: [] };
229
229
  },
@@ -235,24 +235,24 @@ const logic: GameLogic<MyState> = {
235
235
  state.players[playerId].x += payload.dx;
236
236
  // ctx.emit でイベント発火 (購読側は events で predict を宣言する)
237
237
  ctx.emit('sound', { sound: 'step' });
238
- // 時刻は ctx.now を使う。Date.now() は端末とサーバーでズレる
238
+ // 時刻は ctx.after(d) を使う。Date.now() は epoch が違う (Unix ms vs ゲーム内時刻)
239
239
  },
240
240
  },
241
241
 
242
242
  // サーバーでのみ走る。実時刻・乱数・fetch などクライアントが再現できない処理。
243
243
  // actions と同名にすると「同じ action のサーバー側の続き」になる。
244
244
  serverActions: {
245
- async notifyExternal({ state, payload, playerId }) {
245
+ async notifyExternal({ state, payload, playerId, ctx }) {
246
246
  await fetch('https://example.com/notify', {
247
247
  method: 'POST',
248
248
  body: JSON.stringify({ playerId, ...payload }),
249
249
  });
250
- state.notifiedAt = Date.now();
250
+ state.notifiedAt = ctx.time;
251
251
  },
252
252
  },
253
253
 
254
254
  update({ state, ctx }) {
255
- // 毎 tick 実行。ctx.tick / ctx.random / ctx.now / ctx.emit / ctx.playerInputs が使える
255
+ // 毎 tick 実行。ctx.tick / ctx.random / ctx.time / ctx.after / ctx.emit / ctx.playerInputs が使える
256
256
  },
257
257
 
258
258
  tickRate: 10, // 秒間 tick 数 (default: 0 = tick なし)
@@ -287,10 +287,10 @@ deadlines: {
287
287
  },
288
288
  ```
289
289
 
290
- | | |
291
- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
292
- | `at` | 締切の絶対時刻 (ms)。`null` / `undefined` で締切なし (optional chain の結果をそのまま返せる)。**state だけから決まる軽い関数にすること** (state が変わるたびに呼ばれる) |
293
- | `handler` | サーバーでのみ走る。`ctx` は `{ now, random, emit }` |
290
+ | | |
291
+ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
292
+ | `at` | 締切の[ゲーム内時刻](#ゲーム内時計) (`GameTime`)。`null` / `undefined` で締切なし (optional chain の結果をそのまま返せる)。**state だけから決まる軽い純関数にすること** (state が変わるたびに呼ばれる) |
293
+ | `handler` | サーバーでのみ走る。`ctx` は `{ time, after, random, emit }` |
294
294
 
295
295
  締切は state から導出するので、**予約を張り替える処理を書かなくてよい**。action が throw して
296
296
  state が巻き戻れば締切も一緒に巻き戻る。発火直前に `at` を評価し直すので、二重発火を
@@ -299,6 +299,49 @@ handler 側で弾く必要も無い。
299
299
  時刻をきっかけに何かを起こすなら `tickRate` で毎秒ポーリングせずこちらを使う。
300
300
  ポーリング中は Durable Object が hibernate できない。
301
301
 
302
+ ### ゲーム内時計
303
+
304
+ **時刻は Unix epoch ではない。** `ctx.time` はゲーム開始からの経過 ms (`GameTime`) で、
305
+ [緊急一時停止](#緊急一時停止)中は進まない。`Date.now()` とは桁も意味も違う。
306
+
307
+ | API | 意味 |
308
+ | ---------------------------- | ----------------------------------------------------------------- |
309
+ | `ctx.time` | そのハンドラが走っているゲーム内時刻。`setup` では必ず `0` |
310
+ | `ctx.after(d)` | 今から `d` ms 後のゲーム内時刻。締切を state に置くときに使う |
311
+ | `gameTime()` | 描画側で読む現在のゲーム内時刻 (推定値)。`performance.now()` 基準 |
312
+ | `plus(t, d)` / `minus(a, b)` | 時刻に長さを足す / 2 つの時刻の差を取る |
313
+
314
+ ```ts
315
+ import { gameTime, minus } from '@uzuhq/code-sdk';
316
+
317
+ // 締切を置く
318
+ actions: {
319
+ startPhase: ({ state, ctx }) => { state.phaseEndsAt = ctx.after(5 * 60_000); },
320
+ },
321
+
322
+ // 残り時間を描く
323
+ const remain = Math.ceil(minus(state.phaseEndsAt, gameTime()) / 1000);
324
+ ```
325
+
326
+ `GameTime` は `number` の brand 型なので、実行時はただの数値。state は素の JSON のまま。
327
+ `Date.now()` を `GameTime` の場所に入れると TypeScript が弾く。
328
+
329
+ ### 緊急一時停止
330
+
331
+ プレイヤーが UZU メニューから全員のタイマーを止められる。**シナリオは停止を知らないし、
332
+ 知る必要も無い。** 停止中は `update()` が呼ばれず、action はサーバーが弾き、締切も来ない。
333
+
334
+ 演出だけを止めたいときに限り、読み取り専用で参照できる。
335
+
336
+ ```ts
337
+ import { isPaused, onPauseChange } from '@uzuhq/code-sdk';
338
+
339
+ onPauseChange((paused) => (paused ? engine.stop() : engine.start()));
340
+ ```
341
+
342
+ `GameLogic` からは触れない。停止を state に持ち込むと「停止中は state が変わらない」という
343
+ 前提が崩れる。
344
+
302
345
  #### `serverOnly(handler)`
303
346
 
304
347
  > **Deprecated**: `serverActions` に直接書く。
@@ -1,28 +1,13 @@
1
- /**
2
- * scenario 側 (`test/*.ts` / `tools/*.ts`) から `window.__uzu_dev` を
3
- * 補完 + 型チェック付きで呼べるようにする ambient module。
4
- *
5
- * 使い方: scenario の `tsconfig.json` で
6
- *
7
- * ```jsonc
8
- * { "compilerOptions": { "types": ["@uzuhq/code-sdk/dev-globals"] } }
9
- * ```
10
- *
11
- * SDK 自身を import するコード (= `@uzuhq/code-sdk` の named import を持つ
12
- * モジュール) では `dev-hooks.ts` 側の `declare global` で同じ型が既に効く
13
- * ため、本 module を `types` に足す必要はない。target は import しない
14
- * scenario test/tools のみ。
15
- */
16
- import type { UzuDevHooks } from './dev-hooks.js';
1
+ import { i as UzuDevHooks } from "./dev-hooks-D6CbhPDP.js";
2
+ //#region src/dev-globals.d.ts
17
3
  declare global {
18
- interface Window {
19
- /**
20
- * dev harness / Playwright / 単独 page で attach される dev hooks。
21
- * 本番 (Flutter native ホスト) では undefined。
22
- * - run() devHarness: 親 frame に attach (authoritative state)
23
- * - sync() / online: 子 frame で undefined
24
- */
25
- __uzu_dev?: UzuDevHooks<unknown>;
26
- }
27
- }
28
- export {};
4
+ interface Window {
5
+ /**
6
+ * dev harness / Playwright / 単独 page で attach される dev hooks。
7
+ * 本番 (Flutter native ホスト) では undefined。
8
+ * - run() devHarness: 親 frame に attach (authoritative state)
9
+ * - sync() / online: 子 frame で undefined
10
+ */
11
+ __uzu_dev?: UzuDevHooks<unknown>;
12
+ }
13
+ }
@@ -1,16 +1 @@
1
- /**
2
- * scenario 側 (`test/*.ts` / `tools/*.ts`) から `window.__uzu_dev` を
3
- * 補完 + 型チェック付きで呼べるようにする ambient module。
4
- *
5
- * 使い方: scenario の `tsconfig.json` で
6
- *
7
- * ```jsonc
8
- * { "compilerOptions": { "types": ["@uzuhq/code-sdk/dev-globals"] } }
9
- * ```
10
- *
11
- * SDK 自身を import するコード (= `@uzuhq/code-sdk` の named import を持つ
12
- * モジュール) では `dev-hooks.ts` 側の `declare global` で同じ型が既に効く
13
- * ため、本 module を `types` に足す必要はない。target は import しない
14
- * scenario test/tools のみ。
15
- */
16
1
  export {};