SocketIO Identify what user disconnected
Asked Answered
P

5

10

I am making a simple Node.js game that uses Express, Socket.io, and an Http server. All of the users are stored in a multidimensional object on the server. This is how the server-side code works:

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.use(express.static(__dirname + '/'));

var playerList = {};

createPlayer = function(array,width,height,spdx,spdy,x,y,color,name,id) {
  var player = {
    width:width,
    height:height,
    spdx:spdx,
    spdy:spdy,
    x:x,
    y:y,
    wKeyDown:false,
    aKeyDown:false,
    sKeyDown:false,
    dKeyDown:false,
    color:color,
    name:name,
    id:id
  }
  array[id] = player;
}

io.on('connection', function(socket) {
  socket.on('new player', function(id, name) {
    id = parseInt(id);
    if (!playerList[id]) {
      createPlayer(playerList,25,25,4,4,Math.round(Math.random() * 800),Math.round(Math.random() * 600),randomColor(),name,id);
    }

    socket.on('pressW', function(id, keyDown) {
      playerList[id].wKeyDown = keyDown;
    });
    socket.on('pressA', function(id, keyDown) {
      playerList[id].aKeyDown = keyDown;
    });
    socket.on('pressS', function(id, keyDown) {
      playerList[id].sKeyDown = keyDown;
    });
    socket.on('pressD', function(id, keyDown) {
      playerList[id].dKeyDown = keyDown;
    });
  });

  socket.on('disconnect', function() {

  });
};

sendPlayerList = function() {
  //newPlayerList is used to prevent client from seeing other users IDs
  var newPlayerList = {};
  var count = 0;
  for (var q in playerList) {
    player = {
      x:playerList[q].x,
      y:playerList[q].y,
      width:playerList[q].width,
      height:playerList[q].height,
      color:playerList[q].color,
      name:playerList[q].name,
    }
    newPlayerList[count] = player;
    count++;
  }

  io.emit('edit playerlist', newPlayerList);
}

SPLInterval = setInterval(sendPlayerList, 1000);

Here is the client-side code for connection:

var id;
$('#playbutton').click(function() {
  var name = document.getElementById('name').value;
  id = Math.floor(Date.now() * Math.random());
  socket.emit('new player', id, name);
});

On the client-side, in the update loop, when the game wants to tell the server your input, it emits your input like so:

update = function() {
    ctx.clearRect(0,0,canvas.width,canvas.height);
    if (document.hasFocus()) {
      socket.emit('pressD', id, dKeyDown);
      socket.emit('pressS', id, sKeyDown);
      socket.emit('pressA', id, aKeyDown);
      socket.emit('pressW', id, wKeyDown);
    }else{
      socket.emit('pressD', id, false);
      socket.emit('pressS', id, false);
      socket.emit('pressA', id, false);
      socket.emit('pressW', id, false);
    }
    clientUpdatePlayer();
    updatePlayers();
  }
}

var updateInterval = setInterval(update, 31.25);

The function to update players just draws players based on the player list sent from the server.

My problem is that when a user disconnects, they stay in the player list. I don't understand how I should go about fixing this. I identify users by getting the ID they send from the client, but I can't get the user's id when they disconnect.

There is a lot more code, but I tried to only include the code that I thought was necessary. I am willing to include more code if that is needed.

Poe answered 4/7, 2015 at 23:26 Comment(2)
possible duplicate: #13444003Troostite
you can use the events in the link above to send a disconnect event with the player id to the server, and you can remove them from the list when that event is received.Troostite
H
13

You could just store the id value in the parent scope, which the disconnect event handler would have access to:

io.on('connection', function(socket) {
  var userId;
  socket.on('new player', function(id, name) {
    userId = id = parseInt(id);
    // ...
  });

  socket.on('disconnect', function() {
    delete playerList[userId];
  });
};
Heartbreaking answered 5/7, 2015 at 1:24 Comment(4)
Would that work for multiple users? Wouldn't that just change the userId variable to the most recent player who connected?Poe
Yes it would work for multiple users. You already have the correct scope from the connection event handler, so it's the same socket and thus the same user. So unless you have it such that a user can register multiple player names concurrently on the same socket, you should be ok.Heartbreaking
why its the correct answer?user A with id=1 connect to server and userId is 1 now after that userB with id=2 connect to server after userA and userId is 2!now if userA disconnect this callback will delete userB from playerList!!Plowshare
I think userId will have the id of the user who joined recently.Fieldpiece
F
8

Maybe I'm late to the party but I was stuck with something similar and found it the hard way and this may help someone.

The best way to detect if the user is disconnected is would be to first set the username in socket session.

Send the name from the client on emit

socket.emit("newUser", username);

and on server

socket.on('newUser',function (username) {
     // we store the username in the socket session for this client
     socket.username = username;
});

and when the user disconnects find that on the disconnect event

socket.on('disconnect', function () {
    var connectionMessage = socket.username + " Disconnected from Socket " + socket.id;
    console.log(connectionMessage);
  });

and you can take it from there.

Fieldpiece answered 28/2, 2018 at 3:38 Comment(1)
Upvoted! Even if the answer posted by mscdex would work, I think it feels much more reliable and flexible to store the username on the socket-object and be able to get it from there at all times.Unskillful
P
3

This worked for me:

On every new connection or user who comes online generate a socket Id, add it to the user object, and add it to the array of all the users online.

const users = [];
io.on('connection', (socket) => {
const socketId = socket.id; 


socket.on('user online', (data) => {

    users.push({ ...data, socketId });
    io.emit('view user online', user);
  });

Then in the disconnect, use forEach to loop through each object in the array, then use for to loop through and delete each key in the object:

 socket.on('disconnect', () => {
    users.forEach((user) => {
      if (user.socketId === socket.id) {
        for (const key in user) {
          delete user[key];
        }
      }
        });

        logger(`A user has disconnected`);
      });
      });
});

Tweak to the way you want.

Punchy answered 8/4, 2020 at 12:52 Comment(0)
D
1
var users = [];
socket.on('newUser', (username) => {
    users.push({
        id: socket.id,
        username: username
    });
});
socket.on('disconnect', () => {
     const presentUser = users.find(user => user.id == socket.id);
     users = users.filter(user => user != presentUser);
});
Damick answered 9/7, 2020 at 10:46 Comment(4)
Please provide more information for further detail.Bernardo
Find the user which has disconnected using "socket.id" const presentUser = users.find(user => user.id == socket.id); Then remove this user from the list of online users using, users = users.filter(user => user != presentUser);Damick
Hope you are OK with the "arrow function" and the "find" and "filter" array methods in javascript.Damick
const presentUser = users.find(user => user.id == socket.id); Here socket.id refers to the socket or client which triggered the disconnect event or the client which has disconnected.Damick
H
0

We can use socket id for storing data as a refrence in playerList. whenever user will disconnect you can delete element from object according to socket id

var playerList = {};
io.on("connection", socket => {

if (!Object.values(playerList).includes(playername) && playername != null) {
      var U_data = {
        [socket.id]: playername
      };
      playerList = { ...playerList, ...U_data };
    }
  socket.on("disconnect", function(e, id) {
    console.log(socket.id);
    delete playerList[socket.id];
    io.emit("broadcast", Object.values(playerList));

  });
}
Hypabyssal answered 22/5, 2019 at 10:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.