OnRep vs multicast

Hi all!
I see that most tutorials use OnRep events and stay away from multicasts.
What is the real difference between doing an OnRep (with no COND and a call directly for listen server), and doing a multicast (called from server)?
Also, one thing that has been bothering me: I assume that functions that are neither client or server, are run by “whoever calls it”. Is this assumption true? (My debugging indicates so…)

Also: Is there some “golden rule” as to what need to be reliable and not? How often will an unreliable RPC be skipped? Can we set stuff like mesh visibility with an unreliable RPC, without visibility bugs becoming a recurring annoyance?

Also, is there any delay with replicated vars? If I change a DoRep var on the server, will the OnRep be called instantly (so that further methods in the initial function can rely on change made by the said OnRep), or does this happen “when it happens”? In other words: If you check a replicated var; do you check a local copy of this var, or do you actually check the var directly on the server?

Hoping Rama, or someone, can come along and share of their voodoo :slight_smile:

An intro to replication exists, I know, but it would be nice to have like a primer or something, that just goes over roles and the various things that happens when you call the different kinds of RPCs from the different levels of auth. Maybe I could write one myself, when I get these questions answered… :slight_smile:

Alright, let’s say you have a replicated Actor but it’s not network relevant to a client.

If the server wants the Actor to explode, it could trigger a multicasted event which plays an explosion effect. Clients where the Actor isn’t network relevant don’t need to see the explosion and they won’t.

Though let’s say the server wants to change the colour of the Actor and have the change replicated to clients. If the server triggers a multicast event to change the colour, that will fire on all the clients where the actor is network relevant.

That means (generally) that clients close to the Actor will see the updated colour, but clients far away won’t get the event to update the colour so they’ll still see the old one indefinitely.

If you have a replicated variable to control the colour state with an OnRep instead, even if the Actor isn’t relevant the OnRep will fire when the Actor becomes network relevant again and the colour will update correctly.

So basically: Use OnRep when you need to replicate a change in persistant state and multicast events for temporary things that won’t matter in the future.

Also, my golden rule with reliable is to use it when an event or variable change must get to the client, and not reliable when it’s something that updates a lot (like every frame) and it doesn’t matter if an update gets lost.

9 Likes

@
Thanks for the reply. This actually cleared stuff up…

The main difference is, that OnRep will happen sometimes (literally), when replicated variable arrive to clients (which happens sometimes).

Multicast will happen right now, after it’s called on server. It will happen even before any replicated variables, replicate. Which might or might not be desired behaviour.

Ok. Then I think I have RPCs covered.
Out of curiosity: Is there a set time between replication updates? Is it arbitrary, or does it happen every tick, or…?
How long should I “wait” until I can trust a replicated var to be “correct”?

All variables are replicaated at end of tick. They are check for changes several time in one tick tough.

so should we be doing both?

multicast and onrep so when the actor becomes relevant it works vs it being just multicast?

I heard people saying dont use multicast because it will cause lag

Use one or the other depending on if you’re replicating state or not.
Multicast is fine if it’s being used properly, but if they’re being called so many times it lags maybe it’s time to optimize.

Senior Multiplayer programmer here - here is a good rule of thumb:

  • If you are changing the State of an actor, use a replicated variable. Use an OnRep callback if you want to respond to changes.
  • If you need a one-time Event, use a multicast.

This design eliminates any interference from Network Relevancy and handles Join-In-Progress etc seamlessly. Personally, I don’t often find much use for Multicasts in gameplay code - they’re more useful for say, broadcasting a server message to players etc.

However - sometimes it can make sense to use replicated variables for events which occur very often. A good example is ShooterGame’s ‘BurstCounter’ - which in that case is just simple integer value on the weapon class, which increments and uses an OnRep to trigger firing effects on clients.

You don’t want to be clogging up your RPC buffer with unreliable multicasts for simple cosmetic events like this, especially as they occur so often. Leave the RPC buffer free for other more important things. Variable replication is also considerably more efficient here, because you can benefit from network prioritisation and update rate optimisations - you get no such benefit with RPC’s.

Correction: Unreliable Multicast RPC’s do actually go via the same path as properties it turns out. Use that information how you wish…


There is a myth that OnRep callbacks are not reliable, but they absolutely are. If you receive a value from the Server and it differs from the Clients’ current value, the OnRep WILL be called. I have worked on several games that rely on this behaviour, and they simply wouldn’t work if it didn’t.

In addition, OnRep’s have some other useful tools you can use. You can force the OnRep to be called even if the Clients’ current state matches the received state by adding the following flags in GetLifetimeReplicatedProps:



DOREPLIFETIME_CONDITION_NOTIFY(AMyActor, MyReplicatedProperty, COND_Custom, REPNOTIFY_Always);


You can also optionally add a “Previous Value” argument to the OnRep callback, and Unreal will pass the variables previous client value to it. This is now used by Epic quite extensively as part of the Gameplay Abilities system, but it has always been a feature, and you can use it in regular gamecode too. Here’s an example from one of my projects:

.h



/* Used to drive firing simulation effects (muzzle flashes, audio etc.) */
UPROPERTY(Transient, DuplicateTransient, ReplicatedUsing = "OnRep_BurstCounter")
FHT_RepBurstInfo BurstCounter;

/* Replication function. */
UFUNCTION() void OnRep_BurstCounter(const FHT_RepBurstInfo& PreviousValue);


The Server will ONLY send values to clients if it thinks that the client has a different value currently (the server maintains a list of “acked” property states for every property).

I think this is where people get confused and assume it to not be working properly. You will not receive all updates made to a variable, you are only garaunteed to receive the eventual state. It’s up to you to make the code resilient to this.

9 Likes

Hello everyone,

I just started playing with UE4 and wanted to implement a “shift to run” feature. I wanted it to work in multiplayer, offline as a client and on the server. My first realization was that the Max Walk Speed is not a replicated value. I came up with two solutions to solve this, which actually this post boils down to RepNotify vs Multicast.

My first solution was to set the value on the server and then have the server do a multicast to inform everyone of the change to Max Walk Speed.

I then had the idea that I could replicate the “IsRunning” variable on the character by using RepNotify. So I call the server to update the IsRunning variable, and then in OnRep_IsRunning I update the Max Walk Speed.

Reading what you wrote above, out of my two solutions, the RepNotify is the recommended one? Maybe there’s a better way of doing a “shift to run” feature?

So multicast would be good for starting up your weather event?

i would use RepNotify on IsRunning" then you can use that to do it all. From get him to run, but also use it in your anim tree to get animations to fire the run animation.

Wouldn’t it make sense to use both multicast and OnRep for some things?
For example an explosion. You would want an OnRep to notify all players and future joining players that the bomb had exploded. But if you bind the explosion to an OnRep, new joining players would see the explosion at incorrect time, as the OnRep would be called for them, yeah? Wouldn’t it be good to have a multicast for cosmetic things in that case?

lol it is not “sometimes”, the engine will check if that property is different from the one on the server and if it’s the case, the server will send the updated property and will trigger the onrep event.
If the network is poorly optimized and cluttered by other RPCs and replicated variables, replication will not be reliable at all, but that’s caused by the developer not the engine.

It really depends on the use-case.

In this example, what’s the likelihood that the object will even exist for more than a few seconds after it’s exploded? That’s commonly (but not always ofc) a precursor to the actor being destroyed shortly after anyway.

If the actor is not destroyed after it explodes, and merely changes it’s state, you could also use timestamps to allow clients to determine whether to play FX etc when receiving the change.

Another thing to consider is how significant the “event” is. A huge bomb exploding is not something you’d want to miss as a client, even if it is purely cosmetic - and using unreliable multicast might cause that - but if it’s just a small localised explosion, perhaps it doesn’t matter.

Even Reliable Multicast has it’s uses sometimes (rarely for anything cosmetic though) - particularly if you want to garauntee some event makes it to relevant clients before the actor is destroyed.

1 Like

But reliable would still cause the event to be missed if a client joins late, yeah?

It would yeah, that’s really the core argument for using Properties for state is that it means “late join” and “relevancy” work automatically.

1 Like

I would also not update the maxWalkSpeed outside of the character movement component’s functionality. If you update the values outside of the synchronized functionality it’s going to break a lot of things you aren’t aware of. Learn how to override the savedMove to handle passing sprint to the CharacterMovementComponent, and pass whether the character is sprinting through the player inputs, gas abilities (if that’s the route you’ve taken), or the OnMovementModeChanged function.