Wrap this in a coroutine so it saves all the players’ data at once.
Also, I don’t see any autosaving?
Edit: How to use corountines:
if RunService:IsStudio() then
return
end
for _,plr in pairs(game.Players:GetPlayers()) do
corountine.wrap(function()
local PlayerUserId = "Player_"..plr.UserId
local data = {
Strength = plr.leaderstats.Strength.Value;
}
local success, errormessage = pcall(function()
DataStore:UpdateAsync(PlayerUserId, function(OldData)
return data
end)
end)
if success then
print('Data Successfully Saved!')
end
if errormessage then
print('Data UnSuccessfully Saved!')
warn(errormessage)
end
end)()
end
This should work perfectly. As some people have already mentioned, you need to make sure it is saving data when the player leaves, and when the server is being shutdown.
To detect when the server is shutting down you can use the BindToClose event. You should make it that when the server is shutting down, before closing the server, it goes through every player in game and saves their data. This may back up your datastore, so make sure to add a small delay between each player in the loop. But, since the server is shutting down anyways, it shouldn’t be an issue.
Also, one minor issue with your above script is that exploiters can spam the Autosave event, which would backup your datastore. You should add a server-sided cooldown for the autosave event.
--insert save function here
function onShutdown()
for _,plr in ipairs(game.Players:GetPlayers()) do
coroutine.wrap(save)(plr)
end
end
game:BindToClose(function()
onShutdown()
wait(1)
end)
local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("DataStore3")
local DataStore1 = DataStoreService:GetDataStore("Pets4")
local DataStore2 = DataStoreService:GetDataStore("PetsEquips1")
local function save(plr)
local PlayerUserId = "Player_"..plr.UserId
local data = {
Strength = plr.leaderstats.Strength.Value;
Prestige = plr.SecretFolder.Prestige.Value;
Cash = plr.leaderstats.Cash.Value;
StrengthMulti = plr.SecretFolder.StrengthMulti.Value;
Rank = plr.SecretFolder.Rank.Value;
TimePlayed = plr.SecretFolder.TimePlayed.Value;
Rebirths = plr.SecretFolder.Rebirths.Value;
RobuxDonated = plr.SecretFolder.RobuxDonated.Value;
StrengthMultiplier = plr.SecretFolder.StrengthMultiplier.Value;
CashMultiplier = plr.SecretFolder.CashMultiplier.Value;
EggsHatched = plr.leaderstats.EggsHatched.Value;
}
DataStore:UpdateAsync(PlayerUserId, function(OldData)
return data
end)
local key = "pets-"..plr.UserId
local activated = {}
for i,v in pairs(plr.Pets:GetChildren()) do
if v:IsA("BoolValue") then
table.insert(activated, v.Name)
end
end
DataStore1:SetAsync(key,activated)
local key = "petsequip-"..plr.UserId
local activated = {}
for i,v in pairs(plr.Equipped:GetChildren()) do
if v:IsA("BoolValue") then
table.insert(activated, v.Name)
end
end
DataStore2:SetAsync(key,activated)
end
local function onShutdown()
for _,plr in pairs(game.Players:GetPlayers()) do
save(plr)
wait()
end
end
game:BindToClose(function()
onShutdown()
wait(1)
end)
local cooldown = {}
game.ReplicatedStorage.AutoSave.OnServerEvent:Connect(function(plr)
local t = tick()
if cooldown[plr.Name]==nil or t-cooldown[plr.Name]>=250 then
-- It has been at least 250 seconds since the last time the event was fired by the player
cooldown[plr.Name]=t
save(plr)
end
end)
game.Players.PlayerRemoving:Connect(save)
But that doesn’t account for time. The tick function returns a number of seconds, and always increases. This could be used to check how much time has passed since the last time the event was fired by the player.