My tool saving script gives players all the tools in my game randomly

I want to achieve a tool saving script that saves multiple items and does not give players all the items in the game.
The issue is that players, when they respawn or rejoin the game sometimes get all the purchasable items in the game.
I have looked all over the DevForum for solutions, however I have found none.

NOTE: Please send the code in the reply instead of sending me a model as it would be more convenient
Here’s the model: Tool Save - Roblox
I will still put the code in the post if you prefer it that way.

local datastoreservice = game:GetService("DataStoreService")
local ds = datastoreservice:GetDataStore("ToolsDataStore")
local connectionNewTool
local connectionRemoveTool 

game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:connect(function(character)
		local success,message = pcall(function()
			if player.UserId > 0 then
				ID = player.UserId
			end		
			local toolsDS = {}
			local tools = ds:GetAsync(ID)
			wait(4)  --Give the game pass tools a chance to load first.
			if tools then
				toolsDS = tools
				for _,tool in pairs(toolsDS) do				--Restore previously earned tools.
					local found = false
					for _,w in pairs(player.Backpack:GetChildren()) do
						if w.Name == tool then
							found = true
							break
						end
					end
					if not found and not (character:FindFirstChild(tool) and character:FindFirstChild(tool).ClassName == "Tool") then
						if game.ReplicatedStorage.Rewards:FindFirstChild(tool) and game.ReplicatedStorage.Rewards[tool].ClassName == "Tool" then
							game.ReplicatedStorage.Rewards[tool]:Clone().Parent = player.Backpack
							print("Tool", tool, "restored from datastore for player", player.Name)
						elseif game.ReplicatedStorage.Tools:FindFirstChild(tool) and game.ReplicatedStorage.Tools[tool].ClassName == "Tool" then
							game.ReplicatedStorage.Tools[tool]:Clone().Parent = player.Backpack 
							print("Tool", tool, "restored from datastore for player", player.Name)
						elseif game.ReplicatedStorage.ToolsDrops:FindFirstChild(tool) and game.ReplicatedStorage.ToolsDrops[tool].ClassName == "Tool" then
							game.ReplicatedStorage.ToolsDrops[tool]:Clone().Parent = player.Backpack 
							print("Tool", tool, "restored from datastore for player", player.Name)
						else
							print("DataStoreToolsScript: Player:", player.Name, "had a tool called:", tool, "But it is not in ReplicatedStorage Rewards, Tools, or ToolsDrops.  If you want it restored when they return, put it in one of those folders.")
						end
					end
				end
			end
											--Update tool database as new tools are earned.
			connectionNewTool = player.Backpack.ChildAdded:Connect(function(newTool)
				
				if newTool and newTool.ClassName == "Tool" then
					local found = false
					if toolsDS and #toolsDS > 0 then
						for _,tool in pairs(toolsDS) do  
							if tool == newTool.Name then
								found = true		-- already saved.
								break
							end
						end
					end
					if not found then
						toolsDS[#toolsDS + 1] = newTool.Name
						wait(1)  --prevent overloading datastore.
						local success,message = pcall(function()
							ds:SetAsync(ID,toolsDS)
						end)
						if success then
							print("New tool ("..newTool.Name..") saved for player", player.Name)
						else
							warn("ERROR in SetAsync NewTool", script.Name,message)
						end
						
					end
				end
			end)
			
			connectionRemoveTool = character.ChildRemoved:Connect(function(removeTool)
				if removeTool.ClassName == "Tool" then
					local removeToolName = removeTool.Name
					wait(.2)
					if removeTool and removeTool.Parent == player.Backpack then
						--It just move to the backpack.
					else
						local found = false
						if toolsDS and #toolsDS > 0 then
							for i,tool in pairs(toolsDS) do  
								if tool == removeToolName then
									found = true
									toolsDS[i] = ""
									break
								end
							end
						end
						if found then
							wait(1)  --prevent overloading datastore.
							local success,message = pcall(function()
								ds:SetAsync(ID,toolsDS)
							end)
							if success then
								print("Removed tool ("..removeToolName..") from player", player.Name)
							else
								warn("ERROR in SetAsync RemoveTool", script.Name,message)
							end
							
						end
					end
				end
			end)
			
		end)
		if not success then
			warn("ERROR in GetAsync", script.Name,message)
		end
	end)
		
	player.CharacterRemoving:Connect(function ()
		if connectionNewTool and connectionNewTool.Connected then
			connectionNewTool:Disconnect()
		end
		if connectionRemoveTool and connectionRemoveTool.Connected then
			connectionRemoveTool:Disconnect()
		end
	end)
end)

This line is useless and will cause extra delay, take it out. GetAsync is an Asynchronous task so it will yield the thread until it gets a result.

1 Like

Okay, I will try that. Is it possible that the line is causing these problems?

no, I’m reviewing the rest of the code now

1 Like

Oh okay. Thanks for clarifying.

The only things that will be in the players Backpack are things that get Replicated from StarterPack


again 0 point to this line.


As for the problem you are having I can’t seem to find anything. Can you tell me the problem exactly. When the player joins they get all the tools in your game even ones they don’t own?

Well, not when they first join. It only happens when they rejoin or respawn. And yes, they do get the tools they don’t even own.

The saving system you have is a little crazy, you are making datastore calls on character added and saving things when they get removed from the character there are a lot of things that you shouldn’t be doing in this script that you are doing.

I’m going to write out a whole script with comments then send it to you, give me a couple minutes.

Oh okay, thank you for helping me.

code
local DataStorService = game:GetService("DataStorService")
local DataStore = DataStorService:GetDatStore("ToolsDataStore")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Players = game.Players

local PlayerData = {} -- table with all the players data
-- you will want to add functions to add tools to the PlayerData table when they buy it, which will add it to the table and put a tool in their Backpack

local function onCharacterAdded (player) -- this will run each time the player respawns
    -- assuming nothing is in StarterPack
    for _,tool in ipairs(PlayerData[player]) do -- this assumes the player data table is an array with a list of tool names, if it's a dictionary you can would use key,value
        local ToolObject = ReplicatedStorage.TooldsFolder:FindFirstChild(tool)
        if ToolObject then
            ToolObject:Clone().Parent = player.Backpack
        end
    end
end



Players.PlayerAdded:Connect(function(player) -- this will run once for each player
    
    local key = player.UserId -- key 
    local Data

    local success,err = pcall(function() -- only making one Datastore call when they join and one when they leave
        Data = DataStore:GetAsync(key)
    end)


    if not success then 
        warn(err)
        -- datastore called failed you can kick the player or do whatever you want
    end

    if Data then
        PlayerData[player] = Data
    else
        -- new player
        PlayerData[player] = {} -- default tools or whatever you want
    end

    player.CharacterAdded:Connect(onCharacterAdded)(player) -- run the character added
end)


Players.PlayerRemoving:Connect(function(player) -- this will run once for each player
    local DataToSave = PlayerData[player]
    local key = player.UserId
    local success,err = pcall(function()
        DataStore:SetAsync(key,DataToSave) -- this is basic it is really better to use UpdateAsync but that's more advanced
    end)
end)
2 Likes

Thank you! I will try this out and mark your post as a solution.

Also @elonrocket, what do I do if there are items in StarterPack?

you don’t do anything, I was just saying because if you put things in StarterPack it will replicate to each player (regardless if they own it, also it won’t affect their data table), if you want every player to have a default tool you can put it in StarterPack. Otherwise keep the tools in ReplicatedStorage.

Oh okay. Thank you for this quick answer.

1 Like

Wait, currently the tools aren’t saving.
Btw, not all tools are from the shop. Some are from animal drops.

I cannot write out your entire game for you, you have to take the template and incorporate it into your game.

Oh okay, thanks for the clarification.