Resolved: #12 Regions - limit state bandwidth

This commit is contained in:
Jeremiah Billmann
2013-08-23 13:30:13 -04:00
parent e805c2d991
commit 790c69305a
8 changed files with 132 additions and 30 deletions
+1
View File
@@ -11,6 +11,7 @@ A simple, lightweight, HTML multiplayer game server (and client) for Node.js
- Server State History
- Server and Client Messaging
- Server Reconciliation
- Region Broadcasting
- Works with any rendering and/or physics engine
## Install
+27 -1
View File
@@ -236,4 +236,30 @@ GarageServerIO.sendPlayersEvent(data)
```
Allows server to broadcast events to all players. Use this to make custom calls to GarageServer.IO clients for your game.
`data` **object literal**
Object containing all properties specific to the custom event.
Object containing all properties specific to the custom event.
#### setPlayerRegion
---
```js
GarageServerIO.setPlayerRegion(id, region)
```
Sets the player region. GarageServer.IO will broadcast the state of players and entities who share the same region. NOTE: This will implicitly enable GarageServer.IO region broadcasting - only those players and entities with regions with be notified of state. Use `clearRegions` to revert region broadcasting.
`id` **string**
Id of the player to receive event.
`region` **string**
Name of the region.
#### setEntityRegion
---
```js
GarageServerIO.setEntityRegion(id, region)
```
Sets the entity region. GarageServer.IO will broadcast the state of players and entities who share the same region. NOTE: This will implicitly enable GarageServer.IO region broadcasting - only those players and entities with regions with be notified of state. Use `clearRegions` to revert region broadcasting.
`id` **string**
Id of the entity to receive event.
`region` **string**
Name of the region.
#### clearRegions
---
```js
GarageServerIO.clearRegions()
```
Clears all regions associated with players and entities. GarageServer.IO will default back to broadcasting state to all players.
+5
View File
@@ -32,5 +32,10 @@ EntityController.prototype = {
return;
}
}
},
clearRegions: function () {
for (var i = 0; i < this.entities.length; i ++) {
this.entities[i].setRegion('');
}
}
};
+4 -4
View File
@@ -9,11 +9,11 @@ function PlayerController (maxHistorySecondBuffer) {
PlayerController.prototype = Object.create(entityController.prototype);
PlayerController.prototype.add = function (client) {
PlayerController.prototype.add = function (socket) {
var newPlayer, playerFound = false;
this.entities.some(function (player) {
if (player.client.id === client.id) {
if (player.id === socket.id) {
newPlayer = player;
playerFound = true;
return true;
@@ -21,7 +21,7 @@ PlayerController.prototype.add = function (client) {
});
if (!playerFound) {
newPlayer = new player(client, this.maxHistorySecondBuffer);
newPlayer = new player(socket, this.maxHistorySecondBuffer);
this.entities.push(newPlayer);
}
return newPlayer;
@@ -29,7 +29,7 @@ PlayerController.prototype.add = function (client) {
PlayerController.prototype.addInput = function (id, input, sequence, time) {
this.entities.some(function (player) {
if (player.client.id === id) {
if (player.id === id) {
player.inputs.push({ input: input, seq: sequence, time: time });
return true;
}
+4
View File
@@ -8,6 +8,7 @@ function Entity (id, maxHistorySecondBuffer) {
this.id = id;
this.maxHistorySecondBuffer = maxHistorySecondBuffer;
this.stateHistory = [];
this.region = '';
}
Entity.prototype = {
@@ -31,5 +32,8 @@ Entity.prototype = {
if (spliceTo > 0) {
this.stateHistory.splice(0, spliceTo);
}
},
setRegion: function (region) {
this.region = region;
}
};
+9 -3
View File
@@ -2,14 +2,20 @@ var entity = require('./entity');
exports = module.exports = Player;
function Player (client, maxHistorySecondBuffer) {
entity.call(this, client.id, maxHistorySecondBuffer);
this.client = client;
function Player (socket, maxHistorySecondBuffer) {
entity.call(this, socket.id, maxHistorySecondBuffer);
this.socket = socket;
this.inputs = [];
}
Player.prototype = Object.create(entity.prototype);
Player.prototype.setRegion = function (region) {
this.socket.join(region);
this.socket.leave(this.region);
this.region = region;
};
Player.prototype.addState = function (state, executionTime) {
this.addHistory(state, executionTime);
this.sequence += this.inputs.length;
+18 -2
View File
@@ -37,8 +37,12 @@ function GarageServer(socketio, options) {
this.socketPath = namespace;
this.io = socketio;
this.registerSocketEvents(options);
this.game = new garageServerGame(options, function (state) {
socketio.of(namespace).emit('update' ,state);
this.game = new garageServerGame(options, function (state, region) {
if (!region) {
socketio.of(namespace).emit('update' ,state);
} else {
socketio.of(namespace).in(region).emit('update' ,state);
}
});
}
@@ -163,6 +167,18 @@ GarageServer.prototype.sendPlayersEvent = function (data) {
this.io.of(this.socketPath).emit('event', data);
};
GarageServer.prototype.setPlayerRegion = function (id, region) {
this.game.setPlayerRegion(id, region);
};
GarageServer.prototype.setEntityRegion = function (id, region) {
this.game.setEntityRegion(id, region);
};
GarageServer.prototype.clearRegions = function () {
this.game.clearRegions();
};
exports.createGarageServer = function (io, options) {
return new GarageServer(io, options);
};
+64 -20
View File
@@ -11,6 +11,7 @@ function GarageServerGame(options, broadcastCallback) {
this.playerController = new playerController(this.options.maxHistorySecondBuffer ? this.options.maxHistorySecondBuffer : 1000);
this.entityController = new entityController(this.options.maxHistorySecondBuffer ? this.options.maxHistorySecondBuffer : 1000);
this.broadcastCallback = broadcastCallback;
this.regions = [];
}
GarageServerGame.prototype.start = function () {
@@ -25,13 +26,20 @@ GarageServerGame.prototype.stop = function () {
};
GarageServerGame.prototype.broadcastState = function () {
var currentTime = new Date().getTime() - this.startTime,
var i = 0, currentTime = new Date().getTime() - this.startTime,
state = { time: currentTime, playerStates: [], entityStates: [] };
state.playerStates = this.getState(this.playerController);
state.entityStates = this.getState(this.entityController);
this.broadcastCallback(state);
if (this.regions.length > 0) {
for (i = 0; i < this.regions.length; i ++) {
state.playerStates = this.getStateByRegion(this.playerController, this.regions[i]);
state.entityStates = this.getStateByRegion(this.entityController, this.regions[i]);
this.broadcastCallback(state, this.regions[i]);
}
} else {
state.playerStates = this.getState(this.playerController);
state.entityStates = this.getState(this.entityController);
this.broadcastCallback(state);
}
};
GarageServerGame.prototype.getState = function (controller) {
@@ -42,6 +50,16 @@ GarageServerGame.prototype.getState = function (controller) {
return states;
};
GarageServerGame.prototype.getStateByRegion = function (controller, region) {
var states = [];
controller.entities.forEach(function (entity) {
if (entity.region === region) {
states.push([ entity.id, entity.state, entity.sequence ]);
}
});
return states;
};
GarageServerGame.prototype.getPlayers = function () {
var list = [];
this.playerController.entities.forEach(function (player) {
@@ -58,18 +76,6 @@ GarageServerGame.prototype.getEntities = function () {
return list;
};
GarageServerGame.prototype.getPlayer = function (id) {
var playerFound;
this.playerController.entities.some(function (player) {
if (player.id === id) {
playerFound = player;
return true;
}
});
return playerFound;
};
GarageServerGame.prototype.updatePlayerState = function (id, state) {
this.updateState(this.playerController, id, state);
};
@@ -89,8 +95,8 @@ GarageServerGame.prototype.updateState = function (controller, id, state) {
});
};
GarageServerGame.prototype.addPlayer = function (client) {
this.playerController.add(client);
GarageServerGame.prototype.addPlayer = function (socket) {
this.playerController.add(socket);
};
GarageServerGame.prototype.removePlayer = function (id) {
@@ -112,8 +118,46 @@ GarageServerGame.prototype.addPlayerInput = function (id, input, sequence, time)
GarageServerGame.prototype.sendPlayerEvent = function (id, data) {
this.playerController.entities.some(function (player) {
if (player.id === id) {
player.client.emit('event', data);
player.socket.emit('event', data);
return true;
}
});
};
GarageServerGame.prototype.setPlayerRegion = function (id, region) {
this.setRegion(this.playerController, id, region);
};
GarageServerGame.prototype.setEntityRegion = function (id, region) {
this.setRegion(this.entityController, id, region);
};
GarageServerGame.prototype.setRegion = function (controller, id, region) {
var self = this;
controller.entities.some(function (entity) {
if (entity.id === id) {
entity.setRegion(region);
self.updateRegions(region);
return true;
}
});
};
GarageServerGame.prototype.updateRegions = function (region) {
var regionFound = false;
this.regions.forEach(function (item) {
if (item === region) {
regionFound = true;
}
});
if (!regionFound) {
this.regions.push(region);
}
};
GarageServerGame.prototype.clearRegions = function () {
this.regions = [];
this.entityController.clearRegions();
this.playerController.clearRegions();
};