Performance for while loop

So I have a while loop running every (1) second for my time rewards system (this is based on the time you play so updating every sec) and I’m wondering if this can be bad for performance since i’ll have multiple players getting timeplayed value up every sec with a loop

If you doing it like

while true do
    for _, player in pairs(Players:GetPlayers()) do
        -- Add point
    end

    task.wait(1)
end

Then you’ll be fine, will not have any noticeable affect on performance

This can be done MUCH better. Try not to run for loops in a while loop:

game.Players.PlayerAdded:Connect(function(player)
    while task.wait(1) do
        -- Add point
    end
end)
1 Like

This is worse, for several reasons:

  1. This would run a new while loop every single time a player joins (1 million players join over time in a single server, you gonna have problems)
  2. Doing the wait inside the while do part is heavely frowned upon. Don’t do it, ever.
  3. There is nothing wrong with for loops in while loops. Can have dozens of for loops in a single while loop and have no issues
2 Likes

here is a way you can do it without loops

local times = {}
local rewardPerSecond = 10

local function ClaimReward(player)
    local deltaTime = os.time() - times[player]
    player.leaderstats.Coins.Value += deltaTime * rewardPerSecond
    times[player] += deltaTime
end

game.Players.PlayerAdded:Connect(function(player)
    -- save the time the player enters the game
    times[player] = os.time()
end)

game.Players.PlayerRemoving:Connect(function(player)
    ClaimReward(player)

    -- remove the players time so we don't have a memory leak
    times[player] = nil
end)

That would work but thats not my goal

whats your goal? because it can be modified

is this your goal?

-- server script

local times = {}
local rewardPerSecond = 10

local function GetPlayerCoins(player)
    local deltaTime = os.time() - times[player]
    return player.leaderstats.Coins.Value + deltaTime * rewardPerSecond
end

local function ClaimReward(player)
    local deltaTime = os.time() - times[player]
    player.leaderstats.Coins.Value += deltaTime * rewardPerSecond
    times[player] += deltaTime
    player.Reward.Value = times[player]
end

game.Players.PlayerAdded:Connect(function(player)
    -- save the time the player enters the game
    times[player] = os.time()

    -- create a NumberValue so the player can see how many coins they have
    local reward = Instance.new("NumberValue")
    reward.Name = "Reward"
    reward.Value = times[player]
    reward.Parent = player
end)

game.Players.PlayerRemoving:Connect(function(player)
    ClaimReward(player)

    -- remove the players time so we don't have a memory leak
    times[player] = nil
end)

-- localscript inside starterplayerscripts

local rewardPerSecond = 10
local reward = game.Players.LocalPlayer:WaitForChild("Reward")

while true do
    local deltaTime = os.time() - reward.Value
    print("Coins", player.leaderstats.Coins.Value + deltaTime * rewardPerSecond)
    task.wait(1)
end

Basically I wanna save a value called “TimePlayed” and update it every second any good way to achieve this?

why do you want to update it every second instead of updating it only when you need to use it

Its “TimePlayed” so its recording how long you’ve played forever

ok ill show you how to save it into a datastore without a loop

local dataStoreService = game:GetService("DataStoreService")
local dataStore = dataStoreService:GetDataStore("Store")

local times = {}
local timePlayed = {}

local function GetCurrentPlayTime(player)
    return timePlayed[player] + os.time() - times[player]
end

game.Players.PlayerAdded:Connect(function(player)
    -- get the players play time from the datastore
    local success, value = pcall(dataStore.GetAsync, dataStore, player.UserId)

    -- datastore failed to load roblox datastore server might be down
    if success == false then return end

    -- set the current time
    times[player] = os.time()

    -- set the play time
    timePlayed[player] = value or 0
end)

game.Players.PlayerRemoving:Connect(function(player)
    -- the players datastore failed to load so this is now nil
    if times[player] = nil then return end

    -- work out how long the player has been playing
    local deltaTime = os.time() - times[player]

    -- add the delta time to the play time
    timePlayed[player] += deltaTime

    -- save the play time into the datastore
    local success, value = pcall(dataStore.SetAsync, dataStore, player.UserId, timePlayed[player])

    -- delete the values so we don't have a memory leak
    times[player] = nil
    timePlayed[player] = nil
end)

this is also more accurate then using

while true do
    task.wait(1)
end

because task.wait does not wait exactly 1 second
you can find out more here