EverestAPI / Everest

Everest - Celeste Mod Loader / Mod API
https://everestapi.github.io/
MIT License
329 stars 71 forks source link

Entity update skips a tick exactly every 832ms with .NET 7.0 #783

Closed tddebart closed 1 week ago

tddebart commented 1 week ago

My mods and Everest install are up to date

Yes

I have recreated the bug with only Everest OR a minimum number of mods enabled

Yes

Describe the bug

Was working on a mod that requires consistent input like a TAS and noticed when I updated the .NET version to 7.0 that the game is skipping update ticks. Quickly made a reproducer and noticed that it is exactly every 832ms that the game skips one update tick on every entity. While it doesn't do this if you build the project with .NET framework 452. I can't just leave my project on version 452 because I want to use ImGui and that doesn't have support for that old version. I hope this isn't a CPU related problem and that it can be fixed because I currently can't continue on my mod like this.

Steps to reproduce

  1. Download the reproducer project https://github.com/tddebart/TickMissReproducer
  2. Put the project in your celeste mod folder
  3. build the project
  4. launch the game with --console and go into any level
  5. see in console that only TickMissReproducer70 is skipping a update tick every 832ms

Expected behavior

No matter the .NET version is should never skip a update tick

Operating System

Windows 10

Everest Version

4818

Mods required to reproduce

The reproducer mod https://github.com/tddebart/TickMissReproducer

Additional context

Also noticed that if I started the game through Rider which attached the console to the editor. The difference between skips becomes 833ms instead of 832ms

Wartori54 commented 1 week ago

I strongly believe that your measurements were improperly done, since you used TimeSpan.FromSeconds(rawDt).Ticks and assumed that it was the actual amount that Celeste internally added on each update to the session time.

.NET Core and .NET Framework TimeSpans work differently, this is why you are seeing a difference in ticks every 832ms. Celeste was patched under core to still use the old implementation, so you should also use that same one. It can be found in the NETCoreifier project, in Patches/TimeSpan.cs.

Patching your code to use the TimeSpanShims implementation instead on line 43 in your entity seemingly fixes the issue (a single tick was missed at around 10 seconds).

Regarding your actual issue, since you are using precise timings, and we know that timespan implementations do change, maybe its just FNA.dll being ran under .NET Core (since it uses TimeSpans) that causes your desyncs in your actual app (or maybe its just the switch from XNA (which can be used under .NET Framework) and FNA (which will be always used on .NET Core)).

tddebart commented 1 week ago

Thanks, using the TimeSpanShims implementation fully fixes my issue and i'm getting no tick skips now (the one you got was probably from dashing or pausing since it still keeps updating then). Didn't know the session time calculation had changed in .NET core.