dphfox / Fusion

A modern reactive UI library, built specifically for Roblox and Luau.
https://elttob.uk/Fusion/
MIT License
530 stars 91 forks source link

Update step jumps massively 1 frame after Fusion is loaded #357

Open funwolf7 opened 2 days ago

funwolf7 commented 2 days ago

The update step is always 0 when Fusion is loaded, and then will become os.clock (in the case of RobloxExternal being used) upon next step, causing a massive jump. This in turn affects TweenScheduler/SpringScheduler in the main branch and ExternalTime in the push-pull-execution branch.

This causes any Tween or Spring made in the same frame that Fusion is loaded to jump to completion the next frame.

funwolf7 commented 2 days ago

There is a TODO in External.luau that hints at the solution: https://github.com/dphfox/Fusion/blob/259e56139175072268619bb2738c01defa73f5ed/src/External.luau#L115-L117 A system to preserve the time would fix not only this issue but also the issue of swapping external providers. When I discovered this bug about a week ago (didn't think about making an issue for some reason), I thought about a system which would allow this without requiring the providers to do much.

Currently, "now" is passed from the external provider to Fusion whenever an update step happens. For this idea to work, Fusion would need to be able to ask the external provider for "now."

Essentially, the idea is that Fusion has its own "standard time" that is used internally by Fusion, and each provider only needs to give Fusion its "local time." To translate from local time to standard time we can use a local and standard reference timestamp that we know mean the same timestamp. Simply subtract the local reference timestamp from the current timestamp and add that to the reference timestamp.

currentStandardTime = currentLocalTime - localReferenceTimestamp + standardReferenceTimestamp

The easiest reference timestamps are when providers change. To get the standard reference, get the standard time using the old provider (if none exists, keep the previous standard reference). To get the local reference, ask the new provider for its current local time (if none exists, do nothing).

Both reference timestamps can start at 0. When the first provider is added, it will begin increasing monotonically.