Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of github.com:AdrianGaudebert/tetwis

Conflicts:
	lib/game.js
  • Loading branch information...
commit 46f48ea4bba4239e7a1e171cc39a29cf4063a17f 2 parents 53f0f0e + 3dd83b5
@AdrianGaudebert authored
Showing with 1,162 additions and 283 deletions.
  1. +46 −6 client/css/main.css
  2. +1 −1  client/game.conf
  3. +37 −23 client/index.html
  4. +3 −3 client/js/core/brick.js
  5. +2 −2 client/js/core/cell.js
  6. +10 −12 client/js/core/config.js
  7. +34 −11 client/js/core/displayer.js
  8. +140 −0 client/js/core/engine.js
  9. +6 −6 client/js/core/events.js
  10. +26 −78 client/js/core/game.js
  11. +6 −7 client/js/core/map.js
  12. +126 −0 client/js/core/message-builder.js
  13. +85 −22 client/js/core/message-parser.js
  14. +30 −14 client/js/core/socket.js
  15. +12 −0 client/js/init.js
  16. +10 −0 client/js/libs/jquery.tmpl.js
  17. +2 −0  client/js/libs/socket.io.min.js
  18. +54 −0 client/js/login.js
  19. +19 −13 client/js/main.js
  20. +5 −0 client/js/tetwis.js
  21. +7 −0 client/templates/game.html
  22. +23 −0 client/templates/games-list.html
  23. +5 −0 client/templates/loading.html
  24. +6 −0 client/templates/login.html
  25. +6 −10 lib/client.js
  26. +124 −2 lib/engine.js
  27. +31 −26 lib/game.js
  28. +151 −0 lib/message-builder.js
  29. +119 −32 lib/message-parser.js
  30. +5 −9 lib/player.js
  31. +24 −0 lib/user.js
  32. +7 −6 server.js
View
52 client/css/main.css
@@ -2,20 +2,60 @@
* Main.css
**********************************************************************/
-#content {
- width: 400px;
+button {
+ cursor: pointer;
+}
+
+.clear {
+ clear: both;
+}
+
+#body {
+ margin: auto;
+ width: 900px;
+}
+
+#information {
+ width: 290px;
float: right;
}
- #content h1,
- #content h2 {
+ #information h1,
+ #information h2 {
margin: 0;
text-align: center;
}
- #content h1 {
- font-size: 6.5em;
+ #information h1 {
+ font-size: 4.5em;
margin: 0;
}
+#content {
+ text-align: center;
+}
+ #content .games-list {
+ width: 600px;
+ }
+ #content .games-list ul {
+ margin: 0;
+ padding: 0;
+ }
+ #content .games-list ul li {
+ background-color: #ff9;
+ border: 1px solid #f90;
+ border-radius: 3px;
+ list-style-type: none;
+ list-style-position: outside;
+ padding: 5px 10px;
+ margin: 5px 0;
+ }
+ #content .games-list ul li p {
+ margin: 3px 0;
+ }
+ #content .games-list .join-game {
+ float: right;
+ padding: 9px 18px;
+ }
+
#players {
border: 1px solid black;
background: black;
View
2  client/game.conf
@@ -10,6 +10,6 @@
},
"server": {
"host": null,
- "port": "80"
+ "port": 9309
}
}
View
60 client/index.html
@@ -7,30 +7,37 @@
</head>
<body>
- <div id="content">
- <header>
- <h1>TetWis</h1>
- <h2>Multiplayer Web Tetris Game</h2>
- </header>
+ <div id="body">
+ <div id="information">
+ <header>
+ <h1>TetWis</h1>
+ <h2>Multiplayer Web Tetris Game</h2>
+ </header>
- <p>
- You are <span id="whoami">not connected</span>.
- </p>
- <p>
- Ingame: <span id="ingame-number">0</span>
- </p>
- <p>
- Awaiting: <span id="awaiting-number">0</span>
- </p>
- </div>
+ <div id="player-state">
+ <p>
+ You are <span id="whoami">not connected</span>.
+ </p>
+ </div>
+ <div id="game-state">
+ <p>
+ Ingame: <span id="ingame-number">0</span>
+ </p>
+ <p>
+ Awaiting: <span id="awaiting-number">0</span>
+ </p>
+ </div>
+ </div>
- <div id="players">
- <span id="p1">Player 1</span>
- <span id="p2">Player 2</span>
- <span id="p3">Player 3</span>
- <span id="p4">Player 4</span>
- </div>
- <div id="map"><img src="images/loader.gif" id="loader" alt="Loading..." /><p id="loading-state">Loading configuration...</p></div>
+ <div id="content">
+ <div class="login">
+ <img src="images/loader.gif" id="loader" alt="Loading..." />
+ <p id="loading-state">Loading...</p>
+ </div>
+ </div>
+
+ <div class="clear"></div>
+ </div>
<footer>
<p>
@@ -42,11 +49,17 @@
<ul id="log"></ul>
- <script src="http://cdn.socket.io/stable/socket.io.js"></script>
+ <!--<script src="http://cdn.socket.io/stable/socket.io.js"></script>-->
+
+ <script>var tetwis = {};</script>
+ <script src="js/libs/load.js"></script>
+ <script src="js/login.js"></script>
+<!--
<script src="js/libs/jquery.min.js"></script>
<script src="js/libs/jquery.timers.js"></script>
<script src="js/libs/json2.js"></script>
+ <script src="js/libs/socket.io.min.js"></script>
<script src="js/core/config.js"></script>
<script src="js/core/cell.js"></script>
<script src="js/core/brick.js"></script>
@@ -57,5 +70,6 @@
<script src="js/core/socket.js"></script>
<script src="js/core/game.js"></script>
<script src="js/main.js"></script>
+-->
</body>
</html>
View
6 client/js/core/brick.js
@@ -2,7 +2,7 @@
* Class Brick
* Represents a brick that can be moved
*/
-function Brick(data) {
+tetwis.Brick = function(data) {
this.x = data.x;
this.y = data.y;
this.color = data.color;
@@ -11,9 +11,9 @@ function Brick(data) {
for (var i = 0; i < this.cells.length; i++) {
var cell = this.cells[i];
- this.cells[i] = new Cell(cell);
+ this.cells[i] = new tetwis.Cell(cell);
}
}
-Brick.prototype = {
+tetwis.Brick.prototype = {
}
View
4 client/js/core/cell.js
@@ -1,8 +1,8 @@
-function Cell(data) {
+tetwis.Cell = function(data) {
this.x = data.x;
this.y = data.y;
this.color = data.color;
}
-Cell.prototype = {
+tetwis.Cell.prototype = {
}
View
22 client/js/core/config.js
@@ -1,6 +1,4 @@
-function Config(game) {
- this.game = game;
-
+tetwis.Config = function() {
// TODO couper au dernier slash, si on appelle index.html par exemple
this.configFile = window.location.href + "game.conf";
@@ -9,20 +7,20 @@ function Config(game) {
this.players = null;
};
-Config.prototype = {
+tetwis.Config.prototype = {
- load: function() {
- log("Loading configuration");
+ load: function(callback) {
+ tetwis.log("Loading configuration");
var instance = this;
$.getJSON(this.configFile, function(data) {
- log("Configuration loaded");
+ tetwis.log("Configuration loaded");
- instance.server = data.server;
- instance.map = data.map;
- instance.players = data.players;
+ this.server = data.server;
+ this.map = data.map;
+ this.players = data.players;
- instance.game.launch();
- });
+ callback();
+ }.bind(this));
return this;
},
View
45 client/js/core/displayer.js
@@ -5,20 +5,25 @@
* @author Adrian Gaudebert - adrian@gaudebert.fr
* @constructor
*/
-function Displayer(map, delay) {
- this.map = map;
+tetwis.Displayer = function() {
+ this.mapElt = null;
+ this.contentElt = $('#content');
- this.htmlElt = $('#map');
- this.cellSize = this.map.cellSize;
- this.cellSizeCSS = this.cellSize - 1;
-
- this.delay = delay;
+ this.delay = 100; // TODO move to the config file (see Game)
this.intervalId = null;
}
-Displayer.prototype = {
+tetwis.Displayer.prototype = {
+
+ setMap: function(map) {
+ this.map = map;
+
+ this.cellSize = this.map.cellSize;
+ this.cellSizeCSS = this.cellSize - 1;
+ },
start: function() {
+ this.mapElt = $('#map');
this.intervalId = window.setInterval(this.display.bind(this), this.delay);
return this;
},
@@ -30,22 +35,40 @@ Displayer.prototype = {
display: function() {
// Reset current map
- this.htmlElt.empty();
+ this.mapElt.empty();
// Displaying map
for (var i = 0, size = this.map.cells.length; i < size; i++) {
var cell = this.map.cells[i];
- this.htmlElt.append('<div class="cell" style="top: '+ cell.y * this.cellSize +'px; left: '+ cell.x * this.cellSize +'px; background-color: '+ cell.color +'; width: '+this.cellSizeCSS+'px; height: '+this.cellSizeCSS+'px;"></div>');
+ this.mapElt.append('<div class="cell" style="top: '+ cell.y * this.cellSize +'px; left: '+ cell.x * this.cellSize +'px; background-color: '+ cell.color +'; width: '+this.cellSizeCSS+'px; height: '+this.cellSizeCSS+'px;"></div>');
}
for (var k = 0, nb = this.map.bricks.length; k < nb; k++) {
var currentBrick = this.map.bricks[k];
for (var i = 0, size = currentBrick.cells.length; i < size; i++) {
var cell = currentBrick.cells[i];
- this.htmlElt.append('<div class="cell" style="top: '+ (currentBrick.y + cell.y) * this.cellSize +'px; left: '+ (currentBrick.x + cell.x) * this.cellSize +'px; background-color: '+ cell.color +'; width: '+this.cellSizeCSS+'px; height: '+this.cellSizeCSS+'px;"></div>');
+ this.mapElt.append('<div class="cell" style="top: '+ (currentBrick.y + cell.y) * this.cellSize +'px; left: '+ (currentBrick.x + cell.x) * this.cellSize +'px; background-color: '+ cell.color +'; width: '+this.cellSizeCSS+'px; height: '+this.cellSizeCSS+'px;"></div>');
}
}
return this;
},
+
+ displayTemplate: function(templateURI, data, callback) {
+ this.contentElt.empty();
+
+ $.get(templateURI, function(tpl) {
+
+ $.tmpl(tpl, data).appendTo(this.contentElt);
+
+ if (callback != null) {
+ callback();
+ }
+
+ }.bind(this));
+ },
+
+ setState: function(state) {
+ $('#loading-state').text(state);
+ },
};
View
140 client/js/core/engine.js
@@ -0,0 +1,140 @@
+/**
+ * Class Engine
+ * Central class, creates the configuration, the server connection,
+ * then displays games lists and launches games.
+ *
+ * @author Adrian Gaudebert - adrian@gaudebert.fr
+ * @constructor
+ */
+tetwis.Engine = function() {
+ this.config = null;
+
+ this.socket = null;
+ this.messageParser = null;
+ this.messageBuilder = null;
+
+ this.games = [];
+};
+
+tetwis.Engine.prototype = {
+
+ /**
+ * Initializes the game engine. Creates the MessageParser and MessageBuilder.
+ * @return this.
+ */
+ init: function() {
+ tetwis.mp = this.messageParser = new tetwis.MessageParser(this);
+ tetwis.mb = this.messageBuilder = new tetwis.MessageBuilder();
+
+ return this;
+ },
+
+ /**
+ * Launches the engine by loading the configuration.
+ * @return this.
+ */
+ launch: function() {
+ this.loadConfig();
+ return this;
+ },
+
+ /**
+ * Loads the configuration and places it in the tetwis namespace.
+ * @return this.
+ */
+ loadConfig: function() {
+ tetwis.config = this.config = new tetwis.Config().load( this.onConfigLoaded.bind(this) );
+ return this;
+ },
+
+ /**
+ * Callback function called when the configuration is loaded.
+ */
+ onConfigLoaded: function() {
+ tetwis.displayer.setState("Connecting to the server... ");
+ this.openConnection();
+ },
+
+ /**
+ * Opens a connection to the server.
+ * @return this.
+ */
+ openConnection: function() {
+ tetwis.socket = this.socket = new tetwis.Socket().init( this.onConnectionOpened.bind(this) );
+ return this;
+ },
+
+ /**
+ * Callback function called when the connection to the server is opened.
+ */
+ onConnectionOpened: function() {
+ this.socket.send( this.messageBuilder.createAuthenticationLogin( tetwis.user ) );
+ this.getGamesList();
+ },
+
+ /**
+ * Asks the server for the list of all the existing games.
+ */
+ getGamesList: function() {
+ this.socket.send( this.messageBuilder.createGamesListQuery() );
+ },
+
+ /**
+ * Set the list of the existing games from the server, and displays it.
+ * @param gamesList Array containing the games, coming from the server.
+ */
+ setGamesList: function(gamesList) {
+ this.games = gamesList;
+ this.launchGamesList();
+ },
+
+ /**
+ * Displays the games list and binds the actions.
+ */
+ launchGamesList: function() {
+ var gamesList = { games: this.games };
+ tetwis.displayer.displayTemplate('templates/games-list.html', gamesList, function() {
+ $('#create-game').click(function() {
+ tetwis.engine.createGame();
+ });
+ $('.join-game').click(function() {
+ var gameId = $(this).attr('id');
+ gameId = gameId.split('-');
+ gameId = gameId[1];
+
+ tetwis.engine.joinGame(gameId);
+ });
+ });
+ return this;
+ },
+
+ /**
+ * Asks the server to create a new game and join it.
+ */
+ createGame: function() {
+ this.socket.send( this.messageBuilder.createCreateGameAction() );
+ this.launchNewGame();
+ },
+
+ /**
+ * Asks the server to join an existing new game.
+ * @param gameId ID of the game to join.
+ */
+ joinGame: function(gameId) {
+ this.socket.send( this.messageBuilder.createJoinGameAction(gameId) );
+ this.launchNewGame();
+ },
+
+ /**
+ * Creates a new game and launches it.
+ * @return this.
+ */
+ launchNewGame: function() {
+ /*tetwis.displayer.displayTemplate('templates/loading.html', null, function(data) {
+ tetwis.displayer.setState("Receiving data...");
+ });*/
+ this.game = new tetwis.Game();
+ return this;
+ },
+
+};
View
12 client/js/core/events.js
@@ -1,9 +1,9 @@
-function Events(game) {
+tetwis.Events = function(game) {
this.game = game;
this.bound = $.browser == 'msie' ? '#map' : window;
}
-Events.prototype = {
+tetwis.Events.prototype = {
bindAll: function() {
this.bindKeys();
return this;
@@ -13,11 +13,11 @@ Events.prototype = {
var instance = this;
$(this.bound).keypress(function(e) {
switch(e.charCode || e.keyCode) {
- case 74: case 106: instance.game.moveLeft(); break; // J
- case 76: case 108: instance.game.moveRight(); break; // L
- case 73: case 105: instance.game.changeShape(); break; // I
+ case 74: case 106: this.game.moveLeft(); break; // J
+ case 76: case 108: this.game.moveRight(); break; // L
+ case 73: case 105: this.game.changeShape(); break; // I
}
return false;
- });
+ }.bind(this));
}
}
View
104 client/js/core/game.js
@@ -5,72 +5,49 @@
* @author Adrian Gaudebert - adrian@gaudebert.fr
* @constructor
*/
-function Game() {
+tetwis.Game = function() {
this.initialized = false;
- this.config = null;
-
this.events = null;
- this.socket = null;
- this.mp = null;
- this.displayer = null;
-
this.map = null;
this.score = 0;
this.level = 0;
- this.displayDelay = 100;
-
- this.onReady = null;
+ this.displayDelay = 100; // TODO move to the config file (see Displayer)
}
-Game.prototype = {
-
- loadConfig: function() {
- this.config = new Config(this).load();
- return this;
- },
-
- /**
- * Launches the game: connects to the server and waits for data.
- */
- launch: function() {
- log("Game: launch");
- $('#loading-state').text("Connecting to server...");
- this.mp = new MessageParser(this);
-
- this.socket = new Socket(this, this.mp);
- this.socket.init();
-
- return this;
- },
-
- /**
- * Sets a callback function when the game is ready.
- * @param callback Function to call.
- */
- ready: function(callback) {
- this.onReady = callback;
- },
+tetwis.Game.prototype = {
/**
* Initializes the Game object
*/
init: function(data) {
- log("Game: init");
+ tetwis.log("Game: init");
if (this.initialized == false)
{
- this.events = new Events(this);
+ this.events = new tetwis.Events(this);
this.events.bindAll();
- this.map = new Map(this, data);
+ this.map = new tetwis.Map(data);
+
+ // loading the game template
+ tetwis.displayer.displayTemplate('templates/game.html', null, function() {
+ var cellSize = this.map.cellSize,
+ height = this.map.height * cellSize,
+ width = this.map.width * cellSize;
- this.displayer = new Displayer(this.map, this.displayDelay);
+ $('#map').width(width).height(height);
+ $('#players').width(width);
- this.onReady.call();
+ for (var i = 0; i < tetwis.config.players.number; i++) {
+ $('#p'+(i+1)).css('color', tetwis.config.players.colors[i]);
+ }
- this.displayer.start();
+ tetwis.displayer.setMap(this.map);
+ tetwis.displayer.start();
+
+ }.bind(this));
this.initialized = true;
}
@@ -83,7 +60,6 @@ Game.prototype = {
*/
updateMap: function(data) {
this.map.update(data);
- //~ this.display();
},
updatePlayersInfo: function(data) {
@@ -92,38 +68,10 @@ Game.prototype = {
},
/**
- * Displays the game
- */
- display: function() {
- var mapElt = $('#map'),
- cellSize = this.map.cellSize,
- cellSizeCSS = cellSize - 1;
-
- // Reset current map
- mapElt.empty();
-
- // Displaying map
- for (var i = 0, size = this.map.cells.length; i < size; i++) {
- var cell = this.map.cells[i];
- mapElt.append('<div class="cell" style="top: '+ cell.y * cellSize +'px; left: '+ cell.x * cellSize +'px; background-color: '+ cell.color +'; width: '+cellSizeCSS+'px; height: '+cellSizeCSS+'px;"></div>');
- }
-
- for (var k = 0, nb = this.map.bricks.length; k < nb; k++) {
- var currentBrick = this.map.bricks[k];
- for (var i = 0, size = currentBrick.cells.length; i < size; i++) {
- var cell = currentBrick.cells[i];
- mapElt.append('<div class="cell" style="top: '+ (currentBrick.y + cell.y) * cellSize +'px; left: '+ (currentBrick.x + cell.x) * cellSize +'px; background-color: '+ cell.color +'; width: '+cellSizeCSS+'px; height: '+cellSizeCSS+'px;"></div>');
- }
- }
-
- return this;
- },
-
- /**
* The game is lost, tell so to the player and stop it
*/
gameOver: function() {
- log('Game OVER!');
+ tetwis.log('Game OVER!');
return this;
},
@@ -132,28 +80,28 @@ Game.prototype = {
* @param msg String containing the message to send.
*/
send: function(msg) {
- this.socket.send(msg);
+ tetwis.socket.send(msg);
},
/**
* Asks the server to move our brick to the left.
*/
moveLeft: function() {
- this.send( this.mp.getMoveLeft() );
+ this.send( tetwis.mb.getMoveLeft() );
},
/**
* Asks the server to move our brick to the right.
*/
moveRight: function() {
- this.send( this.mp.getMoveRight() );
+ this.send( tetwis.mb.getMoveRight() );
},
/**
* Asks the server to change the shape of our brick.
*/
changeShape: function() {
- this.send( this.mp.getChangeShape() );
+ this.send( tetwis.mb.getChangeShape() );
},
}
View
13 client/js/core/map.js
@@ -2,18 +2,17 @@
* Map class
* Manages the map, meaning all the cells and the current brick
*/
-function Map(game, data) {
- this.game = game;
+tetwis.Map = function(data) {
- this.width = game.config.map.width;
- this.height = game.config.map.height;
- this.cellSize = game.config.map.cellSize;
+ this.width = tetwis.config.map.width;
+ this.height = tetwis.config.map.height;
+ this.cellSize = tetwis.config.map.cellSize;
this.cells = data.cells;
this.bricks = data.bricks;
}
-Map.prototype = {
+tetwis.Map.prototype = {
update: function(data) {
if (typeof data.cells != undefined && data.cells != null) {
@@ -28,7 +27,7 @@ Map.prototype = {
updateBricks: function() {
for (var i = 0; i < this.bricks.length; i++) {
var brick = this.bricks[i];
- this.bricks[i] = new Brick(brick);
+ this.bricks[i] = new tetwis.Brick(brick);
}
},
}
View
126 client/js/core/message-builder.js
@@ -0,0 +1,126 @@
+/**
+ * Class MessageBuilder
+ * Create messages to send to the server in a simple way.
+ *
+ * @author Adrian Gaudebert - adrian@gaudebert.fr
+ * @constructor
+ */
+tetwis.MessageBuilder = function() {
+}
+
+tetwis.MessageBuilder.prototype = {
+
+ /**
+ * Create the basic structure of a message, and stringify to JSON.
+ * @param type Type of message. Can be "login", "query", "data" or "action".
+ * @param data Object containing data of the message.
+ * @return JSON message to send.
+ */
+ createMessage: function(type, data) {
+ var msg = {
+ type: type,
+ data: data
+ };
+
+ return JSON.stringify(msg);
+ },
+
+ /**
+ * Create a login message, and stringify to JSON.
+ * @param login Username.
+ * @param data Object containing other login data.
+ * @return JSON message to send.
+ */
+ createLogin: function(login, data) {
+ data.username = login;
+ return this.createMessage('login', data);
+ },
+
+ /**
+ * Create a query message, and stringify to JSON.
+ * @param responseMethod Type of message we want to receive in response.
+ * @param responseData Object containing data about this query.
+ * @return JSON message to send.
+ */
+ createQuery: function(responseMethod, responseData) {
+ var data = {};
+ data.response_type = responseMethod;
+ data.query_data = responseData;
+ return this.createMessage("query", data);
+ },
+
+ /**
+ * Create an action message, and stringify to JSON.
+ * @param name Name of the action.
+ * @param data Object containing data about this action.
+ * @return JSON message to send.
+ */
+ createAction: function(name, data) {
+ var actionData = {};
+ actionData.name = name;
+ actionData.action_data = data;
+ return this.createMessage("action", actionData);
+ },
+
+ /**
+ * Create a login message to authenticate on the server.
+ * @param login Login of the user.
+ * @param password Password of the user.
+ * @return JSON message to send.
+ */
+ createAuthenticationLogin: function(login, password) {
+ var data = {};
+ if (password != null) {
+ data.password = password;
+ }
+ return this.createLogin(login, data);
+ },
+
+ /**
+ * Create a query to ask for the games list.
+ * @return JSON message to send.
+ */
+ createGamesListQuery: function() {
+ return this.createQuery('data', { data_name: 'games-list' });
+ },
+
+ createCreateGameAction: function() {
+ return this.createAction("create-game", {});
+ },
+
+ /**
+ * Create an action message to join a game.
+ * @param gameId Identifier of the game to join.
+ * @return JSON message to send.
+ */
+ createJoinGameAction: function(gameId) {
+ var data = {};
+ data.game_id = gameId;
+ return this.createAction("join-game", data);
+ },
+
+ createQueue: function(queue) {
+ return this.createMessage("queue", queue);
+ },
+
+ // TODO: change method name for consistency
+ getChangeBrick: function(action) {
+ return this.createAction(action, {});
+ },
+
+ // TODO: change method name for consistency
+ getMoveLeft: function() {
+ return this.getChangeBrick("move-left");
+ },
+
+ // TODO: change method name for consistency
+ getMoveRight: function() {
+ return this.getChangeBrick("move-right");
+ },
+
+ // TODO: change method name for consistency
+ getChangeShape: function() {
+ return this.getChangeBrick("change-shape");
+ },
+
+}
View
107 client/js/core/message-parser.js
@@ -1,46 +1,109 @@
-function MessageParser(game) {
- this.game = game;
+tetwis.MessageParser = function(engine) {
+ this.engine = engine;
}
-MessageParser.prototype = {
+tetwis.MessageParser.prototype = {
parse: function(msg) {
- var data = JSON.parse(msg);
+ var obj = JSON.parse(msg);
- if (data.method == "get") {
+ if (typeof obj.type != undefined && obj.type != null) {
+ switch (obj.type) {
+ case "query":
+ this.parseQuery(obj.data);
+ break;
+ case "action":
+ this.parseAction(obj.data);
+ break;
+ case "data":
+ this.parseData(obj.data);
+ break;
+ default:
+ throw "Unknown message type"; // TODO: using an object of type Exception
+ }
+ }
+ else {
+ this.parseOld(obj);
+ }
+
+ return this;
+ },
+
+ /**
+ * @deprecated
+ */
+ parseOld: function(data) {
+ if (data.method == "get") {
if (data.object == "map") {
- this.game.init(data.data);
+ this.engine.game.init(data.data);
}
}
else if (data.method == "update") {
if (data.object == "map") {
- this.game.updateMap(data.data);
+ this.engine.game.updateMap(data.data);
}
else if (data.object == "playersInfo") {
- this.game.updatePlayersInfo(data.data);
+ this.engine.game.updatePlayersInfo(data.data);
}
}
+ },
+
+ parseQuery: function(data) {
+ return this;
+ },
+
+ parseAction: function(data) {
+ return this;
},
- getChangeBrick: function(action) {
- return JSON.stringify({
- method: "do",
- object: "brick",
- data: {
- action: action
- },
- });
+ parseData: function(data) {
+ switch (data.method) {
+ case "new":
+ this.parseNewData(data.object, data.object_data);
+ break;
+ case "update":
+ this.parseUpdateData(data.object, data.object_data);
+ break;
+ case "delete":
+ this.parseDeleteData(data.object, data.object_data);
+ break;
+ }
+ return this;
},
- getMoveLeft: function() {
- return this.getChangeBrick("moveLeft");
+ parseNewData: function(object, data) {
+ switch (object) {
+ case "games-list":
+ tetwis.log("Games list received: " + data);
+ this.engine.setGamesList(data);
+ break;
+ case "Game":
+ this.gameEngine.world.gameData(data);
+ break;
+ case "Player":
+ this.gameEngine.world.playerData(data);
+ break;
+ case "Map":
+ this.gameEngine.world.mapData(data);
+ break;
+ }
+ return this;
},
- getMoveRight: function() {
- return this.getChangeBrick("moveRight");
+ parseUpdateData: function(object, data) {
+ switch (object) {
+ case "Game":
+ this.gameEngine.world.gameUpdate(data);
+ break;
+ case "Player":
+ this.gameEngine.world.playerUpdate(data);
+ break;
+ }
+ return this;
},
- getChangeShape: function() {
- return this.getChangeBrick("changeShape");
+ parseDeleteData: function(object, data) {
+ return this;
},
+
}
View
44 client/js/core/socket.js
@@ -1,15 +1,21 @@
-function Socket(game, mp) {
- this.game = game;
- this.mp = mp; // MessageParser
-
+tetwis.Socket = function() {
this._socket = null;
- this.host = game.config.server.host;
- this.port = game.config.server.port;
+ this.host = tetwis.config.server.host;
+ this.port = tetwis.config.server.port;
+
+ this.callback = null;
+
+ this._queue = [];
+ this.delay = 50; // (ms)
}
-Socket.prototype = {
- init: function() {
+tetwis.Socket.prototype = {
+
+ init: function(callback) {
+ tetwis.log("Trying to open a connection to the server... ");
+
+ this.callback = callback;
this._socket = new io.Socket(this.host, { port: this.port, rememberTransport: false });
this._socket.on('connect', this._onOpen.bind(this));
@@ -18,23 +24,25 @@ Socket.prototype = {
this._socket.connect();
- this.mp = new MessageParser(this.game);
+ setInterval(this._sendAllMessages.bind(this), this.delay);
- log("Socket initialized");
+ tetwis.log("Socket initialized");
+ return this;
},
send: function(msg) {
- this._socket.send(msg);
+ this._queue.push(msg);
+ return this;
},
_onOpen: function() {
- log("Socket: onOpen");
- $('#loading-state').text("Connected. Receiving data...");
+ tetwis.log("Socket: onOpen");
+ this.callback();
},
_onMessage: function(msg) {
//log("Socket: onMessage = " + msg);
- this.mp.parse(msg);
+ tetwis.mp.parse(msg);
},
_onClose: function() {
@@ -42,4 +50,12 @@ Socket.prototype = {
// TODO
// Display: cannot connect to server
},
+
+ _sendAllMessages: function() {
+ if (this._queue.length > 0) {
+ this._socket.send( tetwis.mb.createQueue(this._queue) );
+ this._queue = [];
+ }
+ },
+
}
View
12 client/js/init.js
@@ -0,0 +1,12 @@
+(function() {
+ // Create the Engine instance
+ tetwis.engine = new tetwis.Engine().init();
+
+ // Start the engine
+ tetwis.engine.loadConfig();
+
+ // Connect to the server
+
+ // Send the user's login
+ // Load the games list
+})();
View
10 client/js/libs/jquery.tmpl.js
@@ -0,0 +1,10 @@
+/*
+ * jQuery Templates Plugin 1.0.0pre
+ * http://github.com/jquery/jquery-tmpl
+ * Requires jQuery 1.4.2
+ *
+ * Copyright Software Freedom Conservancy, Inc.
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+(function(a){var r=a.fn.domManip,d="_tmplitem",q=/^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,b={},f={},e,p={key:0,data:{}},i=0,c=0,l=[];function g(g,d,h,e){var c={data:e||(e===0||e===false)?e:d?d.data:{},_wrap:d?d._wrap:null,tmpl:null,parent:d||null,nodes:[],calls:u,nest:w,wrap:x,html:v,update:t};g&&a.extend(c,g,{nodes:[],parent:d});if(h){c.tmpl=h;c._ctnt=c._ctnt||c.tmpl(a,c);c.key=++i;(l.length?f:b)[i]=c}return c}a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(f,d){a.fn[f]=function(n){var g=[],i=a(n),k,h,m,l,j=this.length===1&&this[0].parentNode;e=b||{};if(j&&j.nodeType===11&&j.childNodes.length===1&&i.length===1){i[d](this[0]);g=this}else{for(h=0,m=i.length;h<m;h++){c=h;k=(h>0?this.clone(true):this).get();a(i[h])[d](k);g=g.concat(k)}c=0;g=this.pushStack(g,f,i.selector)}l=e;e=null;a.tmpl.complete(l);return g}});a.fn.extend({tmpl:function(d,c,b){return a.tmpl(this[0],d,c,b)},tmplItem:function(){return a.tmplItem(this[0])},template:function(b){return a.template(b,this[0])},domManip:function(d,m,k){if(d[0]&&a.isArray(d[0])){var g=a.makeArray(arguments),h=d[0],j=h.length,i=0,f;while(i<j&&!(f=a.data(h[i++],"tmplItem")));if(f&&c)g[2]=function(b){a.tmpl.afterManip(this,b,k)};r.apply(this,g)}else r.apply(this,arguments);c=0;!e&&a.tmpl.complete(b);return this}});a.extend({tmpl:function(d,h,e,c){var i,k=!c;if(k){c=p;d=a.template[d]||a.template(null,d);f={}}else if(!d){d=c.tmpl;b[c.key]=c;c.nodes=[];c.wrapped&&n(c,c.wrapped);return a(j(c,null,c.tmpl(a,c)))}if(!d)return[];if(typeof h==="function")h=h.call(c||{});e&&e.wrapped&&n(e,e.wrapped);i=a.isArray(h)?a.map(h,function(a){return a?g(e,c,d,a):null}):[g(e,c,d,h)];return k?a(j(c,null,i)):i},tmplItem:function(b){var c;if(b instanceof a)b=b[0];while(b&&b.nodeType===1&&!(c=a.data(b,"tmplItem"))&&(b=b.parentNode));return c||p},template:function(c,b){if(b){if(typeof b==="string")b=o(b);else if(b instanceof a)b=b[0]||{};if(b.nodeType)b=a.data(b,"tmpl")||a.data(b,"tmpl",o(b.innerHTML));return typeof c==="string"?(a.template[c]=b):b}return c?typeof c!=="string"?a.template(null,c):a.template[c]||a.template(null,q.test(c)?c:a(c)):null},encode:function(a){return(""+a).split("<").join("&lt;").split(">").join("&gt;").split('"').join("&#34;").split("'").join("&#39;")}});a.extend(a.tmpl,{tag:{tmpl:{_default:{$2:"null"},open:"if($notnull_1){__=__.concat($item.nest($1,$2));}"},wrap:{_default:{$2:"null"},open:"$item.calls(__,$1,$2);__=[];",close:"call=$item.calls();__=call._.concat($item.wrap(call,__));"},each:{_default:{$2:"$index, $value"},open:"if($notnull_1){$.each($1a,function($2){with(this){",close:"}});}"},"if":{open:"if(($notnull_1) && $1a){",close:"}"},"else":{_default:{$1:"true"},open:"}else if(($notnull_1) && $1a){"},html:{open:"if($notnull_1){__.push($1a);}"},"=":{_default:{$1:"$data"},open:"if($notnull_1){__.push($.encode($1a));}"},"!":{open:""}},complete:function(){b={}},afterManip:function(f,b,d){var e=b.nodeType===11?a.makeArray(b.childNodes):b.nodeType===1?[b]:[];d.call(f,b);m(e);c++}});function j(e,g,f){var b,c=f?a.map(f,function(a){return typeof a==="string"?e.key?a.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g,"$1 "+d+'="'+e.key+'" $2'):a:j(a,e,a._ctnt)}):e;if(g)return c;c=c.join("");c.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/,function(f,c,e,d){b=a(e).get();m(b);if(c)b=k(c).concat(b);if(d)b=b.concat(k(d))});return b?b:k(c)}function k(c){var b=document.createElement("div");b.innerHTML=c;return a.makeArray(b.childNodes)}function o(b){return new Function("jQuery","$item","var $=jQuery,call,__=[],$data=$item.data;with($data){__.push('"+a.trim(b).replace(/([\\'])/g,"\\$1").replace(/[\r\t\n]/g," ").replace(/\$\{([^\}]*)\}/g,"{{= $1}}").replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,function(m,l,k,g,b,c,d){var j=a.tmpl.tag[k],i,e,f;if(!j)throw"Unknown template tag: "+k;i=j._default||[];if(c&&!/\w$/.test(b)){b+=c;c=""}if(b){b=h(b);d=d?","+h(d)+")":c?")":"";e=c?b.indexOf(".")>-1?b+h(c):"("+b+").call($item"+d:b;f=c?e:"(typeof("+b+")==='function'?("+b+").call($item):("+b+"))"}else f=e=i.$1||"null";g=h(g);return"');"+j[l?"close":"open"].split("$notnull_1").join(b?"typeof("+b+")!=='undefined' && ("+b+")!=null":"true").split("$1a").join(f).split("$1").join(e).split("$2").join(g||i.$2||"")+"__.push('"})+"');}return __;")}function n(c,b){c._wrap=j(c,true,a.isArray(b)?b:[q.test(b)?b:a(b).html()]).join("")}function h(a){return a?a.replace(/\\'/g,"'").replace(/\\\\/g,"\\"):null}function s(b){var a=document.createElement("div");a.appendChild(b.cloneNode(true));return a.innerHTML}function m(o){var n="_"+c,k,j,l={},e,p,h;for(e=0,p=o.length;e<p;e++){if((k=o[e]).nodeType!==1)continue;j=k.getElementsByTagName("*");for(h=j.length-1;h>=0;h--)m(j[h]);m(k)}function m(j){var p,h=j,k,e,m;if(m=j.getAttribute(d)){while(h.parentNode&&(h=h.parentNode).nodeType===1&&!(p=h.getAttribute(d)));if(p!==m){h=h.parentNode?h.nodeType===11?0:h.getAttribute(d)||0:0;if(!(e=b[m])){e=f[m];e=g(e,b[h]||f[h]);e.key=++i;b[i]=e}c&&o(m)}j.removeAttribute(d)}else if(c&&(e=a.data(j,"tmplItem"))){o(e.key);b[e.key]=e;h=a.data(j.parentNode,"tmplItem");h=h?h.key:0}if(e){k=e;while(k&&k.key!=h){k.nodes.push(j);k=k.parent}delete e._ctnt;delete e._wrap;a.data(j,"tmplItem",e)}function o(a){a=a+n;e=l[a]=l[a]||g(e,b[e.parent.key+n]||e.parent)}}}function u(a,d,c,b){if(!a)return l.pop();l.push({_:a,tmpl:d,item:this,data:c,options:b})}function w(d,c,b){return a.tmpl(a.template(d),c,b,this)}function x(b,d){var c=b.options||{};c.wrapped=d;return a.tmpl(a.template(b.tmpl),b.data,c,b.item)}function v(d,c){var b=this._wrap;return a.map(a(a.isArray(b)?b.join(""):b).filter(d||"*"),function(a){return c?a.innerText||a.textContent:a.outerHTML||s(a)})}function t(){var b=this.nodes;a.tmpl(null,null,null,this).insertBefore(b[0]);a(b).remove()}})(jQuery);
View
2  client/js/libs/socket.io.min.js
@@ -0,0 +1,2 @@
+/* Socket.IO.min 0.6.2 @author Guillermo Rauch <guillermo@learnboost.com>, @license The MIT license., @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> */
+var io=this.io={version:"0.6.2",setPath:function(a){window.console&&console.error&&console.error("io.setPath will be removed. Please set the variable WEB_SOCKET_SWF_LOCATION pointing to WebSocketMain.swf"),this.path=/\/$/.test(a)?a:a+"/",WEB_SOCKET_SWF_LOCATION=a+"lib/vendor/web-socket-js/WebSocketMain.swf"}};"jQuery"in this&&(jQuery.io=this.io),typeof window!="undefined"&&typeof WEB_SOCKET_SWF_LOCATION=="undefined"&&(WEB_SOCKET_SWF_LOCATION="/socket.io/lib/vendor/web-socket-js/WebSocketMain.swf"),function(){var a=this.io,b=!1;a.util={ios:!1,load:function(a){if(/loaded|complete/.test(document.readyState)||b)return a();"attachEvent"in window?window.attachEvent("onload",a):window.addEventListener("load",a,!1)},inherit:function(a,b){for(var c in b.prototype)a.prototype[c]=b.prototype[c]},indexOf:function(a,b,c){for(var d=a.length,e=c<0?Math.max(0,d+c):c||0;e<d;e++)if(a[e]===b)return e;return-1},isArray:function(a){return Object.prototype.toString.call(a)==="[object Array]"},merge:function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])}},a.util.ios=/iphone|ipad/i.test(navigator.userAgent),a.util.android=/android/i.test(navigator.userAgent),a.util.opera=/opera/i.test(navigator.userAgent),a.util.load(function(){b=!0})}(),function(){var a=this.io,b="~m~",c=function(a){if(Object.prototype.toString.call(a)=="[object Object]"){if(!("JSON"in window)){"console"in window&&console.error&&console.error("Trying to encode as JSON, but JSON.stringify is missing.");return'{ "$error": "Invalid message" }'}return"~j~"+JSON.stringify(a)}return String(a)};Transport=a.Transport=function(b,c){this.base=b,this.options={timeout:15e3},a.util.merge(this.options,c)},Transport.prototype.send=function(){throw new Error("Missing send() implementation")},Transport.prototype.connect=function(){throw new Error("Missing connect() implementation")},Transport.prototype.disconnect=function(){throw new Error("Missing disconnect() implementation")},Transport.prototype._encode=function(d){var e="",f,d=a.util.isArray(d)?d:[d];for(var g=0,h=d.length;g<h;g++)f=d[g]===null||d[g]===undefined?"":c(d[g]),e+=b+f.length+b+f;return e},Transport.prototype._decode=function(a){var c=[],d,e;do{if(a.substr(0,3)!==b)return c;a=a.substr(3),d="",e="";for(var f=0,g=a.length;f<g;f++){e=Number(a.substr(f,1));if(a.substr(f,1)==e)d+=e;else{a=a.substr(d.length+b.length),d=Number(d);break}}c.push(a.substr(0,d)),a=a.substr(d)}while(a!=="");return c},Transport.prototype._onData=function(a){this._setTimeout();var b=this._decode(a);if(b&&b.length)for(var c=0,d=b.length;c<d;c++)this._onMessage(b[c])},Transport.prototype._setTimeout=function(){var a=this;this._timeout&&clearTimeout(this._timeout),this._timeout=setTimeout(function(){a._onTimeout()},this.options.timeout)},Transport.prototype._onTimeout=function(){this._onDisconnect()},Transport.prototype._onMessage=function(a){this.sessionid?a.substr(0,3)=="~h~"?this._onHeartbeat(a.substr(3)):a.substr(0,3)=="~j~"?this.base._onMessage(JSON.parse(a.substr(3))):this.base._onMessage(a):(this.sessionid=a,this._onConnect())},Transport.prototype._onHeartbeat=function(a){this.send("~h~"+a)},Transport.prototype._onConnect=function(){this.connected=!0,this.connecting=!1,this.base._onConnect(),this._setTimeout()},Transport.prototype._onDisconnect=function(){this.connecting=!1,this.connected=!1,this.sessionid=null,this.base._onDisconnect()},Transport.prototype._prepareUrl=function(){return(this.base.options.secure?"https":"http")+"://"+this.base.host+":"+this.base.options.port+"/"+this.base.options.resource+"/"+this.type+(this.sessionid?"/"+this.sessionid:"/")}}(),function(){var a=this.io,b=new Function,c=function(){if(!("XMLHttpRequest"in window))return!1;var a=new XMLHttpRequest;return a.withCredentials!=undefined}(),d=function(a){if("XDomainRequest"in window&&a)return new XDomainRequest;if("XMLHttpRequest"in window&&(!a||c))return new XMLHttpRequest;if(!a){try{var b=new ActiveXObject("MSXML2.XMLHTTP");return b}catch(d){}try{var e=new ActiveXObject("Microsoft.XMLHTTP");return e}catch(d){}}return!1},e=a.Transport.XHR=function(){a.Transport.apply(this,arguments),this._sendBuffer=[]};a.util.inherit(e,a.Transport),e.prototype.connect=function(){this._get();return this},e.prototype._checkSend=function(){if(!this._posting&&this._sendBuffer.length){var a=this._encode(this._sendBuffer);this._sendBuffer=[],this._send(a)}},e.prototype.send=function(b){a.util.isArray(b)?this._sendBuffer.push.apply(this._sendBuffer,b):this._sendBuffer.push(b),this._checkSend();return this},e.prototype._send=function(a){var c=this;this._posting=!0,this._sendXhr=this._request("send","POST"),this._sendXhr.onreadystatechange=function(){var a;if(c._sendXhr.readyState==4){c._sendXhr.onreadystatechange=b;try{a=c._sendXhr.status}catch(d){}c._posting=!1,a==200?c._checkSend():c._onDisconnect()}},this._sendXhr.send("data="+encodeURIComponent(a))},e.prototype.disconnect=function(){this._onDisconnect();return this},e.prototype._onDisconnect=function(){if(this._xhr){this._xhr.onreadystatechange=b;try{this._xhr.abort()}catch(c){}this._xhr=null}if(this._sendXhr){this._sendXhr.onreadystatechange=b;try{this._sendXhr.abort()}catch(c){}this._sendXhr=null}this._sendBuffer=[],a.Transport.prototype._onDisconnect.call(this)},e.prototype._request=function(a,b,c){var e=d(this.base._isXDomain());c&&(e.multipart=!0),e.open(b||"GET",this._prepareUrl()+(a?"/"+a:"")),b=="POST"&&"setRequestHeader"in e&&e.setRequestHeader("Content-type","application/x-www-form-urlencoded; charset=utf-8");return e},e.check=function(a){try{if(d(a))return!0}catch(b){}return!1},e.xdomainCheck=function(){return e.check(!0)},e.request=d}(),function(){var a=this.io,b=a.Transport.websocket=function(){a.Transport.apply(this,arguments)};a.util.inherit(b,a.Transport),b.prototype.type="websocket",b.prototype.connect=function(){var a=this;this.socket=new WebSocket(this._prepareUrl()),this.socket.onmessage=function(b){a._onData(b.data)},this.socket.onclose=function(b){a._onClose()},this.socket.onerror=function(b){a._onError(b)};return this},b.prototype.send=function(a){this.socket&&this.socket.send(this._encode(a));return this},b.prototype.disconnect=function(){this.socket&&this.socket.close();return this},b.prototype._onClose=function(){this._onDisconnect();return this},b.prototype._onError=function(a){this.base.emit("error",[a])},b.prototype._prepareUrl=function(){return(this.base.options.secure?"wss":"ws")+"://"+this.base.host+":"+this.base.options.port+"/"+this.base.options.resource+"/"+this.type+(this.sessionid?"/"+this.sessionid:"")},b.check=function(){return"WebSocket"in window&&WebSocket.prototype&&WebSocket.prototype.send&&!!WebSocket.prototype.send.toString().match(/native/i)&&typeof WebSocket!="undefined"},b.xdomainCheck=function(){return!0}}(),function(){var a=this.io,b=a.Transport.flashsocket=function(){a.Transport.websocket.apply(this,arguments)};a.util.inherit(b,a.Transport.websocket),b.prototype.type="flashsocket",b.prototype.connect=function(){var b=this,c=arguments;WebSocket.__addTask(function(){a.Transport.websocket.prototype.connect.apply(b,c)});return this},b.prototype.send=function(){var b=this,c=arguments;WebSocket.__addTask(function(){a.Transport.websocket.prototype.send.apply(b,c)});return this},b.check=function(){if(typeof WebSocket=="undefined"||!("__addTask"in WebSocket))return!1;if(a.util.opera)return!1;if("navigator"in window&&"plugins"in navigator&&navigator.plugins["Shockwave Flash"])return!!navigator.plugins["Shockwave Flash"].description;if("ActiveXObject"in window)try{return!!(new ActiveXObject("ShockwaveFlash.ShockwaveFlash")).GetVariable("$version")}catch(b){}return!1},b.xdomainCheck=function(){return!0}}(),function(){var a=this.io,b=a.Transport.htmlfile=function(){a.Transport.XHR.apply(this,arguments)};a.util.inherit(b,a.Transport.XHR),b.prototype.type="htmlfile",b.prototype._get=function(){var a=this;this._open(),window.attachEvent("onunload",function(){a._destroy()})},b.prototype._open=function(){this._doc=new ActiveXObject("htmlfile"),this._doc.open(),this._doc.write("<html></html>"),this._doc.parentWindow.s=this,this._doc.close();var a=this._doc.createElement("div");this._doc.body.appendChild(a),this._iframe=this._doc.createElement("iframe"),a.appendChild(this._iframe),this._iframe.src=this._prepareUrl()+"/"+ +(new Date)},b.prototype._=function(a,b){this._onData(a);var c=b.getElementsByTagName("script")[0];c.parentNode.removeChild(c)},b.prototype._destroy=function(){this._iframe&&(this._iframe.src="about:blank",this._doc=null,CollectGarbage())},b.prototype.disconnect=function(){this._destroy();return a.Transport.XHR.prototype.disconnect.call(this)},b.check=function(){if("ActiveXObject"in window)try{var b=new ActiveXObject("htmlfile");return b&&a.Transport.XHR.check()}catch(c){}return!1},b.xdomainCheck=function(){return!1}}(),function(){var a=this.io,b=a.Transport["xhr-multipart"]=function(){a.Transport.XHR.apply(this,arguments)};a.util.inherit(b,a.Transport.XHR),b.prototype.type="xhr-multipart",b.prototype._get=function(){var a=this;this._xhr=this._request("","GET",!0),this._xhr.onreadystatechange=function(){a._xhr.readyState==4&&a._onData(a._xhr.responseText)},this._xhr.send(null)},b.check=function(){return"XMLHttpRequest"in window&&"prototype"in XMLHttpRequest&&"multipart"in XMLHttpRequest.prototype},b.xdomainCheck=function(){return!0}}(),function(){var a=this.io,b=new Function,c=a.Transport["xhr-polling"]=function(){a.Transport.XHR.apply(this,arguments)};a.util.inherit(c,a.Transport.XHR),c.prototype.type="xhr-polling",c.prototype.connect=function(){if(a.util.ios||a.util.android){var b=this;a.util.load(function(){setTimeout(function(){a.Transport.XHR.prototype.connect.call(b)},10)})}else a.Transport.XHR.prototype.connect.call(this)},c.prototype._get=function(){var a=this;this._xhr=this._request(+(new Date),"GET"),this._xhr.onreadystatechange=function(){var c;if(a._xhr.readyState==4){a._xhr.onreadystatechange=b;try{c=a._xhr.status}catch(d){}c==200?(a._onData(a._xhr.responseText),a._get()):a._onDisconnect()}},this._xhr.send(null)},c.check=function(){return a.Transport.XHR.check()},c.xdomainCheck=function(){return a.Transport.XHR.xdomainCheck()}}(),function(){var a=this.io;a.JSONP=[],JSONPPolling=a.Transport["jsonp-polling"]=function(){a.Transport.XHR.apply(this,arguments),this._insertAt=document.getElementsByTagName("script")[0],this._index=a.JSONP.length,a.JSONP.push(this)},a.util.inherit(JSONPPolling,a.Transport["xhr-polling"]),JSONPPolling.prototype.type="jsonp-polling",JSONPPolling.prototype._send=function(a){function h(){b._iframe&&b._form.removeChild(b._iframe);try{f=document.createElement('<iframe name="'+b._iframeId+'">')}catch(a){f=document.createElement("iframe"),f.name=b._iframeId}f.id=b._iframeId,b._form.appendChild(f),b._iframe=f}function g(){h(),b._posting=!1,b._checkSend()}var b=this;if(!("_form"in this)){var c=document.createElement("FORM"),d=document.createElement("TEXTAREA"),e=this._iframeId="socket_io_iframe_"+this._index,f;c.style.position="absolute",c.style.top="-1000px",c.style.left="-1000px",c.target=e,c.method="POST",c.action=this._prepareUrl()+"/"+ +(new Date)+"/"+this._index,d.name="data",c.appendChild(d),this._insertAt.parentNode.insertBefore(c,this._insertAt),document.body.appendChild(c),this._form=c,this._area=d}h(),this._posting=!0,this._area.value=a;try{this._form.submit()}catch(i){}this._iframe.attachEvent?f.onreadystatechange=function(){b._iframe.readyState=="complete"&&g()}:this._iframe.onload=g},JSONPPolling.prototype._get=function(){var a=this,b=document.createElement("SCRIPT");this._script&&(this._script.parentNode.removeChild(this._script),this._script=null),b.async=!0,b.src=this._prepareUrl()+"/"+ +(new Date)+"/"+this._index,b.onerror=function(){a._onDisconnect()},this._insertAt.parentNode.insertBefore(b,this._insertAt),this._script=b},JSONPPolling.prototype._=function(){this._onData.apply(this,arguments),this._get();return this},JSONPPolling.check=function(){return!0},JSONPPolling.xdomainCheck=function(){return!0}}(),function(){var a=this.io,b=a.Socket=function(b,c){this.host=b||document.domain,this.options={secure:!1,document:document,port:document.location.port||80,resource:"socket.io",transports:["websocket","flashsocket","htmlfile","xhr-multipart","xhr-polling","jsonp-polling"],transportOptions:{"xhr-polling":{timeout:25e3},"jsonp-polling":{timeout:25e3}},connectTimeout:5e3,reconnect:!0,reconnectionDelay:500,maxReconnectionAttempts:10,tryTransportsOnConnectTimeout:!0,rememberTransport:!0},a.util.merge(this.options,c),this.connected=!1,this.connecting=!1,this._events={},this.transport=this.getTransport(),!this.transport&&"console"in window&&console.error("No transport available")};b.prototype.getTransport=function(b){var c=b||this.options.transports,d;this.options.rememberTransport&&!b&&(d=this.options.document.cookie.match("(?:^|;)\\s*socketio=([^;]*)"),d&&(this._rememberedTransport=!0,c=[decodeURIComponent(d[1])]));for(var e=0,f;f=c[e];e++)if(a.Transport[f]&&a.Transport[f].check()&&(!this._isXDomain()||a.Transport[f].xdomainCheck()))return new a.Transport[f](this,this.options.transportOptions[f]||{});return null},b.prototype.connect=function(){if(this.transport&&!this.connected){this.connecting&&this.disconnect(!0),this.connecting=!0,this.emit("connecting",[this.transport.type]),this.transport.connect();if(this.options.connectTimeout){var a=this;this.connectTimeoutTimer=setTimeout(function(){if(!a.connected){a.disconnect(!0);if(a.options.tryTransportsOnConnectTimeout&&!a._rememberedTransport){a._remainingTransports||(a._remainingTransports=a.options.transports.slice(0));var b=a._remainingTransports;while(b.length>0&&b.splice(0,1)[0]!=a.transport.type);b.length&&(a.transport=a.getTransport(b),a.connect())}(!a._remainingTransports||a._remainingTransports.length==0)&&a.emit("connect_failed")}a._remainingTransports&&a._remainingTransports.length==0&&delete a._remainingTransports},this.options.connectTimeout)}}return this},b.prototype.send=function(a){if(!this.transport||!this.transport.connected)return this._queue(a);this.transport.send(a);return this},b.prototype.disconnect=function(a){this.connectTimeoutTimer&&clearTimeout(this.connectTimeoutTimer),a||(this.options.reconnect=!1),this.transport.disconnect();return this},b.prototype.on=function(a,b){a in this._events||(this._events[a]=[]),this._events[a].push(b);return this},b.prototype.emit=function(a,b){if(a in this._events){var c=this._events[a].concat();for(var d=0,e=c.length;d<e;d++)c[d].apply(this,b===undefined?[]:b)}return this},b.prototype.removeEvent=function(a,b){if(a in this._events)for(var c=0,d=this._events[a].length;c<d;c++)this._events[a][c]==b&&this._events[a].splice(c,1);return this},b.prototype._queue=function(a){"_queueStack"in this||(this._queueStack=[]),this._queueStack.push(a);return this},b.prototype._doQueue=function(){if(!("_queueStack"in this)||!this._queueStack.length)return this;this.transport.send(this._queueStack),this._queueStack=[];return this},b.prototype._isXDomain=function(){var a=window.location.port||80;return this.host!==document.domain||this.options.port!=a},b.prototype._onConnect=function(){this.connected=!0,this.connecting=!1,this._doQueue(),this.options.rememberTransport&&(this.options.document.cookie="socketio="+encodeURIComponent(this.transport.type)),this.emit("connect")},b.prototype._onMessage=function(a){this.emit("message",[a])},b.prototype._onDisconnect=function(){var a=this.connected;this.connected=!1,this.connecting=!1,this._queueStack=[],a&&(this.emit("disconnect"),this.options.reconnect&&!this.reconnecting&&this._onReconnect())},b.prototype._onReconnect=function(){function e(){if(!!a.reconnecting)if(!a.connected){if(a.connecting&&a.reconnecting)return a.reconnectionTimer=setTimeout(e,1e3);a.reconnectionAttempts++>=a.options.maxReconnectionAttempts?a.redoTransports?(a.emit("reconnect_failed"),d()):(a.on("connect_failed",e),a.options.tryTransportsOnConnectTimeout=!0,a.transport=a.getTransport(a.options.transports),a.redoTransports=!0,a.connect()):(a.reconnectionDelay*=2,a.connect(),a.emit("reconnecting",[a.reconnectionDelay,a.reconnectionAttempts]),a.reconnectionTimer=setTimeout(e,a.reconnectionDelay))}else d()}function d(){a.connected&&a.emit("reconnect",[a.transport.type,a.reconnectionAttempts]),a.removeEvent("connect_failed",e).removeEvent("connect",e),delete a.reconnecting,delete a.reconnectionAttempts,delete a.reconnectionDelay,delete a.reconnectionTimer,delete a.redoTransports,a.options.tryTransportsOnConnectTimeout=b,a.options.rememberTransport=c;return}this.reconnecting=!0,this.reconnectionAttempts=0,this.reconnectionDelay=this.options.reconnectionDelay;var a=this,b=this.options.tryTransportsOnConnectTimeout,c=this.options.rememberTransport;this.options.tryTransportsOnConnectTimeout=!1,this.reconnectionTimer=setTimeout(e,this.reconnectionDelay),this.on("connect",e)},b.prototype.fire=b.prototype.emit,b.prototype.addListener=b.prototype.addEvent=b.prototype.addEventListener=b.prototype.on,b.prototype.removeListener=b.prototype.removeEventListener=b.prototype.removeEvent}();var swfobject=function(){function V(b){var c=/[\\\"<>\.;]/,d=c.exec(b)!=null;return d&&typeof encodeURIComponent!=a?encodeURIComponent(b):b}function U(a,b){if(!!x){var c=b?"visible":"hidden";t&&P(a)?P(a).style.visibility=c:T("#"+a,"visibility:"+c)}}function T(c,d,e,f){if(!y.ie||!y.mac){var g=i.getElementsByTagName("head")[0];if(!g)return;var h=e&&typeof e=="string"?e:"screen";f&&(v=null,w=null);if(!v||w!=h){var j=Q("style");j.setAttribute("type","text/css"),j.setAttribute("media",h),v=g.appendChild(j),y.ie&&y.win&&typeof i.styleSheets!=a&&i.styleSheets.length>0&&(v=i.styleSheets[i.styleSheets.length-1]),w=h}y.ie&&y.win?v&&typeof v.addRule==b&&v.addRule(c,d):v&&typeof i.createTextNode!=a&&v.appendChild(i.createTextNode(c+" {"+d+"}"))}}function S(a){var b=y.pv,c=a.split(".");c[0]=parseInt(c[0],10),c[1]=parseInt(c[1],10)||0,c[2]=parseInt(c[2],10)||0;return b[0]>c[0]||b[0]==c[0]&&b[1]>c[1]||b[0]==c[0]&&b[1]==c[1]&&b[2]>=c[2]?!0:!1}function R(a,b,c){a.attachEvent(b,c),o[o.length]=[a,b,c]}function Q(a){return i.createElement(a)}function P(a){var b=null;try{b=i.getElementById(a)}catch(c){}return b}function O(a){var b=P(a);if(b){for(var c in b)typeof b[c]=="function"&&(b[c]=null);b.parentNode.removeChild(b)}}function N(a){var b=P(a);b&&b.nodeName=="OBJECT"&&(y.ie&&y.win?(b.style.display="none",function(){b.readyState==4?O(a):setTimeout(arguments.callee,10)}()):b.parentNode.removeChild(b))}function M(a,b,c){var d=Q("param");d.setAttribute("name",b),d.setAttribute("value",c),a.appendChild(d)}function L(c,d,f){var g,h=P(f);if(y.wk&&y.wk<312)return g;if(h){typeof c.id==a&&(c.id=f);if(y.ie&&y.win){var i="";for(var j in c)c[j]!=Object.prototype[j]&&(j.toLowerCase()=="data"?d.movie=c[j]:j.toLowerCase()=="styleclass"?i+=' class="'+c[j]+'"':j.toLowerCase()!="classid"&&(i+=" "+j+'="'+c[j]+'"'));var k="";for(var l in d)d[l]!=Object.prototype[l]&&(k+='<param name="'+l+'" value="'+d[l]+'" />');h.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+i+">"+k+"</object>",n[n.length]=c.id,g=P(c.id)}else{var m=Q(b);m.setAttribute("type",e);for(var o in c)c[o]!=Object.prototype[o]&&(o.toLowerCase()=="styleclass"?m.setAttribute("class",c[o]):o.toLowerCase()!="classid"&&m.setAttribute(o,c[o]));for(var p in d)d[p]!=Object.prototype[p]&&p.toLowerCase()!="movie"&&M(m,p,d[p]);h.parentNode.replaceChild(m,h),g=m}}return g}function K(a){var c=Q("div");if(y.win&&y.ie)c.innerHTML=a.innerHTML;else{var d=a.getElementsByTagName(b)[0];if(d){var e=d.childNodes;if(e){var f=e.length;for(var g=0;g<f;g++)(e[g].nodeType!=1||e[g].nodeName!="PARAM")&&e[g].nodeType!=8&&c.appendChild(e[g].cloneNode(!0))}}}return c}function J(a){if(y.ie&&y.win&&a.readyState!=4){var b=Q("div");a.parentNode.insertBefore(b,a),b.parentNode.replaceChild(K(a),b),a.style.display="none",function(){a.readyState==4?a.parentNode.removeChild(a):setTimeout(arguments.callee,10)}()}else a.parentNode.replaceChild(K(a),a)}function I(b,c,d,e){u=!0,r=e||null,s={success:!1,id:d};var g=P(d);if(g){g.nodeName=="OBJECT"?(p=K(g),q=null):(p=g,q=d),b.id=f;if(typeof b.width==a||!/%$/.test(b.width)&&parseInt(b.width,10)<310)b.width="310";if(typeof b.height==a||!/%$/.test(b.height)&&parseInt(b.height,10)<137)b.height="137";i.title=i.title.slice(0,47)+" - Flash Player Installation";var j=y.ie&&y.win?"ActiveX":"PlugIn",k="MMredirectURL="+h.location.toString().replace(/&/g,"%26")+"&MMplayerType="+j+"&MMdoctitle="+i.title;typeof c.flashvars!=a?c.flashvars+="&"+k:c.flashvars=k;if(y.ie&&y.win&&g.readyState!=4){var l=Q("div");d+="SWFObjectNew",l.setAttribute("id",d),g.parentNode.insertBefore(l,g),g.style.display="none",function(){g.readyState==4?g.parentNode.removeChild(g):setTimeout(arguments.callee,10)}()}L(b,c,d)}}function H(){return!u&&S("6.0.65")&&(y.win||y.mac)&&!(y.wk&&y.wk<312)}function G(c){var d=null,e=P(c);if(e&&e.nodeName=="OBJECT")if(typeof e.SetVariable!=a)d=e;else{var f=e.getElementsByTagName(b)[0];f&&(d=f)}return d}function F(){var b=m.length;if(b>0)for(var c=0;c<b;c++){var d=m[c].id,e=m[c].callbackFn,f={success:!1,id:d};if(y.pv[0]>0){var g=P(d);if(g)if(S(m[c].swfVersion)&&!(y.wk&&y.wk<312))U(d,!0),e&&(f.success=!0,f.ref=G(d),e(f));else if(m[c].expressInstall&&H()){var h={};h.data=m[c].expressInstall,h.width=g.getAttribute("width")||"0",h.height=g.getAttribute("height")||"0",g.getAttribute("class")&&(h.styleclass=g.getAttribute("class")),g.getAttribute("align")&&(h.align=g.getAttribute("align"));var i={},j=g.getElementsByTagName("param"),k=j.length;for(var l=0;l<k;l++)j[l].getAttribute("name").toLowerCase()!="movie"&&(i[j[l].getAttribute("name")]=j[l].getAttribute("value"));I(h,i,d,e)}else J(g),e&&e(f)}else{U(d,!0);if(e){var n=G(d);n&&typeof n.SetVariable!=a&&(f.success=!0,f.ref=n),e(f)}}}}function E(){var c=i.getElementsByTagName("body")[0],d=Q(b);d.setAttribute("type",e);var f=c.appendChild(d);if(f){var g=0;(function(){if(typeof f.GetVariable!=a){var b=f.GetVariable("$version");b&&(b=b.split(" ")[1].split(","),y.pv=[parseInt(b[0],10),parseInt(b[1],10),parseInt(b[2],10)])}else if(g<10){g++,setTimeout(arguments.callee,10);return}c.removeChild(d),f=null,F()})()}else F()}function D(){k?E():F()}function C(b){if(typeof h.addEventListener!=a)h.addEventListener("load",b,!1);else if(typeof i.addEventListener!=a)i.addEventListener("load",b,!1);else if(typeof h.attachEvent!=a)R(h,"onload",b);else if(typeof h.onload=="function"){var c=h.onload;h.onload=function(){c(),b()}}else h.onload=b}function B(a){t?a():l[l.length]=a}function A(){if(!t){try{var a=i.getElementsByTagName("body")[0].appendChild(Q("span"));a.parentNode.removeChild(a)}catch(b){return}t=!0;var c=l.length;for(var d=0;d<c;d++)l[d]()}}var a="undefined",b="object",c="Shockwave Flash",d="ShockwaveFlash.ShockwaveFlash",e="application/x-shockwave-flash",f="SWFObjectExprInst",g="onreadystatechange",h=window,i=document,j=navigator,k=!1,l=[D],m=[],n=[],o=[],p,q,r,s,t=!1,u=!1,v,w,x=!0,y=function(){var f=typeof i.getElementById!=a&&typeof i.getElementsByTagName!=a&&typeof i.createElement!=a,g=j.userAgent.toLowerCase(),l=j.platform.toLowerCase(),m=l?/win/.test(l):/win/.test(g),n=l?/mac/.test(l):/mac/.test(g),o=/webkit/.test(g)?parseFloat(g.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):!1,p=!1,q=[0,0,0],r=null;if(typeof j.plugins!=a&&typeof j.plugins[c]==b)r=j.plugins[c].description,r&&(typeof j.mimeTypes==a||!j.mimeTypes[e]||!!j.mimeTypes[e].enabledPlugin)&&(k=!0,p=!1,r=r.replace(/^.*\s+(\S+\s+\S+$)/,"$1"),q[0]=parseInt(r.replace(/^(.*)\..*$/,"$1"),10),q[1]=parseInt(r.replace(/^.*\.(.*)\s.*$/,"$1"),10),q[2]=/[a-zA-Z]/.test(r)?parseInt(r.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0);else if(typeof h.ActiveXObject!=a)try{var s=new ActiveXObject(d);s&&(r=s.GetVariable("$version"),r&&(p=!0,r=r.split(" ")[1].split(","),q=[parseInt(r[0],10),parseInt(r[1],10),parseInt(r[2],10)]))}catch(t){}return{w3:f,pv:q,wk:o,ie:p,win:m,mac:n}}(),z=function(){!y.w3||((typeof i.readyState!=a&&i.readyState=="complete"||typeof i.readyState==a&&(i.getElementsByTagName("body")[0]||i.body))&&A(),t||(typeof i.addEventListener!=a&&i.addEventListener("DOMContentLoaded",A,!1),y.ie&&y.win&&(i.attachEvent(g,function(){i.readyState=="complete"&&(i.detachEvent(g,arguments.callee),A())}),h==top&&function(){if(!t){try{i.documentElement.doScroll("left")}catch(a){setTimeout(arguments.callee,0);return}A()}}()),y.wk&&function(){if(!t){if(!/loaded|complete/.test(i.readyState)){setTimeout(arguments.callee,0);return}A()}}(),C(A)))}(),W=function(){y.ie&&y.win&&window.attachEvent("onunload",function(){var a=o.length;for(var b=0;b<a;b++)o[b][0].detachEvent(o[b][1],o[b][2]);var c=n.length;for(var d=0;d<c;d++)N(n[d]);for(var e in y)y[e]=null;y=null;for(var f in swfobject)swfobject[f]=null;swfobject=null})}();return{registerObject:function(a,b,c,d){if(y.w3&&a&&b){var e={};e.id=a,e.swfVersion=b,e.expressInstall=c,e.callbackFn=d,m[m.length]=e,U(a,!1)}else d&&d({success:!1,id:a})},getObjectById:function(a){if(y.w3)return G(a)},embedSWF:function(c,d,e,f,g,h,i,j,k,l){var m={success:!1,id:d};y.w3&&!(y.wk&&y.wk<312)&&c&&d&&e&&f&&g?(U(d,!1),B(function(){e+="",f+="";var n={};if(k&&typeof k===b)for(var o in k)n[o]=k[o];n.data=c,n.width=e,n.height=f;var p={};if(j&&typeof j===b)for(var q in j)p[q]=j[q];if(i&&typeof i===b)for(var r in i)typeof p.flashvars!=a?p.flashvars+="&"+r+"="+i[r]:p.flashvars=r+"="+i[r];if(S(g)){var s=L(n,p,d);n.id==d&&U(d,!0),m.success=!0,m.ref=s}else{if(h&&H()){n.data=h,I(n,p,d,l);return}U(d,!0)}l&&l(m)})):l&&l(m)},switchOffAutoHideShow:function(){x=!1},ua:y,getFlashPlayerVersion:function(){return{major:y.pv[0],minor:y.pv[1],release:y.pv[2]}},hasFlashPlayerVersion:S,createSWF:function(a,b,c){return y.w3?L(a,b,c):undefined},showExpressInstall:function(a,b,c,d){y.w3&&H()&&I(a,b,c,d)},removeSWF:function(a){y.w3&&N(a)},createCSS:function(a,b,c,d){y.w3&&T(a,b,c,d)},addDomLoadEvent:B,addLoadEvent:C,getQueryParamValue:function(a){var b=i.location.search||i.location.hash;if(b){/\?/.test(b)&&(b=b.split("?")[1]);if(a==null)return V(b);var c=b.split("&");for(var d=0;d<c.length;d++)if(c[d].substring(0,c[d].indexOf("="))==a)return V(c[d].substring(c[d].indexOf("=")+1))}return""},expressInstallCallback:function(){if(u){var a=P(f);a&&p&&(a.parentNode.replaceChild(p,a),q&&(U(q,!0),y.ie&&y.win&&(p.style.display="block")),r&&r(s)),u=!1}}}}();(function(){function b(){}if(!window.WebSocket){var a=window.console;if(!a||!a.log||!a.error)a={log:function(){},error:function(){}};if(!swfobject.hasFlashPlayerVersion("10.0.0")){a.error("Flash Player >= 10.0.0 is required.");return}location.protocol=="file:"&&a.error("WARNING: web-socket-js doesn't work in file:///... URL unless you set Flash Security Settings properly. Open the page via Web server i.e. http://..."),WebSocket=function(a,b,c,d,e){var f=this;f.__id=WebSocket.__nextId++,WebSocket.__instances[f.__id]=f,f.readyState=WebSocket.CONNECTING,f.bufferedAmount=0,setTimeout(function(){WebSocket.__addTask(function(){WebSocket.__flash.create(f.__id,a,b,c||null,d||0,e||null)})},0)},WebSocket.prototype.send=function(a){if(this.readyState==WebSocket.CONNECTING)throw"INVALID_STATE_ERR: Web Socket connection has not been established";var b=WebSocket.__flash.send(this.__id,encodeURIComponent(a));if(b<0)return!0;this.bufferedAmount+=b;return!1},WebSocket.prototype.close=function(){this.readyState!=WebSocket.CLOSED&&this.readyState!=WebSocket.CLOSING&&(this.readyState=WebSocket.CLOSING,WebSocket.__flash.close(this.__id))},WebSocket.prototype.addEventListener=function(a,b,c){"__events"in this||(this.__events={}),a in this.__events||(this.__events[a]=[],"function"==typeof this["on"+a]&&(this.__events[a].defaultHandler=this["on"+a],this["on"+a]=this.__createEventHandler(this,a))),this.__events[a].push(b)},WebSocket.prototype.removeEventListener=function(a,b,c){"__events"in this||(this.__events={});if(a in this.__events)for(var d=this.__events.length;d>-1;--d)if(b===this.__events[a][d]){this.__events[a].splice(d,1);break}},WebSocket.prototype.dispatchEvent=function(a){if(!("__events"in this))throw"UNSPECIFIED_EVENT_TYPE_ERR";if(!(a.type in this.__events))throw"UNSPECIFIED_EVENT_TYPE_ERR";for(var b=0,c=this.__events[a.type].length;b<c;++b){this.__events[a.type][b](a);if(a.cancelBubble)break}!1!==a.returnValue&&"function"==typeof this.__events[a.type].defaultHandler&&this.__events[a.type].defaultHandler(a)},WebSocket.prototype.__handleEvent=function(b){"readyState"in b&&(this.readyState=b.readyState);try{if(b.type=="open")this.onopen&&this.onopen();else if(b.type=="close")this.onclose&&this.onclose();else if(b.type=="error")this.onerror&&this.onerror(b);else{if(b.type!="message")throw"unknown event type: "+b.type;if(this.onmessage){var c=decodeURIComponent(b.message),d;window.MessageEvent&&!window.opera?(d=document.createEvent("MessageEvent"),d.initMessageEvent("message",!1,!1,c,null,null,window,null)):d={data:c},this.onmessage(d)}}}catch(d){a.error(d.toString())}},WebSocket.prototype.__createEventHandler=function(a,c){return function(d){var e=new b;e.initEvent(c,!0,!0),e.target=e.currentTarget=a;for(var f in d)e[f]=d[f];a.dispatchEvent(e,arguments)}},WebSocket.CONNECTING=0,WebSocket.OPEN=1,WebSocket.CLOSING=2,WebSocket.CLOSED=3,WebSocket.__flash=null,WebSocket.__instances={},WebSocket.__tasks=[],WebSocket.__nextId=0,WebSocket.__initialize=function(){if(!WebSocket.__flash){WebSocket.__swfLocation&&(window.WEB_SOCKET_SWF_LOCATION=WebSocket.__swfLocation);if(!window.WEB_SOCKET_SWF_LOCATION){a.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");return}var b=document.createElement("div");b.id="webSocketContainer",b.style.position="absolute",WebSocket.__isFlashLite()?(b.style.left="0px",b.style.top="0px"):(b.style.left="-100px",b.style.top="-100px");var c=document.createElement("div");c.id="webSocketFlash",b.appendChild(c),document.body.appendChild(b),swfobject.embedSWF(WEB_SOCKET_SWF_LOCATION,"webSocketFlash","1","1","10.0.0",null,null,{hasPriority:!0,swliveconnect:!0,allowScriptAccess:"always"},null,function(b){b.success||a.error("[WebSocket] swfobject.embedSWF failed")})}},WebSocket.loadFlashPolicyFile=function(a){WebSocket.__addTask(function(){WebSocket.__flash.loadManualPolicyFile(a)})},WebSocket.__onFlashInitialized=function(){setTimeout(function(){WebSocket.__flash=document.getElementById("webSocketFlash"),WebSocket.__flash.setCallerUrl(location.href),WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);for(var a=0;a<WebSocket.__tasks.length;++a)WebSocket.__tasks[a]();WebSocket.__tasks=[]},0)},WebSocket.__onFlashEvent=function(){setTimeout(function(){var a=WebSocket.__flash.receiveEvents();for(var b=0;b<a.length;++b)WebSocket.__instances[a[b].webSocketId].__handleEvent(a[b])},0);return!0},WebSocket.__log=function(b){a.log(decodeURIComponent(b))},WebSocket.__error=function(b){a.error(decodeURIComponent(b))},WebSocket.__addTask=function(a){WebSocket.__flash?a():WebSocket.__tasks.push(a)},WebSocket.__isFlashLite=function(){if(!window.navigator||!window.navigator.mimeTypes)return!1;var a=window.navigator.mimeTypes["application/x-shockwave-flash"];if(!a||!a.enabledPlugin||!a.enabledPlugin.filename)return!1;return a.enabledPlugin.filename.match(/flashlite/i)?!0:!1},b.prototype.cancelable=!0,b.prototype.cancelBubble=!1,b.prototype.preventDefault=function(){this.cancelable&&(this.returnValue=!1)},b.prototype.stopPropagation=function(){this.cancelBubble=!0},b.prototype.initEvent=function(a,b,c){this.type=a,this.cancelable=c,this.timeStamp=new Date},window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION||(window.addEventListener?window.addEventListener("load",function(){WebSocket.__initialize()},!1):window.attachEvent("onload",function(){WebSocket.__initialize()}))}})()
View
54 client/js/login.js
@@ -0,0 +1,54 @@
+(function() {
+ var user = null
+ ,loaded = false
+ ;
+
+ load("js/libs/jquery.min.js", "js/core/displayer.js")
+ .then("js/libs/jquery.tmpl.js", "js/tetwis.js")
+ .thenRun(function() {
+
+ prepare();
+
+ tetwis.displayer.displayTemplate('templates/login.html', null, function(data) {
+ $('#submit-login').click(function (e) {
+ e.preventDefault();
+ var login = $('#user-login').val();
+
+ if (login != null && login != '') {
+ user = login;
+ tetwis.displayer.displayTemplate('templates/loading.html');
+ next();
+ }
+ });
+ });
+
+ });
+
+ function prepare() {
+ load("js/libs/socket.io.min.js",
+ "js/libs/jquery.timers.js",
+ "js/libs/json2.js",
+ "js/core/config.js",
+ "js/core/cell.js",
+ "js/core/brick.js",
+ "js/core/map.js",
+ "js/core/displayer.js",
+ "js/core/events.js",
+ "js/core/message-builder.js",
+ "js/core/message-parser.js",
+ "js/core/socket.js",
+ "js/core/game.js",
+ "js/core/engine.js"
+ ).thenRun(function() {
+ loaded = true;
+ next();
+ });
+ }
+
+ function next() {
+ if (user != null && loaded) {
+ tetwis.user = user;
+ load("js/init.js");
+ }
+ }
+})();
View
32 client/js/main.js
@@ -1,15 +1,21 @@
$(document).ready(function() {
- var game = new Game().loadConfig();
- game.ready(function() {
- var cellSize = game.map.cellSize,
- height = game.map.height * cellSize,
- width = game.map.width * cellSize;
-
- $('#map').width(width).height(height);
- $('#players').width(width);
-
- for (var i = 0; i < game.config.players.number; i++) {
- $('#p'+(i+1)).css('color', game.config.players.colors[i]);
- }
- });
+
+ // loading the game template
+ $.get('templates/game.html', function(data) {
+ $.tmpl(data).appendTo('#content');
+
+ var game = new tetwis.Game().loadConfig();
+ game.ready(function() {
+ var cellSize = game.map.cellSize,
+ height = game.map.height * cellSize,
+ width = game.map.width * cellSize;
+
+ $('#map').width(width).height(height);
+ $('#players').width(width);
+
+ for (var i = 0; i < game.config.players.number; i++) {
+ $('#p'+(i+1)).css('color', game.config.players.colors[i]);
+ }
+ });
+ });
});
View
5 client/js/tetwis.js
@@ -0,0 +1,5 @@
+tetwis.user = null;
+tetwis.log = function(msg) {
+ console.log(msg);
+}
+tetwis.displayer = new tetwis.Displayer();
View
7 client/templates/game.html
@@ -0,0 +1,7 @@
+<div id="players">
+ <span id="p1">Player 1</span>
+ <span id="p2">Player 2</span>
+ <span id="p3">Player 3</span>
+ <span id="p4">Player 4</span>
+</div>
+<div id="map"></div>
View
23 client/templates/games-list.html
@@ -0,0 +1,23 @@
+<div class="games-list">
+ {{if games.length}}
+
+ <p class="center"><button id="create-game">Create a new game</button></p>
+
+ <ul>
+ {{each games}}
+ <li>
+ <button class="join-game" id="game-${id}">Join this game!</button>
+ <p>
+ Level ${level}, Score = ${score}
+ <p>
+ </p>
+ Currently ${players} players and ${awaitings} awaitings.
+ </p>
+ </li>
+ {{/each}}
+ </ul>
+ {{else}}
+ <p>There is currently no game running on the server...</p>
+ <p class="center"><button id="create-game">Create one!</button></p>
+ {{/if}}
+</div>
View
5 client/templates/loading.html
@@ -0,0 +1,5 @@
+<div class="login">
+ <h2>Loading... </h2>
+ <img src="images/loader.gif" id="loader" alt="Loading..." />
+ <p id="loading-state">Loading configuration...</p>
+</div>
View
6 client/templates/login.html
@@ -0,0 +1,6 @@
+<div class="login">
+ <h2>Welcome! Who are you?</h2>
+ <form>
+ <p>My name is <input type="text" id="user-login" />, and now <button id="submit-login">I wanna play!</button></p>
+ </form>
+</div>
View
16 lib/client.js
@@ -6,14 +6,11 @@ var sys = require("sys");
* @author Adrian Gaudebert - adrian@gaudebert.fr
* @constructor
*/
-function Client(connectionData, game, server, parser) {
+function Client(connectionData, engine) {
+ this.engine = engine;
this.conn = connectionData;
- this.game = game;
- this.server = server;
- this.mp = parser;
+ this.mp = engine.messageParser;
this.id = this.conn.sessionId;
-
- sys.log("New connection: " + this.id);
}
Client.prototype = {
@@ -24,7 +21,7 @@ Client.prototype = {
this.conn.on("disconnect", this._onClose.bind(this));
// initialization
- this.game.newPlayer(this);
+ this.engine.addUser(this);
return this;
},
@@ -37,12 +34,11 @@ Client.prototype = {
_onMessage: function(msg) {
//~ sys.log("Client: onMessage > " + msg);
- this.mp.parse(msg, this);
+ this.mp.parse(msg, this.id);
},
_onClose: function() {
- sys.log("Client: onClose");
- this.game.clientClose(this);
+ this.engine.clientClose(this);
},
}
View
126 lib/engine.js
@@ -1,12 +1,134 @@
+var util = require('util')
+ ,User = require('./user.js')
+ ,Game = require('./game.js')
+ ,MessageParser = require('./message-parser.js')
+ ,MessageBuilder = require('./message-builder.js')
+ ;
-function Engine() {
- this.players = [];
+function Engine(server) {
+ this.server = server;
+
+ this.messageParser = null;
+ this.messageBuilder = null;
+
+ this.users = [];
this.games = [];
+
+ this.gameId = 0;
}
Engine.prototype = {
+ /**
+ * Initializes the Engine, creates the message parser and builder.
+ *
+ * @return this.
+ */
+ init: function() {
+ this.messageParser = new MessageParser(this);
+ this.messageBuilder = new MessageBuilder();
+
+ return this;
+ },
+
+ //---> Users
+
+ /**
+ * Get a user by its id.
+ *
+ * @param id Id of the user (same as the client id and player id).
+ * @return User object or null.
+ */
+ getUser: function(id) {
+ return this.users[id];
+ },
+
+ /**
+ * Creates a new user object and adds it to the list.
+ *
+ * @param client Client object handling the connection.
+ * @return The new user.
+ */
+ addUser: function(client) {
+ return this.users[client.id] = new User(client);
+ },
+
+ /**
+ * Called when a client disconnect.
+ *
+ * @param client Client object handling the connection.
+ * @return this.
+ */
+ clientClose: function(client) {
+ var user = this.getUser(client.id);
+ if (user.inGame != null) {
+ var game = this.getGame(user.inGame);
+ game.clientClose(user);
+ user.inGame = null;
+ }
+
+ // TODO
+ // this.removeUser(user);
+
+ return this;
+ },
+
+ //---> Games
+
+ /**
+ * Get a game by its id.
+ *
+ * @param id Id of the game.
+ * @return Game object or null.
+ */
+ getGame: function(id) {
+ return this.games[id];
+ },
+
+ /**
+ * Creates a new game object and adds it to the list.
+ *
+ * @param id Id of the new game to create.
+ * @return The new game.
+ */
+ addGame: function(id) {
+ return this.games[id] = new Game(id, this).init().start();
+ },
+
+ /**
+ * Creates a new game and makes the user join it.
+ *
+ * @param user User joining the game (User object).
+ * @return The new game.
+ */
+ createGame: function(user) {
+ var game = this.addGame(this.gameId++);
+ game.newPlayer(user);
+
+ return game;
+ },
+
+ /**
+ * Adds a user to an existing game.
+ *
+ * @param user User joining the game (User object).
+ * @param gameId ID of the game to join.
+ * @return The new game.
+ */
+ joinGame: function(user, gameId) {
+ var game = this.getGame(gameId);
+ if (game != null) {
+ game.newPlayer(user);
+ }
+
+ return game;
+ },
+
+ getGamesListMessage: function() {
+ return this.messageBuilder.createGamesListData(this.games);
+ },
+
};
module.exports = Engine;
View
57 lib/game.js
@@ -1,4 +1,4 @@
-var sys = require("sys"),
+var util = require("util"),
Map = require("./map.js"),
Player = require("./player.js");
@@ -8,8 +8,9 @@ var sys = require("sys"),
* @author Adrian Gaudebert - adrian@gaudebert.fr
* @constructor
*/
-function Game(server) {
- this.server = server;
+function Game(id, engine) {
+ this.id = id;
+ this.engine = engine;
this.map = null;
this.players = [];
@@ -21,6 +22,9 @@ function Game(server) {
this.newBrickDelay = -1;
this.nextBrick = 3;
+
+ this.level = 0;
+ this.score = 0;
}
Game.prototype = {
@@ -96,7 +100,7 @@ Game.prototype = {
this.nextBrick = 0;
}
- //sys.log("GenerateNewBrick : start > " + this.nextBrick);
+ //util.log("GenerateNewBrick : start > " + this.nextBrick);
var player = this.players[this.nextBrick];
@@ -108,7 +112,6 @@ Game.prototype = {
player.newBrick( this.map.nextBrick(this.nextBrick) );
this.nextBrick++;
- //~ sys.log("GenerateNewBrick : end");
return this;
},
@@ -132,16 +135,17 @@ Game.prototype = {
return this.map.toJSON(true);
},
- _createNewPlayer: function(client, playerId) {
- var newPlayer = new Player(this, client);
+ _createNewPlayer: function(user, playerId) {
+ var newPlayer = new Player(this, user);
newPlayer.init();
this.players[playerId] = newPlayer;
return this.updatePlayersInfo();
},
- newPlayer: function(client) {
- this.awaitings.push(client);
+ newPlayer: function(user) {
+ user.inGame = this.id;
+ this.awaitings.push(user);
this.updatePlayersInfo().checkAwaitings();
return this;
},
@@ -152,16 +156,16 @@ Game.prototype = {
return this.updatePlayersInfo();
},
- clientClose: function(client) {
- var cl = this.findClientIn(client, this.players);
+ clientClose: function(user) {
+ var cl = this.findUserIn(user, this.players);
if (cl != null) {
this.removePlayer(cl);
this.checkAwaitings();
}
else {
- cl = this.findClientIn(client, this.awaitings);
+ cl = this.findUserIn(user, this.awaitings);
if (cl != null) {
- for (size = this.awaitings.length; cl < size - 1; cl++) {
+ for (var size = this.awaitings.length; cl < size - 1; cl++) {
this.awaitings[cl] = this.awaitings[cl+1];
}
this.awaitings.pop();
@@ -171,7 +175,7 @@ Game.prototype = {
},
checkAwaitings: function() {
- //~ sys.log("Game: checkAwaitings >> " + this.awaitings.length);
+ //~ util.log("Game: checkAwaitings >> " + this.awaitings.length);
if (this.awaitings.length != 0) {
for (var i = 0, size = this.maxPlayers; i < size; i++) {
if (typeof this.players[i] == undefined || this.players[i] == null) {
@@ -183,40 +187,40 @@ Game.prototype = {
return this;
},
- findClientIn: function(client, array) {
+ findUserIn: function(user, array) {
for (var i = 0; i < array.length; i++) {
- if (typeof array[i] != undefined && array[i] != null && client.id == array[i].id) {
+ if (typeof array[i] != undefined && array[i] != null && user.id == array[i].id) {
return i;
}
}
return null;
},
- getPlayer: function(client) {
- var i = this.findClientIn(client, this.players);
+ getPlayer: function(user) {
+ var i = this.findUserIn(user, this.players);
if (i == null) return null;
if (typeof this.players[ i ] == undefined) return null;
return this.players[ i ];
},
- moveLeft: function(client) {
- var player = this.getPlayer(client);
+ moveLeft: function(user) {
+ var player = this.getPlayer(user);
if (player != null && player.brick != null) {
player.brick.moveLeft();
}
return this;
},
- moveRight: function(client) {
- var player = this.getPlayer(client);
+ moveRight: function(user) {
+ var player = this.getPlayer(user);
if (player != null && player.brick != null) {
player.brick.moveRight();
}
return this;
},
- changeShape: function(client) {
- var player = this.getPlayer(client);
+ changeShape: function(user) {
+ var player = this.getPlayer(user);
if (player != null && player.brick != null) {
player.brick.changeShape();
}
@@ -224,7 +228,8 @@ Game.prototype = {
},
updatePlayersInfo: function() {
- this.mp.updatePlayersInfo(this.countPlayers(), this.awaitings.length);
+ var message = this.engine.messageBuilder.updatePlayersInfo(this.countPlayers(), this.awaitings.length);
+ this.sendAll(message);
return this;
},
@@ -235,7 +240,7 @@ Game.prototype = {
for (; i < ln; i++) {
var player = this.players[i];
if (typeof player != undefined && player != null) {
- this.players[i].client.send(msg);
+ this.players[i].user.send(msg);
}
}
View
151 lib/message-builder.js
@@ -0,0 +1,151 @@
+
+/**
+ * Class MessageBuilder
+ * Create messages to send to the server in a simple way.
+ *
+ * @author Adrian Gaudebert - adrian@gaudebert.fr, Van-Duc Nguyen
+ * @constructor
+ */
+function MessageBuilder() {
+};
+
+MessageBuilder.prototype = {
+
+ /**
+ * Deprecated
+ */
+ updatePlayersInfo: function(nbPlayers, nbAwaitings) {
+ var data = {
+ method: "update",
+ object: "playersInfo",
+ data: {
+ ingame: nbPlayers,
+ awaiting: nbAwaitings
+ }
+ };
+
+ return JSON.stringify(data);
+ },
+
+ /**
+ * Create the basic structure of a message, and stringify to JSON.
+ * @param type Type of message. Can be "login", "query", "data" or "action".
+ * @param data Object containing data of the message.
+ * @return JSON message to send.
+ */
+ createMessage: function(type, data) {
+ var msg = {
+ type: type,
+ data: data
+ };
+
+ return JSON.stringify(msg);
+ },
+
+ /**
+ * Create a query message, and stringify to JSON.
+ * @param responseMethod Type of message we want to receive in response.
+ * @param responseData Object containing data about this query.
+ * @return JSON message to send.
+ */
+ createQuery: function(responseType, responseData) {
+ var data = {};
+ data.response_type = responseType;
+ data.data = responseData;
+
+ return this.createMessage("query", data);
+ },
+
+ /**
+ * Create an action message, and stringify to JSON.
+ * @param name Name of the action.
+ * @param data Object containing data about this action.
+ * @return JSON message to send.
+ */
+ createAction: function(name, data) {
+ var actionData = {};
+ actionData.name = name;
+ actionData.data = data;
+
+ return this.createMessage("action", actionData);
+ },
+
+ /**
+ * Create a data message, and stringify to JSON.
+ * @param method What to do with data. Can be "new", "update" or "delete".
+ * @param object Name of the concerned object.
+ * @param object_data Object containing data about this object.
+ * @return JSON message to send.
+ */
+ createData: function(method, object, object_data) {
+ var data = {};
+ data.method = method;
+ data.object = object;
+ data.object_data = object_data;
+
+ return this.createMessage("data", data);
+ },
+
+ /**
+ * Create a request message asking for the login of the client.
+ * @return JSON message to send.
+ */
+ createAuthenticationQuery: function() {
+ return this.createQuery("login", {});
+ },
+
+ /**
+ * Create a data message confirming the authentication.
+ * @param username Login used to authenticate.
+ * @param valid Boolean to say if authentication is done or not.
+ * @return JSON message to send.
+ */
+ createAuthenticationData: function(userId, valid) {
+ var data = {};
+ data.id = userId;
+ data.valid = valid;
+ return this.createData("new", "Authentication", data);
+ },
+
+ createGamesListData: function(gamesList) {
+ var i = 0
+ ,ln = gamesList.length
+ ,data = []
+ ;
+
+ for (; i < ln; i++) {
+ data.push({
+ "id": gamesList[i].id,
+ "players": gamesList[i].countPlayers(),
+ "awaitings": gamesList[i].awaitings.length,
+ "level": gamesList[i].level,
+ "score": gamesList[i].score
+ });
+ }
+
+ return this.createData("new", "games-list", data);
+ },
+
+ createJoinAction: function() {
+ return this.createAction();
+ },
+
+ createNewGameData: function(game) {
+ return this.createData("new", "Game", game);
+ },
+
+ createUpdateGameData: function(game) {
+ return this.createData("update", "Game", game);
+ },
+
+ createNewPlayerData: function(player) {
+ return this.createData('new', 'Player', player);
+ },
+
+ createUpdatePlayerData: function(player) {
+ return this.createData("update", "player", player);
+ },
+
+};
+
+module.exports = MessageBuilder;
View
151 lib/message-parser.js
@@ -1,4 +1,4 @@
-var sys = require("sys");
+var util = require("util");
/**
* Class MessageParser
@@ -6,45 +6,132 @@ var sys = require("sys");
* @author Adrian Gaudebert - adrian@gaudebert.fr
* @constructor
*/
-function MessageParser(game) {
- this.game = game;
- this.game.mp = this;
+function MessageParser(engine) {
+ this.engine = engine;
}
MessageParser.prototype = {
- parse: function(msg, client) {
- //~ sys.log("MessageParser: parse = " + msg);
- var action = JSON.parse(msg);
-
- if (action.method == "do") {
- if (action.object == "brick") {
- if (action.data.action == "moveLeft") {
- this.game.moveLeft(client);
- }
- else if (action.data.action == "moveRight") {
- this.game.moveRight(client);
- }
- else if (action.data.action == "changeShape") {
- this.game.changeShape(client);
- }
- }
- }
+
+ parse: function(message, clientId) {
+ var user = null;
+
+ if (clientId._client) {
+ user = clientId;
+ }
+ else {
+ user = this.engine.getUser(clientId);
+ }
+
+ if (user) {
+ var obj = JSON.parse(message);
+
+ switch (obj.type) {
+ case "query":
+ this.parseQuery(obj.data, user);
+ break;
+ case "login":
+ this.parseLogin(obj.data, user);
+ break;
+ case "action":
+ this.parseAction(obj.data, user);
+ break;
+ case "data":
+ this.parseData(obj.data, user);
+ break;
+ case "queue":
+ this.parseQueue(obj.data, user);
+ break;
+ default:
+ throw "Warning - MessageParser.parse - Unknown message type: " + obj.type; // TODO: using an object of type Exception
+ }
+ }
+ else {
+ util.log('Warning - MessageParser.parse - Unknown user id: ' + clientId);
+ }
+
+ return this;
+ },
+
+ parseQuery: function(data, user) {
+ switch (data.response_type) {
+ case 'data':
+ this.parseQueryData(data.query_data, user);
+ break;
+ default:
+ throw "Warning - MessageParser.parseQuery - Unknown asked response type: " + data.response_type; // TODO: using an object of type Exception
+ }
+
+ return this;
+ },
+
+ parseQueryData: function(data, user) {
+ switch (data.data_name) {
+ case 'games-list':
+ user.send( this.engine.getGamesListMessage() );
+ break;
+ default:
+ throw "Warning - MessageParser.parseQueryData - Unknown asked data name: " + data.data_name; // TODO: using an object of type Exception
+ }
+
+ return this;
+ },
+
+ parseLogin: function(data, user) {
+ user.login = data.username;
+ util.log('User '+user.id+' is now known as '+data.username);
+ return this;
+ },
+
+ parseAction: function(action, user) {
+ if (user.inGame != null) {
+ var game = this.engine.getGame(user.inGame);
+
+ if (game != null)
+ {
+ switch (action.name) {
+ case "move-left":
+ game.moveLeft(user);
+ break;
+ case "move-right":
+ game.moveRight(user);
+ break;
+ case "change-shape":
+ game.changeShape(user);
+ break;
+ }
+ }
+ }
+ else {
+ switch (action.name) {
+ case "create-game":
+ this.engine.createGame(user);
+ break;
+ case "join-game":
+ this.engine.joinGame( user, action.action_data.game_id );
+ break;
+ }
+ }
+
+ return this;
},
- updatePlayersInfo: function(nbPlayers, nbAwaitings) {
- var data = {
- method: "update",
- object: "playersInfo",
- data: {
- ingame: nbPlayers,
- awaiting: nbAwaitings
- }
- };
+ parseData: function(data, user) {
+
+ return this;
+ },
- var json = JSON.stringify(data);
+ parseQueue: function(data, user) {
+ var i = 0
+ ,ln = data.length
+ ;
- this.game.sendAll(json);
+ for (; i < ln; i++) {
+ this.parse(data[i], user);
+ }
+
+ return this;
},
+
}
module.exports = MessageParser;
View
14 lib/player.js
@@ -7,32 +7,28 @@ var sys = require("sys"),
* @author Adrian Gaudebert - adrian@gaudebert.fr
* @constructor
*/
-function Player(game, client) {
+function Player(game, user) {
this.game = game;
- this.client = client;
+ this.user = user;
this.brick = null;
- this.id = client.id;
+ this.id = user.id;
}
Player.prototype = {
init: function() {
- this.client.send( this.game.getMapAllData() );
+ this.user.send( this.game.getMapAllData() );
this.brick = new Brick(null, null, null, true);
this.brick.isBottom = true;
},
send: function(msg) {
- this.client.send(msg);
+ this.user.send(msg);
},
newBrick: function(newBrick) {
this.brick = newBrick;
},
-
- refresh: function() {
- this.client.send( this.game.getMapDisplayData() );
- }
};
module.exports = Player;
View
24 lib/user.js
@@ -0,0 +1,24 @@
+
+/**
+ * Class User
+ *
+ * @author Adrian Gaudebert - adrian@gaudebert.fr
+ * @constructor
+ */
+function User(client) {
+ this._client = client;
+
+ this.id = client.id;
+ this.login = null;
+ this.inGame = null;
+};
+
+User.prototype = {
+
+ send: function(msg) {
+ this._client.send(msg);
+ },
+
+};
+
+module.exports = User;
View
13 server.js
@@ -5,9 +5,9 @@ var sys = require("util"),
url = require("url"),
mime = require("mime"),
io = require("socket.io"),
- Game = require("./lib/game.js"),
+
Client = require("./lib/client.js"),
- MessageParser = require("./lib/message-parser.js");
+ Engine = require("./lib/engine.js");
sys.log("Starting server... ");
@@ -58,12 +58,13 @@ server.listen(port);
var socket = io.listen(server);
-var game = new Game(server).init().start();
-var parser = new MessageParser(game);
+var engine = new Engine(server).init();
+
+//var game = new Game(server).init().start();
+//var parser = new MessageParser(game);
socket.on('connection', function(conn){
- sys.log('Client connected');
- new Client(conn, game, server, parser).init();
+ new Client(conn, engine).init();
});
sys.log("Server created. Listening on port " + port + ". ");
Please sign in to comment.
Something went wrong with that request. Please try again.