Datastore not working correctly

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)```
1 Like

–IF THE SCRIPT HAS PREVIOUSLY WORKED–

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.

1 Like

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)```
1 Like

Because it uses ipairs(), you need numerical keys. I do not see any keys there at all.
You could do:

local skins = {
    [1] = "Vector",
    [2] = "Neon"
}

or

local skins = {
    "Vector",
    "Neon"
}

Alternatively, you could just use pairs().

local skinsToAdd = {
    ["Skin1"] = "Vector",
    ["Skin2"] = "Neon"
}

for i, skin in pairs(skinsToAdd) do
    --code here
end
2 Likes

Try using task.wait(2) so it can have time to load everything.

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).

works, thanks so much. i found the problem I made

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.