MarvinECL

Hi there, the SpineWidget in my project now have this crash report:

uEntry = (UTrackEntry *)0x000001c350f44fc0(Name=Illegal name(block index outof range)_2130739455)

And because the NAME is out of the range, the AnimationComplete broadcast is failed, and thus cause the ue4 crash.

I found a similar UE4 crash in the forum: http://zh.esotericsoftware.com/forum/UE4-CRASH-I-want-to-solve-the-problem-16805
So I update my 4.0 SpinePlugin to the latest: directly download github source code today (2022.Feb.12)
But this bug STILL exists.

I will post my UE4 blueprint of the widget below, but since my project don't have much development time left, I want to know one thing first:
Would this bug only effect the animation broadcast of the SpineWidget, or this bug would effect all types of animation broadcast (including spine skeleton component)?

---

Here is my SpineWidget blueprint:
MyWidgetBlueprint.jpg


---

Hi there, today I add one line code after the uEntry instance is generated (basically just let UE4 to print the uEntry name on the screen):
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, uEntry->UObject::GetName());
And I start my project, let the SpineWidget play the animation.

At first, the uEntry name is printed normally, one example is "Trackentry_2147482509", and the project didn' crash.
But after a few seconds, the name of the uEntry turned into "None", and the Windows system just crash. Windows error is "DPC_WATCHDOG_VIOLATION".

I have two assumptions about this situation:
1. The pointer is garbage collected by something, maybe is by UE4. But I don't know which pointer is garbage collected.
2. The process of "void *pointer cast to UTrackEntry *pointer" is not stable, will cause memory access violation.

I will keep post my debug process here.
Nemaš dopuštenje za pregledavanje privit(a)ka dodan(og)ih postu.
MarvinECL
  • Postovi: 8

Mario

I'm afraid I can't reproduce this just based on your blueprint. Could you please send me a small, self-contained UE4 project that reproduces the issue?
Avatar
Mario

Mario
  • Postovi: 3242

MarvinECL

Hi Mario, thanks for the advice. But I have a good news and a bad news here.

The good news is, after I create a new project trying to reproduce the problem, the editor and the game doesn't crash this time. The new project basically just contain one UE4 UserWidget blueprint, and the UI struct is the same as my project.

The bad news is, after I deep analysis my project, I found that the "SetAnimation" blueprint node and the "SetSkin" blueprint node of the problem spine widget is not link to the default UE4 Event Construct (or Event Pre Construct) of this problem Userwidget. I remebered that this is bucause I need to ensure my custom initial process only be excuted once.

So in conclution, I think the problem is 99% because I didn't link the "SetAnimation" blueprint and the "SetSkin" blueprint to the default UE4 Event Construct. The problem turns to be: if the UE4 Event Construct of a UE4 UserWidget is empty and be called by something else, the process of create uEntry from
(UTrackEntry *)entry->getRendererObject()
will cause UObject name is None.

So I have a question here: Is the "SetAnimation" blueprint and the "SetSkin" blueprint of a spine widget has to be linked to UE4 Event Construct? This is the official suggested way to use SpineWidget but is there a way to replace it?

==============================

Sorry I posted too impatient today, this evening I will try to create a project to reproduce the things I mentioned above.
MarvinECL
  • Postovi: 8

Mario

No, the SetAnimation and SetSkin node can be called from anywhere unless the widget hasn't been created yet or has been disposed. I'd appreciate a repro sample, as I can't find the underlying issue without it.
Avatar
Mario

Mario
  • Postovi: 3242

MarvinECL

OK I understand, I'm still working on to reproduce the problem in a new project.

---

Hi there, sorry I didn't repost for a long time. The main reason is that I cannot reproduce the problem in a new project, and I cannot upload the origin project since it is a business project.

But today this project produced the same error appearance because of another code error. Also 0xffffffff, also dpc_watchdog_violation Windows error. And this new error is because of a pointer is garbage collected by UE4. So maybe this info cannot help to fix the bug, but I want to post it here in case someone meet the same problem as I am.
MarvinECL
  • Postovi: 8

Mario

Do you have any info what type of pointer is being garbage collected?
Avatar
Mario

Mario
  • Postovi: 3242

Pearson

I guess its happening when i change animation (SetAnimation) in Tick function. This bug happens regularly but not often.
Nemaš dopuštenje za pregledavanje privit(a)ka dodan(og)ih postu.
Pearson
  • Postovi: 4

Mario

Are you holding on to the UTrackEntry somewhere in your code or blueprints? I can see the foo bar objects, but it's impossible to tell without a repro why they turn foo bar.
Avatar
Mario

Mario
  • Postovi: 3242

Pearson

I don't use UTrackEntry anywhere.

I change two animation in TickFunction. If distance is zero then stand anaimtaion else walk animation.
SpineAnimation->SetAnimation(0, FString("stand"), false);
SpineAnimation->SetAnimation(0, FString("walk"), true);
Pearson
  • Postovi: 4

Mario

In that case the runtime still has to create track entries internally. I need a small project that reliably reproduces the issue to fix this. It is likely related to how you create and destroy spine components in your map/blueprints.
Avatar
Mario

Mario
  • Postovi: 3242

MarvinECL

Hi Mario, MarvinECL here, sorry for not repost for solong since I can't find which pointer is nullptr.

But today when I use "SetTrackTime" Node, the same problem turns out and I think I find the glitch one.

My project is doing "Voice linked Mouth", that character's mouth can open and close accroding to voice loud. And this funtion is, I read current voice data and use "SetTrackTime" to set the individual mouth track to a certain track time.

Everything is fine at the start, but when I change the mouth by reset the individual mouth track anime, the track entry becomes nullptr. I made a test blueprint to describe this problem.

TrackEntryNullPtr.png


There is three events in the test blueprint. When I execute Z EVENT for the target spine, everything is fine, C EVENT tells me that the track entry of track two is ok. But when I use X EVENT to set new animation at track two (change mouth), the C EVENT tells me that the track entry of track two is nullptr.

I don't save the track entry as a variable, and I even don't know whether this nullptr is the same problem of my topic. But I think I need to post this problem here asking for help -- how do I make the "Voice linked Mouth" function since the track entry would be nullptr :'(

---

And for the topic problem, now I modify the broadcast code of the anime state - bind broadcast on SkeletonAnimationComponent instead of on uEntry instance:
void callback(AnimationState *state, spine::EventType type, TrackEntry *entry, Event *event) {
USpineSkeletonAnimationComponent *component = (USpineSkeletonAnimationComponent *) state->getRendererObject();
int TrackIndex = entry->getTrackIndex();
if (entry->getRendererObject()) {
if (type == EventType_Start) {
component->AnimationStart.Broadcast(TrackIndex);
} else if (type == EventType_Interrupt) {
component->AnimationInterrupt.Broadcast(TrackIndex);
} else if (type == EventType_Event) {
FSpineEvent evt;
evt.SetEvent(event);
component->AnimationEvent.Broadcast(TrackIndex, evt);
} else if (type == EventType_Complete) {
component->AnimationComplete.Broadcast(TrackIndex);
} else if (type == EventType_End) {
component->AnimationEnd.Broadcast(TrackIndex);
} else if (type == EventType_Dispose) {
component->AnimationDispose.Broadcast(TrackIndex);
component->GetCurrent(TrackIndex)->SetTrackEntry(nullptr);
component->GCTrackEntry(component->GetCurrent(TrackIndex));
}
}
}
Nemaš dopuštenje za pregledavanje privit(a)ka dodan(og)ih postu.
MarvinECL
  • Postovi: 8

Mario

While that is a solution, it functions differently. The SetAnimation and AddAnimation nodes return a TrackEntry in the unmodified spine-ue4 runtime. This allows you to listen to that specific track entry you added. If you broadcast via the SpineSkeletonAnimationComponent instead, you lose the ability to easily differentiate between the track entries you queued up. I do not understand how the UTrackEntry can be garbage collected at all in the original sources. Every time you set or add an animation, a UTrackEntry is created and added to a set on the SpineAnimationComponent:
https://github.com/EsotericSoftware/spine-runtimes/blob/4.0/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp#L219

That set is marked as a UPROPERTY which means itself and its entries will not get garbage collected until the SpineSkeletonAnimationComponent is garbage collected:
https://github.com/EsotericSoftware/spine-runtimes/blob/4.0/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonAnimationComponent.h#L311

This is absolutely puzzling, and since I can not reproduce it, I can not understand why it happens regardless. If you can boil your example down to something I can actually run here, I can give it another try.
Avatar
Mario

Mario
  • Postovi: 3242

MarvinECL

Good news, I reproduce the "Track Two Entry Invalid after I SetAnimation on Track Two" problem in a new project.

Here is the link: https://drive.google.com/file/d/1sCpNMuBNVrHF_xgp2rjdwUEIWL19gqKz/view?usp=sharing

Run the project in editor, and press keyboard Z,X,C to see the problem. The event is in level blueprint.

But I think this package can only show you why the track entry would be nullptr at sometimes. I guess it is caused by UE4 GC but I don't have any proof.

---

Hi there, today when I check my project at editor runtime, the SpineSkeletonRenderComponent generate more than 40 Material Instance when I check its details. I hope this infomation would be help on this problem.

---

Today I talked with our animator and I found that they used a third-party texture packer instead of spine build-in texture packer. I cheked the output png difference and I think the "too many texture instance problem" is caused by this third-party texture packer.
MarvinECL
  • Postovi: 8

Mario

Hm, I can't speak for the material issues. The rendering component needs to create a new material everytime a texture changes. I don't know how the third party packer works, but it may be the culprit.

Thank you for the repro! I'll try to fix this asap!
Avatar
Mario

Mario
  • Postovi: 3242

Pearson

I guess I solved this bug. I had big memory leaks. When the delegate was called, it ran out of memory. Because the delegate tries to allocate memory.
Pearson
  • Postovi: 4

Mario

You are refering to the GC issue or the texture packer issue?
Avatar
Mario

Mario
  • Postovi: 3242

MarvinECL

Don't mind the texture packer issue (sorry I confused the problem solving), I have fixed that (by pack all spine part in one png file), and after I fixed that the "Track Two Entry Invalid after I SetAnimation on Track Two" problem still exist.

Just let this page focus on the empty track problem.
MarvinECL
  • Postovi: 8

Mario

Finally found time to look into your sample project. I can't get it to crash at all in both UE4 and UE5 :/ I'm seriously puzzled how it can crash.

Capture.PNG
Nemaš dopuštenje za pregledavanje privit(a)ka dodan(og)ih postu.
Avatar
Mario

Mario
  • Postovi: 3242

MarvinECL

OK let me explain what problem I found with uEntry instance:

Spine Runtime version: github 2022.Feb.12 version

1. The Broadcast function of the anime state may cause the whole project crash. And it is an nullptr problem. But this problem I cannot reproduce in a new project. Currently I rewrite the callback function work for anime state and let the SpineSkeletonAnimationComponent do the broadcast. This alternative implement can let the project not crash but not solve the nullptr problem.

2. I find out that the return uEntry of setAnimation function could be nullptr when I set a new mouth for the spine (which I can reproduce it in a new project and sent it to you), and even if it is valid I still cannot use setTrackTime function to control the mouth open and close (which I find out a few days ago and not included in the project). I think this new problem is related to uEntry instance so I posted it here instead of open a new topic.

And Mario did you checked the level blueprint of the examble project? The pic you posted looks like you just randomly press the ZXC button.

---

Steps to Reproduce:
1. Launch game in ue4 editor
2. Press keyboard Z to initialize the spine
3. Press keyboard C to check the uEntry valid (using isValidAnimation function), the result is true
4. Press keyboard X to change mouth for the spine (using setAnimation function)
5. Press keyboard C to check the uEntry valid (using isValidAnimation function), the result is false

---

Basically the project I uploaded doesn't reproduce the topic problem, but may help you find the problem of uEntry. I think the two problem is both caused by uEntry.
MarvinECL
  • Postovi: 8

Mario

Ah, you didn't specify the order in which I have to press the keys in the last post, nor what the expected output is. I'll try with your new instructions.
Avatar
Mario

Mario
  • Postovi: 3242

Mario

You modified SpineSkeletonAnimationComponent, namely the callback() function, or you are using an oudated spine-ue4 version from the 4.0 branch. This is what lines 65-67 should look like:
uEntry->AnimationDispose.Broadcast(uEntry);
uEntry->SetTrackEntry(nullptr);
component->GCTrackEntry(uEntry);
You are calling component->GetCurrent() instead, which is wrong, and causes the output after pressing C to print false.

I don't know if you only changed that in the repro project you or in your crashing full project as well. Please change it back to what it was and try if you can repro the crash in your big project.
Avatar
Mario

Mario
  • Postovi: 3242

MarvinECL

OK I will try that right now

---

Now I change the code to this:
void callback(AnimationState *state, spine::EventType type, TrackEntry *entry, Event *event)
{
USpineSkeletonAnimationComponent *component = (USpineSkeletonAnimationComponent *) state->getRendererObject();
int TrackIndex = entry->getTrackIndex();
if (entry->getRendererObject())
{
UTrackEntry *uEntry = (UTrackEntry *) entry->getRendererObject();
......
else if (type == EventType_Dispose)
{
component->AnimationDispose.Broadcast(TrackIndex);
uEntry->SetTrackEntry(nullptr);
component->GCTrackEntry(uEntry);
}
}
}
And this did solve the problem Two: "Track Two Entry Invalid after I SetAnimation on Track Two"

I still won't let the uEntry do the broadcast. Current this version should work for my project (althogh the problem One is not located). Thanks for the help!!

---

Today I find our project DID NOT Add SpinePlugin to our Build.cs file. Thus I think "Name Out Of Range" problem is most likely a performance issue. So if the whole game is eating too much memory, or generating too much cache while looping, or has memory leaking, this problem occurs.
Sorry for reporting this, and thanks for your patience!
MarvinECL
  • Postovi: 8


Natrag na Bugs