diff --git a/client/garageserver.io.js b/client/garageserver.io.js index 225ac46..3b9c501 100644 --- a/client/garageserver.io.js +++ b/client/garageserver.io.js @@ -1,14 +1,16 @@ /* options = { - onConnect: function() + onPlayerConnect: function() + onPlayerDisconnect: function (), + onPlayerReconnect: function (), onPlayerUpdate: function (data), - onPlayerDisconnect: function (id), + onPlayerRemove: function (id), onPing: function (data), + onUpdatePlayerPhysics: function (state, inputs), + onInterpolation: function(previousState, targetState, amount) logging: true, clientSidePrediction: true, - onUpdatePlayerPhysics: function (state, inputs), interpolation: true, - onInterpolation: function(statePrevious, stateTarget, amount) pingInterval: 2000 } */ @@ -21,23 +23,37 @@ window.GarageServerIO = (function (window, socketio) { players = [], inputs = [], currentState = {}, + currentTime, + currentDelta, + currentPlayerId, options = null, pingDelay = 100, - // TODO: DONE CALLBACK connectToGarageServer = function (path, opts) { - socket = io.connect(path + '/garageserver.io'); options = opts; + socket = io.connect(path + '/garageserver.io'); registerSocketEvents(); registerPinger(); }, registerSocketEvents = function () { + socket.on('connect', function () { + if (options.onPlayerConnect) { + options.onPlayerConnect(); + } + }); + socket.on('disconnect', function () { + if (options.onPlayerDisconnect) { + options.onPlayerDisconnect(); + } + }); + socket.on('reconnect', function () { + if (options.onPlayerReconnect) { + options.onPlayerReconnect(); + } + }); socket.on('update', function(data) { updateState(data); - if (options.logging) { - //console.log('garageserver.io:: socket state update'); - } }); socket.on('ping', function(data) { pingDelay = new Date().getTime() - data; @@ -52,7 +68,7 @@ window.GarageServerIO = (function (window, socketio) { } }); }, - + registerPinger = function () { var interval = 2000; if (options.pingInterval) { @@ -62,8 +78,11 @@ window.GarageServerIO = (function (window, socketio) { socket.emit('ping', new Date().getTime()); }, interval); }, - + updateState = function (data) { + currentTime = data.time - pingDelay / 2; + currentDelta = data.delta; + updatePlayerState(data); updateEntityState(data); }, @@ -83,6 +102,7 @@ window.GarageServerIO = (function (window, socketio) { if (socket.socket.sessionid === playerState.id) { currentState = playerState.state; + currentPlayerId = playerState.id; if (options.clientSidePrediction) { for (updateIdx = 0; updateIdx < inputs.length; updateIdx ++) { @@ -111,6 +131,9 @@ window.GarageServerIO = (function (window, socketio) { } break; } + if (players[playerIdx].updates.length > 60) { + players[playerIdx].updates.splice(0, players[playerIdx].updates.length - 60); + } } if (!playerFound) { @@ -141,8 +164,8 @@ window.GarageServerIO = (function (window, socketio) { } } - if (options.onPlayerDisconnect) { - options.onPlayerDisconnect(id); + if (options.onPlayerRemove) { + options.onPlayerRemove(id); } }, @@ -162,28 +185,68 @@ window.GarageServerIO = (function (window, socketio) { sendPlayerInput = function (clientInput) { socket.emit('input', { input: clientInput, seq: sequenceNumber }); }, + + getPositions = function (playerUpdates) { + var positions = {}, + range, + difference, + amount; + + for (var updateIdx = 0; updateIdx < playerUpdates.length; updateIdx ++) { + var previous = playerUpdates[updateIdx]; + var target = playerUpdates[updateIdx + 1]; + + if(currentTime > previous.time && currentTime < target.time) { + range = target.time - previous.time; + difference = currentTime - previous.time; + amount = Math.toFixed( difference / range, 3); + + positions.previousState = previous.state; + positions.targetState = target.state; + positions.amount = amount; + + break; + } + } + return positions; + }, getPlayerStates = function (stateCallback) { var maxUpdate = 0; for (var playerIdx = 0; playerIdx < players.length; playerIdx ++) { if (players[playerIdx].updates.length > 0) { - if (options.interpolation) { - - + maxUpdate = players[playerIdx].updates.length - 1; + if (options.interpolation && options.onInterpolation) { + var positions = getPositions(players[playerIdx].updates); + if (positions.previousState && positions.targetState) { + stateCallback(options.onInterpolation(positions.previousState, positions.targetState, positions.amount)); + } + else { + stateCallback(players[playerIdx].updates[maxUpdate].state); + } } else { - maxUpdate = players[playerIdx].updates.length - 1; stateCallback(players[playerIdx].updates[maxUpdate].state); } } } stateCallback(currentState); + }, + + getPlayerId = function () { + return currentPlayerId; + }, + + setPlayerState = function (state) { + socket.emit('state', state); }; return { connectToGarageServer: connectToGarageServer, addPlayerInput: addPlayerInput, - getPlayerStates: getPlayerStates + getPlayerStates: getPlayerStates, + getPlayerId: getPlayerId, + setPlayerState: setPlayerState }; }) (window, io); \ No newline at end of file diff --git a/example/public/javascripts/game.js b/example/public/javascripts/game.js index ea4e981..fa5e52e 100644 --- a/example/public/javascripts/game.js +++ b/example/public/javascripts/game.js @@ -21,6 +21,14 @@ $(function () { } } return state; + }, + onInterpolation: function (previousState, targetState, amount) { + var newState = {}; + + newState.x = (previousState.x + amount * (targetState.x - previousState.x)); + newState.y = (previousState.y + amount * (targetState.y - previousState.y)); + + return newState; } }); diff --git a/lib/server/garageserver.io.js b/lib/server/garageserver.io.js index 63c215f..3b5c764 100644 --- a/lib/server/garageserver.io.js +++ b/lib/server/garageserver.io.js @@ -9,6 +9,7 @@ options = { onPlayerInput: function (socket, input), onPlayerDisconnect: function (socket), onPing: function (socket, data), + onState: function (socket, data), onUpdatePlayerPhysics: function (state, inputs), } */ @@ -48,6 +49,13 @@ GarageServer.prototype.registerSocketEvents = function (options) { } self.onPing(socket, data, options); }); + + socket.on('state', function (data) { + if (options.logging) { + console.log('garageserver.io:: socket state ' + data); + } + self.onPing(socket, data, options); + }); }); }; @@ -80,6 +88,13 @@ GarageServer.prototype.onPing = function (socket, data, options) { } }; +GarageServer.prototype.onState = function (socket, data, options) { + this.game.setPlayerState(socket, data); + if (options.onState) { + options.onState(socket, data); + } +}; + exports.createGarageServer = function (io, options) { return new GarageServer(io, options); }; \ No newline at end of file diff --git a/lib/server/garageservergame.js b/lib/server/garageservergame.js index 4d47879..1c15133 100644 --- a/lib/server/garageservergame.js +++ b/lib/server/garageservergame.js @@ -5,9 +5,11 @@ function GarageServerGame(options) { this.entities = []; this.options = options; this.startTime = new Date().getTime(); + this.physicsInterval = options.physicsInterval ? options.physicsInterval : 15; + this.stateInterval = options.stateInterval ? options.stateInterval : 45; - this.physicsIntervalId = setInterval(function () { self.updatePhysics(options); }, options.physicsInterval ? options.physicsInterval : 15); - this.stateIntervalId = setInterval(function () { self.updateState(options); }, options.stateInterval ? options.stateInterval : 45); + this.physicsIntervalId = setInterval(function () { self.updatePhysics(options); }, this.physicsInterval); + this.stateIntervalId = setInterval(function () { self.updateState(options); }, this.stateInterval); } GarageServerGame.prototype.updateState = function (options) { @@ -17,7 +19,7 @@ GarageServerGame.prototype.updateState = function (options) { GarageServerGame.prototype.updatePlayers = function (options) { var currentTime = new Date().getTime() - this.startTime, - state = { time: currentTime, playerStates: [] }, + state = { time: currentTime, delta: this.physicsInterval, playerStates: [] }, i = 0; for (i = 0; i < this.players.length; i ++) { @@ -72,6 +74,16 @@ GarageServerGame.prototype.removePlayer = function (client) { } }; +GarageServerGame.prototype.setPlayerState = function (client, state) { + for (var i = 0; i < this.players.length; i ++) { + if (this.players[i].client.id === client.id) { + this.players[i].state = state; + this.players[i].sequence += 1; + this.players[i].inputs = []; + } + } +}; + GarageServerGame.prototype.addPlayerInput = function (client, input) { for (var i = 0; i < this.players.length; i ++) { if (this.players[i].client.id === client.id) {