-
Notifications
You must be signed in to change notification settings - Fork 9
Tests #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Tests #17
Changes from all commits
06f551a
3594076
c725114
dcfb85c
b9e2498
354b6e1
b72be3b
9673b80
ee0cfac
eff9210
b707e47
579a1b9
75465da
d1e5792
51b4358
dab0c9b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,8 +66,6 @@ module.exports = function (app) { | |
|
||
var gamedata = games.join(pin, { session: {} }, { ua: req.headers['user-agent'] }); | ||
|
||
|
||
|
||
console.log('-------------------'); | ||
console.log(gamedata.game.players); | ||
|
||
|
@@ -115,62 +113,81 @@ module.exports = function (app) { | |
res.send(true); | ||
}); | ||
|
||
/** | ||
* Status: start a new game or hang an xhr until two players have joined. | ||
* | ||
* If there's no pin present (or no game for the given pin) then a new game is | ||
* created by getPin, then retrieved by get(pin), and then the current user | ||
* joins that new game. | ||
* | ||
* The pin is saves in req.session.pin and req.session.ingame, and the xhr | ||
* is closed with a 'start' event. | ||
* | ||
* -- | ||
* | ||
* If there is a pin and matching game, it will do one of two things... | ||
* | ||
* If the game is in one of a few states (isn't the FSM supposed to manage | ||
* that stuff?) then it must be ready to go, so close the xhr right away (via | ||
* ready()), passing back various bits of data. | ||
* | ||
* If it's not yet ready, (ie, waiting), then we wait on the FSM changing | ||
* state before closing the XHR. | ||
*/ | ||
app.get('/status/:pin?', function (req, res, next) { | ||
var pin = req.params.pin, | ||
game = games.get(req.pin); | ||
if (req.xhr) { | ||
if (pin && game) { | ||
var ready = function () { | ||
var turn = game.isCurrentPlayer(req.session.playerId), | ||
otherLetter = req.session.playerId === 'a' ? 'b' : 'a', | ||
me = { | ||
letter: req.session.playerId, | ||
score: game.getPlayerByLetter(req.session.playerId).score | ||
}, | ||
them = { | ||
letter: otherLetter, | ||
score: game.getPlayerByLetter(otherLetter).score | ||
}; | ||
|
||
res.send({ | ||
type: 'ready', | ||
data: { | ||
towin: game.towin, | ||
gameover: game.state === 'gameover', | ||
me: me, | ||
them: them, | ||
currentPlayer: turn ? req.session.playerId : otherLetter, | ||
turn: req.session.debug ? true : turn | ||
} | ||
}); | ||
}; | ||
|
||
if (game.state === 'ready' || game.state === 'playing' || game.state === 'gameover') { | ||
ready(); | ||
} else if (game.state === 'waiting') { | ||
console.log('waiting for game to start'); | ||
|
||
// FIXME this event isn't being picked up at all | ||
game.on('state.ready', ready); | ||
} | ||
} else { | ||
// start a game | ||
pin = req.session.pin = games.getPin(req.session); | ||
|
||
game = games.get(pin); | ||
var gamedata = games.join(pin, req, { ua: req.headers['user-agent'] }); | ||
console.log(pin, game); | ||
// console.log('xhr?', req.xhr); | ||
// if (!req.xhr) return next(); | ||
if (pin && game) { | ||
var ready = function () { | ||
var turn = game.isCurrentPlayer(req.session.playerId), | ||
otherLetter = req.session.playerId === 'a' ? 'b' : 'a', | ||
me = { | ||
letter: req.session.playerId, | ||
score: game.getPlayerByLetter(req.session.playerId).score | ||
}, | ||
them = { | ||
letter: otherLetter, | ||
score: game.getPlayerByLetter(otherLetter).score | ||
}; | ||
|
||
req.session.playerId = gamedata.playerId; | ||
req.session.ingame = pin; | ||
res.send({ | ||
type: 'start', | ||
type: 'ready', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I added in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ignore me, I checked start.js and it is used.... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Blimey - right, I realise what's happened here, the diff has said it's a change from 'start' to 'ready' which now looking makes no sense, otherwise the game would have never started, but in fact github is diffing two completely different lines - hence my confusion! |
||
data: { | ||
pin: pin | ||
towin: game.towin, | ||
gameover: game.state === 'gameover', | ||
me: me, | ||
them: them, | ||
currentPlayer: turn ? req.session.playerId : otherLetter, | ||
turn: req.session.debug ? true : turn | ||
} | ||
}); | ||
}; | ||
|
||
if (game.state === 'ready' || game.state === 'playing' || game.state === 'gameover') { | ||
ready(); | ||
} else if (game.state === 'waiting') { | ||
console.log(pin, 'waiting for game to start'); | ||
|
||
game.on('state.ready', ready); | ||
} | ||
} else { | ||
next(); | ||
// start a game | ||
pin = req.session.pin = games.getPin(req.session); | ||
|
||
game = games.get(pin); | ||
var gamedata = games.join(pin, req, { ua: req.headers['user-agent'] }); | ||
|
||
req.session.playerId = gamedata.playerId; | ||
req.session.ingame = pin; | ||
res.send({ | ||
type: 'start', | ||
data: { | ||
pin: pin | ||
} | ||
}); | ||
} | ||
}); | ||
|
||
|
@@ -193,12 +210,17 @@ module.exports = function (app) { | |
var result = false; | ||
if (req.session.ingame) { | ||
// player should leave this game first | ||
var game = games.get(req.session.ingame); | ||
game.leave(game.getOtherPlayer(req.session.playerId).id); | ||
var game = games.get(req.session.ingame), | ||
player = game.getOtherPlayer(req.session.playerId); | ||
if (player) game.leave(player.id); | ||
} | ||
res.send(result); | ||
}); | ||
|
||
/** | ||
* Join a game. Hit when join form is submitted. This may create the game if | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Hit" not to be confused with "hit" game wording! :) |
||
* it does not exist. | ||
*/ | ||
app.post('/join', function (req, res) { | ||
// TODO test if there's an active game under that pin, | ||
// if so, allow join and remove from cache | ||
|
@@ -222,27 +244,33 @@ module.exports = function (app) { | |
req.session.ingame = pin; | ||
|
||
if (req.xhr) { | ||
res.send(true); | ||
} else { | ||
res.redirect('/play'); | ||
} | ||
} else if (game) { | ||
console.log('failed joining - game may be full'); | ||
if (req.xhr) { | ||
res.send(false); | ||
} else { | ||
res.render('join', { | ||
'message': "That game is full!" | ||
}); | ||
return res.send(true); | ||
} | ||
} else if (req.xhr) { | ||
console.log('no game data'); | ||
return res.redirect('/play'); | ||
} | ||
|
||
// I don't think this can happen, becuase in the case of a falsey game, a | ||
// new one is created (above) | ||
console.log('failed joining - game may be full'); | ||
if (req.xhr) { | ||
res.send(false); | ||
} else { | ||
res.redirect('/join/' + pin); | ||
res.render('join', { | ||
'message': "That game is full!" | ||
}); | ||
} | ||
}); | ||
|
||
/** | ||
* All roads lead to the player view. | ||
* | ||
* Headshot is almost a single page app, but with server state and | ||
* code injection. | ||
* | ||
* All scripts are injected simultanously and manage their own initialisation. | ||
* Mostly it's in start.js where getState conspires with init to pick what to | ||
* show to the user. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ...because WebRTC under deadlines and upgrading beta browsers is a shit to work with - and all roads (apparently, against my better judgement) lead to SPAs. |
||
*/ | ||
app.get(['/play', '/join', '/start', '/join/:pin?', '/start/:pin?'], function (req, res, next) { | ||
var debug = req.session.debug || false; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,43 +17,53 @@ turnEl.on('animationend', removeTurnClass); | |
var timer = null, | ||
title = document.title; | ||
|
||
/** | ||
* Status opens an xhr to /status or /status/:pin. | ||
* | ||
* This will: | ||
* - if there's no pin | ||
* - create a game and re-request /status/:pin | ||
* - otherwise | ||
* - hang until another player joins and the xhr closes | ||
* - then: | ||
* - the URL is updated | ||
* - user's score and turn bindings are set up | ||
* - the game ('play' in game.js) is init'd | ||
*/ | ||
function status(callback) { | ||
callback = callback || function () {}; | ||
clearTimeout(timer); | ||
xhr.get('/status/' + (pin ? pin : ''), function (err, result) { | ||
if (err) { | ||
console.log(this); | ||
timer = setTimeout(status, 5000); | ||
} | ||
if (result) { | ||
if (result.type === 'ready') { | ||
window.history.replaceState({}, title, '/play'); | ||
window.game = new Bind(result.data, { | ||
'me.score': '#myscore', | ||
'them.score': function (value) { | ||
$.trigger('theirScore', value); | ||
}, | ||
'turn': function (myturn) { | ||
turnEl.dataset.turn = myturn; | ||
$.trigger('myturn', myturn); | ||
} | ||
}); | ||
towin = window.game.towin; | ||
play.init(); | ||
if (!ready) { | ||
waiting[0].hidden = false; | ||
if (!result) return callback(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tend to refer exit routes at the end - only for reading from top to bottom (and/or typical code routes taking higher presidence). |
||
if (result.type === 'ready') { | ||
window.history.replaceState({}, title, '/play'); | ||
window.game = new Bind(result.data, { | ||
'me.score': '#myscore', | ||
'them.score': function (value) { | ||
$.trigger('theirScore', value); | ||
}, | ||
'turn': function (myturn) { | ||
turnEl.dataset.turn = myturn; | ||
$.trigger('myturn', myturn); | ||
} | ||
|
||
// this is done after play.init to ensure the event order is right | ||
} else if (result.type === 'start') { | ||
setPin(result.data.pin); | ||
window.history.replaceState({}, title, '/start/' + pin); | ||
status(); | ||
}); | ||
towin = window.game.towin; | ||
play.init(); | ||
if (!ready) { | ||
waiting[0].hidden = false; | ||
} | ||
} | ||
|
||
if (callback) { | ||
callback(); | ||
// this is done after play.init to ensure the event order is right | ||
} else if (result.type === 'start') { | ||
setPin(result.data.pin); | ||
window.history.replaceState({}, title, '/start/' + pin); | ||
status(); | ||
} | ||
callback(); | ||
}); | ||
} | ||
|
||
|
@@ -126,6 +136,12 @@ function tap(el, handler) { | |
el.on('click', handler, false); | ||
} | ||
|
||
/** | ||
* Extract state and pin from the URL. | ||
* | ||
* `pin` is in the global scope, so this just modifies that, and returns the | ||
* state, which is the first part of the URL. | ||
*/ | ||
function getState() { | ||
var l = window.location, | ||
state = 'join', | ||
|
@@ -157,6 +173,9 @@ function getState() { | |
return state; | ||
} | ||
|
||
/** | ||
* Decide how load the app. Initialiased based on the state from getState. | ||
*/ | ||
function init(state) { | ||
console.log(state, pin); | ||
if (state === 'start' || (state === 'join' && pin)) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"isn't the FSM supposed to manage that stuff" - it does manage it (we don't change the state or any properties of the FSM), but I think you mean shouldn't the FSM be responsible for firing the callback? If so, then you could (not you should, I mean for discussion) add a new method on the FSM in the various states that allow you to pass in the
req
object so that when the game is ready (or in a playing-type state) then it sends the response back to the client.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think one reason I listen for the state change here and not pass in the
req
object, is because I refer to see all the request and response handling in this simple router.