From a96db28611ffeec0e41bf89fba0c6fdc6107e991 Mon Sep 17 00:00:00 2001 From: Henry Liao Date: Tue, 23 Dec 2025 20:05:14 -0800 Subject: [PATCH 1/9] add changes back in for python connection --- ipc/pythonHandlers.js | 4 +-- preload.js | 34 +++++++++--------- src/components/MatchPlayer.js | 66 +++++++++++++++++++++++++++++------ 3 files changed, 76 insertions(+), 28 deletions(-) diff --git a/ipc/pythonHandlers.js b/ipc/pythonHandlers.js index 6712c37..52bcffc 100644 --- a/ipc/pythonHandlers.js +++ b/ipc/pythonHandlers.js @@ -197,7 +197,7 @@ function setupPythonScriptHandlers(store, enginePath) { if (code !== 0) { reject(new Error(`Python script error: ${scriptError}`)); } else { - resolve(tcpResult); + resolve(scriptOutput); } }); @@ -219,7 +219,7 @@ function setupPythonScriptHandlers(store, enginePath) { console.log('TCP data received'); }, (jsonData) => { // onMessage - event.sender.send('stream-tcp-message', jsonData); + event.sender.send('stream-tcp-json', jsonData); console.log('TCP data parsed'); tcpResult = jsonData; }, diff --git a/preload.js b/preload.js index 8f7ab9c..4397241 100644 --- a/preload.js +++ b/preload.js @@ -26,6 +26,24 @@ contextBridge.exposeInMainWorld('electron', { sendTCPInterrupt: () => ipcRenderer.invoke('tcp-send-interrupt'), disconnectTCP: () => ipcRenderer.invoke('tcp-disconnect'), + onTcpData: (callback) => { + const handler = (_, data) => callback(data); + ipcRenderer.on('stream-tcp-data', handler); + return () => ipcRenderer.removeListener('stream-tcp-data', handler); + }, + + onTcpJson: (callback) => { + const handler = (_, data) => callback(data); + ipcRenderer.on('stream-tcp-message', handler); + return () => ipcRenderer.removeListener('stream-tcp-message', handler); + }, + + onTcpStatus: (callback) => { + const handler = (_, status) => callback(status); + ipcRenderer.on('stream-tcp-status', handler); + return () => ipcRenderer.removeListener('stream-tcp-status', handler); + }, + onStreamOutput: (callback) => { const handler = (_, chunk) => callback(chunk); ipcRenderer.on('stream-output', handler); @@ -49,20 +67,4 @@ contextBridge.exposeInMainWorld('electron', { ipcRenderer.on('stream-error-full', handler); return () => ipcRenderer.removeListener('stream-error-full', handler); }, - - onTcpData: (callback) => { - const handler = (_, data) => callback(data); - ipcRenderer.on('stream-tcp-data', handler); - return () => ipcRenderer.removeListener('stream-tcp-data', handler); - }, - onTcpJson: (callback) => { - const handler = (_, data) => callback(data); - ipcRenderer.on('stream-tcp-message', handler); - return () => ipcRenderer.removeListener('stream-tcp-message', handler); - }, - onTcpStatus: (callback) => { - const handler = (_, status) => callback(status); - ipcRenderer.on('stream-tcp-status', handler); - return () => ipcRenderer.removeListener('stream-tcp-status', handler); - }, }); \ No newline at end of file diff --git a/src/components/MatchPlayer.js b/src/components/MatchPlayer.js index 4bb3025..acd9479 100644 --- a/src/components/MatchPlayer.js +++ b/src/components/MatchPlayer.js @@ -10,8 +10,6 @@ import GameOutputs from './GameOutputs'; import PlayerStats from './PlayerStats'; import { Button } from '@/components/ui/button'; import { Bot } from 'lucide-react'; -import { match } from 'assert'; - const path = require('path'); @@ -73,15 +71,43 @@ function MatchPlayer() { setBot2File(bot2File); setShouldPlayMatch(true); } - - const tcpJSONCallback = () => { + const handleStdOutData = (chunk) => { + console.log("stdout"); + console.log(chunk); + } + + const handleStdOutDataFull = (fullOutput) => { + console.log("stdoutfull"); + console.log(fullOutput); + } + + const handleErrOutData = (chunk) => { + console.log("errout"); + console.log(chunk); + } + + const handleErrOutDataFull = (fullOutput) => { + console.log("errout"); + console.log(fullOutput); + } + + const handleTcpData = (data) => { + console.log("tcpdata"); + console.log(data); + } + + const handleTcpMessage = (json) => { + console.log("tcpmessage"); + console.log(json); } - const tcpStatusCallback = () => { - + const handleTcpStatus = (status) => { + console.log("tcpstatus"); + console.log(status); } + useEffect(() => { let interval; if (isPlaying) { @@ -121,14 +147,34 @@ function MatchPlayer() { '--output_dir', `"${resultFilePath}"` ]; - - const result = await window.electron.runPythonScript(scriptArgs); + + // register handlers + // Register handlers and get cleanup functions + const cleanupTcpData = window.electron.onTcpData(handleTcpData); + const cleanupTcpJson = window.electron.onTcpJson(handleTcpMessage); + const cleanupTcpStatus = window.electron.onTcpStatus(handleTcpStatus); + const cleanupOutput = window.electron.onStreamOutput(handleStdOutData); + const cleanupOutputFull = window.electron.onStreamOutputFull(handleStdOutDataFull); + const cleanupError = window.electron.onStreamError(handleErrOutData); + const cleanupErrorFull = window.electron.onStreamErrorFull(handleErrOutDataFull); + + try { + setEngineOutput(await window.electron.runPythonScript(scriptArgs)); + } finally { + cleanupTcpData(); + cleanupTcpJson(); + cleanupTcpStatus(); + cleanupOutput(); + cleanupOutputFull(); + cleanupError(); + cleanupErrorFull(); + } try { const resultFileContent = await window.electron.readFile(resultFilePath); const matchLog = JSON.parse(resultFileContent); await window.electron.copyMatch(resultFilePath, num); - await window.electron.storeSet("numMatches", (num + 1) % 100000) + await window.electron.storeSet("numMatches", (num + 1) % 1000000) const m = await processData(matchLog); setMatchStates(m.match_states); @@ -157,7 +203,7 @@ function MatchPlayer() {
- Turn #:{currentMatchStateIndex} + Turn #:{currentMatchStateIndex}
From d66b6d9d7cba77c1bcd7d947364a3bbe0a5db14a Mon Sep 17 00:00:00 2001 From: Henry Liao Date: Tue, 23 Dec 2025 23:48:15 -0800 Subject: [PATCH 2/9] fix streaming data --- ipc/pythonHandlers.js | 66 +++++++++++++++++++++++++---------- src/components/MatchPlayer.js | 11 +++--- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/ipc/pythonHandlers.js b/ipc/pythonHandlers.js index 52bcffc..c8ca301 100644 --- a/ipc/pythonHandlers.js +++ b/ipc/pythonHandlers.js @@ -45,7 +45,6 @@ function closePython(){ } } - class TcpClientManager { constructor() { this.client = null; @@ -54,12 +53,36 @@ class TcpClientManager { this.messageBuffer = ''; // For handling partial messages } - connect(host, port, onData, onMessage, onComplete, onError, onClose) { + async connect(host, port, onData, onMessage, onComplete, onError, onClose, maxRetries = 20, initialDelay = 100) { + for (let attempt = 0; attempt < maxRetries; attempt++) { + try { + await this._attemptConnect(host, port, onData, onMessage, onComplete, onError, onClose); + console.log(`Successfully connected to TCP server on port ${port}`); + return; // Success! + } catch (error) { + if (attempt === maxRetries - 1) { + throw new Error(`Failed to connect after ${maxRetries} attempts: ${error.message}`); + } + + const delay = Math.min(initialDelay * Math.pow(1.5, attempt), 2000); + console.log(`Connection attempt ${attempt + 1} failed, retrying in ${delay}ms...`); + await new Promise(resolve => setTimeout(resolve, delay)); + } + } + } + + _attemptConnect(host, port, onData, onMessage, onComplete, onError, onClose) { return new Promise((resolve, reject) => { - // crate tcp client + // Create tcp client this.client = new net.Socket(); - //start registering handlers + // Set connection timeout + const connectionTimeout = setTimeout(() => { + this.client.destroy(); + reject(new Error('Connection timeout')); + }, 2000); + + // Start registering handlers this.client.on('data', (data) => { const chunk = data.toString(); this.dataBuffer += chunk; @@ -79,7 +102,7 @@ class TcpClientManager { onMessage(jsonMessage); } catch (e) { console.warn('Received non-JSON message:', message); - onMessage({ type:"unparsed" , raw:message }); + onMessage({ type: "unparsed", raw: message }); } } } @@ -90,45 +113,46 @@ class TcpClientManager { this.connected = false; if (onComplete) { - onComplete() - }; + onComplete(); + } }); this.client.on('close', () => { console.log('TCP connection closed'); this.connected = false; if (onClose) { - onClose() - }; + onClose(); + } }); this.client.on('error', (err) => { + clearTimeout(connectionTimeout); console.error('TCP client error:', err); - if (onError) { + + // Only call onError for errors after successful connection + if (this.connected && onError) { onError(err); } + this.connected = false; - reject(err); }); // Actually connect this.client.connect(port, host, () => { + clearTimeout(connectionTimeout); console.log(`TCP client connected to ${host}:${port}`); this.connected = true; resolve(); }); - - }); } - disconnect(){ + disconnect() { if (this.client && this.connected) { - this.client.end() + this.client.end(); } - this.connected = false - + this.connected = false; } sendInterrupt() { @@ -141,6 +165,8 @@ class TcpClientManager { } } + + function setupPythonScriptHandlers(store, enginePath) { ipcMain.handle('run-python-script', async (event, scriptArgs) => { @@ -163,7 +189,11 @@ function setupPythonScriptHandlers(store, enginePath) { // Create new TCP client manager tcpClientManager = new TcpClientManager(); - pythonProcess = spawn(`"${pythonpath} ${gameScript}"`, [...scriptArgs], { + + console.log("running") + console.log(`"${pythonpath} ${gameScript} ${[...scriptArgs]}"`) + + pythonProcess = spawn(`"${pythonpath}" "${gameScript}"`, [...scriptArgs], { cwd: enginePath, shell: true }); diff --git a/src/components/MatchPlayer.js b/src/components/MatchPlayer.js index acd9479..a5f7143 100644 --- a/src/components/MatchPlayer.js +++ b/src/components/MatchPlayer.js @@ -46,11 +46,12 @@ function MatchPlayer() { const handleSetMap = (value) => { setMap(value) + console.log(value) - let match_states = new Array(1).fill(null); - match_states[0] = getMap(value) - setMatchStates(match_states); - setCurrentMatchStateIndex(0); + // let match_states = new Array(1).fill(null); + // match_states[0] = getMap(value) + // setMatchStates(match_states); + // setCurrentMatchStateIndex(0); setMatchInfo(null) } @@ -88,7 +89,7 @@ function MatchPlayer() { } const handleErrOutDataFull = (fullOutput) => { - console.log("errout"); + console.log("erroutfull"); console.log(fullOutput); } From 1a42d5287716e487cd7ff1ad348f4ff071578976 Mon Sep 17 00:00:00 2001 From: Henry Liao Date: Wed, 24 Dec 2025 14:30:10 -0800 Subject: [PATCH 3/9] begin map builder refactor --- src/components/CellSelector.js | 2 +- src/components/MapBuilder.js | 179 ++++++++---------- .../{MapVis.js => MapBuilderVis.js} | 31 ++- src/components/MapSettings.js | 28 +-- 4 files changed, 108 insertions(+), 132 deletions(-) rename src/components/{MapVis.js => MapBuilderVis.js} (88%) diff --git a/src/components/CellSelector.js b/src/components/CellSelector.js index 7dcccce..688ca5e 100644 --- a/src/components/CellSelector.js +++ b/src/components/CellSelector.js @@ -1,7 +1,7 @@ import { useState } from 'react' export default function CellSelector({handleCellChange}) { - const [ids, setIds] = useState(["Space", "Wall", "Snake A", "Snake B", "Portal 1", "Portal 2"]); + const [ids, setIds] = useState(["Space", "Wall", "Player 1", "Player 2", "Hill"]); return ( diff --git a/src/components/MapBuilder.js b/src/components/MapBuilder.js index 49b9764..960a524 100644 --- a/src/components/MapBuilder.js +++ b/src/components/MapBuilder.js @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import MapSettings from './MapSettings'; import ShowSpawn from './ShowSpawn'; -import MapVis from './MapVis'; +import MapBuilderVis from './MapBuilderVis'; import CellSelector from './CellSelector' import SymmetrySelector from './SymmetrySelector' import { Button } from '@/components/ui/button'; @@ -12,43 +12,38 @@ const GridValues = { EMPTY: 0, WALL: 1, APPLE: 2, - SNAKE_A_HEAD: 3, - SNAKE_A_BODY: 4, - SNAKE_B_HEAD: 5, - SNAKE_B_BODY: 6, - START_PORTAL: 7, - END_PORTAL: 8 + PLAYER_1: 3, + PLAYER_2: 5, + HILL: 7, } export default function MapBuilder() { - const [showSnakeStart, setShowSnakeStart] = useState(true); + const [showSpawn, setShowSpawn] = useState(true); const [aSpawn, setASpawn] = useState([-1, -1]); const [bSpawn, setBSpawn] = useState([-1, -1]); const [mapHeight, setMapHeight] = useState(20); const [mapWidth, setMapWidth] = useState(20); const [walls, setWalls] = useState(null); // Array to store wall positions, initially empty - const [portals, setPortals] = useState(null); // Array to store wall positions, initially empty const [cellType, setCellType] = useState(GridValues.EMPTY); - const [appleRate, setAppleRate] = useState(50); - const [appleNum, setAppleNum] = useState(1); + const [powerupRate, setPowerupRate] = useState(50); + const [powerupNum, setPowerupNum] = useState(1); const [symmetry, setSymmetry] = useState("Vertical"); const [canvasRerender, setCanvasRerender] = useState(false) - const [startSize, setStartSize] = useState(5) const [mapName, setMapName] = useState("") - const [startPortal, setStartPortal] = useState([-1, -1]) - const [endPortal, setEndPortal] = useState([-1, -1]) + const [hillGrid, setHillGrid] = useState(null) // Array to store wall positions, initially empty + const [hillID, setHillID] = useState(1) + const { toast } = useToast(); const min_map = 1; const max_map = 64; - const min_apple_num = 1; - const max_apple_num = 1000; - const min_apple_rate = 1; - const max_apple_rate = 200; - const min_start_size = 2; - const max_start_size = 1000; - const min_size = 2; + const min_powerup_num = 1; + const max_powerup_num = 1000; + const min_powerup_rate = 1; + const max_powerup_rate = 200; + const min_hill_id = 1; + const max_hill_id = 1000; const reflect = (x, y) => { if (symmetry == "Vertical") { @@ -72,26 +67,18 @@ export default function MapBuilder() { case "Space": setCellType(GridValues.EMPTY); break; - // case "Apple": - // setCellType(GridValues.APPLE); - // break; case "Wall": setCellType(GridValues.WALL); break; - case "Snake A": - - setCellType(GridValues.SNAKE_A_HEAD); + case "Player 1": + setCellType(GridValues.PLAYER_1); break; - case "Snake B": - - setCellType(GridValues.SNAKE_B_HEAD); + case "Player 2": + setCellType(GridValues.PLAYER_2); break; - case "Portal 1": - setCellType(GridValues.START_PORTAL) + case "Hill": + setCellType(GridValues.HILL) break; - case "Portal 2": - setCellType(GridValues.END_PORTAL) - break } }; @@ -101,11 +88,10 @@ export default function MapBuilder() { const f = Math.max(Math.min(max_map, value), min_map) setMapHeight(f); setWalls(new Array(f).fill().map(() => new Array(mapWidth).fill(false))); - setPortals(new Array(f).fill().map(() => new Array(mapWidth).fill(-1))); + setHillGrid(new Array(f).fill().map(() => new Array(mapWidth).fill(0))); setASpawn([-1, -1]) setBSpawn([-1, -1]) - setStartPortal([-1, -1]) - setEndPortal([-1, -1]) + setHillID(1) }; const handleWidthChange = (event) => { @@ -113,34 +99,32 @@ export default function MapBuilder() { const f = Math.max(Math.min(max_map, value), min_map) setMapWidth(f); setWalls(new Array(mapHeight).fill().map(() => new Array(f).fill(false))); - setPortals(new Array(mapHeight).fill().map(() => new Array(f).fill(-1))); + setHillGrid(new Array(mapHeight).fill().map(() => new Array(f).fill(0))); setASpawn([-1, -1]) setBSpawn([-1, -1]) - setStartPortal([-1, -1]) - setEndPortal([-1, -1]) + setHillID(1) }; - const handleAppleRateChange = (event) => { + const handlePowerupRateChange = (event) => { const value = event.target.value ? parseInt(event.target.value, 10) : 0; - setAppleRate(Math.max(Math.min(max_apple_rate, value), min_apple_rate)) + setPowerupRate(Math.max(Math.min(max_powerup_rate, value), min_powerup_rate)) }; - const handleAppleNumChange = (event) => { + const handlePowerupNumChange = (event) => { const value = event.target.value ? parseInt(event.target.value, 10) : 0; - setAppleNum(Math.max(Math.min(max_apple_num, value), min_apple_num)) + setPowerupNum(Math.max(Math.min(max_powerup_num, value), min_powerup_num)) }; - const handleShowSnakeStart = (event) => { - setShowSnakeStart(event.target.checked); + const handleShowSpawn = (event) => { + setShowSpawn(event.target.checked); setCanvasRerender(!canvasRerender) }; - const handleStartSizeChange = (event) => { + const handleHillIDChange = (event) => { const value = event.target.value ? parseInt(event.target.value, 10) : 0; - setStartSize(Math.max(Math.min(max_start_size, value), min_start_size)) + setHillID(Math.max(Math.min(max_hill_id, value), min_hill_id)) }; - const handleChangeMapName = (event) => { setMapName(event.target.value) }; @@ -149,11 +133,10 @@ export default function MapBuilder() { const value = event.target.value; setSymmetry(value); setWalls(new Array(mapHeight).fill().map(() => new Array(mapWidth).fill(false))); - setPortals(new Array(mapHeight).fill().map(() => new Array(mapWidth).fill(-1))); + setHillGrid(new Array(mapHeight).fill().map(() => new Array(mapWidth).fill(0))); setASpawn([-1, -1]) setBSpawn([-1, -1]) - setStartPortal([-1, -1]) - setEndPortal([-1, -1]) + setHillID(1) }; @@ -193,9 +176,9 @@ export default function MapBuilder() { for (let i = 0; i < mapHeight; i++) { for (let j = 0; j < mapWidth; j++) { let portalString = [] - if (portals[i][j] >= 0) { - let othery = Math.floor(portals[i][j] / mapWidth) - let otherx = portals[i][j] % mapWidth + if (hills[i][j] >= 0) { + let othery = Math.floor(hills[i][j] / mapWidth) + let otherx = hills[i][j] % mapWidth portalString.push(j) portalString.push(i) @@ -214,7 +197,7 @@ export default function MapBuilder() { parts.push(startSize.toString()); parts.push(min_size.toString()); parts.push(portalList.join("_")); - parts.push(appleRate.toString() + "," + appleNum.toString() + "," + symmetry); + parts.push(powerupRate.toString() + "," + powerupNum.toString() + "," + symmetry); let wallarr = [] @@ -269,29 +252,29 @@ export default function MapBuilder() { walls[y][x] = false; const reflection = reflect(x, y); walls[reflection[1]][reflection[0]] = false; - } else if (portals != null && portals[y][x] >= 0) { - const partnerPortal = portals[y][x] + } else if (hills != null && hills[y][x] >= 0) { + const partnerPortal = hills[y][x] const partnerPortalX = partnerPortal % mapWidth const partnerPortalY = Math.floor(partnerPortal / mapWidth) - portals[y][x] = -1; - portals[partnerPortalY][partnerPortalX] = -1; + hills[y][x] = -1; + hills[partnerPortalY][partnerPortalX] = -1; } - } else if (cellType == GridValues.SNAKE_A_HEAD) { + } else if (cellType == GridValues.PLAYER_1) { const reflection = reflect(x, y); if (reflection[0] != x || reflection[1] != y) { if (walls != null && walls[y][x]) { walls[y][x] = false; walls[reflection[1]][reflection[0]] = false; - } else if (portals != null && portals[y][x] >= 0) { - const partnerPortal = portals[y][x] + } else if (hills != null && hills[y][x] >= 0) { + const partnerPortal = hills[y][x] const partnerPortalX = partnerPortal % mapWidth const partnerPortalY = Math.floor(partnerPortal / mapWidth) - portals[y][x] = -1; - portals[partnerPortalY][partnerPortalX] = -1; + hills[y][x] = -1; + hills[partnerPortalY][partnerPortalX] = -1; } if (reflection[0] != x || reflection[1] != y) { setASpawn([x, y]) @@ -300,20 +283,20 @@ export default function MapBuilder() { } - } else if (cellType == GridValues.SNAKE_B_HEAD) { + } else if (cellType == GridValues.PLAYER_2) { const reflection = reflect(x, y); if (reflection[0] != x || reflection[1] != y) { if (walls != null && walls[y][x]) { walls[y][x] = false; walls[reflection[1]][reflection[0]] = false; - } else if (portals != null && portals[y][x] >= 0) { - const partnerPortal = portals[y][x] + } else if (hills != null && hills[y][x] >= 0) { + const partnerPortal = hills[y][x] const partnerPortalX = partnerPortal % mapWidth const partnerPortalY = Math.floor(partnerPortal / mapWidth) - portals[y][x] = -1; - portals[partnerPortalY][partnerPortalX] = -1; + hills[y][x] = -1; + hills[partnerPortalY][partnerPortalX] = -1; } if (reflection[0] != x || reflection[1] != y) { setBSpawn([x, y]) @@ -329,14 +312,14 @@ export default function MapBuilder() { } else if (x == bSpawn[0] && y == bSpawn[1]) { setASpawn([-1, -1]) setBSpawn([-1, -1]) - } else if (portals != null && portals[y][x] >= 0) { - const partnerPortal = portals[y][x] + } else if (hills != null && hills[y][x] >= 0) { + const partnerPortal = hills[y][x] const partnerPortalX = partnerPortal % mapWidth const partnerPortalY = Math.floor(partnerPortal / mapWidth) - portals[y][x] = -1; - portals[partnerPortalY][partnerPortalX] = -1; + hills[y][x] = -1; + hills[partnerPortalY][partnerPortalX] = -1; } walls[y][x] = true; walls[reflection[1]][reflection[0]] = true; @@ -351,21 +334,21 @@ export default function MapBuilder() { } else if (walls != null && walls[y][x]) { walls[y][x] = 0; walls[reflection[1]][reflection[0]] = 0; - } else if (portals != null && portals[y][x] >= 0) { - const partnerPortal = portals[y][x] + } else if (hills != null && hills[y][x] >= 0) { + const partnerPortal = hills[y][x] const partnerPortalX = partnerPortal % mapWidth const partnerPortalY = Math.floor(partnerPortal / mapWidth) - portals[y][x] = -1; - portals[partnerPortalY][partnerPortalX] = -1; + hills[y][x] = -1; + hills[partnerPortalY][partnerPortalX] = -1; } if (endPortal[0] != -1) { - portals[y][x] = endPortal[1] * mapWidth + endPortal[0] - portals[endPortal[1]][endPortal[0]] = y * mapWidth + x + hills[y][x] = endPortal[1] * mapWidth + endPortal[0] + hills[endPortal[1]][endPortal[0]] = y * mapWidth + x setEndPortal([-1, -1]) } else { @@ -382,18 +365,18 @@ export default function MapBuilder() { } else if (walls != null && walls[y][x] > 0) { walls[y][x] = 0; walls[reflection[1]][reflection[0]] = 0; - } else if (portals != null && portals[y][x] >= 0) { - const partnerPortal = portals[y][x] + } else if (hills != null && hills[y][x] >= 0) { + const partnerPortal = hills[y][x] const partnerPortalX = partnerPortal % mapWidth const partnerPortalY = Math.floor(partnerPortal / mapWidth) - portals[y][x] = -1; - portals[partnerPortalY][partnerPortalX] = -1; + hills[y][x] = -1; + hills[partnerPortalY][partnerPortalX] = -1; } if (startPortal[0] != -1) { - portals[y][x] = startPortal[1] * mapWidth + startPortal[0] - portals[startPortal[1]][startPortal[0]] = y * mapWidth + x + hills[y][x] = startPortal[1] * mapWidth + startPortal[0] + hills[startPortal[1]][startPortal[0]] = y * mapWidth + x setStartPortal([-1, -1]) } else { @@ -408,8 +391,8 @@ export default function MapBuilder() { if (walls == null) { setWalls(new Array(mapHeight).fill().map(() => new Array(mapWidth).fill(false))); } - if (portals == null) { - setPortals(new Array(mapHeight).fill().map(() => new Array(mapWidth).fill(-1))); + if (hills == null) { + setHills(new Array(mapHeight).fill().map(() => new Array(mapWidth).fill(-1))); } }, []); @@ -467,7 +450,7 @@ export default function MapBuilder() {

Symmetry

- +
@@ -528,7 +511,7 @@ export default function MapBuilder() {
{ + const drawHill = (x, y) => { ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; ctx.beginPath(); ctx.arc( @@ -109,7 +107,7 @@ export default function MapVis({ } - const drawSnakeHead = (x, y, color, direction) => { + const drawPlayer = (x, y, color, direction) => { ctx.fillStyle = color; ctx.beginPath(); ctx.arc( @@ -177,18 +175,15 @@ export default function MapVis({ if(walls != null && walls[y][x]){ drawWall(x, y); } - else if(portals != null && portals[y][x] >= 0){ - drawPortal(x, y) + else if(hillMap != null && hillMap[y][x] != 0){ + drawHill(x, y) } - else if((x == startPortal[0] && y == startPortal[1])||(x == endPortal[0] && y == endPortal[1])){ - drawPortal(x, y) + else if(showSpawn && x == aSpawn[0] && y == aSpawn[1]){ + drawPlayer(x, y, 'green', Action.NORTH); } - else if(showSnakeStart && x == aSpawn[0] && y == aSpawn[1]){ - drawSnakeHead(x, y, 'green', Action.NORTH); - } - else if(showSnakeStart && x == bSpawn[0] && y == bSpawn[1]){ - drawSnakeHead(x, y, 'blue', Action.NORTH); + else if(showSpawn && x == bSpawn[0] && y == bSpawn[1]){ + drawPlayer(x, y, 'blue', Action.NORTH); } } @@ -212,12 +207,10 @@ export default function MapVis({ }, [ aSpawn, bSpawn, - startPortal, - endPortal, mapHeight, mapWidth, walls, - portals, + hillMap, mouseCellX, mouseCellY, rerender diff --git a/src/components/MapSettings.js b/src/components/MapSettings.js index c276802..6d45c55 100644 --- a/src/components/MapSettings.js +++ b/src/components/MapSettings.js @@ -1,9 +1,9 @@ function MapSettings({ mapHeight, handleHeightChange, mapWidth, handleWidthChange, - appleRate, handleAppleRateChange, - appleNum, handleAppleNumChange, - startSize, handleStartSizeChange + powerupRate, handlePowerupRateChange, + powerupNum, handlePowerupNumChange, + hillID, handleHillIDChange }) { return (
@@ -33,38 +33,38 @@ function MapSettings({
- +
- +
- +
From 06207e46d5d6f4294b68c72b935db3f4bf550fd6 Mon Sep 17 00:00:00 2001 From: Henry Liao Date: Wed, 24 Dec 2025 14:41:18 -0800 Subject: [PATCH 4/9] WIP MapBuilder refactor --- src/components/MapBuilder.js | 14 ++++++-------- src/components/MapBuilderVis.js | 6 +++--- src/components/MapSettings.js | 14 +++++++------- src/components/ShowSpawn.js | 6 +++--- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/components/MapBuilder.js b/src/components/MapBuilder.js index 960a524..62123c4 100644 --- a/src/components/MapBuilder.js +++ b/src/components/MapBuilder.js @@ -391,8 +391,8 @@ export default function MapBuilder() { if (walls == null) { setWalls(new Array(mapHeight).fill().map(() => new Array(mapWidth).fill(false))); } - if (hills == null) { - setHills(new Array(mapHeight).fill().map(() => new Array(mapWidth).fill(-1))); + if (hillGrid == null) { + setHillGrid(new Array(mapHeight).fill().map(() => new Array(mapWidth).fill(-1))); } }, []); @@ -450,7 +450,7 @@ export default function MapBuilder() {

Symmetry

- +
Copy Map String
-
- +
- +
- + diff --git a/src/components/ShowSpawn.js b/src/components/ShowSpawn.js index 566c254..f94cb95 100644 --- a/src/components/ShowSpawn.js +++ b/src/components/ShowSpawn.js @@ -1,5 +1,5 @@ function ShowSpawn ({ - showSnakeStart, handleShowSnakeStart + showSpawn, handleShowSpawn }){ return ( @@ -7,8 +7,8 @@ function ShowSpawn ({
+ disabled={!canStart && !isMatchRunning} + onClick={handleBattleStart} + > + {isMatchRunning ? 'Stop Match' : 'Start Battle'} +
Date: Thu, 25 Dec 2025 16:36:27 -0800 Subject: [PATCH 8/9] fix match stopping --- src/components/MatchPlayer.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/MatchPlayer.js b/src/components/MatchPlayer.js index 940ee73..ae2b9d0 100644 --- a/src/components/MatchPlayer.js +++ b/src/components/MatchPlayer.js @@ -72,8 +72,6 @@ function MatchPlayer() { if (isMatchRunning) { // Stop the match window.electron.sendTCPInterrupt(); - setIsMatchRunning(false); - setEngineOutput("Match terminated by user"); } else { // Start the match setBot1File(bot1File); From b0d55a82380d588887a1307e27f68864308e11b3 Mon Sep 17 00:00:00 2001 From: Henry Liao Date: Thu, 25 Dec 2025 16:56:47 -0800 Subject: [PATCH 9/9] rename dist to 2026 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 774db96..4c1e0f9 100755 --- a/package.json +++ b/package.json @@ -57,8 +57,8 @@ "typescript": "^5.8.2" }, "build": { - "appId": "com.bytefight.bytefightclient2025", - "productName": "Bytefight Client 2025", + "appId": "com.bytefight.bytefightclient2026", + "productName": "Bytefight Client 2026", "forceCodeSigning": false, "files": [ {