Are you sure it’s 20hz? From my own testing, it seems to be 60hz.
Code
Client:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local NetRateRem = ReplicatedStorage.NetRateTest
local ChangeRateRem = ReplicatedStorage.ChangeRate
local UI = script.Parent
local Label = UI.Calculated
local RateChangeBox = UI.NewRate
local CurrentFrameId = 0
local LastEventFrameId = 0
local EventsInSameFrame = 0
local TargetRate = 60
RateChangeBox.FocusLost:Connect(function()
local NewRate = tonumber(RateChangeBox.Text) or 60
-- so that the server script can just step multiple times with a very simple division
if NewRate > 60 then
NewRate = math.ceil(NewRate / 60) * 60
end
ChangeRateRem:FireServer(NewRate)
RateChangeBox.Text = `Try to reach rate: {NewRate}`
TargetRate = NewRate
end)
RunService.PreRender:Connect(function()
CurrentFrameId += 1
EventsInSameFrame = 0
end)
NetRateRem.OnClientEvent:Connect(function()
if CurrentFrameId == LastEventFrameId then
EventsInSameFrame += 1
end
LastEventFrameId = CurrentFrameId
end)
while true do
if EventsInSameFrame > 0 then
print(`Event fired multiple times in a single frame ({EventsInSameFrame} times), net rate is lower than the fire rate!`)
end
Label.Text = `Actual rate: {TargetRate/(EventsInSameFrame + 1)} (EISF: {EventsInSameFrame})`
task.wait(1/60)
end
Server:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local NetRateTest = ReplicatedStorage.NetRateTest
local ChangeRate = ReplicatedStorage.ChangeRate
local Rate = 60
ChangeRate.OnServerEvent:Connect(function(_, NewRate)
Rate = NewRate
print(`The new rate is {Rate}`)
end)
wait(1)
while true do
if Rate >= 60 then
for _ = 1, Rate / 60 do
NetRateTest:FireAllClients()
end
task.wait(1/60)
else
NetRateTest:FireAllClients()
task.wait(1/Rate)
end
end
The “Try to Reach Rate” (“Target Rate”) is how many times, per second, the Server will fire the Remote Event. The Actual Rate is how many times the event is received per second, divided by how many times the event fires in the same frame (also given as “EISF”). My reasoning for this is that Roblox should process packets as soon as they arrive, so if they manually add a little bit of delay to try to hide the network rate, this doesn’t work. If multiple events occur in the same frame, it indicates Roblox has accumulated them and sent them as a single packet due to the event being fired at a rate faster than the connections can actually be replicated, which can be shown by setting a ludicrously high Target like 4020
(:FireAllClients
/second).
Unfortunately, I can’t record a video of it in action because the Recorder seems to cap my FPS at 60
regardless of what I set in the Menu through that new option, which, on my non-stellar internet connection, causes multiple packets to be handled per frame, which doesn’t happen when I’m running above 60 FPS
.
With the Target set to 60
, nothing interesting happens, the Actual Rate is just the Target Rate without any kind of “snapping” to a lower value, meaning the system can consistently send and receive that many packets per second without any of them being accumulated together.
If I set the Target Rate above 60, the Actual Rate will snap and flash between the Target and exactly 60
, showing that the networking rate must be 60hz
(excluding the aforementioned potential caveat) as that is the maximum rate the system can consistently hit, going above that means the Server is firing the event multiple times per Server frame, as the Server runs at 60 FPS. So, hypothetically, if the networking rate is below 60hz
(like, for example, 20hz
), then the same jitter should be observed even while the Target is below the Server FPS and above 20
, which, it doesn’t.
Actual Rate
= Target / (EISF + 1)
TL;DR:
- Target Rate below or at 60 (and Client framerate above Target Rate): Actual Rate is Target Rate
- Target Rate above 60 (eg:
4020
): Actual Rate frequently snaps to 60
, EISF
is 66
(4020/(66+1)
= 60
)
So, above 60hz
, multiple packets are processed per frame because the Server runs at 60 FPS, but just below or at 60hz
, only one event per Server frame and one event per Client frame, which I have equated to a single network packet. If the networking rate was 20hz
, we should expect to see the Client receive 3 events per frame, as 60 :FireAllClients per second / 20hz networking rate = 3 packets per frame
, which doesn’t happen.
Unless I’ve done something wrong.