Custom changed event in OOP being connected and fired multiple times

For some reasons the function that im connecting the changed event to is being fired multiple times. The issues seem to occur whenever I equip and unequip my tool, it will keep on adding and adding. You can have a look at the code here:
Local script placed in tool:

local tool = script.Parent
local RepStorage = game:GetService("ReplicatedStorage")
local combatModules = RepStorage.Modules:WaitForChild("Combat")

local toolClass = require(combatModules:WaitForChild("toolClass")).init(weaponStats["Class"])

tool.Equipped:Connect(function()
	toolClass:OnEquip()
    print("Equipped")
end)

tool.Unequipped:Connect(function()
	toolClass:OnUnequip()		
end)

Toolclass script:

local toolClass = {}
toolClass.__index = toolClass

local FSM = require(script.Parent.Parent.FSM).Init()

function toolClass.init(weaponType)
	self.db = false
	self.isEquipped = false

	return self
end

function toolClass:OnEquip()
	self.isEquipped = true	
	
	FSM.onStateChanged:Connect(function(oldState, newState, endState)
		if endState == "IdleAnim" and self.isEquipped and not self.IdleAnim.IsPlaying then
			-- play anim
		end
	end)
end)

function toolClass:OnUnequip()
	self.isEquipped = false
end

FSM:

local FSM = {}

FSM.__index = FSM

function FSM.Init()
	local self = setmetatable(config, FSM)
	
	self.currState = self.init
	
	local mt = setmetatable(FSM, {
		__index = function(tbl, key)
			return self[key]
		end,
		__newindex = function(tbl, key, val)
			changedEvent:Fire("onStateChanged", self.currState, val)
			print("Fired")
			self[key] = val
			return self[key]
		end,
	})
	
	self.onStateChanged = {}
	
	function self.onStateChanged:Connect(callback)
		changedEvent.Event:Connect(function(eventName, oldState, newState)
			if eventName == "onStateChanged" then
				for i, v in pairs(changedTable.states) do
					if table.find(v.from, newState) then
						print("Is stacking")
						return callback(oldState, newState, v.to)
					end
				end
			end
		end)
	end

	return mt
end

function FSM:is(state)
	return self.currState == state
end

return FSM

I have tried connecting and disconnecting the onStateChanged in the FSM but that would just break my script.
Here’s a video of the output: https://gyazo.com/453c8056ad74c135bea2373fc22a6779
As you can see, the event only fired once, but for some reason the onStateChanged event stacked, and it accumulates based on the how many times I have equipped my tools. Thus, I tried connecting and disconnecting

    local e 
    e = FSM.onStateChanged:Connect(function(oldState, newState, endState)
		if endState == "IdleAnim" and self.isEquipped and not self.IdleAnim.IsPlaying then
			-- play anim
            e:Disconnect()
		end
	end)

But it doesn’t seem to work.
Any help is appreciated!

Can someone please help me, I have absolutely zero idea on how to debug this one

Place the onStateChanged connection outside the toolClass:OnEquip() function(currently you’re creating a new connection every time the tool is equipped), and use self.isEquipped as a debounce to restrict the event from running if the tool isn’t equipped:

--only using this to set the equipped state
function toolClass:OnEquip()
	self.isEquipped = true	
end)

--inside the toolClass module, outside of the functions
FSM.onStateChanged:Connect(function(oldState, newState, endState)
	if endState == "IdleAnim" and self.isEquipped and not self.IdleAnim.IsPlaying then
		-- play anim
	end
end)
1 Like

Hi, thanks for your reply, it worked as intended. I felt so embarrassing that I hadn’t tried this. But whenever I put the connection outside the toolClass:OnEquip() function it doesn’t pick up the self, because, self explanatory. I tried setting up a connection in the on equip function and disconnect it whenever the player unequips it, but it doesn’t work.

local e 

function toolClass:OnEquip()
	self.isEquipped = true	

	e = FSM.onStateChanged:Connect(function(oldState, newState, endState)
		if endState == "IdleAnim" and self.isEquipped and not self.IdleAnim.IsPlaying then
			self.IdleAnim:Play()	
		end
	end)	
end

function toolClass:OnUnequip()
	self.isEquipped = false
	
	e:Disconnect()
end

The output says attempt to index nil with Disconnect, whenever I print out e it says nil. Does anyone know how to resolve this ?