How do I find out what item was added to or removed from a table?

So Im messing around with DataStore2, and I cant figure out how to do the tool saving.
If I do this:

local function toolUpdate(updatedTable)
local MyTable = tools:GetTable(defaultTools)
	
	for key, value in pairs(updatedTable) do
		local thing = Instance.new("StringValue")
		thing.Name = value
		thing.Parent = player.Tools
	end
	
end

toolUpdate(tools:Get(defaultTools))

tools:OnUpdate(toolUpdate)

Then the tools in the Tool folder get duplicated every time a new one was added or one was removed.
How do I check what item was added into a table, so I can prevent this from happening?

1 Like

Bit of an odd question and I’d be lying if I said I fully understood what you meant, but I’ll take a swing at it.

When removed:

for _,value in pairs(player.Tools:GetChildren()) do
	if not table.find(updatedTable,value.Name) then
		-- tool was removed from table
	end
end

When added:

for _,value in pairs(updatedTable) do
	if not player.Tools:FindFirstChild(value) then
		-- tool was added to the table
	end
end

The problem is that you can have multiple of the same tool, so I dont think this would work.

Have you tried implementing some sort of flagging/UUID system? For saving items that an individual can have multiple of I typically resort to:

local int = 1

for _,value in pairs(player.Tools:GetChildren()) do
	table.insert(updatedTable,1,value .. "_" .. tostring(int))

	int += 1
end

And then removing that identifying number when turning the string back into a value instance.

Already tried this:

local lastTools = {}

local function toolUpdate(updatedTable)
		local MyTable = tools:GetTable(defaultTools)
		local updatedTools = updatedTable
		
		local function find(obj)
			for i,v in pairs(lastTools) do
				if v == obj then
					return true
				end
			end
			return false
		end
		
		for i,v in pairs(updatedTable) do
			if find(v) then
				table.remove(updatedTools, i)
			end
		end		
		
		for i,v in pairs(updatedTools) do
			print(v)
		end
		
		for key, value in pairs(updatedTools) do
			local thing = Instance.new("StringValue")
			thing.Name = value
			thing.Parent = player.Tools
		end
		
		lastTools = MyTable
	end
	
	lastTools = tools:GetTable(defaultTools)

But it gives some really weird results, for instance it cuts my tools in half, so if I have 5 “Sword” tools then it prints out “Sword” x2

It just doesnt seem to work correctly and I dont know how to fix it

EDIT: Still wouldnt detect when tools are removed anyway

Another issue is that Im transfering to DataStore2, my game already has 600k visits, so I cant add UUID’s to already existing items

I tried this:

local function toolUpdate(updatedTable)
		local updatedTools = {}
		
		local function find(obj)
			for i,v in pairs(lastTools) do
				if v == obj then
					return true
				end
			end
			return false
		end
		
		for i,v in pairs(updatedTable) do
			if find(v) then
				--print("removed")
				--table.remove(updatedTools, i)
			else
				table.insert(updatedTools,v)
			end
		end		
		
		for i,v in pairs(updatedTools) do
			print(v)
		end
		
		wait()
		
		for key, value in pairs(updatedTools) do
			local thing = Instance.new("StringValue")
			thing.Name = value
			--thing.Parent = player.Tools
		end
		
		lastTools = updatedTable
	end

But it still didnt work, but this time I actually know why:
The find function checks for an object name, and since you can have a couple of the same tool, it returns true.

Unless someone finds out how to do this, Ill just parent the tool to the Tools folder and ditch the whole table thing.
Of course this isnt the best solution, as it is advised to change stats and values with datastore2 on the OnUpdate function, but this is literally impossible to solve

local function toolUpdate(updatedTable)
	local MyTable = tools:GetTable(defaultTools)
	
	for _, v in pairs(player.Tools:GetChildren()) do
		v:Destroy()
	end

	for key, value in pairs(updatedTable) do
		local thing = Instance.new("StringValue")
		thing.Name = value
		thing.Parent = player.Tools
	end
end

toolUpdate(tools:Get(defaultTools))

tools:OnUpdate(toolUpdate)

try this

1 Like

The issue is that my custom backpack system would basically reset every new tool you get, since they get all deleted (every item would get unequipped)

1 Like

I was wondering, instead of giving someone a tool OnUpdate, why don’t you just give them the tool in buy item script?

1 Like

Datastore2 generally advises for value changes to be hooked up to OnUpdate, but I was thinking of this too since the solution is still not found

Does tools:GetTable(defaultTools) return an array? {"tool1", "tool2", "tool3', -- etc..}

1 Like

Yes, it does

need more characters lol

-- a list which will store the number of tools each player has
local numberOfTools = {}

-- add the player into the list when they join
game.Players.PlayerAdded:Connect(function(player)
	numberOfTools[player] = 0
end

-- remove the player from the list when they leave
game.Players.PlayerRemoving:Connect(function(player)
	numberOfTools[player] = nil
end

local function toolUpdate(updatedTable)
	local MyTable = tools:GetTable(defaultTools)
	
	-- initial tool giver
	if numberOfTools[player] == 0 then -- you're going to have to define the player btw
		for _, v in pairs(MyTable) do
			local thing = Instance.new("StringValue")
			thing.Name = v
			thing.Parent = player.Tools
			numberOfTools[player] = numberOfTools[player] + 1
		end

		return
	end

	-- run only if one tool was added
	if #MyTable = numberOfTools[player]+1 then
		-- #MyTable returns number of values in the array
		-- The tool will be inserted at the end of the table with the index #MyTable
		local thing = Instance.new("StringValue")
		thing.Name = MyTable[#MyTable]
		thing.Parent = player.Tools
	end
end

toolUpdate(tools:Get(defaultTools))

tools:OnUpdate(toolUpdate)

I haven’t tested the code but I’m pretty sure this should work. Let me know what happens.

I did it!

local function toolUpdate(updatedTable)
	local addedTools = updatedTable
	local removedTools = lastTools
			
	local function find(obj, tabl)
		for i,v in pairs(tabl) do
			if v == obj then
				return true
			end
		end
		return false
	end
	
	if #updatedTable > #lastTools then -- tool added
		--print("tool added")
		for i,v in pairs(lastTools) do
			if find(v, updatedTable) then
				--print("removed")
				addedTools[i] = nil
			end
		end		
						
		for key, value in pairs(addedTools) do
			local thing = Instance.new("StringValue")
			thing.Name = value
			thing.Parent = player.Tools
		end
		
		lastTools = tools:GetTable(defaultTools)
		
	elseif #updatedTable < #lastTools then -- tool removed
		--print("tool removed")
		for i,v in pairs(lastTools) do
			if find(v, updatedTable) then
				--print("removed")
				removedTools[i] = nil
			end
		end	
					
		for i,v in pairs(removedTools) do
			if player.Tools:FindFirstChild(v) then
				local tool = player.Tools:FindFirstChild(v)
				tool:Destroy()
			end
		end
					
		lastTools = tools:GetTable(defaultTools)
	end
end

I dont know if the waits are the best idea, since tools COULD possibly get overridden, but it completly breaks without the waits anyway

EDIT: Fixed some of the code and got rid of the waits()!!

1 Like

Here I am, 3 months later…

Turns out the code doesnt work properly when removing a tool, so I just manually delete the stringValue from the Tool folder. This should work fine, I dont feel like setting my brain on fire again to make this work.