Best way to loop from server

I feel like the use of while wait() do loops are frowned, but how else can I loop from the server?? And how can I get other scripts to run while this loop continuously runs. It’s in a module script, and is being required from a separate script that contains more code below the require. So I want the module to require, and run, without causing other modules to yield forever.

local MoodService = require(script.MoodService)

print('Continue running')
local MoodService = {}

local ReplicatedStorage = game:GetService('ReplicatedStorage')
local ServerStorage = game:GetService('ServerStorage')

local Remotes = ReplicatedStorage:WaitForChild('Remotes')
local Events = Remotes:WaitForChild('Events')
local Mood = Events:WaitForChild('Mood')

local PlayerData = ServerStorage:WaitForChild('PlayerData')

local function changeMood(mood)
	if mood < 5 then return end
	
	mood = mood - 5
	
	print(mood)
end

function MoodService:SetUp(player)
	User = PlayerData[player.UserId]
	if not User then return end
end

while wait(5) do
	if User then
		local RandomMood = math.random(#User.Moods, 1)
		changeMood(RandomMood)
	end
end

return MoodService
1 Like

Spawning a thread is more than enough:

spawn(function()
    while true do
        if User then
            RandomMood = math.random(1,#User.Moods)
            changeMood(RandomMood)
        end
        wait(5)
    end
end)

while wait() do loops are frowned upon because they are usually able to be replaced by RunService's events, as well as RunService:BindToRenderStep. This, however, is not the case because you are waiting longer than the minimum time.

You can use coroutines to create separate threads to run multiple parts of code at the same time, You can either use coroutines (which has more functions/events and far better in most situations) or the spawn function, Both can be found below.
Coroutines: https://developer.roblox.com/api-reference/lua-docs/coroutine
Spawn: https://developer.roblox.com/api-reference/lua-docs/Roblox-Globals#spawn
for your case, You can do.

local coroutine = coroutine.wrap(function()
                while true do
                    wait()
                  --and go along with your code
              end
      end)()

Misclicked and posted it too early.

1 Like

With a while loop. Just don’t do while wait() do, because that’s not correct use of a while loop. Use a proper condition value.


@goldenstein64

Not quite.

4 Likes

Technically it is correct use, because the return value of wait is being checked if its non nil

it’s basically the equivalent to while wait() ~= nil do

To note, spawn is a coroutine as well.

While I don’t often create coroutines, they are not exactly like a thread created via spawn. They have a lot more control than a spawned thread.

No it’s really not. Just because you can do something, doesn’t mean you should. That as well, just because something works, doesn’t mean it’s correct usage (see: hacking together features).

Relying on the fact that wait returns a truthy value and using it to implicitly pass the while condition is a code smell and bad practice. This is also not intuitive either. Wait doesn’t always wait the exact amount of seconds you specify and this code isn’t necessarily readable or maintainable.

This practice, as the document mentions, especially plagues Roblox developers because of it’s availability in the sandbox. Vanilla Lua doesn’t have this so it creates a knowledge discrepancy and you end up taking that bad practice wherever you go.

Other languages don’t necessarily have a sleep function, you have to write one - even in Vanilla Lua. Are you just going to expect that each language has a sleep function that you can use to pass a loop condition?

1 Like

You’re right, but putting it as a condition or in a block of code really doesn’t change how unreliable wait() is, if you’re going to use it, use it how you like…

The only difference i see with wait being in the conditional vs in a block of code

  1. u cant capture its return value
  2. u always yield at beginning

As far as im concerned wait will and has never returned a nil value

A lot of other languages have sleep functions
Java

  1. import lang.thread
  2. create thread object and run thread object ([thread object].start())
  3. inside the thread you can call Thread.sleep(long mili)

Python (I don’t know this lang but did some quick research)

  1. import time module
  2. time.sleep(n)

I personally hate wait() and never use it in my code… but if someone were to use it in a while loop as a condition there would be no more harm caused than it being in the block of the while loop

As a condition, yes it does. It implicitly passes the condition. It’s bad practice, terrible use of the while condition and a code smell. It also leads to bad habits, non maintainability, less readability and in most cases, marginal inefficiency.

The purpose of a condition is an indication that the return values coming from the evaluation of the condition are important towards whether the thread should continue or terminate. In fact, thr whole point of the conditional statement is to determine if the loop should terminate or not.

-- Example from the document, not exact

-- Bad
while wait(1) do
    if ((p1 - 02).magnitude <= 100 then
        break
    end
end

-- Good
while (p1 - p2).magnitude > 100 do
    wait(1)
end

Unnecessary yielding at the beginning, or unnecessary yielding at all, is bad practice. Often at times, it also indicates a deeper problem in your code (i.e. improper organisation).

Not at all the point of what I said. Regardless of whether it does or not, using wait is an abuse of the while condition and bad code.

Yes there is.

  • Teaches bad habits
  • Marginal inefficiency
  • Introduces a code smell
  • Forces you to yield pointlessly at the start of an iteration over letting you choose a more appropriate place to yield
  • Implies that you have no terminating conditions (or otherwise a non-terminating loop)
  • Introduces code complexities (see above)

It’s bad code.

The thread I linked delves into the While-Wait-Do Idiom more (three pages worth discussing the idiom itself and why it’s bad).

spawn is not a good choice, it has a lot of delay. i would say spawn() and delay() are Deprecated, use corountines instead. its much better.

1 Like

There isn’t a noticeable delay using spawn tho?

its not immediatlly noticeable but it will cause you trouble, you can test it yourself. like in this example image
corountines also give more opportunities.

I use over a dozen times in my game, and yet to have any problems arise.

Just because you didn’t have any problems doesn’t mean its a good tool. after starting to use spawn more you will notice the delay. the delay can also reach 15 seconds, witch is pretty bad, its obvious that coroutines are better. especially if you will need to use it a lot, coroutines are just a way to avoid the problems that you could have with spawn. coroutines are as easy ,so i don’t see why not using them.

3 Likes

So… When using spawn the function will be executed the next time roblox’s task scheduler runs an update cycle, This delay will take at least 29 milliseconds for every thread. But arbitrarily can take longer depending on the target framerate and various throttling conditions making this an unreliable function

1 Like

that’s why I use task.wait, task.spawn and task.delay instead as it’s faster

As Malcom said, it is not possible to loop from a server script. If you want to run a loop every X seconds, you can use wait(seconds) like so:
while true do
– do stuff
wait(5)
end