papercats/game-server.js

252 lines
6.1 KiB
JavaScript
Raw Normal View History

2017-02-25 18:52:52 -05:00
var Grid = require("./grid.js");
var Player = require("./player.js");
2017-02-25 18:52:52 -05:00
var core = require("./game-core.js");
var consts = require("./game-consts.js");
var GRID_SIZE = consts.GRID_SIZE;
var CELL_WIDTH = consts.CELL_WIDTH;
var MAX_PLAYERS = consts.MAX_PLAYERS;
function Game(id)
{
2017-02-25 18:52:52 -05:00
var nextInd = 0;
var players = [];
var newPlayers = [];
2017-02-25 18:52:52 -05:00
var newPlayerFrames = [];
var frame = 0;
var filled = 0;
var grid = new Grid(GRID_SIZE, function(row, col, before, after) {
if (!!after ^ !!before)
{
if (after)
filled++;
else
filled--;
}
});
this.id = id;
this.addPlayer = function(client, name) {
2017-02-25 18:52:52 -05:00
if (players.length >= MAX_PLAYERS)
return false;
var start = findEmpty(grid);
if (!start)
return false;
var params = {
posX: start.col * CELL_WIDTH,
posY: start.row * CELL_WIDTH,
2017-02-25 18:52:52 -05:00
currentHeading: Math.floor(Math.random() * 4),
name: name,
2017-02-25 18:52:52 -05:00
num: nextInd
};
var p = new Player(false, grid, params);
p.client = client;
2017-02-25 18:52:52 -05:00
players.push(p);
newPlayers.push(p);
2017-02-26 02:31:30 -05:00
newPlayerFrames.push(0);
2017-02-25 18:52:52 -05:00
nextInd++;
core.initPlayer(grid, p);
2017-02-25 18:52:52 -05:00
var splayers = players.map(function(val) {return val.serialData();});
client.emit("game", {
"num": p.num,
"gameid": id,
"frame": frame,
"players": splayers,
"grid": gridSerialData(grid, players)
});
2017-02-26 02:31:30 -05:00
//console.log(frame);
//playerReady(p, frame);
console.log(p.name + " joined.");
2017-02-25 23:25:06 -05:00
//TODO: kick off any clients that take too long.
2017-02-25 18:52:52 -05:00
//TODO: limit number of requests per frame.
client.on("requestFrame", function () {
2017-02-25 23:25:06 -05:00
//if (p.frame === frame)
// return;
2017-02-25 18:52:52 -05:00
var splayers = players.map(function(val) {return val.serialData();});
client.emit("game", {
2017-02-25 18:52:52 -05:00
"num": p.num,
"gameid": id,
"frame": frame,
"players": splayers,
"grid": gridSerialData(grid, players)
});
2017-02-26 02:31:30 -05:00
//playerReady(p, frame);
2017-02-25 18:52:52 -05:00
});
2017-02-25 18:52:52 -05:00
client.on("frame", function(data, errorHan){
if (typeof data === "function")
{
errorHan(false, "No data supplied.");
return;
}
if (typeof errorHan !== "function")
errorHan = function() {};
if (!data)
errorHan(false, "No data supplied.");
else if (!checkInt(data.frame, 0, Infinity))
errorHan(false, "Requires a valid non-negative frame integer.");
//else if (data.frame < frame)
// errorHan(false, "Late frame received.");
2017-02-25 18:52:52 -05:00
else if (data.frame > frame)
errorHan(false, "Invalid frame received.");
else
{
2017-02-25 23:25:06 -05:00
if (data.frame < frame)
console.log(data.frame + " != " + frame);
2017-02-26 02:31:30 -05:00
if (data.heading !== undefined)
2017-02-25 18:52:52 -05:00
{
if (checkInt(data.heading, 0, 4))
{
p.heading = data.heading;
errorHan(true);
}
else
errorHan(false, "New heading must be an integer of range [0, 4).");
}
}
});
2017-02-25 23:25:06 -05:00
client.on('disconnect', function() {
console.log(p.name + " left.")
});
return true;
2017-02-25 18:52:52 -05:00
};
2017-02-26 02:31:30 -05:00
/*
2017-02-25 23:25:06 -05:00
var ready = 0;
var readyTick = false;
2017-02-25 18:52:52 -05:00
2017-02-25 23:25:06 -05:00
function playerReady(player, waitFrame)
{
if (player.frame < waitFrame)
{
ready++;
player.frame = waitFrame;
}
tick();
}
2017-02-26 02:31:30 -05:00
*/
2017-02-25 23:25:06 -05:00
function tick() {
2017-02-26 02:31:30 -05:00
//if (readyTick && ready === players.length)
//{
// ready = 0;
// readyTick = false;
//}else
// return;
2017-02-25 23:25:06 -05:00
//TODO: notify those that drop out.
2017-02-25 18:52:52 -05:00
var snews = newPlayers.map(function(val) {return val.serialData();});
var moves = players.map(function(val) {return {heading: val.heading};});
var data = {frame: frame + 1, moves: moves};
2017-02-25 18:52:52 -05:00
if (snews.length > 0)
{
data.newPlayers = snews;
newPlayers = [];
}
2017-02-25 23:25:06 -05:00
var waitFrame = frame + 1;
2017-02-26 02:31:30 -05:00
var splayers = players.map(function(val) {return val.serialData();});
var gridData = gridSerialData(grid, players);
2017-02-25 23:25:06 -05:00
players.forEach(function(val) {
2017-02-26 02:31:30 -05:00
//val.client.emit("game", {
// "num": val.num,
// "gameid": id,
// "frame": frame,
// "players": splayers,
// "grid": gridData
//});
2017-02-25 23:25:06 -05:00
val.client.emit("notifyFrame", data, function() {
2017-02-26 02:31:30 -05:00
//playerReady(val, waitFrame);
2017-02-25 23:25:06 -05:00
});
});
2017-02-25 18:52:52 -05:00
frame++;
2017-02-26 02:31:30 -05:00
setTimeout(update, 1);
2017-02-25 18:52:52 -05:00
};
2017-02-25 23:25:06 -05:00
this.tickFrame = function() {
2017-02-26 02:31:30 -05:00
//readyTick = true;
2017-02-25 23:25:06 -05:00
tick();
}
2017-02-25 18:52:52 -05:00
function update()
{
var dead = [];
core.updateFrame(grid, players, newPlayerFrames, dead);
dead.forEach(function(val) {
console.log(val.name + " died.");
val.client.disconnect(true);
});
}
}
2017-02-25 18:52:52 -05:00
function checkInt(value, min, max)
{
if (typeof value !== "number")
return false;
if (value < min || value >= max)
return false;
if (Math.floor(value) !== value)
return false;
return true;
}
function gridSerialData(grid, players)
{
var buff = Buffer.alloc(grid.size * grid.size);
2017-02-26 02:31:30 -05:00
var numToIndex = new Array(players.length > 0 ? players[players.length - 1].num + 1 : 0);
2017-02-25 18:52:52 -05:00
for (var i = 0; i < players.length; i++)
numToIndex[players[i].num] = i + 1;
for (var r = 0; r < grid.size; r++)
for (var c = 0; c < grid.size; c++)
{
var ele = grid.get(r, c);
buff[r * grid.size + c] = ele ? numToIndex[ele.num] : 0;
}
return buff;
}
function findEmpty(grid)
{
var available = [];
for (var r = 1; r < grid.size - 1; r++)
for (var c = 1; c < grid.size - 1; c++)
{
var cluttered = false;
checkclutter: for (var dr = -1; dr <= 1; dr++)
{
for (var dc = -1; dc <= 1; dc++)
{
if (grid.get(r + dr, c + dc))
{
cluttered = true;
break checkclutter;
}
}
}
if (!cluttered)
available.push({row: r, col: c});
}
if (available.length === 0)
return null;
else
return available[Math.floor(available.length * Math.random())];
}
module.exports = Game;