Chess on the ATmosphere checkmate.blue
chess
18
fork

Configure Feed

Select the types of activity you want to include in your feed.

Implement draw offers, fix waitForOpponent Jetstream bug

Draw offers: player writes drawOffered to their record, opponent sees
accept/decline banner via Jetstream. Accepting writes draw result,
declining just dismisses. Making a move implicitly declines. State
persists across page reloads.

Also fixes: waitForOpponent ignoring events with status != active
(prevents premature transition when creating game as black),
connectJetstream called before PDS write (prevents dead Jetstream if
write fails), game controls hidden until first move played, explicit
result tracking for resignation and draw by agreement.

authored by

Scott Hadfield and committed by tangled.org 0a5175f1 88907421

+9 -6
+9 -6
src/routes/game/[did]/[rkey]/+page.svelte
··· 293 293 blackDid: black, 294 294 status: 'active' as const, 295 295 }); 296 + resolvePlayerHandles(white, black); 297 + connectJetstream(opponentDid); 298 + 299 + // Persist to PDS after Jetstream is connected 296 300 if (auth.agent && myRkey) { 297 301 const updates: Record<string, unknown> = { status: 'active' }; 298 302 if (weAreWhite) updates.black = black; 299 303 else updates.white = white; 300 - await updateGame(auth.agent, myRkey, updates); 304 + updateGame(auth.agent, myRkey, updates).catch(() => {}); 301 305 } 302 - resolvePlayerHandles(white, black); 303 - connectJetstream(opponentDid); 304 306 } 305 307 }, 306 308 onConnectionChange: (isConnected) => { ··· 491 493 if (!auth.agent || !auth.did || !myRkey) return; 492 494 493 495 const result = game.myColor === 'white' ? '0-1' : '1-0'; 496 + game.setResult(result, 'resignation'); 494 497 game.setStatus('completed'); 495 498 await updateGame(auth.agent, myRkey, { 496 499 status: 'completed', ··· 863 866 </div> 864 867 {/if} 865 868 866 - {#if !isSpectator} 869 + {#if !isSpectator && game.status === 'active' && game.moveCount > 0} 867 870 <GameControls 868 - gameOver={game.result !== null || game.status === 'completed'} 871 + gameOver={game.result !== null} 869 872 drawOfferedByMe={game.drawOfferedByMe} 870 873 drawOfferedByOpponent={game.drawOfferedByOpponent} 871 874 onresign={handleResign} ··· 879 882 onclick={handleAbandon} 880 883 class="text-sm text-text-secondary transition-colors hover:text-danger" 881 884 > 882 - {game.status === 'waiting' ? 'Cancel game' : `Claim win (opponent inactive ${daysSinceActivity}d)`} 885 + Claim win (opponent inactive {daysSinceActivity}d) 883 886 </button> 884 887 {/if} 885 888 {/if}