fixed refreshed issue ?

This commit is contained in:
Didictateur 2025-11-26 23:10:18 +01:00
parent 71f16b6da8
commit c930b10132
2 changed files with 52 additions and 15 deletions

View file

@ -147,6 +147,27 @@
}catch(_){ }
}
// Robust card:play emitter with refresh fallback.
// Sometimes the client or network misses the room:update after playing a card —
// this helper emits card:play and requests a room refresh if no ack/update is received.
function emitCardPlay(payload, cb){
try{
if(!socket) return cb && cb({ error: 'no_socket' });
let acked = false;
const timer = setTimeout(()=>{
if(!acked){
try{ socket.emit('room:refresh', { roomId }, ()=>{}); }catch(_){ }
}
}, 1500);
socket.emit('card:play', payload, (resp)=>{
acked = true; try{ clearTimeout(timer); }catch(_){ }
// ask server to push a fresh room:update to ensure UIs are in sync
try{ socket.emit('room:refresh', { roomId }, ()=>{}); }catch(_){ }
if(cb) cb(resp);
});
}catch(e){ if(cb) cb({ error: 'emit_failed' }); }
}
// play a short shuffle animation (shake + fade) when pieces are mixed
function playShuffleAnimation(){
if(!boardEl) return;
@ -749,7 +770,7 @@
const occ = currentBoardState && Array.isArray(currentBoardState.pieces) && currentBoardState.pieces.find(p => p.square === square);
if(!occ || occ.color === myShort){ log('select an enemy piece (second)'); return; }
// emit swap payload: sourceSquare + targetSquare
socket.emit('card:play', { roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { sourceSquare: pendingCard.firstTarget, targetSquare: square } }, (resp)=>{
emitCardPlay({ roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { sourceSquare: pendingCard.firstTarget, targetSquare: square } }, (resp)=>{
if(resp && resp.error){ log('card:play error', resp); showToast(resp.message || resp.error, { background: 'rgba(200,60,60,0.95)' }); }
else { log('inversion played', resp); }
});
@ -761,7 +782,7 @@
const occupied = currentBoardState && Array.isArray(currentBoardState.pieces) && currentBoardState.pieces.find(p => p.square === square);
if(occupied){ log('square not empty for mine placement'); return; }
// send mine placement
socket.emit('card:play', { roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square } }, (resp)=>{
emitCardPlay({ roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square } }, (resp)=>{
if(resp && resp.error){ log('card:play error', resp); showToast(resp.message || resp.error, { background: 'rgba(200,60,60,0.95)' }); }
else { log('card played with target', resp); }
});
@ -770,7 +791,7 @@
const piece = currentBoardState && Array.isArray(currentBoardState.pieces) && currentBoardState.pieces.find(p => p.square === square);
if(!piece || piece.color !== myShort){ log('select one of your pieces'); return; }
if(piece.type && piece.type.toLowerCase() === 'k'){ log('cannot select king'); return; }
socket.emit('card:play', { roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square } }, (resp)=>{
emitCardPlay({ roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square } }, (resp)=>{
if(resp && resp.error){ log('card:play error', resp); showToast(resp.message || resp.error, { background: 'rgba(200,60,60,0.95)' }); }
else { log('card played with target', resp); }
});
@ -787,7 +808,7 @@
// canceled
pendingCard = null; clearTargetHighlights(); return;
}
socket.emit('card:play', { roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square, promotion: promotionChoice } }, (resp)=>{
emitCardPlay({ roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square, promotion: promotionChoice } }, (resp)=>{
if(resp && resp.error){ log('card:play error', resp); showToast(resp.message || resp.error, { background: 'rgba(200,60,60,0.95)' }); }
else { log('card played with promotion', resp); }
});
@ -798,7 +819,7 @@
const occ = currentBoardState && Array.isArray(currentBoardState.pieces) && currentBoardState.pieces.find(p => p.square === square);
if(!occ || occ.color === myShort){ log('select an enemy piece'); return; }
if(occ.type && occ.type.toLowerCase() === 'k'){ log('cannot select king'); return; }
socket.emit('card:play', { roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square } }, (resp)=>{
emitCardPlay({ roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square } }, (resp)=>{
if(resp && resp.error){ log('card:play error', resp); showToast(resp.message || resp.error, { background: 'rgba(200,60,60,0.95)' }); }
else { log('card played with target', resp);
// after server applied the card effect, request legal moves for the selected piece so the client
@ -812,7 +833,7 @@
else if(req === 'enemy_queen'){
const occ = currentBoardState && Array.isArray(currentBoardState.pieces) && currentBoardState.pieces.find(p => p.square === square);
if(!occ || occ.color === myShort || !occ.type || occ.type.toLowerCase() !== 'q'){ log('select an enemy queen'); return; }
socket.emit('card:play', { roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square } }, (resp)=>{
emitCardPlay({ roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square } }, (resp)=>{
if(resp && resp.error){ log('card:play error', resp); showToast(resp.message || resp.error, { background: 'rgba(200,60,60,0.95)' }); }
else { log('card played with target', resp);
try{ setSelection(square); }catch(_){ }
@ -824,7 +845,7 @@
const occ = currentBoardState && Array.isArray(currentBoardState.pieces) && currentBoardState.pieces.find(p => p.square === square);
if(!occ){ log('select a piece'); return; }
if(occ.type && occ.type.toLowerCase() === 'k'){ log('cannot select king'); return; }
socket.emit('card:play', { roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square } }, (resp)=>{
emitCardPlay({ roomId, playerId: myPlayerId, cardId: pendingCard.cardId, payload: { targetSquare: square } }, (resp)=>{
if(resp && resp.error){ log('card:play error', resp); showToast(resp.message || resp.error, { background: 'rgba(200,60,60,0.95)' }); }
else { log('card played with target', resp); }
});
@ -1189,7 +1210,7 @@
const opponents = Object.keys(handCounts || {}).filter(pid => pid !== myPlayerId);
if(opponents.length === 1){
const targetPlayerId = opponents[0];
socket.emit('card:play', { roomId, playerId: myPlayerId, cardId: cid, payload: { targetPlayerId } }, (resp)=>{
emitCardPlay({ roomId, playerId: myPlayerId, cardId: cid, payload: { targetPlayerId } }, (resp)=>{
if(resp && resp.error){ log('card:play error', resp); showToast(resp.message || resp.error, { background: 'rgba(200,60,60,0.95)' }); }
else { log('card played (steal card)', resp); }
});
@ -1198,7 +1219,7 @@
// show modal to pick which player to steal from
showStealModal(handCounts, (targetPlayerId)=>{
if(!targetPlayerId) return; // canceled
socket.emit('card:play', { roomId, playerId: myPlayerId, cardId: cid, payload: { targetPlayerId } }, (resp)=>{
emitCardPlay({ roomId, playerId: myPlayerId, cardId: cid, payload: { targetPlayerId } }, (resp)=>{
if(resp && resp.error){ log('card:play error', resp); showToast(resp.message || resp.error, { background: 'rgba(200,60,60,0.95)' }); }
else { log('card played (steal card)', resp); }
});
@ -1213,7 +1234,7 @@
}
// immediate-play card (no target required)
const payload = {};
socket.emit('card:play', { roomId, playerId: myPlayerId, cardId: cid, payload }, (resp)=>{
emitCardPlay({ roomId, playerId: myPlayerId, cardId: cid, payload }, (resp)=>{
if(resp && resp.error){ log('card:play error', resp); showToast(resp.message || resp.error, { background: 'rgba(200,60,60,0.95)' }); }
else { log('card played', resp); }
});

View file

@ -141,7 +141,12 @@ function maybeDrawAtTurnStart(room, playerId){
try{
if(!room) return;
if(room.autoDraw){
drawCardForPlayer(room, playerId);
const drawn = drawCardForPlayer(room, playerId);
// if nothing was drawn (deck empty, hand full, or noRemise), still push a room update
// so clients get the freshest state and don't remain out-of-sync.
if(!drawn){
try{ sendRoomUpdate(room); }catch(_){ }
}
} else {
// ensure clients get the updated room state even if no draw happens
sendRoomUpdate(room);
@ -1316,6 +1321,17 @@ io.on('connection', (socket) => {
}catch(err){ console.error('room:deck:set error', err); return cb && cb({ error: 'server_error' }); }
});
// Client-requested refresh: allow client to ask server to resend the personalized room:update
socket.on('room:refresh', ({ roomId }, cb) => {
try{
const room = rooms.get(roomId);
if(!room) return cb && cb({ error: 'room not found' });
// only send personalized updates (sendRoomUpdate handles per-client privacy)
sendRoomUpdate(room);
return cb && cb({ ok: true });
}catch(e){ console.error('room:refresh error', e); return cb && cb({ error: 'server_error' }); }
});
socket.on('disconnect', () => {
const roomId = socket.data.roomId;
if (!roomId) return;