[HARD] UI destroy system help

Hi devs,
I am currently creating a game where there are characters who destroy the map, and there are a certain number of parts that can be destroyed. What i want is for the ui bar to fill up when a player destroys something, and to fill up only when all things are destroyed. For some reason, it fills up early, when there are still a few things left to destroy. Other than that it works fine. I want to say that my script organisation skills are quite bad so prepare yourselves :joy: I’m using ui gradient and altering its offset property to achieve this.
Heres my server script, it’s long and hard to understand, so any help is appreciated.

local mapFolder = game.Workspace.CurrentMap

local playerNum = 0

local maxHavoc = 2
local vulnerableNum = 3

local charEvent = game:GetService("ReplicatedStorage"):WaitForChild("CharChange")

local teams = {
	"Destroyer",
	"Destroyer"
}

local maxVulnerable

local parts = {}

local destroyedEvent = game.ServerStorage.DestroyedEvent
local wonEvent = game.ServerStorage.WonEvent

local highlight = game:GetService("ServerStorage").Highlight

local currentHavocNum = 2

local destroyedClientEvent = game.ReplicatedStorage.DestroyedEventClient

local function randomHighlight()
	if #parts > 1 then
		local ranNum = math.random(1, #parts)
		local ranPart = parts[ranNum]
	
	if ranPart and ranPart.Parent then
		
		local newHighlight = highlight:Clone()
		newHighlight.Parent = ranPart
	
		ranPart:SetAttribute("Vulnerable", true)
		table.remove(parts, ranNum)
	end
	
	
	elseif #parts == 1 then
		local ranPart = parts[1]
		
		local newHighlight = highlight:Clone()
		newHighlight.Parent = ranPart
		
		ranPart:SetAttribute("Vulnerable", true)
		table.remove(parts, 1)
	end
end

local function randomTeam(plr)
	local ranNum = math.random(1, #teams)
	local ranTeam = teams[ranNum]
		
	if playerNum == 2 then
		for i, v in game.Players:GetChildren() do
			if ranNum == 1 then
				v:WaitForChild("GameTeam").Value = "Destroyer"
			else
				v:WaitForChild("GameTeam").Value = "Protector"
			end
		end
	else
		if currentHavocNum == 0 and ranNum == 1 then
			randomTeam()
		else
			plr:WaitForChild("GameTeam").Value = ranTeam
		end
		
		if ranTeam == "Destroyer" then
			currentHavocNum -= 1
		end	
	end
end

destroyedEvent.Event:Connect(function(destroyedPart)
	
	destroyedPart:SetAttribute("Vulnerable", false)
		
	local highlight = destroyedPart:FindFirstChild("Highlight")
	
	if highlight then
		randomHighlight(parts)
		highlight:Destroy()
	else
		local index = table.find(parts, destroyedPart)
		
		if index then
			table.remove(parts, index)
		end
	end

	destroyedClientEvent:FireAllClients(parts, false)

	
	if #parts == 0 then
		local vulnerableExists = false

		for _, v in mapFolder:GetDescendants() do
			if v:GetAttribute("Vulnerable") then
				vulnerableExists = true
				break
			end
		end

		if not vulnerableExists then
			wonEvent:Fire()
		end
	end
end)

mapFolder.ChildAdded:Connect(function(child)
	currentHavocNum = maxHavoc
	for i, plr in game.Players:GetChildren() do
		playerNum += 1
		randomTeam(plr)
	end

	
	for i, v in child:GetDescendants() do
		if v:GetAttribute("Vulnerable") then
			v:SetAttribute("Vulnerable", false)
			table.insert(parts, v)
		end
	end
	
	for i = 1, vulnerableNum do
		randomHighlight(parts)
	end
	
	
	destroyedClientEvent:FireAllClients(parts, true, vulnerableNum)
end)

mapFolder.ChildRemoved:Connect(function()
	for i, v in game.Players:GetChildren() do
		v.GameTeam.Value = "No Team"
	end
	for i, v in workspace.InGameChars.Other:GetChildren() do
		v:Destroy()
	end
end)

game.Players.PlayerAdded:Connect(function(plr)
	local val = Instance.new("StringValue")
	val.Name = "GameTeam"
	val.Parent = plr
	
	local protChar = Instance.new("StringValue")
	protChar.Name = "ProtectorCharacter"
	protChar.Parent = plr

	local destChar = Instance.new("StringValue")
	destChar.Name = "DestroyerCharacter"
	destChar.Parent = plr


	
	
	val.Changed:Connect(function()
		if val.Value == "Destroyer" or val.Value == "Protector" then
			local char = plr.Character
			char.Parent = game.Workspace.InGameChars:FindFirstChild(val.Value)
		end
	end)
end)

Ignore the majority of it, the most important part is parts where destroyedClientEvent is called, as thats the event that gets fired to the client.

Here’s my local script that receives this event.

local destroyedEvent = game.ReplicatedStorage.DestroyedEventClient

local maxVulnerable
local currentVulnerable

local frame = script.Parent

local roundHandler = game.ReplicatedStorage.RoundHandler

destroyedEvent.OnClientEvent:Connect(function(partsTable, isMaxVulnerable, vulnerableNum)
	if isMaxVulnerable == true then
		maxVulnerable = #partsTable + vulnerableNum
		frame.UIGradient.Offset = Vector2.new(0, 0)
		frame.TextLabel.UIGradient.Offset = Vector2.new(0, 0)
	else
		currentVulnerable = #partsTable
		
		local offset = (currentVulnerable / maxVulnerable)
		
		frame.UIGradient.Offset = Vector2.new(1 - offset, 0)
		frame.TextLabel.UIGradient.Offset = Vector2.new(1 - offset, 0)
		
	end
end)


roundHandler.OnClientEvent:Connect(function(timeLeft, status, roundTime)
	if status == "Game" then
		frame.Parent.Visible = true
	else
		frame.Parent.Visible = false
	end
end)

much shorter and more managable, i hope.

This is a very hard issue to fix, because my code probably is not easy at all to read.
Thanks in advance!!

anybody know whats wrong?

I fixed it by in the server script i added a new table called leftover parts which i inserted the vulnerable parts in, then removed when they were destroeyd, so it always showed all the parts that could be destroyed, but weren’t. I then passed that as a third argument into the destroyedClientEvent, and used that instead of the first argument in the local script.