BridgeNet | Insanely optimized, easy-to-use networking library full of utilities, now with roblox-ts! | v1.9.9-beta

Is there any setup tutorials anywhere?

I see you removed WaitForBridge. What can I use instead? This breaks a ton of code. I wrote around that function existing.

1 Like

You should theoretically be able to use CreateBridge.

Hello @ffrostfall,

I am really impressed with everything you’ve done here - the github page, the documentation, etc. It’s all very well organized. However, something stood out to me that and is your ping measurements. I wondered: how can something that uses RemoteEvents to send over data be faster than the RemoteEvents themselves? It’s somewhat a paradox.

I had a theory, but to test it, I created an empty baseplate. I would measure ping by doing the following with both Roblox’s remote event API and your own API:

  1. Client stores tick in a variable and calls :FireServer with no parameters
  2. Server receives the event and does :FireClient immediately with no parameters
  3. Once the client receives the event, it subtracts the current tick from the stored one to get the elapsed time.

This is a very simple but rigorous method to test the ping of a specific network event. I tested 100 requests after waiting 5 seconds on the client for any more lag due to replication/first joining to settle. The environment is exactly the same. After putting it to the test, there were the results:

Results

image
BridgeNet consistently gets ~60ms, while roblox gets ~40ms. Although Roblox’s time is far more spread out, the overall difference between the two makes it negligent.

I do have an explanation for this and why it is different from your results:
I believe the way your system queues the results and sends them once per frame slowly allows the packet size to be smaller overall and allows roblox to more quickly send packets that are used to measure ping, however this is at the cost of the speed in which the server/client receives data. Although Roblox’s stats show the ping to be low, that is not a measurement of how long it takes for the data going through the BridgeNet to reach the server, its a measurement that ROBLOX takes internally. The actual time it takes for the server to receive the event, particularly when done multiple times per frame, takes tremendous amounts of time, (>1000ms).

Personally, I’m almost certain that ROBLOX already handles serialization of instances and compression on the backend for anything sent over the network. In fact, I’m certain most multiplayer games do; compression algorithms have been one of the most researched and developed algorithms I can think of. I totally agree with your last statement though. ROBLOX should have an alternative API for handling data that is loss-tolerable (UDP).

TL;DR: My main complaint is that your original post describes it as if there are no cons. Overall, this system is great if the delay between when the packet is sent and received isn’t important; however, this isn’t always the case (for example, when a player hits an enemy and the client requests the enemy to be damaged. Speed is very important here!)

I have attached the Google Sheets file with the data along with the place file with the test scripts of both ROBLOX and BridgeNet.
Testing game (90.4 KB)
Spreadsheet download (35.1 KB)

4 Likes

I see. Could you update the documentation? It’s very out of date and I find it hard to keep up with the frequent breaking changes. Fortunately, I can find/replace all bridgenet calls to a wrapper module (which may be the done way anyway?)

1 Like

You’re fundamentally misinterpreting what BridgeNet does. “how can something that uses RemoteEvents to send over data be faster than the RemoteEvents themselves?” I never claim to be faster as in less ping, I claim to use less data, which is true.

“however this is at the cost of the speed in which the server/client receives data.” Actually, this is a bug with 2.0.0. I don’t think you’ll see this sort of behavior in earlier versions- and if you do, please report it. 2.0.0-rc3 is short for 2.0.0 release-candidate 3, which means that it’s an unstable version that isn’t ready for production usage. I introduced variable replication rates (replicating some remotes at 20hz), and in that I suppose I must have code that accidentally waits one more frame per remote call. I’ll definitely be investigating and fixing this.

“Personally, I’m almost certain that ROBLOX already handles serialization of instances and compression on the backend for anything sent over the network.” No, they don’t unfortunately.

Blank remote call: ~9 bytes

string (len 0): 2 bytes
string (len 1): 4 bytes
string (len 2): 8 bytes
string (len 3): 9 bytes
string (len 4): 10 bytes
string (len 5): 11 bytes
string (len 6): 12 bytes
string (len 8): 14 bytes
string (len 16): 22 bytes
string (len 32): 36 bytes

boolean: 2 bytes
number: 9 bytes

table (empty): 2 bytes
table (array with 4 numbers): 38 bytes

EnumItem: 4 bytes
Vector3: 13 bytes
CFrame (axis aligned): 14 bytes
CFrame (random rotation): 20 bytes

Source listed here: In-Depth Explanation of Roblox's RemoteEvents, Instance Replication, and Physics Replication (w/ sources!)

Your post does actually remind me of another critical flaw of Roblox though- we don’t have the ability to tap into when networksteps happen, and do behavior on those steps. Feature request is here, if you want to support it! RunService.NetworkStepped Event

I actually really appreciate this post because it brought attention to a bug in 2.0.0, which is an unstable version. Thank you! Oh, and one more thing: Any test you do is going to be fundamentally flawed, because network receive is done at the beginning of the frame, however code that reacts to it will not take effect until later stages, so the ping there is mostly irrelevant.

8 Likes

I’ll be updating the documentation when 2.0.0 is fully ready- as shown by the above post, it is not ready at the moment.

i’m scared of writing all the documentation though not gonna lie

1 Like

Even incremental updates would be nice! I have no idea how to use new bridgenet and can’t figure out how to modify my code to support it. I might just use regular network events until then.

this is a must have, i am definetely going to use this for my current and future projects.

2 Likes

I’m confused;
Roblox Remotes
Sent: 426.82 KB/s
Received: 541.99 KB/s

BridgeNet
Sent: 496.77 KB/s
Received 496.07 KB/s

With bridgenet you’ve received 0.70 KB/s less than you sent,
doesn’t that imply the amount of data sent wasn’t fully received? ie; data loss?

1 Like

It’s separate numbers afaik, it’s not passing the value through and then back again.
Also- there’s variance, you shouldn’t rely on exact numbers like that because Roblox has net code that gets logged in there too.

I really like this module but how can I invoke from server to client and why you haven’t add remote function APIs

1 Like

Invoking the client is an anti-pattern. It’s an exploit vulnerability, pretty much.

However, the client can invoke the server through InvokeServerAsync

1 Like

Hi,

When I run the test below it does not show the correct values and returns a table for Val1 and nil for Val2 and 3.

What am I doing wrong?

23:06:25.493 plr CanterCrow - Server - BNet-Client-To-Server-SS:7
23:06:25.493 Val1 table: 0x986ee00f34d665e4 - Server - BNet-Client-To-Server-SS:8
23:06:25.493 Val2 nil - Server - BNet-Client-To-Server-SS:9
23:06:25.493 Val3 nil - Server - BNet-Client-To-Server-SS:10

–Local Script
local BridgeNet = require(game.ReplicatedStorage.Modules.BridgeNet)
BridgeNet.Start({})
local ClientRemoteLS = BridgeNet.CreateBridge(“Remote”)
while true do
ClientRemoteLS:Fire(“Val1”, “Val2”, “Val3”)
task.wait(1)
end

–Remote Script
local BridgeNet = require(game.ReplicatedStorage.Modules.BridgeNet)
BridgeNet.Start({})
local ClientRemoteSS = BridgeNet.CreateBridge(“Remote”)
ClientRemoteSS:Connect(function(plr, Val1, Val2, Val3)
print("plr " … tostring(plr))
print("Val1 " … tostring(Val1))
print("Val2 " … tostring(Val2))
print("Val3 " … tostring(Val3))
end)

1 Like

Apologies for this- this is due to an oversight I missed in testing. This will be fixed in 2.0.0-rc4, which should come out soon-ish (I would say within 2 days or so). I’ve been working pretty hard on it.

This is very interesting and cool, but is there a tutorial on this? Sorry, I’m not that great at scripting and don’t know a lot about this stuff.

Will there be some way of deciding the data type in Declare? Apparently you can get way better results doing stuff like encoding ints from 0 to 255 as bytes, as well as big savings from obscure data types like Vector3int16. It would be great if there was functionality for this.

There’s functionality planned, however this is separate to RemoteEvents- I plan on creating an abstraction for string.pack

I’m working pretty hard on 2.0 which is already jam-packed with improvements, so this likely won’t come soon.

2.0.0-rc4

Reminder- rc stands for release candidate. This version, and this module, are unstable. It’s available on the Roblox marketplace, and on Wally under ffrostflame/bridgenet@2.0.0-rc4. I will be updating the roblox-ts port when 2.0.0 fully releases.

  • Unpacked arguments on server receive (Thank you @MELON-Om4r)
  • Fixed numerous queue-related bugs
  • Invoke UUIDs are now packed for less network usage (34 bytes → 18 bytes)
  • The Identifiers function is a closure again
  • Added outbound middleware
  • Added middleware to the client
  • Middleware now passes in the plr argument on the server
  • Overall middleware improvements
  • Client-sided improvements w/ connections
  • Added .GetQueue() for debugging purposes
  • General improvements to client receive
  • Temporarily removed warning signals until I can figure out a better way to add them, they’re kind of a mess right now.
  • Removed config symbols
  • Removed logging features- it turns out I forgot to fully implement them, plus nobody used them.
  • Removed BridgeNet.Start(), the module now runs when you require it for the first time.
  • Removed :InvokeServer()
  • Removed both dependencies

I’m very happy with the current state of BridgeNet. This update should help accessibility and usability across architectures, and it also significantly speeds up development. I will be releasing 2.0.0 likely soon.

1 Like

I keep getting this error everytime I try to run my code:

  14:26:38.266  Infinite yield possible on 'ReplicatedStorage:WaitForChild("AutoSerde")'  -  Studio
  14:26:38.266  Stack Begin  -  Studio
  14:26:38.266  Script 'ReplicatedStorage.Utils.BridgeNet.SerdesLayer', Line 38 - function _start  -  Studio - SerdesLayer:38
  14:26:38.267  Script 'ReplicatedStorage.Utils.BridgeNet', Line 73  -  Studio - BridgeNet:73
  14:26:38.267  Stack End  -  Studio

The code:

Client:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local BridgeNet = require(ReplicatedStorage.Utils.BridgeNet)

local Remote = BridgeNet.CreateBridge("Remote")

Remote:Connect(function(stringA, stringB)
	print(stringA .. stringB) -- Prints
	-- Hello, world!
	-- Hello, someone!
end)

Server:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local BridgeNet = require(ReplicatedStorage.Utils.BridgeNet)

local Remote = BridgeNet.CreateBridge("Remote")

while true do
	Remote:FireAll("Hello, ", "world!") -- Fires to everyone
	Remote:FireTo(game.Players.Someone, "Hello, ", "someone!") -- Fires to a specific player
	task.wait(1)
end