That would be a really good library, but there’s one question I’d like to ask. Would there be any way to introduce this in a Rojo workflow? (Visual Studio Code)
A wally package for it exists, if you are lookijg for roblox-ts package that exists too
Will there be an invoke client?
Quick polls
One thing that helps me a lot developing BridgeNet is how battle-tested it is and how many people are using it. Factors like these decide how I want to develop BridgeNet, where I should improve BridgeNet, and overall how safe the module is to use.
- Yes
- No
0 voters
If you don’t use BridgeNet, please message me (on the devforum) what features/design BridgeNet is lacking in order for you to use it.
- I have used it / it is useful to me
- I have never used it
- I don’t know what that is (lacking sufficient documentation)
0 voters
- Yes
- No
- I don’t know what that is (lacking sufficient documentation)
0 voters
- Yes
- No
0 voters
- Yes, I’m okay with it
- No, I would like another way.
0 voters
(Please direct message me for these next questions)
What features (apart from basic :Fire(), :FireTo()) do you use in BridgeNet the most?
What features do you wish were in BridgeNet?
What issues do you have with networking code that BridgeNet doesn’t fix?
2.0.0-rc2
This is a release candidate for 2.0. It is unfinished, unstable, and not ready for production usage- that being said, it would mean a lot to me if anyone could help poke around and help find some bugs / issues. It is only available on wally at the moment under 2.0.0-rc2
- Middleware now is defaulted off if there’s nothing in the table
- Some small improvements
- Renamed
Declare
toCreateBridgeTree
- Exposed the typings
Bridge
,ClientBridge
andServerBridge
to the user. - Added
Bridge:SetReplicationRate()
- Started on a better way of doing releases for wally and non-wally. Kinda experimenting right now!
Again- 2.0 is not stable at the moment.
2.0.0-rc3
This is likely going to be pushed out as 2.0.0- not much left I want to do, this leaves the library in a pretty finished state. After intensive testing & 2.0.0 released, I may consider labeling the library as production-ready.
Roblox marketplace
Github release
ffrostflame/bridgenet@2.0.0-rc3
on Wally
- Multiple :Fire()s can be sent in the same frame
- Performance improvements
- Bugfixes w/ SerdesLayer & replication
- Added more test cases- 2.0.0 should be usable and more stable.
- Fixed invokes
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.
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:
- Client stores tick in a variable and calls :FireServer with no parameters
- Server receives the event and does :FireClient immediately with no parameters
- 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
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)
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?)
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.
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
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.
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?
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
Invoking the client is an anti-pattern. It’s an exploit vulnerability, pretty much.
However, the client can invoke the server through InvokeServerAsync
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)