I agree with POG about using SetAsync, Im more used to it.
I was playing with your code a little, this code probably is not friendly with other systems you could have, I deleted the leader board and stuff that was not needed for the test, I was playing… so I added a repeat function instead of repeat return etc. And modified keys in your tables.
Its working fine for me, when I place a model rig into the player folder, and leave/close studio. It saves normally, when joining again its printing what its saved.
Obviously it has an issue trying to save twice when in a real server, it shutdown. Cause apparently PlayerRemoving and BindToClose can fire both when a real server shutdown. I just added a InStudio check to not fire it from studio.
Give it a try, dont forget to add your leaderstats and stuff.
local plrs = game:GetService("Players")
local DSS = game:GetService("DataStoreService")
local playerDataStore = DSS:GetDataStore("PlayerData")
local RS = game:GetService("RunService")
local cs = game:GetService("CollectionService")
local function retry(func, attempt)
if not attempt then
attempt = 0
end
local s, m = pcall(function()
return func()
end)
if not s then
attempt = attempt + 1
--print(attempt)
--warn(m, "Attempt:", attempt)
task.wait(2)
return retry(func, attempt)
end
if attempt == 5 and not s then
warn('Error' .. tostring(m))
return false
end
return s, m
end
local function loadData(player:Player)
local plrNPCs = Instance.new("Folder")
plrNPCs.Parent = player
plrNPCs.Name = "PlayerNPCFolder"
local deceasedPlrNPCs = Instance.new("Folder")
deceasedPlrNPCs.Parent = plrNPCs
deceasedPlrNPCs.Name = ("DeceasedNPCs")
local s, m = retry(function()
return playerDataStore:GetAsync(player.UserId)
end)
if s then
warn("DSS connection success")
if m then
warn("data found for:", player)
print(m)
for _, items in pairs(m) do
--print(items)
end
else
warn("player has not data")
end
else
warn("DSS connection failed after retries", player)
end
end
function saveData(player)
local data = {}
for _, item in pairs(player:WaitForChild("PlayerNPCFolder"):GetChildren()) do
if item:IsA("Model") then
local bodycolors = {}
local gender
local accessory = false
for _, bodypart in pairs(item:GetChildren()) do
if bodypart.Name == "Head" or bodypart:IsA("MeshPart") then
local colors = {
R = math.floor(bodypart.Color.R*255),
G = math.floor(bodypart.Color.G*255),
B = math.floor(bodypart.Color.B*255)
}
bodycolors[bodypart.Name] = colors
elseif bodypart:IsA("Accessory") then
accessory = bodypart.Name
end
end
for _, tag in pairs(cs:GetTags(item)) do
if tag == "Male" or tag == "Female" then
gender = tag
end
end
table.insert(data, {
NameNPC = item.Name,
Accessory = accessory,
BodyColors = bodycolors,
Gender = gender
})
end
end
print(#data)
if #data > 0 then
warn("saving")
local s, m = retry(function()
return playerDataStore:SetAsync(player.UserId, data)
end)
if s then
warn("data saved for:", player)
else
warn("data not saved for:", player)
end
end
end
plrs.PlayerAdded:Connect(loadData)
plrs.PlayerRemoving:Connect(saveData)
game:BindToClose(function()
if (RS:IsStudio()) then
warn("BindToClose in Studio should do nothing")
--task.wait(1)
else
-- Shutdown in a real Server
-- In a real server when it shutdown, its trying to save twice.
-- One from PlayerRemoving event and one from this BindToClose
for _, plr in pairs(plrs:GetPlayers()) do
task.spawn(function()
saveData(plr)
end)
end
end
end)