From fae9393e8c549e78770e1ab7023491e7fb262ba7 Mon Sep 17 00:00:00 2001 From: Ole Date: Sun, 14 Jun 2026 22:40:15 +0200 Subject: [PATCH] =?UTF-8?q?Gameplay:=20Nochmal-Synchronisation=20+=20Echtz?= =?UTF-8?q?eit-Commit-Z=C3=A4hler=20+=20Host-Button=20umbenannt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Host-Lobby: 'Münzwurf starten' → 'Spiel starten' - 'Nochmal': warten bis alle bereit (ready_next/ready_next_all), erst dann 'Münzwurf starten' anzeigen - Progress zeigt Commits/Reveals in Echtzeit (auch vor eigenem Start) - totalPeers bereits im Konstruktor setzen für sofortige Anzeige --- app.js | 62 ++++++++++++++++++++++++++++++++--------------------- index.html | 2 +- protocol.js | 22 +++++++++++-------- 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/app.js b/app.js index 619e69a..df14e6f 100644 --- a/app.js +++ b/app.js @@ -5,6 +5,7 @@ let protocol = null; let role = null; let scanningHost = false; + let _nextReady = new Set(); const $ = id => document.getElementById(id); @@ -232,14 +233,26 @@ }); } + /* ─── Show start-protocol button after all ready ─── */ + function _showStartButton() { + $('btn-start-protocol').hidden = false; + $('result-area').hidden = true; + $('results-container').hidden = true; + $('protocol-text').textContent = 'Bereit zum Münzwurf'; + $('btn-retry').disabled = false; + $('btn-retry').textContent = 'Nochmal'; + updatePhases('IDLE'); + } + /* ─── Game setup ─── */ - function setupGame(autostart) { + function setupGame() { + _nextReady = new Set(); show('game'); renderPlayers('game-player-list'); - $('btn-start-protocol').hidden = autostart || role !== 'host'; + $('btn-start-protocol').hidden = false; $('results-container').hidden = true; $('result-area').hidden = true; - $('protocol-text').textContent = autostart ? 'Starte Protokoll...' : 'Bereit zum Münzwurf'; + $('protocol-text').textContent = 'Bereit zum Münzwurf'; updatePhases('IDLE'); protocol = new CoinFlipProtocol(mesh); @@ -264,23 +277,23 @@ }; mesh.ondata = (peerId, msg) => { - if (msg.type === 'protocol_start') { - if (protocol) protocol.reset(); - $('results-container').hidden = true; - $('result-area').hidden = true; - $('btn-start-protocol').hidden = true; - updatePhases('IDLE'); - protocol.start(); + if (msg.type === 'ready_next') { + _nextReady.add(peerId); + const all = [mesh.myPeerId, ...mesh.getPeerIds()]; + if (_nextReady.size >= all.length) { + mesh.broadcast({ type: 'ready_next_all' }); + _showStartButton(); + } + return; + } + if (msg.type === 'ready_next_all') { + _showStartButton(); return; } if (msg.type === 'protocol' && protocol) { protocol.handleMessage(peerId, msg); } }; - - if (autostart) { - protocol.start(); - } } /* ─── Start screen ─── */ @@ -392,8 +405,8 @@ }; mesh.ondata = (peerId, msg) => { - if (msg.type === 'protocol_start') { - setupGame(true); + if (msg.type === 'game_start') { + setupGame(); } }; @@ -426,13 +439,15 @@ /* ─── Host: start game button (in host screen) ─── */ $('btn-start-game').addEventListener('click', () => { - setupGame(false); + if (!mesh) return; + mesh.broadcast({ type: 'game_start' }); + setupGame(); }); /* ─── Host: start protocol button (in game screen) ─── */ $('btn-start-protocol').addEventListener('click', async () => { if (!mesh || !protocol) return; - mesh.broadcast({ type: 'protocol_start' }); + _nextReady = new Set(); $('btn-start-protocol').hidden = true; await protocol.start(); }); @@ -440,11 +455,10 @@ /* ─── Retry / again ─── */ $('btn-retry').addEventListener('click', () => { if (protocol) protocol.reset(); - $('results-container').hidden = true; - $('result-area').hidden = true; - $('btn-start-protocol').hidden = role !== 'host'; - $('protocol-text').textContent = 'Bereit zum Münzwurf'; - updatePhases('IDLE'); + _nextReady.add(mesh.myPeerId); + mesh.broadcast({ type: 'ready_next' }); + $('btn-retry').disabled = true; + $('btn-retry').textContent = 'Warte...'; }); /* ─── Result screen → play again ─── */ @@ -452,7 +466,7 @@ if (protocol) protocol.reset(); $('results-container').hidden = true; $('result-area').hidden = true; - setupGame(false); + setupGame(); }); /* ─── Back to start ─── */ diff --git a/index.html b/index.html index 160eab1..9861ed7 100644 --- a/index.html +++ b/index.html @@ -50,7 +50,7 @@ - + diff --git a/protocol.js b/protocol.js index ca0ceb2..fa84561 100644 --- a/protocol.js +++ b/protocol.js @@ -6,7 +6,7 @@ class CoinFlipProtocol { this.commits = new Map(); this.reveals = new Map(); this.result = null; - this.totalPeers = 0; + this.totalPeers = 1 + mesh.getPeerIds().length; this.expectedPeers = new Set(); this.TIMEOUT_MS = 12000; this._commitTimer = null; @@ -26,7 +26,7 @@ class CoinFlipProtocol { this.secret = await generateSecret(); const myCommit = await commit(this.secret); this.commits.set(this.mesh.myPeerId, myCommit); - if (this.onprogress) this.onprogress('commit', 1, this.totalPeers); + if (this.onprogress) this.onprogress('commit', this.commits.size, this.totalPeers); if (this.onstatechange) this.onstatechange('COMMITTING'); this.mesh.broadcast({ type: 'protocol', phase: 'commit', data: bufToBase64(myCommit) }); this.state = 'WAITING_FOR_COMMITS'; @@ -38,20 +38,24 @@ class CoinFlipProtocol { handleMessage(peerId, msg) { if (msg.type !== 'protocol') return; - if (msg.phase === 'commit' && (this.state === 'WAITING_FOR_COMMITS' || this.state === 'COMMITTING' || this.state === 'STARTING')) { + if (msg.phase === 'commit') { if (!this.commits.has(peerId)) { this.commits.set(peerId, base64ToBuf(msg.data)); - if (this.onprogress) this.onprogress('commit', this.commits.size, this.totalPeers); - this._checkCommits(); + if (this.onprogress) + this.onprogress('commit', this.commits.size, this.totalPeers); + if (this.state === 'WAITING_FOR_COMMITS') this._checkCommits(); } + return; } - if (msg.phase === 'reveal' && (this.state === 'WAITING_FOR_REVEALS' || this.state === 'REVEALING')) { + if (msg.phase === 'reveal') { if (!this.reveals.has(peerId)) { this.reveals.set(peerId, base64ToBuf(msg.data)); - if (this.onprogress) this.onprogress('reveal', this.reveals.size, this.totalPeers); - this._checkReveals(); + if (this.onprogress) + this.onprogress('reveal', this.reveals.size, this.totalPeers); + if (this.state === 'WAITING_FOR_REVEALS') this._checkReveals(); } + return; } } @@ -112,7 +116,7 @@ class CoinFlipProtocol { if (this.onstatechange) this.onstatechange('REVEALING'); this.mesh.broadcast({ type: 'protocol', phase: 'reveal', data: bufToBase64(this.secret) }); this.reveals.set(this.mesh.myPeerId, this.secret); - if (this.onprogress) this.onprogress('reveal', 1, this.totalPeers); + if (this.onprogress) this.onprogress('reveal', this.reveals.size, this.totalPeers); this.state = 'WAITING_FOR_REVEALS'; if (this.onstatechange) this.onstatechange('WAITING_FOR_REVEALS'); this._startRevealTimer();