Cancelling a Function/Event

There is actually a way to disconnect outside of the function. Here’s a quick example I created.

count = 0 
local c = script.Parent.Touched:Connect(function()
	count = count + 1
end)

while true do
    wait()
    if count >= 5 then
	    c:Disconnect()
	end
end

It does seem to disconnect right when it gets to five for me, but it could depend on how many times you are firing the function in a matter of seconds.

1 Like

is there any way I could see the full code?

1 Like

Does :Disconnect() instantly disconnect the function, or does it wait for the function to finish?

Why would you need to cancel a function half-way through? I’m sure you can, but it’ll be messy and there’s probably a better way of writing your code out so it doesn’t need to do this.

4 Likes

Sure. It looks messy at the moment:

If you prefer, i can explain to you what this does.

script:

local RoundFunction = require(script.RoundFunctions)

local ReplicatedStorage = game:WaitForChild("ReplicatedStorage")
local Values = ReplicatedStorage:WaitForChild("Values")
local IntermissionTimer = Values:WaitForChild("IntermissionTimer")

local IntermissionConnect1 = script:WaitForChild("IntermissionConnect1")

local IsIntermission = false
local IntermissionDone = false


local Intermission = IntermissionConnect1:GetPropertyChangedSignal("Value"):Connect(function()
	print("Start")
	wait(0.25)
	IsIntermission = true
	RoundFunction.IntermissionTimer(10)
	IntermissionDone = true
end)

game.ReplicatedStorage.RemoteEvents.AvailablePlayers.OnServerEvent:Connect(function()
	if IntermissionDone == false then
		local AvailablePlayers = RoundFunction.InsertReadyPlayers()
		if #AvailablePlayers <1 then
			if IsIntermission then
				IsIntermission = false
				Intermission:Disconnect()
			end
			if #AvailablePlayers == 0 then
				IntermissionTimer.Value = "2 Ready Players Required"
			elseif #AvailablePlayers == 1 then
				IntermissionTimer.Value = "1 Ready Player Required"
			else
				print("Error")
			end
		elseif #AvailablePlayers >= 1 then
			if not IsIntermission then
				if IntermissionConnect1.Value then
					IntermissionConnect1.Value = false
				elseif not IntermissionConnect1.Value then
					IntermissionConnect1.Value = true
				else
					print("Error")
				end
			end
		end
	end
end)

ModuleScript:

local module = {}

local ReplicatedStorage = game:WaitForChild("ReplicatedStorage")
local Values = ReplicatedStorage:WaitForChild("Values")
local IntermissionTimer = Values:WaitForChild("IntermissionTimer")


function module.InsertReadyPlayers()
	local AvailablePlayers = {}
	for i,v in pairs(game.Players:GetPlayers()) do
		local PlayerGui = v:WaitForChild("PlayerGui")
		local Values = PlayerGui:WaitForChild("Values")
		local Ready = Values:WaitForChild("Ready")
		if Ready.Value then
			if not table.find(AvailablePlayers,v)then
				table.insert(AvailablePlayers,v)
			end
		elseif not Ready.Value then
			if table.find(AvailablePlayers,v)then
				table.remove(AvailablePlayers,i)
			end
		else
			print("Error")
		end
	end
	return AvailablePlayers
end



function module.IntermissionTimer(Seconds)
	local Interrupted = false
	for i = Seconds,0,-1 do
		IntermissionTimer.Value = "Intermission: "..i
		wait(1)
	end
end
1 Like

If it’s something like an infinite loop within the function, disconnecting the listener will cause it to stop listening for the event - but the loop will keep running, so in that case you could: every iteration check for some sort of variable at the beginning of the block, and only run the code if the variable’s value is true, so you could set the value to false after disconnecting.

Read this too: Can I pause a coroutine from outside of it? - #6 by un1ND3X

4 Likes

In my case its a for loop.

So if i’m correct, the function stops, but the for loop in the module script doesn’t?

No the iteration if it was infinite, will keep running in a thread - disconnecting a listener only allows you to unsubscribe to an event so that firing it again (after disconnecting obviously) won’t let the callback passed to the listener run.

local active = true
--  your function
coroutine.wrap(function() 
    while true do
    if not active then coroutine.yield() end -- you could use break too
    -- do your stuff within 
    end
end)()

wait(5)
active = false

This is just one way.

2 Likes

Since Connections are just functions, you can call return to instantly stop the function, returning nothing to the event handler.

local function HandleNoob(p)
  if p.UserId == 8094244 then
     return --do nothing (cancel the event)
  end

  print("Noob Inbound!")
end

Players.PlayerAdded:Connect(HandleNoob)

I see.

I’m trying to make an intermission system, where two people with values set to true (changed with a button) are required for it to start, and if in between the intermission, one decided to leave, the intermission cancels.

I did this successfully by adding if statements and for loops checking that at least 2 players have this value set to true, and making the function run again (by calling it again). However, i found this really messy, so i redesigned the system so that it would only check the players everytime someone pressed the button, and if there were less than 2, cancel the intermission.

So that’s where i am now. I’m trying to make it cancel the intermission when there are less than 2 players with this value set to true.

(Basically in short, i don’t want to use the method you provided me because that would mean i have to stuff my code full of if statements and for loops constantly checking the players).

Edit: i think i’ve found a solution.

yo im in a similar situation almost 4 years later. whats your solution :sweat_smile:

task.cancel()
Is a good way to cancel it mid function, disconnecting the event wouldn’t stop it if it had already started.
task.cancel() would stop it no matter what.

Oh sorry I should’ve looked at the date, read my previous reply.
didn’t notice you reopened this topic.

yo im not sure how that works. can you explain it for me?

I basically have an if statement that checks for something if true it does this
StartCounting = task.spawn(CountDown)

another if statement if true it does this
task.cancel(StartCounting)

is that how it works?

That’s not how cancel works. Cancel prevents the thread from being resumed by the task scheduler which relies on it being in a yielding state. A thread will continue to run if it was executed by the task scheduler and cancelling it won’t abort the thread’s resumption.

Yes, task.spawn creates a thread, the function you spawned will be handled entirely on this thread.
if you use task.cancel to cancel that thread the function you spawned will stop.

I have always used it this way and never had any problems.
The description on creator hub is a bit vague in my opinion but I do think that closing a thread means it stops the function inside of it.

1 Like

The documentation is not vague, it explicitly explains what cancel does which is preventing the task scheduler from resuming a thread. Threads that have already been resumed cannot be cancelled. There is no such thing in Luau as stopping a non-yielded thread mid-execution.

“I didn’t have problems” isn’t the same as “this is correct”. You’re likely using it in the right way, but your explanation about cancel is wrong and misleading.

this solved my problem. Alright thanks, mate :+1:

Yeah no problem, goodluck with your game.