From 27f57504459fc903f5eba03962b49e9ffc078753 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Fri, 28 Nov 2025 17:18:04 +0100 Subject: [PATCH] [unity] Fixed UnscaledTime setting being ignored with threaded animation enabled. Closes #2987. --- .../Components/Base/SkeletonAnimationBase.cs | 24 +++++++++++++++-- .../Components/SkeletonAnimation.cs | 7 +++++ .../Threading/SkeletonUpdateSystem.cs | 27 ++++++++----------- spine-unity/Assets/Spine/package.json | 2 +- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Base/SkeletonAnimationBase.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Base/SkeletonAnimationBase.cs index 02a029e10..606769702 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Base/SkeletonAnimationBase.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Base/SkeletonAnimationBase.cs @@ -94,9 +94,22 @@ namespace Spine.Unity { #endif #if USE_THREADED_ANIMATION_UPDATE #region Threaded update system + protected static float externalDeltaTime = 0f; + protected static float unscaledDeltaTime = 0f; + [SerializeField] protected SettingsTriState threadedAnimation = SettingsTriState.UseGlobalSetting; protected bool isUpdatedExternally = false; + public static float ExternalDeltaTime { + get { return externalDeltaTime; } + set { externalDeltaTime = value; } + } + public static float ExternalUnscaledDeltaTime { + get { return unscaledDeltaTime; } + set { unscaledDeltaTime = value; } + } + public virtual float UsedExternalDeltaTime { get { return ExternalDeltaTime; } } + public bool IsUpdatedExternally { get { return isUpdatedExternally; } set { isUpdatedExternally = value; } @@ -381,6 +394,11 @@ namespace Spine.Unity { public virtual void MainThreadAfterUpdateInternal () { } +#if USE_THREADED_ANIMATION_UPDATE + public virtual void UpdateExternal (int currentFrameCount, bool calledFromOnlyMainThread = true) { + UpdateInternal(UsedExternalDeltaTime, currentFrameCount, calledFromOnlyMainThread); + } +#endif public virtual void UpdateInternal (float deltaTime, int currentFrameCount, bool calledFromOnlyMainThread = true) { if (skipUpdate) return; @@ -395,9 +413,10 @@ namespace Spine.Unity { ApplyAnimation(calledFromOnlyMainThread); } +#if USE_THREADED_ANIMATION_UPDATE /// Progresses the AnimationState according to the given deltaTime, and applies it to the Skeleton. /// Use Time.deltaTime to update manually. Use deltaTime 0 to update without progressing the time. - public virtual CoroutineIterator UpdateInternalSplit (CoroutineIterator coroutineIterator, float deltaTime, + public virtual CoroutineIterator UpdateInternalSplit (CoroutineIterator coroutineIterator, int currentFrameCount) { if (coroutineIterator.IsDone) @@ -410,7 +429,7 @@ namespace Spine.Unity { if (skipUpdate) return CoroutineIterator.Done; frameOfLastUpdate = currentFrameCount; - UpdateAnimationStatus(deltaTime); + UpdateAnimationStatus(UsedExternalDeltaTime); skeletonRenderer.ApplyTransformMovementToPhysics(); if (skeletonRenderer.UpdateMode == UpdateMode.OnlyAnimationStatus) @@ -426,6 +445,7 @@ namespace Spine.Unity { return CoroutineIterator.Done; } } +#endif /// Progresses the AnimationState according to the given deltaTime, and applies it to the Skeleton. /// Use Time.deltaTime to update manually. Use deltaTime 0 to update without progressing the time. diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs index 6fd31c597..21c4fdbcc 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs @@ -388,6 +388,13 @@ namespace Spine.Unity { } } +#if USE_THREADED_ANIMATION_UPDATE + public override float UsedExternalDeltaTime { + get { + return unscaledTime ? ExternalUnscaledDeltaTime : ExternalDeltaTime; + } + } +#endif protected override float DeltaTime { get { return unscaledTime ? Time.unscaledDeltaTime : Time.deltaTime; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Threading/SkeletonUpdateSystem.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Threading/SkeletonUpdateSystem.cs index 67196d638..7d45e9d83 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Threading/SkeletonUpdateSystem.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Threading/SkeletonUpdateSystem.cs @@ -125,7 +125,6 @@ namespace Spine.Unity { public int rangeStart; public int rangeEndExclusive; public int frameCount; - public float deltaTime; public UpdateTiming updateTiming; } @@ -306,15 +305,16 @@ namespace Spine.Unity { numExceptionsSet = 0; int rangePerThread = Mathf.CeilToInt((float)skeletons.Count / (float)numThreads); - int skeletonEnd = skeletons.Count; - int endIndexThreaded = Math.Min(skeletonEnd, rangePerThread * numAsyncThreads); + + SkeletonAnimationBase.ExternalDeltaTime = Time.deltaTime; + SkeletonAnimationBase.ExternalUnscaledDeltaTime = Time.unscaledDeltaTime; MainThreadBeforeUpdate(skeletons, skeletonEnd); #if RUN_ALL_ON_MAIN_THREAD for (int r = 0; r < skeletons.Count; ++r) { - skeletons[r].UpdateInternal(Time.deltaTime, Time.frameCount, calledFromOnlyMainThread: true); + skeletons[r].UpdateExternal(Time.frameCount, calledFromOnlyMainThread: true); } #else if (!mainThreadUpdateCallbacks) @@ -338,7 +338,6 @@ namespace Spine.Unity { var range = new SkeletonUpdateRange() { rangeStart = start, rangeEndExclusive = end, - deltaTime = Time.deltaTime, frameCount = Time.frameCount, updateTiming = timing }; @@ -384,7 +383,6 @@ namespace Spine.Unity { var range = new SkeletonUpdateRange() { rangeStart = start, rangeEndExclusive = end, - deltaTime = Time.deltaTime, frameCount = Time.frameCount, updateTiming = timing }; @@ -406,7 +404,6 @@ namespace Spine.Unity { var range = new SkeletonUpdateRange() { rangeStart = start, rangeEndExclusive = end, - deltaTime = Time.deltaTime, frameCount = Time.frameCount, updateTiming = timing }; @@ -426,7 +423,7 @@ namespace Spine.Unity { Thread.MemoryBarrier(); // process main thread callback part - anyWorkLeft = UpdateSkeletonsMainThreadSplit(skeletons, endIndexThreaded, Time.deltaTime, Time.frameCount); + anyWorkLeft = UpdateSkeletonsMainThreadSplit(skeletons, endIndexThreaded, Time.frameCount); isFirstIteration = false; } while (anyWorkLeft && ++timeoutCounter < TimeoutIterationCount); @@ -517,7 +514,6 @@ namespace Spine.Unity { var range = new SkeletonUpdateRange() { rangeStart = start, rangeEndExclusive = end, - deltaTime = Time.deltaTime, frameCount = Time.frameCount, updateTiming = UpdateTiming.InLateUpdate }; @@ -671,7 +667,6 @@ namespace Spine.Unity { #if SPINE_ENABLE_THREAD_PROFILING instance.profilerSamplerUpdate[threadIndex].Begin(); #endif - float deltaTime = range.deltaTime; int frameCount = range.frameCount; int start = range.rangeStart; int end = range.rangeEndExclusive; @@ -681,7 +676,7 @@ namespace Spine.Unity { for (int r = start; r < end; ++r) { try { - skeletonAnimations[r].UpdateInternal(deltaTime, frameCount, calledFromOnlyMainThread: false); + skeletonAnimations[r].UpdateExternal(frameCount, calledFromOnlyMainThread: false); } catch (Exception exc) { instance.DeferredLogException(exc, skeletonAnimations[r], threadIndex); } @@ -713,7 +708,6 @@ namespace Spine.Unity { // avoid allocation, unfortunately this is really necessary static Action cachedUpdateSkeletonsAsyncSplitImpl = UpdateSkeletonsAsyncSplitImpl; static void UpdateSkeletonsAsyncSplitImpl (SkeletonUpdateRange range, int threadIndex) { - float deltaTime = range.deltaTime; int frameCount = range.frameCount; int start = range.rangeStart; int end = range.rangeEndExclusive; @@ -731,7 +725,7 @@ namespace Spine.Unity { try { SkeletonAnimationBase targetSkeletonAnimation = skeletonAnimations[r]; if (!splitUpdateMethod[r].IsDone) { - splitUpdateMethod[r] = targetSkeletonAnimation.UpdateInternalSplit(splitUpdateMethod[r], deltaTime, frameCount); + splitUpdateMethod[r] = targetSkeletonAnimation.UpdateInternalSplit(splitUpdateMethod[r], frameCount); } } catch (Exception exc) { instance.DeferredLogException(exc, skeletonAnimations[r], threadIndex); @@ -745,7 +739,7 @@ namespace Spine.Unity { } bool UpdateSkeletonsMainThreadSplit (List skeletons, int endIndexThreaded, - float deltaTime, int frameCount) { + int frameCount) { bool anyWorkLeft = false; for (int r = 0; r < endIndexThreaded; ++r) { @@ -756,7 +750,7 @@ namespace Spine.Unity { } else { if (!splitUpdateMethod[r].IsDone) { anyWorkLeft = true; - splitUpdateMethod[r] = targetSkeletonAnimation.UpdateInternalSplit(splitUpdateMethod[r], deltaTime, frameCount); + splitUpdateMethod[r] = targetSkeletonAnimation.UpdateInternalSplit(splitUpdateMethod[r], frameCount); } } } catch (Exception exc) { @@ -770,9 +764,10 @@ namespace Spine.Unity { void UpdateSkeletonsSynchronous (List skeletons, SkeletonUpdateRange range) { int start = range.rangeStart; int end = range.rangeEndExclusive; + int frameCount = range.frameCount; for (int r = start; r < end; ++r) { - skeletons[r].UpdateInternal(range.deltaTime, range.frameCount, calledFromOnlyMainThread: true); + skeletons[r].UpdateExternal(frameCount, calledFromOnlyMainThread: true); } } diff --git a/spine-unity/Assets/Spine/package.json b/spine-unity/Assets/Spine/package.json index 45617d57e..476b67143 100644 --- a/spine-unity/Assets/Spine/package.json +++ b/spine-unity/Assets/Spine/package.json @@ -2,7 +2,7 @@ "name": "com.esotericsoftware.spine.spine-unity", "displayName": "spine-unity Runtime", "description": "This plugin provides the spine-unity runtime core and examples. Spine Examples can be installed via the Samples tab.", - "version": "4.3.31", + "version": "4.3.32", "unity": "2018.3", "author": { "name": "Esoteric Software",