Unable to fully loop a table

I have a script for model placement and a function for marking parts where you can build.

...
reloadCityRanges = function(state)
	local playerParty
	for _, p in pairs(PARTIES) do
		if p.leader == LOCAL_PLAYER then
			playerParty = p
			break
		end
	end
	if playerParty then
		CITY_RANGES_SHOWN = state
		local partyCities = {}
		for _, s in pairs(STRUCTURES) do
			if s.party and s.party.id == playerParty.id and (s.structureType == "city" or s.info.structureType == "city") then
				table.insert(partyCities, s)
			end
		end
		
		local range_diameter = if state then GET_CITY_RADIUS_EVENT:InvokeServer() else 0
		local get_instancesInChunk = function(chunk, position)
			local parts = {}
			for _, i in pairs(chunk.instances) do
				if i and (i.Position - position).magnitude <= (range_diameter / 2) then
					table.insert(parts, i)
				end
			end
			for _, i in pairs(chunk.water) do
				if i and (i.Position - position).magnitude <= (range_diameter / 2) then
					table.insert(parts, i)
				end
			end
			return parts
		end
		
		local parts_update = {}
		for _, c in pairs(partyCities) do
			if c.model then
				for _, chunk in pairs(CHUNKS) do
					local instances = get_instancesInChunk(chunk, c.model:GetPivot().Position)
					for _, i in pairs(instances) do if not table.find(parts_update, i) then table.insert(parts_update, i) end end
				end
			end
		end
		
------ The problem is probably located in the next loop - not sure though
		for i = 1, #CITY_RANGE_PARTS do
			local part = CITY_RANGE_PARTS[i]; if not part then print("invalid part") continue end
			local found = false
			if #parts_update > 0 then
				for _, p in pairs(parts_update) do
					if part.part == p then
						found = true
						break
					end
				end
			end
			if not found then
				part.ignore_updates = true
				if part.part then
					part.part.Material = part.material
					part.part.Color = part.color
				end
				
				table.remove(CITY_RANGE_PARTS, i)
			end
		end
		for i = 1, #parts_update do
			local p_update = parts_update[i]; if not p_update then continue end
			local found = false
			for _, p in pairs(CITY_RANGE_PARTS) do
				if p.part == p_update then
					found = true
					break
				end
			end
			if not found then
				local orig_color = p_update.Color
				local orig_material = p_update.Material
				p_update.Color = Color3.new(1, 0.666667, 0)
				p_update.Material = Enum.Material.SmoothPlastic
				
				table.insert(CITY_RANGE_PARTS, {
					color = orig_color,
					material = orig_material,
					part = p_update
				})
			end
			if i / 100 == math.round(i / 100) then task.wait() end
		end
	end
end
...

The reloadCityRanges function should assure that the map parts that are generated get highlighted when you call it. It works just fine when you call it with ā€˜true’ to highlight the parts, but when you want to give them the original color and material, half of the parts stay the same. I also noticed that the CITY_RANGE_PARTS table length doesn’t correspond with the values you can actually get.

Example:

t = { {...} , {...} } -- table that has 2 values (length 2)
for i = 1, #t do -- #t is 2 here
    print(t[i]) -- prints {...} for 1st value, nil for 2nd value
end

Here is a video depicting the issue

Everything goes fine until I click the button to end building. Exactly half of the parts stay the same and the console prints out ā€˜invalid part’ for each of those. Probably a problem somewhere in my script, not sure where though.

I am looking forward to any responses and suggestions!

1 Like

It might be this line here. Here’s what that would cause.

local elements = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for i, v in pairs(elements) do
    print(v)
    table.remove(elements, i)
    -- this shifts the table. If we are on elements[i],
    -- the next loop is elements[i+1] which means
    -- we actually skip one because we just shifted the table down.
end

Output: 1 3 5 7 9

There are two solutions to this. One solution is to have an ā€œindices to deleteā€ table, so you delete all the entries after the loop finishes. (ETA this also involves iterating backwards) The more preferred method though is to iterate backwards so that the table shifting doesn’t mess you up.

local entries = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for i = #entries, 1, -1 do
    print(entries[i])
    table.remove(entries, i)
end

Output: 10 9 8 7 6 5 4 3 2 1

1 Like