Script doesn't update a table when a tool is removed from both the backpack and character

Hello!

I have got a tool saving script. But it doesn’t recheck if a tool has been removed from the player’s backpack and their character. And what I want it to do is update the tools table and remove that tool that has been removed from the player.

Script:

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

local player_data = DataStoreService:GetDataStore("TestData4")
local RemoveSoldItem = ReplicatedStorage.Remotes.RemoveSoldItem
local LostItem = ReplicatedStorage.Remotes.LostItem

local tools = {} -- Stores both backpack & equipped tools
local CharacterReferences = {}

-- Function to save a player's inventory safely
local function SaveInventory(client)
	if not client then return end -- Safety check

	local key = "client_" .. client.UserId
	local Backpack = client:FindFirstChild("Backpack") or Instance.new("Backpack", client)
	local Character = client.Character
	tools[client] = {BackpackTools = {}, EquippedTools = {}}

	-- ✅ Save tools from Character (equipped tools)
	if Character then
		for _, item in ipairs(Character:GetChildren()) do
			if item:IsA("Tool") then
				table.insert(tools[client].EquippedTools, item.Name)
			end
		end
	end

	-- ✅ Save tools from Backpack
	for _, item in ipairs(Backpack:GetChildren()) do
		if item:IsA("Tool") then
			table.insert(tools[client].BackpackTools, item.Name)
		end
	end

	-- ✅ Safe data saving using UpdateAsync
	local success, err = pcall(function()
		player_data:UpdateAsync(key, function(oldData)
			return tools[client]
		end)
	end)

	if success then
		print("💾 Saved Inventory for " .. client.Name .. ": Equipped[" .. table.concat(tools[client].EquippedTools, ", ") .. "] Backpack[" .. table.concat(tools[client].BackpackTools, ", ") .. "]")
	else
		warn("❌ Failed to save inventory for " .. client.Name .. ": " .. err)
	end
end

-- Function to load a player's inventory
local function LoadInventory(client)
	local key = "client_" .. client.UserId
	local inventory = player_data:GetAsync(key) or {BackpackTools = {}, EquippedTools = {}}
	tools[client] = inventory
	print("📦 Loaded Inventory for " .. client.Name .. ": Equipped[" .. table.concat(inventory.EquippedTools, ", ") .. "] Backpack[" .. table.concat(inventory.BackpackTools, ", ") .. "]")

	local Backpack = client:FindFirstChild("Backpack") or Instance.new("Backpack", client)

	-- Clear existing tools before loading
	for _, item in ipairs(Backpack:GetChildren()) do
		if item:IsA("Tool") then
			item:Destroy()
		end
	end
	local Character = client.Character
	if Character then
		for _, item in ipairs(Character:GetChildren()) do
			if item:IsA("Tool") then
				item:Destroy()
			end
		end
	end

	-- ✅ Load Backpack tools
	for _, name in ipairs(inventory.BackpackTools) do
		local tool = ReplicatedStorage.ItemAssets:FindFirstChild(name) or ReplicatedStorage.LureAssets:FindFirstChild(name)
		if tool then
			local ClonedTool = tool:Clone()
			ClonedTool.Parent = Backpack
			print("✔ Added tool to backpack:", name)
		else
			warn("⚠ Item could not be cloned:", name)
		end
	end

	-- ✅ Load Equipped tools into Character
	if Character then
		for _, name in ipairs(inventory.EquippedTools) do
			local tool = ReplicatedStorage.ItemAssets:FindFirstChild(name) or ReplicatedStorage.LureAssets:FindFirstChild(name)
			if tool then
				local ClonedTool = tool:Clone()
				ClonedTool.Parent = Character
				print("✔ Equipped tool:", name)
			else
				warn("⚠ Item could not be cloned:", name)
			end
		end
	end
end

-- Handles when a player joins
Players.PlayerAdded:Connect(function(client)
	client.CharacterAdded:Wait()
	local char = client.Character
	CharacterReferences[client.UserId] = char
	LoadInventory(client) -- Load inventory on join
end)

-- Handles when a player leaves
Players.PlayerRemoving:Connect(function(client)
	-- ✅ Move equipped tools back to the backpack before saving
	local char = CharacterReferences[client.UserId]
	if char then
		print("Character found before player leaves:", char:GetChildren())
		for _, item in ipairs(char:GetChildren()) do
			if item:IsA("Tool") then
				local itemClone = item:Clone()
				itemClone.Parent = client.Backpack
				item:Destroy()
				print("Moved " .. item.Name .. " to the player's backpack!")
			end
		end
	else
		print("❌ No character found for", client.Name)
	end

	-- ✅ Update tools table with current backpack tools
	local Backpack = client:FindFirstChild("Backpack")
	if Backpack then
		tools[client] = {BackpackTools = {}, EquippedTools = {}}
		for _, item in ipairs(Backpack:GetChildren()) do
			if item:IsA("Tool") then
				table.insert(tools[client].BackpackTools, item.Name)
			end
		end
	end

	-- ✅ Save inventory after moving tools
	SaveInventory(client)

	-- ✅ Cleanup
	CharacterReferences[client.UserId] = nil
	tools[client] = nil
end)

-- Handles item removal when sold
RemoveSoldItem.OnServerEvent:Connect(function(plr, toolItemName)
	if tools[plr] then
		-- Remove from Backpack list
		local TargetPosition = table.find(tools[plr].BackpackTools, toolItemName)
		if TargetPosition then
			table.remove(tools[plr].BackpackTools, TargetPosition)
		end

		-- Remove from Equipped list
		TargetPosition = table.find(tools[plr].EquippedTools, toolItemName)
		if TargetPosition then
			table.remove(tools[plr].EquippedTools, TargetPosition)
		end

		-- ✅ Remove tool from player's Backpack or Character
		local Backpack = plr:FindFirstChild("Backpack")
		local Character = plr.Character

		if Backpack then
			local tool = Backpack:FindFirstChild(toolItemName)
			if tool then tool:Destroy() end
		end

		if Character then
			local tool = Character:FindFirstChild(toolItemName)
			if tool then tool:Destroy() end
		end

		-- ✅ Immediately save updated inventory
		SaveInventory(plr)
	end
end)

-- Handles lost items
LostItem.OnServerEvent:Connect(function(plr, ItemName)
	if tools[plr] then
		-- Remove from Backpack list
		local TargetPosition = table.find(tools[plr].BackpackTools, ItemName)
		if TargetPosition then
			table.remove(tools[plr].BackpackTools, TargetPosition)
		end

		-- Remove from Equipped list
		TargetPosition = table.find(tools[plr].EquippedTools, ItemName)
		if TargetPosition then
			table.remove(tools[plr].EquippedTools, TargetPosition)
		end

		-- ✅ Remove tool from player's Backpack or Character
		local Backpack = plr:FindFirstChild("Backpack")
		local Character = plr.Character

		if Backpack then
			local tool = Backpack:FindFirstChild(ItemName)
			if tool then tool:Destroy() end
		end

		if Character then
			local tool = Character:FindFirstChild(ItemName)
			if tool then tool:Destroy() end
		end

		-- ✅ Immediately save updated inventory
		SaveInventory(plr)
	end
end)

All help is appreciated!

It looks like your code is doing what you’re asking? See LostItem.OnServerEvent and RemoveSoldItem.OnServerEvent callbacks. On another note, I advise against allowing the client to tell the server when an item should be removed from their cached inventory. An exploiter could sell the item but not prompt the server to remove it, allowing them to sell the item in infinite quantities, leading to infinite money