Event connections not disconnecting with db and connection management

my Gui spawn button erratically fires countless times the more i respawn, I have been fighting it for days trying to figure out a fix

I’ve looked on the forum for similar issues and even tried similar approaches to disconnecting events, I have written various different functions for event removals

The script works in 3 parts, Local > Module > Server

-- This is the localScript

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage") -- Constants....

if LocalPlayer.Character then
	spawnGui.Enabled = false
	print("I stopped the script")
	return
end

local spawnMenu = spawnModule.new(spawnGui)

spawnMenu:connectEvents()

updateHeader()

spawnMenu.openSpawnList.MouseButton1Click:Connect(function()
	spawnMenu:populateSpawns()
end)

spawnMenu.confirmSpawn.MouseButton1Click:Connect(function()
	spawnMenu:disconnectEvents()
	if spawnMenu.selectedSpawn ~= nil and spawnMenu.confirmDebounce == false then
		spawnMenu:disconnectEvents()
		spawnMenu:confirmSpawnSelection()
	else
		spawnMenu:disconnectEvents()
	end
end)

spawnMenu.runnerButton.MouseButton1Click:Connect(function()
	spawnMenu:selectRunners()
	updateHeader()
end)

spawnMenu.policeButton.MouseButton1Click:Connect(function()
	spawnMenu:selectPolice()
	updateHeader()
end)

-- This is the server code snippet

local function loadCharacter(player, location)
	if debounceTable[player] == true then
		return
	else
		local spawnPosition = workspace:FindFirstChild(tostring(player.Team).."Spawn"):FindFirstChild(location)
		debounceTable[player] = true

		player.CharacterAdded:Connect(function(character)
			print(debounceTable[player])
			initializeTags(player)
			giveEquippedWeapons(player)
			sendData(player)

			debounceTable[player] = false
		end)

		player:LoadCharacter()
		player.Character:MoveTo(spawnPosition.Position)
	end
end

spawnSelectionEvent.OnServerEvent:Connect(function(player, Instructions, Extras1, Extras2)
	if Instructions == "SelectTeam" then
		teamPlayer(player, Extras1)
	elseif Instructions == "Spawn" then
		task.wait(0.1)
		loadCharacter(player, Extras1, Extras2)
	elseif Instructions == "plrLoaded" then
		local loadCl = ReplicatedFirst:FindFirstChild("SpawnGui"):Clone()
		loadCl.Parent = player.PlayerGui
	end
end)

-- Module for the spawnGui

local SpawnMenu = {}

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService") --Various Constants....

function SpawnMenu.new(spawnGui)
	local self = setmetatable({}, SpawnMenu)

	self.spawnGui = spawnGui
	self.cameraBrick = nil
	self.selectedSpawn = nil
	self.confirmDebounce = false
	self.spawnMenuConnections = {}

	self.mainFrame = spawnGui:WaitForChild("mainFrame")
	self.playerCount = self.mainFrame:WaitForChild("Detail"):WaitForChild("TextLabel")
	self.openSpawnList = self.mainFrame:WaitForChild("spawnButton")

    --Rest of module init
      function SpawnMenu:confirmSpawnSelection() --Snippet responsible for spawning the player
	self:disconnectEvents()
	if self.selectedSpawn and not self.confirmDebounce then
		self.confirmDebounce = true  
		self:disconnectEvents()
		spawnSelectionEvent:FireServer("Spawn" , tostring(self.selectedSpawn), self.spawnGui)
		RunService:UnbindFromRenderStep("UpdateCamera")
		self.spawnGui.Enabled = false
		print(self.spawnMenuConnections)

		local Character = self:WaitForCharacterLoaded(LocalPlayer)
		if Character then
			Character:WaitForChild("Humanoid")
			if Character.Humanoid then
				workspace.CurrentCamera.CameraSubject = Character:FindFirstChild("Humanoid")
				workspace.CurrentCamera.CameraType = Enum.CameraType.Custom
				workspace.CurrentCamera.FieldOfView = 70
			end
		end
		self:disconnectEvents()
		self:destroy()
		spawn(function()
			wait(2)
			self.confirmDebounce = false
		end)
	else
		warn("Location not found")
	end
end

1 of many methods/functions for connection management


function SpawnMenu:connectEvents()
	self:disconnectEvents()

	table.insert(self.spawnMenuConnections, self.openSpawnList.MouseButton1Click:Connect(function()
		self:populateSpawns()
	end))

	table.insert(self.spawnMenuConnections, self.confirmSpawn.MouseButton1Click:Connect(function()
		self:confirmSpawnSelection()
	end))

	table.insert(self.spawnMenuConnections, self.runnerButton.MouseButton1Click:Connect(function()
		self:selectRunners()
	end))

	table.insert(self.spawnMenuConnections, self.policeButton.MouseButton1Click:Connect(function()
		self:selectPolice()
	end))	
end

function SpawnMenu:disconnectEvents()
	for _, connection in ipairs(self.spawnMenuConnections) do
		connection:Disconnect()
	end
	self.spawnMenuConnections = {}
end

function SpawnMenu:destroy()
	self:disconnectEvents()

	if self.selectedSpawn then
		self.selectedSpawn = nil
	end

	self:clearPorts()

	self.spawnGui.Enabled = true
	self.spawnSelectionFrame.Visible = false
	self.confirmSpawn.Visible = false

	workspace.CurrentCamera.CameraType = Enum.CameraType.Custom
	workspace.CurrentCamera.CameraSubject = LocalPlayer.Character

	if self.cameraBrick then
		self.cameraBrick:Destroy()
		self.cameraBrick = nil
	end
	
	self.spawnGui:Destroy()

	Lighting.Blur.Enabled = false
end

second method

function SpawnMenu:AddConnection(connection)
    for i = 1, #self.spawnMenuConnections do
        if self.spawnMenuConnections[i] == connection then
            return
        end
    end

    table.insert(self.spawnMenuConnections, connection)
end

function SpawnMenu:RemoveConnection(connection)
    for i = 1, #self.spawnMenuConnections do
        if self.spawnMenuConnections[i] == connection then
            self.spawnMenuConnections[i]:Disconnect()
            table.remove(self.spawnMenuConnections, i)
            return
        end
    end
end

function SpawnMenu:Disconnect()
    for i = 1, #self.spawnMenuConnections do
        self.spawnMenuConnections[i]:Disconnect()
    end
    self.spawnMenuConnections = {}
end

third connection management


function SpawnMenu:connectEvents()
    self:disconnectEvents()

    local function isDuplicate(connection)
        local name = connection.Name
        local count = 0

        for _, existingConnection in ipairs(self.spawnMenuConnections) do
            if existingConnection.Name == name then
                count = count + 1
                if count > 1 then
                    return true
                end
            end
        end

        return false
    end

    local function insertConnection(connection)
        if not isDuplicate(connection) then
            table.insert(self.spawnMenuConnections, connection)
        end
    end

    insertConnection(self.openSpawnList.MouseButton1Click:Connect(function()
        self:populateSpawns()
    end))

    insertConnection(self.confirmSpawn.MouseButton1Click:Connect(function()
        self:confirmSpawnSelection()
    end))

    insertConnection(self.runnerButton.MouseButton1Click:Connect(function()
        self:selectRunners()
    end))

    insertConnection(self.policeButton.MouseButton1Click:Connect(function()
        self:selectPolice()
    end))
end

please keep in mind, I have run the functions before, after and from the local script aswell yet the issue persists and before i get suggestions for just coding the gui in the localscript i’ve done that aswell before moving it to a module

i also tried the original method for disconnection

if ConnectionVar ~= nil and ConnectionVar.Connected or typeof(ConnectionVar) == "RBXScriptConnection" then
			ConnectionVar:Disconnect()
		end

it still didn’t work or in some cases causes the buttons to not run at times, for further context on how my system works, it first gives the player the gui when they load into the game, when they spawn it gets deleted by the server script, when they die and the character gets garbage collected they receive the script again

Have you tried setting the ScreenGUI’s ResetOnSpawn property to false, then disabling the script once it’s clicked?

resetonspawn is disabled, the script cleans up all connections then gets deleted when the player confirms to spawn

Instead of creating a table for the connections, you can use :Disconnect instead. Have you tried that method yet?

yes i did, its in the last bit of the post