OnClientEvent Connections are overwriting each other

Hello, I have a ModuleScript for my game which stores the replication events for clients, and makes connections to them… Which functioned tragically after I learned that moving my code like this made the connections overwrite each other even though they didn’t before.

Here is the core components of my module without the bloat:


local ReplicationRemotes = game:GetService("ReplicatedStorage"):WaitForChild("Events"):WaitForChild("Replication")


local inverseLookup : {RemoteEvent} = {}

for _, remote in pairs(ReplicationRemotes:GetChildren()) do

	inverseLookup[remote.Name:lower()] = remote
end



local ClientReplication = {}



function ClientReplication.Connect(eventName : string, callback : () -> ()) : RBXScriptConnection

	local EventName = eventName:lower()


	return inverseLookup[EventName].OnClientEvent:Connect(callback)
end



return ClientReplication

As you can see the code is very bare-bones and should be exactly logically similar to making the connections in each script. But why is it not functioning that way? I really need an explanation, I’ve been searching for one everywhere but I haven’t seen a single mention of OnClientEvent getting overridden in the DevForum

Every time you call Connect, it makes a new connection, which can overwrite previous ones. This causes the event to stop working right.

That is not the expected behavior of Connect. I was doing the same exact thing before I made the module, making a single new connection to the same event’s OnClientEvent for each LocalScript. It is not the normal behavior to have them overwrite each other, each call should connect a NEW event handler to the same Event, as it says in the Documentation: Remote events and callbacks | Server → Client - Roblox Documentation

If what you are saying is true, in what cases does it overwrite, and in what cases does it not?

I recently found out about this but it’s called Connection Stacking i believe, I did not know it existed until someone else pointed it out a couple of days ago. It overwrites any previous connection and causes it to break. for an example of seeing this I assume you can make a lava part and connect multiple things to it and see how it works… I don’t know make a TakeDamage, WalkSpeed, and JumpPower for the lavaPart and see.

Does this align for what you are experiencing?

1 Like

This is a great idea, and it is probably exactly what is happening to me. Although I don’t know why it’s a problem, as when I make connections using this module, I only do it once at the bottom of the scripts (no connection nesting at all)

It did function perfectly when I manually made the connections in each script:
ReplicatedStorage.Events.ReplicationRemotes.Stats:Connect(func)

should be perfectly similar to my modules function (but starts overwriting…):
ClientReplication.Connect("Stats", func)

Are you possibly calling the ClientReplication.Connect("Stats", callback) multiple times if so then you have your connection stacking issue. You can either save the connection to a variable or table then check if it exists and if it exists just override it with the new connection?

It is only called once per script (but yes, multiple scripts call the same function with “Stats” using a different callback for each script)

If i change the call to the function in all scripts with the first line (manual connection), it magically starts working again even though the calls are logically similar

Well there is your error! You have Connection Stacking multiple connections are tied to the “Stats” remote event / function, which is giving you the overwriting issue or just not working at all. May i ask why are you making multiple call backs for once remote event?

Multiple ScreenGui scripts need to update their state when the Stats get replicated. So each controller script listens to OnClientEvent to know when to update their state. This is standard, is it not?

Why does it work if I make the connections manually? Im doing the same thing there, so why is there no issue?

I honestly have no clue why it works manually and not automatically. But I believe the standarad would be storing all the replicated Stats Data into a module then referencing that module.

local PlayerStats = {}


function PlayerStats.SetStat(statName: string, value)
 -- However you decide to change stat value.
end

function PlayerStats.GetStat(statName: String)
 return -- your referenece to stat
end

return PlayerStats 

This might be what you are looking for. I suggest moving it to a module script that acts as a PlayerStatsManager. you could also use GetPropertyChangedSignal if its an IntValue or whatever and listen to when the property Value is changed?

That won’t help me, sadly. I would still need a way to inform the client that their data is updated, since the module on the Server would be different than the module on the Client.

I’m gonna make the connections manually (the Connection stack is well-defined in that case) until someone can pinpoint why using the module instead causes weird errors

1 Like

What do you mean by overwriting? Because I just tried your code on a baseplate and it work fine for me.

Wait could you try inserting the connection into a different table?

local ReplicationRemotes = game:GetService("ReplicatedStorage"):WaitForChild("Events"):WaitForChild("Replication")


local inverseLookup : {RemoteEvent} = {}

for _, remote in pairs(ReplicationRemotes:GetChildren()) do

	inverseLookup[remote.Name:lower()] = remote
end



local ClientReplication = {}
local eventConnections = {}


function ClientReplication.Connect(eventName: string, callback: () -> ()) : RBXScriptConnection
    local EventName = eventName:lower()

    -- If this event has no connection Stats? create a new one
    if not eventConnections[EventName] then
        eventConnections[EventName] = {}
    end

    local connection = inverseLookup[EventName].OnClientEvent:Connect(callback)
    table.insert(eventConnections[EventName], connection)

    return connection
end

return ClientReplication

Fingers crossed. If not maybe we can try to return the existing connection?

Are you calling the function multiple times with the same eventName?

Yep, I tried everything, including 2 connections on the same remote in the same script / in 2 script, as well as 2 remotes event with 4 local script that call a Module.Connect function for both event and it work fine.

That was also a great idea, but sadly the result is the same. For the other guy, I have about 4 local scripts which all call

ClientReplication.Connect("Stats", uniqueCallbackFunc)

once at the bottom of each script

It causes only 1 of them to work.

I know it’s an overwrite issue because If I disable the script that it works in, another one starts to work

I don’t know what’s wrong with your place, but here’s mine:
RemotePlace.rbxl (49.3 KB)

This game is showing clear favoritism

1 Like

What exactly is your callback? Is your callback the whole Stats? or is your callback different for each script.

P.S now that we know its favoritism could you try and implement your callsback into @Crygen54 's place?

The callback is a different local function for each script. Right now, they literally only change the color of the UI, thats it

I would do that, but his callbacks are identical to mine, they just print instead

I CAN LITERALLY PUT MY SCRIPTS IN HIS GAME AND THEY WORK

Im just gonna make the connections manually, this is too much for me (favoritism confirmed)

this is unbelievably infuriating. Seriously?? Why can I just put everything in his game, delete the non-existent references, and then it works???