Download

Replication Rabbit Hole

Alrighty

Hopefully someone can restore my sanity of the replication rabbit hole I’ve gone into with this method…

It ‘works’ but I’m not convinced I’m doing this in the best or even the correct way.

The root of my problem is that replicated variables won’t replicate unless its value is different than the last time it replicated. Which is fine and lovely, I understand that all good. I’ve accounted for this and got it working but it doesn’t feel right, feels hacky and makes me want to scrub myself with a Brillo pad.

The basic gist of the method is to play a hit reaction animation and replicate it to the clients.

I use an OnRep which gets called when the value of the UAnimMontage variable ‘CurrentHitReactionAnimMontage’ variable is replicated.

So to the code of cack:

After a pawn is hit by a melee attack it processes the attack and fires off the below function to play the animation:



void AGCharacter::PlayHitReactionAnimation(UAnimMontage* AnimMontage)
{

/* Play Melee Animation */


// replicate animation to clients
if (Role == ROLE_Authority)
{
    CurrentHitReactionAnimMontage = AnimMontage;
}

// Play animation on server
    OnRep_ClientPlayHitReactionAnim();

}



The On Rep function looks like this:



void AGCharacter::OnRep_ClientPlayHitReactionAnim()
{
    if (CurrentHitReactionAnimMontage != nullptr)
    {
        UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
        if (AnimInstance != nullptr)
        {
            UE_LOG(LogTemp, Log, TEXT("Current Hit Reaction Montage %s"), *CurrentHitReactionAnimMontage->GetName());

            /* Resets Replicated variable to null - stops variable not replicating if same value as last time it replicated */
            GetWorldTimerManager().SetTimer(TimerHandle_Invincible, this, &AGCharacter::InvincibleOff, 0.2f);            

            AnimInstance->Montage_Play(CurrentHitReactionAnimMontage);
        }

    }

}


The problem arises due to the replicated variable ‘CurrentHitReactionAnimMontage’. The first hit a pawn takes is fine but if the next time its hit it gets passed the same Animation Montage then it won’t replicate and the client doesn’t play the animation.

So the filthy thing I’ve done to deal with this is to start a timer in the OnRep so it runs on both the server and the client, when the timer ends it just sets the CurrentHitReactionAnimMontage variable to nullptr.



void AGCharacter::InvincibleOff()
{
    CurrentHitReactionAnimMontage = nullptr;
}


I feel like I’m going the wrong way about replicating this variable or using it with the OnRep incorrectly. The above works, the animations are playing in sync between the server and client so I could live with it if need be but I’m sure there’s a better way.

I sort of think that maybe I’ve caused a bit of a loop by doing that as when the server gets reset to null, is it then firing off another OnRep to the clients? It doesn’t seem to be doing that but I’m not convinced. Or is the OnRep not being called when the server gets reset to nullptr because it see’s the client has the same value as server as I cleared the value on both server and client? This is where my brain got in a muddle…

That last paragraph was a horrible brain dump of words…

Any advice or valium will be warmly received

Wrap your animation in a struct and add a counter to it that you increment to make sure the struct is replicated.
Look at AShooterCharacter::ReplicateHit(…) and the struct FTakeHitInfo to get some implementation details.

Yeah good shout that sounds a more sturdy method I’ll give it a razz. Sounds so simple now was defintely having one of those brain overload days. Cheers for the help :slight_smile: