eugeneloza / decoherence

Project moved to https://gitlab.com/EugeneLoza/decoherence
GNU General Public License v3.0
10 stars 7 forks source link

Backward-going time bug #578

Open eugeneloza opened 6 years ago

eugeneloza commented 6 years ago

We may get a very buggy behavior in case OS time goes backward during world management (e.g. in case the time would get automatically updated from the time server). As far as every frame would try to balance frame rate and critical/non-critical management tasks, NewTime-OldTime would be less than FrameDuration for a long time, which would make the game freeze for a prolonged period of time. I'm not exactly sure how long that might take, as the amount of management tasks is actually finite, but anyway that would be a very hard to track bug that would force the game to freeze for at least several seconds without any message (as the manager would "think" it's a normal time flow and would perform management tasks until management queue is empty).

Actually the freeze shouldn't be too long, as such calculations would be done during every initialization of the overworld, but still it's a bug, and I should keep an eye on it. The simplest solution would be just add "Please wait..." nag in case NewTime-OldTime < 0 or less than some "minimal value". This way it'll just take some time to recalculate the world objects, and as long as this would be an extremely rare event it won't bother the player too much.

michaliskambi commented 6 years ago

Note that at least on Linux, the time does not go backward in case of synchronization, at least when it was not desynchronized a lot. They use a trick (they slow down time to synchronize), to avoid causing the problems you're thinking about for many applications:)

See https://serverfault.com/questions/94683/will-ntp-drift-the-clock-backwards and other results for Google "linux time backwards ntp" :)

eugeneloza commented 6 years ago

Well, the first thing I thought of was a comment in CastleTimeUtils about time going back on Android. And the second one - changing the time manually (e.g. by date --set 15:00:00) or automatically (e.g. due to DST switching). Sometimes the user may have been long time off the Internet (e.g. due to poor connection) and the change is larger than a few seconds. All of the above are extremely rare case. But not impossible. So yes, this issue is marked as "Unimportant" for that reason, because when it actually happens there will be no way for the player to understand "why did it freeze?" so, adding a "Please Wait" would be quiet fine, I guess.

eugeneloza commented 6 years ago

Anyway, I'll need to implement some sort of that thing somehow during the reentry to the overworld, maybe even by manually setting negative time for the frame, so that both will be covered by the same algorithm and would require no additional time :)

michaliskambi commented 6 years ago

Well, the first thing I thought of was a comment in CastleTimeUtils about time going back on Android.

Indeed, it seems that on some Android devices some vendor stupidly turned off this mechanism (to avoid moving time backward), and I was happening very often (like at least once every 5 minutes). Fortunately, it never happens on all other Android devices (or other Unix systems) I tested.

As for DST switching: To this, you can be invulnerable if you always get a time like "number of seconds since the Unix epoch (beginning of 1970 in UTC timezone)" . Functions like gettimeofday work like this. (CGE Timer on Unix uses gettimeofday internally.) If you do your calculations/comparisons using such "time since Unix epoch", then the DST change (and user timezone, in general) doesn't matter to you.

(You are indeed still vulnerable to the case when user just changes the system time, e.g. sets it an hour back or such.)

On Windows, you can also avoid the problem by using GetTickCount, which is local time inside the process. As far as I know, it never goes back, and it ignores any changes to system time (as it's not interested in hour/minute, it only counts the time passed for your process). Same thing for QueryPerformanceCounter, as far as I know. CGE uses this by default on Windows for Timer.

You are of course right that, in general, this is something that could happen and you need to be ready for this! :)

I'm just pointing out that some cases are secure. We are invulnerable to DST change, we are invulnerable to small desynchronization on Unix (if the synchronization happens often, i.e. internet connection is good), we are invulnerable to changes on Windows (with it's "local process time in QueryPerformanceCounter / GetTickCount") -- if you use a proper API, like Timer from CGE :)

eugeneloza commented 6 years ago

if you use a proper API, like Timer from CGE :)

Yeah. But I use a bit simplified (stripped) version of Timer from CGE :) And management routine (which is the only vulnerable) is managed by threaded timer (the one I've told about on SourceForge some time before): https://github.com/eugeneloza/decoherence/blob/master/src/core/decotime.pas#L239 which is even more vulnerable to time going backwards (as zero-time shift is ok there - it just means that a management task was faster than the timer call).