Datastore not working for some reason

so recently i have made a datastore to make a dictionary save, the one dictionary for glove values does save, but the one for the scriptvalues doesnt. for some reason the dictionary says a value but when i save it and then do getasync it just prints out nil, even tough when i run it in a pcall it still says null and it saves, but it just always returns nil on the script datastore

this is my code the formatting glitched out so i will paste it unformatted sorry

local DatastoreService = game:GetService(“DataStoreService”)
local GlovesSave = DatastoreService:GetDataStore(“GloveSave”)
local ScriptSave = DatastoreService:GetDataStore(“ScriptSave”)

local function folderToDictionary(folder)
	local dictionary = {}

	for _, object in ipairs(folder:GetChildren()) do
		if object:IsA("Folder") then
			dictionary[object.Name] = folderToDictionary(object)
		elseif object:IsA("ValueBase") or object.ClassName:match("Value") then
			dictionary[object.Name] = tostring(object.Value)
		end
	end

	return dictionary
end



function GetCode()
	local code = math.random(0,999999)
	if GlovesSave:GetAsync(code) == nil then
		return code
	else
		return nil
	end
end


script.Parent.MouseButton1Click:Connect(function()
local code 
repeat code = GetCode() until code ~= nil
script.Parent.Parent.code.Text = code
local plr = game.Players:GetPlayerFromCharacter(script.Parent.Parent.Parent.Parent.Parent.Character)


local dictionary = folderToDictionary(plr.Backpack:GetChildren()[1])
local scriptDictionary = folderToDictionary(plr.Character:WaitForChild("ScriptValues"))
GlovesSave:SetAsync(code,dictionary)
GlovesSave:SetAsync(code,scriptDictionary)
end) 

`

try this:

-- Services
local DatastoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")

-- DataStores
local GlovesSave = DatastoreService:GetDataStore("GloveSave")
local ScriptSave = DatastoreService:GetDataStore("ScriptSave")

-- Helper Functions
local function folderToDictionary(folder)
    local dictionary = {}
    for _, object in ipairs(folder:GetChildren()) do
        if object:IsA("Folder") then
            dictionary[object.Name] = folderToDictionary(object)
        elseif object:IsA("ValueBase") or object.ClassName:match("Value") then
            dictionary[object.Name] = tostring(object.Value)
        end
    end
    return dictionary
end

local function GetUniqueCode(store)
    local code, success, data
    repeat
        code = math.random(0, 999999)
        success, data = pcall(function()
            return store:GetAsync(tostring(code))
        end)
    until success and data == nil
    return tostring(code) -- Ensure the code is a string for consistency
end

local function saveData(player)
    local code = GetUniqueCode(GlovesSave) -- Assuming gloves are unique enough for initial code generation

    local gloveFolder = player.Backpack:FindFirstChildWhichIsA("Folder") -- Assuming the first folder in Backpack
    local scriptFolder = player.Character:FindFirstChild("ScriptValues")

    if not gloveFolder or not scriptFolder then
        warn("Required folders not found for player " .. player.Name)
        return
    end

    local gloveDictionary = folderToDictionary(gloveFolder)
    local scriptDictionary = folderToDictionary(scriptFolder)

    local successGloves, errorGloves = pcall(function()
        GlovesSave:SetAsync(code, gloveDictionary)
    end)
    
    local successScript, errorScript = pcall(function()
        ScriptSave:SetAsync(code, scriptDictionary)
    end)

    if not successGloves or not successScript then
        warn("Failed to save data for " .. player.Name .. ": " .. (errorGloves or errorScript))
    else
        print("Data saved successfully for " .. player.Name .. " with code: " .. code)
    end
end

-- Connection
script.Parent.MouseButton1Click:Connect(function()
    local player = Players:GetPlayerFromCharacter(script.Parent.Parent.Parent.Parent.Parent.Character)
    if player then
        saveData(player)
    else
        warn("Player not found.")
    end
end)
1 Like

Since the dictionary variable is local to the folderToDictionary function’s scope, it’s currently resetting back to an empty table whenever the function is called either normally or recursively. To fix this problem the variable needs to be created outside of the function’s scope like so:

local dictionary = {}

local function folderToDictionary(folder)
	for _, object in ipairs(folder:GetChildren()) do
		if object:IsA("Folder") then
			dictionary[object.Name] = folderToDictionary(object)
		elseif object:IsA("ValueBase") or object.ClassName:match("Value") then
			dictionary[object.Name] = tostring(object.Value)
		end
	end

	return dictionary
end

Do note that you’ll need to remember to clear the dictionary afterwards, when appropriate

1 Like

i used the function twice, and assigned it to diffrent variables, so i dont think that would affect it, i will now try the other guys solution and then ill get back to you

i tried your script and now my entire thing doesnt work anymore. it doesnt even give me a code. i edited it to give me a code, but now nothing works anymore its both nil instead of only scripts not working

i tried reverting it. but even now nothing works :frowning:

To be honest, after thoroughly rereading your script I’m noticing many possible points of failures. As an example, the GetCode function is quite unusual

Why are you generating a random number in-order to use it as a DataStore key? Why not use the player’s UserId instead, which would greatly improve the performance of the script as it will no longer need to repeatedly check for an available key. I strongly suspect most of the data saving issues you’re experiencing are being caused because of this

well, actually this is kinda the point. as im making a game where u have a gui and u click the save button to save your value. and since i want to allow players to have an unlimited amount of stuff to make (because else the game would become boring) i will make them get a code for every creation

In a case like that I’d strongly recommend always using the player’s UserId as the key and saving a dictionary or array that includes their stuff instead of making a key for every item that every player in your game has, especially if they’re allowed to make an unlimited amount

well, normally i do use user id’s but this is the way i would want to have it. id rather spend my time making it work like this then scrapping the idea and doing it with userid’s. because in this way friends can easily share their gloves with others by sharing the glove id

If the save data is a dictionary, you can have its index be the glove’s ID which should make things relatively simple to share it

wait what. i think i just asked the roblox ai assistant to fix it, and it works now. let me double check

actually no but it atleast is kinda less broken

what do you mean gloves id? as far as i know the gloves dont have an ID linked to them

Well, you did mention it here:

oh well i ment like the auto generated code the script gives you

The auto generated code is technically behaving as the glove’s ID

BTW I can help fix the code the AI generated if you wish

well, i would love it if you would help fix my game with me, i can even give you credits if you want :D, or admin status

I appreciate the offer, but I tend to be quite busy with other projects lately :sweat_smile:

I’m free today which is why I’m helping people out around the forum, but soon I’ll have to leave as it’s getting quite late where I live

ah ok, thats fine, well im about to eat but here is the ai code if you wanna try to fix it

local DatastoreService = game:GetService("DataStoreService")
local GlovesSave = DatastoreService:GetDataStore("GloveSave")
local ScriptSave = DatastoreService:GetDataStore("ScriptSave")

local function ScriptfolderToDictionary(folder)
	local dictionary = {}

	for _, object in ipairs(folder:GetChildren()) do
		if object:IsA("Folder") then
			dictionary[object.Name] = ScriptfolderToDictionary(object)
		elseif object:IsA("ValueBase") or object.ClassName:match("Value") then
			dictionary[object.Name] = object.Value
	end	
	end

	return dictionary
end

local function GlovefolderToDictionary(folder)
	local dictionary = {}

	for _, object in ipairs(folder:GetChildren()) do
		if object:IsA("Folder") then
			dictionary[object.Name] = GlovefolderToDictionary(object)
		elseif object:IsA("ValueBase") or object.ClassName:match("Value") then
			dictionary[object.Name] = tostring(object.Value)
		end
	end

	return dictionary
end

function SaveGlove(plr, code)
	local GloveDictionary = GlovefolderToDictionary(plr.Backpack:GetChildren()[1])
	GlovesSave:SetAsync(code, GloveDictionary)
	print(GlovesSave:GetAsync(code))
end

function SaveScript(plr, code)
	local scriptDictionary = ScriptfolderToDictionary(plr.Character:WaitForChild("ScriptValues"))
	ScriptSave:SetAsync(code, scriptDictionary)
	print(ScriptSave:GetAsync(code))
end

function GetCode()
	local code = math.random(0, 999999)
	if GlovesSave:GetAsync(code) == nil then
		return code
	else
		return nil
	end
end

script.Parent.MouseButton1Click:Connect(function()
	local code
	repeat
		code = GetCode()
	until code ~= nil
	script.Parent.Parent.code.Text = code
	local plr = game.Players:GetPlayerFromCharacter(script.Parent.Parent.Parent.Parent.Parent.Character)

	SaveGlove(plr, code)
	SaveScript(plr, code)
end)