updatee game 5and flow and loading

This commit is contained in:
2026-06-26 10:28:39 +00:00
parent d4bae38a61
commit 2e20e87b45
10 changed files with 873 additions and 806 deletions
+13 -12
View File
@@ -51,9 +51,9 @@
"providerUserId": "p_1775109142385_wq7wfy1p32j",
"notes": "auto: player-coins",
"blocked": false,
"coins": 2072,
"coins": 2140,
"createdAt": "2026-04-02T05:52:21+00:00",
"updatedAt": "2026-06-26T07:58:33+00:00",
"updatedAt": "2026-06-26T10:25:41+00:00",
"daily": {
"anchorMs": 1781197200000,
"claimedDays": [
@@ -67,13 +67,13 @@
],
"lockUntilMs": 0
},
"score": 18,
"score": 86,
"scoreByCase": {
"1": 16,
"10": 514,
"10": 562,
"8": 296,
"11": 20,
"13": 224,
"13": 234,
"14": 30,
"9": 40,
"12": 408,
@@ -83,7 +83,7 @@
"7": 6,
"3": 142,
"6": 44,
"2": 80
"2": 90
},
"lbName": "Q",
"achievements": {
@@ -651,19 +651,20 @@
"providerUserId": "p_1782016990238_0u37bv7pxlxs",
"notes": "auto: player-coins",
"blocked": false,
"coins": 288,
"coins": 368,
"createdAt": "2026-06-21T04:43:11+00:00",
"updatedAt": "2026-06-26T08:07:51+00:00",
"updatedAt": "2026-06-26T09:44:40+00:00",
"lobbyColorThemeIndex": 8,
"lobbySkinToneIndex": 1,
"score": 258,
"score": 338,
"scoreByCase": {
"13": 82,
"10": 120,
"10": 172,
"6": 8,
"8": 20,
"2": 18,
"3": 10
"2": 36,
"3": 10,
"7": 10
},
"lbName": "MONE",
"achievements": {
+1 -1
View File
@@ -74,7 +74,7 @@
"/Game/img/ViolentCrime/Meteo-3.png"
],
"spaceShooterAsteroidExplodeFrameMs": 60,
"spaceShooterAsteroidIntervalMs": 300,
"spaceShooterAsteroidIntervalMs": 200,
"spaceShooterShipDamageOverlayUrls": [
"/Game/img/ViolentCrime/Rocket-broke-1.png",
"/Game/img/ViolentCrime/Rocket-broke-2.png",
+1 -1
View File
@@ -4,7 +4,7 @@
"betweenMs": 3000,
"carryReadMs": 3000,
"carryAnswerMs": 15000,
"carrySessionLength": 2,
"carrySessionLength": 10,
"carryMapPanelTheme": {
"panelBg": "rgba(255, 0, 0, 0)",
"panelBorder": "rgba(255, 255, 255, 0)",
+106 -11
View File
@@ -106,7 +106,20 @@
ov.innerHTML = '<div class="plo-spin"></div><div class="plo-text">กำลังโหลดเกม…</div>';
document.body.insertBefore(ov, document.body.firstChild);
}
setTimeout(hidePlayLoadingOverlay, 8000); /* safety: กันค้างถ้าโหลดนาน/ติด */
/* safety " render" ( join 8 = )
เชคท 1.5 : เกมเรมวาดแล (playLoadingHideScheduled) ปลอย path ปกตอน · งไมวาด+ โชว "เน็ตช้า (N วิ)" คง spinner · เก 30 อยซอนกนคางถาวร */
const _ploT0 = Date.now();
const _ploCheck = function () {
if (playLoadingHidden || playLoadingHideScheduled) return; /* ซ่อนแล้ว/เกมเริ่มวาดแล้ว */
const waited = Date.now() - _ploT0;
if (waited > 30000) { hidePlayLoadingOverlay(); return; } /* hard limit กันค้างถาวร */
if (waited > 5000) {
const txt = document.querySelector('#play-loading-overlay .plo-text');
if (txt) txt.textContent = 'เน็ตช้า… กำลังโหลด (' + Math.floor(waited / 1000) + ' วิ)';
}
setTimeout(_ploCheck, 1500);
};
setTimeout(_ploCheck, 1500);
} catch (_e) { playLoadingHidden = true; }
})();
const playMapIdFromQuery = (params.get('map') || '').trim();
@@ -730,7 +743,9 @@
socket.emit('stack-state', {
idx: stackPreviewTurnIndex,
/* theme ต่อที่นั่ง (host เป็นเจ้าของ) → ทุกจอลงสี block ตรงกัน (เดิม non-host คำนวณสีเองจาก playTint → ไม่ตรง 2 จอ) */
order: stackPreviewTurnOrder.map((e) => ({ kind: e.kind, seat: e.seat, id: e.id, botId: e.botId || null, theme: stackSeatColorThemePlay(e.seat) || null })),
order: stackPreviewTurnOrder.map((e) => ({ kind: e.kind, seat: e.seat, id: e.id, botId: e.botId || null, theme: stackSeatThemeForBroadcastPlay(e.seat) })),
/* สีของ block ที่ "วางแล้ว" ทั้งหอ (host authoritative) → client sync เขียนทับ layer ที่เพี้ยนค้าง (จากจังหวะ dual-host ต้นเกม) */
lthemes: (stackMini && Array.isArray(stackMini.layers)) ? stackMini.layers.map(function (l) { return (l && l.theme >= 1 && l.theme <= 8) ? l.theme : 0; }) : [],
});
logStackSeatColors('host-bcast');
} catch (e) { /* ignore */ }
@@ -740,6 +755,29 @@
function stackTurnOrderReadyPlay() {
return !!(stackPreviewTurnOrder && stackPreviewTurnOrder.length >= 1);
}
/** (host) / auto-heal late-join (client seat "" + )
เทยบรายชอคน (me + others ไมใชบอท/ไมกแบน) + บอท entry ในค; างเมอไหร = อง rebuild */
let _stackHumansSig = '';
function stackOrderNeedsRebuildPlay() {
if (!stackTurnOrderReadyPlay() || !Array.isArray(stackPreviewTurnOrder)) return true;
/* เช็คเฉพาะ "คน" (humans ≤ maxPlayers จึงลงคิวครบเสมอ ไม่โดน cap ตัด) — บอทจัดการใน rebuild เอง */
const cur = [];
if (myId != null && !playBannedSpectator) cur.push(String(myId));
others.forEach((o, id) => {
if (isPreviewBotId(id)) return;
if (o && o.bannedSpectator) return;
cur.push(String(id));
});
cur.sort();
const sig = cur.join('|');
if (sig === _stackHumansSig) return false; /* คนไม่เปลี่ยน → ไม่ต้องเช็ค (กัน rebuild ถี่) */
const ord = [];
stackPreviewTurnOrder.forEach((e) => { if (e && e.kind !== 'bot' && !e.botId && e.id != null) ord.push(String(e.id)); });
ord.sort();
const need = (sig !== ord.join('|'));
if (!need) _stackHumansSig = sig; /* ตรงแล้ว → cache กันเช็คซ้ำทุกเฟรม */
return need;
}
function stackCurrentTurnEntryPlay() {
if (!stackTurnOrderReadyPlay()) return null;
return stackPreviewTurnOrder[stackPreviewTurnIndex % stackPreviewTurnOrder.length] || null;
@@ -766,8 +804,8 @@
pts: hit.pts || 0, progressDelta: hit.progressDelta || 0, landOffsetTiles: hit.landOffsetTiles || 0,
overlap: hit.overlap, supportRatio: hit.supportRatio, delta: hit.delta || 0,
seat: seat || 1, heavy: !!heavy, actorId: actorId != null ? String(actorId) : '', isBot: !!isBot,
/* สี (theme) ที่ host/เจ้าของตา resolve ตอนวาง → ส่งไปด้วย ให้บล็อกที่วางบนทุกจอใช้สีเดียวกัน (กัน host/client คนละสี) */
theme: stackSeatColorThemePlay(seat) || null,
/* สี (theme) ที่ host/เจ้าของตา resolve ตอนวาง → ส่งไปด้วย ให้บล็อกที่วางบนทุกจอใช้สีเดียวกัน (กัน host/client คนละสี) — never-null */
theme: stackSeatThemeForBroadcastPlay(seat),
});
} catch (e) { /* ignore */ }
}
@@ -843,6 +881,15 @@
return ent ? playLobbyThemeIndexForEntityPlay(ent) : null;
}
/** host broadcast " null": resolve default seat
client (broadcast-first) ดค host ไดเสมอ ไมตกไปคำนวณเอง = ตรง host กจอแนนอน */
function stackSeatThemeForBroadcastPlay(seat) {
const t = stackSeatColorThemePlay(seat);
if (t >= 1 && t <= 8) return t;
const s = Math.floor(Number(seat)) || 1;
return ((s - 1) % 8) + 1;
}
/** ส่ง log ไป /gamelog (ดูรวมที่หน้าเว็บ) */
function gamelogPost(cat, ev, detail, who) {
try {
@@ -855,6 +902,7 @@
/** block MG3 seat " avatar (playTint)" vs " block (resolved)"; /gamelog
เรยกเอง: window.__mg3ColorLog() หร auto throttle */
let _mg3ColorLogAt = 0;
let _mg3SnapAt = 0;
let _mg3LastMismatchKey = '';
function logStackSeatColors(tag, force) {
try {
@@ -872,13 +920,34 @@
return { seat: e.seat, kind: e.kind, nick: (ent && ent.nickname) || String(e.id || e.botId || '').slice(0, 6), avatarIdx: avatarIdx, blockIdx: blockIdx, srv: (ent && ent.lobbyThemeIndexSrv) || null, bc: e.theme || null, ok: (avatarIdx && blockIdx) ? (avatarIdx === blockIdx) : null };
});
console.log('[mg3-color/' + (tag || '') + '] host=' + isMePlayHost(), JSON.stringify(rows));
/* ส่งเฉพาะกรณีพบ mismatch (avatar≠block) → เห็นใน /gamelog (MG3) ทันที ไม่ต้องเปิด console */
const role = isMePlayHost() ? 'host' : 'client';
/* (A) snapshot ทุก ~5 วิ จาก "ทั้ง host และ client" → เทียบใน /gamelog ได้: block(=สีที่วาด) av(=สี avatar) srv bc */
if (now - _mg3SnapAt > 5000) {
_mg3SnapAt = now;
/* รายชื่อ "คน" ใน others (เทียบกับคิว) — หา root "client หายจากคิว" */
const othH = [];
if (myId != null) othH.push((me && me.nickname ? me.nickname : 'me') + '(self' + (playBannedSpectator ? ',BAN' : '') + ')');
others.forEach(function (o, id) {
if (isPreviewBotId(id)) return;
othH.push((o && o.nickname ? o.nickname : String(id).slice(0, 5)) + (o && o.bannedSpectator ? '(BAN)' : ''));
});
const ordSeats = rows.length;
/* block ที่ "วางแล้ว" (frozen layer.theme) — ตัวที่ user เห็นเพี้ยน; เทียบ host vs client ทีละ layer (seat:theme) */
let lyr = '';
if (stackMini && Array.isArray(stackMini.layers)) {
const L = stackMini.layers;
lyr = ' || layers(' + L.length + ')=[' + L.slice(-12).map(function (l) { return (l && l.seat != null ? l.seat : '?') + ':' + (l && l.theme != null ? l.theme : 'null'); }).join(',') + ']';
}
const summary = 'order=' + ordSeats + 'seat othHumans=[' + othH.join(',') + '] :: '
+ rows.map(function (r) { return 's' + r.seat + ':' + (r.nick || '?').slice(0, 5) + ' blk=' + r.blockIdx + ' av=' + r.avatarIdx; }).join(' | ') + lyr;
gamelogPost('MG3', 'color-snap', summary, role);
}
/* (B) mismatch (avatar≠block บนจอเดียวกัน) → ส่งทันที (เปลี่ยนค่อยส่งซ้ำ) */
const bad = rows.filter(function (r) { return r.ok === false; });
if (bad.length) {
const key = (isMePlayHost() ? 'H' : 'C') + '|' + bad.map(function (r) { return r.seat + ':' + r.avatarIdx + '!=' + r.blockIdx; }).join(',');
const key = role + '|' + bad.map(function (r) { return r.seat + ':' + r.avatarIdx + '!=' + r.blockIdx; }).join(',');
if (key !== _mg3LastMismatchKey) {
_mg3LastMismatchKey = key;
const role = isMePlayHost() ? 'host' : 'client';
const detail = bad.map(function (r) { return r.nick + ' seat' + r.seat + ' avatar#' + r.avatarIdx + ' แต่ block#' + r.blockIdx + ' (srv' + r.srv + '/bc' + r.bc + ')'; }).join(' | ');
gamelogPost('MG3', 'color-mismatch', detail, role);
}
@@ -12325,7 +12394,8 @@
lastStackTickMs = now;
/* เล่นจริง: host ส่งลำดับตา+index เป็นระยะ → non-host adopt (ครอบ late-join: client โหลดช้า host จะรวมเข้า order ให้) */
if (detectiveCaseFillBots && isMePlayHost()) {
if (!stackTurnOrderReadyPlay()) rebuildStackPreviewTurnOrder();
/* rebuild เมื่อ (ก) ยังไม่มีคิว หรือ (ข) คน/บอท เปลี่ยน (เช่น client เข้าทีหลัง = late-join) → ให้ทุกคนได้ seat + สี */
if (!stackTurnOrderReadyPlay() || stackOrderNeedsRebuildPlay()) rebuildStackPreviewTurnOrder();
const ts = Date.now();
if (ts - stackLastStateEmit > 300) { stackLastStateEmit = ts; broadcastStackStatePlay(); }
}
@@ -12602,11 +12672,13 @@
? stackFall.actorSeat
: (m.pendingDropSeat != null ? m.pendingDropSeat : getStackDropActorSeat());
const heavyDraw = stackFall ? !!stackFall.actorHeavy : !!m.pendingDropHeavy;
/* remote drop → ใช้สีจาก host (actorTheme/pendingDropTheme) เหมือน block ที่วาง → block ห้อย/ตก สีตรง host */
const themeOverrideDraw = stackFall ? (stackFall.actorTheme || null) : (m.pendingDropTheme || null);
const hueHint = (m.layers.length * 47) % 360;
ctx.save();
ctx.translate(bcx, bcy);
ctx.rotate(fallTiltRad + swingTiltRad);
drawStackBlockSpriteOrHue(ctx, -twWorld * zoom / 2, 0, twWorld * zoom, drawStripPx, seatDraw, heavyDraw, hueHint, { missTint: !!hitMissTint, missOverlay: !!hitMissTint });
drawStackBlockSpriteOrHue(ctx, -twWorld * zoom / 2, 0, twWorld * zoom, drawStripPx, seatDraw, heavyDraw, hueHint, { missTint: !!hitMissTint, missOverlay: !!hitMissTint, themeOverride: themeOverrideDraw });
ctx.lineWidth = 1;
ctx.restore();
}
@@ -20399,7 +20471,13 @@
/* MG3 stack — non-host รับลำดับตา+index จาก host (single source of truth) → เลิกแยกตึก/ตาเหลื่อม */
socket.on('stack-state', (d) => {
if (!d || !mapData || !isStack() || !detectiveCaseFillBots || isMePlayHost()) return;
if (!d || !mapData || !isStack() || !detectiveCaseFillBots) return;
/* stack-state = server relay "host " (socket.to ) " host"
แก playHostId (dual-host: เขาใจผดวาเป host แล sim เอง = ลำด/ block หลดก host) */
if (d.hostId != null && myId != null && String(d.hostId) !== String(myId)) {
if (String(playHostId) !== String(d.hostId)) playHostId = d.hostId;
}
if (isMePlayHost()) return;
if (Array.isArray(d.order)) {
stackPreviewTurnOrder = d.order.map((e) => ({
kind: e.kind, seat: e.seat,
@@ -20410,7 +20488,24 @@
}
if (stackPreviewTurnOrder && stackPreviewTurnOrder.length && Number.isFinite(Number(d.idx))) {
const n = stackPreviewTurnOrder.length;
stackPreviewTurnIndex = ((Math.floor(Number(d.idx)) % n) + n) % n;
const newIdx = ((Math.floor(Number(d.idx)) % n) + n) % n;
if (newIdx !== stackPreviewTurnIndex) {
stackPreviewTurnIndex = newIdx;
/* refresh "block " (pendingDropSeat/)
เดมไม mark dirty block อยคางโชวของตาทแล = อนปลอยสไมตรง */
markStackNextDropVisualDirty();
}
}
/* sync block "" host layer ( dual-host )
sync เฉพาะเมอจำนวนชนตรงก (aligned) นเขยนผดตำแหนงชวง drop คาบเกยว */
if (Array.isArray(d.lthemes) && stackMini && Array.isArray(stackMini.layers)
&& d.lthemes.length === stackMini.layers.length) {
for (let i = 0; i < stackMini.layers.length; i++) {
const ht = Math.floor(Number(d.lthemes[i]));
if (ht >= 1 && ht <= 8 && stackMini.layers[i] && stackMini.layers[i].theme !== ht) {
stackMini.layers[i].theme = ht;
}
}
}
logStackSeatColors('client-recv');
});
+30 -3
View File
@@ -10,6 +10,21 @@
const nick = (params.get('nick') || '').trim() || 'ผู้เล่น';
const DISPLAY_NAME_STORAGE_KEY = 'roomLobbyDisplayName';
let profileDisplayName = nick;
/* ===== log LobbyA/B → /gamelog (จับ timeline init: connect/join/preload/loading-hide หาเหตุ "กดไม่ได้ต้องรอ") ===== */
const _lobbyT0 = Date.now();
function lobbyLogCat() {
try { if (clientLobbyMapId === POST_CASE_LOBBY_SPACE_ID || serverSuspectPhaseActive) return 'LobbyB'; } catch (e) { /* ignore */ }
return 'LobbyA';
}
function lobbyLog(ev, detail) {
try {
fetch('/gamelog/log.php', {
method: 'POST', headers: { 'Content-Type': 'application/json' }, keepalive: true,
body: JSON.stringify({ cat: lobbyLogCat(), room: (typeof spaceId === 'string' ? spaceId : ''), who: (function () { try { return getProfileDisplayName(); } catch (e) { return nick; } })(), ev: ev || '', detail: (detail || '') + ' [+' + (Date.now() - _lobbyT0) + 'ms]', src: 'client' }),
}).catch(function () {});
} catch (e) { /* ignore */ }
}
lobbyLog('lobby-open', 'space=' + spaceId);
const DESIGN_MENU = typeof designMainMenuHref === 'function' ? designMainMenuHref() : '/Main-Menu/';
if (!spaceId) { location.href = DESIGN_MENU; return; }
const roomIdValueEl = document.getElementById('room-id-value');
@@ -510,6 +525,7 @@
var elapsed = Date.now() - roomLoadingShownAt;
if (elapsed < ROOM_LOADING_MIN_MS) { setTimeout(hideRoomLoading, ROOM_LOADING_MIN_MS - elapsed); return; }
roomLoadingHidden = true;
try { lobbyLog('loading-hide', 'เริ่มเล่นได้'); } catch (e) { /* ignore */ }
var ov = document.getElementById('room-loading-overlay');
if (ov) { ov.classList.add('is-hidden'); setTimeout(function () { if (ov.parentNode) ov.parentNode.removeChild(ov); }, 600); }
}
@@ -3215,6 +3231,7 @@
socket.on('peer-display-name', applyPeerDisplayNameUpdate);
socket.on('connect', () => {
lobbyLog('socket-connect', '');
/* ส่งค่าสีที่เลือกใน Main-Lobby ติดไปด้วย — server จะใช้ค่านี้ถ้ายังว่าง (กันโชว์สีแดง default ตอนเข้าใหม่) */
var savedThemeIdx = null;
var savedSkinIdx = null;
@@ -3245,6 +3262,8 @@
}
mapData = res.mapData;
roomJoinReady = true;
clientLobbyMapId = res.mapId != null ? res.mapId : null;
lobbyLog('join-ok', 'peers=' + (res.peers || []).length + ' host=' + (res.hostId === socket.id ? 'me' : 'other') + ' map=' + res.mapId + ' bots=' + (res.botSlotCount != null ? res.botSlotCount : '?'));
/* ไอคอนกุญแจ 🔒 โชว์เฉพาะห้อง private (จาก res.isPrivate) — public ไม่โชว์ */
try {
const lockEl = document.getElementById('room-id-lock');
@@ -7585,14 +7604,22 @@
setTimeout(resizeAndDraw, 100);
updateLobbyProfileAvatar();
setupRoomCustomize();
lobbyLog('preload-start', '');
rlEnsureManifest(function () {
lobbyLog('manifest-done', '');
rlResolveMyColors(function () {
lobbyLog('colors-resolved', '');
updateRoomProfileAvatarTinted();
preloadMyTintedCharacter(function () {
lobbyLog('mychar-tinted', 'roomJoinReady=' + roomJoinReady);
/* tint "" ( tint = ~12 )
tint คนอนโหลด background avatar คนอนโผลตามทหลงนดหนอย (ยอมรบได) */
roomPreloadReady = true;
setRoomLoadingPct(100);
lobbyLog('preload-ready(mychar)', '');
maybeHideRoomLoading();
preloadAllLobbyTintedOccupants(function () {
roomPreloadReady = true;
setRoomLoadingPct(100);
maybeHideRoomLoading();
lobbyLog('preload-occupants-done(bg)', '');
}, function (d, t) {
setRoomLoadingPct(t ? (d / t) * 100 : 100);
});
+1 -1
View File
@@ -5412,7 +5412,7 @@
<script src="/app-base.js?v=2"></script>
<script src="/Game/socket.io/socket.io.js"></script>
<script src="js/version.js?v=0.0306"></script>
<script src="js/play.js?v=0.006260111"></script>
<script src="js/play.js?v=0.006260120"></script>
<div class="version-tag">v —</div>
<style id="qc-howto-mg2-fix">
/* HOW TO PLAY ของ quiz_carry (Minigame-4) -> ให้เหมือน Minigame-2 (gch-mg2-mock)
+1 -1
View File
@@ -1648,7 +1648,7 @@
<script src="js/version.js?v=0.0122"></script>
<script src="js/customize-popup.js?v=40" data-customize-triggers="" data-customize-asset-base="img/03-5-Customize"></script>
<script src="js/achievements.js?v=0.002" data-asset-base="img/03-6-Profile"></script>
<script src="js/room-lobby.js?v=0.0324"></script>
<script src="js/room-lobby.js?v=0.0326"></script>
<div class="version-tag">v —</div>
</body>
</html>
+10 -1
View File
@@ -8215,6 +8215,7 @@ io.on('connection', (socket) => {
const space = sid ? spaces.get(sid) : null;
if (!space || !data) return;
const num = (v) => (typeof v === 'number' && Number.isFinite(v)) ? v : 0;
const themeOf = (v) => { const n = Math.floor(Number(v)); return (n >= 1 && n <= 8) ? n : null; };
socket.to(sid).emit('stack-drop', {
placedCx: num(data.placedCx), placedW: num(data.placedW),
miss: !!data.miss, perfect: !!data.perfect,
@@ -8223,6 +8224,7 @@ io.on('connection', (socket) => {
supportRatio: (data.supportRatio == null ? null : num(data.supportRatio)),
delta: num(data.delta),
seat: Math.max(1, Math.min(8, Math.floor(num(data.seat)) || 1)), heavy: !!data.heavy,
theme: themeOf(data.theme), /* สี block ที่วาง (host เป็นเจ้าของ) — เดิมถูกตัดทิ้ง → client freeze สีตัวเอง = เพี้ยน */
actorId: data.actorId != null ? String(data.actorId).slice(0, 64) : '', isBot: !!data.isBot,
});
});
@@ -8251,16 +8253,23 @@ io.on('connection', (socket) => {
const sid = socket.data.spaceId;
const space = sid ? spaces.get(sid) : null;
if (!space || space.hostId !== socket.id || !data) return; /* host เท่านั้น */
const themeOf = (v) => { const n = Math.floor(Number(v)); return (n >= 1 && n <= 8) ? n : null; };
const order = Array.isArray(data.order)
? data.order.filter((e) => e && (e.kind === 'human' || e.kind === 'bot')).slice(0, 8).map((e) => ({
kind: e.kind === 'bot' ? 'bot' : 'human',
seat: Math.max(1, Math.min(8, Math.floor(Number(e.seat)) || 1)),
id: e.id != null ? String(e.id).slice(0, 64) : null,
botId: e.botId != null ? String(e.botId).slice(0, 64) : null,
theme: themeOf(e.theme), /* สีต่อ seat (host เป็นเจ้าของ) — เดิมถูกตัดทิ้ง → client คำนวณเอง = เพี้ยน */
}))
: [];
const idx = Math.max(0, Math.floor(Number(data.idx)) || 0);
socket.to(sid).emit('stack-state', { order, idx });
/* สีของ block ที่วางทั้งหอ (host authoritative) — ต้อง relay ด้วย ไม่งั้นถูก allowlist ตัดทิ้ง */
const lthemes = Array.isArray(data.lthemes)
? data.lthemes.slice(0, 200).map((v) => { const n = Math.floor(Number(v)); return (n >= 1 && n <= 8) ? n : 0; })
: [];
/* hostId (= host จริงที่ server ยืนยัน) → client ที่เข้าใจผิดว่าตัวเองเป็น host (dual-host) แก้ playHostId แล้วหยุด sim เอง */
socket.to(sid).emit('stack-state', { order, idx, hostId: socket.id, lthemes });
});
/* MG3 stack — host ตัดสินจบรอบ relay ให้ทุกคนจบพร้อมกัน */
-35
View File
@@ -1,35 +0,0 @@
{"t":1782460590560,"cat":"MG3","room":"hhh","who":"","ev":"game-start","detail":"เริ่มมินิเกม: Minigame-3 Tower block (การ์ด 1)","src":"server"}
{"t":1782460590711,"cat":"MG3","room":"hhh","who":"Q","ev":"host-change","detail":"host ใหม่ → MONE","src":"server"}
{"t":1782460590711,"cat":"MG3","room":"hhh","who":"Q","ev":"leave","detail":"ออกจากห้อง · เหลือคน 1","src":"server"}
{"t":1782460591013,"cat":"MG3","room":"hhh","who":"MONE","ev":"join","detail":"สี#8 · คน 1 + บอท 3","src":"server"}
{"t":1782460591315,"cat":"MG3","room":"hhh","who":"Q","ev":"join","detail":"สี#7 · คน 2 + บอท 3","src":"server"}
{"t":1782460717354,"cat":"LobbyB","room":"hhh","who":"Q","ev":"host-change","detail":"host ใหม่ → MONE","src":"server"}
{"t":1782460717354,"cat":"LobbyB","room":"hhh","who":"Q","ev":"leave","detail":"ออกจากห้อง · เหลือคน 1","src":"server"}
{"t":1782460718032,"cat":"LobbyB","room":"hhh","who":"Q","ev":"join","detail":"สี#7 · คน 2 + บอท 3","src":"server"}
{"t":1782460719931,"cat":"LobbyB","room":"hhh","who":"MONE","ev":"leave","detail":"ออกจากห้อง · เหลือคน 1","src":"server"}
{"t":1782460720509,"cat":"LobbyB","room":"hhh","who":"MONE","ev":"join","detail":"สี#8 · คน 2 + บอท 3","src":"server"}
{"t":1782461143015,"cat":"MG3","room":"hhh","who":"","ev":"game-start","detail":"เริ่มมินิเกม: Minigame-3 Tower block (การ์ด 1)","src":"server"}
{"t":1782461143223,"cat":"MG3","room":"hhh","who":"Q","ev":"host-change","detail":"host ใหม่ → MONE","src":"server"}
{"t":1782461143223,"cat":"MG3","room":"hhh","who":"Q","ev":"leave","detail":"ออกจากห้อง · เหลือคน 1","src":"server"}
{"t":1782461143637,"cat":"MG3","room":"hhh","who":"Q","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782461143920,"cat":"MG3","room":"hhh","who":"MONE","ev":"join","detail":"สี#8 · คน 2 + บอท 3","src":"server"}
{"t":1782461213243,"cat":"MG3","room":"hhh","who":"Q","ev":"host-change","detail":"host ใหม่ → MONE","src":"server"}
{"t":1782461213243,"cat":"MG3","room":"hhh","who":"Q","ev":"leave","detail":"ออกจากห้อง · เหลือคน 1","src":"server"}
{"t":1782461223245,"cat":"MG3","room":"hhh","who":"Q","ev":"bot-takeover","detail":"หลุดเกิน 10วิ → บอทแทน (สีตามคนออก)","src":"server"}
{"t":1782461274423,"cat":"LobbyB","room":"hhh","who":"MONE","ev":"join","detail":"สี#8 · คน 1 + บอท 4","src":"server"}
{"t":1782461327954,"cat":"LobbyA","room":"aaa","who":"Q","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782461351978,"cat":"LobbyA","room":"aaa","who":"Q","ev":"join","detail":"สี#7 · คน 1 + บอท 4","src":"server"}
{"t":1782461363786,"cat":"LobbyA","room":"aaa","who":"MONE","ev":"join","detail":"สี#8 · คน 2 + บอท 4","src":"server"}
{"t":1782461415359,"cat":"LobbyB","room":"aaa","who":"Q","ev":"host-change","detail":"host ใหม่ → MONE","src":"server"}
{"t":1782461415359,"cat":"LobbyB","room":"aaa","who":"Q","ev":"leave","detail":"ออกจากห้อง · เหลือคน 1","src":"server"}
{"t":1782461425362,"cat":"LobbyB","room":"aaa","who":"Q","ev":"bot-takeover","detail":"หลุดเกิน 10วิ → บอทแทน (สีตามคนออก)","src":"server"}
{"t":1782461428827,"cat":"LobbyA","room":"aaa","who":"Q","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782461438053,"cat":"LobbyA","room":"aaa","who":"MONE","ev":"join","detail":"สี#8 · คน 2 + บอท 3","src":"server"}
{"t":1782461466584,"cat":"MG3","room":"aaa","who":"","ev":"game-start","detail":"เริ่มมินิเกม: Minigame-3 Tower block (การ์ด 1)","src":"server"}
{"t":1782461466705,"cat":"MG3","room":"aaa","who":"Q","ev":"host-change","detail":"host ใหม่ → MONE","src":"server"}
{"t":1782461466705,"cat":"MG3","room":"aaa","who":"Q","ev":"leave","detail":"ออกจากห้อง · เหลือคน 1","src":"server"}
{"t":1782461467047,"cat":"MG3","room":"aaa","who":"MONE","ev":"join","detail":"สี#8 · คน 1 + บอท 3","src":"server"}
{"t":1782461467352,"cat":"MG3","room":"aaa","who":"Q","ev":"join","detail":"สี#7 · คน 2 + บอท 3","src":"server"}
{"t":1782461544478,"cat":"MG3","room":"aaa","who":"Q","ev":"host-change","detail":"host ใหม่ → MONE","src":"server"}
{"t":1782461544479,"cat":"MG3","room":"aaa","who":"Q","ev":"leave","detail":"ออกจากห้อง · เหลือคน 1","src":"server"}
{"t":1782461554486,"cat":"MG3","room":"aaa","who":"Q","ev":"bot-takeover","detail":"หลุดเกิน 10วิ → บอทแทน (สีตามคนออก)","src":"server"}
File diff suppressed because it is too large Load Diff