Right now if you call coroutine.yield in a scripts body the thread scheduler will automatically resume the script. It would be really useful in certain situations to have the thread actually yield until we decide to resume it ourselves.
A use case for this is in custom events. Currently you have to do something like (waitForEvent)
table.insert(threads, coroutine.running())
local output repeat
output = {coroutine.yield()}
local valid = table.remove(output, 1)
until type(valid) ~= "number" -- The scheduler returns a number from yield
coroutine.yield() -- Ensures the scheduler regains control of the thread
return unpack(output)
So if I want to return a value that does not meet that criteria I need to use custom threading.
local class = {}
class.__index = class
class.WillBeLost = "Hi"
local obj = setmetatable({
WillNotBeLost = "Hello"
}, class)
e:Fire(obj)
local obj = e.Event:Wait()
print(obj.WillBeLost) >> nil
I am creating custom objects and firing my own events when they’ve been created. In the case of wait the objects would lose information and their metatables.
It would be nice to “unregister a thread as a roblox thread” (me and a lot of people call Lua threads “roblox threads” when they’re in the sceduler, not sure if there’s an official name for it), but for your issue, a BindableEvent would work fine:
local function CreateEvent()
local be = Instance.new("BindableEvent")
local event,cache = {},{}
function event:Connect(f)
return be.Event:connect(function(key)
local t = cache[key]
f(unpack(t,1,t.n))
end)
end event.connect = event.Connect
function event:Wait()
local t = cache[be.Event:wait()]
return unpack(t,1,t.n)
end event.wait = event.Wait
function event:Fire(...)
local key = tick()
cache[key] = {n=select("#",...),...}
be:Fire(key) cache[key] = nil
end return event
end
local ev = CreateEvent()
spawn(function()
local data = {Banana=123}
local test = setmetatable({},{__index=data})
ev:Fire(data)
end)
ev:connect(function(uhu)
print("Connect:",uhu.Banana)
end)
print("Wait:",ev:wait().Banana)
--> Wait: 123
--> Connect: 123
Lots of people have rewritten custom events that are basically BindableEvent wrappers so they can pass arguments directly. While that would solve your problem, being able to coroutine.yield() “for real” in roblox threads would be nice. Could be something like coroutine.ryield() or whatever. Maybe just have coroutine.setrobloxthread(false) remove the current (or passed-as-argument?) thread from the scheduler.
TL;DR: Being able to “unschedule” threads isn’t necessary for your problem, but nice to have.
While the wiki doesn’t have a lot of information about roblox threads, it has a bit:
Some of the information is outdated (or slightly wrong), but still a good read.