Today, I would like to see if I can restart my (fab) game without the usual assorted problems. Before the switch to a permanent store (naturally CouchDB) this would have been impossible. At this point, I only need to restore the in-code
setTimeout
s, which are used to idle timeout players. Every other attribute should already be in CouchDB.First up, I return the idle timeout epoch milliseconds from the
idle_timeout
method:timeout: 30*60*1000,The actual
timeouts: { },
idle_watch: function(id) {
if (this.timeouts[id])
clearTimeout(this.timeouts[id]);
var self = this;
this.timeouts[id] = setTimeout(function() {
Logger.info("timeout " + id +"!");
self.drop_player(id);
}, self.timeout);
return (new Date((new Date()).getTime() + self.timeout)).getTime();
}
setTimeout
is specified in milliseconds that it will run. I hope to use the epoch seconds returned from idle_timeout
to re-establish timeouts. The difference between the epoch milliseconds and the current epoch milliseconds is the remaining number of milliseconds in the timeout:node> new Date((new Date()).getTime() + 30*60*1000).getTime();The only time the
1283131853957
node> new Date(1283131853957);
Mon, 30 Aug 2010 01:30:53 GMT
node> 1283131853957 - (new Date).getTime();
1533424
idle_timeout
gets updated is during update_player
. That method is also responsible for storing updated player status in the backend. I can use that to store the timeout time:update_player_status: function(status) {With that being stored in CouchDB:
var self = this;
this.get(status.id, function(player) {
Logger.debug("[players.update_player_status] " + inspect(player));
if (player) {
Logger.info("players.update_player_status: " + status.id);
player.status = status;
player.timeout = self.idle_watch(status.id);
db.saveDoc(player);
}
else {
Logger.warn("[players.update_player_status] unknown player: " + status.id + "!");
}
});
}
I can add a bit of code to the
players
init()
method to attempt to restore player timeout:init: function() {That seems to work just fine unless a player needs to be deleted. In that can, the
var self = this;
// Now, in epoch milliseconds
var now = (new Date()).getTime();
// Grab all players from CouchDB
self.all(function(players) {
players.forEach(function(player){
// Difference between recorded time and now
var timeout = player.timeout - now;
// If time left before timeout, begin the wait again
if (timeout > 0) {
Logger.info("[init_timeouts] " + player._id + " " + timeout);
self.idle_watch(player._id, timeout);
}
// Otherwise drop the player
else {
Logger.info("[init_timeouts] dropping: " + player._id);
self.drop_player(player._id);
}
});
});
// Ensure that the faye server has fully established by waiting
// half a second before subscribing to channels
setTimeout(function(){ self.init_subscriptions(); }, 500);
return self;
}
drop_player()
method needs to broadcast via faye that the player is no longer in the room. The problem is that the faye client is not immediately available.To get around this, I move the restore-players functionality into an
init_players()
method to be invoked after the faye client is ready:init: function() {That is all well and good, but does it work?
var self = this;
// Ensure that the faye server has fully established by waiting
// half a second before subscribing to channels
setTimeout(function(){
self.init_subscriptions();
self.init_players();
}, 500);
return self;
}
That is pretty freaking cool! I move my player about in the room a little while, then stop the node.js server with a Ctrl+C. After waiting a few seconds, I restart the server and see that the timeout is restored:
cstrom@whitefall:~/repos/my_fab_game$ ./game.jsMost importantly, I can continue playing as if nothing happened.
[INFO] Starting up...
[INFO] [init_timeouts] bob 1793694
...
Day #210
No comments:
Post a Comment