Resize and board view is working great!
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
6be7b26438
commit
ffb9bfe524
@ -20,6 +20,26 @@ body {
|
||||
background-image: url("./assets/tabletop.png");
|
||||
}
|
||||
|
||||
.Table .Game {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.Table .Board {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.Table .Pieces {
|
||||
display: flex;
|
||||
position: relative;
|
||||
border: 1px solid orange;
|
||||
margin: 1rem;
|
||||
height: 11rem;
|
||||
}
|
||||
|
||||
.Table .Sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -15,7 +15,8 @@ import { PingPong } from "./PingPong.js";
|
||||
import { PlayerList } from "./PlayerList.js";
|
||||
import { PlayerName } from "./PlayerName.js";
|
||||
import { Chat } from "./Chat.js";
|
||||
import { MediaAgent, MediaContext } from "./MediaControl.js";
|
||||
import { MediaAgent } from "./MediaControl.js";
|
||||
import { Board } from "./Board.js";
|
||||
|
||||
import "./App.css";
|
||||
|
||||
@ -27,6 +28,7 @@ const Table = () => {
|
||||
const [ name, setName ] = useState(global.name);
|
||||
const [ error, setError ] = useState(undefined);
|
||||
const [ peers, setPeers ] = useState({});
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(peers);
|
||||
@ -41,7 +43,10 @@ const Table = () => {
|
||||
setWs(event.target);
|
||||
|
||||
/* Request a game-update */
|
||||
event.target.send(JSON.stringify({ type: 'game-update' }));
|
||||
event.target.send(JSON.stringify({
|
||||
type: 'get',
|
||||
fields: [ 'name', 'id' ]
|
||||
}));
|
||||
};
|
||||
|
||||
const onWsMessage = (event) => {
|
||||
@ -52,6 +57,9 @@ const Table = () => {
|
||||
window.alert(data.error);
|
||||
break;
|
||||
case 'game-update':
|
||||
if (!loaded) {
|
||||
setLoaded(true);
|
||||
}
|
||||
console.log(`ws: message - ${data.type}`, data.update);
|
||||
if ('name' in data.update && data.update.name !== name) {
|
||||
console.log(`Updating name to ${data.update.name}`);
|
||||
@ -183,13 +191,18 @@ const Table = () => {
|
||||
return <div>{ error }</div>;
|
||||
}
|
||||
|
||||
console.log(`Loaded: ${loaded}`);
|
||||
|
||||
return <GlobalContext.Provider value={{ ws, name, gameId, peers, setPeers }}>
|
||||
<MediaAgent/>
|
||||
<PingPong/>
|
||||
<div className="Table">
|
||||
<div className="Board">board goes here</div>
|
||||
<div className="Game">
|
||||
<Board/>
|
||||
<div className="Pieces"/>
|
||||
</div>
|
||||
<div className="Sidebar">
|
||||
{ name === "" && <PlayerName/> }
|
||||
{ loaded && name === "" && <PlayerName/> }
|
||||
{ name !== "" && <PlayerList/> }
|
||||
{ name !== "" && <Chat/> }
|
||||
</div>
|
||||
|
@ -1,13 +1,8 @@
|
||||
.Board {
|
||||
display: flex;
|
||||
align-self: stretch;
|
||||
position: absolute;
|
||||
flex: 1;
|
||||
align-items: stretch;
|
||||
right: 30rem;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 11rem;
|
||||
}
|
||||
|
||||
/* Offset 'BorderBox' such that 0,0 is the center
|
||||
|
@ -1,19 +1,153 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState, useContext, useRef, useMemo } from "react";
|
||||
import { assetsPath, debounce } from "./Common.js";
|
||||
import "./Board.css";
|
||||
import { GlobalContext } from "./GlobalContext.js";
|
||||
|
||||
const base = process.env.PUBLIC_URL;
|
||||
const assetsPath = `${base}/assets`;
|
||||
const Board = () => {
|
||||
const { ws } = useContext(GlobalContext);
|
||||
const board = useRef();
|
||||
const [pipElements, setPipElements] = useState(<></>);
|
||||
const [borderElements, setBorderElements] = useState(<></>);
|
||||
const [tileElements, setTileElements] = useState(<></>);
|
||||
const [cornerElements, setCornerElements] = useState(<></>);
|
||||
const [roadElements, setRoadElements] = useState(<></>);
|
||||
const [ signature, setSignature ] = useState("");
|
||||
const [ robber, setRobber ] = useState(-1);
|
||||
const [ robberName, setRobberName ] = useState([]);
|
||||
const [ pips, setPips ] = useState([]);
|
||||
const [ pipOrder, setPipOrder ] = useState([]);
|
||||
const [ borders, setBorders ] = useState([]);
|
||||
const [ borderOrder, setBorderOrder ] = useState([]);
|
||||
const [ tiles, setTiles ] = useState([]);
|
||||
const [ tileOrder, setTileOrder ] = useState([]);
|
||||
const [ placements, setPlacements ] = useState(undefined);
|
||||
const [ turn, setTurn ] = useState({});
|
||||
const [ state, setState ] = useState("");
|
||||
const [ color, setColor ] = useState("");
|
||||
const [ longestRoadLength, setLongestRoadLength ] = useState(0);
|
||||
const fields = useMemo(() => [
|
||||
'signature', 'robber', 'robberName',
|
||||
'pips', 'pipsOrder', 'borders', 'borderOrder', 'tiles', 'tileOrder',
|
||||
'placements', 'turn', 'state', 'color', 'longestRoadLength'
|
||||
], []);
|
||||
|
||||
const Board = ({ table, game }) => {
|
||||
const rows = [3, 4, 5, 4, 3, 2]; /* The final row of 2 is to place roads and corners */
|
||||
const [signature, setSignature] = useState("");
|
||||
const [pips, setPips] = useState(<></>);
|
||||
const [borders, setBorders] = useState(<></>);
|
||||
const [tiles, setTiles] = useState(<></>);
|
||||
const [corners, setCorners] = useState(<></>);
|
||||
const [roads, setRoads] = useState(<></>);
|
||||
const onWsMessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
switch (data.type) {
|
||||
case 'game-update':
|
||||
if (data.update.signature && data.update.signature !== signature) {
|
||||
setSignature(data.update.signature);
|
||||
}
|
||||
|
||||
const [transform, setTransform] = useState(1);
|
||||
if (data.update.robber && data.update.robber !== robber) {
|
||||
setRobber(data.update.robber);
|
||||
}
|
||||
|
||||
if (data.update.robberName && data.update.robberName !== robberName) {
|
||||
setRobberName(data.update.robberName);
|
||||
}
|
||||
|
||||
if (data.update.pips) {
|
||||
setPips(data.update.pips);
|
||||
}
|
||||
if (data.update.pipOrder) {
|
||||
setPipOrder(data.update.pipOrder);
|
||||
}
|
||||
|
||||
if (data.update.borders) {
|
||||
setBorders(data.update.borders);
|
||||
}
|
||||
if (data.update.borderOrder) {
|
||||
setBorderOrder(data.update.borderOrder);
|
||||
}
|
||||
|
||||
if (data.update.tiles) {
|
||||
setTiles(data.update.tiles);
|
||||
}
|
||||
if (data.update.tileOrder) {
|
||||
setTileOrder(data.update.tileOrder);
|
||||
}
|
||||
|
||||
if (data.update.state && data.update.state !== state) {
|
||||
setState(data.update.state);
|
||||
}
|
||||
if (data.update.color && data.update.color !== color) {
|
||||
setColor(data.update.color);
|
||||
}
|
||||
if (data.update.longestRoadLength
|
||||
&& data.update.longestRoadLength !== longestRoadLength) {
|
||||
setLongestRoadLength(data.update.longestRoadLength);
|
||||
}
|
||||
if (data.update.turn) {
|
||||
setTurn(data.update.turn);
|
||||
}
|
||||
if (data.update.placements) {
|
||||
console.log(`placements`, data.update.placements);
|
||||
setPlacements(data.update.placements);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const refWsMessage = useRef(onWsMessage);
|
||||
useEffect(() => { refWsMessage.current = onWsMessage; });
|
||||
|
||||
useEffect(() => {
|
||||
if (!board.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const onResize = debounce(() => {
|
||||
/* Adjust the 'transform: scale' for the BoardBox
|
||||
* so the board fills the Board
|
||||
*
|
||||
* The board is H tall, and H * hexRatio wide */
|
||||
const width = board.current.offsetWidth,
|
||||
height = board.current.offsetHeight;
|
||||
let _transform;
|
||||
if (height * hexRatio > width) {
|
||||
_transform = width / (450. * hexRatio);
|
||||
} else {
|
||||
_transform = height / (450.);
|
||||
}
|
||||
|
||||
const boardBox = board.current.querySelector('.BoardBox');
|
||||
if (boardBox) {
|
||||
console.log(`Setting transofrm scale to ${_transform}`);
|
||||
boardBox.style.transform = `scale(${_transform})`;
|
||||
}
|
||||
}, 250);
|
||||
|
||||
window.addEventListener('resize', onResize);
|
||||
onResize();
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', onResize);
|
||||
}
|
||||
}, [board]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ws) {
|
||||
return;
|
||||
}
|
||||
const cbMessage = e => refWsMessage.current(e);
|
||||
ws.addEventListener('message', cbMessage);
|
||||
return () => {
|
||||
ws.removeEventListener('message', cbMessage);
|
||||
}
|
||||
}, [ws, refWsMessage]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ws) {
|
||||
return;
|
||||
}
|
||||
ws.send(JSON.stringify({
|
||||
type: 'get',
|
||||
fields
|
||||
}));
|
||||
}, [ws, fields]);
|
||||
|
||||
const
|
||||
hexRatio = 1.1547,
|
||||
@ -51,10 +185,16 @@ const Board = ({ table, game }) => {
|
||||
><div className="Tile-Shape"/></div>;
|
||||
};
|
||||
|
||||
const sendPlacement = (type, index) => {
|
||||
ws.send(JSON.stringify({
|
||||
type, index
|
||||
}));
|
||||
};
|
||||
|
||||
const Road = ({road}) => {
|
||||
const onClick = (event) => {
|
||||
console.log(`Road clicked: ${road.index}`);
|
||||
table.placeRoad(road.index);
|
||||
sendPlacement('place-road', road.index);
|
||||
};
|
||||
|
||||
return <div className="Road"
|
||||
@ -70,13 +210,13 @@ const Board = ({ table, game }) => {
|
||||
|
||||
const Corner = ({corner}) => {
|
||||
const onClick = (event) => {
|
||||
// console.log(`Corner ${corner.index}:`, game.layout.corners[corner.index]);
|
||||
let type;
|
||||
if (event.currentTarget.getAttribute('data-type') === 'settlement') {
|
||||
table.placeCity(corner.index);
|
||||
type = 'place-city';
|
||||
} else {
|
||||
table.placeSettlement(corner.index);
|
||||
type = 'place-settlement';
|
||||
}
|
||||
return;
|
||||
sendPlacement(type, corner.index);
|
||||
};
|
||||
|
||||
return <div className="Corner"
|
||||
@ -91,9 +231,7 @@ const Board = ({ table, game }) => {
|
||||
|
||||
const Pip = ({pip}) => {
|
||||
const onClick = (event) => {
|
||||
// console.log(`Pip ${pip.index}:`, game.layout.corners[pip.index]);
|
||||
table.placeRobber(pip.index);
|
||||
return;
|
||||
sendPlacement('place-robber', pip.index);
|
||||
};
|
||||
|
||||
return <div className="Pip"
|
||||
@ -110,280 +248,259 @@ const Board = ({ table, game }) => {
|
||||
><div className="Pip-Shape"/></div>;
|
||||
};
|
||||
|
||||
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;
|
||||
useEffect(() => {
|
||||
if (!signature) {
|
||||
return;
|
||||
}
|
||||
const rows = [3, 4, 5, 4, 3, 2]; /* The final row of 2 is to place roads and corners */
|
||||
|
||||
let index = 0;
|
||||
let road;
|
||||
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;
|
||||
|
||||
const corners = [];
|
||||
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 key={`road-${index}}`} road={road}/>);
|
||||
}
|
||||
|
||||
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 key={`road-${index}}`} road={road}/>);
|
||||
}
|
||||
|
||||
road = {
|
||||
index: index++,
|
||||
angle: 240,
|
||||
top: y,
|
||||
left: x
|
||||
};
|
||||
corners.push(<Road key={`road-${index}}`} road={road}/>);
|
||||
|
||||
road = {
|
||||
index: index++,
|
||||
angle: -60,
|
||||
top: y-0.5*tileHalfHeight,
|
||||
left: x+tileHalfHeight
|
||||
};
|
||||
corners.push(<Road key={`road-${index}}`} road={road}/>);
|
||||
|
||||
if (!lastRow) {
|
||||
road = {
|
||||
index: index++,
|
||||
angle: 0,
|
||||
angle: 240,
|
||||
top: y,
|
||||
left: x
|
||||
};
|
||||
corners.push(<Road key={`road-${index}}`} road={road}/>);
|
||||
}
|
||||
|
||||
if (++rowCount === rows[row]) {
|
||||
road = {
|
||||
index: index++,
|
||||
angle: -60,
|
||||
top: y-0.5*tileHalfHeight,
|
||||
left: x+tileHalfHeight
|
||||
};
|
||||
corners.push(<Road key={`road-${index}}`} road={road}/>);
|
||||
|
||||
if (!lastRow) {
|
||||
road = {
|
||||
index: index++,
|
||||
angle: 0,
|
||||
top: y,
|
||||
left: x+2.*tileHalfHeight
|
||||
left: x
|
||||
};
|
||||
corners.push(<Road key={`road-${index}}`} road={road}/>);
|
||||
}
|
||||
|
||||
if (row > 2) {
|
||||
road = {
|
||||
index: index++,
|
||||
angle: 60,
|
||||
top: y-0.5*tileHalfHeight,
|
||||
left: x+3.*tileHalfHeight
|
||||
};
|
||||
corners.push(<Road key={`road-${index}}`} road={road}/>);
|
||||
}
|
||||
if (++rowCount === rows[row]) {
|
||||
if (!lastRow) {
|
||||
road = {
|
||||
index: index++,
|
||||
angle: 0,
|
||||
top: y,
|
||||
left: x+2.*tileHalfHeight
|
||||
};
|
||||
corners.push(<Road key={`road-${index}}`} road={road}/>);
|
||||
}
|
||||
|
||||
row++;
|
||||
rowCount = 0;
|
||||
y += tileHeight - 10.5;
|
||||
x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight;
|
||||
} else {
|
||||
x += tileHeight;
|
||||
if (row > 2) {
|
||||
road = {
|
||||
index: index++,
|
||||
angle: 60,
|
||||
top: y-0.5*tileHalfHeight,
|
||||
left: x+3.*tileHalfHeight
|
||||
};
|
||||
corners.push(<Road key={`road-${index}}`} road={road}/>);
|
||||
}
|
||||
|
||||
row++;
|
||||
rowCount = 0;
|
||||
y += tileHeight - 10.5;
|
||||
x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight;
|
||||
} else {
|
||||
x += tileHeight;
|
||||
}
|
||||
}
|
||||
return corners;
|
||||
}
|
||||
return corners;
|
||||
}
|
||||
|
||||
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;
|
||||
let index = 0;
|
||||
const corners = [];
|
||||
let corner;
|
||||
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;
|
||||
let index = 0;
|
||||
const corners = [];
|
||||
let corner;
|
||||
|
||||
for (let i = 0; i < 21; i++) {
|
||||
if (row > 2 && rowCount === 0) {
|
||||
corner = {
|
||||
index: index++,
|
||||
top: y-0.5*tileHalfHeight,
|
||||
left: x-tileHalfHeight
|
||||
};
|
||||
corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
|
||||
}
|
||||
|
||||
corner = {
|
||||
index: index++,
|
||||
top: y,
|
||||
left: x
|
||||
};
|
||||
corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
|
||||
|
||||
corner = {
|
||||
index: index++,
|
||||
top: y-0.5*tileHalfHeight,
|
||||
left: x+tileHalfHeight
|
||||
};
|
||||
corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
|
||||
|
||||
if (++rowCount === rows[row]) {
|
||||
corner = {
|
||||
index: index++,
|
||||
top: y,
|
||||
left: x+2.*tileHalfHeight
|
||||
};
|
||||
corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
|
||||
|
||||
if (row > 2) {
|
||||
for (let i = 0; i < 21; i++) {
|
||||
if (row > 2 && rowCount === 0) {
|
||||
corner = {
|
||||
index: index++,
|
||||
top: y-0.5*tileHalfHeight,
|
||||
left: x+3.*tileHalfHeight
|
||||
left: x-tileHalfHeight
|
||||
};
|
||||
corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
|
||||
}
|
||||
|
||||
row++;
|
||||
rowCount = 0;
|
||||
y += tileHeight - 10.5;
|
||||
x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight;
|
||||
} else {
|
||||
x += tileHeight;
|
||||
corner = {
|
||||
index: index++,
|
||||
top: y,
|
||||
left: x
|
||||
};
|
||||
corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
|
||||
|
||||
corner = {
|
||||
index: index++,
|
||||
top: y-0.5*tileHalfHeight,
|
||||
left: x+tileHalfHeight
|
||||
};
|
||||
corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
|
||||
|
||||
if (++rowCount === rows[row]) {
|
||||
corner = {
|
||||
index: index++,
|
||||
top: y,
|
||||
left: x+2.*tileHalfHeight
|
||||
};
|
||||
corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
|
||||
|
||||
if (row > 2) {
|
||||
corner = {
|
||||
index: index++,
|
||||
top: y-0.5*tileHalfHeight,
|
||||
left: x+3.*tileHalfHeight
|
||||
};
|
||||
corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
|
||||
}
|
||||
|
||||
row++;
|
||||
rowCount = 0;
|
||||
y += tileHeight - 10.5;
|
||||
x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight;
|
||||
} else {
|
||||
x += tileHeight;
|
||||
}
|
||||
}
|
||||
return corners;
|
||||
}
|
||||
return corners;
|
||||
}
|
||||
|
||||
const generatePips = () => {
|
||||
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 game.pipOrder.map(order => {
|
||||
pip = {
|
||||
roll: game.pips[order].roll,
|
||||
robber: index === game.robber,
|
||||
index: index++,
|
||||
top: y,
|
||||
left: x,
|
||||
order: order
|
||||
};
|
||||
const div = <Pip
|
||||
pip={pip}
|
||||
key={`pip-${order}`}
|
||||
/>;
|
||||
|
||||
if (++rowCount === rows[row]) {
|
||||
row++;
|
||||
rowCount = 0;
|
||||
y += tileWidth;
|
||||
x = - (rows[row] - 1) * 0.5 * tileHeight;
|
||||
} else {
|
||||
x += tileHeight;
|
||||
}
|
||||
|
||||
return div;
|
||||
});
|
||||
};
|
||||
|
||||
const generateTiles = () => {
|
||||
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 game.tileOrder.map(order => {
|
||||
const tile = Object.assign({},
|
||||
game.tiles[order],
|
||||
{ index: index++, left: x, top: y});
|
||||
|
||||
let div = <Tile
|
||||
key={`${tile.type}-${tile.card}`}
|
||||
tile={tile}
|
||||
const generatePips = () => {
|
||||
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,
|
||||
robber: index === robber,
|
||||
index: index++,
|
||||
top: y,
|
||||
left: x,
|
||||
order: order
|
||||
};
|
||||
const div = <Pip
|
||||
pip={pip}
|
||||
key={`pip-${order}`}
|
||||
/>;
|
||||
|
||||
if (++rowCount === rows[row]) {
|
||||
row++;
|
||||
rowCount = 0;
|
||||
y += tileWidth;
|
||||
x = - (rows[row] - 1) * 0.5 * tileHeight;
|
||||
} else {
|
||||
x += tileHeight;
|
||||
}
|
||||
if (++rowCount === rows[row]) {
|
||||
row++;
|
||||
rowCount = 0;
|
||||
y += tileWidth;
|
||||
x = - (rows[row] - 1) * 0.5 * tileHeight;
|
||||
} else {
|
||||
x += tileHeight;
|
||||
}
|
||||
|
||||
return div;
|
||||
});
|
||||
};
|
||||
return div;
|
||||
});
|
||||
};
|
||||
|
||||
const generateBorders = () => {
|
||||
const sides = 6;
|
||||
let side = -1;
|
||||
return game.borderOrder.map(order => {
|
||||
const border = game.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 <div
|
||||
key={`border-${order}`}
|
||||
className="Border"
|
||||
border={border}
|
||||
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} )`
|
||||
}}
|
||||
/>;
|
||||
});
|
||||
};
|
||||
const generateTiles = () => {
|
||||
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});
|
||||
|
||||
/* If the game is loaded, and the signature is different,
|
||||
* regenerate everything */
|
||||
if (game && game.signature !== signature) {
|
||||
console.log(`Generate for ${game.signature}`);
|
||||
setPips(generatePips);
|
||||
setBorders(generateBorders);
|
||||
setTiles(generateTiles);
|
||||
setCorners(generateCorners);
|
||||
setRoads(generateRoads);
|
||||
setSignature(game.signature);
|
||||
} else {
|
||||
if (!game) {
|
||||
console.log(`No game in Board`);
|
||||
}
|
||||
}
|
||||
let div = <Tile
|
||||
key={`${tile.type}-${tile.card}`}
|
||||
tile={tile}
|
||||
/>;
|
||||
|
||||
/* Adjust the 'transform: scale' for the BoardBox
|
||||
* so the board fills the Board
|
||||
*
|
||||
* The board is H tall, and H * hexRatio wide */
|
||||
const board = document.querySelector('.Board');
|
||||
if (board) {
|
||||
const width = board.offsetWidth,
|
||||
height = board.offsetHeight;
|
||||
let _transform;
|
||||
if (height * hexRatio > width) {
|
||||
_transform = width / (450. * hexRatio);
|
||||
} else {
|
||||
_transform = height / (450.);
|
||||
}
|
||||
if (_transform !== transform) {
|
||||
const boardBox = board.querySelector('.BoardBox');
|
||||
if (boardBox) {
|
||||
console.log(`Setting transofrm scale to ${_transform}`);
|
||||
boardBox.style.transform = `scale(${_transform})`;
|
||||
}
|
||||
setTransform(_transform);
|
||||
}
|
||||
}
|
||||
if (++rowCount === rows[row]) {
|
||||
row++;
|
||||
rowCount = 0;
|
||||
y += tileWidth;
|
||||
x = - (rows[row] - 1) * 0.5 * tileHeight;
|
||||
} else {
|
||||
x += tileHeight;
|
||||
}
|
||||
|
||||
if (game && game.turn) {
|
||||
return div;
|
||||
});
|
||||
};
|
||||
|
||||
const generateBorders = () => {
|
||||
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 <div
|
||||
key={`border-${order}`}
|
||||
className="Border"
|
||||
border={border}
|
||||
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} )`
|
||||
}}
|
||||
/>;
|
||||
});
|
||||
};
|
||||
|
||||
console.log(`Generate for ${signature}`);
|
||||
setPipElements(generatePips());
|
||||
setBorderElements(generateBorders());
|
||||
setTileElements(generateTiles());
|
||||
setCornerElements(generateCorners());
|
||||
setRoadElements(generateRoads());
|
||||
}, [signature,
|
||||
setPipElements, setBorderElements, setTileElements,
|
||||
setCornerElements, setRoadElements,
|
||||
borderImageWidth, radius, tileHalfHeight, tileHalfWidth,
|
||||
borderImageHeight, borderOrder, borders, pipOrder, pips, robber, tileOrder, tiles,
|
||||
tileHeight]);
|
||||
|
||||
if (turn) {
|
||||
let nodes = document.querySelectorAll('.Active');
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
nodes[i].classList.remove('Active');
|
||||
}
|
||||
if (game.turn.roll) {
|
||||
nodes = document.querySelectorAll(`.Pip[data-roll="${game.turn.roll}"]`);
|
||||
if (turn.roll) {
|
||||
nodes = document.querySelectorAll(`.Pip[data-roll="${turn.roll}"]`);
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const index = nodes[i].getAttribute('data-index');
|
||||
if (index !== null) {
|
||||
@ -397,9 +514,9 @@ const Board = ({ table, game }) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (game && game.placements) {
|
||||
if (placements) {
|
||||
/* Set color and type based on placement data from the server */
|
||||
game.placements.corners.forEach((corner, index) => {
|
||||
placements.corners.forEach((corner, index) => {
|
||||
const el = document.querySelector(`.Corner[data-index="${index}"]`);
|
||||
if (!el) {
|
||||
return;
|
||||
@ -412,7 +529,7 @@ const Board = ({ table, game }) => {
|
||||
el.setAttribute('data-type', corner.type);
|
||||
}
|
||||
});
|
||||
game.placements.roads.forEach((road, index) => {
|
||||
placements.roads.forEach((road, index) => {
|
||||
const el = document.querySelector(`.Road[data-index="${index}"]`);
|
||||
if (!el) {
|
||||
return;
|
||||
@ -421,7 +538,7 @@ const Board = ({ table, game }) => {
|
||||
el.removeAttribute('data-color');
|
||||
} else {
|
||||
if (road.longestRoad) {
|
||||
if (road.longestRoad === game.longestRoadLength) {
|
||||
if (road.longestRoad === longestRoadLength) {
|
||||
el.classList.add('LongestRoad');
|
||||
} else {
|
||||
el.classList.remove('LongestRoad');
|
||||
@ -439,10 +556,10 @@ const Board = ({ table, game }) => {
|
||||
nodes[i].classList.remove('Option');
|
||||
}
|
||||
|
||||
/* Add 'Option' based on game.turn.limits */
|
||||
if (game.turn && game.turn.limits) {
|
||||
if (game.turn.limits['roads']) {
|
||||
game.turn.limits['roads'].forEach(index => {
|
||||
/* Add 'Option' based on turn.limits */
|
||||
if (turn && turn.limits) {
|
||||
if (turn.limits['roads']) {
|
||||
turn.limits['roads'].forEach(index => {
|
||||
const el = document.querySelector(`.Road[data-index="${index}"]`);
|
||||
if (!el) {
|
||||
return;
|
||||
@ -450,8 +567,8 @@ const Board = ({ table, game }) => {
|
||||
el.classList.add('Option');
|
||||
});
|
||||
}
|
||||
if (game.turn.limits['corners']) {
|
||||
game.turn.limits['corners'].forEach(index => {
|
||||
if (turn.limits['corners']) {
|
||||
turn.limits['corners'].forEach(index => {
|
||||
const el = document.querySelector(`.Corner[data-index="${index}"]`);
|
||||
if (!el) {
|
||||
return;
|
||||
@ -459,8 +576,8 @@ const Board = ({ table, game }) => {
|
||||
el.classList.add('Option');
|
||||
});
|
||||
}
|
||||
if (game.turn.limits['tiles']) {
|
||||
game.turn.limits['tiles'].forEach(index => {
|
||||
if (turn.limits['tiles']) {
|
||||
turn.limits['tiles'].forEach(index => {
|
||||
const el = document.querySelector(`.Tile[data-index="${index}"]`);
|
||||
if (!el) {
|
||||
return;
|
||||
@ -468,8 +585,8 @@ const Board = ({ table, game }) => {
|
||||
el.classList.add('Option');
|
||||
});
|
||||
}
|
||||
if (game.turn.limits['pips']) {
|
||||
game.turn.limits['pips'].forEach(index => {
|
||||
if (turn.limits['pips']) {
|
||||
turn.limits['pips'].forEach(index => {
|
||||
const el = document.querySelector(`.Pip[data-index="${index}"]`);
|
||||
if (!el) {
|
||||
return;
|
||||
@ -480,63 +597,59 @@ const Board = ({ table, game }) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (game) {
|
||||
let nodes = document.querySelectorAll(`.Pip.Robber`);
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
nodes[i].classList.remove('Robber');
|
||||
[ 'Robert', 'Roberta', 'Velocirobber' ].forEach(robberName =>
|
||||
nodes[i].classList.remove(robberName)
|
||||
);
|
||||
}
|
||||
let nodes = document.querySelectorAll(`.Pip.Robber`);
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
nodes[i].classList.remove('Robber');
|
||||
[ 'Robert', 'Roberta', 'Velocirobber' ].forEach(robberName =>
|
||||
nodes[i].classList.remove(robberName)
|
||||
);
|
||||
}
|
||||
|
||||
if (game.robber !== undefined) {
|
||||
const el = document.querySelector(`.Pip[data-index="${game.robber}"]`);
|
||||
if (el) {
|
||||
el.classList.add('Robber');
|
||||
el.classList.add(game.robberName);
|
||||
}
|
||||
if (robber !== undefined) {
|
||||
const el = document.querySelector(`.Pip[data-index="${robber}"]`);
|
||||
if (el) {
|
||||
el.classList.add('Robber');
|
||||
el.classList.add(robberName);
|
||||
}
|
||||
}
|
||||
|
||||
const canAction = (action) => {
|
||||
return (game && game.turn && Array.isArray(game.turn.actions) && game.turn.actions.indexOf(action) !== -1);
|
||||
return (turn && Array.isArray(turn.actions) && turn.actions.indexOf(action) !== -1);
|
||||
};
|
||||
|
||||
const canRoad = (canAction('place-road')
|
||||
&& game.turn.color === game.color
|
||||
&& (game.state === 'initial-placement' || game.state === 'normal'));
|
||||
&& turn.color === color
|
||||
&& (state === 'initial-placement' || state === 'normal'));
|
||||
|
||||
const canCorner = ((canAction('place-settlement') || canAction('place-city'))
|
||||
&& game.turn.color === game.color
|
||||
&& (game.state === 'initial-placement' || game.state === 'normal'));
|
||||
&& turn.color === color
|
||||
&& (state === 'initial-placement' || state === 'normal'));
|
||||
|
||||
const canPip = (canAction('place-robber')
|
||||
&& game.turn.color === game.color
|
||||
&& (game.state === 'initial-placement' || game.state === 'normal'));
|
||||
&& turn.color === color
|
||||
&& (state === 'initial-placement' || state === 'normal'));
|
||||
|
||||
return (
|
||||
<div className="Board">
|
||||
<div className="Board" ref={board}>
|
||||
<div className="BoardBox">
|
||||
<div className="Borders" disabled>
|
||||
{ borders }
|
||||
{ borderElements }
|
||||
</div>
|
||||
{ game && <>
|
||||
<div className="Tiles" disabled>
|
||||
{ tiles }
|
||||
</div>
|
||||
<div className="Pips" disabled={!canPip}>
|
||||
{ pips }
|
||||
</div>
|
||||
<div className="Corners" disabled={!canCorner}>
|
||||
{ corners }
|
||||
</div>
|
||||
<div className="Roads" disabled={!canRoad}>
|
||||
{ roads }
|
||||
</div>
|
||||
</> }
|
||||
</div>
|
||||
<div className="Tiles" disabled>
|
||||
{ tileElements }
|
||||
</div>
|
||||
<div className="Pips" disabled={!canPip}>
|
||||
{ pipElements }
|
||||
</div>
|
||||
<div className="Corners" disabled={!canCorner}>
|
||||
{ cornerElements }
|
||||
</div>
|
||||
<div className="Roads" disabled={!canRoad}>
|
||||
{ roadElements }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Board;
|
||||
export { Board };
|
||||
|
@ -9,9 +9,21 @@ const getPlayerName = (sessions, color) => {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function debounce(fn, ms) {
|
||||
let timer
|
||||
return _ => {
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(_ => {
|
||||
timer = null
|
||||
fn.apply(this, arguments)
|
||||
}, ms)
|
||||
};
|
||||
}
|
||||
|
||||
const base = process.env.PUBLIC_URL;
|
||||
|
||||
const assetsPath = `${base}/assets`;
|
||||
const gamesPath = `${base}/games`;
|
||||
|
||||
export { base, assetsPath, gamesPath, getPlayerName };
|
||||
export { base, debounce, assetsPath, gamesPath, getPlayerName };
|
@ -7,6 +7,7 @@ import VolumeUp from '@mui/icons-material/VolumeUp';
|
||||
import MicOff from '@mui/icons-material/MicOff';
|
||||
import Mic from '@mui/icons-material/Mic';
|
||||
import { GlobalContext } from "./GlobalContext.js";
|
||||
const debug = false;
|
||||
|
||||
/* Proxy object so we can pass in srcObject to <audio> */
|
||||
const Audio = ({ srcObject, ...props }) => {
|
||||
@ -15,12 +16,13 @@ const Audio = ({ srcObject, ...props }) => {
|
||||
if (!refAudio.current) {
|
||||
return;
|
||||
}
|
||||
console.log('<audio> bind');
|
||||
refAudio.current.srcObject = srcObject;
|
||||
const ref = refAudio.current;
|
||||
if (debug) console.log('<audio> bind');
|
||||
ref.srcObject = srcObject;
|
||||
return () => {
|
||||
console.log('<audio> unbind');
|
||||
if (refAudio.current) {
|
||||
refAudio.current.srcObject = undefined;
|
||||
if (debug) console.log('<audio> unbind');
|
||||
if (ref) {
|
||||
ref.srcObject = undefined;
|
||||
}
|
||||
};
|
||||
}, [srcObject]);
|
||||
@ -35,7 +37,7 @@ const MediaAgent = () => {
|
||||
const onTrack = useCallback((event) => {
|
||||
const connection = event.target;
|
||||
|
||||
console.log("ontrack", event);
|
||||
if (debug) console.log("ontrack", event);
|
||||
let isLocal = true;
|
||||
for (let key in peers) {
|
||||
if (peers[key].connection === connection) {
|
||||
@ -50,14 +52,14 @@ const MediaAgent = () => {
|
||||
throw new Error('Should not be local!');
|
||||
}
|
||||
|
||||
console.log(`MediaAgent - ontrack - remote`, peers);
|
||||
if (debug) console.log(`MediaAgent - ontrack - remote`, peers);
|
||||
setPeers(Object.assign({}, peers));
|
||||
}, [peers, setPeers]);
|
||||
const refOnTrack = useRef(onTrack);
|
||||
|
||||
const onWsMessage = useCallback((event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log(`MediaAgent - onWsMessage`, peers);
|
||||
if (debug) console.log(`MediaAgent - onWsMessage`, peers);
|
||||
|
||||
const addPeer = (config) => {
|
||||
console.log('Signaling server said to add peer:', config);
|
||||
@ -89,7 +91,7 @@ const MediaAgent = () => {
|
||||
attributes: {
|
||||
}
|
||||
};
|
||||
console.log(`MediaAgent - addPeer - remote`, peers);
|
||||
if (debug) console.log(`MediaAgent - addPeer - remote`, peers);
|
||||
setPeers(Object.assign({}, peers));
|
||||
|
||||
connection.onicecandidate = (event) => {
|
||||
@ -120,10 +122,10 @@ const MediaAgent = () => {
|
||||
* to us
|
||||
*/
|
||||
if (config.should_create_offer) {
|
||||
console.log("MediaAgent - Creating RTC offer to ", peer_id);
|
||||
if (debug) console.log("MediaAgent - Creating RTC offer to ", peer_id);
|
||||
return connection.createOffer()
|
||||
.then((local_description) => {
|
||||
console.log("Local offer description is: ", local_description);
|
||||
if (debug) console.log("Local offer description is: ", local_description);
|
||||
return connection.setLocalDescription(local_description)
|
||||
.then(() => {
|
||||
ws.send(JSON.stringify({
|
||||
@ -133,7 +135,7 @@ const MediaAgent = () => {
|
||||
'session_description': local_description
|
||||
}
|
||||
}));
|
||||
console.log("Offer setLocalDescription succeeded");
|
||||
if (debug) console.log("Offer setLocalDescription succeeded");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Offer setLocalDescription failed!");
|
||||
@ -162,11 +164,11 @@ const MediaAgent = () => {
|
||||
const { connection } = peer;
|
||||
const desc = new RTCSessionDescription(session_description);
|
||||
return connection.setRemoteDescription(desc, () => {
|
||||
console.log("setRemoteDescription succeeded");
|
||||
if (debug) console.log("setRemoteDescription succeeded");
|
||||
if (session_description.type === "offer") {
|
||||
console.log("Creating answer");
|
||||
if (debug) console.log("Creating answer");
|
||||
connection.createAnswer((local_description) => {
|
||||
console.log("Answer description is: ", local_description);
|
||||
if (debug) console.log("Answer description is: ", local_description);
|
||||
connection.setLocalDescription(local_description, () => {
|
||||
ws.send(JSON.stringify({
|
||||
type: 'relaySessionDescription',
|
||||
@ -175,7 +177,7 @@ const MediaAgent = () => {
|
||||
session_description: local_description
|
||||
}
|
||||
}));
|
||||
console.log("Answer setLocalDescription succeeded");
|
||||
if (debug) console.log("Answer setLocalDescription succeeded");
|
||||
}, () => {
|
||||
console.error("Answer setLocalDescription failed!");
|
||||
});
|
||||
@ -200,7 +202,7 @@ const MediaAgent = () => {
|
||||
}
|
||||
|
||||
delete peers[peer_id];
|
||||
console.log(`MediaAgent - removePeer - remote or local?`, peers);
|
||||
if (debug) console.log(`MediaAgent - removePeer - remote or local?`, peers);
|
||||
setPeers(Object.assign({}, peers));
|
||||
};
|
||||
|
||||
@ -217,7 +219,7 @@ const MediaAgent = () => {
|
||||
}
|
||||
peer.connection.addIceCandidate(new RTCIceCandidate(ice_candidate))
|
||||
.then(() => {
|
||||
console.log(`Successfully added Ice Candidate for ${peer_id}`);
|
||||
if (debug) console.log(`Successfully added Ice Candidate for ${peer_id}`);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error, peer, ice_candidate);
|
||||
@ -248,7 +250,7 @@ const MediaAgent = () => {
|
||||
for (let id in peers) {
|
||||
delete peers[id];
|
||||
}
|
||||
console.log(`MediaAgent - close - local or remote?`, peers);
|
||||
if (debug) console.log(`MediaAgent - close - local or remote?`, peers);
|
||||
setPeers(Object.assign({}, peers));
|
||||
}
|
||||
const refWsClose = useRef(onWsClose);
|
||||
@ -296,12 +298,12 @@ const MediaAgent = () => {
|
||||
}
|
||||
}
|
||||
if (update) {
|
||||
console.log(`MediaAgent - Adding local`, peers);
|
||||
if (debug) console.log(`MediaAgent - Adding local`, peers);
|
||||
setPeers(Object.assign({}, peers));
|
||||
}
|
||||
}, [peers, name, setPeers, stream]);
|
||||
|
||||
useEffect(async () => {
|
||||
useEffect(() => {
|
||||
if (!ws) {
|
||||
return;
|
||||
}
|
||||
@ -327,8 +329,8 @@ const MediaAgent = () => {
|
||||
ws.send(JSON.stringify({ type: 'join' }));
|
||||
}
|
||||
|
||||
console.log(`MediaAgent - WebSocket open request. Attempting to create local media.`)
|
||||
await setup_local_media().then(() => {
|
||||
if (debug) console.log(`MediaAgent - WebSocket open request. Attempting to create local media.`)
|
||||
setup_local_media().then(() => {
|
||||
/* once the user has given us access to their
|
||||
* microphone/camcorder, join the channel and start peering up */
|
||||
join();
|
||||
@ -342,7 +344,7 @@ const MediaAgent = () => {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
console.log(`MediaAgent`, peers);
|
||||
if (debug) console.log(`MediaAgent`, peers);
|
||||
|
||||
const audioPeers = [];
|
||||
for (let id in peers) {
|
||||
@ -406,7 +408,7 @@ const MediaControl = ({isSelf, peer}) => {
|
||||
}
|
||||
const update = Object.assign({}, peers);
|
||||
update[peer].muted = control.muted;
|
||||
console.log(`MediaControl - toggleMute`, update);
|
||||
if (debug) console.log(`MediaControl - toggleMute`, update);
|
||||
setPeers(update);
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
@ -3131,11 +3131,15 @@ router.ws("/ws/:id", async (ws, req) => {
|
||||
update = {};
|
||||
data.fields.forEach((field) => {
|
||||
switch (field) {
|
||||
case 'id':
|
||||
case 'chat':
|
||||
case 'startTime':
|
||||
case 'state':
|
||||
update[field] = game[field];
|
||||
break;
|
||||
case 'name':
|
||||
update.name = session.name;
|
||||
break;
|
||||
case 'unselected':
|
||||
update[field] = getFilteredUnselected(game);
|
||||
break;
|
||||
@ -3149,9 +3153,11 @@ router.ws("/ws/:id", async (ws, req) => {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.warn(`WARNING: Requested GET unsupported field: ${field}`);
|
||||
if (field in game) {
|
||||
console.warn(`WARNING: Requested GET not-privatized field: ${field}`);
|
||||
update[field] = game.field;
|
||||
} else {
|
||||
console.warn(`WARNING: Requested GET unsupported field: ${field}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user