my first time creating data stores, and im having some issues with it.
im trying to save whatever is in a table, and load it as a string value on join.
it doesnt seem to work though
[btw no errors]
local DataStoreService = game:GetService("DataStoreService")
local SkinDataStore = DataStoreService:GetDataStore("PlayerSkins")
local skinsOwned = {}
Players.PlayerAdded:Connect(function(Player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "skins"
leaderstats.Parent = Player
for i,v in pairs(skinsOwned) do
local skin = Instance.new("StringValue")
skin.Name = v.Name
skin.Parent = Player.skins
skin.Value = SkinDataStore:GetAsync(Player.UserId) or false
end
Player.skins.ChildAdded:Connect(function(added)
if added:IsA("StringValue") then
print("string")
table.insert(skinsOwned, added.Name)
wait(1)
print(skinsOwned)
end
end)
end)
Players.PlayerRemoving:Connect(function(Player)
local Success, Error = pcall(function()
return SkinDataStore:SetAsync(Player.UserId.."SkinsOwned", skinsOwned)
end)
if Error then
warn(Error)
end
end)```
Seems like the game doesn’t have enough time to save data before it shuts down.
Try this:
local runService = game:GetService("Run Service") --this line goes at the top of the script
game:BindToClose(function()
if runService:IsStudio() then task.wait(5) return end
for _, player in pairs(Players:GetPlayers()) do
save(player)
end
end)
note: for this to work, you need to move your saving and loading functions so they are seperate. Example:
local function load(player)
--loading code here
end
local function save(player)
--saving code here
end
Players.PlayerAdded:Connect(load)
Players.PlayerRemoving:Connect(save)
Also, that code will globally add every player’s skins to one table. You need to do it individually, for each player.
local function load(player)
local skins = Instance.new("Folder")
skins.Name = "OwnedSkins"
skins.Parent = player
local skinsToAdd = {} --all of the skins in the game
for i, skin in ipairs(skinsToAdd) do
local var = Instance.new("BoolValue")
var.Name = skin
var.Parent = skins
var.Value = false
end
local playerData
local success, err = pcall(function()
playerData = yourDataStore:GetAsync(your_key)
end)
if success then
if playerData == nil then --give default data if first time playing
playerData = {
["Skins"] = {}
}
end
for i, skin in pairs(playerData["Skins"]) do
skins[skin].Value = true
end
elseif not success and err then
warn("Data loading failed")
warn(err)
load(player)
end
end
local function save(player)
local folder = player.OwnedSkins
local ownedSkins = {}
for i, skin in pairs(folder:GetChildren()) do
if skin.Value == true then
table.insert(ownedSkins, skin.Name)
end
end
local playerData = {
["Skins"] = ownedSkins
}
local success, err = pcall(function()
yourDataStore:SetAsync(your_key, playerData)
end)
if success then
--yay it saved
elseif not success and err then
warn("Loading failed")
warn(err)
save(player)
end
end
Players.PlayerAdded:Connect(load)
Players.PlayerRemoving:Connect(save)
game:BindToClose(function()
--enter code I sent above under BindToClose()
end)
This code allows each player’s skins to be saved. Your code would combine every player’s owned skins, which is essentially everyone having each other’s data.
doesnt seem to wrok at all, no warnings, no errors.
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local SkinDataStore = DataStoreService:GetDataStore("PlayerSkins")
local function load(player)
local skins = Instance.new("Folder")
skins.Name = "OwnedSkins"
skins.Parent = player
local skinsToAdd = {
Skin1 = "Vector",
Skin2 = "Neon"
}
for i, skin in ipairs(skinsToAdd) do
local var = Instance.new("BoolValue")
var.Name = skin
var.Parent = skins
var.Value = false
end
local playerData
local success, err = pcall(function()
playerData = SkinDataStore:GetAsync(player.UserId)
end)
if success then
if playerData == nil then --give default data if first time playing
playerData = {
["Skins"] = {}
}
end
for i, skin in pairs(playerData["Skins"]) do
skins[skin].Value = true
end
elseif not success and err then
warn("Data loading failed")
warn(err)
load(player)
end
end
local function save(player)
local folder = player.OwnedSkins
local ownedSkins = {}
for i, skin in pairs(folder:GetChildren()) do
if skin.Value == true then
table.insert(ownedSkins, skin.Name)
end
end
local playerData = {
["Skins"] = ownedSkins
}
local success, err = pcall(function()
print(ownedSkins)
SkinDataStore:SetAsync(player.UserId, playerData)
end)
if success then
--yay it saved
elseif not success and err then
warn("Loading failed")
warn(err)
save(player)
end
end
Players.PlayerAdded:Connect(load)
Players.PlayerRemoving:Connect(save)
game:BindToClose(function()
if RunService:IsStudio() then task.wait(5) return end
for _, player in pairs(Players:GetPlayers()) do
save(player)
end
end)```
First, I would recommend using DataStore2 in general. Writing datastore code properly is hard, and it’s even harder to tell if it’s working properly.
Second, the line I quoted is one problem. You save the data as a table, but skin is a StringValue. It doesn’t make sense to set a string value to a table.
So you should do something like this to get the data:
skinsOwned = SkinDataStore:GetAsync(Player.UserId) or {}
-- Do a loop over skinsOwned creating the StringValues
You also need to use protected calls and retrying to make sure you data saves. Again, you should use DataStore2 to do this stuff for you. It’s a great resource.
If you aren’t going to use DataStore2, here are something you need:
Use protected calls, if the calls fails, you need to redo the check. If it fails enough, kick the player to prevent their data from being reset
Remember to use game.BindOnClose to save all the player’s data if something happens with the server unexpectedly
You need to update skinsOwned based on changes to the leaderstats. Currently you load the data into skinsOwned, then put that data in leaderstats, then save skinsOwned, which skips changes made to leaderstats
Parent leaderstats after loading, so in the rest of your code you can guarantee leaderstats has loaded data (just a tip)
Another thing you might want to consider is this resource:
It saves the leaderstats folder and makes this stuff pretty easy. Basically all you need to do is use WaitForChild(“leaderstats”) before you use leaderstats and leaderstats will save (the waitforchild makes it wait until leaderstats is fully loaded).