Correct replication for effect

Hey all.

Got a question I wanted to pose regarding replicating an effect in a network game, because I’m seeing some weirdness.

So I’ve got a suppression value per character that is meant to represent how much fire they have been under and it does various visual changes.

Anyway, I’ve got it mostly working, but for the life of me there is a case where it doesn’t make any sense. So wanted to run it past you guys.

So the variable itself is a float, it is set to replicate as such:


	UPROPERTY(BlueprintReadOnly,Transient, ReplicatedUsing = OnRep_Suppression, Category = Health)
	float Suppression = 0;


Now I’ve got a few methods:


void AShooterCharacter::OnRep_Suppression_Implementation()
{
	//UE_LOG(LogShooter, Warning, TEXT("Help help I'm being supressed!"));
	UE_LOG(LogShooter, Warning, TEXT("Client replication recieved notify to surpress %s is now %f"), *GetDebugName(this), Suppression);
}

void AShooterCharacter::Suppress(FHitResult hit, FVector start, FVector end)
{
	if (Role < ROLE_Authority)
	{
		UE_LOG(LogShooter, Warning, TEXT("Client being asked to surpress %s is currently %f"), *GetDebugName(this), Suppression);
		ServerSuppress(hit,start,end);
	}
	else
	{
		Suppression += SuppressionScale;
		UE_LOG(LogShooter, Warning, TEXT("Server sees Suppression for Actor %s is now %f"), *GetDebugName(this), Suppression);
	}
}

bool AShooterCharacter::ServerSuppress_Validate(FHitResult hit, FVector start, FVector end)
{
	return true;
}

void AShooterCharacter::ServerSuppress_Implementation(FHitResult hit, FVector start, FVector end)
{
	UE_LOG(LogShooter, Warning, TEXT("Server implementing suppression calling supress function for %s"), *GetDebugName(this));
	Suppress(hit,start,end);
}


As you can probably see. I’m using a pattern similar to what I’ve seen in other replication code. I call the Suppress method on the character that has been fired at (I use a overlap sphere check for the firing and that works). It then checks if this is the AUTHORITY (i.e. server) and if it isn’t it calls ServerSuppress, which in turn should call the ServerSuppress_Implementation method on the server. Only this is where weird things happen. On a dedicated server, it all works as intended. When one of the connections is a local server, things tend to go wrong. The server player can suppress the other client. But the other client can only suppress the server if during its firing, the line trace hits another surface nearby the player.

I suspect what is happening is that the suppression method via the RPC to the server is only getting sent when another packet is being sent to the server. Otherwise I see no printed values from my debug log. So basically it stays at the client end entirely.

Anyone spot any obvious flaws in my thinking?

Can you show me the function declaration in your header file?

Why does OnRep_Suppression_Implementation() <- have _Implementation ?

While ReplicatedUsing = OnRep_Suppression points to OnRep_Suppression() ?

The OnRep_Suppression() is never going to get called while replication property, because there is no valid signature.

Other part here.

Not sure if I understand this. But if we have Player1 <> Server <> Player2, there is no direct connection between players.
Player2 can’t affect Player1 directly. Player 2 can only tell server “hey I shoot” (you can send more data if you wish), and server “ok lemme check, at what you shoot”.
If you hit another player, server can perform any logic you wish, and then replicate results using NetMulticast, Client, or RepNotify.

But otherwise neither you nor another player will know he has been shoot, until server can replicate it.
That’s of course not entirely true, you can make some prediction on client who started shooting (either purely cosmetic, which doesn’t have any real outcome beyond spawning cosmetic effects, or some more real prediction, where you actually shoot player and send server results to verify).

Sure:


	//////////////////////////////////////////////////////////////////////////
	// Suppression

	// Current suppression value

	UPROPERTY(BlueprintReadOnly,Transient, ReplicatedUsing = OnRep_Suppression, Category = Health)
	float Suppression = 0;
	UPROPERTY(EditAnywhere,BlueprintReadWrite,Category = Health)
	float SuppressionScale = 0.1f;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Health)
	float SuppressionRecoveryRate = 0.1f;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Health)
	float MaxSuppression = 10.0f;
	/** Suppress this character a little */
	UFUNCTION(BlueprintCallable, Category = Health)
	void Suppress(FHitResult hit, FVector start, FVector end);

	// suppression value changed.. so lets update something
	UFUNCTION(BlueprintNativeEvent)
	void OnRep_Suppression();

	UFUNCTION(reliable, server, WithValidation)
	void ServerSuppress(FHitResult hit, FVector start, FVector end);

The “implementation” bit was actually following what the docs said for the type of event I wanted. As far as I can recall, the _Implementation is the default C++ version of the event handler for use in case the blueprint doesn’t override it. But anyway, it DOES call that when the variable value changes (it also calls the blueprint version). So I don’t think that is an issue. The replication is working as intended as far as I can tell, the problem is earlier in the chain of usage. In that calling ServerSuppress seems to sometimes NOT call the server method.

The second part is quite confusing to me too. Basically whats happening is that I fire a weapon, the line trace hits the suppression sphere around the enemy. That then calls the Suppress method on the enemy character. At this point, its meant to call the server method to update the suppression value for that character (and hence show that to all connected clients). Only for some reason it doesn’t work when I fire from a client and it hits the suppression sphere of the local server player. In that case it ONLY works if I fire at the sphere and the actual weapon trace hits a surface near the enemy (the one being controlled by the local server host). So basically it works as intended only if there is an impact nearby and not just if it gets an overlap event on the suppression sphere (which is what I intended).

My guess is that something to do with throttling is not sending the packet for the suppression unless it also has to send a packet for the impact to be propagated too. But that is pure speculation.