Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/client/game/admin-dialogs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export function NotificationDialog(props: NotificationDialogProps) {
className={buttonColor()}
intent="primary"
onClick={() => {
close();
setIsOpen(false);
}}
/>
);
Expand Down
18 changes: 7 additions & 11 deletions src/client/game/game.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,12 @@ export function Game(): JSX.Element {
"game-state",
async () => {
return get("/game-state").then((gameState) => {
setChess(new ChessEngine(gameState.position));
if (gameState.gameEndReason !== undefined) {
setGameInterruptedReason(gameState.gameEndReason);
setChess(new ChessEngine(gameState.state.position));
setPause(gameState.pause);
if (gameState.state.gameEndReason !== undefined) {
setGameInterruptedReason(gameState.state.gameEndReason);
}
return gameState;
return gameState.state;
});
},
false,
Expand Down Expand Up @@ -161,12 +162,7 @@ export function Game(): JSX.Element {
: null
: null;

const gamePauseDialog =
gameHoldReason !== undefined ?
gameHoldReason === GameHoldReason.GAME_PAUSED ?
<PauseDialog />
: null
: null;
const gamePauseDialog = paused ? <PauseDialog /> : null;

const gameUnpauseDialog =
gameHoldReason !== undefined ?
Expand All @@ -177,7 +173,7 @@ export function Game(): JSX.Element {

/** make moves by making a copy of the chessboard and sending the move message */
const handleMove =
paused ?
!paused ?
(move: Move): void => {
setChess(chess.copy(move));
sendMessage(new MoveMessage(move));
Expand Down
64 changes: 49 additions & 15 deletions src/server/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,16 @@
SpinRadiansCommand,
} from "../command/move-command";
import { GridIndices } from "../robot/grid-indices";
import { puzzles, type PuzzleComponents } from "./puzzles";
import {
moveAllRobotsHomeToDefaultOptimized,
moveAllRobotsToDefaultPositions,
moveAllRobotsFromBoardToHome,
} from "../robot/path-materializer";
import type { PuzzleComponents } from "./puzzles";
import { puzzles } from "./puzzles";
import { tcpServer } from "./tcp-interface";
import { robotManager } from "../robot/robot-manager";
import { executor } from "../command/executor";
import { GameHoldReason } from "../../common/game-end-reasons";

/**
* Helper function to move all robots from their home positions to their default positions
Expand All @@ -76,7 +77,7 @@
moveAllRobotsToDefaultPositions(defaultPositionsMap);
await executor.execute(command);
} else {
setAllRobotsToDefaultPositions(defaultPositionsMap);
moveAllRobotsToDefaultPositions(defaultPositionsMap);
}
} else {
if (isMoving) {
Expand Down Expand Up @@ -186,6 +187,17 @@
),
);
}
const robotPos = new Map(
oldSave!.robotPos?.map<[string, GridIndices]>((obj) => [
obj[1],
new GridIndices(
parseInt(obj[0].split(", ")[0]),
parseInt(obj[0].split(", ")[1]),
),
]),
);
console.log(robotPos);
setAllRobotsToDefaultPositions(robotPos);
}
/**
* Note the client currently redirects to home from the game over screen
Expand All @@ -210,7 +222,10 @@
return res.status(400).send({ message: "No game is currently active" });
}
const clientType = clientManager.getClientType(req.cookies.id);
return res.send(gameManager.getGameState(clientType));
return res.send({
state: gameManager.getGameState(clientType),
pause: gamePaused.flag,
});
});

/**
Expand Down Expand Up @@ -285,7 +300,6 @@
const fen = puzzle.fen;
const moves = puzzle.moves;
const difficulty = puzzle.rating;
const tooltip = puzzle.tooltip;

if (puzzle.robotDefaultPositions) {
// Convert puzzle.robotDefaultPositions from Record<string, string> to Map<string, GridIndices>
Expand Down Expand Up @@ -322,7 +336,7 @@
new ChessEngine(),
socketManager,
fen,
tooltip,
"",
moves,
difficulty,
),
Expand All @@ -331,15 +345,6 @@
return res.send({ message: "success" });
});

/**
* Returns robots to home after a game ends.
*/
apiRouter.post("/return-home", async (_req, res) => {
const command = moveAllRobotsFromBoardToHome();
await executor.execute(command);
return res.send({ message: "success" });
});

/**
* Returns all registered robot ids
*/
Expand Down Expand Up @@ -568,8 +573,37 @@

/**
* Unpause the game
* Todo: add authentication instead of an exposed unpause call
*/
apiRouter.get("/unpause-game", async (_, res) => {
if (gamePaused.flag) {
gamePaused.flag = false;
const ids = clientManager.getIds();
if (ids) {
const oldSave = SaveManager.loadGame(ids[0]);
gameManager?.chess.loadFen(oldSave!.oldPos);
setAllRobotsToDefaultPositions(
new Map(
oldSave!.oldRobotPos?.map<[string, GridIndices]>((obj) => [
obj[1],
new GridIndices(
parseInt(obj[0].split(", ")[0]),
parseInt(obj[0].split(", ")[1]),
),
]),
),
);
socketManager.sendToAll(new SetChessMessage(oldSave!.oldPos));
}
socketManager.sendToAll(
new GameHoldMessage(GameHoldReason.GAME_UNPAUSED),
);
return res.send({ message: "success" });
} else {
return res.send({ message: "game not paused" });
}
* Resumes any leftover commands queued in the command executor

Check failure on line 605 in src/server/api/api.ts

View workflow job for this annotation

GitHub Actions / type-check

';' expected.

Check failure on line 605 in src/server/api/api.ts

View workflow job for this annotation

GitHub Actions / type-check

Unexpected keyword or identifier.

Check failure on line 605 in src/server/api/api.ts

View workflow job for this annotation

GitHub Actions / type-check

Unexpected keyword or identifier.

Check failure on line 605 in src/server/api/api.ts

View workflow job for this annotation

GitHub Actions / type-check

';' expected.

Check failure on line 605 in src/server/api/api.ts

View workflow job for this annotation

GitHub Actions / type-check

Expression expected.
* Todo: add authentication instead of an exposed unpause call

Check failure on line 606 in src/server/api/api.ts

View workflow job for this annotation

GitHub Actions / type-check

Unexpected keyword or identifier.

Check failure on line 606 in src/server/api/api.ts

View workflow job for this annotation

GitHub Actions / type-check

Unexpected keyword or identifier.

Check failure on line 606 in src/server/api/api.ts

View workflow job for this annotation

GitHub Actions / type-check

Unexpected keyword or identifier.

Check failure on line 606 in src/server/api/api.ts

View workflow job for this annotation

GitHub Actions / type-check

Unexpected keyword or identifier.

Check failure on line 606 in src/server/api/api.ts

View workflow job for this annotation

GitHub Actions / type-check

';' expected.
*/
apiRouter.get("/unpause-game", async (_, res) => {
return res.send(unpauseGame(true));
Expand Down
7 changes: 7 additions & 0 deletions src/server/api/game-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { SaveManager } from "./save-manager";
import { materializePath } from "../robot/path-materializer";
import { DO_SAVES } from "../utils/env";
import { executor } from "../command/executor";
import { robotManager } from "../robot/robot-manager";
import { gamePaused } from "./managers";

type GameState = {
Expand Down Expand Up @@ -164,6 +165,8 @@ export class HumanGameManager extends GameManager {
this.hostSide,
-1,
this.chess.pgn,
this.chess.fen,
robotManager.getIndicesToIds(),
);
} else {
SaveManager.saveGame(
Expand All @@ -172,6 +175,8 @@ export class HumanGameManager extends GameManager {
oppositeSide(this.hostSide),
-1,
this.chess.pgn,
this.chess.fen,
robotManager.getIndicesToIds(),
);
}
}
Expand Down Expand Up @@ -282,6 +287,8 @@ export class ComputerGameManager extends GameManager {
this.hostSide,
this.difficulty,
this.chess.pgn,
this.chess.fen,
robotManager.getIndicesToIds(),
);
}

Expand Down
23 changes: 20 additions & 3 deletions src/server/api/save-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/

import { Side } from "../../common/game-types";
2;

// Save files contain a date in ms and pgn string
export interface iSave {
Expand All @@ -19,6 +20,10 @@ export interface iSave {
hostWhite: boolean;
aiDifficulty: number;
game: string;
pos: string;
robotPos: Array<[string, string]>;
oldPos: string;
oldRobotPos: Array<[string, string]>;
}

export class SaveManager {
Expand All @@ -27,9 +32,9 @@ export class SaveManager {
*
* Finds or creates a save file
* Save name is host id + client id
* Saves include the game start time and save pgn as json
*
* Input: host id, client id, game pgn
* Saves include the game start time and save fen as json
* Robots are saved as a map of indices to robots
* Input: host id, client id, game fen, robots
* Output: boolean competed
*/
public static saveGame(
Expand All @@ -38,16 +43,28 @@ export class SaveManager {
hostSide: Side,
aiDiff: number,
pgn: string,
fen: string,
robots: Map<string, string>,
) {
const day = new Date().getTime();
const side = hostSide === Side.WHITE;
console.log(JSON.stringify(robots));
const saveContents = {
host: hostId,
date: day,
hostWhite: side,
aiDifficulty: aiDiff,
game: pgn,
pos: fen,
robotPos: Array.from(robots),
oldPos: "",
oldRobotPos: Array<[string, string]>(),
};
const oldGame = SaveManager.loadGame(hostId + "+" + clientID);
if (oldGame && oldGame.pos !== null) {
saveContents.oldPos = oldGame.pos;
saveContents.oldRobotPos = oldGame.robotPos;
}
return FileManager.writeFile(hostId + "+" + clientID, saveContents);
}

Expand Down
9 changes: 7 additions & 2 deletions src/server/command/command.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { gamePaused } from "../api/managers";
import { robotManager } from "../robot/robot-manager";

/**
Expand Down Expand Up @@ -112,7 +113,9 @@ function isReversable(obj): obj is Reversible<typeof obj> {
*/
export class ParallelCommandGroup extends CommandGroup {
public async execute(): Promise<void> {
const promises = this.commands.map((move) => move.execute());
const promises = this.commands.map((move) => {
gamePaused.flag ? null : move.execute();
});
return Promise.all(promises).then(null);
}
public async reverse(): Promise<void> {
Expand All @@ -132,7 +135,9 @@ export class SequentialCommandGroup extends CommandGroup {
public async execute(): Promise<void> {
let promise = Promise.resolve();
for (const command of this.commands) {
promise = promise.then(() => command.execute());
promise = promise.then(() => {
gamePaused.flag ? null : command.execute();
});
}
return promise;
}
Expand Down
6 changes: 6 additions & 0 deletions src/server/robot/robot-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ export class RobotManager {
}
indicesToIds.set(indices.toString(), robotId);
}

stopAllRobots() {
Array.from(this.idsToRobots.values()).forEach((robot) => {
robot.sendStopPacket();
});
}
}

export const robotManager = new RobotManager(
Expand Down
6 changes: 6 additions & 0 deletions src/server/robot/robot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,10 @@ export class Robot {
timeDeltaMs: timeDeltaMs,
});
}

public async sendStopPacket(): Promise<void> {
await this.tunnel!.send({
type: PacketType.ESTOP,
});
}
}
Loading