split Game and GameStorage
This commit is contained in:
parent
e83d3e8d61
commit
792f0d4c31
5 changed files with 108 additions and 93 deletions
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
import GameCommon from '../common/GameCommon.js'
|
import GameCommon from '../common/GameCommon.js'
|
||||||
import { logger } from '../common/Util.js'
|
import { logger } from '../common/Util.js'
|
||||||
import Game from '../server/Game.js'
|
import GameStorage from '../server/GameStorage.js'
|
||||||
|
|
||||||
const log = logger('fix_image.js')
|
const log = logger('fix_image.js')
|
||||||
|
|
||||||
function fix(gameId) {
|
function fix(gameId) {
|
||||||
Game.loadGameFromFile(gameId)
|
GameStorage.loadGame(gameId)
|
||||||
let changed = false
|
let changed = false
|
||||||
|
|
||||||
let imgUrl = GameCommon.getImageUrl(gameId)
|
let imgUrl = GameCommon.getImageUrl(gameId)
|
||||||
|
|
@ -18,7 +18,7 @@ function fix(gameId) {
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
Game.writeGameToFile(gameId)
|
GameStorage.persistGame(gameId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import GameCommon from '../common/GameCommon.js'
|
import GameCommon from '../common/GameCommon.js'
|
||||||
import { logger } from '../common/Util.js'
|
import { logger } from '../common/Util.js'
|
||||||
import Game from '../server/Game.js'
|
import GameStorage from '../server/GameStorage.js'
|
||||||
|
|
||||||
|
|
||||||
const log = logger('fix_tiles.js')
|
const log = logger('fix_tiles.js')
|
||||||
|
|
||||||
function fix_tiles(gameId) {
|
function fix_tiles(gameId) {
|
||||||
Game.loadGameFromFile(gameId)
|
GameStorage.loadGame(gameId)
|
||||||
let changed = false
|
let changed = false
|
||||||
const tiles = GameCommon.getTilesSortedByZIndex(gameId)
|
const tiles = GameCommon.getTilesSortedByZIndex(gameId)
|
||||||
for (let tile of tiles) {
|
for (let tile of tiles) {
|
||||||
|
|
@ -28,7 +27,7 @@ function fix_tiles(gameId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
Game.writeGameToFile(gameId)
|
GameStorage.persistGame(gameId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,60 +1,11 @@
|
||||||
import fs from 'fs'
|
|
||||||
import GameCommon from './../common/GameCommon.js'
|
import GameCommon from './../common/GameCommon.js'
|
||||||
import Util, { logger } from './../common/Util.js'
|
import Util from './../common/Util.js'
|
||||||
import { Rng } from '../common/Rng.js'
|
import { Rng } from '../common/Rng.js'
|
||||||
import GameLog from './GameLog.js'
|
import GameLog from './GameLog.js'
|
||||||
import { createPuzzle } from './Puzzle.js'
|
import { createPuzzle } from './Puzzle.js'
|
||||||
import Protocol from '../common/Protocol.js'
|
import Protocol from '../common/Protocol.js'
|
||||||
import { DATA_DIR } from './Dirs.js'
|
import GameStorage from './GameStorage.js'
|
||||||
|
|
||||||
const log = logger('Game.js')
|
|
||||||
|
|
||||||
function loadAllGames() {
|
|
||||||
const files = fs.readdirSync(DATA_DIR)
|
|
||||||
for (const f of files) {
|
|
||||||
const m = f.match(/^([a-z0-9]+)\.json$/)
|
|
||||||
if (!m) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
const gameId = m[1]
|
|
||||||
loadGameFromFile(gameId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadGameFromFile(gameId) {
|
|
||||||
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}`);
|
|
||||||
}
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
if (!Array.isArray(game.players)) {
|
|
||||||
game.players = Object.values(game.players)
|
|
||||||
}
|
|
||||||
const gameObject = {
|
|
||||||
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,
|
|
||||||
evtInfos: {},
|
|
||||||
scoreMode: game.scoreMode || GameCommon.SCORE_MODE_FINAL,
|
|
||||||
}
|
|
||||||
GameCommon.setGame(gameObject.id, gameObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
const changedGames = {}
|
|
||||||
async function createGameObject(gameId, targetTiles, image, ts, scoreMode) {
|
async function createGameObject(gameId, targetTiles, image, ts, scoreMode) {
|
||||||
const seed = Util.hash(gameId + ' ' + ts)
|
const seed = Util.hash(gameId + ' ' + ts)
|
||||||
const rng = new Rng(seed)
|
const rng = new Rng(seed)
|
||||||
|
|
@ -74,8 +25,7 @@ async function createGame(gameId, targetTiles, image, ts, scoreMode) {
|
||||||
GameLog.log(gameId, Protocol.LOG_HEADER, 1, targetTiles, image, ts, scoreMode)
|
GameLog.log(gameId, Protocol.LOG_HEADER, 1, targetTiles, image, ts, scoreMode)
|
||||||
|
|
||||||
GameCommon.setGame(gameObject.id, gameObject)
|
GameCommon.setGame(gameObject.id, gameObject)
|
||||||
|
GameStorage.setDirty(gameId)
|
||||||
changedGames[gameId] = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPlayer(gameId, playerId, ts) {
|
function addPlayer(gameId, playerId, ts) {
|
||||||
|
|
@ -88,7 +38,7 @@ function addPlayer(gameId, playerId, ts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GameCommon.addPlayer(gameId, playerId, ts)
|
GameCommon.addPlayer(gameId, playerId, ts)
|
||||||
changedGames[gameId] = true
|
GameStorage.setDirty(gameId)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleInput(gameId, playerId, input, ts) {
|
function handleInput(gameId, playerId, input, ts) {
|
||||||
|
|
@ -97,40 +47,12 @@ function handleInput(gameId, playerId, input, ts) {
|
||||||
GameLog.log(gameId, Protocol.LOG_HANDLE_INPUT, idx, input, diff)
|
GameLog.log(gameId, Protocol.LOG_HANDLE_INPUT, idx, input, diff)
|
||||||
|
|
||||||
const ret = GameCommon.handleInput(gameId, playerId, input, ts)
|
const ret = GameCommon.handleInput(gameId, playerId, input, ts)
|
||||||
changedGames[gameId] = true
|
GameStorage.setDirty(gameId)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
function persistChangedGames() {
|
|
||||||
for (const gameId of Object.keys(changedGames)) {
|
|
||||||
writeGameToFile(gameId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeGameToFile(gameId) {
|
|
||||||
const game = GameCommon.get(gameId)
|
|
||||||
if (game.id in changedGames) {
|
|
||||||
delete changedGames[game.id]
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
scoreMode: game.scoreMode,
|
|
||||||
}))
|
|
||||||
log.info(`[INFO] persisted game ${game.id}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
loadGameFromFile,
|
|
||||||
writeGameToFile,
|
|
||||||
createGameObject,
|
createGameObject,
|
||||||
loadAllGames,
|
|
||||||
persistChangedGames,
|
|
||||||
createGame,
|
createGame,
|
||||||
addPlayer,
|
addPlayer,
|
||||||
handleInput,
|
handleInput,
|
||||||
|
|
|
||||||
93
server/GameStorage.js
Normal file
93
server/GameStorage.js
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
import fs from 'fs'
|
||||||
|
import GameCommon from './../common/GameCommon.js'
|
||||||
|
import Util, { logger } from './../common/Util.js'
|
||||||
|
import { Rng } from '../common/Rng.js'
|
||||||
|
import { DATA_DIR } from './Dirs.js'
|
||||||
|
import Time from '../common/Time.js'
|
||||||
|
|
||||||
|
const log = logger('GameStorage.js')
|
||||||
|
|
||||||
|
const DIRTY_GAMES = {}
|
||||||
|
function setDirty(gameId) {
|
||||||
|
DIRTY_GAMES[gameId] = true
|
||||||
|
}
|
||||||
|
function setClean(gameId) {
|
||||||
|
delete DIRTY_GAMES[gameId]
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadGames() {
|
||||||
|
const files = fs.readdirSync(DATA_DIR)
|
||||||
|
for (const f of files) {
|
||||||
|
const m = f.match(/^([a-z0-9]+)\.json$/)
|
||||||
|
if (!m) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const gameId = m[1]
|
||||||
|
loadGame(gameId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadGame(gameId) {
|
||||||
|
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}`);
|
||||||
|
}
|
||||||
|
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 : Time.timestamp()
|
||||||
|
}
|
||||||
|
if (!Array.isArray(game.players)) {
|
||||||
|
game.players = Object.values(game.players)
|
||||||
|
}
|
||||||
|
const gameObject = {
|
||||||
|
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,
|
||||||
|
evtInfos: {},
|
||||||
|
scoreMode: game.scoreMode || GameCommon.SCORE_MODE_FINAL,
|
||||||
|
}
|
||||||
|
GameCommon.setGame(gameObject.id, gameObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
function persistGames() {
|
||||||
|
for (const gameId of Object.keys(changedGames)) {
|
||||||
|
persistGame(gameId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function persistGame(gameId) {
|
||||||
|
const game = GameCommon.get(gameId)
|
||||||
|
if (game.id in DIRTY_GAMES) {
|
||||||
|
setClean(game.id)
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
scoreMode: game.scoreMode,
|
||||||
|
}))
|
||||||
|
log.info(`[INFO] persisted game ${game.id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
loadGames,
|
||||||
|
loadGame,
|
||||||
|
persistGames,
|
||||||
|
persistGame,
|
||||||
|
setDirty,
|
||||||
|
}
|
||||||
|
|
@ -21,6 +21,7 @@ import {
|
||||||
TEMPLATE_DIR,
|
TEMPLATE_DIR,
|
||||||
} from './Dirs.js'
|
} from './Dirs.js'
|
||||||
import GameCommon from '../common/GameCommon.js'
|
import GameCommon from '../common/GameCommon.js'
|
||||||
|
import GameStorage from './GameStorage.js'
|
||||||
|
|
||||||
const log = logger('index.js')
|
const log = logger('index.js')
|
||||||
|
|
||||||
|
|
@ -222,7 +223,7 @@ wss.on('message', async ({socket, data}) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
Game.loadAllGames()
|
GameStorage.loadGames()
|
||||||
const server = app.listen(
|
const server = app.listen(
|
||||||
port,
|
port,
|
||||||
hostname,
|
hostname,
|
||||||
|
|
@ -245,7 +246,7 @@ memoryUsageHuman()
|
||||||
// persist games in fixed interval
|
// persist games in fixed interval
|
||||||
const persistInterval = setInterval(() => {
|
const persistInterval = setInterval(() => {
|
||||||
log.log('Persisting games...')
|
log.log('Persisting games...')
|
||||||
Game.persistChangedGames()
|
GameStorage.persistGames()
|
||||||
|
|
||||||
memoryUsageHuman()
|
memoryUsageHuman()
|
||||||
}, config.persistence.interval)
|
}, config.persistence.interval)
|
||||||
|
|
@ -257,7 +258,7 @@ const gracefulShutdown = (signal) => {
|
||||||
clearInterval(persistInterval)
|
clearInterval(persistInterval)
|
||||||
|
|
||||||
log.log('persisting games...')
|
log.log('persisting games...')
|
||||||
Game.persistChangedGames()
|
GameStorage.persistGames()
|
||||||
|
|
||||||
log.log('shutting down webserver...')
|
log.log('shutting down webserver...')
|
||||||
server.close()
|
server.close()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue