Do modules keep running after death?

I have a LocalScript inside my Gui, like so

local HUD = script.Parent

-- Using this module as an example
local LevelMenu = HUD:WaitForChild('LevelMenu')
local LevelMenuControl = require(LevelMenu.LevelMenuControl)

Now this module is this

local LevelMenuControl = {}
print(1)
local ReplicatedStorage = game:GetService('ReplicatedStorage')

local Remotes = ReplicatedStorage:WaitForChild('Remotes')
local Events = Remotes:WaitForChild('Events')
local GetData = Events:WaitForChild('GetData')

local Frame = script.Parent

local Bar = Frame:WaitForChild('Bar')
local Exp = Frame:WaitForChild('Exp')
local Level = Frame:WaitForChild('Level')

local WhiteExp = Bar:WaitForChild('WhiteExp')

GetData.OnClientEvent:Connect(function(data)
	local ExpNeeded = data.Level * 50
	Level.Text = data.Level
	Exp.Text = data.Exp .. ' / ' .. ExpNeeded
	WhiteExp.Text = Exp.Text
	if Bar then
		Bar:TweenSize(UDim2.new(data.Exp / ExpNeeded, 0, 1, 0), 'Out', 'Linear', 0.5, true) -- ERROR HERE
	end
end)

GetData:FireServer()

return LevelMenuControl

and heres my output when I die
[1]
[13:04:11.216 - Can only tween objects in the workspace]
[13:04:11.216 - Script ‘Players.NinjoOnline.PlayerGui.HUD.LevelMenu.LevelMenuControl’, Line 25]
[1]
[13:04:11.316 - Can only tween objects in the workspace]
[13:04:11.317 - Script ‘Players.NinjoOnline.PlayerGui.HUD.LevelMenu.LevelMenuControl’, Line 25]

So my question is, once I die, does the old module keep running? I have ResetOnSpawn set to true (I need the UI elements to be reset when you die)

Thing is, if Bar exists, then I tween it, so not sure how I can get this error as it has to exist first before it can tween

Yes, they do. Literally spent forever trying to figure out some bugs to find out that this is what was happening. Basically you just gotta manually disconnect all events and break all loops when the player dies to stop the module and it should go to the garbage collector.

3 Likes

How do I do that then???

My attempt

local UpdateData

UpdateData = function(data)
	local ExpNeeded = data.Level * 50
	Level.Text = data.Level
	Exp.Text = data.Exp .. ' / ' .. ExpNeeded
	WhiteExp.Text = Exp.Text
	if Bar then
		Bar:TweenSize(UDim2.new(data.Exp / ExpNeeded, 0, 1, 0), 'Out', 'Linear', 0.5, true)
	end
	UpdateData:Disconnect()
end

GetData:FireServer()

GetData.OnClientEvent:Connect(UpdateData)

So it would look something like this.

local Alive = true;
local Connections = {};


--Loop example
while Condition do
if not Alive then break; end
	--Other loop stuff
end

--Anonymous  Connection Example
table.insert(Connections,Game.Workspace.Changed:Connect(function(Property)
	--DoStuffHere
end));


--Alternative Connection Example
local WorkspaceConnection = Game.Workspace.Changed:Connect(function(Property)
	--DoStuffHere
end)

table.insert(Connections, WorkspaceConnection);

--Breaking it all
Player.CharacterAdded:Connect(function()
	for _,v in ipairs(Connections) do
		v:Disconnect();
	end
	Alive = false;
end)

So I gotta do that in all my scripts?

Just the module ones, normal scripts stop when destroyed.

Also for your attempt here’s how’d you change that, although its not particularly useful as it would only execute once and then never update again.

local Connection;

UpdateData = function(data)
	local ExpNeeded = data.Level * 50
	Level.Text = data.Level
	Exp.Text = data.Exp .. ' / ' .. ExpNeeded
	WhiteExp.Text = Exp.Text
	if Bar then
		Bar:TweenSize(UDim2.new(data.Exp / ExpNeeded, 0, 1, 0), 'Out', 'Linear', 0.5, true)
	end
	Connection:Disconnect()
end

GetData:FireServer()

Connection = GetData.OnClientEvent:Connect(UpdateData)

Just to add onto this reply, you can just disconnect it whenever the script’s parent becomes nil:

local function UpdateData(data)
	local ExpNeeded = data.Level * 50
	Level.Text = data.Level
	Exp.Text = data.Exp .. ' / ' .. ExpNeeded
	WhiteExp.Text = Exp.Text
	if Bar then
		Bar:TweenSize(UDim2.new(data.Exp / ExpNeeded, 0, 1, 0), 'Out', 'Linear', 0.5, true)
	end
end

GetData:FireServer()

local Connection = GetData.OnClientEvent:Connect(UpdateData)

local ParConnection; ParConnection = script:GetPropertyChangedSignal('Parent'):Connect(function()
	if script.Parent == nil then
		Connection:Disconnect()
		ParConnection:Disconnect()
	end
end)

return LevelMenuControl

You can also directly transfer the event and function through the module and make the script connect it, and you won’t have to worry about this happening, in theory:

LevelMenuControl.Connections = {}

local function UpdateData(data) ... end

GetData:FireServer()

LevelMenuControl.Connections[GetData.OnClientEvent] = UpdateData

return LevelMenuControl
local LevelMenuControl = require(LevelMenu.LevelMenuControl)

-- load the rest of your modules

for _,module in ipairs{LevelMenuControl, --[[rest of your modules]]} do
	for event, func in pairs(module.Connections) do
		event:Connect(func)
	end
end
1 Like

Modules do keep running after death. The problem is that your ModuleScript is referencing an old copy of the Gui. If you have the Gui set to ResetOnRespawn, it will get removed when Player.Character changes. The Gui then gets detached from the DataModel and you can’t tween it anymore.

This issue can be fixed through any combination of the methods above or ensuring that your Gui only uses recent copies of a Gui. For example, instead of upvalues for the Gui, move them into the function connected to the remote.

2 Likes