Replication only occurs one way

I have attempted to create my own multiplayer game following the same blueprints provided by the Multiplayer Shootout example. As far as i can tell, everything appears to be working correctly, except replication only seems to occur one way. I am running a listen server, and things seem to connect OK without any errors. However, in screen 1 (player 1), player 2 is frozen, and he does not see any of player 2’s movement. However, in screen 2 (player 2), when player 1 moves i see his movement replicated. I’m not even sure how to begin debugging that, so was wondering if anyone has any idea what may be going wrong.

All replication is one way Server > Client.
Since movement for Pawn/ Character is working out of te box in UE 4.

I assume you forgot to check the bReplicated and bReplicateMovement to true.
If so you will see the movement working fine server side (Listenign Server) but not back to client.

Hope it helps.

I’m actually getting the opposite result. The client can see replicated movement, but the server is not getting any replicated movement. All of my actors are set to replicate, and i added the GetLifetimeReplicatedProps stuff. So on the client side, i see the player on the server side moving around, but the player on the server side, doesn’t see the client player moving around at all… the title on the windows state which one is the server and which one is the client, so i know i’m not just getting them backwards…

You need to do the movement on BOTH the client and the Server, it’s just that the Server sends back authoritative positions and updates them when it gets an update.

I’m not entirely sure what you mean. My pawn class does its movement on tick, which isn’t restricted to client or server. My pawn code is : http://pastie.org/10067026. Maybe my understanding of replication is incorrect, but i was expecting the server to be responsible for sharing the forward/pitch/roll speeds, and then on each tick, both client and server would move their actors based on those shared speeds. The client appears to be doing that correctly, as the “server” pawn movement is being replicated on the client.

When i debug using the following code in my pawn tick method:



    if (Role < ROLE_Authority)
    {
        UE_LOG(LogTemp, Type::Display, TEXT("AWhenYetisFlyPawn::Tick - client"));
    }
    else {
        UE_LOG(LogTemp, Type::Display, TEXT("AWhenYetisFlyPawn::Tick - server"));
    }
    if(PlayerState != nullptr) {
        int id = PlayerState->PlayerId;
        UE_LOG(LogTemp, Type::Display, TEXT("AWhenYetisFlyPawn::Tick - %d"), id);
        UE_LOG(LogTemp, Type::Display, TEXT("AWhenYetisFlyPawn::Tick - %f"), CurrentForwardSpeed);
        UE_LOG(LogTemp, Type::Display, TEXT("AWhenYetisFlyPawn::Tick - %f"), CurrentRollSpeed);
        UE_LOG(LogTemp, Type::Display, TEXT("AWhenYetisFlyPawn::Tick - %f"), CurrentPitchSpeed);
    }


I see that for the client, the currentForwardSpeed/RollSpeed/PitchSpeed is correct for both the first and the second pawn. However, on the server, although it has the correct values for the first pawn (the pawn that originated on the server), the values for the second pawn are always 0/0/0

Hey jjekeli,

The movement you see for player 2 on client 2 is not replicated movement, it is client 2’s local simulation that actually makes it go out of sync with the server. On the server he is standing still. The reason why you do see player 1 moving on player 2’s screen is because, like TheJamsh said, the listen server (player 1) sends authoritive position updates.

Like said, all replication is Server > Client. So as a remote client (player 2), to move and have that happen on the server and thus for everyone, you need to have the server simulate the movement. You do this by sending the player’s input from client to server. For example, as a client tell the server when you start and stop moving forward using a client->server RPC. Then let the server apply that input (for example in Tick) and since the character’s position is updated on the server that will be reflected on all remote clients.

If you’re using CharacterMovementComponent, it may have functions set up for you already but I’m not sure about that. I know that for VehicleMovementComponent if you call SetThrottleInput and SetSteeringInput on the remote client and it has ownership of that actor then that input is sent to the server. Perhaps someone else can tell you more about whether this works for CharacterMovementComponent as well.

Ohhhhh. So “replicating” a property on the client doesn’t actually make that data go client->server, it just makes it go server->client. Just to make sure i have this straight, let me post a quick snippet and see if it’s what you mean; So if i have the method ThrustInput bound to the up and down arrow keys, then ThrustInput would look like:



void AWhenYetisFlyPawn::Tick(float DeltaSeconds) {
    if(HasAuthority()) {
        //do sweep forward based on CurrentForwardSpeed
    }
}

//in hpp, would bind to server via UFUNCTION(BlueprintCallable, Category="GameMode", Server, Reliable, WithValidation)
void AWhenYetisFlyPawn::ServerThrustInput_Implementation(float Val) {
	CurrentForwardSpeed = Val
}

void AWhenYetisFlyPawn::ThrustInput(float Val)
{
        // Calculate new speed
	float NewForwardSpeed = CurrentForwardSpeed + (GetWorld()->GetDeltaSeconds() * Acceleration * Val);
        // Clamp between MinSpeed and MaxSpeed
	CurrentForwardSpeed = FMath::Clamp(NewForwardSpeed, MinSpeed, MaxSpeed); //CurrentForwardSpeed does not need to be replicated anymore
        serverThrustInput(CurrentForwardSpeed);
}


If this is correct, a couple questions about the efficiency of this. It seems like there are a couple ways to do this. I can either take the approach above, where each client computes the currentForwardSpeed, and then the server does the tick, and replicates the position back to the client, or I can have the client compute the forward speed and send it to the server, BUT instead of having just the server do the tick and replicate the movement, each one would do the tick and i wouldn’t replicate the movement, instead relying on the replicated inputs. What is the better practice? To replicate position, or to replicate the inputs that get you to the position, and then calculate the position on both client and server?

Quick update; i tried the approach i mentioned above, and it kind of worked… now the server is seeing movement of the client on his screen, but the client no longer moves at all on his own screen (although the client DOES see the server’s movement on his screen, so its almost as if the server is replicating his OWN movement and sending out authoritative position updates for himself, but he is NOT sending out authoritative position updates for the client’s position; why would that be?)… do i need to do a tick on both even though i have bReplicateMovement=true and bReplicates=true on the pawn? If so, i guess I’m still not clear on how this is supposed to work

I have the exact same issue.

Client replicates movement input to Server, and does nothing on its own (No scaling, movement, rotation or anything). The server replicates its own movement but does not replicate the client movement (even though I can see that movement happening on the server.)

I just can’t get my head around bReplicateMovement, it seems that it’s just one of many things in this engine that does not work as intended, or if it’s intended, there’s a caveat somewhere.

There was indeed a caveat.

For future reference, if anyone ends up and is wondering why your locally controlled pawn is not network synced;

It has to do with the NETRole that the pawn has, there are 4 different types, with the following priority values:



ROLE_None = 0
ROLE_SimulatedProxy = 1
ROLE_AutonomousProxy = 2
ROLE_Authority = 3


Locally controlled Pawns are AutonomousProxy, which means that they move independently of the server and await correction (or correct the server, based on which way you want to implement it). Only None and SimulatedProxy replicate values by default afaik. I need to do a bit of digging to see if there’s any automatic hooks that notify Autonomous Pawns of changes in movement, currently I’m sending the replicated values unreliably to the Pawn, which does not feel like the optimal way of doing things.