RepNotify from c++ confusion.

Hey guys, i have a problem with coding a RepNotify variable from c++ and that is it’s not being replicated at all. I’m trying to follow somehow similar steps to the Blueprints tutorial that was put on some days ago.

in my character’s header file i have this variable that i want to replicate:



UPROPERTY(ReplicatedUsing = UpdateCharacterStatus)
		float HealthPoints;
void Update_Character_Status();
//public function that will call another function to update the text being rendered above the character's head. That other function is (Update_Character_Status).
UFUNCTION()
		void UpdateCharacterStatus();


in my character’s cpp file



// implementation of the two functions mentioned above.
void Athird_PersonTrialCharacter::Update_Character_Status()
{
	CharacterText->Text = FString("HP: ") + FString::FromInt(HealthPoints) + FString(" BombCount: ") + FString::SanitizeFloat(BombCount);
}

void Athird_PersonTrialCharacter::UpdateCharacterStatus()
{
	Update_Character_Status();
}
 
//inside the tick function i have the health variable being reduced by 1 and then being reinitialized.
(HealthPoints <= 0) ? HealthPoints = 100.0f : HealthPoints -= 1.0f;


i also have the variable (HealthPoints) in :



void Athird_PersonTrialCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const 
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	// Replicate to everyone
	DOREPLIFETIME(Athird_PersonTrialCharacter, HealthPoints);
}


Am i missing something or doing something wrong? would be very thankful if someone could help with this!

1 Like

First off all, I am a bit drunk, so hopefully I don’t write to much stupid stuff :smiley:

The idea behind RepNotify is networking. It will only call the notification if it’s not changed by itself.
So if the server changes the value, the client replicates it and call the function.
If you change your own replicated property you wont take any notification for it.

Hope this helps you.

3 Likes

Hello, there are a few things to consider when using RepNotify,

  1. If you subtract 1 from the variable and reset the variable in the same Tick function then the change will go unnoticed and will not get replicated.
  2. For a client to replicate the variable it must own the class/possess the pawn which the variable is contained in.

One key difference between how blueprints and C++ handle the “rep notify” concept is that in blueprints any time a RepNotify variable is set, the OnRep function is automatically called on the server (and on the client when the update happens). In C++, the server does NOT automatically get the ReplicatedUsing function called, only the client does when it gets its update. If you want the server to call that function, you have to do so manually. I’ve had a decent number of requests to show porting the last 2 parts of the blueprint networking tutorial to C++, so I’m hoping I can do that some day soon when I find some time.

Also, whenever you are changing health, you’ll want to make sure you’re only doing so on the server. If you aren’t already, the C++ equivalent of the blueprint macro node for checking authority is:


if (Role == ROLE_Authority)

Thanks guys for your replies, really helped me understand some things that i thought i understood!

Billy, that would would be wicked! I kind of recognize some names from the UnrealScript days but i’m quite lost in the new C++ flow of stuff. I know the language but it’s pretty hard tracking where stuff start from :smiley: Anyway hope to see those tutorials in the near future and thanks for the blueprints one that you put eariler!

Hi Billy, could you provide a quick example of how to do the call for the RPC on the server as well? I’m following the tutorial along right now and trying to program in the C++ equivalent.

What do you mean exactly ?
RPC call is just RPC call.



UFUNCTION(Server, Reliable/Unreliable, WithValidation)
void ServerMyFunction();


Needs more specific as what you mean exactly ;).

Sorry to dig up an old thread but it seems relevant.

I’ve noticed in the ShooterGame example running on 4.7.3 that the RepNotify functions are never called in C++ after modifying the replicated variables. However the RepNotify functions still end up getting called on the client side. Is this due to a recent change in engine behavior? Or is there some odd config flag that you can set that makes this work?

The repnotify was always called on a client when the server changed the variable (at least it did when I used it for mine in 4.6), what DIDN’T call the RepNotify was when you were a local player (i.e. a player on a listen server), so I had to call the Repnotify manually in that case. I suspect that is what is confusing people.

So to summarize:

A variable set with a OnRep notify callback will have that callback called on the client when it receives an update from the server for that variable. UNLESS it is a local client (i.e. on a listen server), so in order for that to function correctly the server needs to check if its a local server and if it is, call the callback manually. Which honestly I think is a bit **** :slight_smile:

1 Like

Ah just saw this thread again, apologies for missing your original question, TheJamsh!

Could you provide a little more detail here? Do you mean that the RepNotify functions aren’t called on the server? That’s a difference in C++ vs. blueprints, the RepNotify functions are not auto-called on the server/net-authority (and must be manually done, if desired). Or is there a client issue?

If you’re a listen server acting as the network authority, that is correct, the RepNotify’s won’t be called directly for you. An example use case here might be that you use the OnRep function purely for visuals (no gameplay relevance) and want that to happen for clients and the listen server, but not the dedicated server. In that case, you’d do something like this:



// Pretend this code is executing on the server, where I'm setting my replicated variable that has a repnotify setup on it (authority guarding it just to be clear/sure). Didn't compile this directly, just typed into the forums, so possible typos, etc.
if (Role == ROLE_Authority)
{
   bMyRepBool = true;
   if (GetNetMode() != NM_DedicatedServer)
   {
      OnRep_bMyRepBool();
   }
}


Another thing to be aware of is that it’s possible for the clients to also not call the OnReps, if their local value of the variable is already equal to the value the server replicates down. For that to happen, someone would likely have also locally modified the value on the client though, which is usually ill-advised. Even still, that behavior can also be changed by modifying how you setup your replication statement:



// This will cause the OnRep to always be called on the client, even if they have the same value locally already (usually don't need to do this, depends on your usage)
DOREPLIFETIME_CONDITION_NOTIFY(MyClass, MyVariable, COND_None, REPNOTIFY_Always);


Out of interest Billy, any idea why Rep notifies aren’t called on a local server? It makes the code paths all a bit convoluted. Why not just call Repnotify for ANY client (including the local server version) and be consistent?

In the listen server case, the local player is not actually a client in the traditional sense. They’re still the net authority and would pass ROLE_Authority checks.

What I meant to say is that in the ShooterGame example, I don’t see any OnRep*() functions called anywhere in the codebase. The replicated variables are changed by the authority and the OnRep*() get triggered on the clients even though they’re never called explicitly by the authority.

For an example look at the BurstCounter variable in ShooterWeapon.h, the variable is incremented or set to zero by the authority but there is never a call to OnRep_BurstCounter(). Despite this, clients still receive a call to OnRep_BurstCounter after the variable is changed on the authority.

Those variables are done using the ReplicatedUsing=“whatever” annotation in the variables property declaration. They call the “whatever” part then the property changes (or when the property changes from the current value), so its one of the parts of the code where the header tool inserts the code to actually call the function.

Ohhhh. I just re-read post #4. I was mis-interpreting it as you had to call the RepNotify manually for everyone [client + server]. But a more careful reading says you only need to call it manually if you want it executed on the server.

Exactly, plus you’d only really want to do it on a server that was also using a local player (i.e. not a dedicated server).

Sorry to revive this antique thread, but I’m really not following the logic here. What if I have a UPROPERTY which is BlueprintReadWrite and uses a ReplicatedUsing function? If the Blueprint changes the value, I have no way to manually call the OnRep function on the server.

e.g.:


UPROPERTY(BlueprintReadWrite, ReplicatedUsing = OnRep_MyFn)
bool bMyProperty;

UFUNCTION()
void OnRep_MyFn();

How would I make sure OnRep_MyFn is called on the server when the value is changed from Blueprint?

At the very least, I would let this behavior be modified by a metaflag on the property.

The blueprint generated code to set that variable will call your OnRep_MyFn when its set via blueprints on the server and client.

I saw that this wasn’t happening in my project, that’s why I searched for this thread. But if you’re sure about it, I’ll check again.

I checked again and looks like it’s only running on the client when modified via blueprints (at least in PIE). If you’re sure it’s supposed to work, I wonder what I’m doing wrong:


	
public:
	UPROPERTY(EditAnywhere, ReplicatedUsing = OnRep_Decisions, Category = "Operator", BlueprintReadWrite)
		TArray<FOperatorDecision> Decisions;

        UFUNCTION()
		void OnRep_Decisions(); //only called on clients when Decisions is set from Blueprint.


I should add that this is on an ActorComponent, not an actor. Could that be part of it?