valorware

Engine: Unity
Spine version: 3.7.87
Spine runtime: version: 3.7.xx

Hi, I'm having a very similar bug to: IndexOutOfRangeException in Spine.Animation.BinarySearch

Except it's color track, and happens usually when I come out of the game pause mode. When I pause the game, I set all spine animations and their track's time scale value to 0f, so they stop. On resume, I set them back to what they're supposed to be doing.

It happens here:
/// <param name="target">After the first and before the last entry.</param>
internal static int BinarySearch (float[] values, float target, int step) {
int low = 0;
int high = values.Length / step - 2;
if (high == 0) return step;
int current = (int)((uint)high >> 1);
while (true) {
if (values[(current + 1) * step] <= target)
low = current + 1;
else
high = current;
if (low == high) return (low + 1) * step;
current = (int)((uint)(low + high) >> 1);
}
}
[img] *just updated this image to fix line numbers, as I added some debug code sorry. should be fine now
https://imgur.com/a/znJAi5z
[/img]

I've managed to find out that it happens when values.Length = 5, and step = 5 (i.e. the same). This makes "high" resolve to -1, which makes current -2147483648 something.

What could be causing step to = 5? Would it be safe to just include:
if (high < 0) return values.Length - 1;
? If I try to return "step", it leads to another OOB error, assuming this is because step is equal to the max length of the animation

I'm on my way home to investigate the animation that's causing the issue, just wondered if there's a chance I could get a bit of insight into why "step" would equal "values.Length", and if it would have something to do with timeScale resuming from 0

edit It seems like step would always = 5 in the ColorTimeline, as it equals "ENTRIES" in Animation.cs
public class ColorTimeline : CurveTimeline, ISlotTimeline {
public const int ENTRIES = 5;
But then why would values.Length = 5 too if this causes "high" to equal -1?

---

I managed to temporarily solve this by editing the problematic animation (more details below)- However, this is not an ideal solution and this still seems like unexpected behaviour and I'm struggling to figure out why this error happens - and it can lead to more problems for me as not all my animations have the last frame keyed as im about to explain:

This is my problematic animation: https://imgur.com/a/KizyHQr
It's very simple, but the last frame doesn't have a color keyed to it. When setting timeScale to 0, waiting for a bit, then resuming timeScale back to 1, this is where the error occurs. I have no idea why.
Keying the last frame prevents this issue. If you would like a copy of the spine file I've emailed it to support form

Please could I have a bit more informaiton on why this may happen and how to prevent it?

---

Further investigation into Animation.cs
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
Slot slot = skeleton.slots.Items[slotIndex];
time is showing as "NaN", not a number, after resuming from pause. I'm checking why this is now

---
/// <summary>
/// Uses <see cref="TrackEntry.TrackTime"/> to compute the animation time between <see cref="TrackEntry.AnimationStart"/>. and
/// <see cref="TrackEntry.AnimationEnd"/>. When the track time is 0, the animation time is equal to the animation start time.
/// </summary>
public float AnimationTime {
get {
if (loop) {
float duration = animationEnd - animationStart;
if (duration == 0) return animationStart;
return (trackTime % duration) + animationStart;
}
return Math.Min(trackTime + animationStart, animationEnd);
}
}
Sources from AnimationTime being "NaN". The animation is looped, so its something in this? Any reason why this may be setting to NaN with just one keyframe on the Color track?

---

Above stems from trackTime being "infinity". animationStart = 0 and animationEnd = 0.3333

---

Above stems from trackTime being set to infinity possibly somewhere in here, although I'm having trouble understanding the code
TrackEntry next = current.next;
if (next != null) {
// When the next entry's delay is passed, change to the next entry, preserving leftover time.
float nextTime = current.trackLast - next.delay;
if (nextTime >= 0) {
next.delay = 0;
next.trackTime = (nextTime / current.timeScale + delta) * next.timeScale;
current.trackTime += currentDelta;
SetCurrent(i, next, true);
while (next.mixingFrom != null) {
next.mixTime += delta;
next = next.mixingFrom;
}
continue;
}
valorware
  • 記事: 12

Nate

Sorry you had to dig into all that! It looks like you are on the right track though. The code you posted doesn't match the latest code:
spine-runtimes/AnimationState.cs at 3.8
Are you setting timeScale to 0? That should be OK, but you should use the latest runtime if possible (please note you must keep your editor/projects and runtime in sync). If you can't use the latest, you could try porting that line.
アバター
Nate

Nate
  • 記事: 9487

valorware

Nate さんが書きました:Sorry you had to dig into all that! It looks like you are on the right track though. The code you posted doesn't match the latest code:
spine-runtimes/AnimationState.cs at 3.8
Are you setting timeScale to 0? That should be OK, but you should use the latest runtime if possible (please note you must keep your editor/projects and runtime in sync). If you can't use the latest, you could try porting that line.
Thanks so much,

Porting that exact line worked great! I'm now running away from 100's of fireballs pausing/unpausing without any errors :)

https://imgur.com/a/xhvtjB5

I can't update to 3.8 for this project, but I will update for next project, thanks so much for the quick solution!
valorware
  • 記事: 12

Nate

Great! :happy: Your game looks interesting!
アバター
Nate

Nate
  • 記事: 9487


Return to Runtimes