Assigning data to a socket - node.js

I'm working with Socket.io, node.js, and express to make a simple two player game that can be played online. Everything I've found on the subject so far either doesn't address my question or is far more complex than what I'm after.
Essentially, I want players to be able to join a room (which I have solved already), and when in a room, need to assign "player 1" and "player 2" attributes to each player. I imagine assigning player 1 to the first connected user and player 2 to the second, but I haven't figured out exactly how to do the assignment of values/variables to an individual socket connection.

You can add attributes to individual sockets like this:
io.sockets.on('connection', function(socket){
socket.name = 'John';
console.log(socket.name); // prints out 'John'
});

It seems like what you're looking for should be pretty straightforward. I like #iheartramen's answer, except it makes it difficult to determine what sockets belong to what room. What I would do is keep a list of rooms, and what sockets belong to them:
var _rooms = [
{
id: 'Some Unique Room ID',
playerSockets: []
}
//...
}
Then when a player connects to a given room, you just add their connection to the list:
io.sockets.on('connection',function(socket){
var room = getRoom(); // however it is you're mapping rooms...
// this returns a reference to a room object
// in the _rooms array
// you can cap the number of players here
socket.playerNumber = room.sockets.length+1;
room.sockets.push( socket );
}
And now you have backwards and forward mapping. You don't have to worry about thread safety with the push() method because there's only a single event thread.

Related

This "if else" statement don't work in my socket.io/Node.js environment

So I am developing a simple game. The logic flow is when 2 players connect to the room, the game will initialize and emit a 3 seconds countdown event alongside with a button . if one player clicks the button, that player will emit an event making him/her the host of the game.
The button will appear for 3 seconds. If it disappear without being clicked, the server will randomly pick the host.
Whether or not the button is clicked,after 3 seconds all clients will emit a "ready" event.
Here is my code.
if the button is clicked, the "host" event will be emitted by the client,and my server side code is
client.on('host',function(){
var player = room.getPlayer(client.id);
player.isHost=true;
});
Then here is the server side for the "ready" event.
client.on("ready", function() {
var player = room.getPlayer(client.id);
var table = room.getTable(player.tableID);
if (2>1) {
for (var i = 0; i < table.players.length; i++) {
if (table.players[i].isHost===true){
console.log("you are the host")
} else {
console.log("we are going to randomly pick a host")
}
}
}
})
Now if no players click the button the terminal will show
we are going to randomly pick a host
we are going to randomly pick a host
we are going to randomly pick a host
we are going to randomly pick a host
Otherwise it will be like
we are going to randomly pick a host
you are the host
we are going to randomly pick a host
you are the host
At this stage only 2 clients are allow for the game so the players.length is 2.It seems like the if/else will be executed same time as the players.length?
I think the first thing to mention is that the if (2>1) { ... is completely unnecessary. The code will simply go through to the for loop as if it's not there.
Your code besides the if statement, is honestly ok. There's nothing that screams 'I cause more loops then necessary'. At this point I would suggest posting anything in the project related to:
Multithreading
Socket Handling / connecting the socket outside of this
I believe more information is due.
Thanks for the helps. Yes the for loop is not necessary and it is the cause of the problem. My solution is to detach it from the if-else statement.
for (var i = 0; i < table.players.length; i++) {
}
//test if Host exit in the table
if (table.ifHost===true){
console.log("you are the host")
} else {
var randomNumber = Math.floor(Math.random() * table.playerLimit);
var Host=table.players[randomNumber]
}
The interesting thing I found out about the socket io is when two sockets fire this event, if Host doesn't exit,the first one will execute the else(noHost) and then create a Host. The second socket will execute the if condition as the host was created by the previous socket....

Can't tell if this is a race condition

I am trying to build a simple chat server(practice), with nodejs. I have a global var chatRooms, and it can be changed or read by all requests to the server. I am trying to figure out if I am possibly causing some race conditions. I am also using sockets via the node net module.
var net = require('net');
var chatRooms = {fender:[]};
function enterRoom(socket, room){
charRooms[room].push(socket.username);
}
function leaveRoom(socket, room){
var indexOfUser = chatRooms[room].indexOf(socket.username);
chatRoom[room].splice(indexOfUser, 1);
}
so, I am trying to figure out this situation:
user A joins chat room fender: - chatRoom looks like {fender:['A']}
user B joins chat room fender: - chatRoom looks like {fender:['A', 'B']}
user B and A want to leave the room, and do so at the same time:
user B indexOfUser === 1;
user A indexOfUser === 0;
user A splices chatRooms gobal var, before user B does.
global ChatRoom var now looks like (fender:['B']}
user B indexOfUser no longer === 1
so when user B splices ChatRooms it will do so using the wrong index.
Is something like this possible, or the single threaded nature of node prevents this from happening.
What is cant figure out is if these two lines of code will be problematic
var indexOfUser = chatRooms[room].indexOf(socket.username);
// another request alters charRooms before the next line of code is reached.
chatRoom[room].splice(indexOfUser, 1);
Single threaded nature of node prevents that. Every full block of code is strongly isolated, i.e. no other code can run in "parallel".

Concurrent timers in node.js with socket.io

So I'm developing simple game with the following scenario:
2 users need to start a game (so I'm creating new room for 3rd user and so on)
2 users is maximum per room
When game is started, event is sent to client, after 60 seconds server needs to end the game.
Code which I wrote will work only for 1 room, but for multiple rooms, cancelling is not correct because my lastRoom variable is incorrect.
I'm new to node.js so I'm not really sure how to deal with this.
Some code:
var lastRoom = 'default'; //this is the first created room
function tryToStartGame(socket){
var clients = io.sockets.adapter.rooms[lastRoom];
console.log("Size of room "+lastRoom+" is: "+getObjectSize(clients));
//we are checking size of last room
if (getObjectSize(clients) == 2){
//players in the room should be different
games['default']= {
'leftPlayer': getFromObject(clients, 0),
'rightPlayer': getFromObject(clients, 1),
'stuff': "some data here"
'roomName': lastRoom
};
console.log("We can start the game");
//let all the people in that room
io.to(lastRoom).emit('game', games['default']);
//game to cancel
gameToCancel = lastRoom;
//client needs to be aware when game is ended
//but if we have simultaneous games this will not work
setTimeout(function(){
console.log("Cancelling game in: "+gameToCancel);
io.to(gameToCancel).emit('gameEnded', "Winner logic is todo ;) ");
}, 8000); //after 8 seconds for test
//reset the room name, so next time when this function is called in second room
//we will have something different
lastRoom = 'game'+new Date().getTime();
}
//we have less then 2 players, wait for another player
if (getObjectSize(clients)<2){
console.log("Less then 2 players");
socket.emit('waiting', 'Waiting for another user to join the game');
}
}
And tryToStartGame(socket) function is called always at connection like this:
io.on('connection', function(socket){
//when client says he wants to play
socket.on('joinGame', function(username){
//add user
addUser(socket, username);
//send list of players
io.emit('playersList', getFormatedPlayers());
//figure out in which room this player bellongs
socket.join(lastRoom);
//try to start the game
tryToStartGame(socket);
});
Problematic part is that lastRoom variable is overwritten and then setTimeout picks the wrong room, so what happens that basically last game is canceled, and the previous ones are not.
How should I correctly track and cancel the game in correct rooms ?
As you noted, lastRoom is a global variable and might/will change between the time you set it and the timeout
You can create a closure on the timeout function to keep the room as a locale variable:
var lastRoom = 'default'; //this has to be set in the same function than the call to setTimeout
//client needs to be aware when game is ended
//but if we have simultaneous games this will not work
setTimeout(function(){
var gameToCancel = lastRoom;
console.log("Cancelling game in: "+gameToCancel);
io.to(gameToCancel).emit('gameEnded', "Winner logic is todo ;) ");
}, 8000); //after 8 seconds for test

Socket.IO, multiple connections on page load

I have a socketIO/express app that goes like this :
function joinRoom(socket,roomName){
socket.join(roomName);
console.log('success joining '+roomName);
socket.broadcast.to(roomName).emit('chat',{type:'join',msg:guestList[socket.id]+' has arrived in '+roomName+'!'});
socket.emit('chat',{type:'join',msg:'You are now in '+roomName});
}
function assignName(socket){
var name = 'Player#'+guestId;
guestList[socket.id]= name;
socket.emit('chat',{type:'name',msg:name});
return guestId+1;
}
io.sockets.on('connection', function (socket) {
io.of('/lobby').on('connection', function (socket) {
guestId=assignName(socket);
joinRoom(socket, 'Lobby');
});
handleMessage(socket);
});
When I open a first browser window, everything goes well, I see Player#0 connected, and the join room msg. However, when I open a second window or browser, I see 2 connections (player#1 and #2), then if I open a 3rd window, i will see 3 connections, #3,#4,#5. What the heck? It has to be something stupid but I can't figure it out, Help!
G.
Sorted!
Basically, I separated the namespace connection from the io.sockets.on(...) and behaviour went back to normal. It makes sense, although I'm not sure why the number of connect events was incremental...

NODE.JS accessing shared variable in socket.IO event handler

I am doing an experimental online poker game using NODE.JS and socket.IO. The game requires 3 players to join to start. I use socket.IO to listen to the connections from joining players. Whenever there are 3 players coming, they will form one group. Currently I use some shared variables to do this. But if there are lots of players coming in at the same time, I am fear it will cause synchronization problem. As you can see from the code snippet, the players, groups, groupNumber, comingPlayer, clients are all shared between multiple 'connection' event handlers. So when one event handler is executed and another event handler got scheduled by the V8 engine, it may corrupt the states of these shared variables.
I have done some research using Google but didn't find satisfactory answers. So I posted here to see if any expert can help me. Thanks in advance!
var clients = {}; // {"player1": 1} {"player2": 1} {"player3": 1}
var groups = {}; // {"1": ["player1", "player2", "player3"]
var groupNumber = 1; // the current group number
var comingPlayers = 0; // a temporary variable for the coming players
var players = []; // a temporary array containing the players which have not formed 1 group
socket.on('connection', function(client) {
sockets[client.id] = client;
players.push(client.id);
clients[client.id] = groupNumber;
comingPlayers++;
if (comingPlayers === 3) { // now there are 3 players which can compose 1 group
groups[groupNumber] = arrayClone(players);
gamePlay(groupNumber);
players = [];
groupNumber++;
comingPlayers = 0;
}
}
The code you've shown is atomic (it will completely finish before another event handler can run), so you shouldn't have any synchronization issues. Remember that in node, all user-written code runs in a single thread. If somebody else is trying to connect, it won't interrupt what you're doing.

Resources