Sorry, I should have given more detail. What I mean is to yield in an async enviroment (by async I mean that the coroutine and normal script are running in a separate thread).
So:
local myFunc = coroutine.wrap(function
end);
myFunc();
myFunc:Wait(); --Something like this, it will wait until the coroutine finished
local stopped = Instance.new("BindableEvent")
coroutine.wrap(function()
stopped:Fire() --Fire right before yielding
coroutine.yield()
end)
stopped.Event:Wait() --will wait until the coroutine finished
You can fire that event from the coroutine whenever you’d like.
Is there any way without using Instances? Bindable events can’t send important arguments like tables with metatables in them. This would break my entire proxy system (Since it is an empty table that is connected to another using a metatable).
Not sure if there’s a way to do it without instances.
But you could store the table variable outside of the coroutine, the coroutine will make changes to it, and then you will have it with the metatables and everything outside of the coroutine, without giving it to the BindableEvent.
local stopped = Instance.new("BindableEvent")
local tab = setmetatable({},{})
coroutine.wrap(function()
--Make changes to the table
stopped:Fire() --Fire right before yielding
coroutine.yield()
end)
stopped.Event:Wait() --will wait until the coroutine finished
--Use tab here
Or the second option, apply the metatables back after the firing.
local thisThread = coroutine.running() -- this will return the thread that is being run right now
coroutine.wrap(function()
-- your stuff
coroutine.resume(thisThread) -- now resume the thread that is outside of this coroutine
end)()
coroutine.yield() -- now this will yield indefinitely until resumed
It is preferable to use task.spawn instead of coroutine.wrap/coroutine.create and coroutine.resume because they are notorious with not logging errors that happen in the threads made by coroutine and will make you pluck your hair out trying to figure why your code just doesn’t work.
Really? I just got 2 answers in one post! The EventModule was really annoying with this since it needed to spawn the function. It logged like “Error in pairs()” instead of the entire thread. Thank you!
Yep, just to make sure you do it right, it’s like this:
local thisThread = coroutine.running() -- this will return the thread that is being run right now
task.spawn(function()
-- your stuff
task.spawn(thisThread) -- now resume the thread that is outside of this coroutine
end)
coroutine.yield() -- now this will yield indefinitely until resumed
Also, you can resume any thread from any other thread as long as you got the thread id using coroutine.running(), so you can resume thread in script A from script B, which is pretty cool
This isn’t entirely true, ‘coroutine’ wrapper functions created via the coroutine.wrap() function are ran in a call stack shared by the active/current thread of execution, any errors that occur in the coroutine’s function’s body are propagated to the call to the wrapper function itself, for example.
coroutine.wrap(function()
print(true + false)
end)()
--attempt to perform arithmetic (add) on boolean
coroutine.resume() on the other hand resumes the execution of coroutines in an alternate call stack (similar to the pcall/xpcall globals) unique to the coroutine itself, this means that errors are not propagated to calls to coroutine.resume().
coroutine.resume(coroutine.create(function()
print(true + false)
end))
--Error is not propagated.
In the former example the call stack of the active/current thread is terminated, in the latter example an alternate call stack is terminated.
Also, you can resume any thread from any other thread as long as you got the thread id using coroutine.running() , so you can resume thread in script A from script B, which is pretty cool
Just be wary of the fact that coroutines do not cross the network boundary.