From f9f1b32378b33abf8b850e2472908d67b0f9093a Mon Sep 17 00:00:00 2001 From: AGulev Date: Tue, 30 Jan 2024 14:51:37 +0100 Subject: [PATCH] fix callback issue --- defold-spine/src/comp_spine_model.cpp | 43 +++++++++++++++--------- defold-spine/src/comp_spine_model.h | 8 +++-- defold-spine/src/script_spine.cpp | 47 ++++++++++++++++++++++++--- 3 files changed, 75 insertions(+), 23 deletions(-) diff --git a/defold-spine/src/comp_spine_model.cpp b/defold-spine/src/comp_spine_model.cpp index 199ba85..763a9bc 100644 --- a/defold-spine/src/comp_spine_model.cpp +++ b/defold-spine/src/comp_spine_model.cpp @@ -299,10 +299,10 @@ namespace dmSpine static void ClearCompletionCallback(SpineAnimationTrack* track) { - if (track->m_AnimationInstance && track->m_AnimationCallbackRef) + if (track->m_AnimationInstance && track->m_CallbackInfo) { - dmScript::UnrefInInstance(track->m_Context, track->m_AnimationCallbackRef+LUA_NOREF); - track->m_AnimationCallbackRef = 0; + DestroyCallback(track->m_CallbackInfo); + track->m_CallbackInfo = 0x0; } } @@ -358,7 +358,7 @@ namespace dmSpine track.m_AnimationInstance->mixDuration = blend_duration; track.m_AnimationInstance->trackTime = dmMath::Clamp(offset, track.m_AnimationInstance->animationStart, track.m_AnimationInstance->animationEnd); - track.m_AnimationCallbackRef = 0; + track.m_CallbackInfo = 0x0; dmMessage::ResetURL(&track.m_Listener); return true; @@ -418,10 +418,18 @@ namespace dmSpine message.m_Playback = track.m_Playback; message.m_Track = entry->trackIndex + 1; - dmGameObject::Result result = dmGameObject::PostDDF(&message, &sender, &receiver, track.m_AnimationCallbackRef, true); - if (result != dmGameObject::RESULT_OK) + if (track.m_CallbackInfo) { - dmLogError("Could not send animation_done to listener: %d", result); + RunTrackCallback(track.m_CallbackInfo, dmGameSystemDDF::SpineAnimationDone::m_DDFDescriptor, (const char*)&message, &sender, true); + track.m_CallbackInfo = 0x0; + } + else + { + dmGameObject::Result result = dmGameObject::PostDDF(&message, &sender, &receiver, 0, true); + if (result != dmGameObject::RESULT_OK) + { + dmLogError("Could not send animation_done to listener: %d", result); + } } } @@ -456,10 +464,17 @@ namespace dmSpine message.m_Node.m_ContextTableRef = 0; message.m_Track = entry->trackIndex + 1; - dmGameObject::Result result = dmGameObject::PostDDF(&message, &sender, &receiver, track.m_AnimationCallbackRef, false); - if (result != dmGameObject::RESULT_OK) + if (track.m_CallbackInfo) { - dmLogError("Could not send animation event '%s' from animation '%s' to listener: %d", entry->animation->name, event->data->name, result); + RunTrackCallback(track.m_CallbackInfo, dmGameSystemDDF::SpineEvent::m_DDFDescriptor, (const char*)&message, &sender, false); + } + else + { + dmGameObject::Result result = dmGameObject::PostDDF(&message, &sender, &receiver, 0, false); + if (result != dmGameObject::RESULT_OK) + { + dmLogError("Could not send animation event '%s' from animation '%s' to listener: %d", entry->animation->name, event->data->name, result); + } } } @@ -502,10 +517,6 @@ namespace dmSpine { // We only send the event if it's not looping (same behavior as before) SendAnimationDone(component, state, entry, event); - - // The animation has ended, so we won't send any more on this - track.m_AnimationCallbackRef = 0; - track.m_AnimationInstance = nullptr; } if (IsPingPong(track.m_Playback)) @@ -967,7 +978,7 @@ namespace dmSpine component->m_ReHash = 1; } - bool CompSpineModelPlayAnimation(SpineModelComponent* component, dmGameSystemDDF::SpinePlayAnimation* message, dmMessage::URL* sender, int callback_ref, lua_State* L) + bool CompSpineModelPlayAnimation(SpineModelComponent* component, dmGameSystemDDF::SpinePlayAnimation* message, dmMessage::URL* sender, void* callback_info, lua_State* L) { bool result = PlayAnimation(component, message->m_AnimationId, (dmGameObject::Playback)message->m_Playback, message->m_BlendDuration, message->m_Offset, message->m_PlaybackRate, message->m_Track - 1); @@ -976,7 +987,7 @@ namespace dmSpine SpineAnimationTrack& track = component->m_AnimationTracks[message->m_Track - 1]; track.m_Listener = *sender; track.m_Context = L; - track.m_AnimationCallbackRef = callback_ref; + track.m_CallbackInfo = callback_info; } return result; } diff --git a/defold-spine/src/comp_spine_model.h b/defold-spine/src/comp_spine_model.h index dbb76c3..ca466a2 100644 --- a/defold-spine/src/comp_spine_model.h +++ b/defold-spine/src/comp_spine_model.h @@ -44,7 +44,8 @@ namespace dmSpine dmGameObject::Playback m_Playback; dmMessage::URL m_Listener; lua_State* m_Context; - int m_AnimationCallbackRef; + + void* m_CallbackInfo; }; struct IKTarget @@ -82,7 +83,7 @@ namespace dmSpine }; // For scripting - bool CompSpineModelPlayAnimation(SpineModelComponent* component, dmGameSystemDDF::SpinePlayAnimation* message, dmMessage::URL* sender, int callback_ref, lua_State* L); + bool CompSpineModelPlayAnimation(SpineModelComponent* component, dmGameSystemDDF::SpinePlayAnimation* message, dmMessage::URL* sender, void* callback_info, lua_State* L); bool CompSpineModelCancelAnimation(SpineModelComponent* component, dmGameSystemDDF::SpineCancelAnimation* message); bool CompSpineModelSetConstant(SpineModelComponent* component, dmGameSystemDDF::SetConstant* message); @@ -97,6 +98,9 @@ namespace dmSpine bool CompSpineModelGetBone(SpineModelComponent* component, dmhash_t bone_name, dmhash_t* instance_id); + void DestroyCallback(void* callback_data); + void RunTrackCallback(void* callback_data, const dmDDF::Descriptor* desc, const char* data, const dmMessage::URL* sender, bool destroy_after_call); + } #endif // DM_GAMESYS_COMP_SPINE_MODEL_H diff --git a/defold-spine/src/script_spine.cpp b/defold-spine/src/script_spine.cpp index 1218be6..db55255 100644 --- a/defold-spine/src/script_spine.cpp +++ b/defold-spine/src/script_spine.cpp @@ -306,14 +306,12 @@ namespace dmSpine lua_pop(L, 1); } - int functionref = 0; + dmScript::LuaCallbackInfo* cbk = 0x0; if (top > 4) // completed cb { if (lua_isfunction(L, 5)) { - lua_pushvalue(L, 5); - // NOTE: By convention m_FunctionRef is offset by LUA_NOREF, see message.h in dlib - functionref = dmScript::RefInInstance(L) - LUA_NOREF; + cbk = dmScript::CreateCallback(L, 5); } } @@ -327,8 +325,13 @@ namespace dmSpine dmMessage::URL sender; dmScript::GetURL(L, &sender); - if (!CompSpineModelPlayAnimation(component, &msg, &sender, functionref, L)) + if (!CompSpineModelPlayAnimation(component, &msg, &sender, cbk, L)) { + // destroy callback immediately if error happened + if (cbk) + { + dmScript::DestroyCallback(cbk); + } char buffer[128]; dmLogError("Failed to run animation '%s' on component '%s'", lua_tostring(L, 2), dmScript::UrlToString(&receiver, buffer, sizeof(buffer))); } @@ -336,6 +339,40 @@ namespace dmSpine return 0; } + void DestroyCallback(void* callback_data) + { + dmScript::LuaCallbackInfo* cbk = (dmScript::LuaCallbackInfo*)callback_data; + dmScript::DestroyCallback(cbk); + } + + void RunTrackCallback(void* callback_data, const dmDDF::Descriptor* desc, const char* data, const dmMessage::URL* sender, bool destroy_after_call) + { + dmScript::LuaCallbackInfo* cbk = (dmScript::LuaCallbackInfo*)callback_data; + if (!dmScript::IsCallbackValid(cbk)) + { + dmLogError("Spine models callback is invalid."); + return; + } + lua_State* L = dmScript::GetCallbackLuaContext(cbk); + DM_LUA_STACK_CHECK(L, 0); + + if (!dmScript::SetupCallback(cbk)) + { + dmLogError("Failed to setup spine animation callback"); + return; + } + lua_pushstring(L, desc->m_Name); + dmScript::PushDDF(L, desc, data, false); + // dmScript::PushURL(L, sender); // function unavaliable in dmsdk + int ret = dmScript::PCall(L, 3, 0); + (void)ret; + dmScript::TeardownCallback(cbk); + if (destroy_after_call) + { + dmScript::DestroyCallback(cbk); + } + } + /*# cancel all animation on a spine model * Cancels all running animations on a specified spine model component. *