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