fix(chess): prevent duplicate players and fix move detection
Some checks failed
Deploy to Production / test (push) Failing after 38s
Some checks failed
Deploy to Production / test (push) Failing after 38s
- Prevent same player from joining as both white and black - Add validation to reject duplicate players in RoomManager - Fix spectator status not resetting when joining as player - Use ref to track latest chess state in ChessBoard for accurate move validation
This commit is contained in:
@@ -46,7 +46,8 @@ export class RoomManager {
|
|||||||
|
|
||||||
const plugin = gameRegistry.get(room.gameSlug)!;
|
const plugin = gameRegistry.get(room.gameSlug)!;
|
||||||
if (room.players.length >= plugin.maxPlayers && role !== "admin") return { ok: false, error: "Room is full" };
|
if (room.players.length >= plugin.maxPlayers && role !== "admin") return { ok: false, error: "Room is full" };
|
||||||
if (room.players.includes(playerId) && role !== "admin") return { ok: true, started: room.status === "playing" };
|
if (room.players.includes(playerId) && role !== "admin") return { ok: true, started: room.status === "waiting" };
|
||||||
|
if (room.players.includes(playerId) && role === "admin") return { ok: false, error: "Already a player in this game" };
|
||||||
|
|
||||||
if (!room.players.includes(playerId) || role === "admin") {
|
if (!room.players.includes(playerId) || role === "admin") {
|
||||||
room.players.push(playerId);
|
room.players.push(playerId);
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ export function ChessBoard({ state, myPlayerId, isSpectator, onAction, players }
|
|||||||
const [promotionTo, setPromotionTo] = useState<string | null>(null);
|
const [promotionTo, setPromotionTo] = useState<string | null>(null);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const [boardWidth, setBoardWidth] = useState(400);
|
const [boardWidth, setBoardWidth] = useState(400);
|
||||||
|
|
||||||
|
// Track latest state in ref to avoid stale closures
|
||||||
|
const chessRef = useRef(chess);
|
||||||
|
useEffect(() => {
|
||||||
|
chessRef.current = chess;
|
||||||
|
}, [chess]);
|
||||||
|
|
||||||
// Responsive board sizing
|
// Responsive board sizing
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -56,7 +62,7 @@ export function ChessBoard({ state, myPlayerId, isSpectator, onAction, players }
|
|||||||
function onDrop(sourceSquare: string, targetSquare: string): boolean {
|
function onDrop(sourceSquare: string, targetSquare: string): boolean {
|
||||||
if (isSpectator || !isMyTurn) return false;
|
if (isSpectator || !isMyTurn) return false;
|
||||||
|
|
||||||
const testGame = new Chess(chess.fen);
|
const testGame = new Chess(chessRef.current.fen);
|
||||||
|
|
||||||
// Check if this is a promotion move
|
// Check if this is a promotion move
|
||||||
const piece = testGame.get(sourceSquare as any);
|
const piece = testGame.get(sourceSquare as any);
|
||||||
|
|||||||
@@ -56,13 +56,16 @@ export function useGameRoom(roomId: string, userId: string, role?: string) {
|
|||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
spectators: [...prev.spectators.filter(s => s.discordId !== msg.player.discordId), msg.player],
|
spectators: [...prev.spectators.filter(s => s.discordId !== msg.player.discordId), msg.player],
|
||||||
isSpectator: isMe ? true : prev.isSpectator,
|
isSpectator: isMe || prev.isSpectator,
|
||||||
roomStatus: prev.roomStatus === "connecting" ? "waiting" : prev.roomStatus,
|
roomStatus: prev.roomStatus === "connecting" ? "waiting" : prev.roomStatus,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isMe = msg.player.discordId === userId;
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
players: [...prev.players.filter(p => p.discordId !== msg.player.discordId), msg.player],
|
players: [...prev.players.filter(p => p.discordId !== msg.player.discordId), msg.player],
|
||||||
|
isSpectator: isMe ? false : prev.isSpectator,
|
||||||
roomStatus: prev.roomStatus === "connecting" ? "waiting" : prev.roomStatus,
|
roomStatus: prev.roomStatus === "connecting" ? "waiting" : prev.roomStatus,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,9 +23,14 @@ export const chessPlugin: GamePlugin<ChessState, ChessAction> = {
|
|||||||
|
|
||||||
createInitialState(players: string[]): ChessState {
|
createInitialState(players: string[]): ChessState {
|
||||||
const game = new Chess();
|
const game = new Chess();
|
||||||
|
|
||||||
|
if (players[0] === players[1]) {
|
||||||
|
throw new Error("Cannot create chess game with same player for both sides");
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fen: game.fen(),
|
fen: game.fen(),
|
||||||
players: { white: players[0], black: players[1] },
|
players: { white: players[0]!, black: players[1]! },
|
||||||
moveHistory: [],
|
moveHistory: [],
|
||||||
status: "playing",
|
status: "playing",
|
||||||
winner: null,
|
winner: null,
|
||||||
|
|||||||
Reference in New Issue
Block a user