Joined: 25 Jan 2006
|Posted: Sun Jun 28, 2020 7:36 pm Post subject: Simple Coroutine Example
|Since this came up in a recent topic, here is an example of using Lua's built-in coroutine functionality. This is using a CE timer as a means to resume the coroutine as needed. (This is a way to do intensive work without freezing the CE UI until things have fully finished.)
This is a very basic example showing the bare minimum of doing something with coroutines. They are extremely flexible and great to use for a lot of things, so I'd encourage people to get familiar with them more since they are generally not used much by less advanced users of Lua.
-- CE Coroutine Example
-- by atom0s
Flag used to determine if the coroutine should continue running.
This is used to tell the coroutine if it should continue working or not. You can set this internally within the coroutine after it has
completed its work, or you can use something else as a way to 'timeout' the coroutine to stop it from endlessly running if it failed
it's objective. (Make a second timer that has a 10 second interval delay and just set isRunning = false and kill that new timer for example.)
local isRunning = true;
Create the coroutine that will do the heavy lifting work.
This coroutine SHOULD NOT do any intensive/long loops. You should be coding this to do a single-attempt fire at what your objective/goal is
in order to allow the yielding to properly work and let CE continue to operate without freezing.
For example, if you are scanning for an AoB endlessly until it is found then you should not do a loop for it here. Instead, you should code
the scan to happen once here. If not found, allow the coroutine.yield() call to happen. If found, set isRunning to false and return early and
the coroutine will die cleanly on the next timer tick itself.
local co = coroutine.create(function()
-- Check if isRunning is false..
while (isRunning == true) do
-- Do your single-tick of work here..
-- Yield the coroutine until it's resumed again via our timer..
-- Coroutine has completed, it will be marked as dead after this print..
print('coroutine has completed!');
Create the timer to tick the coroutine.
This timer is used to resume the coroutine each time the timer interval happens. For intensive workloads, you can just set this timers
interval to something really low (ie. 1 to 10) to ensure it is operating fast. The timer will continue to check the status of the coroutine
each tick until it is either nil or marked as dead. (Meaning it returned without yielding.) Once the coroutine is dead, the timer will kill
itself and cleanup.
local timer = createTimer();
timer.Interval = 500; -- Can adjust to a much smaller interval if you need faster ticks of the coroutines work..
timer.OnTimer = function(t)
-- Check and resume the coroutine each time the ticker ticks if the coroutine is valid..
local status = coroutine.status(co);
if (co ~= nil and status ~= 'dead') then
-- Kill the timer if the coroutine has died..
print('timer has been destroyed!');
Creates an example hotkey as a means of 'canceling' the coroutine.
This is just to demonstate how to kill the coroutine outside of the coroutine and timer functions via the isRunning flag.
Think of this like a 'Cancel' button.
print('hotkey was pressed!');
-- Tell the coroutine to finish..
isRunning = false;
This will create a coroutine that is continuously resumed by a timer every 500ms.
You can press F2 to exit the coroutine which will self-kill the timer.