I can’t post in the bug reports section for some reason so I will post here. I’m having this odd issue with yielding coroutines within a module. If a coroutine has been yielded inside a module script and resumed at any future time, the module script will continue to run but it will not return to the caller after it has finished running.
It’s possible there may be some underlying logic behind this, but this doesn’t seem like desired or expected behavior.
Somebody please try this. I was able to recreate it in a blank world. Just look over and copy the two scripts below.
Is this a bug or is there something else going on?
-- Script
local module = script.ModuleScript
local resume
function shared.ScheduleThread()
resume = coroutine.running()
end
function SameAsModule()
print("Halt")
shared.ScheduleThread()
coroutine.yield()
print("Resume")
return true
end
function ThisWorks()
coroutine.wrap(function()
SameAsModule()
print("This will print")
end)()
end
function ThisDoesnt()
coroutine.wrap(function()
require(module)
print("This will not print")
end)()
end
ThisDoesnt() -- Change this to ThisWorks() to see what I'm talking about
wait(5)
coroutine.resume(resume)
That’s because that’s not how module scripts work. A module script will run all of it’s code at start up just like any other script. The only difference is that you can return a value from a module script and require it into another script. Knowing this, you can do:
-- ModuleScript
local module = {}
module.ThisWorks = function()
print("Halt")
shared.ScheduleThread()
coroutine.yield()
print("Resume")
end
return module
as your module script and
function ThisDoesnt()
coroutine.wrap(function()
require(module).ThisWorks()
print("This will not print")
end)()
end
This solution is just a variation of the ThisWorks() function. I’m wondering why it doesn’t work when the modules thread gets yielded and resumed.
If you run ThisDoesnt(), you can see that coroutine.resume actually works, but it stops at “return true” and doesn’t go back to the caller. How is this not a bug?
Yes I understand that, but I’m not requiring it more than once. The code only requires the module one time and then yields the thread within the coroutine that requires the module.
shared.ScheduleThread schedules a coroutine.resume call to continue after the yield. If you test it you’ll see that “Resume” actually gets printed even though it comes after coroutine.yield()
-- Inside module script
shared.ScheduleThread() -- This calls function shared.ScheduleThread in the main script
coroutine.yield()
-- Inside main script
function shared.ScheduleThread()
resume = coroutine.running() -- Sets the resume variable to the current thread
end
-- Bottom of main script
wait(5)
coroutine.resume(resume) -- Resume the thread
Try copying my code directly and you can see that it prints both “Halt” and “Resume” so you know it actually is resuming.
I see what you mean now, that is rather odd. Is there any specific reason you need the code to be like this specifically since this will only ever be able to be used once which seems counter-intuitive to the point of module scripts.
However, it seems like it’s being treated as two separate threads so it’s not actually returning. I don’t know why.
Doing this:
-- Script
local module = script.ModuleScript
local resume
local r2
function shared.ScheduleThread()
r2 = coroutine.running()
print("Schedule")
end
function ThisDoesnt()
resume = coroutine.create(function()
print("Run")
require(module)
print("This will not print")
end)
coroutine.resume(resume)
end
ThisDoesnt()
wait(5)
coroutine.resume(r2)
coroutine.resume(resume)
It does print everything, however it treats them as two separate threads entirely. I was able to further this result as if I resume only one or the other either “Resume” will print or “This will not print” will print. Obviously this isn’t what you want though.
Also further backed up by this result:
-- Script
local module = script.ModuleScript
local resume
function shared.ScheduleThread()
resume = coroutine.running()
print("Schedule")
end
function ThisDoesnt()
coroutine.wrap(function()
print("Run")
require(module)
print("This will not print")
end)()
print(coroutine.running())
end
ThisDoesnt()
wait(5)
print(resume)
coroutine.resume(resume)
It seems that calling your shared.SchedleThread() from the module seems to separate them into two threads which is why you only see “Resume” and not “This will not print” Though I don’t know of any real solution to this.
Sorry for eariler, I misunderstood what wasn’t working.
Here’s something new I tested that seems to work:
function shared.ScheduleThread()
--resume = coroutine.running()
print(coroutine.running == resume) --Prints false! It is not equal to the thread.
end
function ThisDoesnt()
resume = coroutine.create(function()
require(module)
print("This will not print")
end) --Create the thread
coroutine.resume(resume) --Run it
end
wait(5)
coroutine.resume(resume)
It seems that the thread scheduleThread picks up is not the thread you yielded.
I think Roblox is binding a separate thread to a require() call meaning that coroutine.running() will return a separate thread than the initial resume coroutine. You’re right but this does still seem like a bug. Can someone make a bug report and link my original post?