mirror of
https://github.com/wassname/GarageServer.IO.git
synced 2026-07-14 01:00:07 +08:00
+64
-41
@@ -5,10 +5,11 @@ options = {
|
||||
onPlayerReconnect: function (),
|
||||
onPlayerUpdate: function (state),
|
||||
onPlayerRemove: function (id),
|
||||
onGameState: function (),
|
||||
onGameState: function (state),
|
||||
onPing: function (pingDelay),
|
||||
onUpdatePlayerPhysics: function (state, inputs, deltaTime),
|
||||
onInterpolation: function(currentState, previousState, targetState, amount)
|
||||
onUpdate: function (),
|
||||
onInterpolation: function(previousState, targetState, amount)
|
||||
logging: true,
|
||||
clientSidePrediction: true,
|
||||
interpolation: true,
|
||||
@@ -24,17 +25,26 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
this.clientTime;
|
||||
this.renderTime;
|
||||
this.physicsDelta;
|
||||
this.physicsIntervalId;
|
||||
this.currentTime;
|
||||
this.accumulator = 0.0;
|
||||
this.playerId;
|
||||
this.pingDelay = 100;
|
||||
this.interpolationDelay = 100;
|
||||
this.fps = 0;
|
||||
this.fpsLastUpdate = (new Date()) * 1 - 1;
|
||||
this.fpsFilter = 50;
|
||||
}
|
||||
StateController.prototype = {
|
||||
setTime: function (serverTime) {
|
||||
this.clientTime = serverTime;
|
||||
this.renderTime = this.clientTime - this.interpolationDelay;
|
||||
},
|
||||
accumulate: function () {
|
||||
var newTime = new Date().getTime(),
|
||||
frameTime = newTime - this.currentTime;
|
||||
if (frameTime > 250) {
|
||||
frameTime = 250;
|
||||
}
|
||||
this.currentTime = newTime;
|
||||
this.accumulator += frameTime;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -74,13 +84,18 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
function Player(id) {
|
||||
this.updates = [];
|
||||
this.id = id;
|
||||
this.currentState = {};
|
||||
}
|
||||
Player.prototype = {
|
||||
anyUpdates: function () {
|
||||
return this.updates.length > 0;
|
||||
},
|
||||
addUpate: function (state, seq, time) {
|
||||
this.updates.push(new Update(state, seq, time));
|
||||
var newUpdate = new Update(state, seq, time);
|
||||
if (this.updates.length === 0) {
|
||||
this.currentState = newUpdate.state;
|
||||
}
|
||||
this.updates.push(newUpdate);
|
||||
if (this.updates.length > 120) {
|
||||
this.updates.splice(0, 1);
|
||||
}
|
||||
@@ -88,17 +103,17 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
getLatestUpdate: function () {
|
||||
return this.updates[this.updates.length - 1];
|
||||
},
|
||||
processState: function (playerState, time) {
|
||||
processState: function (state, seq, time) {
|
||||
var updateFound = false;
|
||||
this.updates.some(function (update) {
|
||||
if (update.seq === playerState.seq) {
|
||||
update.state = playerState.state;
|
||||
if (update.seq === seq) {
|
||||
update.state = state;
|
||||
updateFound = true;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (!updateFound) {
|
||||
this.addUpate(playerState.state, playerState.seq, time);
|
||||
this.addUpate(state, seq, time);
|
||||
}
|
||||
},
|
||||
getSurroundingPositions: function (time) {
|
||||
@@ -141,7 +156,7 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
_inputController = new InputController(),
|
||||
_playerController = new PlayerController(),
|
||||
|
||||
connectToGarageServer = function (path, opts) {
|
||||
initializeGarageServer = function (path, opts) {
|
||||
_options = opts;
|
||||
_socket = _io.connect(path + '/garageserver.io');
|
||||
registerSocketEvents();
|
||||
@@ -161,7 +176,7 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
});
|
||||
_socket.on('state', function(data) {
|
||||
if (_options.onGameState) {
|
||||
_options.onGameState();
|
||||
_options.onGameState(data);
|
||||
}
|
||||
_stateController.physicsDelta = data.physicsDelta;
|
||||
});
|
||||
@@ -195,6 +210,9 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
});
|
||||
_socket.on('removePlayer', function(id) {
|
||||
removePlayer(id);
|
||||
if (_options.onPlayerRemove) {
|
||||
_options.onPlayerRemove(id);
|
||||
}
|
||||
if (_options.logging) {
|
||||
console.log('garageserver.io:: socket removePlayer ' + id);
|
||||
}
|
||||
@@ -211,6 +229,12 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
}, interval);
|
||||
},
|
||||
|
||||
start = function () {
|
||||
var self = this;
|
||||
_stateController.currentTime = new Date().getTime();
|
||||
_stateController.physicsIntervalId = setInterval(function () { self.update(); }, this.physicsDelta * 1000);
|
||||
},
|
||||
|
||||
getPlayerId = function () {
|
||||
return _stateController.playerId;
|
||||
},
|
||||
@@ -221,9 +245,16 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
|
||||
removePlayer = function (id) {
|
||||
_playerController.removePlayer(id);
|
||||
},
|
||||
|
||||
if (_options.onPlayerRemove) {
|
||||
_options.onPlayerRemove(id);
|
||||
update = function () {
|
||||
if (_options.onUpdate) {
|
||||
_stateController.accumulate();
|
||||
while (_stateController.accumulator >= (_stateController.physicsDelta * 1000))
|
||||
{
|
||||
_options.onUpdate();
|
||||
_stateController.accumulator -= (_stateController.physicsDelta * 1000);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -232,7 +263,7 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
if (_options.clientSidePrediction && _options.onUpdatePlayerPhysics) {
|
||||
_stateController.state = _options.onUpdatePlayerPhysics(_stateController.state, [{ input: clientInput }], _stateController.physicsDelta);
|
||||
}
|
||||
_socket.emit('input', { input: clientInput, seq: _inputController.sequenceNumber, time: _stateController.renderTime });
|
||||
_socket.emit('input', [ clientInput, _inputController.sequenceNumber, _stateController.renderTime ]);
|
||||
},
|
||||
|
||||
updateState = function (data) {
|
||||
@@ -244,21 +275,21 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
|
||||
updatePlayersState = function (data) {
|
||||
data.playerStates.forEach(function (playerState) {
|
||||
if (_socket.socket.sessionid === playerState.id) {
|
||||
if (_socket.socket.sessionid === playerState[0]) {
|
||||
updatePlayerState(playerState);
|
||||
} else {
|
||||
updateOtherPlayersState(playerState, data.time);
|
||||
}
|
||||
|
||||
if (_options.onPlayerUpdate) {
|
||||
_options.onPlayerUpdate(playerState.state);
|
||||
_options.onPlayerUpdate(playerState[1]);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updatePlayerState = function (playerState) {
|
||||
_stateController.state = playerState.state;
|
||||
_inputController.removeUpToSequence(playerState.seq);
|
||||
_stateController.state = playerState[1];
|
||||
_inputController.removeUpToSequence(playerState[2]);
|
||||
|
||||
if (_options.clientSidePrediction && _inputController.any()) {
|
||||
_stateController.state = _options.onUpdatePlayerPhysics(_stateController.state, _inputController.inputs, _stateController.physicsDelta);
|
||||
@@ -268,15 +299,15 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
updateOtherPlayersState = function (playerState, time) {
|
||||
var playerFound = false;
|
||||
_playerController.players.some(function (player) {
|
||||
if (player.id === playerState.id) {
|
||||
if (player.id === playerState[0]) {
|
||||
playerFound = true;
|
||||
player.processState(playerState, time);
|
||||
player.processState(playerState[1], playerState[2], time);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (!playerFound) {
|
||||
var newPlayer = _playerController.addPlayer(playerState.id);
|
||||
newPlayer.addUpate(playerState.state, playerState.seq, time);
|
||||
var newPlayer = _playerController.addPlayer(playerState[0]);
|
||||
newPlayer.addUpate(playerState[1], playerState[2], time);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -301,19 +332,20 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
getPlayerStatesInterpolated = function (stateCallback) {
|
||||
var latestUpdate, positions, amount;
|
||||
var positions, amount, newState;
|
||||
_playerController.players.forEach(function (player) {
|
||||
if (player.anyUpdates()) {
|
||||
latestUpdate = player.getLatestUpdate();
|
||||
positions = player.getSurroundingPositions(_stateController.renderTime);
|
||||
if (positions.previous && positions.target) {
|
||||
amount = getInterpolatedAmount(positions.previous.time, positions.target.time);
|
||||
stateCallback(_options.onInterpolation(latestUpdate.state, positions.previous.state, positions.target.state, amount));
|
||||
newState = _options.onInterpolation(positions.previous.state, positions.target.state, amount);
|
||||
player.currentState = newState = _options.onInterpolation(player.currentState, newState, _stateController.physicsDelta * 20);
|
||||
stateCallback(player.currentState);
|
||||
}
|
||||
else {
|
||||
stateCallback(latestUpdate.state);
|
||||
stateCallback(player.currentState);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -325,25 +357,16 @@ window.GarageServerIO = (function (window, socketio) {
|
||||
amount = parseFloat((difference / range).toFixed(3));
|
||||
|
||||
return amount;
|
||||
},
|
||||
|
||||
getFPS = function () {
|
||||
var now,
|
||||
thisFrameFPS = 1000 / ((now = new Date()) - _stateController.fpsLastUpdate);
|
||||
|
||||
_stateController.fps += (thisFrameFPS - _stateController.fps) / _stateController.fpsFilter;
|
||||
_stateController.fpsLastUpdate = now;
|
||||
|
||||
return Math.round(_stateController.fps);
|
||||
};
|
||||
|
||||
return {
|
||||
connectToGarageServer: connectToGarageServer,
|
||||
initializeGarageServer: initializeGarageServer,
|
||||
start: start,
|
||||
update: update,
|
||||
addPlayerInput: addPlayerInput,
|
||||
getPlayerStates: getPlayerStates,
|
||||
getPlayerId: getPlayerId,
|
||||
setPlayerState: setPlayerState,
|
||||
getFPS: getFPS
|
||||
setPlayerState: setPlayerState
|
||||
};
|
||||
|
||||
}) (window, io);
|
||||
+1
-1
@@ -47,5 +47,5 @@ sockets.set('log level', 0);
|
||||
|
||||
garageServer.createGarageServer(sockets,{
|
||||
logging: true,
|
||||
onUpdatePlayerPhysics: gamePhysics.OnProcessGamePhysics
|
||||
onUpdatePlayerPhysics: gamePhysics.onUpdatePlayerPhysics
|
||||
});
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
$(function () {
|
||||
GarageServerIO.connectToGarageServer('http://garageserver_io.jbillmann.c9.io', {
|
||||
var canvas = document.getElementById('gameCanvas'), ctxCanvas = canvas.getContext('2d'), keyboard = new THREEx.KeyboardState(),
|
||||
requestAnimFrame = (function () {
|
||||
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000/60); };
|
||||
})();
|
||||
|
||||
GarageServerIO.initializeGarageServer('http://garageserver_io.jbillmann.c9.io', {
|
||||
logging: true,
|
||||
clientSidePrediction: true,
|
||||
interpolation: true,
|
||||
onUpdatePlayerPhysics: OnProcessGamePhysics,
|
||||
onInterpolation: function (currentState, previousState, targetState, amount) {
|
||||
onUpdatePlayerPhysics: onUpdatePlayerPhysics,
|
||||
onInterpolation: function (previousState, targetState, amount) {
|
||||
var interpolationState = {};
|
||||
interpolationState.x = (previousState.x + amount * (targetState.x - previousState.x));
|
||||
interpolationState.y = (previousState.y + amount * (targetState.y - previousState.y));
|
||||
return interpolationState;
|
||||
}
|
||||
});
|
||||
|
||||
var gameCanvas = document.getElementById('gameCanvas'),
|
||||
keyboard = new THREEx.KeyboardState(),
|
||||
ctxGameCanvas = gameCanvas.getContext('2d'),
|
||||
|
||||
requestAnimFrame = (function () {
|
||||
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000/60); };
|
||||
})(),
|
||||
|
||||
processClientInput = function () {
|
||||
},
|
||||
onUpdate: function () {
|
||||
if (keyboard.pressed('left')) {
|
||||
GarageServerIO.addPlayerInput('left');
|
||||
}
|
||||
@@ -33,22 +28,20 @@ $(function () {
|
||||
if (keyboard.pressed('up')) {
|
||||
GarageServerIO.addPlayerInput('up');
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
draw = function () {
|
||||
ctxGameCanvas.clearRect(0, 0, gameCanvas.width, gameCanvas.height);
|
||||
GarageServerIO.start();
|
||||
GarageServerIO.setPlayerState({ x: 0, y: 0 });
|
||||
render();
|
||||
|
||||
GarageServerIO.getPlayerStates(function (state) {
|
||||
ctxGameCanvas.fillRect(state.x, state.y, 15, 15);
|
||||
});
|
||||
},
|
||||
function render () {
|
||||
requestAnimFrame(render);
|
||||
|
||||
update = function () {
|
||||
requestAnimFrame(update);
|
||||
processClientInput();
|
||||
draw();
|
||||
$('#fps').html('FPS: ' + GarageServerIO.getFPS());
|
||||
};
|
||||
ctxCanvas.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
update();
|
||||
GarageServerIO.getPlayerStates(function (state) {
|
||||
ctxCanvas.fillRect(state.x, state.y, 15, 15);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
(function(exports){
|
||||
|
||||
exports.OnProcessGamePhysics = function (state, inputs, deltaTime) {
|
||||
exports.onUpdatePlayerPhysics = function (state, inputs, deltaTime) {
|
||||
var i = 0;
|
||||
|
||||
if (!state.x && !state.y) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
extends layout
|
||||
|
||||
block content
|
||||
div#fps
|
||||
canvas#gameCanvas
|
||||
@@ -9,7 +9,7 @@ options = {
|
||||
onPlayerInput: function (socket, input),
|
||||
onPlayerDisconnect: function (socket),
|
||||
onPing: function (socket, data),
|
||||
onState: function (socket, data),
|
||||
onPlayerState: function (socket, data),
|
||||
onUpdatePlayerPhysics: function (state, inputs),
|
||||
}
|
||||
*/
|
||||
@@ -39,7 +39,7 @@ GarageServer.prototype.registerSocketEvents = function (options) {
|
||||
|
||||
socket.on('input', function (data) {
|
||||
if (options.logging) {
|
||||
console.log('garageserver.io:: socket input ' + socket.id + ' ' + data.input + ' ' + data.seq);
|
||||
console.log('garageserver.io:: socket input ' + socket.id + ' ' + data[0] + ' ' + data[1]);
|
||||
}
|
||||
self.onPlayerInput(socket, data, options);
|
||||
});
|
||||
@@ -55,7 +55,7 @@ GarageServer.prototype.registerSocketEvents = function (options) {
|
||||
if (options.logging) {
|
||||
console.log('garageserver.io:: socket playerState ' + data);
|
||||
}
|
||||
self.onState(socket, data, options);
|
||||
self.onPlayerState(socket, data, options);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -89,10 +89,10 @@ GarageServer.prototype.onPing = function (socket, data, options) {
|
||||
}
|
||||
};
|
||||
|
||||
GarageServer.prototype.onState = function (socket, data, options) {
|
||||
GarageServer.prototype.onPlayerState = function (socket, data, options) {
|
||||
this.game.setPlayerState(socket, data);
|
||||
if (options.onState) {
|
||||
options.onState(socket, data);
|
||||
if (options.onPlayerState) {
|
||||
options.onPlayerState(socket, data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ GarageServerGame.prototype.updatePlayers = function (options) {
|
||||
state = { time: currentTime, playerStates: [] };
|
||||
|
||||
this.players.forEach(function (player) {
|
||||
state.playerStates.push({ id: player.client.id, state: player.state, seq: player.sequence });
|
||||
state.playerStates.push([ player.client.id, player.state, player.sequence ]);
|
||||
});
|
||||
|
||||
this.players.forEach(function (player) {
|
||||
@@ -54,10 +54,9 @@ GarageServerGame.prototype.addPlayer = function (client) {
|
||||
}
|
||||
});
|
||||
|
||||
// Set player state callback
|
||||
var player = {
|
||||
client: client,
|
||||
state: {x: 0, y: 0},
|
||||
state: {},
|
||||
inputs: [],
|
||||
sequence: 1
|
||||
};
|
||||
@@ -78,7 +77,6 @@ GarageServerGame.prototype.setPlayerState = function (client, state) {
|
||||
this.players.some(function (player) {
|
||||
if (player.client.id === client.id) {
|
||||
player.state = state;
|
||||
player.sequence += 1;
|
||||
player.inputs = [];
|
||||
return true;
|
||||
}
|
||||
@@ -88,7 +86,7 @@ GarageServerGame.prototype.setPlayerState = function (client, state) {
|
||||
GarageServerGame.prototype.addPlayerInput = function (client, input) {
|
||||
this.players.some(function (player) {
|
||||
if (player.client.id === client.id) {
|
||||
player.inputs.push(input);
|
||||
player.inputs.push({ input: input[0], seq: input[1], time: input[2] });
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user