puzzle/server/Game.js

149 lines
4.2 KiB
JavaScript
Raw Normal View History

2020-11-25 22:03:35 +01:00
import fs from 'fs'
2020-11-17 22:34:15 +01:00
import GameCommon from './../common/GameCommon.js'
import Util, { logger } from './../common/Util.js'
2020-12-21 18:34:57 +01:00
import { Rng } from '../common/Rng.js'
2020-12-22 22:35:09 +01:00
import GameLog from './GameLog.js'
import { createPuzzle } from './Puzzle.js'
2020-12-23 01:19:30 +01:00
import Protocol from '../common/Protocol.js'
import { DATA_DIR } from './Dirs.js'
2020-11-12 19:19:02 +01:00
const log = logger('Game.js')
2020-11-25 22:03:35 +01:00
function loadAllGames() {
const files = fs.readdirSync(DATA_DIR)
2020-11-25 22:03:35 +01:00
for (const f of files) {
2020-12-24 14:19:21 +01:00
const m = f.match(/^([a-z0-9]+)\.json$/)
if (!m) {
2020-11-25 22:03:35 +01:00
continue
}
2020-12-24 14:19:21 +01:00
const gameId = m[1]
2021-04-30 09:09:10 +02:00
loadGameFromFile(gameId)
2020-12-24 14:19:21 +01:00
}
}
2021-04-30 09:09:10 +02:00
function loadGameFromFile(gameId) {
2020-12-24 14:19:21 +01:00
const file = `${DATA_DIR}/${gameId}.json`
const contents = fs.readFileSync(file, 'utf-8')
let game
try {
game = JSON.parse(contents)
} catch {
log.log(`[ERR] unable to load game from file ${file}`);
2020-12-24 14:19:21 +01:00
}
if (typeof game.puzzle.data.started === 'undefined') {
game.puzzle.data.started = Math.round(fs.statSync(file).ctimeMs)
}
if (typeof game.puzzle.data.finished === 'undefined') {
let unfinished = game.puzzle.tiles.map(Util.decodeTile).find(t => t.owner !== -1)
game.puzzle.data.finished = unfinished ? 0 : Util.timestamp()
2020-11-25 22:03:35 +01:00
}
2020-12-24 14:19:21 +01:00
if (!Array.isArray(game.players)) {
game.players = Object.values(game.players)
}
2021-04-30 01:03:43 +02:00
const gameObject = {
2020-12-24 14:19:21 +01:00
id: game.id,
rng: {
type: game.rng ? game.rng.type : '_fake_',
obj: game.rng ? Rng.unserialize(game.rng.obj) : new Rng(),
},
puzzle: game.puzzle,
players: game.players,
2021-04-27 21:43:53 +02:00
evtInfos: {},
scoreMode: game.scoreMode || GameCommon.SCORE_MODE_FINAL,
2021-04-30 01:03:43 +02:00
}
GameCommon.setGame(gameObject.id, gameObject)
2020-11-25 22:03:35 +01:00
}
2020-12-13 00:11:42 +01:00
const changedGames = {}
2021-04-27 21:43:53 +02:00
async function createGameObject(gameId, targetTiles, image, ts, scoreMode) {
2020-12-22 22:35:09 +01:00
const seed = Util.hash(gameId + ' ' + ts)
const rng = new Rng(seed)
2021-04-30 00:31:24 +02:00
return {
id: gameId,
rng: { type: 'Rng', obj: rng },
puzzle: await createPuzzle(rng, targetTiles, image, ts),
players: [],
evtInfos: {},
scoreMode,
}
2020-12-22 22:35:09 +01:00
}
2021-04-27 21:43:53 +02:00
async function createGame(gameId, targetTiles, image, ts, scoreMode) {
2021-04-30 01:03:43 +02:00
const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode)
2020-12-22 22:54:31 +01:00
GameLog.create(gameId)
2021-04-27 21:43:53 +02:00
GameLog.log(gameId, Protocol.LOG_HEADER, 1, targetTiles, image, ts, scoreMode)
2020-12-22 22:35:09 +01:00
2021-04-30 01:03:43 +02:00
GameCommon.setGame(gameObject.id, gameObject)
2020-12-22 22:35:09 +01:00
2020-12-13 00:11:42 +01:00
changedGames[gameId] = true
}
2020-12-22 22:35:09 +01:00
function addPlayer(gameId, playerId, ts) {
2020-12-23 01:19:30 +01:00
const idx = GameCommon.getPlayerIndexById(gameId, playerId)
2021-04-30 00:58:39 +02:00
const diff = ts - GameCommon.getStartTs(gameId)
2020-12-23 01:19:30 +01:00
if (idx === -1) {
GameLog.log(gameId, Protocol.LOG_ADD_PLAYER, playerId, diff)
} else {
GameLog.log(gameId, Protocol.LOG_UPDATE_PLAYER, idx, diff)
}
2020-12-22 22:35:09 +01:00
GameCommon.addPlayer(gameId, playerId, ts)
2020-12-13 00:11:42 +01:00
changedGames[gameId] = true
}
2020-12-22 22:35:09 +01:00
function handleInput(gameId, playerId, input, ts) {
2020-12-23 01:19:30 +01:00
const idx = GameCommon.getPlayerIndexById(gameId, playerId)
const diff = ts - GameCommon.getStartTs(gameId)
GameLog.log(gameId, Protocol.LOG_HANDLE_INPUT, idx, input, diff)
2020-12-22 22:35:09 +01:00
const ret = GameCommon.handleInput(gameId, playerId, input, ts)
2020-12-13 00:11:42 +01:00
changedGames[gameId] = true
return ret
}
function persistChangedGames() {
2020-12-24 13:56:14 +01:00
for (const gameId of Object.keys(changedGames)) {
2021-04-30 20:41:08 +02:00
writeGameToFile(gameId)
2020-12-24 13:56:14 +01:00
}
}
2021-04-30 20:41:08 +02:00
function writeGameToFile(gameId) {
2020-12-24 13:56:14 +01:00
const game = GameCommon.get(gameId)
if (game.id in changedGames) {
delete changedGames[game.id]
}
2020-12-24 13:56:14 +01:00
fs.writeFileSync(`${DATA_DIR}/${game.id}.json`, JSON.stringify({
id: game.id,
rng: {
type: game.rng.type,
obj: Rng.serialize(game.rng.obj),
},
puzzle: game.puzzle,
players: game.players,
2021-04-27 21:43:53 +02:00
scoreMode: game.scoreMode,
2020-12-24 13:56:14 +01:00
}))
log.info(`[INFO] persisted game ${game.id}`)
2020-11-25 22:03:35 +01:00
}
2020-11-12 19:19:02 +01:00
export default {
2021-04-30 20:41:08 +02:00
loadGameFromFile,
writeGameToFile,
2020-12-22 22:35:09 +01:00
createGameObject,
2020-11-25 22:03:35 +01:00
loadAllGames,
2020-12-13 00:11:42 +01:00
persistChangedGames,
2020-11-12 19:19:02 +01:00
createGame,
2020-12-13 00:11:42 +01:00
addPlayer,
handleInput,
2020-12-05 19:45:34 +01:00
getAllGames: GameCommon.getAllGames,
2020-12-21 02:29:14 +01:00
getRelevantPlayers: GameCommon.getRelevantPlayers,
2020-12-05 19:45:34 +01:00
getActivePlayers: GameCommon.getActivePlayers,
getFinishedTileCount: GameCommon.getFinishedTileCount,
getImageUrl: GameCommon.getImageUrl,
getTileCount: GameCommon.getTileCount,
2020-11-17 22:34:15 +01:00
exists: GameCommon.exists,
2020-12-03 21:11:52 +01:00
playerExists: GameCommon.playerExists,
2020-11-17 22:34:15 +01:00
get: GameCommon.get,
2020-12-07 02:38:07 +01:00
getStartTs: GameCommon.getStartTs,
getFinishTs: GameCommon.getFinishTs,
2020-11-12 19:19:02 +01:00
}