Thank you for the information regarding the target version for the fix.
As we have some concerns about the release timing of UE5.8.4, we would like to consider a workaround in the meantime.
(1)
We are considering reverting the timing at which Notify dispatch is executed in CharacterMovementComponent.cpp
back to the behavior of UCharacterMovementComponent::MoveAutonomous in UE5.7.4.
This would reintroduce the UE-308913 issue, but fortunately we do not use a dedicated server, and we did not observe that issue in UE5.7.4.
(2)
As an alternative, we are also considering replacing the critical Notifies with Branching Points.
This would be a fallback option in case approach (1) turns out to be difficult due to requiring too many changes to the Engine. Since it would require inspecting a large amount of data and may also have some performance impact, we would prefer to pursue approach (1) first.
Regarding approach (1), could you please confirm whether this kind of modification is appropriate?
Also, if there is any better workaround, we would greatly appreciate your guidance.
Note: We tried the following code.
CharacterMovementComponent.cpp
■
void UCharacterMovementComponent::MoveAutonomous - Restore the dispatch processing
(around Line ~10714)
// If not playing root motion, tick animations after physics. We do this here to keep events, notifies, states and transitions in sync with client updates.
if (CharacterOwner && !CharacterOwner->bClientUpdating && !CharacterOwner->IsPlayingRootMotion() && CharacterOwner->GetMesh())
{
if (!bWasPlayingRootMotion) // If we were playing root motion before PerformMovement but aren't anymore, we're on the last frame of anim root motion and have already ticked character
{
TickCharacterPose(DeltaTime);
}
// TODO: SaveBaseLocation() in case tick moves us?
USkeletalMeshComponent* OwnerMesh = CharacterOwner->GetMesh();
check(OwnerMesh != nullptr)
#if 1 // [START : Revert AnimNotify dispatch timing to UE5.7.4 behavior]
if (CharacterMovementCVars::EnableQueuedAnimEventsOnServer)
{
if (UAnimInstance* AnimInstance = OwnerMesh->GetAnimInstance())
{
if (OwnerMesh->VisibilityBasedAnimTickOption <= EVisibilityBasedAnimTickOption::AlwaysTickPose && AnimInstance->NeedsUpdate())
{
// If we are doing a full graph update on the server but its doing a parallel update,
// trigger events right away since these are notifies queued from the montage update, and we could be receiving multiple ServerMoves per frame.
OwnerMesh->ConditionallyDispatchQueuedAnimEvents();
// We need to manually clear the anim notify queue (since normally its only is cleared in PreUpdateAnimation()) otherwise if animation ticks, the notifies queued from the ServerMove would fire twice.
AnimInstance->ClearQueuedAnimEvents(false);
// When animation ticks, we want its queued events to be triggered.
OwnerMesh->AllowQueuedAnimEventsNextDispatch();
}
}
}
else
#else // [END : Revert AnimNotify dispatch timing to UE5.7.4 behavior]
// Fallback to old behaviour if needed. Otherwise, event are dispatched in TickCharacterPose().
if (!CharacterMovementCVars::EnableQueuedAnimEventsOnServer)
#endif
{
// Revert back to old behavior if wanted/needed.
if (OwnerMesh->ShouldOnlyTickMontages(DeltaTime) || OwnerMesh->ShouldOnlyTickMontagesAndRefreshBones(DeltaTime))
■
TickCharacterPose() - Disabled the dispatch processing added in 5.8
(around Line ~12107)
#if 0 // [START : Revert AnimNotify dispatch timing to UE5.7.4 behavior]
// We need to dispatch any queued events, since these can affect the next move request, after we ticked the character pose.
if (CharacterMovementCVars::EnableQueuedAnimEventsOnServer)
{
UAnimInstance* AnimInstance = CharacterMesh->GetAnimInstance();
UAnimInstance* PostProcessAnimInstance = CharacterMesh->GetPostProcessInstance();
if (AnimInstance || PostProcessAnimInstance)
{
const bool bIsAnimGraphUpdateEnabled = CharacterMesh->VisibilityBasedAnimTickOption <= EVisibilityBasedAnimTickOption::AlwaysTickPose;
const bool bIsMainAnimGraphUpdatePending = AnimInstance ? AnimInstance->NeedsUpdate() : false;
const bool bIsPostProcessAnimGraphUpdatePending = PostProcessAnimInstance ? PostProcessAnimInstance->NeedsUpdate() : false;
const bool bIsAnimGraphUpdatePending = bIsMainAnimGraphUpdatePending || bIsPostProcessAnimGraphUpdatePending;
if (bIsAnimGraphUpdateEnabled && bIsAnimGraphUpdatePending)
{
// If we are doing a full graph update on the server but its doing a parallel update,
// trigger events right away since these are notifies queued from the montage update, and we could be receiving multiple ServerMoves per frame.
CharacterMesh->ConditionallyDispatchQueuedAnimEvents();
// We need to manually clear the anim notify queue (since normally its only is cleared in PreUpdateAnimation()) otherwise if animation ticks, the notifies queued from the ServerMove would fire twice.
CharacterMesh->ForEachAnimInstance([](UAnimInstance* InAnimInstance)
{
check(InAnimInstance);
InAnimInstance->ClearQueuedAnimEvents(false);
});
// When animation ticks, we want its queued events to be triggered.
CharacterMesh->AllowQueuedAnimEventsNextDispatch();
}
}
}
#endif // [END : Revert AnimNotify dispatch timing to UE5.7.4 behavior]
Thank you very much for your support.
---
修正の対象バージョンの情報など、ありがとうございます。
UE5.8.4 の対応時期などに不安があり、ワークアラウンドを検討したいと思っております。
(1)
CharacterMovementComponent.cpp の Notify の Dispatch 実行タイミングを、
UE5.7.4 の UCharacterMovementComponent::MoveAutonomous に戻すことにより対応できないか考えております。
UE-308913 の不具合は戻ってしまいますが、幸い Dedicated Server は未使用で、UE5.7.4 では当該不具合を認識しておりませんでした。
(2)
もう一つの案として、重要な Notify を Branching Point に置き換えることも検討しています。
こちらは (1) の対応で Engine への変更が多くなり対応が難しそうな場合の代替案です。
多くのデータの検査が必要で、パフォーマンスへの影響も多少ありそうなため、まずは (1) を検討したいと考えております。
(1) の対応に関して、このような修正が適切か、ご確認いただけませんでしょうか?
また、他によいワークアラウンドがありましたら、ご教示いただければと思います。
以上、よろしくお願いいたします。
[Attachment Removed]