ByteNet provides a large amount of "primitive" types for you to build more complex types that suit your game. Since primitive types don't need any parameters, you can just access them like the following: ByteNet.<typename>. For building more complex data structures, go look at the Specials page.
Special types always take parameters. You have to call them: ByteNet.<type name>(<any primitive type>).
Danger
-
There are drawbacks to using these!
Using these types incurs 1-2 bytes of overhead due to the dynamic nature.
They take drastically more time to parse
@@ -703,77 +706,92 @@
There are drawbacks to using these!<
+
Structs
+
Structs let you send structured data in the form of dictionaries. The fields are optimized away, so they don't take any bandwidth. Structs are how you'll be sending most of your data likely: they are the best for organization, and they let you do really interesting things. For example:
+
Optional types are a cool name for the concept of "This doesn't have to exist". It's good for optional parameters: for example if some invoked function were to fail, you might want to send back a blank copy to indicate that something is wrong.
-
packets.luau
return{
-myCoolPacket=ByteNet.definePacket({
-structure={
--- An "optional" type takes in a parameter.
--- This can be anything! You can even have optional arrays.
-helloWorldString=ByteNet.optional(ByteNet.string)
-
--- This works!
-eachCharacter=ByteNet.optional(ByteNet.array(ByteNet.string))
-},
-})
-}
+
packets.luau
returnByteNet.defineNamespace("chunks",function()
+return{
+myCoolPacket=ByteNet.definePacket({
+value=ByteNet.struct({
+-- An "optional" type takes in a parameter.
+-- This can be anything! You can even have optional arrays.
+helloWorldString=ByteNet.optional(ByteNet.string)
+
+-- This works!
+eachCharacter=ByteNet.optional(ByteNet.array(ByteNet.string))
+}),
+})
+}
+end)
You really don't have to think about using optional types. You just send it!
-
server.luau
localpackets=require(path.to.packets)
-
-localrandomlyStringOrNil=
-ifmath.random(1,2)==1then"Hello, world!"elsenil
-
-packets.myCoolPacket:sendToAll({
-helloWorldString=randomlyAppearingString,
-
--- Note that even if we don't put the "eachCharacter" field here,
--- it won't error. This is because it's optional!
-})
+
server.luau
localpackets=require(path.to.packets)
+
+localrandomlyStringOrNil=
+ifmath.random(1,2)==1then"Hello, world!"elsenil
+
+packets.myCoolPacket.sendToAll({
+helloWorldString=randomlyAppearingString,
+
+-- Note that even if we don't put the "eachCharacter" field here,
+-- it won't error. This is because it's optional!
+})
Arrays
Arrays are fairly self explanatory. They're just plain old arrays. However, it's important to note that mixed tables have undefined behavior when passed as an array. This means things might be missing when they come out on the other side!
There is a 2 byte overhead to sending an array in ByteNet. This is because these 2 bytes are an unsigned 16-bit integer, which stores the array length. As a side effect, arrays sent through ByteNet have a max length of 2^16, which is equal to 65,536. It's likely that in the future, you will be able to reduce the overhead to 1 byte through configuration, in turn reducing the max length of the array.
localpackets=require(path.to.packets)
-
-packets.myCoolPacket:sendToAll({
--- Important to note that mixed arrays/arrays with holes
--- shouldn't be sent through.
-myArray={true,false,true}
-})
+
server.luau
localpackets=require(path.to.packets)
+
+packets.myCoolPacket.sendToAll({
+-- Important to note that mixed arrays/arrays with holes
+-- shouldn't be sent through.
+true,false,true
+})
Maps
Maps are by far the most powerful "special" type in ByteNet. They let you send, what's most commonly referred to as a dictionary, through ByteNet. However it's important to keep in mind two things: the type of the key (or index), and the type of the value, cannot change.
Like arrays, maps have a 2-byte overhead to store the length of the map. This is done by iterating over the map using generic iteration and increasing a variable by 1 for every key-value pair. This, once again, means that there is a 2^16 (which equals to 65,536) cap to the number of elements in the map.
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api/functions/definePacket/index.html b/api/functions/definePacket/index.html
index 99f3ef3..c1853d2 100755
--- a/api/functions/definePacket/index.html
+++ b/api/functions/definePacket/index.html
@@ -41,14 +41,18 @@
-
-
+
+
-
+
-
+
+
+
+
+
@@ -713,19 +717,19 @@
what even is a packet in ByteNe
ByteNet's purpose as a library is to provide a way to structure your data, and send that structure in a hyper-optimized way.
Okay, where do I start?
-
I highly recommended storing all of your packets in a single, shared module, and then using a dictionary to access the individual packets. Not only does this make using ByteNet a breeze, it also gives you a better form of typechecking.
-
The keys of your packet determine the ID it gets. The server and the client sharing this key is essential: that's the core of how ByteNet works. Unfortunately, this means you cannot have duplicate contents of packets. This may change in the future.
-
Enough of how it works, let's start off with making a basic packet:
+
Enough of how it works, let's start off with making a basic packet. We will also need to create a namespace:
packets.luau
localByteNet=require(path.to.bytenet)
-return{
-printSomething=ByteNet.definePacket({
--- This structure field is very important!
-structure={
-message=ByteNet.string,
-}
-})
-}
+returnByteNet.defineNamespace("messaging",function()
+return{
+printSomething=ByteNet.definePacket({
+-- This value field is very important!
+value=ByteNet.struct({
+message=ByteNet.string,
+})
+})
+}
+end)
Sending
@@ -739,40 +743,40 @@
Sending
send
-
These functions must obey your structure created in definePacket, and if you have strict typing on, an error will be raised if the types do not match.
+
Any data passed through these functions must obey your structure created in definePacket, and if you have strict typing on, an error will be raised if the types do not match.
code examples
client.luau
-- Sending to server
-packets.myPacket:send({
+packets.myPacket.send({message="Hello, world!"})
server.luau
-- Sending to all players
-packets.myPacket:sendToAll({
+packets.myPacket.sendToAll({message="Hello, players!"})-- Sending to an individual playerlocalsomeArbitraryPlayer=Players.You
-packets.myPacket:sendTo({
+packets.myPacket.sendTo({message="Hello, random player!"},someArbitraryPlayer)-- Sending to all except a certain playerlocalsomeArbitraryPlayer=Players.You
-packets.myPacket:sendToAllExcept({
+packets.myPacket.sendToAllExcept({message="Hello, everyone except one person!"})
Receiving
You can use the listen method to listen for when a packet is received.
In ByteNet, you don't need to worry about type validation, optimization, packet structure, etc. ByteNet does all the hard parts for you! Strictly typed with an incredibly basic API that explains itself, ByteNet makes networking simple, easy, and quick.
localByteNet=require(path.to.ByteNet)
-localpackets={
-myPacket=ByteNet.definePacket({
-structure={
--- A map where the key is a Vector3, and the value is a string
-map=ByteNet.dataTypes.map(ByteNet.dataTypes.vec3(),ByteNet.dataTypes.string())
-}
-})
-}
+returnByteNet.defineNamespace("example",function()
+return{
+vectorStringMap=ByteNet.definePacket({
+value=ByteNet.dataTypes.map(ByteNet.dataTypes.vec3(),ByteNet.dataTypes.string())
+})
+}
+end)
-
+
example of sending a packet to all clients
server.luau
localpackets=require(path.to.packets)
-packets.myPacket:sendToAll({
-map={
-[Vector3.new(1,1,1)]="10x less bandwidth than a remote!",
-[Vector3.new(1,2,1)]="oh wait, its way more than 10x less.",
-
-[Vector3.new(2,1,1)]="depending on how you use your data,",
-[Vector3.new(1,1,2)]="it could be 100x less!",
-}
-})
+packets.myPacket.sendToAll({
+[Vector3.new(1,1,1)]="10x less bandwidth than a remote!",
+[Vector3.new(1,2,1)]="oh wait, its way more than 10x less.",
+
+[Vector3.new(2,1,1)]="depending on how you use your data,",
+[Vector3.new(1,1,2)]="it could be 100x less!",
+})
+
+
+
+
+
Not enough? here's more
+
+
No more RemoteEvents
+ByteNet handles all instances for you; you don't need to worry about reliability type, parenting, etc
+
+
- As low-level as you can get
+ByteNet lets you directly read/write data types such as uint32, buffers, in a way where the keys are abstracted away. Reap the benefits of a structured, strictly typed library, while retaining the benefits of hardcore optimization.
+
-
-
Not enough? here's more
-
- No more RemoteEvents
-
ByteNet handles all instances for you; you don't need to worry about reliability type, parenting, etc
-
- As low-level as you can get
-
ByteNet lets you directly read/write data types such as uint32, buffers, in a way where the keys are abstracted away. Reap the benefits of a structured, strictly typed library, while retaining the benefits of hardcore optimization.
In ByteNet, you don't need to worry about type validation, optimization, packet structure, etc. ByteNet does all the hard parts for you! Strictly typed with an incredibly basic API that explains itself, ByteNet makes networking simple, easy, and quick.
Getting started Download
practical example of a packet's definition
packets.luau
local ByteNet = require(path.to.ByteNet)\n\nlocal packets = {\n myPacket = ByteNet.definePacket({\n structure = {\n -- A map where the key is a Vector3, and the value is a string\n map = ByteNet.dataTypes.map(ByteNet.dataTypes.vec3(), ByteNet.dataTypes.string())\n }\n })\n}\n
example of sending a packet to all clients
server.luau
local packets = require(path.to.packets)\n\npackets.myPacket:sendToAll({\n map = {\n [Vector3.new(1, 1, 1)] = \"10x less bandwidth than a remote!\",\n [Vector3.new(1, 2, 1)] = \"oh wait, its way more than 10x less.\",\n\n [Vector3.new(2, 1, 1)] = \"depending on how you use your data,\",\n [Vector3.new(1, 1, 2)] = \"it could be 100x less!\",\n }\n})\n
"},{"location":"#not-enough-heres-more","title":"Not enough? here's more","text":""},{"location":"#-no-more-remoteevents","title":"- No more RemoteEvents","text":"
ByteNet handles all instances for you; you don't need to worry about reliability type, parenting, etc
"},{"location":"#-as-low-level-as-you-can-get","title":"- As low-level as you can get","text":"
ByteNet lets you directly read/write data types such as uint32, buffers, in a way where the keys are abstracted away. Reap the benefits of a structured, strictly typed library, while retaining the benefits of hardcore optimization.
ByteNet provides a large amount of \"primitive\" types for you to build more complex types that suit your game. Since primitive types don't need any parameters, you can just access them like the following: ByteNet.<typename>. For building more complex data structures, go look at the Specials page.
Special types are how complex packet types are made. They can take in nearly any type, including themselves, and most importantly they are dynamic. This means you can have an array of any length, a map of any key type and any value type, and an optional value of any type.
Special types always take parameters. You have to call them: ByteNet.<type name>(<any primitive type>).
Danger
"},{"location":"api/dataTypes/Specials/#available-special-types","title":"Available special types","text":""},{"location":"api/dataTypes/Specials/#there-are-drawbacks-to-using-these","title":"There are drawbacks to using these!","text":"
Using these types incurs 1-2 bytes of overhead due to the dynamic nature.
They take drastically more time to parse
They are heavier on memory usage, as a new closure is created each time. You will never have to worry about this unless you have dozens of packets, though.
Optional types are a cool name for the concept of \"This doesn't have to exist\". It's good for optional parameters: for example if some invoked function were to fail, you might want to send back a blank copy to indicate that something is wrong.
packets.luau
return {\n myCoolPacket = ByteNet.definePacket({\n structure = {\n -- An \"optional\" type takes in a parameter.\n -- This can be anything! You can even have optional arrays.\n helloWorldString = ByteNet.optional(ByteNet.string)\n\n -- This works!\n eachCharacter = ByteNet.optional(ByteNet.array(ByteNet.string))\n },\n })\n}\n
You really don't have to think about using optional types. You just send it! server.luau
local packets = require(path.to.packets)\n\nlocal randomlyStringOrNil = \n if math.random(1, 2) == 1 then \"Hello, world!\" else nil\n\npackets.myCoolPacket:sendToAll({\n helloWorldString = randomlyAppearingString,\n\n -- Note that even if we don't put the \"eachCharacter\" field here,\n -- it won't error. This is because it's optional!\n})\n
Arrays are fairly self explanatory. They're just plain old arrays. However, it's important to note that mixed tables have undefined behavior when passed as an array. This means things might be missing when they come out on the other side!
There is a 2 byte overhead to sending an array in ByteNet. This is because these 2 bytes are an unsigned 16-bit integer, which stores the array length. As a side effect, arrays sent through ByteNet have a max length of 2^16, which is equal to 65,536. It's likely that in the future, you will be able to reduce the overhead to 1 byte through configuration, in turn reducing the max length of the array.
local packets = require(path.to.packets)\n\npackets.myCoolPacket:sendToAll({\n -- Important to note that mixed arrays/arrays with holes\n -- shouldn't be sent through.\n myArray = { true, false, true }\n})\n
Maps are by far the most powerful \"special\" type in ByteNet. They let you send, what's most commonly referred to as a dictionary, through ByteNet. However it's important to keep in mind two things: the type of the key (or index), and the type of the value, cannot change.
Like arrays, maps have a 2-byte overhead to store the length of the map. This is done by iterating over the map using generic iteration and increasing a variable by 1 for every key-value pair. This, once again, means that there is a 2^16 (which equals to 65,536) cap to the number of elements in the map.
local packets = require(path.to.packets)\n\npackets.myCoolPacket:sendToAll({\n people = {\n john = 21,\n jane = 24,\n dave = 26,\n you = 162,\n }\n})\n
"},{"location":"api/functions/definePacket/","title":"definePacket","text":"Defining a packet"},{"location":"api/functions/definePacket/#what-even-is-a-packet-in-bytenet-anyway","title":"what even is a packet in ByteNet anyway?","text":"
Packets are the structured dictionaries you use to define the \"format\" your data is going to be sent in. These are named packets as you 'send' packets through network, and packets have their contents usually formatted in a specific way because, well they have to be.
ByteNet's purpose as a library is to provide a way to structure your data, and send that structure in a hyper-optimized way.
"},{"location":"api/functions/definePacket/#okay-where-do-i-start","title":"Okay, where do I start?","text":"
I highly recommended storing all of your packets in a single, shared module, and then using a dictionary to access the individual packets. Not only does this make using ByteNet a breeze, it also gives you a better form of typechecking.
The keys of your packet determine the ID it gets. The server and the client sharing this key is essential: that's the core of how ByteNet works. Unfortunately, this means you cannot have duplicate contents of packets. This may change in the future.
Enough of how it works, let's start off with making a basic packet: packets.luau
local ByteNet = require(path.to.bytenet)\n\nreturn {\n printSomething = ByteNet.definePacket({\n -- This structure field is very important!\n structure = {\n message = ByteNet.string,\n }\n })\n}\n
On the server, there are 3 methods of sending packets to players. It's important to note that when a player should be specified, it's the second parameter given, not the first. This is an intentional design choice.
sendToAll
sendToAllExcept
sendTo
On the client, there is only one, because you can only send data to the server:
send
These functions must obey your structure created in definePacket, and if you have strict typing on, an error will be raised if the types do not match.
code examples client.luau
-- Sending to server\npackets.myPacket:send({\n message = \"Hello, world!\"\n})\n
server.luau
-- Sending to all players\npackets.myPacket:sendToAll({\n message = \"Hello, players!\"\n})\n\n-- Sending to an individual player\nlocal someArbitraryPlayer = Players.You\n\npackets.myPacket:sendTo({\n message = \"Hello, random player!\"\n}, someArbitraryPlayer)\n\n-- Sending to all except a certain player\nlocal someArbitraryPlayer = Players.You\n\npackets.myPacket:sendToAllExcept({\n message = \"Hello, everyone except one person!\"\n})\n
Currently, the only config accessible right now is reliability types. This will change as time goes on, however right now, you can switch reliability types by defining reliabilityType to be \"reliable\" or \"unreliable\".
"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"simple buffer-based networking
In ByteNet, you don't need to worry about type validation, optimization, packet structure, etc. ByteNet does all the hard parts for you! Strictly typed with an incredibly basic API that explains itself, ByteNet makes networking simple, easy, and quick.
Getting started Download
practical example of a packet's definition
packets.luau
local ByteNet = require(path.to.ByteNet)\n\nreturn ByteNet.defineNamespace(\"example\", function()\n return {\n vectorStringMap = ByteNet.definePacket({\n value = ByteNet.dataTypes.map(ByteNet.dataTypes.vec3(), ByteNet.dataTypes.string())\n })\n }\nend)\n
example of sending a packet to all clients
server.luau
local packets = require(path.to.packets)\n\npackets.myPacket.sendToAll({\n [Vector3.new(1, 1, 1)] = \"10x less bandwidth than a remote!\",\n [Vector3.new(1, 2, 1)] = \"oh wait, its way more than 10x less.\",\n\n [Vector3.new(2, 1, 1)] = \"depending on how you use your data,\",\n [Vector3.new(1, 1, 2)] = \"it could be 100x less!\",\n})\n
Not enough? here's more No more RemoteEvents ByteNet handles all instances for you; you don't need to worry about reliability type, parenting, etc - As low-level as you can get ByteNet lets you directly read/write data types such as uint32, buffers, in a way where the keys are abstracted away. Reap the benefits of a structured, strictly typed library, while retaining the benefits of hardcore optimization."},{"location":"api/dataTypes/Primitives/","title":"Primitives","text":"
ByteNet provides a large amount of \"primitive\" types for you to build more complex types that suit your game. Since primitive types don't need any parameters, you can just access them like the following: ByteNet.<typename>. For building more complex data structures, go look at the Specials page.
"},{"location":"api/dataTypes/Primitives/#available-primitive-types","title":"Available primitive types","text":""},{"location":"api/dataTypes/Primitives/#supported-general-types","title":"Supported general types","text":"
string: String
buff: Buffer
bool: Boolean
nothing: Nothing
unknown: Any type
"},{"location":"api/dataTypes/Primitives/#supported-number-types","title":"Supported number types","text":"
Special types are how complex packet types are made. They can take in nearly any type, including themselves, and most importantly they are dynamic. This means you can have an array of any length, a map of any key type and any value type, and an optional value of any type.
Special types always take parameters. You have to call them: ByteNet.<type name>(<any primitive type>).
Danger
Using these types incurs 1-2 bytes of overhead due to the dynamic nature.
They take drastically more time to parse
They are heavier on memory usage, as a new closure is created each time. You will never have to worry about this unless you have dozens of packets, though.
"},{"location":"api/dataTypes/Specials/#available-special-types","title":"Available special types","text":""},{"location":"api/dataTypes/Specials/#structs","title":"Structs","text":"
Structs let you send structured data in the form of dictionaries. The fields are optimized away, so they don't take any bandwidth. Structs are how you'll be sending most of your data likely: they are the best for organization, and they let you do really interesting things. For example: chunkPackets.luau
Optional types are a cool name for the concept of \"This doesn't have to exist\". It's good for optional parameters: for example if some invoked function were to fail, you might want to send back a blank copy to indicate that something is wrong.
packets.luau
return ByteNet.defineNamespace(\"chunks\", function()\n return {\n myCoolPacket = ByteNet.definePacket({\n value = ByteNet.struct({\n -- An \"optional\" type takes in a parameter.\n -- This can be anything! You can even have optional arrays.\n helloWorldString = ByteNet.optional(ByteNet.string)\n\n -- This works!\n eachCharacter = ByteNet.optional(ByteNet.array(ByteNet.string))\n }),\n })\n }\nend)\n
You really don't have to think about using optional types. You just send it! server.luau
local packets = require(path.to.packets)\n\nlocal randomlyStringOrNil = \n if math.random(1, 2) == 1 then \"Hello, world!\" else nil\n\npackets.myCoolPacket.sendToAll({\n helloWorldString = randomlyAppearingString,\n\n -- Note that even if we don't put the \"eachCharacter\" field here,\n -- it won't error. This is because it's optional!\n})\n
Arrays are fairly self explanatory. They're just plain old arrays. However, it's important to note that mixed tables have undefined behavior when passed as an array. This means things might be missing when they come out on the other side!
There is a 2 byte overhead to sending an array in ByteNet. This is because these 2 bytes are an unsigned 16-bit integer, which stores the array length. As a side effect, arrays sent through ByteNet have a max length of 2^16, which is equal to 65,536. It's likely that in the future, you will be able to reduce the overhead to 1 byte through configuration, in turn reducing the max length of the array.
local packets = require(path.to.packets)\n\npackets.myCoolPacket.sendToAll({\n -- Important to note that mixed arrays/arrays with holes\n -- shouldn't be sent through.\n true, false, true\n})\n
Maps are by far the most powerful \"special\" type in ByteNet. They let you send, what's most commonly referred to as a dictionary, through ByteNet. However it's important to keep in mind two things: the type of the key (or index), and the type of the value, cannot change.
Like arrays, maps have a 2-byte overhead to store the length of the map. This is done by iterating over the map using generic iteration and increasing a variable by 1 for every key-value pair. This, once again, means that there is a 2^16 (which equals to 65,536) cap to the number of elements in the map.
packets.luau
return ByteNet.defineNamespace(\"example\", function()\n return {\n people = ByteNet.definePacket({\n -- [name] = age\n value = ByteNet.map(ByteNet.string, ByteNet.uint8)\n })\n }\nend)\n
server.luau
local packets = require(path.to.packets)\n\npackets.myCoolPacket.sendToAll({\n john = 21,\n jane = 24,\n dave = 26,\n you = 162,\n})\n
"},{"location":"api/functions/definePacket/","title":"definePacket","text":"Defining a packet"},{"location":"api/functions/definePacket/#what-even-is-a-packet-in-bytenet-anyway","title":"what even is a packet in ByteNet anyway?","text":"
Packets are the structured dictionaries you use to define the \"format\" your data is going to be sent in. These are named packets as you 'send' packets through network, and packets have their contents usually formatted in a specific way because, well they have to be.
ByteNet's purpose as a library is to provide a way to structure your data, and send that structure in a hyper-optimized way.
"},{"location":"api/functions/definePacket/#okay-where-do-i-start","title":"Okay, where do I start?","text":"
Enough of how it works, let's start off with making a basic packet. We will also need to create a namespace: packets.luau
local ByteNet = require(path.to.bytenet)\n\nreturn ByteNet.defineNamespace(\"messaging\", function()\n return {\n printSomething = ByteNet.definePacket({\n -- This value field is very important!\n value = ByteNet.struct({\n message = ByteNet.string,\n })\n })\n }\nend)\n
On the server, there are 3 methods of sending packets to players. It's important to note that when a player should be specified, it's the second parameter given, not the first. This is an intentional design choice.
sendToAll
sendToAllExcept
sendTo
On the client, there is only one, because you can only send data to the server:
send
Any data passed through these functions must obey your structure created in definePacket, and if you have strict typing on, an error will be raised if the types do not match.
code examples client.luau
-- Sending to server\npackets.myPacket.send({\n message = \"Hello, world!\"\n})\n
server.luau
-- Sending to all players\npackets.myPacket.sendToAll({\n message = \"Hello, players!\"\n})\n\n-- Sending to an individual player\nlocal someArbitraryPlayer = Players.You\n\npackets.myPacket.sendTo({\n message = \"Hello, random player!\"\n}, someArbitraryPlayer)\n\n-- Sending to all except a certain player\nlocal someArbitraryPlayer = Players.You\n\npackets.myPacket.sendToAllExcept({\n message = \"Hello, everyone except one person!\"\n})\n
Currently, the only config accessible right now is reliability types. This will change as time goes on, however right now, you can switch reliability types by defining reliabilityType to be \"reliable\" or \"unreliable\".
"}]}
\ No newline at end of file
diff --git a/sitemap.xml.gz b/sitemap.xml.gz
index aae0403..87ced21 100755
Binary files a/sitemap.xml.gz and b/sitemap.xml.gz differ