I'm trying to build a game which uses WebSockets. The collision detection and game state is handled on the server, which runs a game loop approx every 16ms. Each iteration, it sends out a message with the updated state to all players, which update the local copy and render the game.
About half the messages arrive fine, but sometimes there will be a batch where hundreds of ms of game time arrives instantly.
I created a minimal test case, which sends the current timestamp every 16ms. On the client, you can see it buffer messages every couple of seconds:
I've profiled the application, and over the duration of that gif there was only one dropped frame, with it otherwise maintaining a consistent 60fps.
I'm guessing GC could be the cause of one of the delays, but as for the others and resolving this I'm pretty stuck.
The application itself is Vue, however the game part is implemented in plain JS + Canvas.
Is your game loop using Window.requestAnimationFrame()? I would try to run the websocket code separetly, like in a timer.
You can also try other values for the websocket refresh like 36ms, 60ms, 120ms and see if this problem is still active. Maybe there are too many requests and some caching going on in the browser or in the server side.
I can't reprocude your problem, you should make sure this is because of the GC. (If this is the case you can try to eliminate the heavy GC calls (try reuse objects/arrays). Or maybe you can use your websocket code in a web worker somehow, but if the GC runs then the mainthread is blocked so you can put logic in the web worker also, but this is just a wild speculation, anyway you can test the communication in a webworker without game logic, just timestamps values).
Related
What i want to be able to do is in effect is check for messages from my web workers at a set point. so at the moment I have it set up so i tell my web workers to go ahead and get on with some complex calculations in the background and then my main frame gets on with some stuff too and then when the web workers are done they interrupt the main frame to do their callback function and it usually does this at a non ideal time effecting performance. So is there a way to kind of queue the callbacks and then run them when main frame says it's ok to do so...?
The only option around this i can see at the moment is to set up an extra worker where the other workers post their results to using 'MessageChannel' when they are done which can then be checked by the main frame on it's own terms!
thanks...
Update
after messing around with this for a while, i've realised what i thought was my problem is not actually my problem! what's actually happening is that when my web worker's finish this actually slows down my code... and given that i'm running an animation in the main frame this is seen as a stutter when each worker finishes! If I keep the worker going in the background with random tasks then this doesn't happen :-/ Very confusing??
Why would this happen? It's not as if I'm calling anything when the script finishes...
update 2
after a ridiculous amount of searching and playing around it turns out that this is only an issue when chrome (62) devtools is open!
I am developing a multiplayer game (for scientific experiment) where participants engage in 20 rounds of interactive decision making. Each round has 3 stages, each should last maximum for 30 seconds. I wonder what would be a good way to implement the countdown.
Currently, I am using a client side approach. On the creation of the round template, I use client side timer that submits the answer of the participant when it reaches 0. This is working fine so far (because everyone starts the game at the exact same time, and the next round starts only after everyone has submitted an answer). I am not sure that this is a good way to do it, considering that participants might disconnect (go offline, close the browser, have connectivity issues) and might manipulate the sessions or something.
Would it be a better approach to do a server side timer? For instance, a collection that contains the timer, and participants subscribe to that collection? If so, how would one implement a server-side countdown? Also, would this approach cause high demand on the server, given that every second in the countdown (that we display in the template) would require listening to data on the server?
Never trust the client.
With that in mind, we need to find a way for the client to display the remaining time, according to the time the server chose... First, the server puts the end-time of a round when it is created (or start time + duration).
Now that everyone has the same end-time which is according to the server, we need to sync them with server time. Let's use mizzao:timesync it's pretty straightforward, it receives the server time, and creates a difference from the client time. Monitors the client time to make sure no weird clock changes occur and even considers the latency. This might be a bit more than what you need, but it's already done, so less work for us!
Now that we know the current server time, and the round end time, we can easily show how long we got remaining! If a player comes back after a disconnect or refresh, both of those times will still be valid and they'll be able to continue the game.
I'm developing an app that should receive a .CSV file, save it, scan it, and insert data of every record into DB and at the end delete the file.
With a file with about 10000 records there aren't problems but with a larger file the PHP script is correctly runned and all data are saved into DB but is printed ERROR 504 The server didn't respond in time..
I'm scanning the .CSV file with the php function fgetcsv();.
I've already edit settings into php.ini file (max execution time (120), etc..) but nothing change, after 1 minute the error is shown.
I've also try to use a javascript function to show an alert every 10 seconds but also in this case the error is shown.
Is there a solution to avoid this problem? Is it possible pass some data from server to client every tot seconds to avoid the error?
Thank's
Its typically when scaling issues pop up when you need to start evolving your system architecture, and your application will need to work asynchronously. This problem you are having is very common (some of my team are dealing with one as I write) but everyone needs to deal with it eventually.
Solution 1: Cron Job
The most common solution is to create a cron job that periodically scans a queue for new work to do. I won't explain the nature of the queue since everyone has their own, some are alright and others are really bad, but typically it involves a DB table with relevant information and a job status (<-- one of the bad solutions), or a solution involving Memcached, also MongoDB is quite popular.
The "problem" with this solution is ultimately again "scaling". Cron jobs run periodically at fixed intervals, so if a task takes a particularly long time jobs are likely to overlap. This means you need to work in some kind of locking or utilize a scheduler that supports running the job sequentially.
In the end, you won't run into the timeout problem, and you can typically dedicate an entire machine to running these tasks so memory isn't as much of an issue either.
Solution 2: Worker Delegation
I'll use Gearman as an example for this solution, but other tools encompass standards like AMQP such as RabbitMQ. I prefer Gearman because its simpler to set up, and its designed more for work processing over messaging.
This kind of delegation has the advantage of running immediately after you call it. The server is basically waiting for stuff to do (not unlike an Apache server), when it get a request it shifts the workload from the client onto one of your "workers", these are scripts you've written which run indefinitely listening to the server for workload.
You can have as many of these workers as you like, each running the same or different types of tasks. This means scaling is determined by the number of workers you have, and this scales horizontally very cleanly.
Conclusion:
Crons are fine in my opinion of automated maintenance, but they run into problems when they need to work concurrently which makes running workers the ideal choice.
Either way, you are going to need to change the way users receive feedback on their requests. They will need to be informed that their request is processing and to check later to get the result, alternatively you can periodically track the status of the running task to provide real-time feedback to the user via ajax. Thats a little tricky with cron jobs, since you will need to persist the state of the task during its execution, but Gearman has a nice built-in solution for doing just that.
http://php.net/manual/en/book.gearman.php
I am making a realtime puzzle game using Node.js and Socket.io in the backend and Angular in the frontend. I need to keep track of time that the user spends on the puzzle and send it to the backend once they complete the puzzle OR if the time runs out before. I am not sure what the best approach for this would be.
My initial thought is just to keep track the time on the client side, which is easy to do. I would then send the time once the user completes the puzzle OR the time runs out. I think this would not be very secure since the client can easily slow down their computer or do something else to send false data.
My other idea is to just keep track of the time on the server side for EACH socket/player. I would also have to update the client side by emitting a message to the client after every second or something. This way is definitely secure because the client would never send me the time information. But this approach has other issues, how would this scale?
My last idea is to use a combination of both techniques. For example, I'll have a counter on the client side that shows the client the time so I don't have to make the server "emit" a time message every second or something. I would keep track of the time on the sever side, and simply use that information to update the score etc.
Thanks
The third option definitely sounds best to me. Since you're using Node on the back end, you get access to setTimeout just like you do in the browser. You can use that to schedule an event to be emitted to the client when their time is up, and meanwhile use front-end code to display the time remaining. You'll just want to make sure you don't start the clock on the front end until you've received confirmation that the timer has started on the server, and maybe pad the server timeout slightly to ensure that you don't cheat your player out of any time if things gets slightly out of sync!
Your third option is definitely the best. The only question is: how precise does it have to be? I don't know if people are going to compete for high scores based on time, but it would suck if higher latency would lead to a worse time. Personally I believe you could accept this for puzzle games, because it would otherwise become quite complicated. One solution for this could be to initially accept the (possibly tainted) client side measured time, but check it with the server time with a certain margin (+/- 1 second for example).
I fully understood what you were going to implement
I think you must implement the tracking in server, not frontend
As you know, the users can send the fake request
So in this case, you can use the websocket method
If you use the websocket method, we can check the user's played time
For example, we know when users start and end the game
so I think you can count the while time
I hope the websocket method is good way for you
Thanks
I am currently developing a peer to peer game in JavaScript using WebRTC. It treats one of the peers (i.e. the host) as the server and any other peers who join connect to the host through a node.js brokering server.
I am currently trying to solve an issue where the game stops updating for everyone if the host switches tabs such that the game is no longer the active tab. After doing some research, I discovered that this is because I'm using something like:
setTimeout(callback, 1000 / 60);
in my game loop. setTimeout (at least in Chrome and Firefox, which are the browsers I'm concerned with) is defined such that if the page calling it is not in your active tab, it can be called a maximum of once per second.
I read that Web Workers don't have this constraint, but in order to make that work I would need to run all of my game logic inside the web worker. I tried sending my game object to the worker using JSON.stringify(), but it said that the object had a circular reference (in the game loop) and it couldn't be converted to JSON. So I'm not sure what to do about that.
I also looked into implementing my own timer which kept running regardless of whether the page was in the active tab, but I'm not sure how to do this, either.
I don't really have a problem doing it either of these ways, or even some other way I haven't thought of yet, provided it doesn't incur a large performance overhead. Any suggestions would be greatly appreciated.
So, as I said above, Web Workers are able to call setTimeout() without the 1 second delay for inactive tabs. My solution then was to create a Web Worker which was only responsible for calling setTimeout() (called in its onmessage event listener). Then, at the end of each game loop I called:
this.worker.postMessage(null)
It could be argued that it would be more efficient to give the Web Worker more responsibility than just calling setTimeout(), since I've already added the overhead of waiting for messages to be sent between the main thread and the worker. This is something I might look at in the future.
The main problem with doing it this way is compatibility with IE; IE did not get support for web workers until version 10.0. This isn't really a concern for me but I think it's worth mentioning.