Save tool folder

Hi, I am making a simulator game and whenever you buy a tool, that tool will be saved in your playerTools (not player backpack) to verify it has been bought and you don’t have to buy it again. Now I want to save those tools in that folder when you leave and rejoin. The script I have now is:

local players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local ServerStorage = game:GetService("ServerStorage")

local DataStore = DataStoreService:GetDataStore("Storage")
local ItemsFolder = ServerStorage:FindFirstChild("Tools")
local starterTool = ServerStorage:FindFirstChild("StarterTool")


players.PlayerAdded:Connect(function(Player)
	
	local loadedData
	local playerTools = ServerStorage:FindFirstChild("PlayerTools"):WaitForChild(Player.Name)

	local worked, err = pcall(function()
		  loadedData = DataStore:GetAsync(Player.UserId)
		for i, v in pairs(loadedData) do -- problem here
			if v:IsA("Tool") then
				v:Clone().Parent = playerTools
				print("yes")
			end
		end
	end)
	
	if loadedData ~= nil then
		for i , v in pairs(loadedData) do
			local Tool = starterTool:GetChildren(v)
			if Tool then
				Tool:Clone().Parent = Player.Backpack
				Tool:Clone().Parent = Player.StarterGear
			end
		end
	end
end)

players.PlayerRemoving:Connect(function(Player)
	local tools = {}
	local playerTools = ServerStorage:FindFirstChild("PlayerTools"):WaitForChild(Player.Name)
	for i,v in pairs(playerTools:GetChildren()) do
		if v:IsA("Tool") then
			table.insert(tools,v.Name)
		end
	end
	
	local worked, err = pcall(function()
		DataStore:SetAsync(Player.UserId,tools)
	end)
	
	if not worked then warn(err)
	end
end) -- this works 

However, when you join it doesn’t load the tools back into the playerTools. I think it has something to do with the loop not getting the children, I have tried changing the for i, v in pairs(loadedData) do to
for i, v in pairs(loadedData:GetChildren()) do but that didn’t work either. Is there anyone that can help me with this?

2 Likes

Why would you do this to verify if someone already has brought something when you could just check the data storage to see if someone has brought something already.

oh no I didn’t know how to say that someone has bought the item so I said verify

when you buy an item it gets placed in the playertools, so the shop can see that you bought it and equip it, and I want to save those items you bought so you don’t have to buy them again when you rejoin

Hey there,

I am seeing 2 problems with your code.

Problem 1:

loadedData = DataStore:GetAsync(Player.UserId)
for i, v in pairs(loadedData) do -- problem here
	if v:IsA("Tool") then
		v:Clone().Parent = playerTools
		print("yes")
	end
end

In this section you are loading the data that is saved for the player. When the player is leaving you are saving the tool names (which is the correct way). However, in this section you are expecting that the datastore is loading the tools itself ( if v:IsA("Tool") then ).

Problem 2:

if loadedData ~= nil then
	for i , v in pairs(loadedData) do
		local Tool = starterTool:GetChildren(v)
		if Tool then
			Tool:Clone().Parent = Player.Backpack
			Tool:Clone().Parent = Player.StarterGear
		end
	end
end

at the line local Tool = starterTool:GetChildren(v) did you mean to use FindFirstChild?

Hope this helps!

For reference, if he intended to do :GetChildren() he should use a for i,v in pairs loop to iterate through the children.

Still don’t understand why you can’t just check the data store to see if someone owns it.

The second problem is the part for when the player first joins, so I will try that later but for what do I need to search then, do I need to look for a string? if yes, how?

Here’s your issue, you cannot call :GetChildren() on a datastore table. You can iterate through a table using a for i,v in pairs loop but this is incorrect.

how would I do it the correct way? (sorry I am kinda new to scripting)

Essentially, :GetChildren() is not a valid property of a Datastore, this is what is causing your error.

is there any way I could do it differently/fix it

This isn’t going to be a simple fix, as your entire code is referencing invalid objects, :IsA() cannot be called on a Datastore, and checking whether it’s a tool is just going to error.

hmm, I’ll try something else then

If you replace the GetChildren(v) with FindFirstChild(v) it should work perfectly.

As for the first problem I reported you could remove this entire loop and combine it with the second one. It will look like this then

if loadedData ~= nil then
	for i , v in pairs(loadedData) do
		local Tool = starterTool:FindFirstChild(v)
		if Tool then
			Tool:Clone().Parent = Player.Backpack
			Tool:Clone().Parent = Player.StarterGear
			Tool:Clone().Parent = playerTools
		end
	end
end
Your entire code fixed would look like this
local players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local ServerStorage = game:GetService("ServerStorage")

local DataStore = DataStoreService:GetDataStore("Storage")
local ItemsFolder = ServerStorage:FindFirstChild("Tools")
local starterTool = ServerStorage:FindFirstChild("StarterTool")


players.PlayerAdded:Connect(function(Player)

	local loadedData
	local playerTools = ServerStorage:FindFirstChild("PlayerTools"):WaitForChild(Player.Name)

	local worked, err = pcall(function()
		loadedData = DataStore:GetAsync(Player.UserId)
	end)

	if loadedData ~= nil then
		for i , v in pairs(loadedData) do
			local Tool = ItemsFolder:FindFirstChild(v)
			if Tool then
				Tool:Clone().Parent = Player.Backpack
				Tool:Clone().Parent = Player.StarterGear
				Tool:Clone().Parent = playerTools
			end
		end
	else
		for i , v in pairs(starterTool:GetChildren()) do
			if v:IsA("Tool") then
				v:Clone().Parent = Player.Backpack
				v:Clone().Parent = Player.StarterGear
				v:Clone().Parent = playerTools
			end
		end
	end
end)

players.PlayerRemoving:Connect(function(Player)
	local tools = {}
	local playerTools = ServerStorage:FindFirstChild("PlayerTools"):WaitForChild(Player.Name)
	for i,v in pairs(playerTools:GetChildren()) do
		if v:IsA("Tool") then
			table.insert(tools,v.Name)
		end
	end

	local worked, err = pcall(function()
		DataStore:SetAsync(Player.UserId,tools)
	end)

	if not worked then warn(err)
	end
end)
local players = game:GetService("Players")
local dss = game:GetService("DataStoreService")
local ss = game:GetService("ServerStorage")
local location = game.ServerStorage -- Location of Tools

local ds = dss:GetDataStore("Storage")
local data = {tools = {}}

game.Players.PlayerAdded:Connect(function(player)
	local tools = ds:GetAsync(player.UserId)
	if tools.tools then
		for i,v in pairs(tools.tools) do
			if location:FindFirstChild(v) then
				location:FindFirstChild(v):Clone().Parent = player.Backpack
			end
		end
	else
		print("No tools stored")
	end
end)

sadly, this didn’t work. That part is used for when the player has no data yet and it looks trough the starterTool to clone the starter tool in the players backpack. What I want is when a player buys something in the shop, which then gets cloned to the playerTools, for that tool to save in the playerTools.

This will allow you to store more than 1 tool, simply choose the location of the tool and save it.

I’ll try that (character limit)

To set someone’s tools, use this. (I had this for debugging purposes)

local data = {tools = {"Tool1","Tool2"}}
local player = game.Players.LocalPlayer
game:GetService("DataStoreService"):GetDataStore("Storage"):SetAsync(player.UserId,data)