Have you tried the fix that I suggested right below that part?
Slightly confused as to what you mean by this tho??
Instead of doing
UpdateMood:FireServer(true, 'Energy')
do
UpdateMood:FireServer({}, 'Energy')
(donât change false
) and see if it fixes the loop running more than once. If it does, you will know that the issue is that normally your boolean is set back to true
before the loop notices itâs false
.
Also make sure to change your loopâs condition to while active == Updating do
Might be overkill and it sounds like you have a more fundamental problem somewhere, but this will prevent more than 1 loop running at once.
I also suggest putting a wait before you call the loop, and then any subsequent waits at the end of the loop to prevent the scenario where updating goes false, but the loop still runs as youâre caught in the 3 second wait window.
local loopId = 0
local updating = false
function yourLoop( active )
if active == updating then
return
end
updating = active
if updating then
local identifier = loopId + 1
loopId = identifier
wait( 3 )
while updating and loopId == identifier do
-- your stuff here
wait( 3 )
end
end
end
Hmmm, it still does it. But itâs like not reliant. So I spammed the function a dozen times or so, stopped, and let it print, and it would print 1 every 3 seconds. Then when I did it another 10 times, it would do the usual print 1 multiple times in that 3 second span
Whatâs probably happening is that because you donât have the loop in a separate thread, itâs preventing any further execution of code. Even if it does not, the function update references a new scope every time. That means every time you call it, it starts a new while loop and uses the arguments you pass to update for itâs conditional statement.
This code may suffice:
--[[
spawn the loop in a separate thread for each player
to guarantee that there aren't any duplicate loops.
--]]
local Updating = false
local UpdatingMood
game.Players.PlayerAdded:Connect(function(player)
-- this doesn't have to be a coroutine,
-- but it will help with my explanation at the bottom.
coroutine.wrap(function()
while player:IsDescendantOf(game.Players) do
-- keeping players in a {[player] = bool} table is also a good idea,
-- with Players.PlayerRemoving removing them from the table.
if Updating and UpdatingMood then
print(1)
if User.Moods[UpdatingMood] < 100 then
User.Moods[UpdatingMood] = User.Moods[UpdatingMood] + 5
getMood(player)
end
end
wait(3)
end
end)()
end)
--[[
make `update` a setter for Updating and UpdatingMood
instead of also starting loops
--]]
local function update(player, active, mood) --Player, bool, string
Updating = active
UpdatingMood = mood
end
This is how you would prevent duplicate loops, by not allowing update
to start them, but it is probably not the best way to structure your loop if there are multiple loops for moods that have to be updated, in which case you would iterate through an entire table of moods instead.
This does not account for what will happen when multiple players are in your game; Updating
and UpdatingMood
, as well as User
, are not player-specific variables, and there will probably have to be some kind of change in architecture to achieve this.
However, if this all happens to be in a giant game.Players.PlayerAdded
connection, you would probably want to make sure update
is referring to the right player, and that the coroutine connected to PlayerAdded
in my function is by itself.
Rather than start a new logic loop for each player that joins, I think you should take a task-scheduling approach. Essentially, you have an array of âtasksâ that a singular while-loop executes periodically. Whenever a player joins the game, you then schedule that new task. This allows you to better manage your system, reduce spaghetti-code, and improve performance by reducing the amount of overhead required for each playerâs own routine.
Ok I believe this works
Well I tested it a few times and it seemed to look good
Much appreciated