So, I looked at your new code and noticed somethings you can do to make it cleaner. I recommend separating things into functions, and trying to attempt to get from datastores a few times before backing off.
So, I took some of my ideas and @GameMaster4268 to create this feel free to change it up for your project:
-- services
local DSS = game:GetService("DataStoreService"):GetDataStore("PlayerData")
local Players = game:GetService("Players")
local RS = game:GetService("RunService")
-- settings
local SAVE_INTERVAL = 300
local dataPrefix = "id_"
-- pcall trys
local maxTries = 5
-- define
local dataCache = {}
local TemplateData = {
["leaderstats"] = {
["Bounty"] = 0,
["Kills"] = 0,
},
["playertats"] = {
["Cash"] = 0,
["Bank"] = 0
},
["playersettings"] = {
["FirstPlay"] = false,
["DataLoaded"] = false
}
}
-- functions
local function LoadData(plr:Player, Data)
if Data then
-- Load Data
for folderName, folderData in pairs(Data) do
local folder = plr:FindFirstChild(folderName)
if folder then
for childName, Value in pairs(folderData) do
local child = folder:FindFirstChild(childName)
if child then
child.Value = Value
end
end
end
end
dataCache[plr.UserId] = Data
print("Loaded "..plr.UserId.." Data!")
else
-- New player no need to load any data
dataCache[plr.UserId] = TemplateData
plr.playersettings.FirstPlay.Value = true
print("Created New Data For "..plr.UserId.."!")
end
-- Set DataLoaded true
plr.playersettings.DataLoaded.Value = true
end
local function SaveData(plr:Player)
-- Check if data loaded
local DataLoaded = plr:FindFirstChild("playersettings").DataLoaded
if DataLoaded and DataLoaded.Value == false then
warn("Player data not loaded! Trying to save!")
return
end
local key = dataPrefix..plr.UserId
local Data = {}
-- Loop through the folders
for folderName, children in TemplateData do
local folder = plr:FindFirstChild(folderName)
local folderData = {}
if folder then
for childName, _ in children do
local child = folder:FindFirstChild(childName)
if child then
folderData[childName] = child.Value
end
end
end
Data[folderName] = folderData -- Add data to a dictionary
end
-- Save Data
local success, err = pcall(function()
DSS:SetAsync(key, Data)
end)
if not success then
warn("Could not save "..plr.UserId.." data! Error:"..err)
else
print("Saved "..plr.UserId.." data!")
end
end
-- on player added
Players.PlayerAdded:Connect(function(plr:Player)
-- create instances
for folderName, children in TemplateData do
local folderObject = Instance.new("Folder")
folderObject.Name = folderName
for childName, value in children do
local typeOfValue = typeof(value) -- Type of value
local childObject
if typeOfValue == "number" then
childObject = Instance.new("NumberValue")
elseif typeOfValue == "boolean" then
childObject = Instance.new("BoolValue")
elseif typeOfValue == "string" then
childObject = Instance.new("StringValue")
end
childObject.Name = childName
childObject.Value = value
childObject.Parent = folderObject
end
folderObject.Parent = plr
end
-- get playerdata
local key, data = dataPrefix..plr.UserId, nil
local success, err
local trys = 0
-- Atempt to get save data
repeat
success, err = pcall(function()
data = DSS:GetAsync(key)
end)
trys += 1
until success or trys == maxTries -- if success or reached max trys stop attempting to get data
if success then
LoadData(plr, data)
elseif not success then
plr:Kick("DataStoreService may be suffering connection difficulties at this moment, please try playing again later to avoid data loss.") -- replace with ui thing later
end
-- saves player data every 5 mins to prevent data loss
task.spawn(function()
while task.wait(SAVE_INTERVAL) do
pcall(function()
SaveData(plr)
end)
end
end)
-- on character added
plr.CharacterAdded:Connect(function(char)
char:WaitForChild("Humanoid").Died:Connect(function()
local tag = char.Humanoid:FindFirstChild("creator")
if tag and tag.Value then
local ls = tag.Value:FindFirstChild("leaderstats")
if ls then ls.Kills.Value += 1 end
end
end)
end)
end)
-- on player removing
Players.PlayerRemoving:Connect(function(plr)
SaveData(plr)
dataCache[plr] = nil
end)
-- saves every player's data on server shutdown
if not RS:IsStudio() then
game:BindToClose(function()
for _, plr in (Players:GetPlayers()) do
task.spawn(function()
SaveData(plr)
dataCache[plr] = nil
end)
end
end)
end
By the way I tested it, and it works!