Clients now render from the state delivered with each move/update and drop stale or echoed updates via a ply-version guard, instead of issuing a full game-state fetch per event. Adds captured-piece trays, a material advantage badge, a move list, a status line, and the mobile menu toggle. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
71 lines
2.3 KiB
JavaScript
71 lines
2.3 KiB
JavaScript
const ChessSignalR = {
|
|
connection: null,
|
|
|
|
async setupConnection() {
|
|
this.connection = new signalR.HubConnectionBuilder()
|
|
.withUrl("/chessHub")
|
|
.configureLogging(signalR.LogLevel.Information)
|
|
.build();
|
|
|
|
this.connection.onclose(err => {
|
|
console.error("❌ SignalR connection closed:", err?.message);
|
|
});
|
|
|
|
this.connection.on("ReceiveMoveUpdate", async (gameId, moveDto, moveResultDto, state) => {
|
|
await this.handleMoveUpdate(gameId, moveDto, moveResultDto, state);
|
|
});
|
|
|
|
this.connection.on("ReceiveGameOver", async (gameId, winner, reason) => {
|
|
await this.handleGameOver(gameId, winner, reason);
|
|
});
|
|
|
|
try {
|
|
await this.connection.start();
|
|
console.log("✅ SignalR connected");
|
|
await this.connection.invoke("JoinWebsocketGroup", GameState.currentGameId);
|
|
} catch (err) {
|
|
console.error("❌ SignalR failed to start or join:", err);
|
|
}
|
|
},
|
|
|
|
async handleMoveUpdate(gameId, moveDto, moveResultDto, state) {
|
|
if (gameId !== GameState.currentGameId) return;
|
|
|
|
// Drop the echo of our own move and any out-of-order delivery.
|
|
if (!GameState.shouldApply(state?.version)) return;
|
|
|
|
GameState.setPreviousMove([moveDto.sourceRow, moveDto.sourceCol], [moveDto.targetRow, moveDto.targetCol]);
|
|
ChessBoard.renderState(state);
|
|
|
|
ChessAPI.alertGameStatusChange(moveResultDto);
|
|
},
|
|
|
|
async handleGameOver(gameId, winner, reason) {
|
|
if (gameId !== GameState.currentGameId) return;
|
|
|
|
const youWon = (winner === "White") === GameState.currentPlayerIsWhite;
|
|
|
|
if (reason === "forfeit")
|
|
alert(youWon ? "🏳️ Your opponent forfeited — you win!" : "🏳️ You forfeited this game.");
|
|
|
|
showCopyPgn(gameId);
|
|
await this.leaveGame();
|
|
},
|
|
|
|
async leaveGame() {
|
|
if (this.connection) {
|
|
await this.connection.invoke("LeaveWebsocketGroup", GameState.currentGameId);
|
|
await this.connection.stop();
|
|
this.connection = null;
|
|
}
|
|
},
|
|
|
|
async stopConnection() {
|
|
if (this.connection) {
|
|
await this.connection.stop();
|
|
this.connection = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
console.log("ChessSignalR.js loaded"); |