Stop sharing variables whit modules

I got an events framework module, recently its bugging a lot on the PlayerGui scripts, making that when the players dies, it has the functions that were connected before the player died when the garbage collector should remove them and the table where i store them is a local variable on the module and not a global table like _G.
I just found out that it’s bc module scripts share variables whit all scripts or the same type.
The problem right now is that I don’t know how to fix this.

script:


local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local HttpService = game:GetService("HttpService")

--// OTHER \\--

local RemoteEvent = script:WaitForChild("RemoteEvent", math.huge)
local RemoteFunction = script:WaitForChild("RemoteFunction", math.huge)
local BindableEvent = script:WaitForChild("Event", math.huge)
local BindableFunction = script:WaitForChild("Function", math.huge)

local scriptIndicator = "[UTILS][EventsFramework] : %s"

local Listners = {
	RemoteEvent = {},
	RemoteFunction = {},
	BindableEvent = {},
	BindableFunction = {},
}

--// HELPER FUNCTIONS  \\--

local newThread = function(callBack: () -> any?) return coroutine.wrap(callBack)() end
local cancelThread = function(thread: thread) return coroutine.close(thread) end

local function output(func: (string) -> any?, msg: string)
	func(string.format(scriptIndicator, msg.."\n traceback: "..debug.traceback()))
end

local function checkIfCallerIsSafe()
	pcall(function() if game.HttpGet then Players.LocalPlayer:Kick("Tryed to accses to a privileged ModuleScript.") end end)
	
	return getfenv(3).script and getfenv(3).script.Parent
end

local function reciveClient(Key: string, ...)
	for i, Listner in next, Listners.RemoteEvent do 
		if Listner._key == Key then 
			return Listner._callBack(...)
		end
	end
	
	output(warn, "No listners found on client RemoteEvent function.")
end

local function reciveServer(Player: Player, Key: string, ...)
	for i, Listner in next, Listners.RemoteEvent do 
		if Listner._key == Key then 
			return Listner._callBack(Player, ...)
		end
	end
	
	output(warn, "No listners found on server RemoteEvent function.")
end

local function reciveServerFunction(Player: Player, Key: string, ...)
	for i, Listner in next, Listners.RemoteFunction do 
		if Listner._key == Key then 
			return Listner._callBack(Player, ...)
		end
	end

	output(warn, "No listners found on client RemoteFunction function.")
end

local function reciveClientFunction(Player: Player, Key: string, ...)
	for i, Listner in next, Listners.RemoteFunction do 
		if Listner._key == Key then 
			return Listner._callBack(Player, ...)
		end
	end

	output(warn, "No listners found on client RemoteFunction function.")
end

local function reciveBindableEvent(Key: string, ...)
	for i, Listner in next, Listners.BindableEvent do 
		if Listner._key == Key then 
			return Listner._callBack(...)
		end
	end

	output(warn, "No listners found on BindableEvent function.")
end

local function reciveBindableFunction(Key: string, ...)
	for i, Listner in next, Listners.BindableFunction do 
		if Listner._key == Key then 
			return Listner._callBack(...)
		end
	end

	output(warn, "No listners found on BindableFunction function.")
end



--// MAIN MODULE \\--

local Framework = {
	Enums = {
	["RemoteEvent"] =       "RemoteEvent",
	["RemoteFunction"] =    "RemoteFunction",
	["BindableEvent"] =     "BindableEvent",
	["BindableFunction"] =  "BindableFunction",
}}

--// FUNCTIONS

function Framework:AddListner(Key: string, Event: string, Callback: (any?) -> any?)
	if not checkIfCallerIsSafe() then Players.LocalPlayer:Kick("Tryed to accses to a privileged ModuleScript.") return end
	if not Listners[Event] then
		output(warn, "Invalid event name.")
		return 
	end
	if Listners[Event][Key] then
		output(warn, "Key already exists on "..Event..".")
		return 
	end
	
	local newListner = {
		_key = Key,
		_callBack = Callback,
	}
	
	Listners[Event][Key] = newListner
	
	return newListner
end

function Framework:RemoveListner(Key: string, Event: string)
	if not checkIfCallerIsSafe() then Players.LocalPlayer:Kick("Tryed to accses to a privileged ModuleScript.") return end
	if not Listners[Event] then
		output(warn, "Invalid event name.")
		return 
	end
	
	if Listners[Event][Key] then
		Listners[Event][Key] = nil
		return
	end
	
	output(warn, "No listner found to remove whit the key '"..Key.."'.")
end

function Framework:FireServer(Key: string, ...)
	if RunService:IsServer() then
		output(warn, "Can not send to the server while the caller is the server.")
		return
	end
	
	if not checkIfCallerIsSafe() then
		Players.LocalPlayer:Kick("Tryed to accses to a privileged ModuleScript.") 
		return
	end
	
	RemoteEvent.FireServer(RemoteEvent, Key, ...)
end

function Framework:FireClient(Player: Player, Key: string, ...)
	if RunService:IsClient() then
		output(warn, "Can not send to the client while the caller is a client.")
		return
	end
	
	if not checkIfCallerIsSafe() then
		Players.LocalPlayer:Kick("Tryed to accses to a privileged ModuleScript.") 
		return
	end

	RemoteEvent.FireClient(RemoteEvent, Player, Key, ...)
end

function Framework:FireAllClients(Key: string, ...)
	if RunService:IsClient() then
		output(warn, "Can not send to the clients while the caller is a client.")
		return
	end
	
	if not checkIfCallerIsSafe() then
		Players.LocalPlayer:Kick("Tryed to accses to a privileged ModuleScript.") 
		return
	end

	RemoteEvent.FireAllClients(RemoteEvent, Key, ...)
end

function Framework:InvokeServer(Key: string, ...)
	if RunService:IsServer() then
		output(warn, "Can not invoke to the server while the caller is the server.")
		return
	end

	if not checkIfCallerIsSafe() then
		Players.LocalPlayer:Kick("Tryed to accses to a privileged ModuleScript.") 
		return
	end

	RemoteFunction.InvokeServer(RemoteFunction, Key, ...)
end

function Framework:InvokeClient(Player: Player, Key, ...)
	if RunService:IsClient() then
		output(warn, "Can not invoke to a client while the caller is a client.")
		return
	end

	if not checkIfCallerIsSafe() then
		Players.LocalPlayer:Kick("Tryed to accses to a privileged ModuleScript.") 
		return
	end

	RemoteFunction.InvokeClient(RemoteFunction, Player,  Key, ...)
end

function Framework:InvokeAllClients(Key: string, ...)
	if RunService:IsClient() then
		output(warn, "Can not invoke to all clients while the caller is a client.")
		return
	end

	if not checkIfCallerIsSafe() then
		Players.LocalPlayer:Kick("Tryed to accses to a privileged ModuleScript.") 
		return
	end

	RemoteFunction.InvokeServer(RemoteFunction, Key, ...)
end

function Framework:Invoke(...)
	if not checkIfCallerIsSafe() then
		Players.LocalPlayer:Kick("Tryed to accses to a privileged ModuleScript.") 
		return
	end
	
	BindableFunction.Invoke(BindableFunction, ...)
end

function Framework:Fire(...)
	if not checkIfCallerIsSafe() then
		Players.LocalPlayer:Kick("Tryed to accses to a privileged ModuleScript.") 
		return
	end

	BindableEvent.Fire(BindableEvent, ...)
end


--// ON RECEIVED

if RunService:IsServer() then
	RemoteEvent.OnServerEvent:Connect(reciveServer)
	RemoteFunction.OnServerInvoke = reciveServerFunction
else
	RemoteEvent.OnClientEvent:Connect(reciveClient)
	RemoteFunction.OnClientInvoke = reciveClient
end

BindableEvent.Event:Connect(reciveBindableEvent)
BindableFunction.OnInvoke = reciveBindableFunction



return Framework```
1 Like

When removing event listeners it is safer to manually disconnect them, as the garbage collector can only clear up stuff without any references, leaving the connection (even if the table referencing the remote/bindable event is cleared) will probably mean it passes it over.
Try this, see if it helps:

--In function Remove:Listener()
      --code before
      if Listners[Event][Key] then
        Listners[Event][Key]:Disconnect()
		Listners[Event][Key] = nil
		return
	  end
      --code after

You can’t call “Disconnect” on a table becasue tables doesn’t have a function called “Disconnect”. And also, the problem I’m talking about is that the table is shared whit all local scripts. I think I can use OOP but I don’t know how to implement that on the recive functions.