RPC replication not obeying cause and effect

Hello UE4 answerhub,

I am currently pulling my hair out over what should be a very simple RPC replication process. I have an actor (station), which is owned by a player pawn (so it should be able to run ‘Execute on Server’ RPCs remotely). This actor has a begin play function:

As you can see, remote clients will print the “CLIENT” statement before running Initialise Station Grid, which is an RPC run on the server instance of station. The code from there is as follows:

The server sends some updates to all the client instances of station (now that it knows that those clients exist, or the function would not have been called) in the RPCs UpdateGrid_MultiCast and InitialiseModulesClient. It then prints the “SERVER” statement to let us know that the server has received the function call from a client instance and has executed it.

Here is the issue: When running a listen server with one extra client, I immediately get the “SERVER” print statement on the listen server and have to wait several more seconds for the other client to load, before getting a “CLIENT” statement on the client. I do not then get another “SERVER” statement. This seems to me like a violation of cause-and-effect, which is a pretty fundamental requirement for our universe to function correctly… I’ve also slapped some print statements on the two multicast functions to see if the client is receiving any of those function calls, but it is not.

What could be causing this issue? Surely, if the listen server were triggering Initialise Station Grid, then it would have to consider itself to be remote, which it is obviously not. Furthermore, why would the client not successfully call Initialise Station Grid after printing “CLIENT”? Note: I am using two separate processes when playing in editor as this minimizes other buggy behaviour and is more faithful to the final product. This complicates it even more, as the client has to load from a completely new process which hasn’t even loaded by the time the listen server throws the “SERVER” text. Any ideas?

Thanks,

David

What is the reason that you need the Client to ask the Server to “InitializeStationGrid”? Station “Remote” BeginPlay is the same thing.

Also remember that you can Spawn an Actor with a Replicated variable set to “Instance Editable” and “Expose on Spawn” to have the variable ready on “Remote” BeginPlay. If the station is using a default variable you don’t have to replicate it.

A listen-server will execute RPC’s on itself as if they were local functions.

Also note that sending multiple RPC’s in a for loop will never guarantee that they will arrive in the same order. The Completed event may not be the last RPC being received by the client.

The only way to guarantee RPC’s arrive at the same time is to bundle them into one RPC call.

I am having issues with the station grid variable (maps an integer vector to a struct) replicating from server to client - this was fixed in the past by having the client ask the server to manually update the information.

Thanks for the response - the order in which the function calls arrive in the for loop on the client side is not actually an issue. The issue is that they don’t arrive at all. The listen server seems to run the InitializeStationGrid code, which ultimately does nothing because the remote instance of the station did not yet exist at that stage. This is strange because the only way it can call this function is if it also printed the “CLIENT” string before executing it, which it does not. Hopefully this makes sense…

It is the ordering of the print statements which gives an insight into what’s happening, which seems to contradict logic, and is breaking the game for the client.

If you can’t rely on the server to update the client then you are digging a big hole for yourself. It might have been a problem in the past but I haven’t had problems with this approach. Network States should be Replicated variables and Network Events should be RPC’s often unreliable.

It is indeed odd that the listen-server thinks it doesn’t have authority. I have never had this problem and I have been working with multiplayer for almost 3 years. You could try to use Breakpoints and only break on the Server-side and see if it still triggers the Remote branch.

I added some breakpoints - one on the start of the execution of the RPC (2nd image) and another at begin play where the RPC is called (1st image). The breakpoint inside the RPC function is immediately triggered, but the breakpoint at begin play is not, which is completely counter-intuitive. The RPC is not called anywhere else other than begin play. Nor is it called outside of the station class.

I agree that I am potentially digging a big hole here, although there is some other code that needs to run on top of this variable replication business (the InitialiseModulesClient bit, which has to do with lighting). This is mainly why I’m posting this question - to see if there’s something simple I’m doing incorrectly to cause this behaviour which could be easily resolved.

You should use variables for state changes and RPC’s for Events that may or may not change the replicated state variables. Relying on RPC’s on dynamic Actors to reach the Client is not a good idea.

You can use the Blueprint Debugger to trace where the call came from in the Call Stack

Thanks for that advice - a different class was actually calling the RPC which was not listed when I searched for references of the function. This removes the issue of the initial “SERVER” message at the start, but the client still fails to get the server to do anything. I appreciate that there are some optimisations I need to do which you have suggested, but it seems to me that the client should still be able to get the server to run the RPC, which it does not.

Check your output log for any warnings related to NetDriver stating something about the “owning connection” and also try to check if “GetOwner” matches with something the Client trying to make the RunOnServer RPC actually owns.

Also ensure that you are actually setting “owner” when spawning the Station Actors. If you set it after you spawned the Station then you have to wait until “Owner” has been replicated before calling the RPC.

I’ve done some debugging, and it looks like the issue is actually caused by a big time delay between the client calling the RPC and the server receiving that call. There are no problems with NetDriver in the log, and the client does indeed own the station actor.

I think this might be because of a lot of reliable functions being called around this time which seems causes lots of latency issues… I think it’s down to optimisation and only declaring functions as reliable if absolutely necessary.

Sounds plausible.