@uzuhq/code-cli 0.5.2 → 0.5.3
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.
|
@@ -290,6 +290,17 @@ export class GameRoom {
|
|
|
290
290
|
this.ensureTickLoop();
|
|
291
291
|
}
|
|
292
292
|
async handleMessage(ws, msg) {
|
|
293
|
+
// SDK は生文字列で送受信する (本番の setWebSocketAutoResponse と同じ wire 形式)。
|
|
294
|
+
// JSON.parse より前に返さないと heartbeat が落ちて 35 秒ごとに全席が再接続する。
|
|
295
|
+
if (msg === '__ping') {
|
|
296
|
+
try {
|
|
297
|
+
ws.send('__pong');
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
/* disconnected */
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
293
304
|
const attachment = this.attachments.get(ws);
|
|
294
305
|
if (!attachment)
|
|
295
306
|
return;
|
|
@@ -302,10 +313,6 @@ export class GameRoom {
|
|
|
302
313
|
return;
|
|
303
314
|
}
|
|
304
315
|
const msgType = parsed.type;
|
|
305
|
-
if (msgType === '__ping') {
|
|
306
|
-
this.sendTo(ws, { type: '__pong' });
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
316
|
console.log(`[GameRoom] ⬅ recv from=${senderId} type=${msgType}`);
|
|
310
317
|
if (msgType === '__action') {
|
|
311
318
|
if (!this.gameState) {
|
|
@@ -25,6 +25,17 @@ export class RelayRoom {
|
|
|
25
25
|
ws.send(JSON.stringify({ type: '__room_init', myId: playerId }));
|
|
26
26
|
}
|
|
27
27
|
handleMessage(ws, msg) {
|
|
28
|
+
// SDK は生文字列で送受信する (本番の setWebSocketAutoResponse と同じ wire 形式)。
|
|
29
|
+
// JSON.parse より前に返さないと heartbeat が落ちて 35 秒ごとに全席が再接続する。
|
|
30
|
+
if (msg === '__ping') {
|
|
31
|
+
try {
|
|
32
|
+
ws.send('__pong');
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
/* disconnected */
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
28
39
|
const attachment = this.attachments.get(ws);
|
|
29
40
|
if (!attachment)
|
|
30
41
|
return;
|
|
@@ -36,15 +47,6 @@ export class RelayRoom {
|
|
|
36
47
|
catch {
|
|
37
48
|
return;
|
|
38
49
|
}
|
|
39
|
-
if (parsed.type === '__ping') {
|
|
40
|
-
try {
|
|
41
|
-
ws.send(JSON.stringify({ type: '__pong' }));
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
/* disconnected */
|
|
45
|
-
}
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
50
|
console.log(`[RelayRoom] ⬅ recv from=${senderId}`, JSON.stringify(parsed));
|
|
49
51
|
const outData = JSON.stringify({ ...parsed, __from: senderId });
|
|
50
52
|
if (parsed.__to && typeof parsed.__to === 'string') {
|
|
@@ -78,6 +78,17 @@ export class SyncRoom {
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
handleMessage(ws, msg) {
|
|
81
|
+
// SDK は生文字列で送受信する (本番の setWebSocketAutoResponse と同じ wire 形式)。
|
|
82
|
+
// JSON.parse より前に返さないと heartbeat が落ちて 35 秒ごとに全席が再接続する。
|
|
83
|
+
if (msg === '__ping') {
|
|
84
|
+
try {
|
|
85
|
+
ws.send('__pong');
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
/* disconnected */
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
81
92
|
const attachment = this.attachments.get(ws);
|
|
82
93
|
if (!attachment)
|
|
83
94
|
return;
|
|
@@ -90,15 +101,6 @@ export class SyncRoom {
|
|
|
90
101
|
return;
|
|
91
102
|
}
|
|
92
103
|
const msgType = parsed.type;
|
|
93
|
-
if (msgType === '__ping') {
|
|
94
|
-
try {
|
|
95
|
-
ws.send(JSON.stringify({ type: '__pong' }));
|
|
96
|
-
}
|
|
97
|
-
catch {
|
|
98
|
-
/* disconnected */
|
|
99
|
-
}
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
104
|
console.log(`[SyncRoom] ⬅ recv from=${senderId} type=${msgType}`);
|
|
103
105
|
if (msgType === '__init_state') {
|
|
104
106
|
if (this.stateInitialized) {
|
package/dist/harness/mount.js
CHANGED
|
@@ -33,6 +33,14 @@ const PHONE_SVG = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" x
|
|
|
33
33
|
<rect x="6.5" y="2" width="11" height="20" rx="2.5" stroke="white" stroke-width="2"/>
|
|
34
34
|
<line x1="10" y1="18.5" x2="14" y2="18.5" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
35
35
|
</svg>`;
|
|
36
|
+
// 擬似ノッチ表示トグル。 createNotchDecor が実際に描く装飾 (横向き端末・左の
|
|
37
|
+
// Dynamic Island・下中央のホームインジケータ) をそのまま象る。 隣の PHONE_SVG
|
|
38
|
+
// (縦向き) とは向きで見分ける。
|
|
39
|
+
const NOTCH_SVG = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
40
|
+
<rect x="2" y="4.5" width="20" height="15" rx="3.5" stroke="white" stroke-width="1.8"/>
|
|
41
|
+
<rect x="4.8" y="8.5" width="2.2" height="7" rx="1.1" fill="white"/>
|
|
42
|
+
<line x1="11" y1="17" x2="17" y2="17" stroke="white" stroke-width="1.6" stroke-linecap="round"/>
|
|
43
|
+
</svg>`;
|
|
36
44
|
/** buildIframeUrl に渡す HUD の避け領域 (Flutter HudInsets と同じ計算)。 */
|
|
37
45
|
function hudInsetParams(hasMenu, actionCount) {
|
|
38
46
|
let x = HUD_LEFT;
|
|
@@ -429,19 +437,12 @@ function openPlayerSwitcher(opts, currentIndex, anchor) {
|
|
|
429
437
|
};
|
|
430
438
|
setTimeout(() => document.addEventListener('click', close), 0);
|
|
431
439
|
}
|
|
432
|
-
/**
|
|
433
|
-
* 各 iframe (= 各プレイヤー画面) の左上に載せる overlay chrome。
|
|
434
|
-
* 本番アプリ (Flutter GamePlayScreen) と同じ仕様:
|
|
435
|
-
* SafeArea top:8 / left:12 → [UZU ボタン 44] [gap 6] [ActionBar ピル: chat, mic]。
|
|
436
|
-
* UZU ボタンは dev メニュー (State/Reset/Emulator) + その player の「スマホで開く」を開く。
|
|
437
|
-
* chat / mic は本番の見た目に合わせた dev 表示 (機能は SDK 側が担うため配線しない)。
|
|
438
|
-
*/
|
|
439
440
|
function createCellChrome(opts, playerIndex,
|
|
440
441
|
// facade=true (実機の単体表示) では見た目だけ揃える。 admin channel が無いので
|
|
441
442
|
// UZU メニュー / 実機 QR は配線せず、 アイコンはタップ無効 (ハリボテ)。
|
|
442
443
|
facade = false,
|
|
443
|
-
// grid では no-op
|
|
444
|
-
|
|
444
|
+
// grid では no-op のマイク枠を擬似ノッチ表示トグルに転用する。
|
|
445
|
+
notchToggle,
|
|
445
446
|
// 単体表示 (実機) では UZU ボタンをプレイヤー切替に転用する。
|
|
446
447
|
onUzuClick) {
|
|
447
448
|
const wrap = document.createElement('div');
|
|
@@ -489,17 +490,24 @@ onUzuClick) {
|
|
|
489
490
|
'border-radius:18px',
|
|
490
491
|
'display:flex;align-items:center',
|
|
491
492
|
].join(';');
|
|
492
|
-
// 1つめ:
|
|
493
|
-
//
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
mic.style.cssText = onMicClick
|
|
493
|
+
// 1つめ: 本番は音声トグルだが harness には音声が無い。 grid ではこの枠を擬似ノッチ
|
|
494
|
+
// 表示のトグルに転用し、 アイコンも端末フレームへ差し替える (facade は本番の見た目)。
|
|
495
|
+
const micSlot = document.createElement(notchToggle ? 'button' : 'div');
|
|
496
|
+
micSlot.innerHTML = notchToggle ? NOTCH_SVG : MIC_SVG;
|
|
497
|
+
micSlot.style.cssText = notchToggle
|
|
498
498
|
? 'padding:0 10px;height:36px;background:none;border:none;cursor:pointer;display:flex;align-items:center;'
|
|
499
499
|
: 'padding:0 10px;display:flex;align-items:center;';
|
|
500
|
-
if (
|
|
501
|
-
|
|
502
|
-
|
|
500
|
+
if (notchToggle) {
|
|
501
|
+
micSlot.onclick = notchToggle.toggle;
|
|
502
|
+
notchToggle.register((on) => {
|
|
503
|
+
micSlot.style.opacity = on ? '1' : '0.4';
|
|
504
|
+
micSlot.title = `擬似ノッチ表示: ${on ? 'ON' : 'OFF'}`;
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
micSlot.title = 'マイク (dev 表示のみ)';
|
|
509
|
+
}
|
|
510
|
+
bar.appendChild(micSlot);
|
|
503
511
|
// 2つめ: 携帯 (その player を実機で開く QR)。 facade では装飾のみ。
|
|
504
512
|
const phone = document.createElement('button');
|
|
505
513
|
phone.innerHTML = PHONE_SVG;
|
|
@@ -528,7 +536,8 @@ export function mountIframeGrid(opts) {
|
|
|
528
536
|
const iframeSplashes = new Map();
|
|
529
537
|
const iframePredictionWarns = new Map();
|
|
530
538
|
// 擬似ノッチ (各 cell 共通トグル)。 iframe を再生成せず inset だけ切り替える。
|
|
531
|
-
|
|
539
|
+
// 既定は OFF: ノッチ帯のぶん画面が縮むので、 SafeArea を確認したいときだけ出す。
|
|
540
|
+
let notchSimOn = false;
|
|
532
541
|
const notchAppliers = [];
|
|
533
542
|
const toggleNotchSim = () => {
|
|
534
543
|
notchSimOn = !notchSimOn;
|
|
@@ -575,6 +584,7 @@ export function mountIframeGrid(opts) {
|
|
|
575
584
|
iframeStatusDots.clear();
|
|
576
585
|
iframeSplashes.clear();
|
|
577
586
|
iframePredictionWarns.clear();
|
|
587
|
+
notchAppliers.length = 0;
|
|
578
588
|
for (let i = 0; i < opts.seats.length; i++) {
|
|
579
589
|
const seat = seatAt(opts, i);
|
|
580
590
|
const cell = document.createElement('div');
|
|
@@ -616,7 +626,13 @@ export function mountIframeGrid(opts) {
|
|
|
616
626
|
screen.appendChild(splash);
|
|
617
627
|
// admin は端末を模す必要が無いので overlay chrome / 擬似ノッチを載せず素の画面にする。
|
|
618
628
|
if (seat.kind !== 'admin') {
|
|
619
|
-
screen.appendChild(createCellChrome(opts, i, false,
|
|
629
|
+
screen.appendChild(createCellChrome(opts, i, false, {
|
|
630
|
+
toggle: toggleNotchSim,
|
|
631
|
+
register: (apply) => {
|
|
632
|
+
apply(notchSimOn);
|
|
633
|
+
notchAppliers.push(apply);
|
|
634
|
+
},
|
|
635
|
+
}));
|
|
620
636
|
}
|
|
621
637
|
// 先読み警告の内訳パネル。 バッジクリックで開閉する。 画面の上に重ねるので
|
|
622
638
|
// ゲームの見た目は普段どおりのまま、 必要なときだけ前に出る。
|