Introducing UnreliableRemoteEvents

“unreliable” just makes it sound like that you shouldn’t use it, because it is so unreliable, sorry if i’m speaking some stupid stuff, but it just sounds like that

2 Likes

That’s exactly part of the intent of the naming!

Only advanced users will be able to make effective use of UnreliableRemoteEvent. The “unreliable” is a big flashing warning to less experienced users to stay away or look at the documentation before they proceed, because it’s very easy to get yourself into trouble by using unreliable remotes unless you know what you’re doing.

For example, an inexperienced user may put unreliable remotes in their game, see “Hey, it runs faster, great!”… and not realize that their experience is going to break when people play it over Wifi because they were testing over their high quality wired connection which is unlikely to drop packets even with an unreliable remote.

13 Likes

so that’s why it’s called that, makes sense now, thanks!

2 Likes

So, I’ve heard people say that this will be good for games like first person shooters, but how exactly? Would I want to use it for shooting guns, and other rapid fire actions?

Say my gun uses something to repeatedly send remote events to tell the server to raycast. Would I be better off using normal remotes, or unreliable remotes?

Unreliable remote events are used for sending streams of data where it doesn’t matter if one or more packets are dropped. A common application would be replicating look angles.

You’ll have to be careful when using unreliable remote events for replicating fired bullets as that information could be lost entirely, thus effectively making the bullet not count at all. This is confusing for the player.

As a rule of thumb, only use unreliable events for frequent, (insignificant) data streams which update old information. In all other cases, use regular remote events.

3 Likes

It’s called a UnreliableRemoteEvent … because it’s unreliable? ReplicationEvent makes absolutely no sense whatsoever from the derived instance RemoteEvent and doesn’t hint on the word unreliable that it was made for.

4 Likes

I was wondering, what % of packets generally get dropped using UDP/Unreliable remotes? For mobile data? For your average connection?

Would it be worth using for something that is only sent about once per second?

2 Likes

Thank you so much this is pretty useful.

I think I would’ve preferred if it was a property in the RemoteEvent object instead of another instance completely.

4 Likes

An average is near useless when you don’t know how good a connection will be in advance. Simply don’t make any assumptions about packet loss frequency.

What are you sending once per second?

Also, please read an earlier response of mine.

3 Likes

Seems sort of pointless but cool

1 Like

im gonna have to say the obvious here but i think this is pretty unreliable

3 Likes

So, when you use these and you don’t care if an event is dropped, but you don’t really want to process them out of order, do you use some sort of tick timestamp to disregard processing an ‘older’ event after a newer one has been received ?

Yes.

Awesome minimum characters!

1 Like

In a game I work on we have the orientation of someone’s head, neck and torso based on the angle of their camera. Let’s call this “HeadRotation”

It sends these three CFrames to the server each 8 heartbeats. (IF these have changed, that is)

The server stores whatever the clients send over and sends the entire list to all clients each 8 heartbeats. (I am aware that it is not synced up with the heartbeats on the clients)

Now this feels like an opportunity, but how many bytes do CFrames need?

I think I’ll go for one unreliable request to the server and an unreliable request to all clients for each user’s HeadRotation separately.

Will that work? Will that be better? I have no insight on how the network exactly behaves.

If CFrames take too much bytes, do I have to encode them with a tiny quality loss?

I honestly don’t know, feedback is appreciated.

I would use a RemoteFunction, it will yield until the server has processed the request.

(Firing the RemoteEvent once is already more than enough to cause the server to process the event; the only thing you need is to wait for the server to finish processing the request. Which is something RemoteFunctions do amazingly.)

1 Like

I would rather use a normal RemoteEvent in your case unless you are only comparing then with previously sent packets.
You would actually have to wait for the future packets to arrive if you wanted to compare them to the future packets.
Most you can do is compare it to previously received packets or else you might be waiting for nothing since some of the future packets might be dropped.

Generally I’d not use them if:

  • you don’t want dropped packets;
  • order matters a lot; or
  • you can replace the functionality with something that runs entirely on the client.

Wow, thanks! They actually worked perfectly in my case.

1 Like

It’s an ideal use case for unreliable remotes since it (presumably) purely visual.

CFrames are compressed into up to 20 bytes by the engine if you send them over the network so would be up to 5 kb/s plus some additional overhead for each time a remote event is used (so on the server you should ideally use only a single remote event call to send all head rotations which you already seem to be doing) if you send 8 of them per second for 32 players.

For optimization you probably shouldn’t be using CFrames but use Vector3s instead since all you probably need to send is the look vector of the CFrame/the direction the character is looking at which would bring that down to 12 bytes.

Since that look vector is always a unit vector you could even further compress that to avoid sending redundant information over the network by projecting the coordinates of the sphere that make up all possible unit vectors onto a 2D plane in which case you should be able to compress it down to 4 bytes if you want it to be reasonably precise or even just 2 bytes if you don’t mind a maximum error of 1-2 degrees, though this probably isn’t really necessary for you.

1 Like

Replication =/= remote

Replication event is past tense.

Thanks for the tip!

Encoding HeadRotation
I’ve decided to only grab the X and Y of the LookVector as I’d only need these for all of the custom player models to calculate the three CFrames, next to that I’m now sending the head rotation to the server at either each change of at least 0.01 on the LookVector.X or LookVector.Y OR if 300 heartbeats have passed.

Next to that I’ve encoded the LookVector.X and LookVector.Y into one number ranging 0-999999 allowing me up to a precision of 0.002 ranging from -1 to 0.998 for both LookVector.X and LookVector.Y.

On the server I’ve decided to make all nearby players replicate to the target player each time, but far away players only replicate per <x> heartbeats, variable per distance.

The server then sends an array of {UserId, Encoded LookVector, UserId, Encoded LookVector, etc.} for all the selected players to replicate to the target user.

The target user then decodes this LookVector and calculates the CFrames for the head rotation, this happens in parallel scripting.
Then in synchronised scripting it applies all the CFrames.

Further encoding + Use of buffers
I think that would take about 18 bytes per player, but I can make it smaller by removing the need for a userid.
I could give all users in the server a separate attribute instead of an id, and re-use ids that are no longer used; having around 45 “ids” as attributes, which still fit in the same 8 bytes number.
Even smaller would be possible if Roblox releases buffers I think;
I could store it as:
1 8-bit unsigned int for the attribute “id”
1 8-bit unsigned int for LookVector.X with precision 1/256th
1 8-bit unsigned int for LookVector.Y with precision 1/256th
Theoretically letting me use 3*playerquantity bytes.

Feedback?
I wonder if that’s the most I can do and if my optimisations are good, but right now this should be sufficient for a full server (45 players for the target experience) through one single packet. Correct me if I’m wrong

Another case
Next to that I decided to make analytics CLICK-EVENT calls (I store analytics data to see what buttons are clicked the most) unreliable too. These events fire each click on a gui button and aren’t too important, a little unreliability is fine on these I think. Though I can still encode these events to a number for each type of event. And I could queue them, sending multiple of them together and using buffers.

Ps: Sorry for going slightly offtopic, as encoding with buffers should fall under the other topic