Hi all
Suppose I want to count down a timer and when it is zero, do something(for example a player can upgrade something)
The timer is set from the server(for example 120 seconds). If yield return new WaitForSeconds is not accurate, there will be a problem. The time in the client side is zero but when a player clicks, it says you can not upgrade (because the timer in the server side is not zero).
WaitForSeconds is scaled by Time.timeScale, so it may not be accurate. Use WaitForSecondsRealtime.
Also, to enable a flawless user experience, consider having a buffer of time so that the user always wins. The server could tell the client to wait 120 seconds, but the server-side timer is only 118 seconds. So the user will never lose.
Is the server also handling whatever user action is being gated? If so then there shouldn’t be an issue.
- Client asks server to upgrade
- Server processes upgrade, starts 120 second timer, sends success response to client
- Client gets success and starts 120 second timer locally (this will always finish after server)
I don’t know what you said. never lose!
It can only create a delay. I can synchronize for example every one min
yes so I said to know yield return is accurate or not!! it can create a delay if it is not accurate
Client gets success and starts 120 second timer locally
if every waitforseconds(1f) is 1.02 or more or less than one…
Which accuracy are we talking about? The one influenced by delay due to data transmission over the network or the actual accuracy of WaitForSeconds (in disregard of networking)?
WaitForSeconds itself will never be accurate to the number of seconds / ms you passed in. It’s a yield instruction that will be processed after the Update function so it will be done waiting once the internal timer has surpassed the number of specified seconds for the first time. If you’re lucky, it could be exact, but it’s most-likely going to overshoot for some ms most of the time.
WaitForSeconds will allow the coroutine to continue on the first frame that is past the duration you give it. So it’ll basically be no more than duration + Time.deltaTime. So yes, it could be 1.02 seconds if your frames take 200ms to process ![]()
I didn’t know what you say dude. forget latency due to data transmission (it is ok and doesn’t create any problem)
I said when time is less than or equal zero and called AppearButton(), it has not passed accurate 120sec.
So when a player clicks on the button(), he/she receives a message that you can not upgrade because time has left(because time in client side is zero but not in sever side)
IEnumerator Timer()
{
float time=120;
while(time>0){
yield return new waitforseconds(1);// it waits for 0.98s
time--;
}
// maybe 118 sec instead of 120sec?
AppearButton();
}
unless when time is zero I sent a request to the server and check time is finished or not and get current time again?
You aren’t reading the replies very well. WaitForSeconds will not return early, ever. It will return >= the asked for time.
it is so obvious. I know it waits almost 1sec!!! the problem is almost
I think you don’t understand what I say
Well, sometimes I have trouble understanding you, but …
Your example showed less than 1 second and less than 120 seconds. That is impossible. Do you understand that?
please say the possible wait time interval when I write:
yield return new waitforseconds(1) for example: 1sec-1.03 sec?
and when I wait inside a loop with iteration 120: finally how much do I wait accurately?120-120.03?
when I wait inside a loop with iteration 100000: finally how much do I wait accurately?100000-100000.03?
and when this one sec wait is inside a loop with n iteration: the error is accumulated? n*0.02 error?
there is no definitive answer. It’s been written several times here in this thread. The time will be >= 1sec (per your example).
If it’s > 1 sec… it could be anything.
There’s already a great solution posted for you here, if you’re using a server. Tell the server you want to begin, it begins, and tells you it has. Then, when you get that message, you start your timer.
You could add, possibly redundant “wait” at the end. Your timer expires and says “Finishing” until a message from the server arrives saying that the timer has elapsed. At that point, you are certain it is what you think it is ![]()
Hopefully that makes more sense now.
It’s not even a flat n * value (well, unless the loop was done in 1 frame), but over “frames” (plural), it would/could vary ![]()
Thanks I said the worst and the most error.
obviously it differs because the frame rate is different
Cool, well I think that part is less relevant than the main idea here that the timer will be >= the time you requested to yield. With that knowledge, you can probably build what you want, right?
void Start () {
StartCoroutine("Timer");
}
IEnumerator Timer() {
float time = 200;
System.DateTime dt = System.DateTime.Now;
while (time>0) {
yield return new WaitForSeconds(1f);
time--;
}
System.DateTime dt2 = System.DateTime.Now;
print(dt2-dt);
}
}
I tested it. the error is about 2secs for 200 secs duration. it is huge.
00:03:22.1063079
Because this value(202.106 secs) is more than accurate value(200secs), it is ok and when a player sees 00:00 in the game and clicks on the button to upgrade, the time in server side is zero definitely
Thanks dudes ![]()
KelsoMRK said right, yield return new waitforseconds waits for more than accurate time.
Why don’t you just use real time for this? I think it is much more suitable.
WaitForSeconds can be very incurrate for such a task, for instance on laggy devices.
That’s because your mechanism for waiting is totally borked. Just yield a WaitForSeconds(200) if you want to wait 200 seconds. Otherwise you’re accumulating the error across 200 waits.
In either case - glad you figured it out.