diff --git a/cardshifter.js b/cardshifter.js index a02a2bb..c53e9fc 100644 --- a/cardshifter.js +++ b/cardshifter.js @@ -9,5 +9,6 @@ CardshifterApp.config(function($routeProvider) { .when("/lobby", { controller: "LobbyController", templateUrl: "lobby/lobby.html", + css: "lobby/lobby.css" }) }); \ No newline at end of file diff --git a/lobby/lobby_controller.js b/lobby/lobby_controller.js index 903e2c9..37a8729 100644 --- a/lobby/lobby_controller.js +++ b/lobby/lobby_controller.js @@ -1,8 +1,7 @@ -CardshifterApp.controller("LobbyController", function($scope, $interval, $timeout) { +CardshifterApp.controller("LobbyController", function($scope, $timeout) { var CHAT_FEED_LIMIT = 10; - var POLL_FREQ = 2000; - var MESSAGE_DELAY = 3000; var ENTER_KEY = 13; + var MESSAGE_DELAY = 3000; $scope.users = []; $scope.chatMessages = []; @@ -15,54 +14,21 @@ CardshifterApp.controller("LobbyController", function($scope, $interval, $timeou }; $scope.gotInvite = false; - var getUsersMessage = new CardshifterServerAPI.messageTypes.ServerQueryMessage("USERS", ""); - CardshifterServerAPI.sendMessage(getUsersMessage); // get all online users - - $interval(function() { // update chat and users - while(message = CardshifterServerAPI.getMessage()) { - switch(message.command) { - case "userstatus": - // do conditional checking if user is offline - if(message.status === "OFFLINE") { - for(var i = 0, length = $scope.users.length; i < length; i++) { - - if($scope.users[i].userId === message.userId) { - $scope.users.splice(i, 1); // remove that user from the array - } - } - } else { - $scope.users.push(message); - } - - break; - case "chat": - if($scope.chatMessages.length === CHAT_FEED_LIMIT) { - // remove the latest (opposite of earliest) chat message - $scope.chatMessages.shift(); - } - - var now = new Date(); - var YMD = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate(); - var HMS = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(); - message.timestamp = YMD + " " + HMS; - - $scope.chatMessages.push(message); - break; + var commandMap = { + "userstatus": updateUserList, + "chat": addChatMessage, + "inviteRequest": displayInvite, + "availableMods": displayMods, + "newgame": enterNewGame + }; - case "inviteRequest": - console.log("got invite"); - $scope.invite.id = message.id; - $scope.invite.name = message.name; - $scope.invite.type = message.gameType; - $scope.gotInvite = true; + var getUsers = new CardshifterServerAPI.messageTypes.ServerQueryMessage("USERS", ""); + CardshifterServerAPI.sendMessage(getUsers); - break; - case "availableMods": - $scope.mods = message.mods; - break; - } - } - }, POLL_FREQ); + CardshifterServerAPI.setMessageListener(function(message) { + commandMap[message.command](message); + $scope.$apply(); // needs to manually updated since this is an event + }, ["userstatus", "chat", "inviteRequest", "availableMods", "newgame"]); $scope.sendMessage = function(e) { if(e && e.keyCode !== ENTER_KEY) { // user may hit "enter" key @@ -78,30 +44,81 @@ CardshifterApp.controller("LobbyController", function($scope, $interval, $timeou $scope.sending = false; }, MESSAGE_DELAY); } - $scope.startGame = function() { if($scope.selected_mod && $scope.selected_opponent) { - var startGameMessage = new CardshifterServerAPI.messageTypes.StartGameRequest($scope.selected_opponent, - $scope.selected_mod); - CardshifterServerAPI.sendMessage(startGameMessage, function(returnMessage) { - if(returnMessage.command !== "wait") { - console.log("server didn't like that") - } - }); + var startGame = new CardshifterServerAPI.messageTypes.StartGameRequest($scope.selected_opponent, + $scope.selected_mod); + CardshifterServerAPI.sendMessage(startGame); } else { // user needs to choose an opponent and/or a mod console.log("need to choose mod and/or opponent"); } } - $scope.acceptInvite = function(accept) { - - var inviteResponse = new CardshifterServerAPI.messageTypes.InviteResponse($scope.invite.id, accept); - CardshifterServerAPI.sendMessage(inviteResponse); + var accept = new CardshifterServerAPI.messageTypes.InviteResponse($scope.invite.id, accept); + CardshifterServerAPI.sendMessage(accept); $scope.gotInvite = false; + } + - if(accept) { - // switch to game page + // The command map functions: + /** + * Based on the content of message, will add or remove + * a user from the user list. + */ + function updateUserList(message) { + if(message.status === "OFFLINE") { + for(var i = 0, length = $scope.users.length; i < length; i++) { + if($scope.users[i].userId === message.userId) { + $scope.users.splice(i, 1); // remove that user from the array + break; + } + } + } else { + $scope.users.push(message); } } + /** + * Adds a chat message to the message feed. If the message + * feed is at the maximum limit of messages, deletes the oldest + * message. + */ + function addChatMessage(message) { + if($scope.chatMessages.length === CHAT_FEED_LIMIT) { + // remove the oldest chat message + $scope.chatMessages.shift(); + } + + var now = new Date(); + var YMD = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate(); + var HMS = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(); + message.timestamp = YMD + " " + HMS; + + $scope.chatMessages.push(message); + } + /** + * Shows buttons and a message to this client for accepting + * or declining a game request. + */ + function displayInvite(message) { + $scope.invite.id = message.id; + $scope.invite.name = message.name; + $scope.invite.type = message.gameType; + $scope.gotInvite = true; + } + /** + * Shows to the user a list of all available mods. + */ + function displayMods(message) { + $scope.mods = message.mods; + } + /** + * Stores the game ID in currentUser for other controllers + * to use and navigates to the deck-builder page for the + * user to select a deck. + */ + function enterNewGame(message) { + currentUser.currentGameId = message.gameId; + console.log("change to game"); + } }); \ No newline at end of file diff --git a/login/login_controller.js b/login/login_controller.js index 90a9d55..4b2b0d5 100644 --- a/login/login_controller.js +++ b/login/login_controller.js @@ -9,36 +9,36 @@ CardshifterApp.controller("LoginController", function($scope, $location, $rootSc var login = new CardshifterServerAPI.messageTypes.LoginMessage($scope.username); try { - CardshifterServerAPI.sendMessage(login, function(serverResponse) { - if(serverResponse.status === SUCCESS && serverResponse.message === "OK") { - + CardshifterServerAPI.setMessageListener(function(welcome) { + if(welcome.status === SUCCESS && welcome.message === "OK") { // taking the easy way out window.currentUser = { username: $scope.username, - id: serverResponse.userId + id: welcome.userId } $rootScope.$apply(function() { $location.path("/lobby"); }); } else { - // I don't actually know what the server will respond with - // notify the user that there was an issue logging in (custom server issue ???) - - console.log("server message: " + serverResponse.message); + console.log("server messsage: " + welcome.message); $scope.loggedIn = false; + $scope.$apply(); } - }); + }, ["loginresponse"]); + CardshifterServerAPI.sendMessage(login); } catch(e) { // notify the user that there was an issue logging in (loginmessage issue) console.log("LoginMessage error(error 2): " + e); $scope.loggedIn = false; + $scope.$apply(); } }, function() { // notify the user that there was an issue logging in (websocket issue) console.log("Websocket error(error 1)"); $scope.loggedIn = false; + $scope.$apply(); }); } }); \ No newline at end of file diff --git a/server_interface/server_interface.js b/server_interface/server_interface.js index 9cfdddd..f978913 100644 --- a/server_interface/server_interface.js +++ b/server_interface/server_interface.js @@ -3,6 +3,8 @@ var wsProtocolFinder = /ws(s)*:\/\//; var SOCKET_OPEN = 1; + var eventTypes = []; + function Message(command) { this.command = command; } @@ -36,34 +38,33 @@ window.CardshifterServerAPI = { socket: null, - incomingMessages: [], messageTypes: { - /** - * Incoming login message. - *

- * A login message from a client to add a user to the available users on the server. - * This login message is required before any other action or message can be performed between a client and a server. - * @constructor - * @param username the incoming user name passed from client to server, not null - * @example Message: { "command":"login","username":"JohnDoe" } - */ + /** + * Incoming login message. + *

+ * A login message from a client to add a user to the available users on the server. + * This login message is required before any other action or message can be performed between a client and a server. + * @constructor + * @param username the incoming user name passed from client to server, not null + * @example Message: { "command":"login","username":"JohnDoe" } + */ LoginMessage: function(username) { this.username = username; }, - /** - * Request available targets for a specific action to be performed by an entity. - *

- * These in-game messages request a list of al available targets for a given action and entity. - * The client uses this request in order to point out targets (hopefully with a visual aid such as highlighting targets) - * that an entity (such as a creature card, or a player) can perform an action on (for example attack or enchant a card. - * @constructor - * @param gameId The Id of this game currently being played - * @param id The Id of this entity which requests to perform an action - * @param action The name of this action requested to be performed - */ + /** + * Request available targets for a specific action to be performed by an entity. + *

+ * These in-game messages request a list of al available targets for a given action and entity. + * The client uses this request in order to point out targets (hopefully with a visual aid such as highlighting targets) + * that an entity (such as a creature card, or a player) can perform an action on (for example attack or enchant a card. + * @constructor + * @param gameId The Id of this game currently being played + * @param id The Id of this entity which requests to perform an action + * @param action The name of this action requested to be performed + */ RequestTargetsMessage: function(gameId, id, action) { - this.gamdId = gameId; + this.gameId = gameId; this.id = id; this.action = action; }, @@ -236,10 +237,6 @@ var protocolAddon = (wsProtocolFinder.test(server) ? "" : "ws" + secureAddon + "://"); var socket = new WebSocket(protocolAddon + server); - socket.onmessage = function(message) { - self.incomingMessages.push(JSON.parse(message.data)); - } - socket.onopen = onReady; socket.onerror = function() { @@ -251,33 +248,20 @@ }, /** - * Sends a message to the server. - * - * @param message:Message -- The message to send. - * @param onReceive:Function (OPTIONAL) -- A function to run when a message has returned - * @error NotInitializedException -- If the API has not been initialized yet. + * Sends a message to the server * - * This will use websocket setup by `this.init` to send a message to the server. - * - * NOTE: The onReceive function will NOT NECESSARILY be run when the desired request - * is received. However, it is likely. + * @param message:Message -- The message to send + * @error SocketNotReadyException -- The socket is not ready to be used + * @error NotInitializedException -- The API has not yet been initialized */ - sendMessage: function(message, onReceive) { + sendMessage: function(message) { var socket = this.socket; var self = this; if(socket) { if(socket.readyState === SOCKET_OPEN) { this.socket.send(JSON.stringify(flatten(message))); - if(onReceive) { - this.socket.onmessage = function(msg) { - onReceive(JSON.parse(msg.data)); - this.onmessage = function(msg2) { - self.incomingMessages.push(JSON.parse(msg2.data)); - } - } - } } else { - throw new SocketNotReadyException("The Websocket is not yet ready to be used", socket.readyState); + throw new SocketNotReadyException("The Websocket is not ready to be used.", socket.readyState); } } else { throw new NotInitializedException("The API has not yet been initialized."); @@ -285,19 +269,44 @@ }, /** - * Gets a message from the recieved message queue. + * Sets an event listener for when the server sends a message and + * the message type is one of the types in types * - * @return Message -- The first message in the incoming messages queue + * @param listener:Function -- The function to fire when a message of types is received + * @param types:[string] (OPTIONAL) -- Only fire the listener when the message type is in this array + * @param timeout:Object (OPTIONAL) -- The function(.ontimeout) to call after MS(.ms) of no reply * - * This will .shift() the incomingMessages queue and return the value. - * This allows the API to handle the messages from the server so the - * main game code can access the messages as it needs to. + * TODO: Maybe a timeout will be needed? Pass in a function and a MS count. + */ + setMessageListener: function(listener, types) { + eventTypes = types; + + this.socket.onmessage = function(message) { + var data = JSON.parse(message.data); + if(eventTypes) { + if(eventTypes.indexOf(data.command) !== -1) { // if contains + listener(data); + } + } else { + listener(data); + } + } + }, + + /** + * Adds types to the types to listen for in the message event listener * - * Although the function is very simple, the name make is clear what is - * happening. + * @param types:[string] -- The types to add + */ + addEventTypes: function(types) { + eventTypes = eventTypes.concat(types); + }, + + /** + * Removes the message event listener */ - getMessage: function() { - return this.incomingMessages.shift(); + removeMessageListener: function() { + this.socket.onmessage = null; } }; })(Function("return this")()); \ No newline at end of file