Saving Tools with custom attributes to datastore

I was working an a system to save the player’s tools with custom attributes to data store and load them whenever the player joins

local dss = game:GetService("DataStoreService")
local toolsDS = dss:GetDataStore("Sus")

local toolsFolder = game.ServerStorage:WaitForChild("Items")

game.Players.PlayerAdded:Connect(function(plr)
	local toolsSaved = toolsDS:GetAsync(plr.UserId .. "-tools") or {}

	for i, toolData in pairs(toolsSaved) do
		local toolName = toolData.Name
		local qy = toolData.qy

		if toolsFolder:FindFirstChild(toolName) then
			local toolClone = toolsFolder[toolName]:Clone()
			toolClone:SetAttribute("qy",qy)
			toolClone.Parent = plr.Backpack
			
		end
	end

	plr.CharacterRemoving:Connect(function(char)
		char.Humanoid:UnequipTools()
	end)
end)


game.Players.PlayerRemoving:Connect(function(plr)
	local toolsOwned = {}

	for i, toolInBackpack in pairs(plr.Backpack:GetChildren()) do
		local toolData = {
			Name = toolInBackpack.Name,
			qy = toolInBackpack:GetAttribute("qy") 
		}
		table.insert(toolsOwned, toolData)
	end

	local success, errormsg = pcall(function()
		toolsDS:SetAsync(plr.UserId .. "-tools", toolsOwned)
	end)

	if errormsg then
		warn(errormsg)
	end
	
end)

I have tried to search youtube and the dev forum but all i found is saving tools without attributes
In my script, I am saving a table with the tool’s name and an attribute called qy, which stands for the quantity, which is a number value. When I rejoin my tools don’t load and i don’t understand why

3 Likes

Can you try putting :GetAsync() into a pcall and post the errors if any, the same way you did with :SetAsync()?

I have used :GetAsync() as you said and I didn’t get any errors in the console

At the line

for i, toolInBackpack in pairs(plr.Backpack:GetChildren()) do

You are using pairs to iterate, but GetChildren returns an array, not a dictionary. Either use ipairs or get rid of the iterator function completely, which simplifies things a lot.
So try:

for i, toolInBackpack in plr.Backpack:GetChildren() do

In addition, toolsSaved is also not a dictionary, it has the structure of {toolData}. That is, it is an array of dictionaries. So using pairs in

for i, toolData in pairs(toolsSaved) do

Also does nothing.

for i, toolData in pairs(toolsSaved) do

makes it so I don’t get an error saying
ServerScriptService.ToolSaver:12: attempt to index nil with ‘Name’.

I have switched

for i, toolInBackpack in pairs(plr.Backpack:GetChildren()) do

with

for i, toolInBackpack in plr.Backpack:GetChildren() do

but still, nothing happens

I have made another script witch works fine

local DataStoreService = game:GetService("DataStoreService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local function cloneBackpackData(player)
	local playerDataStore = DataStoreService:GetDataStore("PlayerBackpackData")

	-- Retrieve the backpack data from the DataStore using the player's UserId as the key
	local backpackData = playerDataStore:GetAsync(player.UserId)

	-- Check if data was retrieved successfully
	if backpackData then
		-- Iterate through the backpack data and clone the tools
		for _, child in pairs(backpackData) do
			local toolTemplate = ReplicatedStorage.Items:FindFirstChild(child.name)
			if toolTemplate then
				local newTool = toolTemplate:Clone()
				newTool.Parent = player.Backpack
				newTool:SetAttribute("qy", child.quantity)
			else
				print("Tool not found:", child.name)
			end
		end
	else
		print("No backpack data found for player:", player.Name)
	end
end

-- Create a function to save the backpack data to a DataStore
local function saveBackpackData(player, backpackData)
	local playerDataStore = DataStoreService:GetDataStore("PlayerBackpackData")

	-- Save the backpack data to the DataStore using the player's UserId as the key
	playerDataStore:SetAsync(player.UserId, backpackData)
end

-- Create a function to get the backpack children
local function getBackpackChildren(player)
	local backpack = player:WaitForChild("Backpack") -- Wait for the player's Backpack to load

	local children = {} -- Table to store the backpack children

	-- Iterate through each child of the backpack and add them to the table
	for _, child in pairs(backpack:GetChildren()) do
		local childData = {
			name = child.Name,
			quantity = child:GetAttribute("qy") or 0
		}
		table.insert(children, childData)
	end

	return children -- Return the table of backpack children
end




game:GetService("Players").PlayerAdded:Connect(function(player)
	cloneBackpackData(player)
end)
	
game:GetService("Players").PlayerRemoving:Connect(function(player)
	local backpackChildren = getBackpackChildren(player)

	-- Save the backpack data to the DataStore
	saveBackpackData(player, backpackChildren)
end)
1 Like

Yeah, you got the error because now the script actually did something with toolsSaved after

for i, toolData in toolsSaved do

in

local toolName = toolData.Name

It was trying to use toolData.Name, which was empty because nothing was saved in the datastore yet. On line

local toolsSaved = toolsDS:GetAsync(plr.UserId … “-tools”) or {}

you assigned an empty table if GetAsync returns nil.

Instead of doing a simple check to see if #toolsSaved == 0, you go and copy paste an entirely new script. Thanks for wasting my time, I know not to bother helping you again.

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