@uzuhq/code-cli 0.6.0 → 0.6.1

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/dist/cli.js CHANGED
@@ -549,7 +549,8 @@ import { WebSocketServer } from "ws";
549
549
  import { randomUUID } from "crypto";
550
550
 
551
551
  // ../engine-core/src/game-time.ts
552
- var plus = (t, d) => t + d;
552
+ var toMs = (t) => t;
553
+ var plus = (t, d) => toMs(t) + d;
553
554
  var asGameTime = (ms) => ms;
554
555
 
555
556
  // ../engine-core/src/game-clock.ts
@@ -584,7 +585,7 @@ var GameClock = class {
584
585
  }
585
586
  /** ゲーム内時刻を、alarm / setTimeout が使う実時刻へ直す。 */
586
587
  toWall(at) {
587
- return at + this.startedAtWall + this.pausedTotalMs;
588
+ return toMs(at) + this.startedAtWall + this.pausedTotalMs;
588
589
  }
589
590
  /** 実際に理由を足したら true。呼び出し側が永続化や tick 停止の要否に使う。 */
590
591
  freeze(reason) {
@@ -628,9 +629,10 @@ var GameClock = class {
628
629
  function withGameClock(time, fn) {
629
630
  const realNow = Date.now;
630
631
  const RealDate = Date;
631
- Date.now = () => time;
632
+ const ms = toMs(time);
633
+ Date.now = () => ms;
632
634
  globalThis.Date = new Proxy(RealDate, {
633
- construct: (target, args) => Reflect.construct(target, args.length === 0 ? [time] : args)
635
+ construct: (target, args) => Reflect.construct(target, args.length === 0 ? [ms] : args)
634
636
  });
635
637
  try {
636
638
  return fn();
@@ -6,8 +6,213 @@ var DEFAULT_ICON_URLS = [
6
6
  "https://imagedelivery.net/htp-D7B2hJT5XtdWYN9e7Q/43f45d11-da38-4d6e-637d-3df78e583500/original"
7
7
  ];
8
8
 
9
+ // ../engine-core/src/game-time.ts
10
+ var toMs = (t) => t;
11
+ var plus = (t, d) => toMs(t) + d;
12
+ var sub = (t, d) => toMs(t) - d;
13
+ var minus = (a, b) => toMs(a) - toMs(b);
14
+ var asGameTime = (ms) => ms;
15
+
9
16
  // ../engine-core/src/game-clock.ts
10
17
  var NO_PLAYERS_GRACE_MS = 5 * 6e4;
18
+ var GameClock = class {
19
+ startedAtWall = 0;
20
+ pausedTotalMs = 0;
21
+ pausedAtWall = null;
22
+ frozenBy = /* @__PURE__ */ new Set();
23
+ /** 時計を 0 から始め直す。`setup()` を呼ぶ直前に通す。 */
24
+ restart() {
25
+ this.startedAtWall = Date.now();
26
+ this.pausedTotalMs = 0;
27
+ this.pausedAtWall = null;
28
+ this.frozenBy.clear();
29
+ }
30
+ get frozen() {
31
+ return this.frozenBy.size > 0;
32
+ }
33
+ isFrozenBy(reason) {
34
+ return this.frozenBy.has(reason);
35
+ }
36
+ /**
37
+ * 現在のゲーム内時刻。停止中は `pausedAtWall` で凍るので同じ値を返し続ける。
38
+ *
39
+ * IMPORTANT: [withGameClock] の中で呼んではいけない。実装が `Date.now()` を読むので、
40
+ * 差し替え済みの時刻を実時刻として引き算し、大きく負の値になる。
41
+ * ハンドラへ渡す時刻は必ず外で 1 回取ってから渡すこと。
42
+ */
43
+ now() {
44
+ return asGameTime((this.pausedAtWall ?? Date.now()) - this.startedAtWall - this.pausedTotalMs);
45
+ }
46
+ /** ゲーム内時刻を、alarm / setTimeout が使う実時刻へ直す。 */
47
+ toWall(at) {
48
+ return toMs(at) + this.startedAtWall + this.pausedTotalMs;
49
+ }
50
+ /** 実際に理由を足したら true。呼び出し側が永続化や tick 停止の要否に使う。 */
51
+ freeze(reason) {
52
+ if (this.frozenBy.has(reason)) return false;
53
+ const wasFrozen = this.frozen;
54
+ this.frozenBy.add(reason);
55
+ if (!wasFrozen) this.pausedAtWall = Date.now();
56
+ return true;
57
+ }
58
+ /** 実際に理由を外したら true。 */
59
+ unfreeze(reason) {
60
+ if (!this.frozenBy.delete(reason)) return false;
61
+ if (!this.frozen && this.pausedAtWall !== null) {
62
+ this.pausedTotalMs += Date.now() - this.pausedAtWall;
63
+ this.pausedAtWall = null;
64
+ }
65
+ return true;
66
+ }
67
+ snapshot() {
68
+ return {
69
+ startedAtWall: this.startedAtWall,
70
+ pausedTotalMs: this.pausedTotalMs,
71
+ pausedAtWall: this.pausedAtWall,
72
+ frozenBy: [...this.frozenBy]
73
+ };
74
+ }
75
+ /**
76
+ * 永続化した内容から復元する。欠損は「未停止」に倒す。
77
+ *
78
+ * 読めなかったせいで世界が止まったままになる方が、動き出すより悪い。
79
+ */
80
+ restore(saved) {
81
+ this.startedAtWall = saved.startedAtWall ?? 0;
82
+ this.pausedTotalMs = saved.pausedTotalMs ?? 0;
83
+ this.pausedAtWall = saved.pausedAtWall ?? null;
84
+ this.frozenBy.clear();
85
+ for (const reason of saved.frozenBy ?? []) this.frozenBy.add(reason);
86
+ if (this.frozen && this.pausedAtWall === null) this.frozenBy.clear();
87
+ }
88
+ };
89
+ function withGameClock(time, fn) {
90
+ const realNow = Date.now;
91
+ const RealDate = Date;
92
+ const ms = toMs(time);
93
+ Date.now = () => ms;
94
+ globalThis.Date = new Proxy(RealDate, {
95
+ construct: (target, args) => Reflect.construct(target, args.length === 0 ? [ms] : args)
96
+ });
97
+ try {
98
+ return fn();
99
+ } finally {
100
+ globalThis.Date = RealDate;
101
+ Date.now = realNow;
102
+ }
103
+ }
104
+ function resolveDeadline(at, key, warned, report) {
105
+ if (at === null || at === void 0) return null;
106
+ if (typeof at === "number" && Number.isFinite(at)) return asGameTime(at);
107
+ if (!warned.has(key)) {
108
+ warned.add(key);
109
+ report(
110
+ `deadline "${key}" \u306E at() \u304C\u7DE0\u5207\u306B\u4F7F\u3048\u306A\u3044\u5024\u3092\u8FD4\u3057\u305F: ${String(at)}\u3002\u3053\u306E\u7DE0\u5207\u306F\u4E8C\u5EA6\u3068\u767A\u706B\u3057\u306A\u3044\u3002\u5EC3\u6B62\u3055\u308C\u305F ctx.now \u3092\u8AAD\u3093\u3067\u3044\u306A\u3044\u304B\u78BA\u8A8D\u3059\u308B\u3053\u3068`
111
+ );
112
+ }
113
+ return null;
114
+ }
115
+
116
+ // ../engine-core/src/json-patch.ts
117
+ function escapePointer(key) {
118
+ return key.replace(/~/g, "~0").replace(/\//g, "~1");
119
+ }
120
+ function unescapePointer(token) {
121
+ return token.replace(/~1/g, "/").replace(/~0/g, "~");
122
+ }
123
+ function compare(oldObj, newObj, basePath = "") {
124
+ if (oldObj === newObj) return [];
125
+ if (oldObj === null || newObj === null || typeof oldObj !== "object" || typeof newObj !== "object") {
126
+ return [{ op: "replace", path: basePath || "/", value: newObj }];
127
+ }
128
+ if (Array.isArray(oldObj) || Array.isArray(newObj)) {
129
+ if (JSON.stringify(oldObj) === JSON.stringify(newObj)) return [];
130
+ return [{ op: "replace", path: basePath || "/", value: newObj }];
131
+ }
132
+ const ops = [];
133
+ const oldKeys = Object.keys(oldObj);
134
+ const newKeys = Object.keys(newObj);
135
+ for (const key of oldKeys) {
136
+ if (!(key in newObj)) {
137
+ ops.push({ op: "remove", path: `${basePath}/${escapePointer(key)}` });
138
+ }
139
+ }
140
+ for (const key of newKeys) {
141
+ const childPath = `${basePath}/${escapePointer(key)}`;
142
+ if (!(key in oldObj)) {
143
+ ops.push({ op: "add", path: childPath, value: newObj[key] });
144
+ } else {
145
+ const childOps = compare(oldObj[key], newObj[key], childPath);
146
+ ops.push(...childOps);
147
+ }
148
+ }
149
+ return ops;
150
+ }
151
+ function applyPatch(doc, ops) {
152
+ for (const op of ops) {
153
+ const tokens = op.path.split("/").slice(1).map(unescapePointer);
154
+ if (tokens.length === 0) return false;
155
+ if (op.op === "replace" || op.op === "add") {
156
+ let target = doc;
157
+ for (let i = 0; i < tokens.length - 1; i++) {
158
+ target = target?.[tokens[i]];
159
+ if (target === void 0 || target === null) return false;
160
+ }
161
+ const lastKey = tokens[tokens.length - 1];
162
+ target[lastKey] = op.value;
163
+ } else if (op.op === "remove") {
164
+ let target = doc;
165
+ for (let i = 0; i < tokens.length - 1; i++) {
166
+ target = target?.[tokens[i]];
167
+ if (target === void 0 || target === null) return false;
168
+ }
169
+ const lastKey = tokens[tokens.length - 1];
170
+ if (Array.isArray(target)) {
171
+ target.splice(Number(lastKey), 1);
172
+ } else {
173
+ delete target[lastKey];
174
+ }
175
+ }
176
+ }
177
+ return true;
178
+ }
179
+
180
+ // ../engine-core/src/random.ts
181
+ var SeededRandomImpl = class _SeededRandomImpl {
182
+ _state;
183
+ constructor(seed) {
184
+ this._state = seed | 0;
185
+ }
186
+ get state() {
187
+ return this._state;
188
+ }
189
+ static fromState(state) {
190
+ const r = new _SeededRandomImpl(0);
191
+ r._state = state;
192
+ return r;
193
+ }
194
+ float() {
195
+ this._state |= 0;
196
+ this._state = this._state + 1831565813 | 0;
197
+ let t = Math.imul(this._state ^ this._state >>> 15, 1 | this._state);
198
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
199
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
200
+ }
201
+ int(max) {
202
+ return Math.floor(this.float() * max);
203
+ }
204
+ pick(array) {
205
+ return array[this.int(array.length)];
206
+ }
207
+ shuffle(array) {
208
+ const a = [...array];
209
+ for (let i = a.length - 1; i > 0; i--) {
210
+ const j = this.int(i + 1);
211
+ [a[i], a[j]] = [a[j], a[i]];
212
+ }
213
+ return a;
214
+ }
215
+ };
11
216
 
12
217
  // ../engine-core/src/server-only.ts
13
218
  function serverOnly(handler) {
@@ -16,9 +221,45 @@ function serverOnly(handler) {
16
221
  function isServerOnlyAction(handler) {
17
222
  return typeof handler === "function" && "__serverOnly" in handler && handler.__serverOnly === true;
18
223
  }
224
+
225
+ // ../engine-core/src/roster.ts
226
+ function parseRoster(rosterParam) {
227
+ if (!rosterParam) return null;
228
+ let raw;
229
+ try {
230
+ raw = JSON.parse(rosterParam);
231
+ } catch {
232
+ return null;
233
+ }
234
+ if (!Array.isArray(raw)) return null;
235
+ return raw.filter((p) => (p.kind ?? "player") === "player").map((p) => ({
236
+ id: p.id,
237
+ nickname: p.name ?? "Guest",
238
+ iconUrl: p.iconUrl ?? "",
239
+ characterId: p.characterId
240
+ }));
241
+ }
242
+
243
+ // ../engine-core/src/versions.ts
244
+ var BRIDGE_VERSION = 2;
245
+ var WIRE_VERSION = 2;
19
246
  export {
247
+ BRIDGE_VERSION,
20
248
  DEFAULT_ICON_URLS,
249
+ GameClock,
250
+ NO_PLAYERS_GRACE_MS,
21
251
  SERVER_TIME,
252
+ SeededRandomImpl,
253
+ WIRE_VERSION,
254
+ applyPatch,
255
+ asGameTime,
256
+ compare,
22
257
  isServerOnlyAction,
23
- serverOnly
258
+ minus,
259
+ parseRoster,
260
+ plus,
261
+ resolveDeadline,
262
+ serverOnly,
263
+ sub,
264
+ withGameClock
24
265
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uzuhq/code-cli",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "UZU ゲーム開発 CLI - ビルド・パブリッシュ・プロジェクト作成ツール",
5
5
  "type": "module",
6
6
  "bin": {