Hi, I’ve been trying to write server-sided code for a day and night cycle for my “restaurant” game that relies on the time to know when the store is open or closed. Currently, I’ve been using a “while true loop” to code this. However, as I do my research, I find that this may not be optimal?
I’m receiving varied responses on how to go about this, and need a clear cut answer. A lot of the tutorial and resources use a while true loop for their cycles, however I’ve come across a post against this, warning it could be very performance heavy.
So, would you recommend using a while loop for a day and night cycle? Reminder that I ALWAYS need time to be changing in my game to get it to work how I want it to be. If not a while loop, what else would you recommend?
Yes, I do have a task.wait() in my loop, but even with that performance will still be demanding, no? My loop has a wait for over 1/30th second, which is very close to 0. I would assume because of this, it’s still performance heavy.
If you are waiting for that short of a timespan, maybe consider using the RunService and attaching it to an event to run every frame. I know you are talking about it being demanding on performance, but RunService will make it cycle smoother at least. I personally think you are better off using the run service when you are doing it ever 1/30 seconds.
RunService only runs on the player, some for that I’m concerned about time-syncing. Also, about the controllability RunService. In my game, I’m looking for the restaurant closing time to last about 4 minutes, and the restaurant to be open for 6 minutes real world. If I have this run service that is uncontrollable the rate it fires, I may not be able to accomplish this.
RunService should properly sync if you use delta time correctly.
Honestly, if you want it to be less resource intensive, just make the wait for the day night cycle longer. Your approach really depends on how realistic you want it to look when it changes.
I see, so taking a look at my code for example (very messy at the moment and equations need to be figured out, but will essentially almost look the same with hundreds of prints for debugging…), all it’s essentially doing is calculating and setting minutes after midnight. Would you deem this performance heavy?
And the thing about solving the problem first, the problem is more of if I should be using a runservice or while true loop. I’m just thinking it would be very helpful to know if a runservice will probably be better, so I don’t end up needing to rewrite the whole system since runservice and while loops run a bit differently.
while true do
wait()
if math.floor(lighting.ClockTime) == 0 then
totalTime = 0
end
if lighting.ClockTime >= 0 and lighting.ClockTime < 8 then --once 12am ingame time goes slower (4m)
while totalTime < closeTime do
--timeShift = 16/165 -- 1/15 old value
local deltaTime = task.wait(1/30)
totalTime += deltaTime
counter += 1
--print(totalTime.. " ".. counter)
--local minutesshift = game.Lighting:GetMinutesAfterMidnight() + (totalTime*60)
rate = 480/(closeTime/60) --480/4 480 = 8 hours in minutes, 4 represents end time
stominutes = (totalTime/60)*rate
--print(stominutes)
--print(rate)
lighting:SetMinutesAfterMidnight(stominutes)
end
print("reset")
elseif lighting.ClockTime >= 8 and lighting.ClockTime < 24 then --once 8am time ingame time goes faster (6m)
while totalTime < (closeTime+openTime) do
--breaktrue = true
local deltaTime = task.wait(1/30)
totalTime += deltaTime
rate = 960/(openTime/60)
minusrate = rate*4+(-480)
roc = ((((closeTime+10/60)*rate)-minusrate) - (((closeTime/60)*rate)-minusrate))/(((closeTime+10) - (closeTime)))
print("roc is ".. roc)
intitialvalue = -closeTime*roc
retainrate = closeTime*(roc)+(intitialvalue)
print(minusrate.. " and ".. rate)
print("retainrate is ".. retainrate)
stominutes = (((totalTime/60)*rate)-minusrate)-retainrate -- we multiply the minutes after midnight by 60 to get the seconds. Divide that by 120 for the conversion giving us total time. , then multiply by 160 for
print("total time is ".. totalTime)
print((totalTime/60)*rate)
print("minutes after midnigh is ".. stominutes)
lighting:SetMinutesAfterMidnight(stominutes)
end
end
if breaktrue == true then
print(tick() - starttime)
print('whole loop broken.')
break
end
end
RunService exists in both the client and server. However, you should be doing animation animation-wise on the client. You can have syncing by updating the server at a slower rate and smoothing it over on the client each time it’s updated, or just have a timestamp to base the time cycle on and not have to have the server update even once.
Yes, all animations and visual stuff should be handled by the client as much as possible. Roblox’s servers are rather weak. Plus animations look bad when the server handles it anyway. When I say animation, I mean anything that moves rapidly or anything more than just “teleporting”. The server should be used for secure data and client communication only (or as much as possible).
You can use remotes, among other things, to sync animations on each client, or have the client react directly.
Animations that are played on a player’s Character, or are to only be seen by a particular player’s character need to be created and played on that client.
Any animation (other than on a player’s Character) that needs to be seen by all, needs to be played on the server.
Are animations loaded by the server still run on the client? If not, then the client should still be doing that anyway. A remote to all clients can sync the animation. I’ll assume it does make each client animate it instead of the server animating it though, as that would make more sense realistically.
I don’t see anything wrong with a server side loop for the time and day.
Shouldn’t be any sort of performance loss.
local lighting = game.Lighting
local slowSpeed = .5 -- in hours per second
local fastSpeed = 2 --in hours per second
local slowTimeStart = 0 --in clock time
local fastTimeStart = 8 -- in clock time
while true do
local elapsed = wait()
if lighting.ClockTime> fastTimeStart then
elapsed = elapsed * fastSpeed
else
elapsed = elapsed * slowSpeed
end
lighting.ClockTime = lighting.ClockTime + elapsed
end
I would still recommend running that on the client as the animator situation is different. If it’s at a slower speed that it doesn’t particularly matter, but if it’s for a constant non-AnimationTrack animation, such as a loop or tween, it would be better to have the client handle it. Both for the purpose of taking any stress it would have off the server, but more importantly, to have a smoother animation.
Like I said earlier in this thread, you could even use a timestamp and not have to use the server at all, while keeping everything in sync.
You are correct, if its something you want to sync to a specific value that the client has, and it needs to be super precise, then yeah, play the animation on the client, according to whatever variable the client is keeping track of.
However, if it doesn’t need to be super precise, don’t worry about playing animations on the server, this isn’t causing undue strain on the server, as playing animations has become really optimized recently on Roblox, and servers are more than capable of playing serve side animations (which in truth are not actually played on the server, but rather the animation data is sent to each client) without causing any strain.
if performance in your loop is bad simply increase the wait time a bit and make the time increments larger (make larger shifts in longer intervals) but otherwise its fine i have written a clock cycle with a for loop before its fine.