Packet - Networking library

Update 1.2

No longer possible for the client to make the server print error messages in live games


By stopping the client from making the server print error messages it stops exploiters from flooding the server and causing the server to slow down

Hi what scripts have been changed? cause i converted the module for rojo and 5m after that u updated lol

Just the mainmodule nothing else

thx, btw will u add a github in future,? i think is a better way to compare and verify updates/minor changes

I personally wont be but if anyone else wants to they can

there is one here: GitHub - mrchigurh/Suphi-Packet: Suphi Kaner Networking Module

but at this time its still on version 1.0

it has now been updated to 1.2

coudnā€™t we keep track of how Much Client sends Every couple of frames And if that exceeds the Limit as well we dont proccess events for Some time, that way if someone spams buffers that are just in range but still big enough to cause a lag it woud Trigger this and stop them From Firing any More Events? genuanly asking if this woud work

thatā€™s kind of what Packet already does

this is done per server heartbeat
the server heartbeat is 60 times a second

but a client can select a higher fps for example 120 and they would send 2 events in the same time the server does 1 heartbeat

the server will add up the size from both events and make sure the total of both events donā€™t pass the limit

in the main module you should fine

table.clear(playerBytes)

this is where we reset the amount of bytes a player has sent if you want to prolong this simple donā€™t clear the table as often

As someone who hasnā€™t really looked into or even considered optimising network efficiency before, this seems like a graceful way to handle this system in a considerate way Iā€™ll find easy to implement!

Only question I have; I believe I remember seeing the word ā€œfloatā€ being used somewhere, cant find it now, but are the ā€œFā€ variants for number types the only ones that will properly function with floats/numbers with decimal values? I dont remember the video mentioning floats/shows them being used and the block comment guide for number types doesnt seem to clarify either.

yes the F variants are floating point numbers

for example F16 has enough precision to support integers up to 2048 after 2048 it will start to skip hole numbers but it will continue to go up to 65519.999... then at 65520 it will become math.huge

its also possible to use the S and U as decimal values but in most cases you will want to use the F variants but just to show you that it is also possible with S and U here is a example

packet:Fire(0.123 * 1000) -- if you round this it will give better results 
packet.OnClientEvent:Connect(function(number)
    print(number / 1000)
end)
local thread = task.spawn(function()
	while true do
		coroutine.yield()
		if cursor.Index > 0 then
			if #cursor.Instances == 0 then
remoteEvent:FireServer(cursor:Truncate())
else
remoteEvent:FireServer(cursor:Truncate(), cursor.Instances)
end
			cursor:Clear()
		end
	end
end)
RunService.Heartbeat:Connect(function() task.defer(thread) end)

should be

local thread = function()
	while true do
		coroutine.yield()
		if cursor.Index > 0 then
			if #cursor.Instances == 0 then
				remoteEvent:FireServer(cursor:Truncate())
			else
				remoteEvent:FireServer(cursor:Truncate(), cursor.Instances)
			end
			cursor:Clear()
		end
	end
end
RunService.Heartbeat:Connect(function() task.defer(thread) end)

because ur calling task.spawn in task.defer, which calling twice thread this add some overhead.

additional change (inline):

if #cursor.Instances == 0 then
	remoteEvent:FireServer(cursor:Truncate())
else
	remoteEvent:FireServer(cursor:Truncate(), cursor.Instances)
end

to

remoteEvent:FireServer(cursor:Truncate(), #cursor.Instances > 0 and cursor.Instances)

No the first task.spawn is correct because it gets the function to the yield then inside the runservice we resume the yielded thread task.spawn() returns a thread not a function

its faster to resume a yielded thread vs making a new thread every time from a function


also the problem with your single line is that it will pass the value of false when there are no instances and that would be a waste of data

you can slap an or nil on that
also, i may be missing something but, what is the benefit of using a thread here? Would just calling the function not be more efficient?

deferring a thread is more efficient then deferring a function by about 2x

the reason we defer is so that if you are using single script architecture or global framework or for any reason you connect to a heartbeat event before packet does

your heartbeat event will run after packets heartbeat event

and if you do packet:Fire() inside that heartbeat event then it will add 0.01666ā€¦ seconds of latency

so by deferring it makes sure that packet will run after all other heartbeat events in your game no matter the order they where connected in

so in short by deferring there wonā€™t be 0.01666ā€¦ seconds of latency if you use packet:Fire() inside a heartbeat event

1 Like

Itā€™s an incredible module. It would be nice to see how it compares to other modules such as Wasp (1.0.9) Fastnet2 and Bridgenet2

Anyone is free to benchmark and post the results

Well as far as Iā€™ve heard and read; Wasp, FastNet2 and BridgeNet2 arenā€™t really among the absolute best networking libraries.

I believe the only true competitors you have at the moment is ByteNet, Zap and Blink.

1 Like

its very easy to see how many bytes each type uses by looking at the types modules

if you wanted to you could very easily make a CFrame type that only uses 6 bytes but I would not recommend doing that because the amount of data that is sent is not the only important thing packet comes with 12, 15 and 18 byte cframes
the 18 byte cframes has about the same precision as robloxs built in remote event cframes we could even make a 20 byte cframe that has more precision then remote event cframes but i decided not to include it but its very easy to make your own custom types if you watch the video we make 3 custom types in the video

if you would like to ask me about how each type works id be happy to explain how each type works and if you feel there is a more optimal way to send a type id be happy to listen

id also be happy for people to share there own custom types with the community to use
for example here is a 20 byte cframe that has better precision then remote events but is not included with the module

--!strict

-- Requires
local Cursor = require(script.Parent.Parent.Cursor)

return {
	
	Read = function(cursor: Cursor.Cursor)
		return CFrame.fromAxisAngle(
			Vector3.new(cursor:ReadS2() / 32767, cursor:ReadS2() / 32767, cursor:ReadS2() / 32767),
			cursor:ReadU2() / 20860.438391054722
		) + Vector3.new(
			cursor:ReadF4(),
			cursor:ReadF4(),
			cursor:ReadF4()
		)
	end,
	
	Write = function(cursor: Cursor.Cursor, value: CFrame)
		cursor:Allocate(20)
		local axis, angle = value:ToAxisAngle()
		cursor:WriteS2(axis.X * 32767 + 0.5)
		cursor:WriteS2(axis.Y * 32767 + 0.5)
		cursor:WriteS2(axis.Z * 32767 + 0.5)
		cursor:WriteU2(angle * 20860.438391054722 + 0.5)
		cursor:WriteF4(value.X)
		cursor:WriteF4(value.Y)
		cursor:WriteF4(value.Z)
	end,
	
}

and here is a 17 byte version [Iā€™m not sure how its precision compares to the built in 18byte version]

--!strict

-- Requires
local Cursor = require(script.Parent.Parent.Cursor)

return {
	
	Read = function(cursor: Cursor.Cursor)
		return CFrame.fromAxisAngle(
			Vector3.new(cursor:ReadS1() / 127, cursor:ReadS1() / 127, cursor:ReadS1() / 127),
			cursor:ReadU2() / 20860.438391054722
		) + Vector3.new(
			cursor:ReadF4(),
			cursor:ReadF4(),
			cursor:ReadF4()
		)
	end,
	
	Write = function(cursor: Cursor.Cursor, value: CFrame)
		cursor:Allocate(17)
		local axis, angle = value:ToAxisAngle()
		cursor:WriteS1(axis.X * 127 + 0.5)
		cursor:WriteS1(axis.Y * 127 + 0.5)
		cursor:WriteS1(axis.Z * 127 + 0.5)
		cursor:WriteU2(angle * 20860.438391054722 + 0.5)
		cursor:WriteF4(value.X)
		cursor:WriteF4(value.Y)
		cursor:WriteF4(value.Z)
	end,
	
}

and here is a vector2 that only uses 4 bytes

--!strict

-- Requires
local Cursor = require(script.Parent.Parent.Cursor)

return {
	
	Read = function(cursor: Cursor.Cursor)
		return Vector2.new(cursor:ReadF2(), cursor:ReadF2())
	end,
	
	Write = function(cursor: Cursor.Cursor, value: Vector2)
		cursor:Allocate(4)
		cursor:WriteF2(value.X)
		cursor:WriteF2(value.Y)
	end,
	
}

and here is a vector2 that only uses 2 bytes

--!strict

-- Requires
local Cursor = require(script.Parent.Parent.Cursor)

return {
	
	Read = function(cursor: Cursor.Cursor)
		return Vector2.new(cursor:ReadS1(), cursor:ReadS1())
	end,
	
	Write = function(cursor: Cursor.Cursor, value: Vector2)
		cursor:Allocate(2)
		cursor:WriteS1(value.X)
		cursor:WriteS1(value.Y)
	end,
	
}

so to me just running a benchmark and testing each one does not really have any meaning
packet source code should be very easy for most scripters to understand and should give them the power to create any type they want i have included the types that i feel are best for general use but please donā€™t feel limited to the types that are included

i have never looked at zap or blink but if you notice there doing something better please tell me and ill implement the same type or if you like make the type and share it with us

2 Likes

lol when people ask this. youā€™re not forced to use anything here, and anybody who posts a resource here is not obligated whatsoever to convince you to use their resource over another. go use zap or blink

1 Like

Iā€™m not stating itā€™s worse or that there are existing options, Iā€™m asking why I should use it over said existing options and if there are any benefits over them that warrant a switch. Sorry if I sounded rude or something.

Has anyone done benchmarks of this in comparison with blink? The DDOS protection feature in this seems awesome.