Files
GarageServer.IO/README.md
T
2013-07-26 21:39:15 -04:00

6.2 KiB

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

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

server.start();

3. Inside physics loop, process inputs for players, process entites and update states

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 -= (50 * deltaTime);
        } else if (inputs[i].input === 'right') {
            newState.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 -= (50 * deltaTime);
            } else if (inputs[i].input === 'right') {
                newState.x += (50 * deltaTime);
            }
        }
    },
    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

GarageServerIO.getStates(function (playerStates, entityStates) {
    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() : [, playerState]

playerStates
Type: array of object literals

getEntityStates


GarageServerIO.getEntityStates() : [, entityState]

entityStates
Type: array of object literals

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