[RESOLVED] Problem with data being deleted with DataStoreService

Hey Devs!

I am currently making a save and load system for player inventories. I have an issue with loading the data, to sum it up, the game saves the data but when loading it the saved data is deleted.

Here is a video of the problem.

Given the fact that I have tried to solve it myself, I have not been able to find the solution to the problem.

Here is the script I am currently using.

local ds = game:GetService("DataStoreService")
local plrData = ds:GetDataStore("InventorySaves")

-- load data
local function onPlayerJoin(plr)
	local key = "ID-"..plr.UserId
	print("ID-"..plr.UserId)
	
	print("[+] Player " .. plr.Name .. " has joined the game")

	local ItemFolder = Instance.new("Folder", plr)
	ItemFolder.Name = "PlayerItems"

	local ItemSwords = Instance.new("Folder", ItemFolder)
	ItemSwords.Name = "Swords"

	local ItemBoosts = Instance.new("Folder", ItemFolder)
	ItemBoosts.Name = "Boosts"
	
	local success, data = pcall(function()
		return plrData:GetAsync(key)
	end)
	
	if success then
		print(data)
		
		if data ~= nil then
			print("Data was found for "..plr.Name.." ("..plr.UserId..")")
			
			for _, v in pairs(data) do
				local tool = FindToolInFolders(game.ReplicatedStorage.ItemsFolder, v)
				if tool then
					local ItemClone = tool.Handle:Clone()
					ItemClone.Name = tool.Name
					local destinationFolder = GetDestinationFolder(tool, plr)
					ItemClone.Parent = destinationFolder
				end
			end
		else
			print("New player")
		end
	else
		print("Error loading data for "..plr.Name..": " .. data)
	end
end

-- saves data
local function onPlayerLeft(plr)	
	local key = "ID-"..plr.UserId
	local inveSaves = {}
	
	print("[-] Player " .. plr.Name .. " has left the game")
	
	pcall(function()
		local swordsFolder = plr.PlayerItems:FindFirstChild("Swords")
		if swordsFolder then
			for _, sword in pairs(swordsFolder:GetChildren()) do
				if sword:IsA("Part") then
					table.insert(inveSaves, sword.Name)
					print("new sword save: "..sword.Name)
				end
			end
		end

		local boostsFolder = plr.PlayerItems:FindFirstChild("Boosts")
		if boostsFolder then
			for _, boost in pairs(boostsFolder:GetChildren()) do
				if boost:IsA("Part") then
					table.insert(inveSaves, boost.Name)
					print("new boost save: "..boost.Name)
				end
			end
		end
		
		print(inveSaves)

		plrData:SetAsync(key, inveSaves)
	end)
end

-- Function to find a tool in folders
function FindToolInFolders(parentFolder, toolName)
	for _, folder in pairs(parentFolder:GetChildren()) do
		local tool = folder:FindFirstChild(toolName)
		if tool then
			return tool
		end
	end
	return nil
end

-- Function to get the destination folder for the tool
function GetDestinationFolder(tool, player)
	local folderName = tool.Parent.Name
	local destinationFolder = player.PlayerItems:FindFirstChild(folderName)

	if not destinationFolder then
		destinationFolder = Instance.new("Folder", player.PlayerItems)
		destinationFolder.Name = folderName
	end

	return destinationFolder
end

game.Players.PlayerAdded:Connect(onPlayerJoin)
game.Players.PlayerRemoving:Connect(onPlayerLeft)

If anyone has any ideas on how to solve this problem, it would be a great help! :wink:

1 Like

I can’t really see properly, are you attempting to datastore a Tool?

From my understanding of looking over the script, you never once call upon “ServerStorage” which is where you keep said tool, you have to script the function of it going back into the players swords folder, it wont automatically be there because of a datastore.

Hi, to give you more information, the objects are stored in ReplicatedStorage, that is in this image.
image

It is there where all the tools that occupy the inventory load are stored, the item that is in ServerStorage, this one.
image

It is a test one, so that the inventory interface can detect it, but that is another topic.

The main problem is the cause of the deletion of the data when I load them, if you see in the Output you can see how the data is saved and loaded, but it does not work as it should.

If you check the script that I have provided, you can never notice that I have given an instruction to delete data on loading (at least what I have seen), it is as if it does not exist in the loading process.

That would be the main problem, anyway, thanks for visiting my topic. :hidere:

Hello, I’ve looked up the topic and this is what I’ve come up with:


You’re using “PlayerRemoved” and playing in Studio, have you tried testing in-game instead?

The issue might be the scope of your inveSaves table. In the function for saving player data, you’re creating a new inveSaves table each time a player leaves. This table is local to the onPlayerLeft function which means it’s not accessible from the onPlayerJoin function.

When a player joins the game, the load function tries to load in data from the inveSaves table, but since this table is not defined in the function or globally, the inveSaves table is likely empty or nil when you try to load the data.

To fix this, you should try defining the inveSaves at the top of the script. This makes it a global variable that accessible from all functions in the script. Something like:

local ds = game:GetService("DataStoreService")
local plrData = ds:GetDataStore("InventorySaves")
local inveSaves = {}  -- define inveSaves here

-- load data
local function onPlayerJoin(plr)
    -- ... (rest of your script)
end

-- saves data
local function onPlayerLeft(plr)  
    local key = "ID-"..plr.UserId
    inveSaves = {}  -- reset inveSaves here, but don't redefine it

    -- ... (rest of your script)
end

-- ... (rest of your script)

(srry for long explanation that might not even work or be the issue)

No, the function should work just fine even in-studio. After all, I’m having a somewhat similar issue to his with my data but the saving still works correctly with .PlayerRemoved. :wink:

Hey, about your solution, I have tried it, but I still have the same problem, and yes, I agree with you that creating a table for each player is a very bad idea because of future conflicts that may arise.

Something that might be helpful and that I did not mention is that the script is executed exactly in ServerScriptService. (something obvious)

Anyway, thanks for trying to help this problem I have. :wink:

Ok, after looking at many possible solutions, the save worked!

The solution was to use game:BindToClose:(), as I was testing it in Studio, but the game fails to save the :SetAsync() properly when in Studio.

Here is part of the script with the solution

local function SaveData(player)
	local key = "ID-"..player.UserId
	local inveSaves = {}

	print("[-] Player " .. player.Name .. " has left the game")

	local swordsFolder = player.PlayerItems:FindFirstChild("Swords")
	if swordsFolder then
		for _, sword in pairs(swordsFolder:GetChildren()) do
			if sword:IsA("Part") then
				table.insert(inveSaves, sword.Name)
			end
		end
	end

	local boostsFolder = player.PlayerItems:FindFirstChild("Boosts")
	if boostsFolder then
		for _, boost in pairs(boostsFolder:GetChildren()) do
			if boost:IsA("Part") then
				table.insert(inveSaves, boost.Name)
			end
		end
	end

	local success, result = pcall(function()
		plrData:SetAsync(key, inveSaves)
	end)

	if not success then
		warn("Failed to save "..player.Name.." data : "..result)
	end
end

-- saves data
local function onPlayerLeft(plr)	
	if not game:GetService("RunService"):IsStudio() then
		local success = pcall(function()
			SaveData(plr)
		end)
	end
end

game:BindToClose(function()
	for _, plr in pairs(game:GetService("Players"):GetPlayers()) do
		local success = pcall(function()
			SaveData(plr)
		end)
	end
end)

Thanks to everyone who tried to help with this problem. See you next time! :wink:

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