diff --git a/app/Game/Client/Networker.js b/app/Game/Client/Networker.js
index 3b3ba12..b40477b 100755
--- a/app/Game/Client/Networker.js
+++ b/app/Game/Client/Networker.js
@@ -53,6 +53,7 @@ function (ProtocolHelper, GameController, User, Nc, Settings, DomController) {
this.sendCommand('join', options);
DomController.setConnected(true);
} else {
+ alert("Error: no channel name");
window.location.href = "/";
}
}
@@ -80,7 +81,7 @@ function (ProtocolHelper, GameController, User, Nc, Settings, DomController) {
}
Networker.prototype.onJoinError = function(options) {
- // alert(options.message);
+ alert(options.message);
window.location.href = "/";
};
diff --git a/app/Game/Config/Settings.js b/app/Game/Config/Settings.js
index 747e8c2..5fd574b 100755
--- a/app/Game/Config/Settings.js
+++ b/app/Game/Config/Settings.js
@@ -76,6 +76,7 @@ define(function() {
NETWORK_LOG_FILTER: ['ping', 'pong', 'worldUpdate', 'lookAt'],
// CHANNEL
+ CHANNEL_MAX_USERS: 20,
CHANNEL_DESTRUCTION_TIME: 5 * 60,
CHANNEL_END_ROUND_TIME: 4, //10,
CHANNEL_DEFAULT_MAX_USERS: 40,
diff --git a/app/Menu/Menu.js b/app/Menu/Menu.js
index e0c573a..5948d7f 100644
--- a/app/Menu/Menu.js
+++ b/app/Menu/Menu.js
@@ -144,11 +144,19 @@ function (ColorConverter, Exception, PointerLockManager, Qs) {
var html = "";
if(list.length > 0) {
for (var i = 0; i < list.length; i++) {
+
var channel = list[i];
- html += "
";
- html += "| " + channel.name + " | ";
+ var fullState = channel.playerCount >= channel.maxUsers;
+ var fullString = fullState ? " Full" : "";
+ var fullStyle = fullState ? 'class="full"' : "";
+ var players = channel.playerCount
+ ? "Player:
- " + channel.players.join("
- ") + ""
+ : "";
+
+ html += "
";
+ html += "| " + channel.channelName + " | ";
html += "death match | ";
- html += "" + channel.playerCount + " | ";
+ html += "" + channel.playerCount + fullString + players + " | ";
html += "
";
};
} else {
@@ -190,8 +198,15 @@ function (ColorConverter, Exception, PointerLockManager, Qs) {
Qs.$("form#createform").onsubmit = function(e) {
try {
- var channelName = Qs.$("#customname").value;
- create(channelName, onCreateSuccess);
+
+ var options = {
+ channelName: Qs.$("#customname").value,
+ levelUids: getSelectedMaps(),
+ maxUsers: parseInt(Qs.$("#userLimit").value, 10),
+ scoreLimit: parseInt(Qs.$("#scoreLimit").value, 10)
+ };
+
+ create(options, onCreateSuccess);
} catch(e) {
console.error(e)
}
@@ -246,7 +261,15 @@ function (ColorConverter, Exception, PointerLockManager, Qs) {
}
if(!channelExists(list, defaultChannelName)) {
- create(defaultChannelName, function() {
+
+ var options = {
+ channelName: defaultChannelName,
+ levelUids: getSelectedMaps(),
+ maxUsers: parseInt(Qs.$("#userLimit").value, 10),
+ scoreLimit: parseInt(Qs.$("#scoreLimit").value, 10)
+ };
+
+ create(options, function() {
join(nickname, defaultChannelName); // only called on success
});
} else {
@@ -283,7 +306,7 @@ function (ColorConverter, Exception, PointerLockManager, Qs) {
function channelExists(list, channelName) {
for (var i = 0; i < list.length; i++) {
var channel = list[i];
- if(channel.name == channelName) {
+ if(channel.channelName == channelName) {
return true;
}
}
@@ -302,18 +325,33 @@ function (ColorConverter, Exception, PointerLockManager, Qs) {
return true;
}
- function validateForCreate(channelName, maps) {
+ function validateForCreate(options) {
+
return true;
- if(maps.length < 1) {
+ // great validation on server side does it all.
+
+ /*
+ if(options.levelUids.length < 1) {
alert("Please choose at least one map.")
return false;
}
- if(!channelName) {
- alert("Please provide a channel name.")
+ if(!options.channelName || options.channelName.length < 3) {
+ alert("Please provide a channel name of at least 3 characters.")
+ return false;
+ }
+
+ if(!parseInt(options.maxUsers) > 1 || !parseInt(options.maxUsers) < 20) {
+ alert("Number of users must be larger than 1 and smaller than 20.");
+ return false;
+ }
+
+ if(!parseInt(options.scoreLimit) > 1 || !parseInt(options.scoreLimit) < 99) {
+ alert("Score limit must be larger than 1 and smaller than 99.");
return false;
}
return true;
+ */
}
function getSelectedMaps() {
@@ -367,20 +405,12 @@ function (ColorConverter, Exception, PointerLockManager, Qs) {
}
}
- function create(channelName, callback) {
- var maps = getSelectedMaps();
+ function create(options, callback) {
- if(validateForCreate(channelName, maps)) {
+ if(validateForCreate(options)) {
- var options = {
- channelName: channelName,
- levelUids: maps,
- maxUsers: 10,
- minUsers: 2,
- scoreLimit: parseInt(Qs.$("#scoreLimit").value, 10)
- }
-
- localStorage["customname"] = channelName;
+ options["minUsers"] = 1;
+ localStorage["customname"] = options.channelName;
ajax("createChannel", options, function(responseText) {
if(typeof callback == 'function') {
diff --git a/app/Server/Api.js b/app/Server/Api.js
index 5eb5cc6..47b4a63 100644
--- a/app/Server/Api.js
+++ b/app/Server/Api.js
@@ -96,22 +96,23 @@ function (Nc, ProtocolHelper, validate, Options, Settings, FileSystem) {
newOptions.maxUsers = options.maxUsers;
} else {
this.isError = true;
- return "Could not create channel, Max users invalid. (Limited to " + Settings.CHANNEL_MAX_USERS + " users)";
+ return "Could not create channel, user limit invalid. Limited to " + Settings.CHANNEL_MAX_USERS + " users";
}
if(validate(options.minUsers, {optional: true, type: 'number', min: 0, max: Settings.CHANNEL_MAX_USERS})) {
newOptions.minUsers = options.minUsers;
} else {
this.isError = true;
- return "Could not create channel, Max users too high. Limited to: " + Settings.CHANNEL_MAX_USERS;
+ return "Could not create channel, minimal users limit too high. Limited to: " + Settings.CHANNEL_MAX_USERS;
}
// Limits
- if(validate(options.scoreLimit, {type: 'number', min: 1, max: 999})) {
+ var scoreLimitPreferences = {type: 'number', min: 1, max: 999};
+ if(validate(options.scoreLimit, scoreLimitPreferences)) {
newOptions.scoreLimit = options.scoreLimit;
} else {
this.isError = true;
- return "Could not create channel, score limit (" + options.scoreLimit + ").";
+ return "Could not create channel, score limit (" + options.scoreLimit + ") must be between " + scoreLimitPreferences.min + " and " + scoreLimitPreferences.max;
}
var defaultOptions = {
diff --git a/app/Server/Coordinator.js b/app/Server/Coordinator.js
index a5da29c..2e2060d 100644
--- a/app/Server/Coordinator.js
+++ b/app/Server/Coordinator.js
@@ -11,7 +11,6 @@ function (User, PipeToChannel, Nc, Settings) {
function Coordinator() {
this.channelPipes = {};
- this.users = [];
Nc.on(Nc.ns.server.events.controlCommand.coordinator, this.onMessage, this);
@@ -19,21 +18,12 @@ function (User, PipeToChannel, Nc, Settings) {
}
Coordinator.prototype.createUser = function (socketLink) {
- this.users.push(new User(socketLink, this));
+ new User(socketLink, this);
}
- Coordinator.prototype.removeUser = function (user) {
- for(var i = 0; i < this.users.length; i++) {
- if(this.users[i] === user) {
- this.users.splice(i, 1);
- break;
- }
- }
- }
-
- Coordinator.prototype.assignUserToChannel = function (user, channelName) {
- var channelPipe = this.channelPipes[channelName];
- user.setChannelPipe(channelPipe);
+ // was assignUserToChannel...
+ Coordinator.prototype.getChannelPipeByName = function (channelName) {
+ return this.channelPipes[channelName];
}
Coordinator.prototype.onDestroyPipe = function(channelName) {
@@ -44,18 +34,17 @@ function (User, PipeToChannel, Nc, Settings) {
var list = [];
for (var channelName in this.channelPipes) {
- var count = 0;
+ var options = this.channelPipes[channelName].options;
- for(var i = 0; i < this.users.length; i++) {
- if(this.users[i].channelPipe === this.channelPipes[channelName]){
- count++;
- }
- }
+ var playerNames = [];
+ var users = this.channelPipes[channelName].getUsers();
+ for (var i = 0; i < users.length; i++) {
+ playerNames[i] = users[i].options.nickname;
+ };
+ options.players = playerNames;
+ options.playerCount = options.players.length;
- list.push({
- name: channelName,
- playerCount: count
- });
+ list.push(options);
}
return list;
}
diff --git a/app/Server/PipeToChannel.js b/app/Server/PipeToChannel.js
index 0e4ff97..7112783 100755
--- a/app/Server/PipeToChannel.js
+++ b/app/Server/PipeToChannel.js
@@ -12,6 +12,8 @@ function (Nc, childProcess) {
function PipeToChannel (options) {
this.fork = null;
+ this.options = options;
+ this.users = [];
try {
this.fork = fork('channel.js'
@@ -28,8 +30,6 @@ function (Nc, childProcess) {
this.send('channel/' + options.channelName, { CREATE: true, options: options });
this.fork.on('message', this.onMessage.bind(this));
-
- var self = this;
}
// While creating user
@@ -52,6 +52,10 @@ function (Nc, childProcess) {
this.fork.send(message);
}
+ PipeToChannel.prototype.isFull = function() {
+ return this.users.length >= this.options.maxUsers;
+ };
+
PipeToChannel.prototype.onMessage = function (message) {
switch(message.recipient) {
case 'coordinator':
@@ -64,6 +68,26 @@ function (Nc, childProcess) {
}
+ PipeToChannel.prototype.addUser = function(user) {
+ this.users.push(user);
+ this.send('channel', { addUser: user.options });
+ };
+
+ PipeToChannel.prototype.removeUser = function(user) {
+ for(var i = 0; i < this.users.length; i++) {
+ if(this.users[i] === user) {
+ this.users.splice(i, 1);
+ break;
+ }
+ }
+
+ this.send('channel', { releaseUser: user.id });
+ };
+
+ PipeToChannel.prototype.getUsers = function() {
+ return this.users;
+ };
+
return PipeToChannel;
});
\ No newline at end of file
diff --git a/app/Server/User.js b/app/Server/User.js
index 44194a0..a9d63a2 100644
--- a/app/Server/User.js
+++ b/app/Server/User.js
@@ -14,6 +14,7 @@ function (Parent, ProtocolHelper, Nc) {
this.coordinator = coordinator;
this.socketLink = socketLink;
this.channelPipe = null;
+ this.options = null;
socketLink.on('message', this.onMessage.bind(this));
socketLink.on('disconnect', this.onDisconnect.bind(this));
@@ -23,15 +24,23 @@ function (Parent, ProtocolHelper, Nc) {
User.prototype = Object.create(Parent.prototype);
+/*
User.prototype.setChannelPipe = function(channelPipe) {
if(channelPipe) {
- this.channelPipe = channelPipe;
+ if (channelPipe.isWithinUserLimit()) {
+ this.channelPipe = channelPipe;
+ this.channelPipe.addUser(this);
+ } else {
+ var message = ProtocolHelper.encodeCommand("joinError", {message:"Channel is full"});
+ this.socketLink.send(message);
+ }
+
} else {
var message = ProtocolHelper.encodeCommand("joinError", {message:"Channel not found"});
this.socketLink.send(message);
}
};
-
+ */
// Socket callbacks
@@ -41,14 +50,12 @@ function (Parent, ProtocolHelper, Nc) {
User.prototype.onDisconnect = function () {
- this.coordinator.removeUser(this);
-
if(!this.channelPipe) {
- console.warn("Disconnecting user without a channel.");
+ console.warn("Disconnecting user without a channel. (Maybe channel was full)");
return;
}
- this.channelPipe.send('channel', { releaseUser: this.id });
+ this.channelPipe.removeUser(this);
}
@@ -56,18 +63,29 @@ function (Parent, ProtocolHelper, Nc) {
// Remember: control commands are coordinator relevant commands
User.prototype.onJoin = function(options) {
- this.coordinator.assignUserToChannel(this, options.channelName);
- if(!this.channelPipe) {
- console.warn("Can not join user because channel (" + options.channelName + ") does not exist.")
+ var channelPipe = this.coordinator.getChannelPipeByName(options.channelName);
+
+ if(!channelPipe) {
+ var message = ProtocolHelper.encodeCommand("joinError", {message:"Channel " + options.channelName + " not found."});
+ this.socketLink.send(message);
return;
}
+ if (channelPipe.isFull()) {
+ var message = ProtocolHelper.encodeCommand("joinError", {message:"Sorry! Channel " + options.channelName + " is full."});
+ this.socketLink.send(message);
+ return;
+ }
+
+ this.channelPipe = channelPipe;
+
var userOptions = {
id: this.id,
nickname: options.nickname
}
- this.channelPipe.send('channel', { addUser: userOptions });
+ this.options = userOptions;
+ this.channelPipe.addUser(this);
};
/* FIXME: watch out and check in wich direction game and control commands flow */
diff --git a/static/css/screen.css b/static/css/screen.css
index 83213d4..6cc74a3 100644
--- a/static/css/screen.css
+++ b/static/css/screen.css
@@ -20,7 +20,7 @@ body {
background: #222;
color: #ccc;
font-family: 'Joystix', "Lucida Grande", sans-serif;
- text-transform: uppercase;
+ /*text-transform: uppercase;*/
margin: 0;
padding: 0;
display: table;
@@ -113,7 +113,7 @@ article#menu {
margin: 4em auto;
background: #1a1a1a;
padding: 2em;
- max-width: 30em;
+ max-width: 40em;
}
table, th, td {
@@ -142,6 +142,31 @@ tr:hover td {
background: #222;
}
+.full {
+ color: #777;
+}
+
+.full a {
+ color: inherit;
+ cursor:not-allowed;;
+}
+
+#players {
+ position: absolute;
+
+ border: 1px solid #777;
+ padding: 20px;
+ margin-left: 35px;
+ margin-top: -10px;
+ background: rgba(20, 20, 20, 0.95);
+ box-shadow: 5px 5px 5px #000;
+ display: none;
+}
+
+.playersCell:hover #players {
+ display: block;
+}
+
a {
color: #ccc;
}
diff --git a/static/html/index.html b/static/html/index.html
index 37dd78b..fb062a7 100644
--- a/static/html/index.html
+++ b/static/html/index.html
@@ -22,6 +22,7 @@
Create your own!
+