一次动作的AnimNotifyState在服务器触发多次

一次动作的AnimNotifyState在客户端触发一次(正确),但是在服务器触发多次(错误),

使用UE5.6版本引擎(Epic launch下载,未修改),操作步骤:

1、新建AnimNotifyState​: NS_Test

2、在NS_Test中添加开始和结束的调试信息(见附图)

3、在AnimationSequence中添加AnimNotifyState:NS_Test(见附图)

4、通过Play As Client的方式启动游戏,发现日志中Server上AnimNotifyState触发多次。(见附图)

重现步骤
使用UE5.6版本引擎(Epic launch下载,未修改),操作步骤:

1、新建AnimNotifyState​: NS_Test

2、在NS_Test中添加开始和结束的调试信息(见附图)

3、在AnimationSequence中添加AnimNotifyState:NS_Test(见附图)

4、通过Play As Client的方式启动游戏,发现日志中Server上AnimNotifyState触发多次。(见附图)

Hi, sorry for the delay in following up on this issue. We’ve been out for the last couple of weeks on break, so I’m just in the process of catching up.

I attempted to get a repro of the issue you described following the steps that you included, but I wasn’t able to reproduce the issue. I’ve attached a video showing the setup that I’m testing with. With this setup, I only see the notify being triggered once for the client and once for the server (although the order is different, but that seems to be a separate issue). Can you let me know if you are doing anything different in your setup to reproduce the bug?

我们重新录制的视频,希望能有帮助!​[Image Removed]

Hi, thanks for providing the video. We were able to get a repro based on that. I didn’t see it previously because I didn’t have a player controller attached to the character blueprint I was testing with. And that’s required for UCharacterMovementComponent::MoveAutonomous to be called which is where the bug occurs. We recently made some changes to how the notify queue is dealt with in that function when the anim instance is being updated on the server. The problem CL is 40476005. That added a call to UAnimInstance::ClearQueuedAnimEvents which is causing the state notifies to be repeatedly removed and then re-added to the notify buffer which causes the state begin/end events to be triggered.

We’re looking at what we can do to fix this at the moment. I’ll follow up once I have more information.

Hi, I wanted to update you on this issue and give you a potential workaround to try.

We’ve spent more time investigating the issue and see that it wasn’t actually introduced by the change in CL 40476005. It has been around for some time (it also affects the 5.5 release).

As I mentioned, the problem is caused by UCharacterMovementComponent::MoveAutonomous. This ticks the anim instance via USkeletalMeshComponent::TickPose. The intention with this code in MoveAutonomous is to be able to replay CMC moves when there is a network correction. This can involve replaying Montages, which is why MoveAutonomous calls USkeletalMeshComponent::TickPose. When a move is replayed, the montage should be replayed, and notifies within the montage retriggered.

However, the bug is caused by the fact that UCharacterMovementComponent::MoveAutonomous doesn’t perform a full update and evaluate of the anim instance. The code was written with the assumption that the anim instance was only being updated for montages (ie. OnlyTickMontagesWhenNotRendered) and not a full graph update (ie. AlwaysTickPose). Because it doesn’t perform a full graph update, notifies that are generated from anim players don’t get sampled during the call from MoveAutonomous. That means, in your use case, the state notify isn’t sampled when MoveAutonomous is called. But it is sampled later in the frame when the regular animation update happens via USkeletalMeshComponent::TickComponent. So we end up in a situation where at one point in the frame UAnimInstance::ActiveAnimNotifyState contains the state notify and at other points in the frame it doesn’t. Because of this, when UCharacterMovementComponent::MoveAutonomous calls USkeletalMeshComponent::ConditionallyDispatchQueuedAnimEvents the state notify is not present, so we treat that as the state notify having completed. When later in the frame ConditionallyDispatchQueuedAnimEvents is called again from USkeletalMeshComponent::TickComponent and the state notify is now present, so we treat the notify has having started again. This is why you see the start/end events being triggered each frame.

I’ve attached a patch with a potential workaround. It copies UAnimInstance::ActiveAnimNotifyState before MoveAutonomous updates the anim instance, and reapplies it after the notifies have been dispatched. Between copying and re-applying, it also strips out any non-montage notifies from the anim instances ActiveAnimNotifyState buffer since MoveAutonomous only cares about notifies from montages.

Would you be able to try this patch and see if it works around the problem for you?

The other option to fix this issue would be to have UCharacterMovementComponent::MoveAutonomous perform a full graph update to sample notifies from both the anim sequence players and also from montages. But performing a full graph update like this - on the game thread - potentially many times in a frame, could have a significant impact on performance, so I would rather avoid making that change.

你好!我们测试了你给的补丁包,是可以解决我们问题的。我们先临时使用这个补丁包,期待ue5的更新,谢谢。

Thanks for confirming that’s resolved the issue. I’ve also created a JIRA to track this issue that the dev team are going to look at this further, along with the workaround I provided you. I can’t guarantee that this will be resolved in the next release but I have asked the dev team to escalate it since you’re not the only licensee that has been affected by this bug.

I’ll close out this thread for now but feel free to reopen it if you have further questions.