Connection is Nil and won't disconnect

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!

I’m trying to disconnect a function as soon as a value reaches 0. The value counting down works and everything pretty much does except for disconnecting.

  1. What is the issue? Include screenshots / videos if possible!

I get these errors:

When executing this code:

The Code


local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
	print(player.Name .. " joined the game!")

	
	wait(8)
	
	
	local EMERGENCYSTOP = false
	warn("HELPP")
	local connection 



	--local player = script.Parent.Parent
	local IsWantedBoolean = player:WaitForChild("IsWantedBoolean",10)
	
	print(player:FindFirstChild("IsWantedBoolean"))
	print(IsWantedBoolean)
	print(IsWantedBoolean.Value)	
	
	local function Counter()
		
		IsWantedBoolean:SetAttribute("Counting", true)
		
		while true do

			if EMERGENCYSTOP == true then
				break
			elseif IsWantedBoolean:GetAttribute("WantedTimeRemaining") <= 0 then
				if connection == nil then
					print("Errro")
				end
				connection:Disconnect()
				IsWantedBoolean:SetAttribute("Counting", false)
				break
			end


			wait(1)

			print(IsWantedBoolean:GetAttribute("WantedTimeRemaining"))

			IsWantedBoolean:SetAttribute("WantedTimeRemaining", IsWantedBoolean:GetAttribute("WantedTimeRemaining") -1)
			
			print(IsWantedBoolean:GetAttribute("WantedTimeRemaining"))
		end

	end

	--wait(3)


	local function runtime()
		warn("Ancestory Changed")
		if IsWantedBoolean then
			warn("Good")
			-- Check if wanted level has a number

			if IsWantedBoolean:GetAttribute("WantedTimeRemaining") ~= 0 then
				-- check the amount and then start counting I guess
				print("Counter call")
				
				
				
				connection = Counter()
			else
				warn("We're Zero!")
			end


			



		else
			error("TheBoolIsNil")
		end

	end


	local function attributeChanged(attributeName)
		print(attributeName, "Changed")
		if attributeName == "WantedTimeRemaining" and IsWantedBoolean:GetAttribute("WantedTimeRemaining") > 0 and IsWantedBoolean:GetAttribute("Counting") ~= true then
			print("Bruh")
			connection = Counter()
		elseif attributeName == "WantedTimeRemaining" and IsWantedBoolean:GetAttribute("WantedTimeRemaining") <= 0 then
			connection:Disconnect()
		end
	end

	IsWantedBoolean.AttributeChanged:Connect(attributeChanged)
	wait(2)

	runtime()

end)

Players.PlayerRemoving:Connect(function(player)
	print(player.Name .. " left the game!")
end)

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

I’ve tried re-writing this over and other and checking for issues. Additionally I tried setting it up exactly like this roblox api article but still no luck sadly. If anyone knows if i’m connecting this wrong, please let me know asap. Thanks!

1 Like

variable connection is nil, it’s not set to store anything, i know you have an connection = Counter() in the runtime function, but the problem is, everytime a player is added it resets the variable:

Players.PlayerAdded:Connect(function(player)
	print(player.Name .. " joined the game!")

	
	wait(8)
	
	
	local EMERGENCYSTOP = false
	warn("HELPP")
	local connection -- this resets it

and i dont see a line where it calls runtime() before checking if connection is nil

2 Likes

Well, one reason the connection variable is inside of the player added function is so that it’ll remain individual to the player and not effect others when they join (please correct me if that’s not how it works, Also I put the connection outside of the player added and it’s the same scenario).

Also, the only reason there is not a check for connection is because it isn’t set until runtime is called

1 Like

okay, also a question, what is this?
image
it will not work unless Counter() returns a value which i dont see it doing.
and for note, you can only disconnect objects returned by :connect(), if ur trying to disconnect something else

2 Likes

So, would I remove the parentheses? Or is there a different way of doing this that I don’t understand?

I’m trying to set the connection to the count event and have it disconnect when it’s no longer needing to count so it won’t be idle.

1 Like

Firstly, Counter returns void so doing connection = Counter() doesn’t do anything.

Secondly, you can’t disconnect from a function so doing connection = Counter and then connection:Disconnect() would be invalid. If you’re trying to stop the while true do loop, use the break keyword or use coroutines instead.

Thirdly, use task.wait instead of wait.

Edit: here’s a valid example of dealing with connections:

local connection = nil
connection = game:GetService("Players").PlayerAdded:Connect(function(plr)
    if plr.Name == "SomeImportantPerson" then
        print("VIP has finally joined!")
        connection:Disconnect()
    else
        print("Not yet...")
    end
end)
2 Likes

Exactly what are you trying to disconnect?

If it is the handler for the PlayerAdded event then you need to move the connection variable and assign the result of the :Connect call to it

local connection = Players.PlayerAdded:Connect(function(player) ... end)
1 Like

You can’t disconnect a variable from a function in the way you are trying.

1 Like
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
	task.wait(8)
	local EMERGENCYSTOP = false
	local connection = true
	local IsWantedBoolean = player:WaitForChild("IsWantedBoolean", 10)
	
	local function Counter()
		if not connection then
			return
		end
		IsWantedBoolean:SetAttribute("Counting", true)
		
		while true do
			if EMERGENCYSTOP then
				break
			elseif IsWantedBoolean:GetAttribute("WantedTimeRemaining") <= 0 then
				connection = false
				IsWantedBoolean:SetAttribute("Counting", false)
				break
			end
			
			task.wait(1)
			IsWantedBoolean:SetAttribute("WantedTimeRemaining", IsWantedBoolean:GetAttribute("WantedTimeRemaining") -1)
		end
	end
	
	local function runtime()
		if IsWantedBoolean then
			if IsWantedBoolean:GetAttribute("WantedTimeRemaining") ~= 0 then
				connection = true
			end
		end
	end
	
	local function attributeChanged(attributeName)
		if attributeName == "WantedTimeRemaining" and IsWantedBoolean:GetAttribute("WantedTimeRemaining") > 0 and IsWantedBoolean:GetAttribute("Counting") ~= true then
			connection = true
		elseif attributeName == "WantedTimeRemaining" and IsWantedBoolean:GetAttribute("WantedTimeRemaining") <= 0 then
			connection = false
		end
	end
	
	IsWantedBoolean.AttributeChanged:Connect(attributeChanged)
	task.wait(2)
	runtime()
end)

Players.PlayerRemoving:Connect(function(player)
end)

This probably isn’t the behavior you’re looking for but this is how you’d create a variable which controls whether or not the body of a function should proceed with execution, in this case “connection” is acting as a debounce, you’ll need to change where I’ve toggled its assigned Boolean value if necessary.

1 Like

You cannot connect a function, connection refers to the RBXScriptSignal object (that is what has the :Disconnect() function). To create a connection you must call :Connect() on an event.

1 Like

I tried using this and for whatever reason it wouldn’t work, but I’ll take another look soon

So then how could I make it so the function stops completely when the attribute reaches zero, basically how can I stop a function

You have to tell the code inside the function to stop. There isn’t a built in way to stop a function in it’s tracks (for complex reasons).

For example, you could do something like this:

local function counter()
    local count = 0

    local active = true
    while active do
        count += 1
        print(count)
        task.wait(1)
    end

    local function fakeDisconnectFunction()
        active = false
    end

    return {Disconnect = fakeDisconnectFunction}
end

When you tell your code to repeat, it’s going to repeat. What you can do though is add an end condition.

In the code above, the repeating stops when the boolean “active” becomes false. You probably want to do this somewhere else in your code, so we send out a function that sets “active” to false that can be used elsewhere.

For example, you could use the code above like this:

local function counter()
    local count = 0

    local active = true
    while active do
        count += 1
        print(count)
        task.wait(1)
    end

    local function fakeDisconnectFunction()
        active = false
    end

    return {Disconnect = fakeDisconnectFunction}
end

local fakeConnection = counter()
wait(2.5)
fakeConnection:Disconnect() -- Can use fakeConnection.Disconnect(), both work (the : sends the fakeDisconnectFunction the entire table too)

Output:

1
2

Let me know if you’ve got any questions :+1:

1 Like

I’m not very sure, but I don’t think you can disconnect an event inside of the event.

1 Like

How would I call fake connect function if it’s inside the counter function?

You can use the return keyword. The return keyword lets a function output a value.

For example:

local function getMessage()
    return "Hello" -- when you run the function it evaluates to "Hello"
end

print(getMessage()) -- same as print("Hello") because "Hello" is outputted by our function getMessage

Output:

"Hello"

Similarly, instead of returning the string “Hello”, we can return a function from inside the other function:

local function getFunction()
    local function myFunction()
        print("Fizz")
    end
   return myFunction -- myFunction is the name of our function. If you want to run a function, add ()
end

local func = getFunction()
func()

Output:

"Fizz"

This might make it make more sense:

local function func()

end

is actually just:

local func = function() end

When you create a function with local function functionName() it’s actually just creating a variable and setting that variable’s value to a new function.

1 Like

I think I understand the function thing you’re talking about but my script still has the Disconnect error :confused:

local fakeConnection 


local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
	print(player.Name .. " joined the game!")

	
	wait(8)
	
	
	local EMERGENCYSTOP = false
	warn("HELPP")
	



	--local player = script.Parent.Parent
	local IsWantedBoolean = player:WaitForChild("IsWantedBoolean",10)
	
	print(player:FindFirstChild("IsWantedBoolean"))
	print(IsWantedBoolean)
	print(IsWantedBoolean.Value)	
	
	local active = true


	local function Counter()
		
		IsWantedBoolean:SetAttribute("Counting", true)
		
		


		while active do

			if EMERGENCYSTOP == true then
				break
			end
			--[[elseif IsWantedBoolean:GetAttribute("WantedTimeRemaining") <= 0 then
				if connection == nil then
					print("Errro")
				end
				connection:Disconnect()
				IsWantedBoolean:SetAttribute("Counting", false)
				break
			end]]


			wait(1)
			
			
			print(IsWantedBoolean:GetAttribute("WantedTimeRemaining"))

			IsWantedBoolean:SetAttribute("WantedTimeRemaining", IsWantedBoolean:GetAttribute("WantedTimeRemaining") -1)
			
			print(IsWantedBoolean:GetAttribute("WantedTimeRemaining"))

		end


		local function fakeDisconnectFunction()
			active = false
			IsWantedBoolean:SetAttribute("Counting", false)
		end

		return {Disconnect = fakeDisconnectFunction}

	end

	--wait(3)
	

	local function runtime()
		warn("Ancestory Changed")
		if IsWantedBoolean then
			warn("Good")
			-- Check if wanted level has a number

			if IsWantedBoolean:GetAttribute("WantedTimeRemaining") ~= 0 then
				-- check the amount and then start counting I guess
				print("Counter call")
				
				
				
				fakeConnection = Counter()
			else
				warn("We're Zero!")
			end


			



		else
			error("TheBoolIsNil")
		end

	end


	local function attributeChanged(attributeName)
		print(attributeName, "Changed")
		if attributeName == "WantedTimeRemaining" and IsWantedBoolean:GetAttribute("WantedTimeRemaining") > 0 and IsWantedBoolean:GetAttribute("Counting") ~= true then
			print("Bruh")
			fakeConnection = Counter()
		elseif attributeName == "WantedTimeRemaining" and IsWantedBoolean:GetAttribute("WantedTimeRemaining") <= 0 then
			fakeConnection:Disconnect()
		end
	end

	IsWantedBoolean.AttributeChanged:Connect(attributeChanged)
	wait(2)

	runtime()

	--local fakeConnection = Counter()
end)



Players.PlayerRemoving:Connect(function(player)
	print(player.Name .. " left the game!")
end)

The function acts kind of like a normal connection, so if you want to use it later in your code you’ll need to store it. I think the problem with your code is that you create the fake connection twice.
I’m not sure where the problem is :doh:. There are some good ways you can refactor your code though:

  • Instead of having a bunch of variables and stuff, why not just use the Attribute “WantedTimeRemaining” to manage everything? For example, if the Attribute is greater than 0 you can assume the player is wanted and if it isn’t then you can assume they aren’t. Then, when the attribute becomes greater than zero, you can start a while loop like so:
while IsWantedBoolean:GetAttribute("WantedTimeRemaining") > 0 do

That makes your code:

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
	local countdownActive = false
	local function attributeChanged(attributeName)
		if attributeName == "WantedTimeRemaining" then
			if (IsWantedBoolean:GetAttribute("WantedTimeRemaining") > 0) and (not countdownActive) then
				countdownActive = true
				while IsWantedBoolean:GetAttribute("WantedTimeRemaining") > 0 do
					IsWantedBoolean:SetAttribute("WantedTimeRemaining", IsWantedBoolean:GetAttribute("WantedTimeRemaining") -1)
					wait(1)
				end
				countdownActive = false
			end
		end
	end
	IsWantedBoolean.AttributeChanged:Connect(attributeChanged)

	--wait(2) -- I'd recommend removing this

	--runTime()
	-- Instead of using runTime, we can just use the attributeChanged handler to process the initial value.
	attributeChanged("WantedTimeRemaining") -- process the initial WantedTimeRemaining value
end)
With explanatory comments
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
	local countdownActive = false
	local function attributeChanged(attributeName)
		-- if correct attribute
		if attributeName == "WantedTimeRemaining" then
			-- if the count-downer-thingy should start
			if (IsWantedBoolean:GetAttribute("WantedTimeRemaining") > 0) and (not countdownActive) then
				-- set the bool to let the rest of the code know the counter is going
				countdownActive = true
				-- run the counter until it should stop
				while IsWantedBoolean:GetAttribute("WantedTimeRemaining") > 0 do
					IsWantedBoolean:SetAttribute("WantedTimeRemaining", IsWantedBoolean:GetAttribute("WantedTimeRemaining") -1)
					wait(1)
				end
				-- set the bool to let the rest of the code know the counter is not going
				countdownActive = false
			end
		end
	end
	IsWantedBoolean.AttributeChanged:Connect(attributeChanged)

	--wait(2) -- I'd recommend removing this

	--runTime()
	-- Instead of using runTime, we can just use the attributeChanged handler to process the initial value.
	attributeChanged("WantedTimeRemaining") -- process the initial WantedTimeRemaining value
end)