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
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.
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
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?
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.