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

superceded

BridgeNet

Typescript

Description

BridgeNet is a networking library bundled with features to make optimizations easier, alongside optimizing remote events itself. It also has numerous features such as :FireAllInRange, and :FireToMultiple.

Documentation

Documentation here.

Benchmarking / Performance

This performed way better than I expected it to. Test was run w/ 200 blank remote calls sent per frame.
BridgeNet 63 KB/s average:
image

Roblox, 110 KB/s average:
image

Test code is in the github repository.


Why should I care about the amount of data being sent/received?

Because that’s integral to your game’s performance. Less data and calls means lower frame times, lower ping, easier for players with packet loss & bad connections, and overall a better experience. Although, I think that the best way to put it is this. If you have a player cap on your game of 50, and each player is receiving 100 kilobytes per second, that means your server is sending 5000 kilobytes per second. 5000/1000 (kilobytes in a megabyte) is 5, which means you have 5 megabytes being sent out per second. Now, we all know Roblox servers are suboptimal compared to your average dedicated game server. And 5 megabytes… isn’t that much nowadays, right?

Well, in the networking world, megabits are used to measure things like speed. One megabyte is 8 megabits, and things like speedtest.net use megabits (abbreviated as Mb). So, if your internet upload speed is 40 megabits per second, that means running your computer as a server for your Roblox game would result in your entire bandwith being taken up.

(Take this with a grain of salt. I’m not 100% sure why BridgeNet performs better here) So this other thing that BridgeNet does better is ordering. When Roblox sends out packets, it waits to make sure it’s done in all the right orders. I expected BridgeNet to not play nicely with packet loss, but I suppose I am incorrect. I’m pretty sure this is because Roblox orders each remote event individually, so when one doesn’t play nice / gets sent earlier or before, it stops and waits before resuming networking. So the more RemoteEvents that are fired / received, the higher the probability is it stops and waits. With BridgeNet, since it’s one remote call per frame, this isn’t an issue. Roblox already sends packets out per frame, so the big packets aren’t an issue.

This makes 100% sense, and this test proves it, but I’m making an explanation for the results, not the other way around. This is my so to say, very educated guess.

Roblox Remotes
image

BridgeNet
image


Features

  • Easy-to-use utility features such as :FireAllInRange(), :FireAllExcept(), :FireMultiple()
  • Dynamically create/destroy “remote events” with ease
  • Configure the rate of which remotes send and receive information
  • Serialization of RemoteEvents for optimization
  • Using compressed ID strings to reduce the amount of data each remote call takes, mimicking multiple remote calls.
  • Utilities to compress the data you’re sending over such as .DictionaryToTable, and .PackUUID
  • Incredibly easy optimization beyond what’s already provided
  • No direct interaction with instances, that’s all abstracted and wrapped away.
  • InvokeServer (returns a Promise) and InvokeServerAsync allow for “RemoteFunction” usability with promises
  • roblox-ts support!

Goals

  • Make optimization easy, but manual. Don’t intrude on the developer where they don’t expect it, but give them the tools to optimize.
  • Keep a simple and human-readable API while still retaining functionality of other net tools.
  • Make all functionality extra- you don’t need to understand middleware in order to use the module, but if you do, you can use middleware.

If your game starts using BridgeNet, please let me know! The amount of people using BridgeNet lets me realize how battle-tested it is and helps me develop the module. It also helps me know when to fully release!


On the topic of networking, reliablity types are a must.

Due to Roblox’s RemoteEvents being reliable and ordered, it can make systems like head rotation systems cause tons of lag and take up a bunch of unused bandwith. It also means any custom humanoid system like Chickynoid will be less effective than if this feature existed.

This feature would improve the Roblox platform tremendously if added, and I ask you all to support this feature. If this is added, I can assure you BridgeNet will immediately update to have streaming data support.

The lack of this feature is a direct roadblock to many MMOs. It’s one of the biggest roadblocks on the platform right now. Please- take your time and show your support.

303 Likes

you can also replace remotefunction with remoteevent, they are much much faster if you’re looking to optimize that too

14 Likes

Definitely something planned, I intend on integrating promises with it. Although I’m sorting out all the base features right now.

I intend on adding a lot of cool stuff to this once I’m done with the initial setup and optimization. This is the start of a long journey :sweat_smile:

7 Likes

0.2.0-alpha

Get it here

  • Some optimizations and polishing
  • Added .FromBridge(), which lets you get a Bridge object from wherever.
  • Fixed an issue where an unused artifact was being sent, increasing packet size drastically.
  • Fixed multiple documentation mistakes
  • Added a “Getting Started” page to documentation
6 Likes

Wow! This looks really cool.
I would love to use this but I’m kind of a noob at scripting so I don’t understand the API documentation. It would be very much appreciated if you could make a tutorial on this.
I’ll be waiting for the tutorial.

5 Likes

I’ll probably make sometime within the next week or so :sweat_smile: thanks for the feedback!

7 Likes

Amazing resource! There are a lot of networking frameworks out there and it seems that each time a new one releases it only gets better. Not only this makes life easier like others but also has incredible performance results which really caught my attention.

Adding it to my game! :smiley:

3 Likes

Nice resource. Can’t wait to see what comes out of this! :+1:

3 Likes

0.2.1-alpha

Get it here here.

  • Better error handling and messages
  • Errors during send/receive will not repeat due to failure to clear queue
  • If the queue is blank, it will not send.

Also took out some print statements I accidentally left in :sweat:

2 Likes

EDIT 2: After talking with OP, it turns out there was a bit of a miscommunication with the benchmarking test and I actually did the test incorrectly.

AFTER benchmarking it correctly, (firing 200 Remotes every Heartbeat) I can confidently say, this 100% works. :grinning:

Roblox Remotes
image

BridgeNet
image

Across different tests I did after, the average amount of data being sent and received was reduced by about 40~70 KB/s! (Also lines up with OP’s own tests)

This is definitely a revolutionary resource to have and I will 100% use this or something similar to this in future projects! :+1:

EDIT 3: Also there is an insanely reduced ping (At least from my testing)

Roblox Remotes
image

BridgeNet
image

BridgeNet’s ping stays comfortably below 100 ms while regular Roblox Remotes skyrocket above, into the 1000’s, despite being the exact same test. Very impressive work!

10 Likes

(post deleted by author)

3 Likes

Hello, I’m getting this error on the server-side

And this is my setup on the server

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Modules = ReplicatedStorage.Modules
local BridgeNet = require(Modules.BridgeNet)

--

BridgeNet.Start({
	default_send_rate = 60,
	default_receive_rate = 60,
})

I think it is probably it’s creating the bridge before actually completing the task of initialization, you could fix this by adding a variable that tells you when the module is ready for production use

3 Likes

I will make sure to add an error message for this, and I’ve corrected the documentation. I apologize for the mistake on my end, but this is why it’s in alpha :sweat:
It’s actually send_default_rate, and receive_default_rate.

3 Likes

0.3.3-alpha

Get it here.

  • Better error handling / messages
  • Removed unused function in ServerBridge/ClientBridge.
  • Added .CreateUUID(), .PackUUID(), .UnpackUUID(). (ty Pyseph!)
  • Added .DictionaryToTable(), which converts a dictionary into an alphabetically-ordered table.
  • Switched .ChildAdded for the client’s serdeLayer to be in serdeLayer._start()
  • Switched “Network” documentation to be “BridgeNet”- Network was a working title.
  • Removed one_remote_event from config.

Edited for hotfix to .CreateIdentifier and connections.

1 Like

If anyone has any suggestions / ideas for BridgeNet, please mention them here! I’ll see if it fits in with the goals of BridgeNet, and if possible I’ll add it in.

2 Likes

Hi ^

Lucky me to have stumbled upon this at the exact right time. I am trying to rotate character’s waist by sending a value from local script to server and then doing the rotation on the server itself. This works fine, but since I’m using remote events, with many clients it will lag like hell, so I want to use your module.

But since the documentation doesn’t provide some necessary information, I hope you can help me figure this out ^

Here’s how it works without BridgeNet

Client:

function updatewaist(dt)
	
	local cameralookvectorY = workspace.CurrentCamera.CFrame.lookVector.Y
	local radian = math.asin(cameralookvectorY)
	
	if camMove.Value == true then
		repEvent:FireServer(waist, c0*CFrame.fromEulerAnglesYXZ(radian,0,0))
	end
	
end


runService.Heartbeat:Connect(updatewaist)

Server:


replicateEvent.OnServerEvent:Connect(function(sender, waist, rot)
	
	waist.C0 = rot
	
end)

Now questions about implementing bridgenet into this.

  1. It says in the documentation that BridgeNet.Start needs to be called only once for server and client. Does this mean that I need to call BridgeNet.Start only in one server script, and it will work for all the others? And also create it just once for each client, or just create it on the server, and I can use it on the client too without creating?

  2. BridgeNet.CreateBridge(). It says that it creates either a client bridge, or a server bridge, depending on where it’s called. So for example in my case, do I need to just call CreateBridge() on client, and then use Fire() without creating anything on the server? So how would I connect to these bridge on the server.

If you could provide some simple example code of firing a remoteevent to server and then doing something on the server,it would be very helpful. And Thank You for very useful module! If not this I would’ve left my game unfinished, since what I’m trying to achieve is a very important aspect of it (Melee Combat System), and Roblox itself doesn’t provide many tools for ping optimization.

4 Likes

about the start command, i think we shouldnt use a table as an arg. because the table indexes for this module are case-sensitive and people might forget if the index name is this or this, so why not make it like this:

bridgeNet.Start(60, 60)

anyway im interested in this module, i always have wanted to optimize remote events so thanks!

1 Like

This actually showcases a flaw with BridgeNet I’ll get on fixing when available.

As of right now there’s no way to tell when BridgeNet is started. This means you’re kinda forced to use single-script architecture which is something I encourage you to research, but I’m not going to assume everyone who uses BridgeNet will do this.

So, I think what I’m going to do is make functions such as CreateBridge yield until BridgeNet starts. However, it’s possible that it plays nicely without starting because starting BridgeNet connects to heartbeat and all that. I’m still going to make this functions yield until start because I don’t want completely unexpected behavior in my module :sweat_smile:

the code snippet you asked for:
Client

local Object = BridgeNet.CreateBridge("Test")

Object:Connect(function(arg1, arg2, arg3)
	print(arg1)
end)

while task.wait(1) do
	Object:Fire("Hello", "world")
end

Server

local Object = BridgeNet.CreateBridge("Test")

Object:Connect(function(plr, arg1, arg2)
	print(plr, arg1)
end)

while task.wait(1) do
	Object:FireTo(game.Players:GetPlayers()[1], "Received: Fire")
end

To answer your second question, the bridges are just connected by string, and you need to call CreateBridge separately on the client and the server. However, if you need to index a bridge that’s already created, you can do .FromBridge(). As of right now, this will return nil if it doesn’t exist, which means I could probably add in a .WaitForBridge() function to make this process easier.


I think one thing I could do is use symbols instead of text indexes, so it would be like

BridgeNet.Start({
[BridgeNet.DefaultReceive] = 60,
[BridgeNet.DefaultSend] = 60,
})

You’re right, plain text keys are easy to forget and get confused (it’s already happened!), but the reason I don’t want to use the order of arguments is because of how difficult it is to change. Say I want to remove the default send and receive options in a year, what happens then? Backwards compatibility breaks.

And thank you! Every bit of support means a lot to me.

4 Likes

An enum thing is also fine. Thank you for this! will there ever be roblox-ts support too?

1 Like

Thank You!! One more follow up question.

Assuming I use 1 script architecture, I still need to use 1 server script and 1 client script. Do I need to call BridgeNet.Start both on Server and on Client, or just call it only on the server?