I removed all keys on a table via Goals[k] = nil, previous object data still exists in table after new entry?

In my game, I have to clear tasks after leaving a level. All works fine when playing one level: “keys” or blocks can be placed inside glowy things and the level’s complete. BUT, the next time I play another level, my script does not detect the new keys, and instead gets the last position values of the previous blocks.

Correct (The position of the block was tracked correctly, showing all the positions tracked each second):

Wrong (The last position stated on the output is different from the current position of the block after the level was restarted. This triggered unwanted completion of the level):

Code:

local Goals = {} -- Requires constant checks

local CurrentChapter
local CurrentLevel

local Checking = false

local ConcatDict = function(dict)
	local str = ""
	
	for k, v in pairs(dict) do
		str = str .. k .. " = " .. tostring(v) .. "\n"
	end
	
	return str
end

local Grant = function()
	
end

local AutomatedCheck = function()
	print("TASKBOARD: Ready to serve a player and a map!")
	local a = Instance.new("Part", workspace)
	local b = Instance.new("Part", workspace)
	
	local Count = 0
	
	for _, _ in pairs(Goals) do
		Count += 1
	end

	a.Color = Color3.new(1, 0, 0)
	b.Color = Color3.new(0, 1, 0)

	a.Anchored = true
	b.Anchored = true

	a.CanCollide = false
	b.CanCollide = false
	
	a.Size = Vector3.new(0.5,0.5,0.5)
	b.Size = Vector3.new(0.5,0.5,0.5)
	while Checking == true do
		wait(1)
		local Completes = 0
		for k, v in pairs(Goals) do
			local Live = workspace.World.Anchor.Position
			local TopLeft = v.TL + Vector2.new(Live.X, Live.Y)
			local BottomRight = v.BR + Vector2.new(Live.X, Live.Y)

			local Key = v.KY
			
			print(Key.Position)

			a.Position = Vector3.new(TopLeft.X, TopLeft.Y, 0)
			b.Position = Vector3.new(BottomRight.X, BottomRight.Y, 0)
			--print(TopLeft, BottomRight)
			
			
			if Key ~= nil then
				local KeyPos2D = Vector2.new(Key.Position.X, Key.Position.Y)

				if KeyPos2D.X > TopLeft.X and KeyPos2D.Y < TopLeft.Y then
					--print("TASKBOARD DEBUG:", k, "is under TopLeft corner.")
					if  (KeyPos2D.X < BottomRight.X and KeyPos2D.Y > BottomRight.Y) then
						--print("TASKBOARD DEBUG:", k, "is not above BottomRight corner.")
						Completes += 1
						--print("TASKBOARD DEBUG:", k, "is  above BottomRight corner.")
					end
				else
					--print("TASKBOARD DEBUG:", k, "is not under TopLeft corner.")
				end
				if Completes == Count then
					Checking = false
					Grant()
					print("TASKBOARD: Completed all tasks! Granting...")
				end
			else
				Goals[k] = nil
				warn("TASKBOARD: For some reason a goal got modified. Removing goal...")
			end
			--print(tostring(Completes), "/", Count)
		end
	end
end

local module = {}

function module.PinGoal(TopLeft, BottomRight, Key, SpecialKey)
	local SK = SpecialKey or tostring(#Goals + 1)
	Goals[SK] = {
		TL = TopLeft,
		BR = BottomRight,
		KY = Key
	}
	print("TASKBOARD: Pinned a goal!")
	print(ConcatDict(Goals[SK]))
end

function module.UnpinGoal(SpecialKey)
	Goals[SpecialKey] = nil
	print("TASKBOARD: Unpinned a goal!")
end

function module.UnpinAll() -- I guess the problematic function.
	for k, _ in pairs(Goals) do -- Problematic (unreferencing)?
		Goals[k].TL = nil
		Goals[k].BR = nil
		Goals[k].KY = nil
		Goals[k] = nil
	end
	
	Goals = {} -- Also tried to renew the table, same results occured.
	print("TASKBOARD: Unpinned all goals!")
	print(ConcatDict(Goals))
end

function module.StartChecks()
	if not Checking then
		Checking = true
		coroutine.resume(coroutine.create(AutomatedCheck))
	else
		print("TASKBOARD: Taskboard is already running!")
	end
	print(ConcatDict(Goals))
end

function module.StopChecks()
	Checking = false
	module.UnpinAll() -- I tried to clear the Goal table again, same thing happened.
	print("TASKBOARD: Aww... Time to rest I guess!")
end

return module

This is bugging me already, I think it is not being garbage collected properly? Is there a way to correctly clear my table Goals?

Thanks in advance!

It’s 2 AM here when I posted this. I won’t be able to read your replies until around 12 PM (PHT, UTC +8).

Further details:

Edit 09/24/2020 @ 10:07 AM UTC +8 :
This video probably shows it better than I do. The highlighted parts show that they’re part of the Goals table. Non-highlighted parts are supposed to be in the said table.

What environment is this code running on? Client or server? Who resets the blocks, who runs the code?

The code is ran from the server. The player would request the server to clear the map and the server is in charge of clearing it.

I’m not sure if extra bit of info helps but the game is singleplayer.

It seems like I forgot to (nullify?) variables in a table, from a different ModuleScript. After adding a for loop to set variables to nil it finally got the previous parts GC’d. Now I can continue working in peace.

Apologies, I did not see my mistake quick enough.