@Kampfkarren
I’m posting this based on the thread you talked about “Avoiding wait() and why”, but I was also hoping if someone more experienced than I am could criticize this code.
The code below is supposed to generate the player cash/second but I didn’t just want to do wait(1) because it’ll look sloppy/slow. So I divided the cash and time by 16 and did it that way. So every 1/16 of a second they get cash.
plrData.data[player].clock = function(table)
while wait(0.05) do
table.cash = table.cash + (table.cps/16)
local formatted
if formatSwitch then
formatted = formatting.shorten(table.cash)
else
formatted = formatting.commaValue(table.cash)
end
CashFlow:FireClient(player,formatted)
end
end
The thread talks about using alternatives like WaitForChild or RunService, but my function doesn’t rely on those things.
Edit: I have a video demonstrating this that I’m about to post here.
If you want to avoid using default wait(), then you should use custom wait function instead.
Here’s my custom wait function I’ve created months ago:
function BulbWait(time)
time = time or 0.03
local et = 0
local tt
while et < time do
_, tt = game:GetService("RunService").Stepped:Wait()
et += tt
end
end
And it will look like this if it’s implemented in your code:
function BulbWait(time)
time = time or 0.03
local et = 0
local tt
while et < time do
_, tt = game:GetService("RunService").Stepped:Wait()
et += tt
end
end
plrData.data[player].clock = function(table)
while true do
BulbWait(0.5)
table.cash = table.cash + (table.cps/16)
local formatted
if formatSwitch then
formatted = formatting.shorten(table.cash)
else
formatted = formatting.commaValue(table.cash)
end
CashFlow:FireClient(player,formatted)
end
end
They added += to Luau because it is convenient and used in a lot of languages.
Simply, x = x + 1 can now be written as x += 1
To add to what @WilliamAlezandro suggests, I question whether spamming the network is
justified for such a UI feature–You could still have less-often cash-update events, and handle
any visual smooth upticks on the client side.
local Number = 0
Number += 1 --Basically it is "Number = Number + 1"
Number += 5 -- "Number = Number + 5"
-- You can use "-=" , "*=" , "/=" and few others ig.
Yea, the cpu usage I usually get with 0.1 cash per second is around 20% but it doubled when I set it to 100 cash per second.
I didn’t want the player to touch the cash so I set it instead server side. I might have to rewire it so that the the loop is happening inside the client, not the server.
Yes, the authoritative cash amount will always be on the server.
So any monkeying with the client’s copy of the cash amount is irrelevant–This also means
that it’s fine for you to do any cash-related UI niceties on the client side as well.
Well the problem with using Stepped or Heartbeat is that they use 30.0/s rate on the script performance while some other of my codes doesn’t even go that high. I’m not sure if that’s too taxing or not for the client.
I could maybe revert back to cash/second instead of 1/16th of a second, then fire that amount to the client every second so that it does the animation thing instead of firing the event every 1/16 of a second.
Yes, and as the others mentioned, if you keep track of the deltas, you don’t need to have the events
extremely regular either. What you can also do is always fire both the before and after values.
So if you take a look at @WilliamAlezandro’s BulbWait(), you’ll see that for each Stepped, it does
just a simple elapsed time check, and if it hasn’t elapsed yet, it immediately is waiting again–Not something
to worry about.
Definitely avoid wait() when you want consistency and accuracy like in your case. Definitely use @blokav’s way of running a loop it is the best method out of all listed.
Kampfkarren was definitely right when he says wait() could deviate by seconds but it might be a little exageratted. I tested wait()'s accuracy by running this code: And the results are that out of 1000 runs, wait deviated by at most 2.98 seconds and on average only deviated by around 0.035.
local AverageDeviation = 0
local MaxDeviation = 0
local Deviation = 0
for i = 1,1000 do
local currentDeviation = math.abs((wait(0.01)-0.01))
Deviation += currentDeviation
if currentDeviation > MaxDeviation then
MaxDeviation = currentDeviation
end
print(currentDeviation)
print(i)
end
AverageDeviation = Deviation/1000
warn("Average: "..tostring(AverageDeviation))
warn("Max: "..tostring(MaxDeviation))
local interval = 1/16
local total = 0
local original = interval
game['Run Service'].Heartbeat:Connect(function(dt)
total += dt
if total > interval then
cash += cps * total
total = (total - interval)
interval = total + original
fireclient(...)
end
end)
Just saying, but you can instead make the cash never increase on the server until a request is sent and have the cash increase on the client
Kinda like this
server:
local lastrequest -- last time they requested this value/ do stuff like buying or whatever, os.clock(), separate for every player
buystuff.OnServerEvent:Connect(function(...)
player.cash += (os.clock()-lastrequest) * cps
fireclient(...) -- update their cash here to fix any deviation
...
I read a little bit about the arguments of Stepped and Heartbeat but I still don’t get it. What does the deltatime parameter do? Does it like get the current time in UTC like os.time()?
The Heartbeat event gives you a ‘delta-time’ argument, which is the approximate time that has passed since the last Heartbeat event. Stepped also has delta-time, but also includes an argument for the total time that the system has been running.
Example of Heartbeat with delta-time in an FPS counter:
local updateTime = 1
local t = 0
local frames = 0
game:GetService("RunService").Heartbeat:Connect(function(dt)
if (t >= updateTime) then
print("Estimated FPS is "..math.round(frames / updateTime))
t = 0
frames = 0
else
t += dt
frames += 1
end
end)
Same example now also using the time parameter in Stepped:
local updateTime = 1
local t = 0
local frames = 0
game:GetService("RunService").Stepped:Connect(function(t0, dt)
if (t >= updateTime) then
print("Estimated FPS is "..math.round(frames / updateTime))
-- RunService also has functions to tell if code is running on the server/client, or if it is running in studio
if (game:GetService("RunService"):IsClient()) then
print("Player has been in game for "..math.round(t0).." seconds")
else
print("Server has been running for "..math.round(t0).." seconds")
end
t = 0
frames = 0
else
t += dt
frames += 1
end
end)
Edit:
It looks like on the wiki page that these events are now recently deprecated. The new events they provide should do the same things and allow you more freedom to specify when the code should be run. (pre/post physics step, pre-render, etc.)
They don’t seem to have the ‘time’ parameter anymore but you can still measure that manually by adding delta-time to a global variable:
local gameTime = 0
local t = 0
-- PreSimulation isn't documented yet but it might be the replacer for Stepped
game:GetService("RunService").PreSimulation:Connect(function(dt)
gameTime += dt
if (t >= 1) then
if (game:GetService("RunService"):IsClient()) then
print("Player has been in game for "..math.round(gameTime).." seconds")
else
print("Server has been running for "..math.round(gameTime).." seconds")
end
t = 0
else
t += dt
end
end)