Replicating transform from client to server without RPC


I’m trying to optimize a vehicle system which clients can use (posses) in my multiplayer game. Currently though the client moves said vehicle ( a cannon) around and each couple of microseconds an RPC is used from the client to the server to tell the server where the client moved said cannon (well rotated actually). This works fine, but is sending a massive amount of data over the network and is pretty much eating up all our bandwith. So i’m looking for a far more efficient way of doing this.

The problem is that on this particular kind of vehicle (cannon) I can’t simply set the rotation directly on the server and then replicate it back to the client, because aiming with the cannon needs to be really really responsive and smooth so the rotating needs to happen on the client and then somehow end up on the server after which it gets replicated down to all the other clients. Things is though it doesn’t need to be very accurate on the server, as the projectile is launched from the exact rotation the client has. The server purely receives the rotation for cosmetic purposes. I’ve tried lowering the RPC frequency down to half a second which is still a lot and this sadly makes it look really choppy and weird, so I need a better way, preferably without an RPC.

Anyone know what the best way to do this would be?

In order to reduce the bandwidth:

  1. Lowering the frequency is the right step… but you should interpolate and extrapolate in between of the packets… and probably half a second is too little (but then again, it highly depends).

  2. You can further compress the variables sent… eg instead of transform, you can just send location + rotation (and not sending scale). Location can further be compressed by sending only delta and each of the component (x,y,z) can be sent as 2 bytes (16 bit) integer (instead of 4 bytes float). So now, the compression level is pretty nice now… the original (transform) is 36 bytes, now you are sending 6 bytes (location), 12 bytes rotation = 18 bytes. It is now halved. And rotation can be compressed too, probably something like
    int pitchChanged:1
    int16 pitch
    int rollChanged:1
    int16 roll
    int yawChanged:1
    int16 yaw;
    The structure above assumes that at one time, not all axis is changed at one time, so you can further compress it. So the size above translates to 3 bit (if no axis is changed) and maximum is 51 bits (slightly above 6 bytes)

Hey Syed thanks for the tips, I will look into reducing the amount of variables in each transform.

I’ve also just read something that confuses me greatly…

In the following question a guy repliad with an answer that has me scratching my head, he claims that multicast functions are much more optimized than replicated variables.

Is this actually true? I always thought that replicated variables are the most optimized form of replicating and that multicasts where to be avoided even as much as possible. Every tutorial ever I could find regarding the topic of replication always spoke of how to use replicated variables as much as possible instead of using rpc / multicast nodes.

Is this guy just wrong or is this actually a fact and am I very wrong?

Ok So I did some testing with the network profiler and appearantly the guy is right. Replacing the replicated variables with a multicast has reduced my bandwith usage of the particular actor to pretty much nothing, when before with the replicated variables the usage was through the roof and hitting nearly 10 KB/s when now for the same period of time I reached 0.04 KB/s

This is awesome, but extremely confusing to me. Can someone please explain why multicasts are soooooooooo much more efficient? What makes replicated variables so extremely expensive? Knowing this now makes me feel like a complete fool and I’ll probably have to redesign a lot of my code now.

Why is this not properly documented as this seems to be something very important to know in my opinion. o_O

From what I’ve been reading I’ve managed to grasp that it’s indeed wiser to use a multicast for variables that change on tick, because with a multicast you can set the reliability to false, which doesn’t matter as the multicast function is called every frame anyway meaning that if it skips one or many times won’t really have much effect if any on the end result for the clients. All replicated variables are reliable which does indeed make them very expensive when changed on tick. So basically knowing this now I guess it’s best that I replace all the replicated variables that change on tick with multicast functions.

Or am I wrong? :stuck_out_tongue:

I think its because if you set some variable to replicated, its updated in NetFrequency, which is default i think as fast as possible (tick?) Or some interval how often you changing it (0,5s to tick), but multicast is fired only when you use it, so if you fire cannon once per 10 s, then you probably reduce your bandwidth ~600x. But im still programming noob so dont trust me at all :slight_smile: i might be wrong

Default update rate for NetFrequency is 100 times per second I think. You can lower this in the actor properties.

I’ve done some more testing and found out that RPC calls are not shown in the actor tab on the network profiler, they are shown on a seperate tab. Looking at that particular tab I found that the rpc calls from the multicasts I made to replace the replicated variables are still sending a significant amount of data, a lot less than the replicated variable, but still a lot. I’ve also started quantatizing my vectors by removing all the decimals which seems to help as well. But overall bandwith usage is still around 2000 which seems extremely high compared to other profilings I’ve seen. The only few things that are giving me such a high bandwith usage are the vectors and rotators which are updated on tick, which are 100% needed for the ships inour game as their position and rotation needs to be as accurate as possible for gameplay purposes. I’d really like to know how others have tackled this issue with vehicles in multiplayer.