November 03, 2014, 11:02:24 am

This seems like a map engine bug to me, so I'm posting it in Map Support, but I'm actually not positive.

I encountered a very strange issue after implementing random battle triggering in Specs: When a battle is triggered, a bunch of stuff is skipped, despite no actual lag occurring at all. It appears there's some erroneous frame-skipping going on here for reasons I can't fathom...

Stand around on the map for a bit, then try to trigger a battle. Once the battle music starts, you'll see a variable number of frames skipped equal to the number of frames spent on the field.

miniSphere 5.0b2 (stable: 4.8.8) - Cell compiler - SSj debugger - thread | on GitHubFor the sake of our continued health I very much hope that Fat Cerberus does not become skilled enough at whatever arcane art it would require to cause computers to spawn enormous man-eating pigs ~Rhuan

Well isn't this something. I had forgotten all about it, but THIS was the issue that ultimately pushed me to make minisphere. Sometime toward the end of 2014 I did eventually figure out the cause of this glitch: Sphere 1.5 has a bug in its FPS throttle code that causes it to skip seconds worth of frames if a script blocks during the main MapEngine() loop.

I actually don't know if this bug was fixed in later Sphere builds like 1.6, but in any case, here it is for posterity - the bug that convinced me Sphere 1.x needed to be replaced.

miniSphere 5.0b2 (stable: 4.8.8) - Cell compiler - SSj debugger - thread | on GitHubFor the sake of our continued health I very much hope that Fat Cerberus does not become skilled enough at whatever arcane art it would require to cause computers to spawn enormous man-eating pigs ~Rhuan

Well isn't this something. I had forgotten all about it, but THIS was the issue that ultimately pushed me to make minisphere. Sometime toward the end of 2014 I did eventually figure out the cause of this glitch: Sphere 1.5 has a bug in its FPS throttle code that causes it to skip seconds worth of frames if a script blocks during the main MapEngine() loop.

I encountered that bug all of the time. I eventually ended up caching the framerate before I go into a blocking loop and then I unthrottle the frame rate. Then when the loop has finished, I bring the framerate back to normal.

It's good to hear that this does not happen in minisphere.

If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Remember those two lines, I'll come back to them in a bit. Sphere's frameloop works by predicting the time of the next frame. If a render takes longer than that, subsequent frames are skipped (up to 20!) to make up the difference. If instead the frameloop is ahead of schedule, the engine kills time until the wall time catches up. Nothing too fancy, minisphere's frameloop works similarly. However, Sphere's has a fatal flaw: It doesn't reset the timer after a skip. Here's the core of the frameloop:

Remember those two lines above? m_NextFrame is reset when a script takes longer than 1000ms. Except sometimes this isn't done (I don't remember the exact scenario that causes that), and that's where the problem starts. The engine now thinks it's WAY behind schedule and tries to catch up by skipping frames. Max frameskip is 20, so after 20 frames it should straighten itself out--except that the timer isn't reset during the skip, so it just keeps on skipping until it catches up. Effectively you have infinite frameskip, with an odd flip thrown in every 20 frames each time the limit is hit.

This was the reason I wrote the minisphere frameloop the way I did. All the frame management is centralized in FlipScreen(), so no matter how your control flow goes, no matter whether an update script blocks or not, the same timing logic is used for every flip so that the above is a non-issue. There's never any need to detect blocking scripts because if, at any time, the frameskip limit is hit (in minisphere, 5 frames by default), the prediction can no longer be trusted and the engine resets it.

Take note of the last sentence in that comment. better that we lag instead of never rendering anything at all. Thanks a lot, buggy engine.

miniSphere 5.0b2 (stable: 4.8.8) - Cell compiler - SSj debugger - thread | on GitHubFor the sake of our continued health I very much hope that Fat Cerberus does not become skilled enough at whatever arcane art it would require to cause computers to spawn enormous man-eating pigs ~Rhuan

It just spins in a while loop for a bit instead of sleeping nicely until the next frame like minisphere does. Now I know why Sphere 1.5 was always such a CPU hog.

miniSphere 5.0b2 (stable: 4.8.8) - Cell compiler - SSj debugger - thread | on GitHubFor the sake of our continued health I very much hope that Fat Cerberus does not become skilled enough at whatever arcane art it would require to cause computers to spawn enormous man-eating pigs ~Rhuan