- Home /
Help me craft a bare-bones position/rotation RPC?
Hey fellas! Delving into networked multiplayer. I have an RPC set up to broadcast a player's position, body Y rotation, and head Y rotation. Looks like this...
private var myPosition : Vector3;
private var myRotation : float;
private var myLookRotation : float;
...
networkView.RPC("UpdateMovement", RPCMode.Others, myPosition, myRotation, myLookRotation);
This is called every 100 ms at most (if a value has changed.) Now from my experience with the Lacewing engine from Multimedia Fusion, I would save bandwidth by sending the rotations as single bytes (giving me 256 directions of rotation, which is enough for aesthetics).
I've heard about disabling timestamp and making RPCs unreliable to save bandwidth, but not descriptions of how to actually do it. How can I strip this RPC down to the bare minimum amount of data (within reason)?
Thanks guys!
Answer by asafsitner · Jan 03, 2013 at 09:42 AM
Unity in itself doesn't give you an option to strip RPC headers or send them unreliable. **uLink** does, if that's what you truly want.
But do you?
If you want to send position/rotation updates and mean to send them unreliable, why use RPCs? There's something called State Synchronization in Unity (and about every sensible networking engine), which does exactly that. I suggest you **read on it here**
As for compressing data to the bare minimum needed, you can convert the floats to shorts, or if you really don't need so much precision, to chars that you can then synchronize.
It's worth mentioning that if you do want to use RPCs, you can also convert them directly to bytes and send them in an array (if you know the first byte is always the head rotation, the second is always the body etc. you can easily unpack the array at the receiving end). This feature is undocumented (unfortunately) but kind of a 'known secret'.
Now, why don't you want to use RPCs for that?
You mentioned that you intend to send an update every ~100ms, if it has changed. This means that you have roughly 10 RPCs broadcasting from each of your players every second. Depending on the amount of players you have this can accumulate to quite a lot of RPCs, ignoring other RPCs you surely want to send as well (such as player instantiation etc).
Unity's RPCs are reliable and ordered. This means the networkng engine numberes and stamps every RPC, and if one happens to drop on the way (which can happen quite frequently depending on network conditions in your environment) it will 'hold back' the others until the correct one arrives.
For example, if RPCs number 1, 2, 3 and 4 were sent, but number 2 dropped, Unity will wait with the network and put execution of RPC 3 and 4 on hold until it has received RPC 2. This can cause noticeable lag in your game, which no one wants.
This is why you want to send things that change frequently as unreliable, meaning they just broadcast without care who got them or if they got them at all. Out of order, missing or duplicate packets are all fine, no one cares.
Now it's true that under the hood Unity's RPCs are also unreliable, but so is the IP protocol. Unity and TCP/IP are doing some magic to turn those into reliable and ordered packets.
In short,
Use unreliable state synchronization for anything that changes frequently, and save the RPCs for things that you're sure absolutely need to happen, and in the specific order they were sent, such as Player Instantiation or Destruction.
In your case, if you don't want a NetworkView
to send data if it hasn't changed, you can verify that at the beginning of the OnSerializeNetworkView
and just return, and it won't broadcast anything at that time.
Thank you for that incredibly helpful response. You've completely solidified my understanding of state sync and RPCs with a single post. Thank you so much!
As a follow-up question, how would I go about sending something like gunshots? They happen very rapidly and frequently in this game and as it stands (with them being handled by RPCs) there often seems to be a significant lag from when a shot is fired and when the RPC makes its way around to all of the clients. I would rather drop a few shots or have them arrive out-of-order than have the game wait to collect all of them together (when the target has already sprinted five meters out of the way.)
I presume you're handling automatic fire; can you send one RPC when the player starts shooting and one when he stops?
No, gunfire ranges from automatic to semi-automatic to single shots every few seconds. At the moment, when a weapon fires, it fires off an RPC with the location and orientation of the bullet.
I'm wondering if there are methods for skinning these kinds of RPCs down to make them as snappy as possible, such as ignoring buffering and superfluous information such as timestamps.
The client should just say, "Fire a bullet from (here) in (this direction)!" and the other clients should do so as soon as they receive that message.
Well, if you make sure everything is synchronized correctly, you don't have to send the position and orientation of the bullet, right? You can just send 'Fire bullet for me', and the position/orientation should be the same for the other clients as well.
You can, and should, never use the RPC buffer for anything that happens more than once per player. The buffer gets sent in it's entirety every time a player connects, so old RPCs that are irrelevant still get sent. This can clutter your network and waste a lot of bandwidth and computation power on obsolete actions.
$$anonymous$$anaging the RPC buffer can be a painful process as you can't access an individual RPC, but you have to remove entire groups of RPCs from the buffer. Use with extreme caution.
The problem is that the weapons have inaccuracy, which makes fired rounds travel in slightly different directions than the weapons are pointed... so just keeping the weapons oriented in the right directions is not enough information for the trajectory of the bullet. (Though the initial position of the bullet will be the same, so that shaves at least one Vector3 off of my RPC. Thanks!)
Ok good, I have been sending my bullet RPCS unbuffered, yes. It seemed at times like they were being buffered, as there would be a lag in gameplay followed by a clump of bullets popping out of the same place... but I realize now that that is a hardware/network clogging issue, not a buffering issue.
Thank you again for your help!