ByteNet | Advanced networking library w/ buffer serialization, strict Luau, absurd optimization, and rbxts support. | 0.4.3

Is there currently a way to stop listening to packets similar to the Connection:Disconnect() method?

Hey @ffrostfall , it looks like the ByteNet Documentation is missing some information that would be useful to have. Also, the latest Github .rbxm release is 5+ months out of date.

This is an amazing library, and making it open-source was an incredible thing of you to do, so thank you! I just want to give some constructive criticism about the docs page to help those who are struggling.

For one, the docs feel incomplete. They don’t contain standard sections for each custom type, like Packet or Namespace. Also, there isn’t any explanation of how the library handles the creation of these types on the server, then replicates them to the client after the client accesses the library. It’s obvious that’s what happens after poking around in the code, but the docs should also specify that.

Some other issues I noticed:

  1. In the ‘definePacket’ section, under the ‘Sending’ heading:
    Docs are missing server send method ‘sendToList’. It only shows 3 send methods for the server, but in the packet’s code it shows ‘sendToList’ as a 4th method for the server.

  2. The docs aren’t very clear on Namespaces.
    The only mention seen is in the ‘definePacket’ section, where you say they are needed, but no more info is given. In the code for namespace definition it’s clear that they’re just encapsulators for packets, but it would nice for the Docs to have a Section about Namespaces, what they are for, why you need them, etc. In that section, an example of using multiple namespaces, each with their own packets (which can have the same name!), would go a long way.

  3. Packet configuration.
    Right now only Reliability types are able to be configured, but there is no code example of how to do this using the API. Again, digging through the code reveals that you need to include ‘reliabilityType’ in the property table passed to the definePacket() function (this is hinted at in the docs). This is could be a lot clearer from the perspective of a user reading the docs for the first time if the docs included a code example.

  4. Some examples are unclear:
    a) ‘definePacket’ section, in the first example script ‘packets.luau’, where you set up a Namespace and Packet, the packet is named “printSomething”. Later in the section in the code examples, it looks like you’re using the packet defined earlier in packets.luau, but confusingly the packet is now called ‘myPacket’.
    b) ‘definePacket’ section example again,

A final issue unrelated to the documentation:
The latest official release on Github is like 5 months out of date. It was last update March 10th, in which time there have been a ton of updates to the source files and a bunch of forks fixing small problems. For people who don’t use NPM or wally, this is rough! Thanks in advance for updating that!

Thanks for making this awesome library!

11 Likes

Hi! Are you able to return values with ByteNet?

Right now there isn’t support for RemoteFunctions, which is what I’m assuming you’re asking about. FFrostfall left that up to us as devs to handle!

The solution is just to send another packet back with data after your first packet requests it.

is this still being maintained? the last commit was a few months ago

2 Likes

I am trying this module and got everything working.
However, when the game was played by more players, this error pops sometimes:
ReplicatedStorage.ByteNet: message=ReplicatedStorage.ByteNet.process.read:40: attempt to index nil with 'reader', trace=ReplicatedStorage.ByteNet.process.read, line 40 ReplicatedStorage.ByteNet.process.client, line 13 - function onClientEvent

Here are my defined packets:
image
image
image
image
image
image

My game uses deferred events signal behaviour, if that can help.
Any chance this can be fixed ?

This is insane, thanks for making this!

I was looking for this too and just found that you can use

local param = definedNamespace.definedPacket.wait()

and it will return the value which was fired on the client once, didnt test using on server tho since its not within my scope atm

I was able to reproduce this problem by not defining the namespaces on the client. What’s likely the culprit is that you’re sending things to the client before the client can define namespaces. The error is because the packet is nil, so adding this below that line in read will stop the error and drop the event.

if not packet then
	break
end

Alternatively (if the event is important), you can wait for a namespace to exist by adding this beneath the while loop:

local packet = ref[buffer.readu8(incomingBuffer, readCursor)]
local tries = 0

while not packet and tries < 5 and game:GetService("RunService"):IsClient() do
	tries += 1
	packet = ref[buffer.readu8(incomingBuffer, readCursor)]

	if not packet then
		task.wait(1)
	end
end

if not packet then
	return warn("[ByteNet] A packet was dropped - no packet/namespace defined")
end

I doubt that this will be fixed for a while.

1 Like

Good remark, that is in fact possible.
I already opted for the first solution until now (drop the packet).

1 Like

Hey!
Does anyone know if it’s possible to make a ByteNet packet subscribable? (Equivalent to RemoteFunctions)

If you’re looking for a RemoteFunction implementation for ByteNet I recommend @Lightning_Game27’s fork called ByteNet Max : )

https://devforum.roblox.com/t/bytenet-max-upgraded-networking-library-w-buffer-serialisation-strict-luau-and-rbxts-support-v011

2 Likes

How do you send instances using uniqueID’s?

Hi

Okay, my previous response wasn’t great because I thought you had the same issue as me but I made an adjustment to the module to allow for packet disconnections at runtime. Here’s the process below (also if anyone has any improvements to the code I added please let me know):


src/packets/packet.luau

I added a return in the .listen() function to get the index of the listener in my main script.
Next I added a new .disconnect() function which intakes the listenerIndex, and removes it from the table of listeners.

function exported.listen(callback)
	table.insert(listeners, callback)
	return callback
end

function exported.disconnect(callback)
	for i, listener in pairs(listeners) do
		if listener == callback then
			table.remove(listeners, i)
			break
		end
	end
end

Here’s how it looks in my script:


script.lua

local packet = require(path.to.packet)

local connection = packet.packetName.listen(function(data)
	...code here...
end)

-- When you're ready to disconnect
packet.packetName.disconnect(connection)
connection = nil

I tested this in my code and it seems to work as expected, hope this helps anyone who’s had trouble with this, hopefully ffrostfall adds this natively soon!

EDIT: I noticed an issue with this where if you removed a certain listener say index 2, but the total listeners are say 5, this would push back the listener table indices which would make the other listeners defined after index 2 invalid. Instead I’m just returning the callback function now into the variable so that way when you disconnect it checks the for the function rather than index tho there’s probably a better way to do this, but I’m not entirely sure and dont have the time to figure it out rn, I updated the scripts with the fix…

2 Likes

anybody know the difference between this and red?

Red doesn’t use buffers and is deprecated. A better question is a difference between ByteNet and Zap.

Generally, Zap is easier to use and ByteNet has slightly better performance. But others might it see differently with ease of use.

1 Like

Hello! Im looking through the documentation and I’m a bit confused as to what define Namespace actually does. What does passing the string value actually do?

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ByteNet = require(ReplicatedStorage.ByteNet)

return ByteNet.defineNamespace("messaging", function() -- what does the string "messaging" do?
	return {
		printSomething = ByteNet.definePacket({
			-- This value field is very important!
			reliabilityType = 'unreliable',
			value = ByteNet.struct({
				message = ByteNet.string,
			})
		}),
		Other = ByteNet.definePacket({
			reliabilityType = 'reliable',
			value = ByteNet.bool,
			
		})
	}
end)

Namespaces allow different groups of packets, allowing ByteNet to organise them. This means u could have the same ‘printSomething’ packet under “messaging” and “sending” namespace for example. As ffrostfall himself says: “Because the ordering needs to be consistent and deterministic, and this ordering is relied on to sync client/server structs.”

1 Like

Why isn’t there a .Disconnect/destroy function

ByteNet uses a singular remote event. There’s no point disconnecting one function.