Quantcast Coroutines, Loop, or update over time without freezing? - ESOUI
Thread Tools Display Modes
06/24/18, 05:27 AM   #1
Necrotic
Join Date: Jun 2018
Posts: 5
Coroutines, Loop, or update over time without freezing?

I would like to make a loop or update that continues for a few seconds.

Using while(nowTime < endTime) freezes the game till it's finished looping.

Are there coroutines in lua?
  Reply With Quote
06/24/18, 05:43 AM   #2
Shinni
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 120
Lua does have them, but the lua variant used in eso is stripped of coroutines.

Votan created a lib (LibAsync), which can be used instead. With the lib you can create a sequence of commands which are then spread over multiple frames via the game's OnUpdate event.

You can find the lib in his minimap addon. I haven't used the lib myself so the following example might be wrong. From looking at the lib's code I think it is used like this:

Let's say you want to replace the following:
Lua Code:
  1. for i = startValue, endValue do
  2.     something with value i
  3. end
then you can instead do
Lua Code:
  1. local async = LibStub("LibAsync")
  2.  
  3. local someFunction = function( i )
  4.     something with value i
  5. end
  6. --variant A
  7. local task = async:Create("yourTaskName")
  8. task:For(startValue, endValue):Do(someFunction)
  9. -- OR variant B
  10. async:For(startValue, endValue):Do(someFunction)

Variant A has the benefit that you can pause or interrupt the task via task:Suspend() or task:Cancel()

Last edited by Shinni : 06/24/18 at 05:50 AM.
  Reply With Quote
06/24/18, 05:47 AM   #3
manavortex
 
manavortex's Avatar
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 137
Edit: I threw something into the wiki.

Lua Code:
  1. -- run for 5 seconds
  2. local withinInterval = true
  3. zo_callLater(function() withinInterval = false end, 5000)
  4.  
  5. while withinInterval do
  6.     -- something
  7. end

Or, more asynchronous - this should call the function around 10 times
Lua Code:
  1. -- run for 5 seconds
  2. local withinInterval = true
  3. zo_callLater(function() withinInterval = false end, 5400)
  4.  
  5. local function callWithinInterval()
  6.     if not withinInterval then return end
  7.     -- do something
  8.     return zo_callLater(callWithinInterval, 500)
  9. end
  10. -- now call it
  11. callWithinInterval()

Last edited by manavortex : 06/24/18 at 07:29 AM.
  Reply With Quote
06/24/18, 02:40 PM   #4
ArtOfShred
 
ArtOfShred's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2016
Posts: 65
The other way is by using EVENT_MANAGER:RegisterForUpdate("name", function, timer)
You can then EVENT_MANAGER:UnregisterForUpdate("name") to stop the function from running if/when needed.

Note there's a lot of discussion over whether or not registering and unregistering events on a consistent basis is a good idea or not. I use it for a few things and I haven't noticed any negative impact from it.
Also it's widely excepted that you should avoid zo_callLater most of the time unless you're only using it sparingly or for something you absolutely need it for.

There is one nice advantage to RegisterForUpdate, and that is you can make a continuous throttle by reregistering the update function whenever a certain function triggers. I use this in LUI Extended to make a "x" variable duration throttle timer for Experience Gain for example. If the player goes 5 seconds without gaining XP then the saved value is dumped, reset, and the event is unregistered. If the player gains XP again during that 5 sec window, the event is reregistered and thus the timer restarts.
  Reply With Quote
06/24/18, 03:59 PM   #5
Baertram
 
Baertram's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 1,617
Isn't zo_callLater just a verison of RegisterForUpdate(...) ? I'm not sure why everyone says zo_callLater is not ok but RegisterForUpdate is then
  Reply With Quote
06/24/18, 05:00 PM   #6
SDPhantom
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 23
They both work. Registering the timer directly with EVENT_MANAGER directly is more efficient than calling zo_callLater(), but the later is easier to deal with.

This is literally what zo_callLater() does.
Lua Code:
  1. local ZO_CallLaterId = 1
  2. function zo_callLater(func, ms)
  3.     local id = ZO_CallLaterId
  4.     local name = "CallLaterFunction"..id
  5.     ZO_CallLaterId = ZO_CallLaterId + 1
  6.  
  7.     EVENT_MANAGER:RegisterForUpdate(name, ms,
  8.         function()
  9.             EVENT_MANAGER:UnregisterForUpdate(name)
  10.             func(id)
  11.         end)
  12.     return id
  13. end

On an added note, if you use EVENT_MANAGER:RegisterForUpdate() and don't unregister the function, it'll just keep calling at the interval you gave it. This is something zo_callLater() simply can't do without calling it more times.
__________________
ESOUI AddOns | WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
06/25/18, 05:00 AM   #7
Necrotic
Join Date: Jun 2018
Posts: 5
Awesome! Thank you all so much!
  Reply With Quote
06/26/18, 04:46 PM   #8
decay2
AddOn Author - Click to view addons
Join Date: Aug 2014
Posts: 67
Originally Posted by SDPhantom View Post
On an added note, if you use EVENT_MANAGER:RegisterForUpdate() and don't unregister the function, it'll just keep calling at the interval you gave it. This is something zo_callLater() simply can't do without calling it more times.
Using zo_callLater() in a way where it can call itself again can lead to problems (function calls get piled up).

EVENT_MANAGER:RegisterForUpdate() is nice in a way that as long as you use a fixed string as the first parameter it will still just run once at every intervall. A second registration attempt with the same name simply fails (it also returns false then).

So it's best to decide on a per case basis which one to use.
  Reply With Quote
06/28/18, 08:38 PM   #9
SDPhantom
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 23
Originally Posted by decay2 View Post
Using zo_callLater() in a way where it can call itself again can lead to problems (function calls get piled up).
zo_callLater() doesn't run the callback itself, it just sets up a timer for the system to do so later. In the process, it does add a call or two to the stack, but it doesn't grow further than that since there is no recursion.
__________________
ESOUI AddOns | WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote

ESOUI » Developer Discussions » Lua/XML Help » Coroutines, Loop, or update over time without freezing?

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off