some more type hinting etc
This commit is contained in:
parent
432e1b6668
commit
ee7804a594
18 changed files with 161 additions and 150 deletions
File diff suppressed because one or more lines are too long
1
build/public/assets/index.85898c1b.js
Normal file
1
build/public/assets/index.85898c1b.js
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -2,7 +2,7 @@
|
||||||
<head>
|
<head>
|
||||||
|
|
||||||
<title>🧩 jigsaw.hyottoko.club</title>
|
<title>🧩 jigsaw.hyottoko.club</title>
|
||||||
<script type="module" crossorigin src="/assets/index.2f18bf13.js"></script>
|
<script type="module" crossorigin src="/assets/index.85898c1b.js"></script>
|
||||||
<link rel="modulepreload" href="/assets/vendor.00b608ff.js">
|
<link rel="modulepreload" href="/assets/vendor.00b608ff.js">
|
||||||
<link rel="stylesheet" href="/assets/index.421011a7.css">
|
<link rel="stylesheet" href="/assets/index.421011a7.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -74,9 +74,6 @@ const logger = (...pre) => {
|
||||||
// get a unique id
|
// get a unique id
|
||||||
const uniqId = () => Date.now().toString(36) + Math.random().toString(36).substring(2);
|
const uniqId = () => Date.now().toString(36) + Math.random().toString(36).substring(2);
|
||||||
function encodeShape(data) {
|
function encodeShape(data) {
|
||||||
if (typeof data === 'number') {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
/* encoded in 1 byte:
|
/* encoded in 1 byte:
|
||||||
00000000
|
00000000
|
||||||
^^ top
|
^^ top
|
||||||
|
|
@ -90,9 +87,6 @@ function encodeShape(data) {
|
||||||
| ((data.left + 1) << 6);
|
| ((data.left + 1) << 6);
|
||||||
}
|
}
|
||||||
function decodeShape(data) {
|
function decodeShape(data) {
|
||||||
if (typeof data !== 'number') {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
top: (data >> 0 & 0b11) - 1,
|
top: (data >> 0 & 0b11) - 1,
|
||||||
right: (data >> 2 & 0b11) - 1,
|
right: (data >> 2 & 0b11) - 1,
|
||||||
|
|
@ -101,15 +95,9 @@ function decodeShape(data) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function encodeTile(data) {
|
function encodeTile(data) {
|
||||||
if (Array.isArray(data)) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
return [data.idx, data.pos.x, data.pos.y, data.z, data.owner, data.group];
|
return [data.idx, data.pos.x, data.pos.y, data.z, data.owner, data.group];
|
||||||
}
|
}
|
||||||
function decodeTile(data) {
|
function decodeTile(data) {
|
||||||
if (!Array.isArray(data)) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
idx: data[0],
|
idx: data[0],
|
||||||
pos: {
|
pos: {
|
||||||
|
|
@ -122,9 +110,6 @@ function decodeTile(data) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function encodePlayer(data) {
|
function encodePlayer(data) {
|
||||||
if (Array.isArray(data)) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
return [
|
return [
|
||||||
data.id,
|
data.id,
|
||||||
data.x,
|
data.x,
|
||||||
|
|
@ -138,9 +123,6 @@ function encodePlayer(data) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
function decodePlayer(data) {
|
function decodePlayer(data) {
|
||||||
if (!Array.isArray(data)) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
id: data[0],
|
id: data[0],
|
||||||
x: data[1],
|
x: data[1],
|
||||||
|
|
@ -461,8 +443,17 @@ var Time = {
|
||||||
durationStr,
|
durationStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SCORE_MODE_FINAL = 0;
|
var PieceEdge;
|
||||||
const SCORE_MODE_ANY = 1;
|
(function (PieceEdge) {
|
||||||
|
PieceEdge[PieceEdge["Flat"] = 0] = "Flat";
|
||||||
|
PieceEdge[PieceEdge["Out"] = 1] = "Out";
|
||||||
|
PieceEdge[PieceEdge["In"] = -1] = "In";
|
||||||
|
})(PieceEdge || (PieceEdge = {}));
|
||||||
|
var ScoreMode;
|
||||||
|
(function (ScoreMode) {
|
||||||
|
ScoreMode[ScoreMode["FINAL"] = 0] = "FINAL";
|
||||||
|
ScoreMode[ScoreMode["ANY"] = 1] = "ANY";
|
||||||
|
})(ScoreMode || (ScoreMode = {}));
|
||||||
const IDLE_TIMEOUT_SEC = 30;
|
const IDLE_TIMEOUT_SEC = 30;
|
||||||
// Map<gameId, Game>
|
// Map<gameId, Game>
|
||||||
const GAMES = {};
|
const GAMES = {};
|
||||||
|
|
@ -502,11 +493,11 @@ function getPlayerIdByIndex(gameId, playerIndex) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
function getPlayer(gameId, playerId) {
|
function getPlayer(gameId, playerId) {
|
||||||
let idx = getPlayerIndexById(gameId, playerId);
|
const idx = getPlayerIndexById(gameId, playerId);
|
||||||
return Util.decodePlayer(GAMES[gameId].players[idx]);
|
return Util.decodePlayer(GAMES[gameId].players[idx]);
|
||||||
}
|
}
|
||||||
function setPlayer(gameId, playerId, player) {
|
function setPlayer(gameId, playerId, player) {
|
||||||
let idx = getPlayerIndexById(gameId, playerId);
|
const idx = getPlayerIndexById(gameId, playerId);
|
||||||
if (idx === -1) {
|
if (idx === -1) {
|
||||||
GAMES[gameId].players.push(Util.encodePlayer(player));
|
GAMES[gameId].players.push(Util.encodePlayer(player));
|
||||||
}
|
}
|
||||||
|
|
@ -580,7 +571,7 @@ function setImageUrl(gameId, imageUrl) {
|
||||||
GAMES[gameId].puzzle.info.imageUrl = imageUrl;
|
GAMES[gameId].puzzle.info.imageUrl = imageUrl;
|
||||||
}
|
}
|
||||||
function getScoreMode(gameId) {
|
function getScoreMode(gameId) {
|
||||||
return GAMES[gameId].scoreMode || SCORE_MODE_FINAL;
|
return GAMES[gameId].scoreMode || ScoreMode.FINAL;
|
||||||
}
|
}
|
||||||
function isFinished(gameId) {
|
function isFinished(gameId) {
|
||||||
return getFinishedTileCount(gameId) === getTileCount(gameId);
|
return getFinishedTileCount(gameId) === getTileCount(gameId);
|
||||||
|
|
@ -601,6 +592,7 @@ function getTilesSortedByZIndex(gameId) {
|
||||||
function changePlayer(gameId, playerId, change) {
|
function changePlayer(gameId, playerId, change) {
|
||||||
const player = getPlayer(gameId, playerId);
|
const player = getPlayer(gameId, playerId);
|
||||||
for (let k of Object.keys(change)) {
|
for (let k of Object.keys(change)) {
|
||||||
|
// @ts-ignore
|
||||||
player[k] = change[k];
|
player[k] = change[k];
|
||||||
}
|
}
|
||||||
setPlayer(gameId, playerId, player);
|
setPlayer(gameId, playerId, player);
|
||||||
|
|
@ -614,6 +606,7 @@ function changeData(gameId, change) {
|
||||||
function changeTile(gameId, tileIdx, change) {
|
function changeTile(gameId, tileIdx, change) {
|
||||||
for (let k of Object.keys(change)) {
|
for (let k of Object.keys(change)) {
|
||||||
const tile = Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx]);
|
const tile = Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx]);
|
||||||
|
// @ts-ignore
|
||||||
tile[k] = change[k];
|
tile[k] = change[k];
|
||||||
GAMES[gameId].puzzle.tiles[tileIdx] = Util.encodeTile(tile);
|
GAMES[gameId].puzzle.tiles[tileIdx] = Util.encodeTile(tile);
|
||||||
}
|
}
|
||||||
|
|
@ -832,7 +825,7 @@ const getPlayerName = (gameId, playerId) => {
|
||||||
};
|
};
|
||||||
const getPlayerPoints = (gameId, playerId) => {
|
const getPlayerPoints = (gameId, playerId) => {
|
||||||
const p = getPlayer(gameId, playerId);
|
const p = getPlayer(gameId, playerId);
|
||||||
return p ? p.points : null;
|
return p ? p.points : 0;
|
||||||
};
|
};
|
||||||
// determine if two tiles are grouped together
|
// determine if two tiles are grouped together
|
||||||
const areGrouped = (gameId, tileIdx1, tileIdx2) => {
|
const areGrouped = (gameId, tileIdx1, tileIdx2) => {
|
||||||
|
|
@ -1023,10 +1016,10 @@ function handleInput$1(gameId, playerId, input, ts) {
|
||||||
finishTiles(gameId, tileIdxs);
|
finishTiles(gameId, tileIdxs);
|
||||||
_tileChanges(tileIdxs);
|
_tileChanges(tileIdxs);
|
||||||
let points = getPlayerPoints(gameId, playerId);
|
let points = getPlayerPoints(gameId, playerId);
|
||||||
if (getScoreMode(gameId) === SCORE_MODE_FINAL) {
|
if (getScoreMode(gameId) === ScoreMode.FINAL) {
|
||||||
points += tileIdxs.length;
|
points += tileIdxs.length;
|
||||||
}
|
}
|
||||||
else if (getScoreMode(gameId) === SCORE_MODE_ANY) {
|
else if (getScoreMode(gameId) === ScoreMode.ANY) {
|
||||||
points += 1;
|
points += 1;
|
||||||
}
|
}
|
||||||
else ;
|
else ;
|
||||||
|
|
@ -1075,7 +1068,7 @@ function handleInput$1(gameId, playerId, input, ts) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (snapped && getScoreMode(gameId) === SCORE_MODE_ANY) {
|
if (snapped && getScoreMode(gameId) === ScoreMode.ANY) {
|
||||||
const points = getPlayerPoints(gameId, playerId) + 1;
|
const points = getPlayerPoints(gameId, playerId) + 1;
|
||||||
changePlayer(gameId, playerId, { d, ts, points });
|
changePlayer(gameId, playerId, { d, ts, points });
|
||||||
_playerChange();
|
_playerChange();
|
||||||
|
|
@ -1150,8 +1143,6 @@ var GameCommon = {
|
||||||
getStartTs,
|
getStartTs,
|
||||||
getFinishTs,
|
getFinishTs,
|
||||||
handleInput: handleInput$1,
|
handleInput: handleInput$1,
|
||||||
SCORE_MODE_FINAL,
|
|
||||||
SCORE_MODE_ANY,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
|
@ -1343,7 +1334,7 @@ async function createPuzzle(rng, targetTiles, image, ts) {
|
||||||
}
|
}
|
||||||
// then shuffle the positions
|
// then shuffle the positions
|
||||||
positions = rng.shuffle(positions);
|
positions = rng.shuffle(positions);
|
||||||
tiles = tiles.map(tile => {
|
const pieces = tiles.map(tile => {
|
||||||
return Util.encodeTile({
|
return Util.encodeTile({
|
||||||
idx: tile.idx,
|
idx: tile.idx,
|
||||||
group: 0,
|
group: 0,
|
||||||
|
|
@ -1362,7 +1353,7 @@ async function createPuzzle(rng, targetTiles, image, ts) {
|
||||||
// Complete puzzle object
|
// Complete puzzle object
|
||||||
return {
|
return {
|
||||||
// tiles array
|
// tiles array
|
||||||
tiles,
|
tiles: pieces,
|
||||||
// game data for puzzle, data changes during the game
|
// game data for puzzle, data changes during the game
|
||||||
data: {
|
data: {
|
||||||
// TODO: maybe calculate this each time?
|
// TODO: maybe calculate this each time?
|
||||||
|
|
@ -1500,7 +1491,7 @@ function loadGame(gameId) {
|
||||||
puzzle: game.puzzle,
|
puzzle: game.puzzle,
|
||||||
players: game.players,
|
players: game.players,
|
||||||
evtInfos: {},
|
evtInfos: {},
|
||||||
scoreMode: game.scoreMode || GameCommon.SCORE_MODE_FINAL,
|
scoreMode: game.scoreMode || ScoreMode.FINAL,
|
||||||
};
|
};
|
||||||
GameCommon.setGame(gameObject.id, gameObject);
|
GameCommon.setGame(gameObject.id, gameObject);
|
||||||
}
|
}
|
||||||
|
|
@ -1746,7 +1737,7 @@ wss.on('message', async ({ socket, data }) => {
|
||||||
throw `[gamelog ${gameId} does not exist... ]`;
|
throw `[gamelog ${gameId} does not exist... ]`;
|
||||||
}
|
}
|
||||||
const log = GameLog.get(gameId);
|
const log = GameLog.get(gameId);
|
||||||
const game = await Game.createGameObject(gameId, log[0][2], log[0][3], log[0][4], log[0][5] || GameCommon.SCORE_MODE_FINAL);
|
const game = await Game.createGameObject(gameId, log[0][2], log[0][3], log[0][4], log[0][5] || ScoreMode.FINAL);
|
||||||
notify([Protocol.EV_SERVER_INIT_REPLAY, Util.encodeGame(game), log], [socket]);
|
notify([Protocol.EV_SERVER_INIT_REPLAY, Util.encodeGame(game), log], [socket]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,12 @@
|
||||||
import Geometry from './Geometry'
|
import Geometry, { Point, Rect } from './Geometry'
|
||||||
import Protocol from './Protocol'
|
import Protocol from './Protocol'
|
||||||
import { Rng } from './Rng'
|
import { Rng } from './Rng'
|
||||||
import Time from './Time'
|
import Time from './Time'
|
||||||
import Util from './Util'
|
import Util from './Util'
|
||||||
|
|
||||||
interface EncodedPlayer extends Array<any> {}
|
export type EncodedPlayer = Array<any>
|
||||||
interface EncodedPiece extends Array<any> {}
|
export type EncodedPiece = Array<any>
|
||||||
|
export type EncodedPieceShape = number
|
||||||
interface Point {
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GameRng {
|
interface GameRng {
|
||||||
obj: Rng
|
obj: Rng
|
||||||
|
|
@ -22,7 +18,7 @@ interface Game {
|
||||||
players: Array<EncodedPlayer>
|
players: Array<EncodedPlayer>
|
||||||
puzzle: Puzzle
|
puzzle: Puzzle
|
||||||
evtInfos: Record<string, EvtInfo>
|
evtInfos: Record<string, EvtInfo>
|
||||||
scoreMode?: number
|
scoreMode?: ScoreMode
|
||||||
rng: GameRng
|
rng: GameRng
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,15 +40,24 @@ interface PuzzleTable {
|
||||||
height: number
|
height: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PieceEdge {
|
||||||
|
Flat = 0,
|
||||||
|
Out = 1,
|
||||||
|
In = -1,
|
||||||
|
}
|
||||||
export interface PieceShape {
|
export interface PieceShape {
|
||||||
top: 0|1|-1
|
top: PieceEdge
|
||||||
bottom: 0|1|-1
|
bottom: PieceEdge
|
||||||
left: 0|1|-1
|
left: PieceEdge
|
||||||
right: 0|1|-1
|
right: PieceEdge
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Piece {
|
export interface Piece {
|
||||||
owner: string|number
|
owner: string|number
|
||||||
|
idx: number
|
||||||
|
pos: Point
|
||||||
|
z: number
|
||||||
|
group: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PuzzleInfo {
|
export interface PuzzleInfo {
|
||||||
|
|
@ -72,8 +77,7 @@ export interface PuzzleInfo {
|
||||||
tilesX: number
|
tilesX: number
|
||||||
tilesY: number
|
tilesY: number
|
||||||
|
|
||||||
// TODO: ts type Array<PieceShape>
|
shapes: Array<EncodedPieceShape>
|
||||||
shapes: Array<any>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Player {
|
export interface Player {
|
||||||
|
|
@ -93,8 +97,10 @@ interface EvtInfo {
|
||||||
_last_mouse_down: Point|null
|
_last_mouse_down: Point|null
|
||||||
}
|
}
|
||||||
|
|
||||||
const SCORE_MODE_FINAL = 0
|
export enum ScoreMode {
|
||||||
const SCORE_MODE_ANY = 1
|
FINAL = 0,
|
||||||
|
ANY = 1,
|
||||||
|
}
|
||||||
|
|
||||||
const IDLE_TIMEOUT_SEC = 30
|
const IDLE_TIMEOUT_SEC = 30
|
||||||
|
|
||||||
|
|
@ -134,20 +140,20 @@ function getPlayerIndexById(gameId: string, playerId: string): number {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPlayerIdByIndex(gameId: string, playerIndex: number) {
|
function getPlayerIdByIndex(gameId: string, playerIndex: number): string|null {
|
||||||
if (GAMES[gameId].players.length > playerIndex) {
|
if (GAMES[gameId].players.length > playerIndex) {
|
||||||
return Util.decodePlayer(GAMES[gameId].players[playerIndex]).id
|
return Util.decodePlayer(GAMES[gameId].players[playerIndex]).id
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPlayer(gameId: string, playerId: string) {
|
function getPlayer(gameId: string, playerId: string): Player {
|
||||||
let idx = getPlayerIndexById(gameId, playerId)
|
const idx = getPlayerIndexById(gameId, playerId)
|
||||||
return Util.decodePlayer(GAMES[gameId].players[idx])
|
return Util.decodePlayer(GAMES[gameId].players[idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPlayer(gameId: string, playerId: string, player: Player) {
|
function setPlayer(gameId: string, playerId: string, player: Player) {
|
||||||
let idx = getPlayerIndexById(gameId, playerId)
|
const idx = getPlayerIndexById(gameId, playerId)
|
||||||
if (idx === -1) {
|
if (idx === -1) {
|
||||||
GAMES[gameId].players.push(Util.encodePlayer(player))
|
GAMES[gameId].players.push(Util.encodePlayer(player))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -168,17 +174,17 @@ function playerExists(gameId: string, playerId: string) {
|
||||||
return idx !== -1
|
return idx !== -1
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActivePlayers(gameId: string, ts: number) {
|
function getActivePlayers(gameId: string, ts: number): Array<Player> {
|
||||||
const minTs = ts - IDLE_TIMEOUT_SEC * Time.SEC
|
const minTs = ts - IDLE_TIMEOUT_SEC * Time.SEC
|
||||||
return getAllPlayers(gameId).filter((p: Player) => p.ts >= minTs)
|
return getAllPlayers(gameId).filter((p: Player) => p.ts >= minTs)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIdlePlayers(gameId: string, ts: number) {
|
function getIdlePlayers(gameId: string, ts: number): Array<Player> {
|
||||||
const minTs = ts - IDLE_TIMEOUT_SEC * Time.SEC
|
const minTs = ts - IDLE_TIMEOUT_SEC * Time.SEC
|
||||||
return getAllPlayers(gameId).filter((p: Player) => p.ts < minTs && p.points > 0)
|
return getAllPlayers(gameId).filter((p: Player) => p.ts < minTs && p.points > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPlayer(gameId: string, playerId: string, ts: number) {
|
function addPlayer(gameId: string, playerId: string, ts: number): void {
|
||||||
if (!playerExists(gameId, playerId)) {
|
if (!playerExists(gameId, playerId)) {
|
||||||
setPlayer(gameId, playerId, __createPlayerObject(playerId, ts))
|
setPlayer(gameId, playerId, __createPlayerObject(playerId, ts))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -186,7 +192,7 @@ function addPlayer(gameId: string, playerId: string, ts: number) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEvtInfo(gameId: string, playerId: string) {
|
function getEvtInfo(gameId: string, playerId: string): EvtInfo {
|
||||||
if (playerId in GAMES[gameId].evtInfos) {
|
if (playerId in GAMES[gameId].evtInfos) {
|
||||||
return GAMES[gameId].evtInfos[playerId]
|
return GAMES[gameId].evtInfos[playerId]
|
||||||
}
|
}
|
||||||
|
|
@ -211,7 +217,7 @@ function getAllGames(): Array<Game> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAllPlayers(gameId: string) {
|
function getAllPlayers(gameId: string): Array<Player> {
|
||||||
return GAMES[gameId]
|
return GAMES[gameId]
|
||||||
? GAMES[gameId].players.map(Util.decodePlayer)
|
? GAMES[gameId].players.map(Util.decodePlayer)
|
||||||
: []
|
: []
|
||||||
|
|
@ -221,11 +227,11 @@ function get(gameId: string) {
|
||||||
return GAMES[gameId]
|
return GAMES[gameId]
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTileCount(gameId: string) {
|
function getTileCount(gameId: string): number {
|
||||||
return GAMES[gameId].puzzle.tiles.length
|
return GAMES[gameId].puzzle.tiles.length
|
||||||
}
|
}
|
||||||
|
|
||||||
function getImageUrl(gameId: string) {
|
function getImageUrl(gameId: string): string {
|
||||||
return GAMES[gameId].puzzle.info.imageUrl
|
return GAMES[gameId].puzzle.info.imageUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,8 +239,8 @@ function setImageUrl(gameId: string, imageUrl: string) {
|
||||||
GAMES[gameId].puzzle.info.imageUrl = imageUrl
|
GAMES[gameId].puzzle.info.imageUrl = imageUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
function getScoreMode(gameId: string) {
|
function getScoreMode(gameId: string): ScoreMode {
|
||||||
return GAMES[gameId].scoreMode || SCORE_MODE_FINAL
|
return GAMES[gameId].scoreMode || ScoreMode.FINAL
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFinished(gameId: string) {
|
function isFinished(gameId: string) {
|
||||||
|
|
@ -259,6 +265,7 @@ function getTilesSortedByZIndex(gameId: string) {
|
||||||
function changePlayer(gameId: string, playerId: string, change: any) {
|
function changePlayer(gameId: string, playerId: string, change: any) {
|
||||||
const player = getPlayer(gameId, playerId)
|
const player = getPlayer(gameId, playerId)
|
||||||
for (let k of Object.keys(change)) {
|
for (let k of Object.keys(change)) {
|
||||||
|
// @ts-ignore
|
||||||
player[k] = change[k]
|
player[k] = change[k]
|
||||||
}
|
}
|
||||||
setPlayer(gameId, playerId, player)
|
setPlayer(gameId, playerId, player)
|
||||||
|
|
@ -274,12 +281,13 @@ function changeData(gameId: string, change: any) {
|
||||||
function changeTile(gameId: string, tileIdx: number, change: any) {
|
function changeTile(gameId: string, tileIdx: number, change: any) {
|
||||||
for (let k of Object.keys(change)) {
|
for (let k of Object.keys(change)) {
|
||||||
const tile = Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx])
|
const tile = Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx])
|
||||||
|
// @ts-ignore
|
||||||
tile[k] = change[k]
|
tile[k] = change[k]
|
||||||
GAMES[gameId].puzzle.tiles[tileIdx] = Util.encodeTile(tile)
|
GAMES[gameId].puzzle.tiles[tileIdx] = Util.encodeTile(tile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTile = (gameId: string, tileIdx: number) => {
|
const getTile = (gameId: string, tileIdx: number): Piece => {
|
||||||
return Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx])
|
return Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -500,7 +508,7 @@ const freeTileIdxByPos = (gameId: string, pos: Point) => {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const collisionRect = {
|
const collisionRect: Rect = {
|
||||||
x: tile.pos.x,
|
x: tile.pos.x,
|
||||||
y: tile.pos.y,
|
y: tile.pos.y,
|
||||||
w: info.tileSize,
|
w: info.tileSize,
|
||||||
|
|
@ -531,9 +539,9 @@ const getPlayerName = (gameId: string, playerId: string) => {
|
||||||
return p ? p.name : null
|
return p ? p.name : null
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPlayerPoints = (gameId: string, playerId: string) => {
|
const getPlayerPoints = (gameId: string, playerId: string): number => {
|
||||||
const p = getPlayer(gameId, playerId)
|
const p = getPlayer(gameId, playerId)
|
||||||
return p ? p.points : null
|
return p ? p.points : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine if two tiles are grouped together
|
// determine if two tiles are grouped together
|
||||||
|
|
@ -746,13 +754,13 @@ function handleInput(gameId: string, playerId: string, input: any, ts: number) {
|
||||||
_tileChanges(tileIdxs)
|
_tileChanges(tileIdxs)
|
||||||
|
|
||||||
let points = getPlayerPoints(gameId, playerId)
|
let points = getPlayerPoints(gameId, playerId)
|
||||||
if (getScoreMode(gameId) === SCORE_MODE_FINAL) {
|
if (getScoreMode(gameId) === ScoreMode.FINAL) {
|
||||||
points += tileIdxs.length
|
points += tileIdxs.length
|
||||||
} else if (getScoreMode(gameId) === SCORE_MODE_ANY) {
|
} else if (getScoreMode(gameId) === ScoreMode.ANY) {
|
||||||
points += 1
|
points += 1
|
||||||
} else {
|
} else {
|
||||||
// no score mode... should never occur, because there is a
|
// no score mode... should never occur, because there is a
|
||||||
// fallback to SCORE_MODE_FINAL in getScoreMode function
|
// fallback to ScoreMode.FINAL in getScoreMode function
|
||||||
}
|
}
|
||||||
changePlayer(gameId, playerId, { d, ts, points })
|
changePlayer(gameId, playerId, { d, ts, points })
|
||||||
_playerChange()
|
_playerChange()
|
||||||
|
|
@ -809,7 +817,7 @@ function handleInput(gameId: string, playerId: string, input: any, ts: number) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (snapped && getScoreMode(gameId) === SCORE_MODE_ANY) {
|
if (snapped && getScoreMode(gameId) === ScoreMode.ANY) {
|
||||||
const points = getPlayerPoints(gameId, playerId) + 1
|
const points = getPlayerPoints(gameId, playerId) + 1
|
||||||
changePlayer(gameId, playerId, { d, ts, points })
|
changePlayer(gameId, playerId, { d, ts, points })
|
||||||
_playerChange()
|
_playerChange()
|
||||||
|
|
@ -881,6 +889,4 @@ export default {
|
||||||
getStartTs,
|
getStartTs,
|
||||||
getFinishTs,
|
getFinishTs,
|
||||||
handleInput,
|
handleInput,
|
||||||
SCORE_MODE_FINAL,
|
|
||||||
SCORE_MODE_ANY,
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,18 @@
|
||||||
interface Point {
|
export interface Point {
|
||||||
x: number
|
x: number
|
||||||
y: number
|
y: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Rect {
|
export interface Rect {
|
||||||
x: number
|
x: number
|
||||||
y: number
|
y: number
|
||||||
w: number
|
w: number
|
||||||
h: number
|
h: number
|
||||||
}
|
}
|
||||||
|
export interface Dim {
|
||||||
|
w: number
|
||||||
|
h: number
|
||||||
|
}
|
||||||
|
|
||||||
function pointSub(a: Point, b: Point): Point {
|
function pointSub(a: Point, b: Point): Point {
|
||||||
return { x: a.x - b.x, y: a.y - b.y }
|
return { x: a.x - b.x, y: a.y - b.y }
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ const MIN = SEC * 60
|
||||||
const HOUR = MIN * 60
|
const HOUR = MIN * 60
|
||||||
const DAY = HOUR * 24
|
const DAY = HOUR * 24
|
||||||
|
|
||||||
export const timestamp = () => {
|
export const timestamp = (): number => {
|
||||||
const d = new Date();
|
const d = new Date();
|
||||||
return Date.UTC(
|
return Date.UTC(
|
||||||
d.getUTCFullYear(),
|
d.getUTCFullYear(),
|
||||||
|
|
@ -17,7 +17,7 @@ export const timestamp = () => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const durationStr = (duration: number) => {
|
export const durationStr = (duration: number): string => {
|
||||||
const d = Math.floor(duration / DAY)
|
const d = Math.floor(duration / DAY)
|
||||||
duration = duration % DAY
|
duration = duration % DAY
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { EncodedPiece, EncodedPieceShape, EncodedPlayer, Piece, PieceShape, Player } from './GameCommon'
|
||||||
|
import { Point } from './Geometry'
|
||||||
import { Rng } from './Rng'
|
import { Rng } from './Rng'
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -27,10 +29,7 @@ export const logger = (...pre: Array<any>) => {
|
||||||
// get a unique id
|
// get a unique id
|
||||||
export const uniqId = () => Date.now().toString(36) + Math.random().toString(36).substring(2)
|
export const uniqId = () => Date.now().toString(36) + Math.random().toString(36).substring(2)
|
||||||
|
|
||||||
function encodeShape(data: any): number {
|
function encodeShape(data: PieceShape): EncodedPieceShape {
|
||||||
if (typeof data === 'number') {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
/* encoded in 1 byte:
|
/* encoded in 1 byte:
|
||||||
00000000
|
00000000
|
||||||
^^ top
|
^^ top
|
||||||
|
|
@ -44,10 +43,7 @@ function encodeShape(data: any): number {
|
||||||
| ((data.left + 1) << 6)
|
| ((data.left + 1) << 6)
|
||||||
}
|
}
|
||||||
|
|
||||||
function decodeShape(data: any) {
|
function decodeShape(data: EncodedPieceShape): PieceShape {
|
||||||
if (typeof data !== 'number') {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
top: (data >> 0 & 0b11) - 1,
|
top: (data >> 0 & 0b11) - 1,
|
||||||
right: (data >> 2 & 0b11) - 1,
|
right: (data >> 2 & 0b11) - 1,
|
||||||
|
|
@ -56,17 +52,11 @@ function decodeShape(data: any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function encodeTile(data: any): Array<any> {
|
function encodeTile(data: Piece): EncodedPiece {
|
||||||
if (Array.isArray(data)) {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
return [data.idx, data.pos.x, data.pos.y, data.z, data.owner, data.group]
|
return [data.idx, data.pos.x, data.pos.y, data.z, data.owner, data.group]
|
||||||
}
|
}
|
||||||
|
|
||||||
function decodeTile(data: any) {
|
function decodeTile(data: EncodedPiece): Piece {
|
||||||
if (!Array.isArray(data)) {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
idx: data[0],
|
idx: data[0],
|
||||||
pos: {
|
pos: {
|
||||||
|
|
@ -79,10 +69,7 @@ function decodeTile(data: any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function encodePlayer(data: any): Array<any> {
|
function encodePlayer(data: Player): EncodedPlayer {
|
||||||
if (Array.isArray(data)) {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
return [
|
return [
|
||||||
data.id,
|
data.id,
|
||||||
data.x,
|
data.x,
|
||||||
|
|
@ -96,10 +83,7 @@ function encodePlayer(data: any): Array<any> {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
function decodePlayer(data: any) {
|
function decodePlayer(data: EncodedPlayer): Player {
|
||||||
if (!Array.isArray(data)) {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
id: data[0],
|
id: data[0],
|
||||||
x: data[1],
|
x: data[1],
|
||||||
|
|
@ -145,7 +129,7 @@ function decodeGame(data: any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function coordByTileIdx(info: any, tileIdx: number) {
|
function coordByTileIdx(info: any, tileIdx: number): Point {
|
||||||
const wTiles = info.width / info.tileSize
|
const wTiles = info.width / info.tileSize
|
||||||
return {
|
return {
|
||||||
x: tileIdx % wTiles,
|
x: tileIdx % wTiles,
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,10 @@
|
||||||
|
import { Dim, Point } from "../common/Geometry"
|
||||||
|
|
||||||
const MIN_ZOOM = .1
|
const MIN_ZOOM = .1
|
||||||
const MAX_ZOOM = 6
|
const MAX_ZOOM = 6
|
||||||
const ZOOM_STEP = .05
|
const ZOOM_STEP = .05
|
||||||
|
|
||||||
type ZOOM_DIR = 'in'|'out'
|
type ZOOM_DIR = 'in'|'out'
|
||||||
interface Point {
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
}
|
|
||||||
interface Dim {
|
|
||||||
w: number
|
|
||||||
h: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Camera () {
|
export default function Camera () {
|
||||||
let x = 0
|
let x = 0
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,23 @@ async function loadImageToBitmap(imagePath: string): Promise<ImageBitmap> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resizeBitmap (bitmap: ImageBitmap, width: number, height: number): Promise<ImageBitmap> {
|
async function resizeBitmap (
|
||||||
|
bitmap: ImageBitmap,
|
||||||
|
width: number,
|
||||||
|
height: number
|
||||||
|
): Promise<ImageBitmap> {
|
||||||
const c = createCanvas(width, height)
|
const c = createCanvas(width, height)
|
||||||
const ctx = c.getContext('2d') as CanvasRenderingContext2D
|
const ctx = c.getContext('2d') as CanvasRenderingContext2D
|
||||||
ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, width, height)
|
ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, width, height)
|
||||||
return await createImageBitmap(c)
|
return await createImageBitmap(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function colorize(image: ImageBitmap, mask: ImageBitmap, color: string): Promise<ImageBitmap> {
|
async function colorize(
|
||||||
const c = createCanvas(image.width, image.height)
|
bitmap: ImageBitmap,
|
||||||
|
mask: ImageBitmap,
|
||||||
|
color: string
|
||||||
|
): Promise<ImageBitmap> {
|
||||||
|
const c = createCanvas(bitmap.width, bitmap.height)
|
||||||
const ctx = c.getContext('2d') as CanvasRenderingContext2D
|
const ctx = c.getContext('2d') as CanvasRenderingContext2D
|
||||||
ctx.save()
|
ctx.save()
|
||||||
ctx.drawImage(mask, 0, 0)
|
ctx.drawImage(mask, 0, 0)
|
||||||
|
|
@ -35,7 +43,7 @@ async function colorize(image: ImageBitmap, mask: ImageBitmap, color: string): P
|
||||||
ctx.restore()
|
ctx.restore()
|
||||||
ctx.save()
|
ctx.save()
|
||||||
ctx.globalCompositeOperation = "destination-over"
|
ctx.globalCompositeOperation = "destination-over"
|
||||||
ctx.drawImage(image, 0, 0)
|
ctx.drawImage(bitmap, 0, 0)
|
||||||
ctx.restore()
|
ctx.restore()
|
||||||
return await createImageBitmap(c)
|
return await createImageBitmap(c)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
"use strict"
|
"use strict"
|
||||||
|
|
||||||
import Geometry from '../common/Geometry'
|
import Geometry, { Rect } from '../common/Geometry'
|
||||||
import Graphics from './Graphics'
|
import Graphics from './Graphics'
|
||||||
import Util, { logger } from './../common/Util'
|
import Util, { logger } from './../common/Util'
|
||||||
import { Puzzle, PuzzleInfo, PieceShape } from './../common/GameCommon'
|
import { Puzzle, PuzzleInfo, PieceShape } from './../common/GameCommon'
|
||||||
|
|
||||||
const log = logger('PuzzleGraphics.js')
|
const log = logger('PuzzleGraphics.js')
|
||||||
|
|
||||||
async function createPuzzleTileBitmaps(img: ImageBitmap, tiles: Array<any>, info: PuzzleInfo) {
|
async function createPuzzleTileBitmaps(
|
||||||
|
img: ImageBitmap,
|
||||||
|
tiles: Array<any>,
|
||||||
|
info: PuzzleInfo
|
||||||
|
): Promise<Array<ImageBitmap>> {
|
||||||
log.log('start createPuzzleTileBitmaps')
|
log.log('start createPuzzleTileBitmaps')
|
||||||
var tileSize = info.tileSize
|
var tileSize = info.tileSize
|
||||||
var tileMarginWidth = info.tileMarginWidth
|
var tileMarginWidth = info.tileMarginWidth
|
||||||
|
|
@ -23,7 +27,7 @@ async function createPuzzleTileBitmaps(img: ImageBitmap, tiles: Array<any>, info
|
||||||
63, 5, 65, 15, 100, 0
|
63, 5, 65, 15, 100, 0
|
||||||
];
|
];
|
||||||
|
|
||||||
const bitmaps = new Array(tiles.length)
|
const bitmaps: Array<ImageBitmap> = new Array(tiles.length)
|
||||||
|
|
||||||
const paths: Record<string, Path2D> = {}
|
const paths: Record<string, Path2D> = {}
|
||||||
function pathForShape(shape: PieceShape) {
|
function pathForShape(shape: PieceShape) {
|
||||||
|
|
@ -89,7 +93,7 @@ async function createPuzzleTileBitmaps(img: ImageBitmap, tiles: Array<any>, info
|
||||||
const c2 = Graphics.createCanvas(tileDrawSize, tileDrawSize)
|
const c2 = Graphics.createCanvas(tileDrawSize, tileDrawSize)
|
||||||
const ctx2 = c2.getContext('2d') as CanvasRenderingContext2D
|
const ctx2 = c2.getContext('2d') as CanvasRenderingContext2D
|
||||||
|
|
||||||
for (let t of tiles) {
|
for (const t of tiles) {
|
||||||
const tile = Util.decodeTile(t)
|
const tile = Util.decodeTile(t)
|
||||||
const srcRect = srcRectByIdx(info, tile.idx)
|
const srcRect = srcRectByIdx(info, tile.idx)
|
||||||
const path = pathForShape(Util.decodeShape(info.shapes[tile.idx]))
|
const path = pathForShape(Util.decodeShape(info.shapes[tile.idx]))
|
||||||
|
|
@ -198,7 +202,7 @@ async function createPuzzleTileBitmaps(img: ImageBitmap, tiles: Array<any>, info
|
||||||
return bitmaps
|
return bitmaps
|
||||||
}
|
}
|
||||||
|
|
||||||
function srcRectByIdx(puzzleInfo: PuzzleInfo, idx: number) {
|
function srcRectByIdx(puzzleInfo: PuzzleInfo, idx: number): Rect {
|
||||||
const c = Util.coordByTileIdx(puzzleInfo, idx)
|
const c = Util.coordByTileIdx(puzzleInfo, idx)
|
||||||
return {
|
return {
|
||||||
x: c.x * puzzleInfo.tileSize,
|
x: c.x * puzzleInfo.tileSize,
|
||||||
|
|
@ -208,7 +212,7 @@ function srcRectByIdx(puzzleInfo: PuzzleInfo, idx: number) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadPuzzleBitmaps(puzzle: Puzzle) {
|
async function loadPuzzleBitmaps(puzzle: Puzzle): Promise<Array<ImageBitmap>> {
|
||||||
// load bitmap, to determine the original size of the image
|
// load bitmap, to determine the original size of the image
|
||||||
const bmp = await Graphics.loadImageToBitmap(puzzle.info.imageUrl)
|
const bmp = await Graphics.loadImageToBitmap(puzzle.info.imageUrl)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
import GameCommon from './../../common/GameCommon'
|
import { ScoreMode } from './../../common/GameCommon'
|
||||||
import Upload from './../components/Upload.vue'
|
import Upload from './../components/Upload.vue'
|
||||||
import ImageTeaser from './../components/ImageTeaser.vue'
|
import ImageTeaser from './../components/ImageTeaser.vue'
|
||||||
|
|
||||||
|
|
@ -64,7 +64,7 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
tiles: 1000,
|
tiles: 1000,
|
||||||
image: '',
|
image: '',
|
||||||
scoreMode: GameCommon.SCORE_MODE_ANY,
|
scoreMode: ScoreMode.ANY,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import Game, { Player, Piece } from './../common/GameCommon'
|
||||||
import fireworksController from './Fireworks'
|
import fireworksController from './Fireworks'
|
||||||
import Protocol from '../common/Protocol'
|
import Protocol from '../common/Protocol'
|
||||||
import Time from '../common/Time'
|
import Time from '../common/Time'
|
||||||
|
import { Dim, Point } from '../common/Geometry'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
@ -34,10 +35,6 @@ export const MODE_REPLAY = 'replay'
|
||||||
let PIECE_VIEW_FIXED = true
|
let PIECE_VIEW_FIXED = true
|
||||||
let PIECE_VIEW_LOOSE = true
|
let PIECE_VIEW_LOOSE = true
|
||||||
|
|
||||||
interface Point {
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
}
|
|
||||||
interface Hud {
|
interface Hud {
|
||||||
setActivePlayers: (v: Array<any>) => void
|
setActivePlayers: (v: Array<any>) => void
|
||||||
setIdlePlayers: (v: Array<any>) => void
|
setIdlePlayers: (v: Array<any>) => void
|
||||||
|
|
@ -474,10 +471,16 @@ export async function main(
|
||||||
RERENDER = true
|
RERENDER = true
|
||||||
} else if (entryWithTs[0] === Protocol.LOG_UPDATE_PLAYER) {
|
} else if (entryWithTs[0] === Protocol.LOG_UPDATE_PLAYER) {
|
||||||
const playerId = Game.getPlayerIdByIndex(gameId, entryWithTs[1])
|
const playerId = Game.getPlayerIdByIndex(gameId, entryWithTs[1])
|
||||||
|
if (!playerId) {
|
||||||
|
throw '[ 2021-05-17 player not found (update player) ]'
|
||||||
|
}
|
||||||
Game.addPlayer(gameId, playerId, nextTs)
|
Game.addPlayer(gameId, playerId, nextTs)
|
||||||
RERENDER = true
|
RERENDER = true
|
||||||
} else if (entryWithTs[0] === Protocol.LOG_HANDLE_INPUT) {
|
} else if (entryWithTs[0] === Protocol.LOG_HANDLE_INPUT) {
|
||||||
const playerId = Game.getPlayerIdByIndex(gameId, entryWithTs[1])
|
const playerId = Game.getPlayerIdByIndex(gameId, entryWithTs[1])
|
||||||
|
if (!playerId) {
|
||||||
|
throw '[ 2021-05-17 player not found (handle input) ]'
|
||||||
|
}
|
||||||
const input = entryWithTs[2]
|
const input = entryWithTs[2]
|
||||||
Game.handleInput(gameId, playerId, input, nextTs)
|
Game.handleInput(gameId, playerId, input, nextTs)
|
||||||
RERENDER = true
|
RERENDER = true
|
||||||
|
|
@ -598,9 +601,9 @@ export async function main(
|
||||||
|
|
||||||
const ts = TIME()
|
const ts = TIME()
|
||||||
|
|
||||||
let pos
|
let pos: Point
|
||||||
let dim
|
let dim: Dim
|
||||||
let bmp
|
let bmp: ImageBitmap
|
||||||
|
|
||||||
if (window.DEBUG) Debug.checkpoint_start(0)
|
if (window.DEBUG) Debug.checkpoint_start(0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, PropType } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
import Scores from './../components/Scores.vue'
|
import Scores from './../components/Scores.vue'
|
||||||
import PuzzleStatus from './../components/PuzzleStatus.vue'
|
import PuzzleStatus from './../components/PuzzleStatus.vue'
|
||||||
|
|
@ -39,6 +39,7 @@ import ConnectionOverlay from './../components/ConnectionOverlay.vue'
|
||||||
import HelpOverlay from './../components/HelpOverlay.vue'
|
import HelpOverlay from './../components/HelpOverlay.vue'
|
||||||
|
|
||||||
import { main, MODE_PLAY } from './../game'
|
import { main, MODE_PLAY } from './../game'
|
||||||
|
import { Player } from '../../common/GameCommon'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'game',
|
name: 'game',
|
||||||
|
|
@ -52,9 +53,8 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// TODO: ts Array<Player> type
|
activePlayers: [] as Array<Player>,
|
||||||
activePlayers: [] as PropType<Array<any>>,
|
idlePlayers: [] as Array<Player>,
|
||||||
idlePlayers: [] as PropType<Array<any>>,
|
|
||||||
|
|
||||||
finished: false,
|
finished: false,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
|
|
@ -103,8 +103,8 @@ export default defineComponent({
|
||||||
MODE_PLAY,
|
MODE_PLAY,
|
||||||
this.$el,
|
this.$el,
|
||||||
{
|
{
|
||||||
setActivePlayers: (v: Array<any>) => { this.activePlayers = v },
|
setActivePlayers: (v: Array<Player>) => { this.activePlayers = v },
|
||||||
setIdlePlayers: (v: Array<any>) => { this.idlePlayers = v },
|
setIdlePlayers: (v: Array<Player>) => { this.idlePlayers = v },
|
||||||
setFinished: (v: boolean) => { this.finished = v },
|
setFinished: (v: boolean) => { this.finished = v },
|
||||||
setDuration: (v: number) => { this.duration = v },
|
setDuration: (v: number) => { this.duration = v },
|
||||||
setPiecesDone: (v: number) => { this.piecesDone = v },
|
setPiecesDone: (v: number) => { this.piecesDone = v },
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import GameCommon from './../common/GameCommon'
|
import GameCommon, { ScoreMode } from './../common/GameCommon'
|
||||||
import Util from './../common/Util'
|
import Util from './../common/Util'
|
||||||
import { Rng } from './../common/Rng'
|
import { Rng } from './../common/Rng'
|
||||||
import GameLog from './GameLog'
|
import GameLog from './GameLog'
|
||||||
|
|
@ -6,7 +6,13 @@ import { createPuzzle } from './Puzzle'
|
||||||
import Protocol from './../common/Protocol'
|
import Protocol from './../common/Protocol'
|
||||||
import GameStorage from './GameStorage'
|
import GameStorage from './GameStorage'
|
||||||
|
|
||||||
async function createGameObject(gameId: string, targetTiles: number, image: { file: string, url: string }, ts: number, scoreMode: number) {
|
async function createGameObject(
|
||||||
|
gameId: string,
|
||||||
|
targetTiles: number,
|
||||||
|
image: { file: string, url: string },
|
||||||
|
ts: number,
|
||||||
|
scoreMode: ScoreMode
|
||||||
|
) {
|
||||||
const seed = Util.hash(gameId + ' ' + ts)
|
const seed = Util.hash(gameId + ' ' + ts)
|
||||||
const rng = new Rng(seed)
|
const rng = new Rng(seed)
|
||||||
return {
|
return {
|
||||||
|
|
@ -19,7 +25,13 @@ async function createGameObject(gameId: string, targetTiles: number, image: { fi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createGame(gameId: string, targetTiles: number, image: { file: string, url: string }, ts: number, scoreMode: number) {
|
async function createGame(
|
||||||
|
gameId: string,
|
||||||
|
targetTiles: number,
|
||||||
|
image: { file: string, url: string },
|
||||||
|
ts: number,
|
||||||
|
scoreMode: ScoreMode
|
||||||
|
) {
|
||||||
const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode)
|
const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode)
|
||||||
|
|
||||||
GameLog.create(gameId)
|
GameLog.create(gameId)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import GameCommon from './../common/GameCommon'
|
import GameCommon, { ScoreMode } from './../common/GameCommon'
|
||||||
import Util, { logger } from './../common/Util'
|
import Util, { logger } from './../common/Util'
|
||||||
import { Rng } from './../common/Rng'
|
import { Rng } from './../common/Rng'
|
||||||
import { DATA_DIR } from './Dirs'
|
import { DATA_DIR } from './Dirs'
|
||||||
|
|
@ -55,7 +55,7 @@ function loadGame(gameId: string): void {
|
||||||
puzzle: game.puzzle,
|
puzzle: game.puzzle,
|
||||||
players: game.players,
|
players: game.players,
|
||||||
evtInfos: {},
|
evtInfos: {},
|
||||||
scoreMode: game.scoreMode || GameCommon.SCORE_MODE_FINAL,
|
scoreMode: game.scoreMode || ScoreMode.FINAL,
|
||||||
}
|
}
|
||||||
GameCommon.setGame(gameObject.id, gameObject)
|
GameCommon.setGame(gameObject.id, gameObject)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import Util from './../common/Util'
|
import Util from './../common/Util'
|
||||||
import { Rng } from './../common/Rng'
|
import { Rng } from './../common/Rng'
|
||||||
import Images from './Images'
|
import Images from './Images'
|
||||||
|
import { EncodedPiece, EncodedPieceShape, PieceShape } from '../common/GameCommon'
|
||||||
|
|
||||||
interface PuzzleInfo {
|
interface PuzzleInfo {
|
||||||
width: number
|
width: number
|
||||||
|
|
@ -31,7 +32,7 @@ async function createPuzzle(
|
||||||
if (!dim || !dim.width || !dim.height) {
|
if (!dim || !dim.width || !dim.height) {
|
||||||
throw `[ 2021-05-16 invalid dimension for path ${imagePath} ]`
|
throw `[ 2021-05-16 invalid dimension for path ${imagePath} ]`
|
||||||
}
|
}
|
||||||
const info = determinePuzzleInfo(dim.width, dim.height, targetTiles)
|
const info: PuzzleInfo = determinePuzzleInfo(dim.width, dim.height, targetTiles)
|
||||||
|
|
||||||
let tiles = new Array(info.tiles)
|
let tiles = new Array(info.tiles)
|
||||||
for (let i = 0; i < tiles.length; i++) {
|
for (let i = 0; i < tiles.length; i++) {
|
||||||
|
|
@ -91,7 +92,7 @@ async function createPuzzle(
|
||||||
// then shuffle the positions
|
// then shuffle the positions
|
||||||
positions = rng.shuffle(positions)
|
positions = rng.shuffle(positions)
|
||||||
|
|
||||||
tiles = tiles.map(tile => {
|
const pieces: Array<EncodedPiece> = tiles.map(tile => {
|
||||||
return Util.encodeTile({
|
return Util.encodeTile({
|
||||||
idx: tile.idx, // index of tile in the array
|
idx: tile.idx, // index of tile in the array
|
||||||
group: 0, // if grouped with other tiles
|
group: 0, // if grouped with other tiles
|
||||||
|
|
@ -113,7 +114,7 @@ async function createPuzzle(
|
||||||
// Complete puzzle object
|
// Complete puzzle object
|
||||||
return {
|
return {
|
||||||
// tiles array
|
// tiles array
|
||||||
tiles,
|
tiles: pieces,
|
||||||
// game data for puzzle, data changes during the game
|
// game data for puzzle, data changes during the game
|
||||||
data: {
|
data: {
|
||||||
// TODO: maybe calculate this each time?
|
// TODO: maybe calculate this each time?
|
||||||
|
|
@ -159,10 +160,10 @@ async function createPuzzle(
|
||||||
function determinePuzzleTileShapes(
|
function determinePuzzleTileShapes(
|
||||||
rng: Rng,
|
rng: Rng,
|
||||||
info: PuzzleInfo
|
info: PuzzleInfo
|
||||||
) {
|
): Array<EncodedPieceShape> {
|
||||||
const tabs = [-1, 1]
|
const tabs = [-1, 1]
|
||||||
|
|
||||||
const shapes = new Array(info.tiles)
|
const shapes: Array<PieceShape> = new Array(info.tiles)
|
||||||
for (let i = 0; i < info.tiles; i++) {
|
for (let i = 0; i < info.tiles; i++) {
|
||||||
let coord = Util.coordByTileIdx(info, i)
|
let coord = Util.coordByTileIdx(info, i)
|
||||||
shapes[i] = {
|
shapes[i] = {
|
||||||
|
|
@ -191,7 +192,11 @@ const determineTilesXY = (w: number, h: number, targetTiles: number) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const determinePuzzleInfo = (w: number, h: number, targetTiles: number) => {
|
const determinePuzzleInfo = (
|
||||||
|
w: number,
|
||||||
|
h: number,
|
||||||
|
targetTiles: number
|
||||||
|
): PuzzleInfo => {
|
||||||
const {tilesX, tilesY} = determineTilesXY(w, h, targetTiles)
|
const {tilesX, tilesY} = determineTilesXY(w, h, targetTiles)
|
||||||
const tiles = tilesX * tilesY
|
const tiles = tilesX * tilesY
|
||||||
const tileSize = TILE_SIZE
|
const tileSize = TILE_SIZE
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import GameSockets from './GameSockets'
|
||||||
import Time from './../common/Time'
|
import Time from './../common/Time'
|
||||||
import Images from './Images'
|
import Images from './Images'
|
||||||
import { UPLOAD_DIR, UPLOAD_URL, PUBLIC_DIR } from './Dirs'
|
import { UPLOAD_DIR, UPLOAD_URL, PUBLIC_DIR } from './Dirs'
|
||||||
import GameCommon from '../common/GameCommon'
|
import GameCommon, { ScoreMode } from '../common/GameCommon'
|
||||||
import GameStorage from './GameStorage'
|
import GameStorage from './GameStorage'
|
||||||
|
|
||||||
let configFile = ''
|
let configFile = ''
|
||||||
|
|
@ -158,7 +158,7 @@ wss.on('message', async ({socket, data} : { socket: WebSocket, data: any }) => {
|
||||||
log[0][2],
|
log[0][2],
|
||||||
log[0][3],
|
log[0][3],
|
||||||
log[0][4],
|
log[0][4],
|
||||||
log[0][5] || GameCommon.SCORE_MODE_FINAL
|
log[0][5] || ScoreMode.FINAL
|
||||||
)
|
)
|
||||||
notify(
|
notify(
|
||||||
[Protocol.EV_SERVER_INIT_REPLAY, Util.encodeGame(game), log],
|
[Protocol.EV_SERVER_INIT_REPLAY, Util.encodeGame(game), log],
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue