Temporarily Yielding a Script Part Way - How To Do This?

I recently revisited an old project of mine and realized I had never gotten a system finished. - To keep it short, I need to find a way to temporarily yield code at any given point in a function by using a BindableEvent, (might be unreliable but I’m not much of an experienced scripter), and then being able to resume the code by using a different event.

Within a larger function of a ModuleScript I have set up for one of the in-game events, I have this function at the top:

YieldEvent.Event:Connect(function()
		print("Event signal received, yielding script.")
		repeat wait() until ResEvent.Event
		print("Event signal received, resuming script.")
	end)

This function’s intended purpose is to stop the larger function when YieldEvent is called, no matter which line of code is being executed next. (Is that a good way to describe it?) And then resume the function when ResEvent is called.

When YieldEvent is called, it doesn’t do its proper function and doesn’t yield the whole script, my only assumption being that it runs as a separate function compared to the rest of the script. How would I make it so that the wait() loop stops the rest of the code momentarily until ResEvent is called? Would I need to code a special wait function for the script, or is there a simpler solution?

tl;dr : trying to figure out how to stop/resume a script midway, tried a couple of things already, need help.

2 Likes

Couldn’t you just do ResEvent.Event:Wait()? It should yield the thread until ResEvent.Event is fired

1 Like

I asked a friend earlier and tried this, changing the function stops the whole rest of the script before anything has a chance to start.

I’m not sure what you mean, couldn’t you call the function that yields the thread last or just use a separate thread entirely for it?

(edited) Actually from what I’ve observed if you’re using bindableEvents your best bet is just to use BindableEvent.Event:Wait();
if you however are customly making your own events then a possible approach could be this
– scripts calling it

task.spawn(function()
 task.wait(5)
 StopCurrentThread:UnWait( someNumberUniqueToCurrentThread) 
end) 
StopCurrentThread:Wait()
module scripts 
```local totalWaits = 0
local stopTable = {}

function Wait()
totalWaits += 1
local CurrentIteration = totalWaits
local currentThread = coroutine.running()
stopTable[CurrentIteration] = false
  task.spawn(function()

       while true do
task.wait()

if stopTable[CurrentIteration] == true then 
task.spawn(currentThread)
end

end
end)
return coroutine.yield()
end
function UnWait(SpecificThread)
-- this will be a number, every thread halted using these functions will have a unique number assigned to them
stopTable[SpecificThread]  = true
end

The supposed-to-be yield function (highlighted in the image) is part of a larger function that is called by an external script. (in-game event that is inside a ModuleScript for organization purposes)

Therefore, using YieldEvent.Event:Wait() in the function will prevent any more code from running beyond that point.

You said I should move the function elsewhere, where should I move it?

Edit: Note that this code is like a year and a half old and I haven’t touched it since yesterday.

Perhaps you should look into the Promise library, it is really helpful for these scenarios

To yield the main function, you can create a new thread for it which can be yielded from the outside. Here’s an example:

function main()
  while task.wait() do
  print("I'm running!")
  end
end

local thread = coroutine.create(main)

local function pause()
  coroutine.yield(thread)
end
local function resume()
  coroutine.resume(thread)
end

YieldEvent.Event:Connect(pause)
ResumeEvent.Event:Connect(resume)
resume()

Hope this helps!

Will this work in a ModuleScript or will I need to convert it to a regular Script?

I tried looking into this before, but I have a really difficult time understanding how it works.

Yes, this works with modulescripts too.

--Promise use case example

module.Start = function() 
	return Promise.new(function(resolve, _, onCancel)
		local cancel = false
		if onCancel(function() cancel = true end) return end

		function OpenBlastShelters()
		end

		function LockBlastShelters()
		end

		while not cancel do
			--do whatever game logic
			task.wait(1)
		end

		resolve() --call when finished thread
	end)
end)

--and this is how you use it:
local startPromise = module.Start()
YieldEvent.Event:Connect(function() startPromise:cancel() end)

I tried this and it didn’t seem to work… did I format it wrong or do I need to move it outside of module.Start?

image

After actually testing my solution, I realized that coroutine.yield is only capable of yielding the current thread, as opposed to a thread the current thread has created. I apologize for providing an incorrect solution.
However, if the main function can be reran from the top upon unpausing you could do something like this:

function loop()
print("Even though I'm not part of the loop, since the function was reran from the top I ran again. Put me outside of this function if you don't want that to happen.")
	while task.wait() do
		print("I'm running!")
	end
end

local thread
local function pause()
	coroutine.close(thread)
end
local function resume()
	thread = coroutine.create(loop)
	coroutine.resume(thread)
end

workspace.Yield.Event:Connect(pause)
workspace.Resume.Event:Connect(resume)
resume()

Hope this works for you, and sorry for both the incorrect response and late reply!

This works… somewhat.
Is there a way to make this so that the function picks up where it previously left off?

I looked into this a little and I’m still having a hard time understanding it. Only replying again now since I have not gotten a different response in >24hrs.

I haven’t tried this yet but after looking at the Promises page and this code, I have a few questions.

  • When the YieldEvent is called, it seems that the function is stopped completely. Is there a way to only pause it momentarily until ResEvent is called?
  • Where do I put the startPromise function? Does it go into the ModuleScript or do I need to put it into a separate script?