Open Decane opened 1 year ago
Another quirk of vanilla X-Ray seems to be that the precision of integers >= 2³¹ saved as u32 is limited to the nearest multiple of 256. So, any integers >= 2,147,483,648 will be rounded to the nearest multiple of 256 when saved using e.g. xr_logic.pstor_save_all
. Thus, if the number saved is in milliseconds, then the number loaded would have a rounding error of up to 128 milliseconds. No big deal if we only need to-the-nearest-second precision, but suppose we're saving a number denominated in seconds. We'd have a rounding error of over 2 minutes in the worst-case scenario!
It turns out
game.time()
wraps around to 0 after ~30¼ game days ((2³² - 1) - 1,679,936,192 game milliseconds). One option would be to convert the C++ struct returned bygame.get_game_time()
into seconds and use that in place ofgame.time()
wherever sub-second precision is not required. The Lua built-inos.time
function could be used for the conversion, albeit at the cost of sub-second rounding errors. Here is an example of how to implement that: https://github.com/Decane/SRP/commit/9919135f6916c04dae5fabc762756f2cacc338d4. If millisecond precision were required,get_game_time_in_seconds()
in the aforementioned commit could be modified to return a fractionalos.time(time_table) + ms * 0.001
, however saving it without losing precision might be tricky since the engine doesn't expose a double-precision floating point save method.Saving a large u32 — like that returned by
get_game_time_in_seconds()
in the commit above, assuming not modified for fractional precision — as a float32 is a bad idea; we begin losing precision with odd numbers above 16,777,216 (2²⁴) and even numbers above 33,554,432 (2²⁵). That means we can only save up to ~194.18 days of seconds into a float32 before we begin seeing ±1 second rounding errors. Past ~388.36 days, these grow to ±2 seconds. If counting were to begin from the epoch (as inos.time
), we'd already be way over the precision limit when the game starts at 06:10 2011/09/10, and our rounding errors would be immense (±64 seconds). Even if counting began from 2011/01/01 instead, we'd be up to 21,795,000 seconds when the game starts. We could hard-code the counting to begin at the vanilla game start time, but that could break mods that use a different start time. As there seems to be no way to access the game start time directly from Lua, my solution againstgame.time()
precision loss in https://github.com/Decane/SRP/commit/f4b5ce8451b30f1713eba0842a91f8e0cee6abc4 was to detect fractional numbers inxr_logic.pstor_save_all
and save those as float32, else save as s32 or u32 yielding 2,147,483,647 (2³¹ - 1) or 4,294,967,295 (2³² - 1) seconds of wiggle room, respectively.To save a fractional
get_game_time_in_seconds()
without precision loss would likely require saving the fractional part separately, perhaps as a u16.