From 69d0474db3a71aaf4aef29872bd8945e55d5fb3e Mon Sep 17 00:00:00 2001 From: bofeng Date: Sun, 27 Apr 2025 11:51:22 +0800 Subject: [PATCH 1/6] Fix spine issues: 1. Callbacks set via setTrackEndListener are not triggered. 2. The setEndListener callback interface cannot retrieve the animation name through the trackEntry parameter. --- .../SkeletonAnimation.cpp | 6 ++- .../spine-wasm/spine-skeleton-instance.cpp | 47 +++++++++++-------- .../spine-wasm/spine-skeleton-instance.h | 2 + 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/native/cocos/editor-support/spine-creator-support/SkeletonAnimation.cpp b/native/cocos/editor-support/spine-creator-support/SkeletonAnimation.cpp index da8da068ea8..a081fdffa4a 100644 --- a/native/cocos/editor-support/spine-creator-support/SkeletonAnimation.cpp +++ b/native/cocos/editor-support/spine-creator-support/SkeletonAnimation.cpp @@ -46,7 +46,11 @@ struct TrackEntryListeners { }; void animationCallback(AnimationState *state, EventType type, TrackEntry *entry, Event *event) { - (static_cast(state->getRendererObject()))->cacheAnimationEvent(entry, type, event); + auto *skeletonAnimation = static_cast(state->getRendererObject()); + skeletonAnimation->cacheAnimationEvent(entry, type, event); + if (type == EventType::EventType_Dispose) { + skeletonAnimation->dispatchEvents(); + } } void trackEntryCallback(AnimationState *state, EventType type, TrackEntry *entry, Event *event) { diff --git a/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp b/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp index b988b50e84b..2681db705bb 100644 --- a/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp +++ b/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp @@ -26,6 +26,14 @@ static void animationCallback(AnimationState *state, EventType type, TrackEntry info.eventType = type; info.event = event; instance->animationEvents.add(info); + + if (type == spine::EventType::EventType_Dispose) { + /** + * In the official implementation of Spine's AnimationState class, the animationCallback is invoked after the trackEntryCallback. + * After the AnimationState completes the EventType_Dispose callback, the TrackEntry will be reclaimed, so this event must be dispatched immediately. + */ + instance->dispatchEvents(); + } } } @@ -37,12 +45,6 @@ static void trackEntryCallback(AnimationState *state, EventType type, TrackEntry info.eventType = type; info.event = event; instance->trackEvents.add(info); - - if (type == EventType_Dispose) { - if (entry->getRendererObject()) { - entry->setRendererObject(nullptr); - } - } } } @@ -135,20 +137,7 @@ void SpineSkeletonInstance::updateAnimation(float dltTime) { _skeleton->update(dltTime); _animState->update(dltTime); _animState->apply(*_skeleton); - //Cache animation events then call back to JS. - auto vecAnimationEvents = animationEvents; - animationEvents.clear(); - //Cache track events then call back to JS. - auto vecTrackEvents = trackEvents; - trackEvents.clear(); - for (int i = 0; i < vecAnimationEvents.size(); i++) { - auto& info = vecAnimationEvents[i]; - onAnimationStateEvent(info.entry, info.eventType, info.event); - } - for (int i = 0; i < vecTrackEvents.size(); i++) { - auto& info = vecTrackEvents[i]; - onTrackEntryEvent(info.entry, info.eventType, info.event); - } + dispatchEvents(); } SpineModel *SpineSkeletonInstance::updateRenderData() { @@ -522,6 +511,7 @@ void SpineSkeletonInstance::onTrackEntryEvent(TrackEntry *entry, EventType type, SpineWasmUtil::s_currentEvent = event; spineTrackListenerCallback(); if (type == EventType_Dispose) { + entry->setRendererObject(nullptr); _trackListenerSet.remove(entry); } } @@ -678,4 +668,21 @@ void SpineSkeletonInstance::setSlotTexture(const spine::String &slotName, const attachmentVertices->_textureUUID = textureUuid; } } +} + +void SpineSkeletonInstance::dispatchEvents() { + //Cache animation events then call back to JS. + auto vecAnimationEvents = animationEvents; + animationEvents.clear(); + //Cache track events then call back to JS. + auto vecTrackEvents = trackEvents; + trackEvents.clear(); + for (int i = 0; i < vecAnimationEvents.size(); i++) { + auto& info = vecAnimationEvents[i]; + onAnimationStateEvent(info.entry, info.eventType, info.event); + } + for (int i = 0; i < vecTrackEvents.size(); i++) { + auto& info = vecTrackEvents[i]; + onTrackEntryEvent(info.entry, info.eventType, info.event); + } } \ No newline at end of file diff --git a/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.h b/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.h index b9182caf84a..05162722f36 100644 --- a/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.h +++ b/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.h @@ -76,6 +76,8 @@ class SpineSkeletonInstance { // Used internal for cache event spine::Vector animationEvents; spine::Vector trackEvents; + // Used internal for dispatch event + void dispatchEvents(); private: void collectMeshData(); From 3d612cbd932fb542fc07cdd377580aa8e7816e5a Mon Sep 17 00:00:00 2001 From: bofeng Date: Sun, 27 Apr 2025 11:55:11 +0800 Subject: [PATCH 2/6] refine --- .../spine-creator-support/SkeletonAnimation.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/native/cocos/editor-support/spine-creator-support/SkeletonAnimation.cpp b/native/cocos/editor-support/spine-creator-support/SkeletonAnimation.cpp index a081fdffa4a..f7da60aef7a 100644 --- a/native/cocos/editor-support/spine-creator-support/SkeletonAnimation.cpp +++ b/native/cocos/editor-support/spine-creator-support/SkeletonAnimation.cpp @@ -49,6 +49,10 @@ void animationCallback(AnimationState *state, EventType type, TrackEntry *entry, auto *skeletonAnimation = static_cast(state->getRendererObject()); skeletonAnimation->cacheAnimationEvent(entry, type, event); if (type == EventType::EventType_Dispose) { + /** + * In the official implementation of Spine's AnimationState class, the animationCallback is invoked after the trackEntryCallback. + * After the AnimationState completes the EventType_Dispose callback, the TrackEntry will be reclaimed, so this event must be dispatched immediately. + */ skeletonAnimation->dispatchEvents(); } } From a79098b5c25ca9b17844dea60749435366dad8a2 Mon Sep 17 00:00:00 2001 From: bofeng Date: Sun, 27 Apr 2025 15:02:34 +0800 Subject: [PATCH 3/6] refine --- .../spine-wasm/spine-skeleton-instance.cpp | 18 ++++++++++++------ .../editor-support/spine/3.8/spine/Vector.h | 13 +++++++++---- .../editor-support/spine/4.2/spine/Vector.h | 11 +++++++++-- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp b/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp index 2681db705bb..a5923cd8040 100644 --- a/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp +++ b/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp @@ -671,12 +671,18 @@ void SpineSkeletonInstance::setSlotTexture(const spine::String &slotName, const } void SpineSkeletonInstance::dispatchEvents() { - //Cache animation events then call back to JS. - auto vecAnimationEvents = animationEvents; - animationEvents.clear(); - //Cache track events then call back to JS. - auto vecTrackEvents = trackEvents; - trackEvents.clear(); + spine::Vector vecAnimationEvents; + spine::Vector vecTrackEvents; + if (animationEvents.size() > 0) { + //Cache animation events then call back to JS. + vecAnimationEvents.addAll(animationEvents); + animationEvents.clear(); + } + if (trackEvents.size() > 0) { + //Cache track events then call back to JS. + vecTrackEvents.addAll(trackEvents); + trackEvents.clear(); + } for (int i = 0; i < vecAnimationEvents.size(); i++) { auto& info = vecAnimationEvents[i]; onAnimationStateEvent(info.entry, info.eventType, info.event); diff --git a/native/cocos/editor-support/spine/3.8/spine/Vector.h b/native/cocos/editor-support/spine/3.8/spine/Vector.h index 5782a7937bc..5f485d2260c 100644 --- a/native/cocos/editor-support/spine/3.8/spine/Vector.h +++ b/native/cocos/editor-support/spine/3.8/spine/Vector.h @@ -117,14 +117,14 @@ class SP_API Vector : public SpineObject { } } - void addAll(Vector &inValue) { + void addAll(const Vector &inValue) { ensureCapacity(this->size() + inValue.size()); for (size_t i = 0; i < inValue.size(); i++) { add(inValue[i]); } } - void clearAndAddAll(Vector &inValue) { + void clearAndAddAll(const Vector &inValue) { this->clear(); this->addAll(inValue); } @@ -199,6 +199,13 @@ class SP_API Vector : public SpineObject { return _buffer; } + Vector &operator=(const Vector &inVector) { + if (this != &inVector) { + clearAndAddAll(inVector); + } + return *this; + } + private: size_t _size; size_t _capacity; @@ -227,8 +234,6 @@ class SP_API Vector : public SpineObject { inline void destroy(T *buffer) { buffer->~T(); } - - // Vector &operator=(const Vector &inVector) {}; }; } // namespace spine diff --git a/native/cocos/editor-support/spine/4.2/spine/Vector.h b/native/cocos/editor-support/spine/4.2/spine/Vector.h index 41a246c13fb..ae596e3cd19 100644 --- a/native/cocos/editor-support/spine/4.2/spine/Vector.h +++ b/native/cocos/editor-support/spine/4.2/spine/Vector.h @@ -116,14 +116,14 @@ namespace spine { } } - inline void addAll(Vector &inValue) { + inline void addAll(const Vector &inValue) { ensureCapacity(this->size() + inValue.size()); for (size_t i = 0; i < inValue.size(); i++) { add(inValue[i]); } } - inline void clearAndAddAll(Vector &inValue) { + inline void clearAndAddAll(const Vector &inValue) { this->clear(); this->addAll(inValue); } @@ -194,6 +194,13 @@ namespace spine { return !(lhs == rhs); } + Vector &operator=(const Vector &inVector) { + if (this != &inVector) { + clearAndAddAll(inVector); + } + return *this; + } + inline T *buffer() { return _buffer; } From 8d9f1a528961262ba836d2fba61094e9319ab346 Mon Sep 17 00:00:00 2001 From: bofeng Date: Mon, 28 Apr 2025 08:59:31 +0800 Subject: [PATCH 4/6] update external version --- native/external-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/external-config.json b/native/external-config.json index 72d3e9f3142..6e79a8b75a5 100644 --- a/native/external-config.json +++ b/native/external-config.json @@ -3,6 +3,6 @@ "type": "github", "owner": "cocos", "name": "cocos-engine-external", - "checkout": "v3.8.7-7" + "checkout": "v3.8.7-8" } } \ No newline at end of file From d4409944484dec8025338b063f7ab62cf2c581cb Mon Sep 17 00:00:00 2001 From: bofeng Date: Mon, 28 Apr 2025 11:27:14 +0800 Subject: [PATCH 5/6] refine --- native/cocos/editor-support/spine/4.2/spine/Vector.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/native/cocos/editor-support/spine/4.2/spine/Vector.h b/native/cocos/editor-support/spine/4.2/spine/Vector.h index ae596e3cd19..ffa356bea2b 100644 --- a/native/cocos/editor-support/spine/4.2/spine/Vector.h +++ b/native/cocos/editor-support/spine/4.2/spine/Vector.h @@ -116,14 +116,14 @@ namespace spine { } } - inline void addAll(const Vector &inValue) { + void addAll(const Vector &inValue) { ensureCapacity(this->size() + inValue.size()); for (size_t i = 0; i < inValue.size(); i++) { add(inValue[i]); } } - inline void clearAndAddAll(const Vector &inValue) { + void clearAndAddAll(const Vector &inValue) { this->clear(); this->addAll(inValue); } @@ -233,8 +233,6 @@ namespace spine { inline void destroy(T *buffer) { buffer->~T(); } - - // Vector &operator=(const Vector &inVector) {}; }; } From 0e68569b709f9572714f962e9ecc50c1ed9f7a78 Mon Sep 17 00:00:00 2001 From: bofeng Date: Mon, 28 Apr 2025 11:50:01 +0800 Subject: [PATCH 6/6] update external version --- native/external-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/external-config.json b/native/external-config.json index 6e79a8b75a5..1ea1afa19ea 100644 --- a/native/external-config.json +++ b/native/external-config.json @@ -3,6 +3,6 @@ "type": "github", "owner": "cocos", "name": "cocos-engine-external", - "checkout": "v3.8.7-8" + "checkout": "v3.8.7-9" } } \ No newline at end of file