Structural mistake which is causing stacking of events

I was structuring my game’s client code using one LocalScript in the StarterGui and many ModuleScripts as descendants of it which are then required every run.

The structure of my code:
image

The problem is that every respawn the events were not disconnecting but were stacking up instead. When I moved the ModuleScripts to the ReplicatedStorage what happened was that when I respawned I have got a lot of problems as I had called the Gui objects from the ModuleScripts so it was always addressing the first set of Gui before the respawn.

What is the easiest way to solve this issue? as I had already progressed so much in the game that when I realized this issue it became rather complicated to fix. I am using the StarterGui for more things which are not related to the UI only.

An example of a module which will stack:

local module = {}

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()

mouse.Button1Down:Connect(function()
    print("Hello")
end)

return module

(I have about 19 ModuleScripts descendants of the LocalScript)

2 Likes

This is something I ran into when setting up a modular system for my client framework. My current solution is to send all Connections and Bindings to a single module inside of it’s own ScreenGui. The ScreenGui has ResetOnSpawn disabled. The module inside of the ScreenGui has a function to accept new connections and bindings, adding them to a table, and a function to disconnect all connections and bindings in that table.

When the player spawns, first the function that disconnects everything is run. Then, all new connections/bindings are added into the table for next time.

This was an extremely frustrating thing to work with and I dearly hope there is a better way to handle this.

4 Likes

Personally, I avoid putting anything in StarterGui whatsoever, except while I’m working on designing GUIs.

StarterPlayerScripts is a better option if you want scripts to only run once. So you have a few options here.

First, I would say, don’t be afraid to use multiple scripts, especially if you’re making a full-on game rather than a package. I have a folder in ReplicatedStorage called ClientEndpoints which contains events for scripts to communicate with each other. Placing BindableEvents (which you should prefer over BindableFunctions) in a static container like ReplicatedStorage can make the code less coupled and framework-dependent.

But more to your issue is that you need events to disconnect when the player dies. If you are using scripts that need to clean up things like event connections or instances, then StarterGui is the wrong place for these scripts. Instead of relying on StarterGui’s behavior copying scripts over every time a player respawns, you should put these scripts in StarterPlayerScripts, and use Player.CharacterAdded and Humanoid.Died to connect and disconnect events.

I would create a helper table, or maybe even a simple “Maid” class where you can collect connections, instances, etc. that need to be removed at a later time.

In the case of the Maid class I linked, you simply need to use Maid:GiveTask(someEvent:Connect(someFunction)). You should call Maid:DoCleaning() both when the character is added, and when the character dies.

edit: Whoops, I forgot to include the “FastSpawn” code in the Maid gist. Refresh the page.

4 Likes

Thanks this worked easily!

Thanks for your answer but it sounds a bit complicated for me at my stage right now. I appreciate it and thank you just the same!