Official ScriptUO EasyUO Scripts > Script development tools

TrailMyx's Fun with Timers

(1/1)

TrailMyx:
I've been going through my vast collection of unfinished tools, and one that popped out that bugged me that wasn't finished (and probably won't ever be) is my automated timer subs.  Anyone who has played with timers and state machines will know how useful they can be.  I'm attaching a group of subs plus a little tidbit of sample code that shows what's going on.  These subs use the global namespace TM_TIMERS so timer status can be seen through other scripting instances.  You can expand on these subs; I just made what I had started work correctly.

For the example script (found at the beginning of the subs) there's alot going on.  Try and follow along with it:


--- Code: easyuo ---gosub TM_ResetTimersgosub TM_RegisterTimer Timer1 auto 10 second Callback1gosub TM_RegisterTimer Timer2 5 1 second set %timer1 0set %timer2 0repeat  gosub TM_ProcessTimers  if Timer1 in #RESULT  {    set %timer1 %timer1 + 1    if %timer1 % 2 = 1      gosub TM_RestartTimer Timer2  }  if Timer2 in #RESULT    set %timer2 %timer2 + 1until #FALSEstop 
In this snippet:

* Timer1 runs forever (auto) and fires every 10 seconds.  Also when the timer fires, the callback function "Callback1" is called
* Timer2 runs only 5 times, and fires every 1 second.
* Timer1 is used to rearm Timer2 when the Timer1 is first run and every ODD firing of Timer1 (watch %timer1 and %timer2 variables)
* #RESULT of TM_ProcessTimers shows a list of expired timers.  If a callback is attached, it will already have run
I have a bunch of subs like this, and perhaps I'll slowly finish them as time goes on.


--- Code: easyuo ---gosub TM_ResetTimersgosub TM_RegisterTimer Timer1 auto 10 second Callback1gosub TM_RegisterTimer Timer2 5 1 second set %timer1 0set %timer2 0repeat  gosub TM_ProcessTimers  if Timer1 in #RESULT  {    set %timer1 %timer1 + 1    if %timer1 % 2 = 1      gosub TM_RestartTimer Timer2  }  if Timer2 in #RESULT    set %timer2 %timer2 + 1until #FALSEstop ; -------------------------------------------------------- sub Callback1  display ok Callback 1 called!return  ; -------------------------------------------------------- sub TM_ResetTimers  namespace push  namespace global TM_TIMER  namespace clear  namespace popreturn ; -------------------------------------------------------- sub TM_RegisterTimer  namespace push  namespace global TM_TIMER   if !num = N/A    set !num -1  if %0 < 4  {    display ok 4 arguments required for TM_RegisterTimer - stopping    stop    }  set !num !num + 1  set !var %1  set !function %2 ; auto, number  set !time_length %3  set !time_unit %4 ; millisecond, second, minute, hour  if %0 = 5    set !callback %5  else    set !callback N/A  set ! . timer , !num !var ; save the name to a list for automatic time updating  set ! . !var , function !function  set ! . !var , trigger_max !function  set ! . !var , time_length !time_length  set ! . !var , time_unit !time_unit  set ! . !var , callback !callback  set ! . !var , enabled #TRUE    if !time_unit notin _millisecond_second_minute_hour_  {    display ok time unit not equal to millisecond, second, minute, hour - stopping    stop  }  if !time_unit = millisecond     set ! . !var , time_unit !time_length  if !time_unit = second     set ! . !var , time_unit ( !time_length * 20 )  if !time_unit = minute     set ! . !var , time_unit ( !time_length * 20 * 60 )  if !time_unit = hour     set ! . !var , time_unit ( !time_length * 20 * 60 * 60 )   set !time_unit !var , time_unit  set ! . !var , timer ( #SCNT2 + ( ! . !time_unit ) )  ; set the actual end time  namespace popreturn ; -------------------------------------------------------- sub TM_ProcessTimers  namespace push  namespace global TM_TIMER  set !lpc #LPC  set #LPC 200    set !RESULT  for !i 0 !num  {    set !current_name ! . timer . !i    set !enabled !current_name , enabled    set !timer !current_name , timer    set !time_unit !current_name , time_unit    set !function !current_name , function    set !callback !current_name , callback     set !test1 #SCNT2 , _ , ! . !timer    if ( ( ! . !enabled = #TRUE ) && ( #SCNT2 > ( ! . !timer ) ) )    {      set !function !current_name , function      if ( ( ( ! . !function ) = auto ) || ( ! . !function <> 0 ) )      {        set !RESULT !RESULT , _ , !current_name ; add expired timer name to present list        set ! . !timer ( #SCNT2 + ( ! . !time_unit ) )  ; set the actual end time, resetting timer        if ! . !function <> auto          set ! . !function ( ( ! . !function ) - 1 )        if ! . !callback <> N/A          gosub ! . !callback      }    }  }  set #RESULT !RESULT  set #LPC !lpc  namespace popreturn #RESULT ; -------------------------------------------------------- sub TM_RestartTimer  namespace push  namespace global TM_TIMER  set !name %1    set !function !name , function  set !trigger_max !name , trigger_max  set !enabled !name , enabled  set !timer !name , timer  set !time_unit !name , time_unit    set ! . !function ! . !trigger_max  set ! . !enable #TRUE    set ! . !timer ( #SCNT2 + ( ! . !time_unit ) )  ; set the actual end time  namespace popreturn ; -------------------------------------------------------- sub TM_StopTimer  namespace push  namespace global TM_TIMER  set !name %1  set !enabled !name , enabled  set ! . !enabled #FALSE  namespace popreturn 

Gaderian:
Thank you for sharing these routines on Timers.

I have had so many conversations about timers in the last maybe 6 months... (hence the signature addition). It is a very nice concept for how to write very efficient code that acts when needed and doesn't have to do anything much when just waiting for timers.

You mention state machines and I have only met a few other programmers who understood these. Personally, I only designed a couple of applications to use a state machine. From a very ubiquitous experience it is a very efficient method to code when you want ultimate UI flexibility. Specifically: Graphical user interfaces (Windows, MacOS, X-Windows) run on a state machine.

It can also be considered/labeled "event driven" programming. The only complexity is being willing to give up the main loop control. The main loop has to be elegant for the system to work smoothly and be understandable. Once a programmer can handle that concept, the code is clean and needs to follow a simple structure.

Combine timers with a state machine and you have a really flexible script. ;)

Gaderian

TrailMyx:

--- Quote from: Gaderian on April 25, 2020, 07:52:46 AM ---Thank you for sharing these routines on Timers.

--- End quote ---

You bet, I have a few others to come


--- Quote from: Gaderian on April 25, 2020, 07:52:46 AM ---I have had so many conversations about timers in the last maybe 6 months... (hence the signature addition). It is a very nice concept for how to write very efficient code that acts when needed and doesn't have to do anything much when just waiting for timers.

--- End quote ---

I saw that; you were the one that prompted me to dig through my stash.  :)


--- Quote from: Gaderian on April 25, 2020, 07:52:46 AM ---You mention state machines and I have only met a few other programmers who understood these. Personally, I only designed a couple of applications to use a state machine. From a very ubiquitous experience it is a very efficient method to code when you want ultimate UI flexibility. Specifically: Graphical user interfaces (Windows, MacOS, X-Windows) run on a state machine.

--- End quote ---

I'm a digital hardware designer by trade, so I often think about software solutions through the lens of hardware programming in VHDL or Verilog.  By default, those methods of expression are inherently parallel in nature.  So it's fun to force EasyUO kicking and screaming to do something it was never designed to do.  heh.  Your Windows programming example is an excellent example of it.


--- Quote from: Gaderian on April 25, 2020, 07:52:46 AM ---It can also be considered/labeled "event driven" programming. The only complexity is being willing to give up the main loop control. The main loop has to be elegant for the system to work smoothly and be understandable. Once a programmer can handle that concept, the code is clean and needs to follow a simple structure.

--- End quote ---

You're right for sure.  If you can break all your total functionality to just use timers and state machines, your main loop can actually look exactly like this:


--- Code: easyuo ---repeat  gosub TM_ProcessTimers  gosub TM_HandleStateMachineuntil #FALSE 
Since you have access to the Elite script section, you can see a few of my scripts that are state machine driven.  Here's a couple:

Mining/Lumberjack Assistant:
http://www.scriptuo.com/index.php?topic=13509.msg112203#msg112203

Zoo donation:
http://www.scriptuo.com/index.php?topic=36.msg36#msg36

SOS Autofarmer:
http://www.scriptuo.com/index.php?topic=2048.msg15109#msg15109

All of these have remarkably small main loops.



Navigation

[0] Message Index

Go to full version