Modify Projectile Velocity On Client

I am currently spawning my projectiles on the server only and replicating them and their movement to the clients.

110405-rep.png

However, when I modify the projectiles velocity on the server post spawn it doesn’t get replicated to the client.
This is obviously because the movement component’s velocity is not replicated.

This results in jerky projectile movement. Since they are moving at different velocities on the server and client.

I know that I could solve this by creating a new replicated property on my Actor or using a RPC.

However, this seems like something that should be built in since the movement is being replicated.

So I dug into it and found FRepMovement.
I figured that setting it’s LinearVelocity on the server would fix the issue I’m having with the velocity not being changed on the client. However it did not.
Is there really no built in way to update the velocity of the projectile on the server only and have the client get it as well?

void UFPSAbility::SpawnProjectile(FName SocketName, FVector Location, FRotator RotationOverride)
{
    if (ProjectileClass)
    {
        if (Character)
        {
            // Spawn the projectile
            UWorld* const World = Character->GetWorld();
            if (World)
            {
                FActorSpawnParameters SpawnParams;
                SpawnParams.Instigator = Character;
                SpawnParams.Owner = Character;
                AFPSAbilityProjectile* Projectile = World->SpawnActor<AFPSAbilityProjectile>(ProjectileClass, Location, RotationOverride, SpawnParams);
                if (Projectile)
                {
                    Projectile->Instigator = Character;
                    // Change the velocity of the projectile based on the chargeup
                    if (MaxChargeUpTime > 0.f)
                    {
                        // Pass the chargeup power to the projectile and let it handle it from here
                        Projectile->SetChargeUpPower(CurrentChargeUpTime / MaxChargeUpTime);
                    }
                }
            }
        }
    }
}

void AFPSAbilityProjectile::SetChargeUpPower(float InChargeUpPower)
{
    ChargeUpPower = InChargeUpPower;

    if (bChargeUpAffectsVelocity)
    {
        if (MovementComp)
        {
            // THIS NEEDS TO BE SET ON THE CLIENT TOO, BECAUSE OF CLIENTSIDE PREDICTION
            float Speed = FMath::Max(MinSpeed, MovementComp->InitialSpeed * ChargeUpPower);
            MovementComp->Velocity = GetActorForwardVector() * Speed;
            ReplicatedMovement.LinearVelocity = MovementComp->Velocity;
        }
    }
}
2 Likes

I’ve encountered this problem here many times and I think the answer is no. The solution you proposed with the new replicated property is a good solution or you could also just set it twice every time, one on the client before calling the server and one on the server and viceversa. I agree with you, it seems intuitive to have a movement component replicated by default since location and velocity are already replicated by default, but I don’t know why it isn’t like that.

1 Like