I was excited to use the changed coroutine.yield on my project while I came across this coroutine issue while using it on RemoteFunction(OnServerInvoke).
ServerScript:
print("Server>> Initialized");
local remote = game.ReplicatedStorage.Request;
remote.OnServerInvoke = function(player)
local currentThread = coroutine.running();
print("Server>> Server invoked, Thread:",currentThread);
coroutine.wrap(function()
wait(1);
coroutine.resume(currentThread, "Hello");
end)();
print("Server>> Server yielding, Thread:",currentThread);
local yieldValue = coroutine.yield();
print("Server>> Server yielded:", yieldValue,", Thread:",currentThread);
return yieldValue;
end
Client Script
print("Client>> Hello world!");
local remote = game.ReplicatedStorage:WaitForChild("Request");
local result;
print("Client>> Invoking server");
delay(2, function() print("Client>> Force print results:", result); end);
result = remote:InvokeServer();
print("Client>> Server results:",result);
Output
As you can see, server outputs yielded: Hello, but it doesn’t return the value to the invoked client and client is stuck yielding for the server’s return.
I’m not sure If I am doing something wrong or if this is a bug. Thanks in advance for reading.
Wow, interesting find. I could reproduce this myself too. So using coroutine.yield within OnServerInvoke causes the return value to never get sent to the client, thus causing the client to yield indefinitely.
Perhaps this should be placed under Engine Bugs instead of Scripting Support?
Before the changes, my assumption is because roblox will take over threads that use any roblox asynchronous functions that yield the thread with the task manager. A problem however is that this effect is not applied beforehand to new threads. A simple example would be using coroutine.yield() before a wait() call and then one after. The second yield will output like a wait() call because of the task managing process. This is most likely a result of the task manager not being able to manage the process’s yield correctly because, as mentioned above, a wait call (which again asserts the thread into the task managing process) will fix the issue. It might have something to do with the change not functioning correctly for these functions in specific.
local t = coroutine.running()
coroutine.wrap(function()
while coroutine.status(t) ~= "dead" do
coroutine.resume(t, "Manual resume")
wait(1)
end
end)()
print(coroutine.yield())
print(wait())
print(coroutine.yield())
I was able to reproduce this with the following code
local bindable = Instance.new("BindableFunction")
function bindable.OnInvoke()
print("Invoked")
local thread = coroutine.running()
spawn(function ()
print("Thread resuming")
coroutine.resume(thread, "Howdy")
end)
print("Thread yielding")
local result = coroutine.yield()
print("Thread resumed")
return result
end
local result
delay(1, function ()
print("Force print:", result)
end)
print("Invoke")
result = bindable:Invoke()
print("Print:", result)
I have a feeling I know what is going on. I’ll verify this now and hopefully have a fix for this soon.
This seems to be unrelated to coroutine.yield and instead, it is related to coroutine.resume. You can repro this by replacing the call to yield in my example with wait(1e5).
Has this been fixed yet? I seem to still be having this issue in the part of my project where I left off back when I first encountered it. Guess I’ll have to use another method in the meantime.
Bump, I ran into this issue, and it took a couple of hours to figure out what was happening
This is roughly how it was in my game (with the main exception that the task.delay() was a task.defer() with an asynchronous function afterwards) Client
local RemoteFunction = game.ReplicatedStorage.RemoteFunction
warn("Server Invoked")
RemoteFunction:InvokeServer()
warn("Remote Returned") -- Client yeilds forever, this is never printed
Server
local RemoteFunction = game.ReplicatedStorage.RemoteFunction
RemoteFunction.OnServerInvoke = function(Player)
local Coroutine = coroutine.running()
task.delay(5,function()
coroutine.resume(Coroutine)
end)
warn("Server yeild started")
coroutine.yield(Coroutine)
warn("Server yeild ended")
return
end