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 and to the point. For a more thorough demonstration of how GarageServer.IO works, look at the example included in the source code.
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 and storing state history.
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)
Establish connection to GarageServer.IO on the server via Socket.IO and register events.
path string
The URL that points to where GarageServer.IO is running at on the server.
options object literal
Configure the different options, events, callbacks that you would like to consume on the client.
options.onPlayerConnect(callback)
Once the client has made a connection to the server, this event will fire.
callback function
Function to be invoked upon event firing.
options.onPlayerDisconnect(callback)
If client has has disconnected from the server, this event will fire.
callback function
Function to be invoked upon event firing.
options.onPlayerReconnect(callback)
If client has has disconnects and reconnects to the server, this event will fire.
callback function
Function to be invoked upon event firing.
options.onPlayerUpdate(callback(state))
callback function
Function to be invoked upon event firing.
state object literal
options.onEntityUpdate(callback(state))
callback function
Function to be invoked upon event firing.
state object literal
options.onPlayerRemove(callback(id))
callback function
id string
options.onEntityRemove(callback(id))
callback function
id string
options.onEvent(callback(data))
callback function
data object literal
options.onWorldState(callback(state))
callback function
state object literal
options.onPing(callback(pingDelay))
callback function
pingDelay number
options.onUpdatePlayerPrediction(callback(state, inputs, deltaTime) : newState)
Returns: object literal
callback function
state object literal
inputs array
deltaTime number
options.onInterpolation(callback(previousState, targetState, amount) : newState)
Returns: object literal
callback function
previousState object literal
targetState object literal
amount number
options.onReady(callback)
callback function
options.logging: true
logging boolean
addInput
GarageServerIO.addInput(input)
input object literal
getPlayerStates
GarageServerIO.getPlayerStates() : [, {id, state}]
Returns: array
id string
state object literal
getEntityStates
GarageServerIO.getEntityStates() : [, {id, state}]
Returns: array
id string
state object literal
getId
GarageServerIO.getId() : playerid
Returns: string
playerid string
sendServerEvent
GarageServerIO.sendServerEvent(data)
data object literal
Server
createGarageServer
require('garageserver.io').createGarageServer(io, options) : GarageServerIO
io Socket.IO instance
options object literal
options.stateInterval
number
options.logging
boolean
options.clientSidePrediction
boolean
options.interpolation
boolean
options.interpolationDelay
number
options.smoothingFactor
number
options.pingInterval
number
options.maxUpdateBuffer
number
options.maxHistorySecondBuffer
number
options.worldState
object literal
options.onPlayerConnect(callback(socket))
callback function
socket Socket
options.onPlayerInput(callback(socket, input))
callback function
socket Socket
input object literal
options.onPlayerDisconnect(callback(socket))
callback function
socket Socket
options.onPing(callback(socket, data))
callback function
socket Socket
data object literal
options.onEvent(callback(data))
callback function
data object literal
start
GarageServerIO.start()
stop
GarageServerIO.stop()
getPlayers
GarageServerIO.getPlayers() : [, {id, state, [, inputs], [, {states, executionTimes}]}]
Returns: array
id string
state object literal
inputs array of object literals
stateHistory array of object literals
getEntities
GarageServerIO.getEntities() : [,{id, state, [, {state, executionTime }]}]
Returns: array
id string
state object literal
stateHistory array of object literals
updatePlayerState
GarageServerIO.updatePlayerState(id, state)
id string
state object literal
updateEntityState
GarageServerIO.updateEntityState(id, state)
id string
state object literal
addEntity
GarageServerIO.addEntity(id)
id string
removeEntity
GarageServerIO.removeEntity(id)
id string
sendPlayerEvent
GarageServerIO.sendPlayerEvent(id, data)
id string
data object literal
sendPlayersEvent
GarageServerIO.sendPlayersEvent(data)
data object literal