task.spawn is perfectly fine, a minor optimization would be to use task.defer instead. The while loop is great depending on how you use it. You can have two loops as well. It’s important to note that this isn’t really running 2 functions “at the same time” roblox schedules each coroutine to happen when one function gives up control (task.wait gives up control in this case) allowing other coroutines to run
This is my code, as much as i tested it, it works. Could i just leave it like this?
local datastoreservice = game:GetService("DataStoreService")
local datastore = datastoreservice:GetDataStore("cashnjoins")
game.Players.PlayerAdded:Connect(function (player)
local folder = Instance.new("Folder")
folder.Parent = player
folder.Name = "leaderstats"
local cash = Instance.new("IntValue")
cash.Parent = folder
cash.Name = "Cash"
local joins = Instance.new("IntValue")
joins.Parent = folder
joins.Name = "Joins"
local data
local success, err = pcall(function()
data = datastore:GetAsync(player.UserId)
end)
if success then
print(data)
print("Data received")
else
print(err)
end
if data == nil then
cash.Value = 10
joins.Value = 1
else
cash.Value = data.Cash + 10
joins.Value = data.Joins + 1
end
while task.wait(2) do
cash.Value = cash.Value + 10
end
end)
game.Players.PlayerRemoving:Connect(function(player)
local data = {
Cash = player.leaderstats.Cash.Value,
Joins = player.leaderstats.Joins.Value
}
local success, err = pcall(function()
datastore:SetAsync(player.UserId,data)
end)
if success then
print("Data Saved")
else
print("Error")
print(err)
end
end)
I recommend making a different script for this kind of thing, to lessen the load on the server, because the other approach such as spawn is that it adds a new function to the load which will keep increasing and there is no way to stop the loop if the player has left it would only cause an error.
So for my recommended approach it is basically one loop and inside of the loop is that it get’s every player on the server and increment their cash that is basically it.
Edit: Of course we could optimize this even further using module scripts where inside of the table are just the cash instance, and just loop that table. And also you have to remove the cash instance from the table if the player have left.
local datastoreservice = game:GetService("DataStoreService")
local datastore = datastoreservice:GetDataStore("cashnjoins")
game.Players.PlayerAdded:Connect(function (player)
local folder = Instance.new("Folder")
folder.Parent = player
folder.Name = "leaderstats"
local cash = Instance.new("IntValue")
cash.Parent = folder
cash.Name = "Cash"
local joins = Instance.new("IntValue")
joins.Parent = folder
joins.Name = "Joins"
local data
local success, err = pcall(function()
data = datastore:GetAsync(player.UserId)
end)
if success then
print(data)
print("Data received")
else
print(err)
end
if data == nil then
cash.Value = 10
joins.Value = 1
else
cash.Value = data.Cash + 10
joins.Value = data.Joins + 1
end
coroutine.wrap(function()
while task.wait(2) do
cash.Value = cash.Value + 10
end
end)()
end)
game.Players.PlayerRemoving:Connect(function(player)
local data = {
Cash = player.leaderstats.Cash.Value,
Joins = player.leaderstats.Joins.Value
}
local success, err = pcall(function()
datastore:SetAsync(player.UserId,data)
end)
if success then
print("Data Saved")
else
print("Error")
print(err)
end
end)
That works fine, :Connect creates a new coroutine for every player added. You will recieve errors when players leave the game (but nothing will break), since cash will be deleted, try adding this condition to the while; checking if cash and it’s parent are valid
while task.wait(2) and cash and cash.Parent do
cash.Value += 10
end
I’ve made a graph before that can help visualize it a little better. A common issue is programmers not knowing what functions are “Yielding” (i.e. they give up control of the thread), for example datastore:GetAsync is a yielding function, so other scripts and coroutines can run while it’s waiting for datastore data to come back, if the player leaves immediately then any player, cash, or joins uses will result in an error. Of course in your :Connected function such an error will not break anything else.