Download

Replication HUGE confusion. Property does not replicate

Hello. I’m totally confused with ue4 replication. I can’t understand the logic behind it. Please, take a look at this simple code:
*.h


UPROPERTY(Replicated, ReplicatedUsing = TestFunction)
int32 Test;

virtual void PlayerTick(float DeltaTime) OVERRIDE;

UFUNCTION()
void TestFunction();

*.cpp


void AMyProjectPlayerController::PlayerTick(float DeltaTime)
{
	Super::PlayerTick(DeltaTime);

	if (Role == ROLE_Authority)
	{
		UE_LOG(LogTemp, Warning, TEXT("On server %s: %d"), *this->GetName(), Test);
		Test++;
	}
	
	UE_LOG(LogTemp, Warning, TEXT("On Client %s: %d"), *this->GetName(), Test);
}

void AMyProjectPlayerController::TestFunction()
{
	UE_LOG(LogTemp, Warning, TEXT("Notification on client %s: %d"), *this->GetName(), Test);
}

I made my controller replicated, I add Test variable in DOREPLIFETIME() macro.

When I run a single client as listen server, I have 2 lines in log - “On server…” and “On Client…” with Test changed. Notification don’t called on server, I know it, it’s how it should work.

When I run a single client with dedicated server I have only log - “On Client…” and Test is unchanged. But why??? It’s changed in PlayerTick() function in ROLE_Authority block and from here:

So, my single client runs on both client and server at the same time. Test is changed on server. Test is Replicated. Why can’t I see it on client? Why notification is not fired?

Next. I added


UFUNCTION(Reliable, Server, WithValidation)
void ServerFunction();

and call it in PlayerTick(). And everything is wonderful - now I can see Test changed on client and even notification is fired.

So, I hope someone can explain why my variable doesn’t replicates. Why I need to call server function for this from client (it’s a lot of unnecessary traffic). What’s the difference of ROLE_Authority and UFUNCTION(Server)?

Up. Sorry… I need an answer, I can’t sleep.

Hi there,

The only thing I can think of is relevancy might be the reason why you don’t see the property replicate until you call the RPC function. When calling an RPC function on an actor, it will force an actor channel to be created, and force a frame of replication.

Is there any chance you could trace the code through UNetDriver::ServerReplicateActors, and watch what happens with this particular actor, and see how far it gets?

Hi John,

I’m looking at this method - it’s HUGE (800 lines). Should I try to find something specific?
Btw, I run an editor from sources, choose 1 client and dedicated server, toggle a breakpoint in UNetDriver::ServerReplicateActors, code gets there and runs till the end. At some point the code gets me to FObjectReplicator::ReplicateProperties where I see that my property is 0 (i.e. no changed), but it should (should it?) - I have this thing in my controller:


if (Role == ROLE_Authority)
{
	UE_LOG(LogTemp, Warning, TEXT("On server %s: %d"), *this->GetName(), Test);
	Test++;
}

Doing this in PlayerTick is your problem :slight_smile:

From PlayerController.h:



/**
 * Processes player input (immediately after PlayerInput gets ticked) and calls UpdateRotation().
 * PlayerTick is only called if the PlayerController has a PlayerInput object. Therefore, **it will only be called for locally controlled PlayerControllers.**
 */
virtual void PlayerTick(float DeltaTime);


This is the key: it will only be called for locally controlled PlayerControllers.

So it’s not called on the server for your PC, so you won’t get an updated value.

You can try moving it to APlayerController::TickActor(), which is called on the server for all PCs, regardless of role.

Yes, that’s exactly my problem. Now everything clear. Thank you a lot.