Hey guys, I think I might not understand well how AnimNotifyState work in multiplayer, so here is my problem.
First of all, I have an anim montage which is triggered by a player input. When the input is pressed, I launch an rpc to the server, then multicast the animation montage.
Now here is how I coded the thing:
I have an anim notify state, where I set a TWeakObjectPtr to the MeshComp anim instance, then I run a function in my casted anim instance.
void UNotifyState_CaptureWallCollision::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
float TotalDuration, const FAnimNotifyEventReference& EventReference)
{
Super::NotifyBegin(MeshComp, Animation, TotalDuration, EventReference);
ZoghAnimInstance = Cast<UZoghThirdPersonAnimInstance>(MeshComp->GetAnimInstance());
}
void UNotifyState_CaptureWallCollision::NotifyTick(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
float FrameDeltaTime, const FAnimNotifyEventReference& EventReference)
{
Super::NotifyTick(MeshComp, Animation, FrameDeltaTime, EventReference);
if (ZoghAnimInstance.IsValid())
{
ZoghAnimInstance->Notify_CaptureWallCollisionTick();
}
}
In this Anim Instance here is what my Notify function look like
void UZoghThirdPersonAnimInstance::Notify_CaptureWallCollisionTick()
{
if (!WolfCharacter)
{
UE_LOG(LogZoghAnimInstance, Error, TEXT("Could not tick in Wall Collision notify: WolfCharacter is null!"))
return;
}
UCaptureHandlerComponent* CaptureHandler = WolfCharacter->GetCaptureHandler();
if (!CaptureHandler)
{
UE_LOG(LogZoghAnimInstance, Error, TEXT("Could not tick in Wall Collision notify: Capture Handler is null!"))
return;
}
CaptureHandler->CheckWallCollision(GetSkelMeshComponent());
}
It then calls a function in my CaptureHandlerComponent which is an actor component, that is created in my character constructor (it is not replicated).
In this component I made some functions to create sphere collisions at the hands of my player. I would like to trigger this particular function below, on both Client and Server (Client side would be to debug only), then by controlling with the GetOwner()->HasAuthority, make some gameplay logic if my player hit a wall.
void UCaptureHandlerComponent::CheckWallCollision(USkeletalMeshComponent* MeshComp)
{
if (!bShouldCheckCollision || !MeshComp) return;
FHitResult HitResult;
TArray<ECollisionChannel> CollisionChannels = { ECC_WorldStatic };
bHasHitWall = CheckCollisionAtHands(MeshComp, SphereWallDetectionRadius, CollisionChannels, bDebugWallSphereCollision, HitResult);
bShouldCheckCollision = !bHasHitWall;
AActor* Owner = GetOwner();
if (!Owner)
{
UE_LOG(LogCaptureHandlerComponent, Error, TEXT("Check Player Collision: Owner was null!"));
return;
}
if (!Owner->HasAuthority()) return;
if (bHasHitWall)
{
AddImpulseOnPlayer(HitResult);
}
}
So now let’s dive into what happens in game. When I trigger my anim montage, it is replicated correctly and every player sees it.
But for the AnimNotifyState, it seems to only trigger whether on the server or the client, but never on both. That is where I am starting to lose it.
This is what the client sees (Spheres are blue because I added a debug to have blue spheres client side and red server side):
And what the server sees:
I decided to put some log to see what was happening. You can see on the first frame of the notify, everything goes as intended with the server, then it starts to break. Sometimes, the AnimNotifyState logs SERVER, but everything else is CLIENT side.
LogCaptureWallNotify: [SERVER] Capture Wall Collision Notify Tick!
LogZoghAnimInstance: Capture Owner = [SERVER] Capture Wall Collision Notify Tick!
LogZoghAnimInstance: MeshComp = [SERVER] Capture Wall Collision Notify Tick!
LogCaptureHandlerComponent: Capture Owner = [SERVER] Check Wall Collision!
LogCaptureHandlerComponent: MeshComp = [SERVER] Check Wall Collision!
LogCaptureWallNotify: [CLIENT] Capture Wall Collision Notify Tick!
LogZoghAnimInstance: Capture Owner = [CLIENT] Capture Wall Collision Notify Tick!
LogZoghAnimInstance: MeshComp = [CLIENT] Capture Wall Collision Notify Tick!
LogCaptureHandlerComponent: Capture Owner = [CLIENT] Check Wall Collision!
LogCaptureHandlerComponent: MeshComp = [CLIENT] Check Wall Collision!
LogCaptureWallNotify: [CLIENT] Capture Wall Collision Notify Tick!
LogZoghAnimInstance: Capture Owner = [CLIENT] Capture Wall Collision Notify Tick!
LogZoghAnimInstance: MeshComp = [CLIENT] Capture Wall Collision Notify Tick!
LogCaptureHandlerComponent: Capture Owner = [CLIENT] Check Wall Collision!
LogCaptureHandlerComponent: MeshComp = [CLIENT] Check Wall Collision!
LogCaptureWallNotify: [SERVER] Capture Wall Collision Notify Tick!
LogZoghAnimInstance: Capture Owner = [CLIENT] Capture Wall Collision Notify Tick!
LogZoghAnimInstance: MeshComp = [CLIENT] Capture Wall Collision Notify Tick!
LogCaptureHandlerComponent: Capture Owner = [CLIENT] Check Wall Collision!
LogCaptureHandlerComponent: MeshComp = [CLIENT] Check Wall Collision!
I hope I haven’t forgotten anything. The post is already long so I hope it will be enough for anyone to help me.
If further details are needed, tell me and I’ll do my best to provide them.
Thanks in advance for your help!