Add cookies and game deletions
This commit is contained in:
@@ -67,6 +67,8 @@ public class ChessController : ControllerBase
|
|||||||
isWhite = false;
|
isWhite = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScheduleRemoveGame(gameState.GameId, TimeSpan.FromDays(1));
|
||||||
|
|
||||||
return Ok(new
|
return Ok(new
|
||||||
{
|
{
|
||||||
Id = playerId,
|
Id = playerId,
|
||||||
@@ -146,12 +148,12 @@ public class ChessController : ControllerBase
|
|||||||
if (result.IsCheckmate || result.IsStalemate)
|
if (result.IsCheckmate || result.IsStalemate)
|
||||||
{
|
{
|
||||||
// queue game removal
|
// queue game removal
|
||||||
_gameRemovalTasks.TryAdd(moveDto.GameId, Task.Run(async () =>
|
ScheduleRemoveGame(gameState.GameId, TimeSpan.FromMinutes(1));
|
||||||
{
|
}
|
||||||
await Task.Delay(TimeSpan.FromMinutes(1));
|
else
|
||||||
_games.Remove(moveDto.GameId, out _);
|
{
|
||||||
_gameRemovalTasks.Remove(moveDto.GameId, out _);
|
// increase timeout if play continues.
|
||||||
}));
|
ScheduleRemoveGame(gameState.GameId, TimeSpan.FromDays(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
@@ -189,4 +191,26 @@ public class ChessController : ControllerBase
|
|||||||
|
|
||||||
return Ok(allMoves);
|
return Ok(allMoves);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ScheduleRemoveGame(Guid id, TimeSpan delay)
|
||||||
|
{
|
||||||
|
if (_gameRemovalTasks.ContainsKey(id))
|
||||||
|
{
|
||||||
|
_gameRemovalTasks[id] = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await Task.Delay(delay);
|
||||||
|
_games.Remove(id, out _);
|
||||||
|
_gameRemovalTasks.Remove(id, out _);
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_gameRemovalTasks.TryAdd(id, Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await Task.Delay(delay);
|
||||||
|
_games.Remove(id, out _);
|
||||||
|
_gameRemovalTasks.Remove(id, out _);
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,14 @@ public class ChessHub : Hub
|
|||||||
await Groups.AddToGroupAsync(Context.ConnectionId, gameId);
|
await Groups.AddToGroupAsync(Context.ConnectionId, gameId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task MoveMade(string gameId, MoveResultDto moveResult)
|
public async Task MoveMade(string gameId, MoveDto moveDto, MoveResultDto moveResult)
|
||||||
{
|
{
|
||||||
await Clients.OthersInGroup(gameId).SendAsync("ReceiveMoveUpdate", gameId, moveResult);
|
await Clients.OthersInGroup(gameId).SendAsync("ReceiveMoveUpdate", gameId, moveDto, moveResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LeaveWebsocketGroup(string gameId)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"❌ Leaving group {gameId}");
|
||||||
|
await Groups.RemoveFromGroupAsync(Context.ConnectionId, gameId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,4 +41,14 @@
|
|||||||
|
|
||||||
#chessBoard.flipped {
|
#chessBoard.flipped {
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chessSquare.previous-start {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 4px solid #ffd700; /* gold or whatever you like */
|
||||||
|
}
|
||||||
|
|
||||||
|
.chessSquare.previous-end {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 4px solid #ff8c00; /* orange */
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,8 @@ let currentPlayerIsWhite = null;
|
|||||||
let signalRConnection = null;
|
let signalRConnection = null;
|
||||||
let selectedPiece = null;
|
let selectedPiece = null;
|
||||||
let legalMoves = [];
|
let legalMoves = [];
|
||||||
|
let previousMoveStart = null;
|
||||||
|
let previousMoveEnd = null;
|
||||||
|
|
||||||
async function startNewGame() {
|
async function startNewGame() {
|
||||||
// Stop previous SignalR connection if needed
|
// Stop previous SignalR connection if needed
|
||||||
@@ -19,35 +21,15 @@ async function startNewGame() {
|
|||||||
currentGameId = gameData.gameId;
|
currentGameId = gameData.gameId;
|
||||||
currentPlayerId = gameData.id;
|
currentPlayerId = gameData.id;
|
||||||
currentPlayerIsWhite = gameData.isWhite;
|
currentPlayerIsWhite = gameData.isWhite;
|
||||||
|
previousMoveStart = null;
|
||||||
|
previousMoveEnd = null;
|
||||||
|
document.cookie = `chessGameId=${currentGameId}; path=/; max-age=86400`; // expires in 1 day
|
||||||
|
document.cookie = `chessPlayerId=${currentPlayerId}; path=/; max-age=86400`;
|
||||||
|
document.cookie = `chessPlayerIsWhite=${currentPlayerIsWhite}; path=/; max-age=86400`
|
||||||
console.log("🆕 Game started:", currentGameId);
|
console.log("🆕 Game started:", currentGameId);
|
||||||
|
|
||||||
// Build and start SignalR connection
|
// Build and start SignalR connection
|
||||||
signalRConnection = new signalR.HubConnectionBuilder()
|
await setupSignalRConnection();
|
||||||
.withUrl("/chessHub")
|
|
||||||
.configureLogging(signalR.LogLevel.Information)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
signalRConnection.onclose(err => {
|
|
||||||
console.error("❌ SignalR connection closed:", err?.message);
|
|
||||||
});
|
|
||||||
|
|
||||||
signalRConnection.on("ReceiveMoveUpdate", async (gameId, moveResultDto) => {
|
|
||||||
if (gameId !== currentGameId) return;
|
|
||||||
|
|
||||||
const res = await fetch(`/api/chess/${gameId}`);
|
|
||||||
const data = await res.json();
|
|
||||||
renderPieces(data.pieces);
|
|
||||||
|
|
||||||
alertGameStatusChange(moveResultDto);
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
await signalRConnection.start();
|
|
||||||
console.log("✅ SignalR connected");
|
|
||||||
await signalRConnection.invoke("JoinWebsocketGroup", currentGameId);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("❌ SignalR failed to start or join:", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render initial state
|
// Render initial state
|
||||||
const gameState = await fetch(`/api/chess/${currentGameId}`);
|
const gameState = await fetch(`/api/chess/${currentGameId}`);
|
||||||
@@ -87,11 +69,23 @@ function renderPieces(pieces) {
|
|||||||
|
|
||||||
for (let i = 0; i < 64; i++) {
|
for (let i = 0; i < 64; i++) {
|
||||||
const square = document.getElementById(`square-${i}`);
|
const square = document.getElementById(`square-${i}`);
|
||||||
|
square.classList.remove("previous-start", "previous-end");
|
||||||
|
|
||||||
if (!square.classList.contains("legal")) {
|
if (!square.classList.contains("legal")) {
|
||||||
square.onclick = () => clearHighlights();
|
square.onclick = () => clearHighlights();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (previousMoveStart && previousMoveEnd) {
|
||||||
|
const [startRow, startCol] = flipCoordinates(...previousMoveStart);
|
||||||
|
const [endRow, endCol] = flipCoordinates(...previousMoveEnd);
|
||||||
|
|
||||||
|
const startIndex = startRow * 8 + startCol;
|
||||||
|
const endIndex = endRow * 8 + endCol;
|
||||||
|
|
||||||
|
document.getElementById(`square-${startIndex}`)?.classList.add("previous-start");
|
||||||
|
document.getElementById(`square-${endIndex}`)?.classList.add("previous-end");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPieceImageUrl(piece) {
|
function getPieceImageUrl(piece) {
|
||||||
@@ -164,6 +158,9 @@ async function handleMove(targetRow, targetCol) {
|
|||||||
PromotionChoice: null // optional
|
PromotionChoice: null // optional
|
||||||
};
|
};
|
||||||
|
|
||||||
|
previousMoveStart = [selectedPiece.row, selectedPiece.col];
|
||||||
|
previousMoveEnd = [targetRow, targetCol];
|
||||||
|
|
||||||
const res = await fetch("/api/chess/move", {
|
const res = await fetch("/api/chess/move", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
@@ -184,7 +181,7 @@ async function handleMove(targetRow, targetCol) {
|
|||||||
selectedPiece = null;
|
selectedPiece = null;
|
||||||
legalMoves = [];
|
legalMoves = [];
|
||||||
clearHighlights();
|
clearHighlights();
|
||||||
await signalRConnection.invoke("MoveMade", currentGameId, moveResultDto);
|
await signalRConnection.invoke("MoveMade", currentGameId, moveDto, moveResultDto);
|
||||||
|
|
||||||
alertGameStatusChange(moveResultDto);
|
alertGameStatusChange(moveResultDto);
|
||||||
}
|
}
|
||||||
@@ -208,7 +205,8 @@ function clearHighlights() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function alertGameStatusChange(moveResultDto) {
|
function alertGameStatusChange(moveResultDto) {
|
||||||
setTimeout(() => {
|
setTimeout(async () => {
|
||||||
|
let gameOver = false;
|
||||||
// 🟡 Optional: show check
|
// 🟡 Optional: show check
|
||||||
if (moveResultDto.isCheck) {
|
if (moveResultDto.isCheck) {
|
||||||
console.log("🛑 Check!");
|
console.log("🛑 Check!");
|
||||||
@@ -222,6 +220,12 @@ function alertGameStatusChange(moveResultDto) {
|
|||||||
alert("🤝 Stalemate!");
|
alert("🤝 Stalemate!");
|
||||||
gameOver = true;
|
gameOver = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gameOver) {
|
||||||
|
await signalRConnection.invoke("LeaveWebsocketGroup", currentGameId);
|
||||||
|
await signalRConnection.stop();
|
||||||
|
signalRConnection = null;
|
||||||
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,5 +236,68 @@ function flipCoordinates(row, col) {
|
|||||||
return [row, col];
|
return [row, col];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCookie(name) {
|
||||||
|
const value = document.cookie.split('; ')
|
||||||
|
.find(row => row.startsWith(name + '='));
|
||||||
|
return value ? value.split('=')[1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setupSignalRConnection() {
|
||||||
|
signalRConnection = new signalR.HubConnectionBuilder()
|
||||||
|
.withUrl("/chessHub")
|
||||||
|
.configureLogging(signalR.LogLevel.Information)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
signalRConnection.onclose(err => {
|
||||||
|
console.error("❌ SignalR connection closed:", err?.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
signalRConnection.on("ReceiveMoveUpdate", async (gameId, moveDto, moveResultDto) => {
|
||||||
|
if (gameId !== currentGameId) return;
|
||||||
|
|
||||||
|
const res = await fetch(`/api/chess/${gameId}`);
|
||||||
|
const data = await res.json();
|
||||||
|
previousMoveStart = [moveDto.sourceRow, moveDto.sourceCol];
|
||||||
|
previousMoveEnd = [moveDto.targetRow, moveDto.targetCol];
|
||||||
|
renderPieces(data.pieces);
|
||||||
|
|
||||||
|
alertGameStatusChange(moveResultDto);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await signalRConnection.start();
|
||||||
|
console.log("✅ SignalR connected");
|
||||||
|
await signalRConnection.invoke("JoinWebsocketGroup", currentGameId);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("❌ SignalR failed to start or join:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log("chessLogic.js loaded");
|
console.log("chessLogic.js loaded");
|
||||||
window.startNewGame = startNewGame;
|
window.startNewGame = startNewGame;
|
||||||
|
|
||||||
|
window.addEventListener('load', async () => {
|
||||||
|
const savedGameId = getCookie("chessGameId");
|
||||||
|
const savedPlayerId = getCookie("chessPlayerId");
|
||||||
|
const savedPlayerIsWhite = getCookie("chessPlayerIsWhite");
|
||||||
|
|
||||||
|
if (savedGameId && savedPlayerId) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/chess/${savedGameId}`);
|
||||||
|
if (response.ok) {
|
||||||
|
console.log("🧠 Rejoining saved game...");
|
||||||
|
currentGameId = savedGameId;
|
||||||
|
currentPlayerId = savedPlayerId;
|
||||||
|
currentPlayerIsWhite = (savedPlayerIsWhite === "true");
|
||||||
|
|
||||||
|
await setupSignalRConnection(); // use your existing SignalR connect logic
|
||||||
|
const gameData = await response.json();
|
||||||
|
renderPieces(gameData.pieces);
|
||||||
|
} else {
|
||||||
|
console.warn("Saved game not found or expired.");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to rejoin saved game:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user