how to set timer for each room in Socket.io, Nodej

2019-08-11 15:20发布

问题:

I want to create a turn based game with socket.io and nodejs . There is some rooms and every room should has it's own timer because players have time limitation for their movements so I want to know how can I handle this , maybe it's stupid way or also impractical to set a timer for each room ?!!! I don't know . please guide me :)

There is my code for player movement and other things :

var server = require('http').Server();
var socketIO = require('socket.io');
var io = socketIO.listen(server);


//var redis = require("redis"),
//client = redis.createClient();
var Room = require("./Room.js").Room;

var server_port = process.env.OPENSHIFT_NODEJS_PORT || 8080;
var server_ip_address = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1';


var connected_players = 0;
var players = {};
var rooms = {};

io.sockets.on('connection', function(socket){
  connected_players = connected_players + 1;
  console.log("New Player Connected :) \n" + "Total Number of Connected Players = " + connected_players );
  players[socket.id] = socket;
  socket.emit("sessionEv", {"session_id" : socket.id});
  socket.on("joining", function(data){


//SOME CODE FOR JOINING !!

  });

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

      console.log("disconnect" + this.id + " ; playerid = " + connected_players);
      delete players[socket.id];

      connected_players = connected_players - 1 ;


  });

  socket.on("move", function(data){
    var tempRoom = rooms[socket.room_name];
    var current_turn = tempRoom.Turn;
    console.log("on Move :" + data.handId + ":" + data.moveType);
    if (current_turn == data.handId ){ 
      console.log("correct move from :" + data.handId);
      //Calculating next turn;
      if(data.moveType == 1){
        while(true){
          current_turn = current_turn + tempRoom.Clock_Flag ;

          if(current_turn > tempRoom.Max*2){
            current_turn = current_turn%(tempRoom.Max * 2);
          }

          if(current_turn === 0){
            current_turn = tempRoom.Max * 2 ;
          }

          if(!checkLoseHand(current_turn, tempRoom)){
            break;
          }
        }
      }
      if(data.moveType === 2){
        tempRoom.Clock_Flag = tempRoom.Clock_Flag * - 1;
        while(true){
          current_turn = current_turn + tempRoom.Clock_Flag ;

          if(current_turn > tempRoom.Max*2){
            current_turn = current_turn%(tempRoom.Max * 2);
          }


          if(current_turn === 0){
            current_turn = tempRoom.Max * 2 ;

          }
          if(!checkLoseHand(current_turn, tempRoom)){
            break;
          }
        }
      }
      if(data.moveType == 3 ){
        while(true){
          current_turn = current_turn + tempRoom.Clock_Flag ;

          if(current_turn > tempRoom.Max * 2){
            current_turn = current_turn%(tempRoom.Max * 2);
          }


          if(current_turn === 0){
            current_turn = tempRoom.Max * 2 ;
          }

          if(!checkLoseHand(current_turn, tempRoom)){
            break;
          }
        }  
        while(true){
          current_turn = current_turn + tempRoom.Clock_Flag ;

          if(current_turn > tempRoom.Max * 2){
            current_turn = current_turn%(tempRoom.Max * 2);
          }


          if(current_turn === 0){
            current_turn = tempRoom.Max * 2 ;
          }

          if(!checkLoseHand(current_turn, tempRoom)){
            break;
          }

        }





    }
    tempRoom.Turn = current_turn;
    var d = new Date();
    var n = d.getSeconds();
    tempRoom.lastmove = n;
    tempRoom.start = true;
    console.log("next turn = " + current_turn);
    io.sockets.in(socket.room_name).emit("move", {"handId" : data.handId , "moveType" : data.moveType, "turn" : current_turn});




  }
    else{
      io.sockets.in(socket.room_name).emit('lose', {"handId" : data.handId} );
      socket.broadcast.to(socket.room_name).volatile.emit("move", {"handId" : data.handId , "moveType" : data.moveType, "turn" : current_turn});
      tempRoom.losers_hand.push(data.handId);

    }
  //}
  });

});

server.listen(server_port , server_ip_address);



playerById =  function(id) {
  var i;
  for (i = 0; i < players.length; i++) {
    if (players[i].id == id)
      return players[i];
  }

  return false;
};

checkLoseHand = function(id, tempRoom ){
  for (i = 0; i < tempRoom.losers_hand.length; i++) {
    if( tempRoom.losers_hand[i] == id){
      return true; 
    }

  }
  return false;
};

function get_users_by_room(nsp, room) {
  var users = [];
  for (var id in io.of(nsp).adapter.rooms[room]) {
    users.push(io.of(nsp).adapter.nsp.connected[id]);
  }
  return users.length;
}

setInterval(function(){
    var d = new Date();
    for (var key in rooms)
    {
        console.log(key);
        console.log(d.getSeconds());
        console.log(rooms[key].lastmove);
        if(Math.abs(d.getSeconds() - rooms[key].lastmove) > 5 && rooms[key].start )
        {
            io.sockets.in(key).emit('lose', {"handId" : rooms[key].Turn } );
            //inja bayad turn badi ham ersal she .
        }
    } 
    //console.log("here");
}, 1000);

when a MOVE EVENT receive I send that move to other players and calculating next turn (NOW timer should start to count seconds for current turn player) and if player move in allowed time nothing happen but if not he must leave the game room .

And as you can see I wrote a SetInteval function at the end of the code . This function just check that time limitation for every room in every second that I think it have heavy load on server if there are too many rooms so I'm seeking a better way .

thank you

回答1:

If you intend to scale to Node.js and setInterval is likely not an ideal solution if you want scalable precise timings.

Iterating through all the rooms will likely be fine for now, as you will need a very large number of rooms before this blocking iteration causes performance issues.

Some ways of mitigating those issues would be scaling your Node cluster horizontally and distributing the rooms across multiple Node processes, or implementing a lazy-check for invalid moves by checking if a move is invalid within the move event listener, rather than having a setInterval.