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();