Different timers for different rooms using Socket.io - node.js

I found 3 other posts about implementing timers for turn based games but none of them had a final answer.
I am working on a poker game project using WebSockets (Socket.io) rooms.
Each room has a timer which takes care of the turns from the server, for example, each player has 10 seconds to choose a card. If there was only one room I was able to do this by using setInterval and changing the turn variable at the end of each interval and emit the new turn to the clients.
But right now, I am confused how to implement a specific timer for each room when there are a lot of rooms considering that node.js is single threaded.

Despite being single threaded, Node.js can manage multiple timers at once. You can just set them. How you do it is up to you. Keep in mind that you'll need to use bind if you're managing your Rooms with objects. You can use variables to manage (for example, cancelling) your timers.
Here is a general example:
var Room = function() {
this.id = String(Date.now());
this.timer = setInterval(this.timerFunction.bind(this), 10000);
}
Room.prototype.timerFunction = function() {
// Example
io.to(this.id).emit("some message");
}
// Create one
new Room();

Related

Should i implement lock statement for each function in server client base to avoid multiple requesting?

consider a multiplayer game that every client can request for some action in server.so that client can send a request continuously.
should i have to implement lock statement on each method that client can call to avoid multiple accessing thread(client)?
something like this one?
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement
is there any better solution?
my game server is photon engine.
if i place this code in a loop with 200 iterate without lock statement,it will show me some ("its not 11") result from multiple threads.
public static number n1 = new number();
public static void PlusAndMinusInt()
{
lock (n1)
{
n1.x++;
Console.WriteLine($"{n1.x}");
if (n1.x != 11)
Console.WriteLine($"its not 11");
n1.x--;
Console.WriteLine($"{n1.x}");
}
}
well i think i got that.
There is no 'at the same time'
When they are called from the same unity client they will have an order and will be executed in that order, if they happen from different clients they will be processed in parallel potentially as they are on different fibers etc
I don't use Photon, but I think the multithreading synchronizing problem I encountered may be similar.
I once used a Socket library, where each socket can set event triggers upon receiving messages, and it uses multithreads to handle the them;
The solution working for me is to use the ConcurrentQueue ; we do not really handle the message immediately.
Rather, the messages are pushed in this queue, and are later de-queued/handled in the Main Thread.
This saved me the hassle of using lock everywhere; hope that is what you want.

Real time multiplayer game using Node.JS, MongoDB and Socket.IO : Game loop and async calls

I'm currently building a HTML5 game using Node.JS, MongoDB and Socket.IO. The purpose of this project is not really creating a finished, fully playable game but rather understanding and implementing some basic concepts of multiplayer game programming and getting used to MongoDB.
Here is the basic server architecture I went with. The server listens to clients through Socket.IO and everytime a message is received, it push it to a queue. A message is received whenever a player wants to move, or effectively alter the game in a way. I'm staying really vague because it does not really matter to show you in details what this game is. So the server receives messages from all the clients and keeps it in memory for a certain time.
Every 50ms the server processes sequentially all the messages in the queue and makes the game state advance, broadcast the changes to clients and then empties the queue and starts listening again to clients.
I'm having some difficulties building this game loop as I'm not really sure of what does MongoDB and if it does it in time, as all the calls are pure async. Let's say the following code is in my game loop, here is my concerns:
for (var i=0; i<queue.length; i++) {
if(queue[i].message.type === "move") {
//The server has first to ensure that the player can effectively move,
//thus making a query to MongoDB. Once the result has been retrieved,
//the server makes an update in MongoDB with the new player position
}
//At this point, due to the async nature of MongoDB,
//I cannot ensure that the queries have been executed nor that the message was effectively handled
}
//Here again, I cannot ensure that the game state gracefully advanced
//and then I cannot broadcast it.
I think the game loop has to be sequential, but I'm not sure if it's possible to do so using MongoDB and I'm not sure MongoDB is the right tool for that job.
I'm using the official Node.JS driver for MongoDB as I'm more interested in nested documents than in Object Data Modeling.
Do you have any clues on building a sequential game loop in this case ? Or am I using MongoDB in a case outside its purpose ?
Seems fairly straight forward.
The solution is not to use a for loop, as you only want to start the next message being processed after the previous one has completed. For this, it is probably easier to use a library like async and the eachSeries function.
https://github.com/caolan/async#each
async.eachSeries(queue, processMessage, allDone);
function processMessage(message, callback) {
// do stuff with message, don't forget to call callback when you have complete all async calls and are done processing the message!
// eg
if(message.type === "move") {
mongo.insert({player: message.player, x:message.x, y:message.y}, function (err, res) {
// error check etc
callback();
}
}
}
function allDone() {
// called when all messages have been proccessed!
// setTimeout(processNewQueue, 50);
}

Why this online game go out of sync after some time?

I'm making a simple online game and I'm suffering from out-of-sync issues. The server is implemented with IOCP, and since the game will be held almost always in LAN, the delay is relatively small.
The core algorithm of network connecting can be described as below: (There are 4 clients in a single fame)
Clients send their actions and the elasped time since the last frame to the server every frame, then wait until get a response from the server.
The server collects all four clients' messages, concatenate them together, then send it to all four clients.
On receiving the response, clients update their game with the messages provided in the response.
Now, I can see that after some time the four games go out of sync. It can be observed that the game I'm controling is different from the other three(which means the other three are the same), and just by walking around makes the problem happen.
Below is the code, if it might be helpful:
First, the server. Every message will be handled in a separate thread.
while(game_host[now_roomnum].Ready(now_playernum)) // wait for the last message to be taken away
{
Sleep(1);
}
game_host[now_roomnum].SetMessage(now_playernum, recv_msg->msg);
game_host[now_roomnum].SetReady(now_playernum, true);
game_host[now_roomnum].SetUsed(now_playernum, false);
while(!game_host[now_roomnum].AllReady()) // wait for all clients' messages
{
Sleep(1);
}
string all_msg = game_host[now_roomnum].GetAllMessage();
game_host[now_roomnum].SetUsed(now_playernum, true);
while(!game_host[now_roomnum].AllUsed()) // wait for all four responses are ready to send
{
Sleep(1);
}
game_host[now_roomnum].SetReady(now_playernum, false);// ready for receiving the next message
strcpy_s(ret.msg, all_msg.c_str());
And the clients' CGame::Update(float game_time) method:
CMessage msg = MakeMessage(game_time);//Make a message with the actions taken in the frame(pushed into a queue) and the elasped time between the two frames
CMessage recv = p_res_manager->m_Client._SendMessage(msg);//send the message and wait for the server's response
stringstream input(recv.msg);
int i;
rest_time -= game_time;
float game_times[MAX_PLAYER+1]={0};
//analyze recv operations
for(i=1; i<=MAX_PLAYER; i++)
{
int n;
input>>n;
input>>game_times[i];//analyze the number of actions n, and player[i]'s elasped game time game_times[i]
for(int oper_i = 1; oper_i <= n; oper_i++)
{
int now_event;
UINT nchar;
input>>now_event>>nchar;
if(now_event == int(Event::KEY_UP))
HandleKeyUpInUpdate(i, nchar);
else //if(now_event == int(Event::KEY_DOWN))
HandleKeyDownInUpdate(i, nchar);
}
}
//update player
for(i=1; i<=MAX_PLAYER; i++)
{
player[i].Update(game_times[i]);//something like s[i] = v[i] * game_time[i]
}
Thank you very much. I'll provide more detail if necassary.
Ur general design is wrong, that's why u get async at some point. The server should never ever deal with the fps of the clients. This is just a horrible design issue. On general the server calculates everything regarding on the input's the clients send to server. And the clients just request the current status of their surroundings of the server. That way u are fps independent on the server side. Which mean u can update the scene on the server as fast as possible, and the clients just retrieve the current status.
When u update the entities on the server fps dependent per user, u would have to keep a local copy of every entity for every client, otherwise it's impossible to transfer for different delta times.
The other design could be that ur server just syncs the clients, so every client calculates the scene on it's own and then send their status to the server. The server then distributes this to the other clients, and the clients decide what to do with this information.
Any other design will lead to major problems, i highly regret to not use any other design.
if u have any further questions feel free to contact me.

How to wait for time interval?

I am busy with a node.js project communicating with an API which involves heavy use of a node library specific to that API. I have read (I think) all the existing questions about the kind of issues involved with pausing and their various solutions but still not sure how to apply a correct solution to my problem.
Simply put, I have a function I call multiple times from the API library and need to ensure they have all completed before continuing. Up to now I have managed to use the excellent caolan/async library to handle my sync/async needs but hit a block with this specific function from the API library.
The function is hideously complicated as it involves https and SOAP calling/parsing so I am trying to avoid re-writing it to behave with caolan/async, in fact I am not even sure at this stage why it is not well behaved.
It is an async function that I need to call multiple times and then wait until all the calls have completed. I have tried numerous ways of of using callbacks and even promises (q library) but just cannot get it to work as expected and as I have successfully done with the other async API functions.
Out of desperation I am hoping for a kludgy solution where I can just wait for say 5 seconds at a point in my program while all existing async functions complete but no further progress is made until 5 seconds have passed. So I want a non-blocking pause of 5 seconds if that is even possible.
I could probably do this using fibres but really hoping for another solution before I go down that route.
one simple solution to your problem would be to increment a counter every time you call your function. Then at the end of the callback have it emit an event. listen to that event and each time it's triggered increment a separate counter. When the two counters are equal you can move on.
This would look something like this
var function_call_counter = 0;
var function_complete_counter = 0;
var self = this;
for(var i = 0; i < time_to_call; i++){
function_call_counter++;
api_call(function(){
self.emit('api_called');
});
}
this.on('api_called', function(){
function_complete_counter++;
});
var id = setInterval(function(){
if(function_call_counter == function_complete_counter){
move_on();
clearInterval(id); // This stops the checking
}
}, 5000 ); // every 5 sec check to see if you can move on
Promises should work also they just might take some finessing. You mentioned q but you may want to check out promises A+

multi-thread flash

I want to do multithreading! I want to make a timer with play/pause/stop buttoms
and when user pressed the play button, a timer starts counting.
I want to do the counting process, while this, another operation should do,
because with this timer user wants to measure sth that is going on, somwhere else in the scene
anyway, I want to to sth, and user measure how long it takes!!!
I'm newbie to flash, but as far as I know the solution is multithreading!
or is there any timer or sth like that that it can measure time, without causing the program to hang!
I'm working with as2 , but if as3 is the only way, it's fine!
tnx
Flash player 11.4 offers multi-threading of sorts with the new concurency (actionscript workers) features. Read about it here: http://blogs.adobe.com/flashplayer/2012/08/flash-player-11-4-and-air-3-4.html
Flash 11.3 and under don't offer multithreading. Your question though doesn't especially require multithreading though. The flash.utils.Timer class and flash.utils.setTimeout() are asynchronous and don't hang your code stack.
I would recommend looking at these classes on the adobe docs.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/Timer.html
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/package.html#setTimeout()
To address your question in the comments:
var timer:Timer = new Timer(1000); //fire every second, make this number smaller to have it update faster
timer.addEventListener(TimerEvent.TIMER, updateLabel);
var timeStamp:int;
function startTimer():void {
timeStamp = getTimer();
timer.reset();
timer.start();
}
function updateLabel(e:Event):void {
var timePassedSoFar:int = getTimer() - timeStamp;
//update your label to show how much time has passed (it's in milliseconds)
}
If you only want seconds, you could also just use the timer.currentCount property (instead of getTimer()) which tells you how many times the timer has fired, which in the example above is the amount of seconds elapsed as it fires once per second.

Resources