2013-07-28 12:21:24 -04:00
2013-07-27 16:31:42 -04:00
2013-07-26 15:37:18 -04:00
2013-07-26 09:54:50 -04:00
2013-05-05 23:50:15 -04:00
2013-06-08 16:43:37 -04:00
2013-05-05 23:00:43 -04:00
2013-07-28 12:21:24 -04:00

GarageServer.IO

A simple, lightweight, HTML multiplayer game server (and client) for Node.js

Features

  • Authoritative Game Server
  • Client Side / Input Prediciton
  • Client Side Smooting
  • Entity Interpolation
  • Server State History
  • Server and Client Messaging

Quick Start

Create a quick game whereby players simply move squares along the x-axis. (I know, it's boring, but it keeps things simple.)

Server

1. Create instance of GarageServer.IO - pass in a Socket.IO instance and GarageServer.IO options

var garageServer = require('garageserver.io'),

var server = garageServer.createGarageServer(sockets, 
    {
        interpolation: true,
        clientSidePrediction: true,
        worldState: { width: '400px', height: '400px'; }
    });

2. Start GarageServer.IO instance prior to starting physics loop. This starts the clock that is used for broadcasting state.

server.start();

3. Inside physics loop, process inputs for players, process entites and update states. Note that state is an object literal effectively offering up any grab bag of properties that pertain to your game's state.

var players = server.getPlayers(),
    entities = server.getEntities();

players.forEach(function (player) {
    var newState = {};
    if (!player.state.x) {
       player.state.x = 0;
    }
    for (i = 0; i < player.inputs.length; i ++) {
        if (player.inputs[i].input === 'left') {
            newState.x = player.state.x - (50 * deltaTime);
        } else if (inputs[i].input === 'right') {
            newState.x = player.state.x + (50 * deltaTime);
        }
    }
    server.updatePlayerState(player.id, newState);
});
entities.forEach(function (entity) {
    // Calculate new state from entity.state and send GarageServer.IO new state
    server.updateEntityState(entity.id, newState);
});

Client

1. Initialize GarageServer.IO.

GarageServerIO.initializeGarageServer('http://insertmygameurlhere.com', {
    onReady: function () {
        // Call your game loop
    },
    onUpdatePlayerPrediction: function (state, inputs, deltaTime) {
        var newState = {};
        if (!player.state.x) {
        player.state.x = 0;
        }
        for (i = 0; i < player.inputs.length; i ++) {
            if (player.inputs[i].input === 'left') {
                newState.x = player.state.x - (50 * deltaTime);
            } else if (inputs[i].input === 'right') {
                newState.x = player.state.x + (50 * deltaTime);
            }
        }
        return newState;
    },
    onInterpolation: function (previousState, targetState, amount) {
        return { x: (previousState.x + amount * (targetState.x - previousState.x)) };
    },
    onWorldState: function (state) {
        document.getElementById('gameCanvas').style.width = state.width;
        document.getElementById('gameCanvas').style.height = state.height;
    }
};

2. Inside physics loop, capture and send input via GarageServer.IO.

GarageServerIO.addInput(myInput);

3. Inside render loop, extract player and entity states.

var playerStates = GarageServerIO.getPlayerStates(),
    entityStates = GarageServerIO.getEntityStates();  
    playerStates.forEach(function (player) {
        ctxCanvas.fillRect(player.state.x, 0, 5, 5);
    });
    entityStates.forEach(function (entity) {
        ctxCanvas.fillRect(entity.state.x, 0, 5, 5);
    });

API

Client

initializeGarageServer


GarageServerIO.initializeGarageServer(path, options)
/*
options = {
    onPlayerConnect(callback),
    onPlayerDisconnect(callback),
    onPlayerReconnect(callback),
    onPlayerUpdate(callback(state)),
    onEntityUpdate(callback(state)),
    onPlayerRemove(callback(id)),
    onEntityRemove(callback(id)),
    onEvent(callback(data)),
    onWorldState(callback(state)),
    onPing(callback(pingDelay)),
    onUpdatePlayerPrediction(callback(state, inputs, deltaTime) : newState),
    onInterpolation(callback(previousState, targetState, amount) : newState),
    onReady(callback),
    logging: true
}
*/

path
Type: string

options
Type: object literal

addInput


GarageServerIO.addInput(input)

input
Type: object literal

getPlayerStates


GarageServerIO.getPlayerStates() : [, {id, state}]

id
Type: string

state
Type: object literal

getEntityStates


GarageServerIO.getEntityStates() : [, {id, state}]

id
Type: string

state
Type: object literal

getId


GarageServerIO.getId() : playerid

playerid
Type: number

sendServerEvent


GarageServerIO.sendServerEvent(data)

data
Type: object literal

Server

createGarageServer


require('garageserver.io').createGarageServer(io, options) : GarageServerIO
/*
options = {
    stateInterval: 45,
    logging: true,
    clientSidePrediction: true,
    interpolation: true,
    interpolationDelay: 100,
    smoothingFactor: 0.3,
    pingInterval: 2000,
    maxUpdateBuffer: 120,
    maxHistorySecondBuffer: 1000,
    worldState: {},
    onPlayerConnect(callback(socket)),
    onPlayerInput(callback(socket, input)),
    onPlayerDisconnect(callback(socket)),
    onPing(callback(socket, data)),
    onEvent(callback(data))
}
*/

io
Type: Socket.IO instance

options
Type: object literal

start


GarageServerIO.start()

stop


GarageServerIO.stop()

getPlayers


GarageServerIO.getPlayers() : [, {id, state, [, inputs], [, {states, executionTimes}]}]

id
Type: string

state
Type: object literal

inputs
Type: array of object literals

stateHistory
Type: array of object literals

getEntities


GarageServerIO.getEntities() : [,{id, state, [, {state, executionTime }]}]

id
Type: string

state
Type: object literal

stateHistory
Type: array of object literals

updatePlayerState


GarageServerIO.updatePlayerState(id, state)

id
Type: string

state
Type: object literal

updateEntityState


GarageServerIO.updateEntityState(id, state)

id
Type: string

state
Type: object literal

addEntity


GarageServerIO.addEntity(id)

id
Type: string

removeEntity


GarageServerIO.removeEntity(id)

id
Type: string

sendPlayerEvent


GarageServerIO.sendPlayerEvent(id, data)

id
Type: string

data
Type: object literal

sendPlayersEvent


GarageServerIO.sendPlayersEvent(data)

data
Type: object literal

License

MIT License

S
Description
A simple, lightweight, HTML multiplayer game server (and client) for Node.js
Readme 593 KiB
Languages
JavaScript 97.7%
Pug 1.5%
CSS 0.8%