From e984172918531e36da1993b0f9ffbcd96f4e7545 Mon Sep 17 00:00:00 2001 From: sepia Date: Tue, 15 Jul 2025 18:10:22 -0500 Subject: [PATCH] Add dist/ to .gitignore, and prevent new games from having a broken gameId --- .gitignore | 4 +- dist/bundle.js | 307 ------------------------------------------- dist/client-entry.js | 305 ------------------------------------------ src/client-entry.ts | 1 - 4 files changed, 3 insertions(+), 614 deletions(-) delete mode 100644 dist/bundle.js delete mode 100644 dist/client-entry.js diff --git a/.gitignore b/.gitignore index 87e5610..a50d08a 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,6 @@ yarn-error.log* **/*.tgz **/*.log package-lock.json -**/*.bun \ No newline at end of file +**/*.bun + +dist/ diff --git a/dist/bundle.js b/dist/bundle.js deleted file mode 100644 index 4cdf4ea..0000000 --- a/dist/bundle.js +++ /dev/null @@ -1,307 +0,0 @@ -// src/game-client/WebSocketClient.ts -class WebSocketClient { - ws = null; - url; - messageQueue = []; - isConnected = false; - reconnectCount = 0; - options; - manualClose = false; - onMessageHandler = () => {}; - onOpenHandler = () => {}; - onCloseHandler = () => {}; - onErrorHandler = () => {}; - constructor(url, options) { - this.url = url; - this.options = { - reconnectAttempts: 5, - reconnectInterval: 3000, - ...options, - }; - } - connect() { - this.manualClose = false; - this.ws = new WebSocket(this.url); - this.ws.onopen = this.handleOpen.bind(this); - this.ws.onmessage = this.handleMessage.bind(this); - this.ws.onclose = this.handleClose.bind(this); - this.ws.onerror = this.handleError.bind(this); - } - send(message) { - if (this.isConnected && this.ws) { - this.ws.send(message); - } else { - this.messageQueue.push(message); - } - } - close() { - this.manualClose = true; - if (this.ws) { - this.ws.close(); - } - } - onMessage(handler) { - this.onMessageHandler = handler; - } - onOpen(handler) { - this.onOpenHandler = handler; - } - onClose(handler) { - this.onCloseHandler = handler; - } - onError(handler) { - this.onErrorHandler = handler; - } - handleOpen() { - this.isConnected = true; - this.reconnectCount = 0; - this.onOpenHandler(); - this.flushMessageQueue(); - } - handleMessage(event) { - this.onMessageHandler(event.data); - } - handleClose(event) { - this.isConnected = false; - this.onCloseHandler(event.code, event.reason); - if ( - !this.manualClose && - this.reconnectCount < this.options.reconnectAttempts - ) { - this.reconnectCount++; - setTimeout(() => this.connect(), this.options.reconnectInterval); - } - } - handleError(event) { - this.onErrorHandler(event); - } - flushMessageQueue() { - while (this.messageQueue.length > 0 && this.isConnected && this.ws) { - const message = this.messageQueue.shift(); - if (message) { - this.ws.send(message); - } - } - } -} - -// src/game-client/GameStateManager.ts -class GameStateManager { - gameState; - stateHistory; - constructor() { - this.gameState = this.getDefaultGameState(); - this.stateHistory = []; - } - getDefaultGameState() { - const emptyBoard = Array(15) - .fill(null) - .map(() => Array(15).fill(null)); - return { - id: '', - board: emptyBoard, - currentPlayer: 'black', - status: 'waiting', - winner: null, - players: {}, - }; - } - getGameState() { - return this.gameState; - } - updateGameState(newState) { - this.stateHistory.push(JSON.parse(JSON.stringify(this.gameState))); - this.gameState = newState; - } - rollbackGameState() { - if (this.stateHistory.length > 0) { - this.gameState = this.stateHistory.pop(); - } else { - console.warn('No previous state to rollback to.'); - } - } -} - -// src/game-client/GameBoardUI.ts -class GameBoardUI { - boardElement; - cells = []; - onCellClickCallback = null; - isInteractionEnabled = true; - constructor(boardElement) { - this.boardElement = boardElement; - this.initializeBoard(); - } - initializeBoard() { - this.boardElement.innerHTML = ''; - this.boardElement.style.display = 'grid'; - this.boardElement.style.gridTemplateColumns = 'repeat(15, 1fr)'; - this.boardElement.style.width = '450px'; - this.boardElement.style.height = '450px'; - this.boardElement.style.border = '1px solid black'; - for (let row = 0; row < 15; row++) { - this.cells[row] = []; - for (let col = 0; col < 15; col++) { - const cell = document.createElement('div'); - cell.classList.add('board-cell'); - cell.style.width = '30px'; - cell.style.height = '30px'; - cell.style.border = '1px solid #ccc'; - cell.style.boxSizing = 'border-box'; - cell.style.display = 'flex'; - cell.style.justifyContent = 'center'; - cell.style.alignItems = 'center'; - cell.dataset.row = row.toString(); - cell.dataset.col = col.toString(); - cell.addEventListener('click', () => this.handleCellClick(row, col)); - this.boardElement.appendChild(cell); - this.cells[row][col] = cell; - } - } - } - updateBoard(gameState) { - const board = gameState.board; - const lastMove = { row: -1, col: -1 }; - for (let row = 0; row < 15; row++) { - for (let col = 0; col < 15; col++) { - const cell = this.cells[row][col]; - cell.innerHTML = ''; - const stone = board[row][col]; - if (stone) { - const stoneElement = document.createElement('div'); - stoneElement.style.width = '24px'; - stoneElement.style.height = '24px'; - stoneElement.style.borderRadius = '50%'; - stoneElement.style.backgroundColor = - stone === 'black' ? 'black' : 'white'; - stoneElement.style.border = '1px solid #333'; - cell.appendChild(stoneElement); - } - cell.classList.remove('last-move'); - } - } - this.isInteractionEnabled = - gameState.status === 'playing' && gameState.currentPlayer === 'black'; - this.boardElement.style.pointerEvents = this.isInteractionEnabled - ? 'auto' - : 'none'; - this.boardElement.style.opacity = this.isInteractionEnabled ? '1' : '0.7'; - console.log( - `Current Player: ${gameState.currentPlayer}, Status: ${gameState.status}`, - ); - } - setOnCellClick(callback) { - this.onCellClickCallback = callback; - } - handleCellClick(row, col) { - if (this.isInteractionEnabled && this.onCellClickCallback) { - this.onCellClickCallback(row, col); - } - } -} - -// src/client-entry.ts -console.log('Gomoku client entry point loaded.'); -var WS_URL = 'ws://localhost:3000/ws'; -var gameStateManager = new GameStateManager(); -var wsClient = new WebSocketClient(WS_URL); -var gameBoardElement = document.getElementById('game-board'); -console.log('gameBoardElement: ', gameBoardElement); -var messagesElement = document.getElementById('messages'); -var playerInfoElement = document.getElementById('player-info'); -if (!gameBoardElement || !messagesElement || !playerInfoElement) { - console.error( - 'Missing essential DOM elements (game-board, messages, or player-info)', - ); - throw new Error( - 'Missing essential DOM elements (game-board, messages, or player-info)', - ); -} -var gameBoardUI = new GameBoardUI(gameBoardElement); -console.log('GameBoardUI initialized.', gameBoardUI); -wsClient.onMessage((message) => { - try { - const msg = JSON.parse(message); - console.log('Parsed message:', msg); - switch (msg.type) { - case 'game_state': - gameStateManager.updateGameState(msg.state); - gameBoardUI.updateBoard(gameStateManager.getGameState()); - console.log('Game state updated: ', gameStateManager.getGameState()); - break; - case 'move_result': - if (msg.success) { - console.log('Move successful!'); - } else { - console.error(`Move failed: ${msg.error}`); - gameStateManager.rollbackGameState(); - gameBoardUI.updateBoard(gameStateManager.getGameState()); - } - break; - case 'player_joined': - console.log(`${msg.playerId} joined the game.`); - break; - case 'player_disconnected': - console.log(`${msg.playerId} disconnected.`); - break; - case 'ping': - break; - default: - console.log(`Unknown message type: ${msg.type}`); - } - } catch (e) { - console.error( - 'Error parsing WebSocket message:', - e, - 'Message was:', - message, - ); - } -}); -gameBoardUI.setOnCellClick((row, col) => { - const moveMessage = { - type: 'make_move', - row, - col, - }; - console.log('Sending move:', moveMessage); - wsClient.send(JSON.stringify(moveMessage)); - const currentGameState = gameStateManager.getGameState(); - const nextPlayer = - currentGameState.currentPlayer === 'black' ? 'white' : 'black'; - const newBoard = currentGameState.board.map((rowArr) => [...rowArr]); - newBoard[row][col] = currentGameState.currentPlayer; - const optimisticState = { - ...currentGameState, - board: newBoard, - currentPlayer: nextPlayer, - }; - gameStateManager.updateGameState(optimisticState); - gameBoardUI.updateBoard(gameStateManager.getGameState()); -}); -wsClient.onOpen(() => { - console.log('Connected to game server.'); - const playerId = `player-${Math.random().toString(36).substring(2, 9)}`; - const joinMessage = { - type: 'join_game', - gameId: 'some-game-id', - playerId, - }; - wsClient.send(JSON.stringify(joinMessage)); - if (playerInfoElement) { - playerInfoElement.textContent = `You are: ${playerId} (Waiting for game state...)`; - } -}); -wsClient.onClose(() => { - console.log('Disconnected from game server. Attempting to reconnect...'); -}); -wsClient.onError((error) => { - console.error( - `WebSocket error: ${error instanceof ErrorEvent ? error.message : String(error)}`, - ); -}); -wsClient.connect(); -gameBoardUI.updateBoard(gameStateManager.getGameState()); -if (playerInfoElement) { - playerInfoElement.textContent = `You are: (Connecting...)`; -} diff --git a/dist/client-entry.js b/dist/client-entry.js deleted file mode 100644 index 3345011..0000000 --- a/dist/client-entry.js +++ /dev/null @@ -1,305 +0,0 @@ -// src/game-client/WebSocketClient.ts -class WebSocketClient { - ws = null; - url; - messageQueue = []; - isConnected = false; - reconnectCount = 0; - options; - manualClose = false; - onMessageHandler = () => {}; - onOpenHandler = () => {}; - onCloseHandler = () => {}; - onErrorHandler = () => {}; - constructor(url, options) { - this.url = url; - this.options = { - reconnectAttempts: 5, - reconnectInterval: 3000, - ...options, - }; - } - connect() { - this.manualClose = false; - this.ws = new WebSocket(this.url); - this.ws.onopen = this.handleOpen.bind(this); - this.ws.onmessage = this.handleMessage.bind(this); - this.ws.onclose = this.handleClose.bind(this); - this.ws.onerror = this.handleError.bind(this); - } - send(message) { - if (this.isConnected && this.ws) { - this.ws.send(message); - } else { - this.messageQueue.push(message); - } - } - close() { - this.manualClose = true; - if (this.ws) { - this.ws.close(); - } - } - onMessage(handler) { - this.onMessageHandler = handler; - } - onOpen(handler) { - this.onOpenHandler = handler; - } - onClose(handler) { - this.onCloseHandler = handler; - } - onError(handler) { - this.onErrorHandler = handler; - } - handleOpen() { - this.isConnected = true; - this.reconnectCount = 0; - this.onOpenHandler(); - this.flushMessageQueue(); - } - handleMessage(event) { - this.onMessageHandler(event.data); - } - handleClose(event) { - this.isConnected = false; - this.onCloseHandler(event.code, event.reason); - if ( - !this.manualClose && - this.reconnectCount < this.options.reconnectAttempts - ) { - this.reconnectCount++; - setTimeout(() => this.connect(), this.options.reconnectInterval); - } - } - handleError(event) { - this.onErrorHandler(event); - } - flushMessageQueue() { - while (this.messageQueue.length > 0 && this.isConnected && this.ws) { - const message = this.messageQueue.shift(); - if (message) { - this.ws.send(message); - } - } - } -} - -// src/game-client/GameStateManager.ts -class GameStateManager { - gameState; - stateHistory; - constructor() { - this.gameState = this.getDefaultGameState(); - this.stateHistory = []; - } - getDefaultGameState() { - const emptyBoard = Array(15) - .fill(null) - .map(() => Array(15).fill(null)); - return { - id: '', - board: emptyBoard, - currentPlayer: 'black', - status: 'waiting', - winner: null, - players: {}, - }; - } - getGameState() { - return this.gameState; - } - updateGameState(newState) { - this.stateHistory.push(JSON.parse(JSON.stringify(this.gameState))); - this.gameState = newState; - } - rollbackGameState() { - if (this.stateHistory.length > 0) { - this.gameState = this.stateHistory.pop(); - } else { - console.warn('No previous state to rollback to.'); - } - } -} - -// src/game-client/GameBoardUI.ts -class GameBoardUI { - boardElement; - cells = []; - onCellClickCallback = null; - isInteractionEnabled = true; - constructor(boardElement) { - this.boardElement = boardElement; - this.initializeBoard(); - } - initializeBoard() { - this.boardElement.innerHTML = ''; - this.boardElement.style.display = 'grid'; - this.boardElement.style.gridTemplateColumns = 'repeat(15, 1fr)'; - this.boardElement.style.width = '450px'; - this.boardElement.style.height = '450px'; - this.boardElement.style.border = '1px solid black'; - for (let row = 0; row < 15; row++) { - this.cells[row] = []; - for (let col = 0; col < 15; col++) { - const cell = document.createElement('div'); - cell.classList.add('board-cell'); - cell.style.width = '30px'; - cell.style.height = '30px'; - cell.style.border = '1px solid #ccc'; - cell.style.boxSizing = 'border-box'; - cell.style.display = 'flex'; - cell.style.justifyContent = 'center'; - cell.style.alignItems = 'center'; - cell.dataset.row = row.toString(); - cell.dataset.col = col.toString(); - cell.addEventListener('click', () => this.handleCellClick(row, col)); - this.boardElement.appendChild(cell); - this.cells[row][col] = cell; - } - } - } - updateBoard(gameState) { - const board = gameState.board; - const lastMove = { row: -1, col: -1 }; - for (let row = 0; row < 15; row++) { - for (let col = 0; col < 15; col++) { - const cell = this.cells[row][col]; - cell.innerHTML = ''; - const stone = board[row][col]; - if (stone) { - const stoneElement = document.createElement('div'); - stoneElement.style.width = '24px'; - stoneElement.style.height = '24px'; - stoneElement.style.borderRadius = '50%'; - stoneElement.style.backgroundColor = - stone === 'black' ? 'black' : 'white'; - stoneElement.style.border = '1px solid #333'; - cell.appendChild(stoneElement); - } - cell.classList.remove('last-move'); - } - } - this.isInteractionEnabled = - gameState.status === 'playing' && gameState.currentPlayer === 'black'; - this.boardElement.style.pointerEvents = this.isInteractionEnabled - ? 'auto' - : 'none'; - this.boardElement.style.opacity = this.isInteractionEnabled ? '1' : '0.7'; - console.log( - `Current Player: ${gameState.currentPlayer}, Status: ${gameState.status}`, - ); - } - setOnCellClick(callback) { - this.onCellClickCallback = callback; - } - handleCellClick(row, col) { - if (this.isInteractionEnabled && this.onCellClickCallback) { - this.onCellClickCallback(row, col); - } - } -} - -// src/client-entry.ts -console.log('Gomoku client entry point loaded.'); -var WS_URL = process.env.WS_URL || 'ws://localhost:3000/ws'; -var gameStateManager = new GameStateManager(); -var wsClient = new WebSocketClient(WS_URL); -var gameBoardElement = document.getElementById('game-board'); -console.log('gameBoardElement: ', gameBoardElement); -var messagesElement = document.getElementById('messages'); -var playerInfoElement = document.getElementById('player-info'); -if (!gameBoardElement || !messagesElement || !playerInfoElement) { - console.error( - 'Missing essential DOM elements (game-board, messages, or player-info)', - ); - throw new Error( - 'Missing essential DOM elements (game-board, messages, or player-info)', - ); -} -var gameBoardUI = new GameBoardUI(gameBoardElement); -console.log('GameBoardUI initialized.', gameBoardUI); -wsClient.onMessage((message) => { - try { - const msg = JSON.parse(message); - console.log('Parsed message:', msg); - switch (msg.type) { - case 'game_state': - gameStateManager.updateGameState(msg.state); - gameBoardUI.updateBoard(gameStateManager.getGameState()); - console.log('Game state updated: ', gameStateManager.getGameState()); - break; - case 'move_result': - if (msg.success) { - console.log('Move successful!'); - } else { - console.error(`Move failed: ${msg.error}`); - gameStateManager.rollbackGameState(); - gameBoardUI.updateBoard(gameStateManager.getGameState()); - } - break; - case 'player_joined': - console.log(`${msg.playerId} joined the game.`); - break; - case 'player_disconnected': - console.log(`${msg.playerId} disconnected.`); - break; - case 'ping': - break; - default: - console.log(`Unknown message type: ${msg.type}`); - } - } catch (e) { - console.error( - 'Error parsing WebSocket message:', - e, - 'Message was:', - message, - ); - } -}); -gameBoardUI.setOnCellClick((row, col) => { - const moveMessage = { - type: 'make_move', - row, - col, - }; - console.log('Sending move:', moveMessage); - wsClient.send(JSON.stringify(moveMessage)); - const currentGameState = gameStateManager.getGameState(); - const nextPlayer = - currentGameState.currentPlayer === 'black' ? 'white' : 'black'; - const newBoard = currentGameState.board.map((rowArr) => [...rowArr]); - newBoard[row][col] = currentGameState.currentPlayer; - const optimisticState = { - ...currentGameState, - board: newBoard, - currentPlayer: nextPlayer, - }; - gameStateManager.updateGameState(optimisticState); - gameBoardUI.updateBoard(gameStateManager.getGameState()); -}); -wsClient.onOpen(() => { - console.log('Connected to game server.'); - const playerId = `player-${Math.random().toString(36).substring(2, 9)}`; - const joinMessage = { - type: 'join_game', - gameId: 'some-game-id', - playerId, - }; - wsClient.send(JSON.stringify(joinMessage)); - if (playerInfoElement) { - playerInfoElement.textContent = `You are: ${playerId} (Waiting for game state...)`; - } -}); -wsClient.onClose(() => { - console.log('Disconnected from game server. Attempting to reconnect...'); -}); -wsClient.onError((error) => { - console.error(`WebSocket error: ${error.message}`); -}); -wsClient.connect(); -gameBoardUI.updateBoard(gameStateManager.getGameState()); -if (playerInfoElement) { - playerInfoElement.textContent = `You are: (Connecting...)`; -} diff --git a/src/client-entry.ts b/src/client-entry.ts index 5504521..d0aaff9 100644 --- a/src/client-entry.ts +++ b/src/client-entry.ts @@ -109,7 +109,6 @@ wsClient.onOpen(() => { const playerId = `player-${Math.random().toString(36).substring(2, 9)}`; const joinMessage = { type: 'join_game', - gameId: 'some-game-id', playerId: playerId, }; wsClient.send(JSON.stringify(joinMessage));