From 41753d8011cc52fe5de29ae6cfe7f246f3760859 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 16 Mar 2022 00:32:23 -0700 Subject: [PATCH] Reconnects all seem to be working, except in video Signed-off-by: James Ketrenos --- client/src/App.js | 29 ++- client/src/Board.js | 612 +++++++++++++++++++++----------------------- 2 files changed, 311 insertions(+), 330 deletions(-) diff --git a/client/src/App.js b/client/src/App.js index 399f623..5ac357e 100755 --- a/client/src/App.js +++ b/client/src/App.js @@ -49,6 +49,8 @@ const Table = () => { const [buildActive, setBuildActive] = useState(false); const [cardActive, setCardActive] = useState(undefined); const [winnerDismissed, setWinnerDismissed] = useState(undefined); + const [global, setGlobal] = useState({ setPeers }); + const [count, setCount] = useState(0); const fields = [ 'id', 'state', 'color', 'name', 'private' ]; useEffect(() => { @@ -159,11 +161,25 @@ const Table = () => { const resetConnection = cbResetConnection(); + if (global.ws !== connection + || global.name !== name + || global.gameId !== gameId + || global.peers !== peers) { + console.log(`board - (app) - setting global`, global, + {connection, name, gameId, peers}); + setGlobal({ + ws: connection, + name, gameId, peers, + setPeers + }); + } + const onWsError = (event) => { console.error(`ws: error`, event); const error = `Connection to Ketr Ketran game server failed! ` + `Connection attempt will be retried every 5 seconds.`; setError(error); + setGlobal(Object.assign({}, global, { ws: undefined })); setWs(undefined); /* clear the socket */ setConnection(undefined); /* clear the connection */ resetConnection(); @@ -174,6 +190,7 @@ const Table = () => { `Attempting to reconnect...`; console.warn(`ws: close`); setError(error); + setGlobal(Object.assign({}, global, { ws: undefined })); setWs(undefined); /* clear the socket */ setConnection(undefined); /* clear the connection */ resetConnection(); @@ -258,11 +275,12 @@ const Table = () => { } else { new_uri = "ws"; } - new_uri = `${new_uri}://${loc.host}${base}/api/v1/games/ws/${gameId}`; + new_uri = `${new_uri}://${loc.host}${base}/api/v1/games/ws/${gameId}?${count}`; console.log(`Attempting WebSocket connection to ${new_uri}`); setWs(new WebSocket(new_uri)); setConnection(undefined); setRetryConnection(false); + setCount(count + 1); return unbind; } @@ -287,9 +305,14 @@ const Table = () => { ws.removeEventListener('error', cbError); ws.removeEventListener('message', cbMessage); } - }, [ setWs, connection, setConnection, retryConnection, setRetryConnection, gameId, ws, refWsOpen, refWsMessage, refWsClose, refWsError ]); + }, [ ws, setWs, connection, setConnection, + retryConnection, setRetryConnection, gameId, + refWsOpen, refWsMessage, refWsClose, refWsError, count, setCount + ]); - return + console.log(`board - (app) - Render with ws: ${ws ? '!' : ''}NULL, connection: ${connection ? '!' : ''}NULL`); + + return { /* */ }
diff --git a/client/src/Board.js b/client/src/Board.js index 54c01a2..cc95cbf 100644 --- a/client/src/Board.js +++ b/client/src/Board.js @@ -56,13 +56,9 @@ const Board = () => { 'placements', 'turn', 'state', 'color', 'longestRoadLength' ], []); - console.log(`board - render ws is ${!ws ? 'NULL' : (ws.readyState === ws.OPEN ? 'OPEN' : '!OPEN')}`); + console.log(`board - ws`, ws); const onWsMessage = (event) => { - if (hack !== ws) { - console.error(`Setting hack`) - hack = ws; - } if (ws && ws !== event.target) { console.error(`Disconnect occur?`); } @@ -141,30 +137,24 @@ const Board = () => { break; } }; - const refWs = useRef(ws); const refWsMessage = useRef(onWsMessage); useEffect(() => { refWsMessage.current = onWsMessage; }); useEffect(() => { - if (!ws) { return; } - refWs.current = ws; - console.log('board - bind'); - if (hack !== ws) { - console.log(`board - ws and hack are different`); + if (ws !== hack) { + console.log(`board - setting out-of-scope hack`); + hack = ws; } + if (!ws) { return; } + console.log('board - bind'); const cbMessage = e => refWsMessage.current(e); ws.addEventListener('message', cbMessage); return () => { console.log('board - unbind'); ws.removeEventListener('message', cbMessage); } - }, [ws, refWsMessage]); + }, [ws]); useEffect(() => { - console.log(`board - initial get`); - if (!ws) { - console.log(`board - initial get - no ws`); - return; - } - console.log(`board - ws is set`); + if (!ws) { return; } ws.send(JSON.stringify({ type: 'get', fields @@ -214,89 +204,22 @@ const Board = () => { onResize(); - const Tile = ({tile}) => { - const onClick = (event) => { - console.log(`Tile clicked: ${tile.index}`); - }; - - return
; - }; -/* -useRef didn't work... - const staticSendCallback = (type, index) => { - ws.send(JSON.stringify({ - type, index - })); - }; - const refStaticSendCallback = useRef(staticSendCallback); - useEffect(() => { refStaticSendCallback.current = staticSendCallback; }); - - - - const sendPlacement = function(...) doesn't work. - - */ - - /* - * const sendPlacement = useCallabck(...) doesn't work. - * - * However it is required for dependency tracking. - */ - const sendPlacement = useCallback((type, index) => { - console.log(`board - sendPlacement - ws is ${!ws ? 'NULL' : (ws.readyState === ws.OPEN ? 'OPEN' : '!OPEN')}`); - if (ws !== hack) { - console.error(`hack and ws are different!`); - if (refWs.current === hack) { - console.log(`refWs is correct!`); - } else { - refWs.current = hack; - } - } - - refWs.current.send(JSON.stringify({ - type, index - })); - }, [ws, refWs]); - - const onRoadClicked = useCallback((road) => { - console.log(`Road clicked: ${road.index}`); - sendPlacement('place-road', road.index); - }, [sendPlacement]); - - const Road = useCallback(({road}) => { - return
{ onRoadClicked(road) }} - data-index={road.index} - style={{ - transform: `translate(-50%, -50%) rotate(${road.angle}deg)`, - top: `${road.top}px`, - left: `${road.left}px` - }} - >
; - }, [onRoadClicked]); - - const onCornerClicked = useCallback((event, corner) => { + useEffect(() => { + console.log(`Generating static corner data... should only occur once per reload.`); + const onCornerClicked = (event, corner) => { let type; if (event.currentTarget.getAttribute('data-type') === 'settlement') { - type = 'place-city'; + type = 'place-city2'; } else { type = 'place-settlement'; } - sendPlacement(type, corner.index); - }, [sendPlacement]); + if (!hack) { console.error(`board - onCornerClicked - ws is NULL`); return; } + ws.send(JSON.stringify({ + type, index: corner.index + })); + }; - const Corner = useCallback(({corner}) => { + const Corner = ({corner}) => { return
{ onCornerClicked(event, corner) }} data-index={corner.index} @@ -305,108 +228,9 @@ useRef didn't work... left: `${corner.left}px` }} >
; - }, [onCornerClicked]); + }; - const onPipClicked = useCallback((pip) => { - sendPlacement('place-robber', pip.index); - }, [sendPlacement]); - - const Pip = useCallback(({pip}) => { - return
{ onPipClicked(pip) }} - data-roll={pip.roll} - data-index={pip.index} - style={{ - top: `${pip.top}px`, - left: `${pip.left}px`, - backgroundImage: `url(${assetsPath}/gfx/pip-numbers.png)`, - backgroundPositionX: `${ 100. * (pip.order % 6) / 5.}%`, - backgroundPositionY: `${ 100 * Math.floor(pip.order / 6) / 5. }%` - }} - >
; - }, [onPipClicked]); - - const generateRoads = useCallback(() => { - let row = 0, rowCount = 0; - let y = -2.5 + tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth, - x = -tileHalfHeight -(rows[row] - 1) * 0.5 * tileHeight; - - let index = 0; - let road; - - const corners = []; - - for (let i = 0; i < 21; i++) { - const lastRow = row === rows.length - 1; - if (row > 2 && rowCount === 0) { - road = { - index: index++, - angle: -60, - top: y-0.5*tileHalfHeight, - left: x-tileHalfHeight - }; - corners.push(); - } - - road = { - index: index++, - angle: 240, - top: y, - left: x - }; - corners.push(); - - road = { - index: index++, - angle: -60, - top: y-0.5*tileHalfHeight, - left: x+tileHalfHeight - }; - corners.push(); - - if (!lastRow) { - road = { - index: index++, - angle: 0, - top: y, - left: x - }; - corners.push(); - } - - if (++rowCount === rows[row]) { - if (!lastRow) { - road = { - index: index++, - angle: 0, - top: y, - left: x+2.*tileHalfHeight - }; - corners.push(); - } - - if (row > 2) { - road = { - index: index++, - angle: 60, - top: y-0.5*tileHalfHeight, - left: x+3.*tileHalfHeight - }; - corners.push(); - } - - row++; - rowCount = 0; - y += tileHeight - 10.5; - x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight; - } else { - x += tileHeight; - } - } - return corners; - }, []); - - const generateCorners = useCallback(() => { + const generateCorners = () => { let row = 0, rowCount = 0; let y = -8 + 0.5 * tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth, x = -tileHalfHeight -(rows[row] - 1) * 0.5 * tileHeight; @@ -464,120 +288,265 @@ useRef didn't work... } } return corners; - }, []); - - const generatePips = function (pipOrder) { - let row = 0, rowCount = 0; - let y = tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth, - x = -(rows[row] - 1) * 0.5 * tileHeight; - let index = 0; - let pip; - return pipOrder.map(order => { - pip = { - roll: pips[order].roll, - index: index++, - top: y, - left: x, - order: order - }; - const div = ; - - if (++rowCount === rows[row]) { - row++; - rowCount = 0; - y += tileWidth; - x = - (rows[row] - 1) * 0.5 * tileHeight; - } else { - x += tileHeight; - } - - return div; - }); }; + + setCornerElements(generateCorners()); + }, [ws, setCornerElements]); + useEffect(() => { - setCornerElements(generateCorners()); - setRoadElements(generateRoads()); - }, [setCornerElements, setRoadElements, generateCorners, generateRoads]); - - console.log(`board - Generate board - ${signature}`); - console.log(`board - tileOrder - `, tileOrder); + const Road = ({road}) => { + const onRoadClicked = (road) => { + console.log(`Road clicked: ${road.index}`); + if (!ws) { console.error(`board - onRoadClicked - ws is NULL`); return; } + ws.send(JSON.stringify({ + type: 'place-road', index: road.index + })); + }; - const generateTiles = function (tileOrder) { - let row = 0, rowCount = 0; - let y = tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth, - x = -(rows[row] - 1) * 0.5 * tileHeight; - let index = 0; - return tileOrder.map(order => { - const tile = Object.assign({}, - tiles[order], - { index: index++, left: x, top: y}); - - let div = ; - - if (++rowCount === rows[row]) { - row++; - rowCount = 0; - y += tileWidth; - x = - (rows[row] - 1) * 0.5 * tileHeight; - } else { - x += tileHeight; - } - - return div; - }); - }; - - const generateBorders = function(borderOrder) { - const sides = 6; - let side = -1; - return borderOrder.map(order => { - const border = borders[order]; - side++; - let x = + Math.sin(Math.PI - side / sides * 2. * Math.PI) * radius, - y = Math.cos(Math.PI - side / sides * 2. * Math.PI) * radius; - let prev = (order === 0) ? 6 : order; - const file = `borders-${order+1}.${prev}.png`; - return
{ onRoadClicked(road) }} + data-index={road.index} style={{ - width: `${borderImageWidth}px`, - height: `${borderImageHeight}px`, - top: `${y}px`, - left: `${x}px`, - transform: `rotate(${side*(360/sides)}deg) translate(${borderOffsetX}px, ${borderOffsetY}px) scale(-1, -1)`, - backgroundImage: `url(${assetsPath}/gfx/${file} )` + transform: `translate(-50%, -50%) rotate(${road.angle}deg)`, + top: `${road.top}px`, + left: `${road.left}px` }} - />; - }); - }; + >
; + }; + + const generateRoads = () => { + let row = 0, rowCount = 0; + let y = -2.5 + tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth, + x = -tileHalfHeight -(rows[row] - 1) * 0.5 * tileHeight; + + let index = 0; + let road; + + const corners = []; + + for (let i = 0; i < 21; i++) { + const lastRow = row === rows.length - 1; + if (row > 2 && rowCount === 0) { + road = { + index: index++, + angle: -60, + top: y-0.5*tileHalfHeight, + left: x-tileHalfHeight + }; + corners.push(); + } + + road = { + index: index++, + angle: 240, + top: y, + left: x + }; + corners.push(); + + road = { + index: index++, + angle: -60, + top: y-0.5*tileHalfHeight, + left: x+tileHalfHeight + }; + corners.push(); + + if (!lastRow) { + road = { + index: index++, + angle: 0, + top: y, + left: x + }; + corners.push(); + } + + if (++rowCount === rows[row]) { + if (!lastRow) { + road = { + index: index++, + angle: 0, + top: y, + left: x+2.*tileHalfHeight + }; + corners.push(); + } + + if (row > 2) { + road = { + index: index++, + angle: 60, + top: y-0.5*tileHalfHeight, + left: x+3.*tileHalfHeight + }; + corners.push(); + } + + row++; + rowCount = 0; + y += tileHeight - 10.5; + x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight; + } else { + x += tileHeight; + } + } + return corners; + } + setRoadElements(generateRoads()); + }, [ws, setRoadElements]); + + /* Generate Pip, Tile, and Border elements */ + useEffect(() => { + const Pip = ({pip}) => { + const onPipClicked = (pip) => { + if (!ws) { console.error(`board - sendPlacement - ws is NULL`); return; } + ws.send(JSON.stringify({ + type: 'place-robber', index: pip.index + })); + }; + + return
{ onPipClicked(pip) }} + data-roll={pip.roll} + data-index={pip.index} + style={{ + top: `${pip.top}px`, + left: `${pip.left}px`, + backgroundImage: `url(${assetsPath}/gfx/pip-numbers.png)`, + backgroundPositionX: `${ 100. * (pip.order % 6) / 5.}%`, + backgroundPositionY: `${ 100 * Math.floor(pip.order / 6) / 5. }%` + }} + >
; + } + + const generatePips = function (pipOrder) { + let row = 0, rowCount = 0; + let y = tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth, + x = -(rows[row] - 1) * 0.5 * tileHeight; + let index = 0; + let pip; + return pipOrder.map(order => { + pip = { + roll: pips[order].roll, + index: index++, + top: y, + left: x, + order: order + }; + const div = ; + + if (++rowCount === rows[row]) { + row++; + rowCount = 0; + y += tileWidth; + x = - (rows[row] - 1) * 0.5 * tileHeight; + } else { + x += tileHeight; + } - if ((signature && signature !== generated) - && (pips && pipOrder && borders && borderOrder - && tiles && tileOrder)) { - setPipElements(generatePips(pipOrder)); - setBorderElements(generateBorders(borderOrder)); - setTileElements(generateTiles(tileOrder)); - - setGenerated(signature); - }/*, [ + return div; + }); + }; + + const Tile = ({tile}) => { + return
; + }; + + const generateTiles = function (tileOrder) { + let row = 0, rowCount = 0; + let y = tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth, + x = -(rows[row] - 1) * 0.5 * tileHeight; + let index = 0; + return tileOrder.map(order => { + const tile = Object.assign({}, + tiles[order], + { index: index++, left: x, top: y}); + let div = ; + if (++rowCount === rows[row]) { + row++; + rowCount = 0; + y += tileWidth; + x = - (rows[row] - 1) * 0.5 * tileHeight; + } else { + x += tileHeight; + } + return div; + }); + }; + + const generateBorders = function(borderOrder) { + const sides = 6; + let side = -1; + return borderOrder.map(order => { + const border = borders[order]; + side++; + let x = + Math.sin(Math.PI - side / sides * 2. * Math.PI) * radius, + y = Math.cos(Math.PI - side / sides * 2. * Math.PI) * radius; + let prev = (order === 0) ? 6 : order; + const file = `borders-${order+1}.${prev}.png`; + return
; + }); + }; + + if (borders && borderOrder) { + console.log(`board - Generate board - borders`); + setBorderElements(generateBorders(borderOrder)); + } + + if (tiles && tileOrder) { + console.log(`board - Generate board - tiles`); + setTileElements(generateTiles(tileOrder)); + } + + /* Regenerate pips every time; it uses ws */ + if (pips && pipOrder) { + console.log(`board - Generate board - pips`); + setPipElements(generatePips(pipOrder)); + } + + if (signature && signature !== generated) { + console.log(`board - Regnerating for ${signature}`); + setGenerated(signature); + } + }, [ signature, generated, - setPipElements, setBorderElements, setTileElements, - borderOrder, borders, pipOrder, pips, tileOrder, tiles - ]);*/ - - console.log(`board - rendering tileOrder - `, tileOrder); - - console.log(`board - todo - look into debouncing the direct DOM update`); - if (turn) { + pips, pipOrder, borders, borderOrder, tiles, tileOrder, + ws + ]); + + /* Re-render turn info after every render */ + useEffect(() => { + if (!turn) { return; } let nodes = document.querySelectorAll('.Active'); for (let i = 0; i < nodes.length; i++) { nodes[i].classList.remove('Active'); @@ -595,15 +564,15 @@ useRef didn't work... nodes[i].classList.add('Active'); } } - } + }); - if (placements) { + /* Re-render placements after every render */ + useEffect(() => { + if (!placements) { return; } /* Set color and type based on placement data from the server */ placements.corners.forEach((corner, index) => { const el = document.querySelector(`.Corner[data-index="${index}"]`); - if (!el) { - return; - } + if (!el) { return; } if (!corner.color) { el.removeAttribute('data-color'); el.removeAttribute('data-type'); @@ -614,9 +583,7 @@ useRef didn't work... }); placements.roads.forEach((road, index) => { const el = document.querySelector(`.Road[data-index="${index}"]`); - if (!el) { - return; - } + if (!el) { return; } if (!road.color) { el.removeAttribute('data-color'); } else { @@ -645,9 +612,7 @@ useRef didn't work... if (turn.limits['roads']) { turn.limits['roads'].forEach(index => { const el = document.querySelector(`.Road[data-index="${index}"]`); - if (!el) { - return; - } + if (!el) { return; } el.classList.add('Option'); el.setAttribute('data-color', turn.color); }); @@ -655,9 +620,7 @@ useRef didn't work... if (turn.limits['corners']) { turn.limits['corners'].forEach(index => { const el = document.querySelector(`.Corner[data-index="${index}"]`); - if (!el) { - return; - } + if (!el) { return; } el.classList.add('Option'); el.setAttribute('data-color', turn.color); }); @@ -665,26 +628,21 @@ useRef didn't work... if (turn.limits['tiles']) { turn.limits['tiles'].forEach(index => { const el = document.querySelector(`.Tile[data-index="${index}"]`); - if (!el) { - return; - } + if (!el) { return; } el.classList.add('Option'); }); } if (turn.limits['pips']) { turn.limits['pips'].forEach(index => { const el = document.querySelector(`.Pip[data-index="${index}"]`); - if (!el) { - return; - } + if (!el) { return; } el.classList.add('Option'); }); } } - } - - useEffect(() => { - let nodes = document.querySelectorAll(`.Pip.Robber`); + + /* Clear the robber */ + nodes = document.querySelectorAll(`.Pip.Robber`); for (let i = 0; i < nodes.length; i++) { nodes[i].classList.remove('Robber'); [ 'Robert', 'Roberta', 'Velocirobber' ].forEach(robberName => @@ -692,6 +650,7 @@ useRef didn't work... ); } + /* Place the robber */ if (robber !== undefined) { const el = document.querySelector(`.Pip[data-index="${robber}"]`); if (el) { @@ -701,7 +660,6 @@ useRef didn't work... } }); - const canAction = (action) => { return (turn && Array.isArray(turn.actions) && turn.actions.indexOf(action) !== -1); };