1
0

Lot of progress

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-01-27 00:11:15 -08:00
parent 71d125b3c2
commit a4c15e83d3
2 changed files with 178 additions and 114 deletions

View File

@ -13,7 +13,7 @@ import { deepOrange, lightBlue, red, grey } from '@material-ui/core/colors';
import Avatar from '@material-ui/core/Avatar'; import Avatar from '@material-ui/core/Avatar';
import Switch from '@material-ui/core/Switch'; import Switch from '@material-ui/core/Switch';
import Moment from 'react-moment'; import Moment from 'react-moment';
//import moment from 'moment'; import moment from 'moment';
/* Start of withRouter polyfill */ /* Start of withRouter polyfill */
// https://reactrouter.com/docs/en/v6/faq#what-happened-to-withrouter-i-need-it // https://reactrouter.com/docs/en/v6/faq#what-happened-to-withrouter-i-need-it
@ -106,7 +106,7 @@ const Tiles = (board) => {
window.requestAnimationFrame(board.drawFrame); window.requestAnimationFrame(board.drawFrame);
}); });
image.addEventListener("error", (event) => { image.addEventListener("error", (event) => {
alert(`Error loading ${file}`); this.setState({message: `Error loading ${file}`});
}); });
image.src = `${assetsPath}/gfx/${file}`; image.src = `${assetsPath}/gfx/${file}`;
}); });
@ -123,7 +123,7 @@ const Pips = (board) => {
window.requestAnimationFrame(board.drawFrame); window.requestAnimationFrame(board.drawFrame);
}); });
image.addEventListener("error", (event) => { image.addEventListener("error", (event) => {
alert(`Error loading ${file}`); this.setState({message: `Error loading ${file}`});
}); });
image.src = `${assetsPath}/gfx/${file}`; image.src = `${assetsPath}/gfx/${file}`;
@ -141,7 +141,7 @@ const Border = (board, border) => {
window.requestAnimationFrame(board.drawFrame); window.requestAnimationFrame(board.drawFrame);
}); });
image.addEventListener("error", (event) => { image.addEventListener("error", (event) => {
alert(`Error loading ${file}`); board.setState({ message: `Error loading ${file}` });
}); });
image.src = `${assetsPath}/gfx/${file}`; image.src = `${assetsPath}/gfx/${file}`;
return border; return border;
@ -154,31 +154,12 @@ const Table = (board) => {
window.requestAnimationFrame(board.drawFrame); window.requestAnimationFrame(board.drawFrame);
}); });
image.addEventListener("error", (event) => { image.addEventListener("error", (event) => {
alert(`Error loading ${file}`); board.setState({ message: `Error loading ${file}` });
}); });
image.src = `${assetsPath}/gfx/${file}`; image.src = `${assetsPath}/gfx/${file}`;
return image; return image;
}; };
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
class Placard extends React.Component { class Placard extends React.Component {
render() { render() {
return ( return (
@ -230,7 +211,7 @@ class Resource extends React.Component {
} }
}; };
const Chat = ({ game, promoteGameState }) => { const Chat = ({ board, promoteGameState }) => {
const chatInput = (event) => { const chatInput = (event) => {
}; };
@ -239,7 +220,7 @@ const Chat = ({ game, promoteGameState }) => {
console.log(`Send: ${event.target.value}`); console.log(`Send: ${event.target.value}`);
promoteGameState({ promoteGameState({
chat: { chat: {
player: game.activePlayer, player: board.game.activePlayer,
message: event.target.value message: event.target.value
} }
}); });
@ -256,7 +237,7 @@ const Chat = ({ game, promoteGameState }) => {
//const timeDelta = game.timestamp - Date.now(); //const timeDelta = game.timestamp - Date.now();
const messages = game.chat.map((item, index) => { const messages = board.game.chat.map((item, index) => {
//const timestamp = moment(item.date - timeDelta).fromNow(); //const timestamp = moment(item.date - timeDelta).fromNow();
return ( return (
<ListItem key={`msg-${index}`}> <ListItem key={`msg-${index}`}>
@ -278,7 +259,7 @@ const Chat = ({ game, promoteGameState }) => {
{ messages } { messages }
</List> </List>
<TextField className="chatInput" <TextField className="chatInput"
disabled={!game.activePlayer} disabled={!board.game.activePlayer}
inputRef={input => input && input.focus()} inputRef={input => input && input.focus()}
onChange={chatInput} onChange={chatInput}
onKeyPress={chatKeyPress} onKeyPress={chatKeyPress}
@ -287,18 +268,28 @@ const Chat = ({ game, promoteGameState }) => {
); );
} }
const Action = ({ game, promoteGameState }) => { const Action = ({ board }) => {
const actionClick = (event) => { const startClick = (event) => {
this.setGameState("active").then((state) => { board.setGameState("active").then((state) => {
game.state = state; board.game.state = state;
}); });
}; };
const newBoardClick = (event) => {
return board.shuffleBoard();
};
const rollClick = (event) => {
board.throwDice();
}
return ( return (
<> <>
{ game.state == 'lobby' && { board.game.state == 'lobby' &&
<Paper className="Action"> <Paper className="Action">
<Button onClick={actionClick}>Start game</Button> <Button fullWidth onClick={startClick}>Start game</Button>
<Button fullWidth onClick={newBoardClick}>New board</Button>
<Button fullWidth onClick={rollClick}>Roll</Button>
</Paper> </Paper>
} }
</> </>
@ -307,7 +298,7 @@ const Action = ({ game, promoteGameState }) => {
/* This needs to take in a mechanism to declare the /* This needs to take in a mechanism to declare the
* player's active item in the game */ * player's active item in the game */
const Players = ({ game, promoteGameState }) => { const Players = ({ board, promoteGameState }) => {
const [selected, setSelected] = useState(""); const [selected, setSelected] = useState("");
const [name, setName] = useState(""); const [name, setName] = useState("");
@ -325,26 +316,26 @@ const Players = ({ game, promoteGameState }) => {
useEffect(() => { useEffect(() => {
const change = { players: {} }; const change = { players: {} };
/* Joining: selected != "", activePlayer == "", and name != "" */ /* Joining: selected != "" and name != "" */
if (selected && !game.activePlayer && name) { if (selected && name && !board.game.activePlayer) {
change.players[selected] = { name: name } change.players[selected] = { name: name }
promoteGameState(change) promoteGameState(change)
return; return;
} }
/* Leaving: selected = "", name = "", activePlayer != "" */ /* Leaving: selected = "", name = "" */
if (!selected && game.activePlayer) { if (!selected && board.game.activePlayer) {
change.players[game.activePlayer] = { name: "" } change.players[board.game.activePlayer] = { name: "" }
promoteGameState(change) promoteGameState(change)
return; return;
} }
/* Updating name: selected != "", activePlayer != "", name != "", name != activePlayer.name*/ /* Updating name: selected != "", name != "", name != board.name*/
if (selected && if (selected &&
game.activePlayer && board.player &&
name && name &&
game.players[game.activePlayer].name !== name) { board.game.players[board.game.activePlayer].name !== name) {
change.players[game.activePlayer] = { name: name } change.players[board.game.activePlayer] = { name: name }
promoteGameState(change) promoteGameState(change)
return; return;
} }
@ -362,8 +353,8 @@ const Players = ({ game, promoteGameState }) => {
const classes = useStyles(); const classes = useStyles();
const players = []; const players = [];
for (let key in game.players) { for (let key in board.game.players) {
const item = game.players[key]; const item = board.game.players[key];
players.push(( players.push((
<ListItem key={`player-${key}`}> <ListItem key={`player-${key}`}>
<ListItemAvatar> <ListItemAvatar>
@ -409,7 +400,8 @@ class Board extends React.Component {
brick: 0, brick: 0,
stone: 0, stone: 0,
wheat: 0, wheat: 0,
game: null game: null,
message: ""
}; };
this.componentDidMount = this.componentDidMount.bind(this); this.componentDidMount = this.componentDidMount.bind(this);
this.updateDimensions = this.updateDimensions.bind(this); this.updateDimensions = this.updateDimensions.bind(this);
@ -419,13 +411,13 @@ class Board extends React.Component {
this.drawDie = this.drawDie.bind(this); this.drawDie = this.drawDie.bind(this);
this.keyUp = this.keyUp.bind(this); this.keyUp = this.keyUp.bind(this);
this.mouseMove = this.mouseMove.bind(this); this.mouseMove = this.mouseMove.bind(this);
this.randomize = this.randomize.bind(this);
this.throwDice = this.throwDice.bind(this); this.throwDice = this.throwDice.bind(this);
this.promoteGameState = this.promoteGameState.bind(this); this.promoteGameState = this.promoteGameState.bind(this);
this.resetGameLoad = this.resetGameLoad.bind(this); this.resetGameLoad = this.resetGameLoad.bind(this);
this.loadGame = this.loadGame.bind(this); this.loadGame = this.loadGame.bind(this);
this.rollDice = this.rollDice.bind(this); this.rollDice = this.rollDice.bind(this);
this.setGameState = this.setGameState.bind(this); this.setGameState = this.setGameState.bind(this);
this.shuffleBoard = this.shuffleBoard.bind(this);
this.mouse = { x: 0, y: 0 }; this.mouse = { x: 0, y: 0 };
this.radius = 0.317; this.radius = 0.317;
@ -448,6 +440,44 @@ class Board extends React.Component {
this.id = (props.router && props.router.params.id) ? props.router.params.id : 0; this.id = (props.router && props.router.params.id) ? props.router.params.id : 0;
} }
shuffleBoard() {
if (this.loadTimer) {
window.clearTimeout(this.loadTimer);
this.loadTimer = null;
}
return window.fetch(`${base}/api/v1/games/${this.state.game.id}/shuffle`, {
method: "PUT",
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
}
}).then((res) => {
if (res.status >= 400) {
throw new Error(`Unable to shuffle!`);
}
return res.json();
}).then((game) => {
console.log (`Board shuffled!`);
this.game = game;
this.setState({ game: game, message: "" });
this.pips = Pips(this);
this.tiles = Tiles(this);
this.table = Table(this);
this.borders = this.game.borders.map((file) => {
return Border(this, file);
});
}).catch((error) => {
console.error(error);
this.setState({message: error.message});
}).then(() => {
this.resetGameLoad();
window.requestAnimationFrame(this.drawFrame);
});
}
rollDice() { rollDice() {
if (this.loadTimer) { if (this.loadTimer) {
window.clearTimeout(this.loadTimer); window.clearTimeout(this.loadTimer);
@ -462,7 +492,7 @@ class Board extends React.Component {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}).then((res) => { }).then((res) => {
if (res.status > 400) { if (res.status >= 400) {
console.log(res); console.log(res);
throw new Error(`Unable to roll dice`); throw new Error(`Unable to roll dice`);
} }
@ -471,10 +501,10 @@ class Board extends React.Component {
console.log (`Dice rolled!`); console.log (`Dice rolled!`);
console.log(game.dice); console.log(game.dice);
this.game = game; this.game = game;
this.setState({ game: { ...this.state.game, dice: game.dice }} ); this.setState({ game: { ...this.state.game, dice: game.dice }, message: ""} );
}).catch((error) => { }).catch((error) => {
console.error(error); console.error(error);
alert(error); this.setState({message: error.message});
}).then(() => { }).then(() => {
this.resetGameLoad(); this.resetGameLoad();
return this.game.dice; return this.game.dice;
@ -487,11 +517,12 @@ class Board extends React.Component {
this.loadTimer = null; this.loadTimer = null;
} }
if (this.state.game) { if (!this.state.game) {
//return; console.error('Attempting to loadGame with no game set');
return;
} }
window.fetch(`${base}/api/v1/games/${this.state.game.id}`, { return window.fetch(`${base}/api/v1/games/${this.state.game.id}`, {
method: "GET", method: "GET",
cache: 'no-cache', cache: 'no-cache',
credentials: 'same-origin', credentials: 'same-origin',
@ -499,17 +530,18 @@ class Board extends React.Component {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}).then((res) => { }).then((res) => {
if (res.status > 400) { if (res.status >= 400) {
console.log(res); console.log(res);
throw new Error(`Unable to load state`); throw new Error(`Unable to load state`);
} }
return res.json(); return res.json();
}).then((game) => { }).then((game) => {
console.log (`Game state loaded.`); console.log (`Game ${game.id} loaded ${moment().format()}.`);
this.setState({ game: game }); this.game = game;
this.setState({ game: game, message: "" });
}).catch((error) => { }).catch((error) => {
console.error(error); console.error(error);
alert(error); this.setState({message: error.message});
}).then(() => { }).then(() => {
this.resetGameLoad(); this.resetGameLoad();
}); });
@ -531,7 +563,7 @@ class Board extends React.Component {
this.loadTimer = null; this.loadTimer = null;
} }
window.fetch(`${base}/api/v1/games/${this.state.game.id}`, { return window.fetch(`${base}/api/v1/games/${this.state.game.id}`, {
method: "PUT", method: "PUT",
cache: 'no-cache', cache: 'no-cache',
credentials: 'same-origin', credentials: 'same-origin',
@ -540,44 +572,24 @@ class Board extends React.Component {
}, },
body: JSON.stringify(change) body: JSON.stringify(change)
}).then((res) => { }).then((res) => {
if (res.status > 400) { if (res.status >= 400) {
console.error(res); console.error(res);
throw new Error(`Unable to change state`); throw new Error(`Unable to change state`);
} }
return res.json(); return res.json();
}).then((game) => { }).then((game) => {
console.log (`Game state changed.`); console.log (`Game state changed.`);
this.setState({ game: game }); this.game = game;
this.setState({ game: game, message: "" });
}).catch((error) => { }).catch((error) => {
console.error(error); console.error(error);
alert(error); this.setState({message: error.message});
}).then(() => { }).then(() => {
this.resetGameLoad(); this.resetGameLoad();
}); });
} }
randomize() {
//this.borders = shuffle(this.borders);
this.tiles = shuffle(this.tiles);
this.tiles.forEach((tile) => {
tile.roads = [];
tile.settlements = [];
tile.jitter = Math.random() - 0.5;
});
this.closest.tile = null;
window.requestAnimationFrame(this.drawFrame);
}
keyUp(event) { keyUp(event) {
if (event.keyCode === 78) { /* n */
this.randomize();
return;
}
if (event.keyCode === 32) { /* space */
this.throwDice();
return;
}
} }
setGameState(state) { setGameState(state) {
@ -594,7 +606,7 @@ class Board extends React.Component {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}).then((res) => { }).then((res) => {
if (res.status > 400) { if (res.status >= 400) {
console.log(res); console.log(res);
throw new Error(`Unable to set state to ${state}`); throw new Error(`Unable to set state to ${state}`);
} }
@ -602,10 +614,10 @@ class Board extends React.Component {
}).then((game) => { }).then((game) => {
console.log (`Game state set to ${game.state}!`); console.log (`Game state set to ${game.state}!`);
this.game = game; this.game = game;
this.setState({ game: { ...this.state.game, state: game.state }} ); this.setState({ game: { ...this.state.game, state: game.state }, message: ""} );
}).catch((error) => { }).catch((error) => {
console.error(error); console.error(error);
alert(error); this.setState({message: error.message});
}).then(() => { }).then(() => {
this.resetGameLoad(); this.resetGameLoad();
return this.game.state; return this.game.state;
@ -754,11 +766,13 @@ class Board extends React.Component {
this.width = window.innerWidth; this.width = window.innerWidth;
this.height = height; this.height = height;
this.canvas.width = this.width; if (this.canvas) {
this.canvas.height = this.height; this.canvas.width = this.width;
this.canvas.style.top = `${offset}px`; this.canvas.height = this.height;
this.canvas.style.width = `${this.width}px`; this.canvas.style.top = `${offset}px`;
this.canvas.style.height = `${this.height}px`; this.canvas.style.width = `${this.width}px`;
this.canvas.style.height = `${this.height}px`;
}
this.cards.style.top = `${offset}px`; this.cards.style.top = `${offset}px`;
this.cards.style.width = `${this.width}px`; this.cards.style.width = `${this.width}px`;
this.cards.style.height = `${this.heigh}tpx`; this.cards.style.height = `${this.heigh}tpx`;
@ -1158,26 +1172,42 @@ class Board extends React.Component {
}, },
// body: JSON.stringify(data) // body data type must match "Content-Type" header // body: JSON.stringify(data) // body data type must match "Content-Type" header
}).then((res) => { }).then((res) => {
if (res.status > 400) { if (res.status < 400) {
let message; return res;
if (this.id) { }
message = `Unable to find game ${this.id}. Starting new game.`; let message;
} else { if (!this.id) {
message = `Starting new game.`; message = `Unable to create new game.`;
}
console.log(message);
throw new Error(message); throw new Error(message);
} }
message = `Unable to find game ${this.id}. Starting new game.`
console.log(message);
this.setState({ message: message });
params.url = `${base}/api/v1/games`;
params.method = "POST";
return window.fetch(params.url, {
method: params.method,
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
}
});
}).then((res) => {
return res.json(); return res.json();
}).then((game) => { }).then((game) => {
console.log (`Game ${game.id} loaded.`); console.log (`Game ${game.id} loaded ${moment().format()}.`);
if (!this.id) { if (!this.id) {
history.push(`${gamesPath}/${game.id}`); history.push(`${gamesPath}/${game.id}`);
} }
this.game = game; this.game = game;
this.setState({ game: game }); this.setState({ game: game, message: "" });
this.pips = Pips(this); this.pips = Pips(this);
this.tiles = Tiles(this); this.tiles = Tiles(this);
this.table = Table(this); this.table = Table(this);
@ -1187,7 +1217,7 @@ class Board extends React.Component {
}); });
}).catch((error) => { }).catch((error) => {
console.error(error); console.error(error);
alert(error); this.setState({message: error.message});
}).then(() => { }).then(() => {
this.resetGameLoad(); this.resetGameLoad();
}); });
@ -1196,6 +1226,9 @@ class Board extends React.Component {
} }
componentWillUnmount() { componentWillUnmount() {
if (this.loadTimer) {
clearTimeout(this.loadTimer);
}
if (this.updateSizeTimer) { if (this.updateSizeTimer) {
clearTimeout(this.updateSizeTimer); clearTimeout(this.updateSizeTimer);
this.updateSizeTimer = 0; this.updateSizeTimer = 0;
@ -1214,9 +1247,10 @@ class Board extends React.Component {
<div className="Cards" ref={el => this.cards = el}> <div className="Cards" ref={el => this.cards = el}>
{ game && { game &&
<div className="Game"> <div className="Game">
<Players game={game} promoteGameState={this.promoteGameState}/> <Players board={this} promoteGameState={this.promoteGameState}/>
<Chat game={game} promoteGameState={this.promoteGameState}/> <Chat board={this} promoteGameState={this.promoteGameState}/>
<Action game={game} promoteGameState={this.promoteGameState}/> <Action board={this}/>
{ this.state.message != "" && <Paper><div style={{align:"left",fontSize:"8pt"}}>{this.state.message}</div></Paper> }
</div> </div>
} }
<div>In hand</div> <div>In hand</div>

View File

@ -120,17 +120,45 @@ const roll = (game, player) => {
} }
} }
router.put("/:id/:action", (req, res) => { router.put("/:id/:action/:value?", (req, res) => {
console.log(`PUT games/${req.params.id}/${req.params.action}`); console.log(`PUT games/${req.params.id}/${req.params.action}`);
if (!req.params.action in games) { if (!req.params.action in games) {
const error = `Game not found: ${req.params.id}`; const error = `Game not found: ${req.params.id}`;
return res.status(404).send(error); return res.status(404).send(error);
} }
const game = games[req.params.id]; const game = games[req.params.id];
if (!req.session.activePlayer || !req.session.activePlayer in game.players) {
const error = `Invalid player: ${req.session.activePlayer}`;
return res.status(404).send(error);
}
const player = game.players[req.session.activePlayer].name;
switch (req.params.action) { switch (req.params.action) {
case "roll": case "roll":
roll(game, req.session.activePlayer); roll(game, player);
break; break;
case "shuffle":
if (game.state === "lobby") {
shuffleBoard(game);
const message = `${player} requested a new board.`;
game.chat.push({ date: Date.now(), message: message });
console.log(message);
return sendGame(res, req, game);
} else {
const error = `Game no longer in lobby (${game.state}). Can not shuffle board.`;
return res.status(400).send(error)
}
case "state":
const state = req.params.value ? req.params.value : "active";
if (state != game.state) {
game.state = state;
const message = `${player} set game state to ${state}.`;
game.chat.push({ date: Date.now(), message: message });
}
return sendGame(res, req, game);
} }
return sendGame(res, req, game); return sendGame(res, req, game);
@ -230,6 +258,14 @@ router.post("/", (req, res/*, next*/) => {
id: crypto.randomBytes(8).toString('hex') id: crypto.randomBytes(8).toString('hex')
}; };
games[game.id] = game;
req.session.activePlayer = null;
shuffleBoard(game);
console.log(`New game created: ${game.id}`);
return sendGame(res, req, game);
});
const shuffleBoard = (game) => {
[ "tiles", "pips", "borders" ].forEach((field) => { [ "tiles", "pips", "borders" ].forEach((field) => {
game[field] = [] game[field] = []
for (let i = 0; i < assetData[field].length; i++) { for (let i = 0; i < assetData[field].length; i++) {
@ -244,13 +280,7 @@ router.post("/", (req, res/*, next*/) => {
}); });
shuffle(game.developmentCards) shuffle(game.developmentCards)
}
games[game.id] = game;
console.log(`New game created: ${game.id}`);
return sendGame(res, req, game);
});
/* /*
return gameDB.sequelize.query("SELECT " + return gameDB.sequelize.query("SELECT " +