• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • ✅ The POLL for Hive's Texturing Contest #33 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!

Timer questions

Status
Not open for further replies.
Level 12
Joined
May 22, 2015
Messages
1,051
So I understand TimerUtils is basically just a timer recycling library. Is this correct? It has some other functions, but that seems like the main use for it. The idea being creating and destroying timers is significantly slower than recycling them.

Anyway, I have heard there are other timer systems which use logic to condense multiple timers into one. I imagine it would keep some kind of list of functions that will execute when it expires. Would it then use triggers as pseudo function handles? Is that faster than making many timers that will expire at the same time?

I am curious how those systems work. Optionally, a link to such a library would be nice. Is there a trade-off between these systems? Is a system that has just one timer to expire at one time going to be less efficient in the case where you never have any timers expire at the same time? How much so?

Thanks for any information in advance!
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,203
Timer Utlis have one very important function which I found out about yesterday.

Basically, you can do the following:

JASS:
//code written by hand on the site, might not compile.
//! zinc
    library something
    {
         struct myStruct
         {
          real number;
         static method whatever()
         {
               timer t = GetExpiredTimer();
               thistype this = GetTimerData(t);
               BJDebugMsg(R2S(this.number)); //will write 5 every 0.03 seconds

         }
         static method create() -> thistype
         {
              thistype this = thistype.allocate();
              timer t = NewTimerEx(this);
              TimerStart(t, 0.03, true, function whatever);
              this.number = 5;
         }
         }
    }
//! endzinc
 
Last edited:
Level 12
Joined
May 22, 2015
Messages
1,051
Ya I was doing that SetTimerData and GetTimerData myself manually. I basically just saved it to a hashtable used only for storing temporary data for timers. In my more recent code, I only needed to store a single index, which I realise now is basically exactly what a struct does lol (I don't use vJASS yet).

I think maybe the best question for me to ask is if timers running / expiring and then running a function is more expensive than running a bunch of triggers. The triggers would be static, but the timers would also essentially be static since they are recycled. I have no idea about the speed between a timer expiring and a trigger being run.

Note that when I say "run a trigger", I really mean TriggerEvaluate(myTrigger).
 
Level 13
Joined
Jan 2, 2016
Messages
978
I checked out the TimerUtils's code.
All this "GetTimerData(t)" does is "GetHandleId(t) - 0x100000"

A bit offtopic, but your script is giving me some information about structs, which I want to confirm:
Since structs are basically linked together global variable arrays, and the struct variable is basically an integer, telling it which index to use for the variables, using "set thistype this = ~integer~" will allow me to loop trough the different structs?
Example:
JASS:
struct Test
    integer i
endstruct

function somefunc takes nothing returns nothing
     local Test t = Test.create()
     set t.i = 5
     call SaveInteger(Table, 0, 0, t)
     call BJDebugMsg(I2S(LoadInteger(Table, 0, 0)))
endfunction

// if this shows ~17 for example~
// if I have another function:

function anotherfunc takes nothing returns nothing
    local Test t = 17
    //if I do:
    call BJDebugMsg(I2S(t.i))
    //will it show 5?
endfunction

EDIT: actually I tested it myself, and it works exactly like that! :D
 
Level 12
Joined
May 22, 2015
Messages
1,051
Back with some more questions:

1) I remember having problems stopping and starting periodic timers. Does Timer Utils deal with this in some way or are you supposed to just not use periodic timers? Maybe I don't fully understand how it all works.

2) If I start a timer with: call TimerStart(t, 1, false, function abc) and then interrupt that timer by pausing it, what happens when I do call TimerStart(t, 1, false, function def)? This is assuming t is the same timer and I never unpaused t. Will it run both abc and def or just def?
 
Level 12
Joined
May 22, 2015
Messages
1,051
(1) TimerUtils just does data attachment. You'll have to handle pausing/resuming timers yourself. Instead of using ResumeTimer(t), try using TimerStart(...) again.

(2) Just def. Timers can only have one schedule to one function.

I am looking at this system for reference (in case it is not the same one most people talk about):
http://www.wc3c.net/showthread.php?t=101322

NewTimer() and ReleaseTimer(t) are used for recycling timers, unless I misunderstand the code.

Note that I am writing my own code because I am interested in learning how the system works. Using TimerStart on a paused periodic timer didn't work. I'll write a small script to test it later to make sure that's what the problem is. Everything is working when I stopped trying to recycle periodic timers.

I feel like it would be mentioned in that other thread, though, if doing ReleaseTimer on a periodic timer didn't work. I'll have to investigate more. The system code is extra complex with the multiple configurations, so I may have missed some important code.
 
Level 13
Joined
Jan 2, 2016
Messages
978
On my map, I'm using my own timer recycling system, and it works without any problems..
I'm pausing the timers, when I recycle them, no matter if they are periodic or not.
And I'm able to start them after.

I don't know why you can't xP

JASS:
library TimerFunctions
    
    globals
        private hashtable Timers = InitHashtable()
        private integer count = 0
    endglobals
    
    function RecTimer takes timer t returns nothing
        if not LoadBoolean(Timers, GetHandleId(t), 0 ) then
            call PauseTimer(t)
            call FlushChildHashtable(udg_Table, GetHandleId(t))
            call SaveTimerHandle(Timers, 0 , count , t )
            set count = count + 1
            call SaveBoolean(Timers, GetHandleId(t), 0 , true)
        endif
        set t = null
    endfunction

    function GetFreeTimer takes nothing returns timer
        local timer t
        if count > 0 then
            set count = count - 1
            set t = LoadTimerHandle(Timers, 0 , count)
            call SaveBoolean(Timers, GetHandleId(t), 0 , false)
            return t
        else
            return CreateTimer()
        endif
    endfunction
    
endlibrary
It's not flawless, but it works fine :p
 
Level 12
Joined
May 22, 2015
Messages
1,051
That is basically what I have as well lmao. It's pretty simple. Maybe I accidentally recycled a null timer somewhere. I will do more thorough tests tonight. I don't think I have a check for that in my recycle function.
 
Level 12
Joined
May 22, 2015
Messages
1,051
Can we see your code? TimerStart(...) works on paused timers. Your recycling might be returning a null timer, which might be why it doesn't seem to be working.

I can post my code when I get home. That's the most likely issue, though. I will do some tests and then see if I am still stuck.

EDIT:
Hey I tested it and it must have been null timers. I put the check to make sure the timer isn't a null when recycling and it worked. Thanks for the help, guys!
 
Last edited:
Status
Not open for further replies.
Top