OneTimer map?

GetTriggerUnit-

DogEntrepreneur
Reaction score
129
I was passing time and got the idea of a map which needs sereval timers but can run all of em on only one timer. I came up with this code. I know it could be better, thats why I'm posting it here. It would need Array recycling, I know.

I tested the code at low and high periods with sereval instances, no lag, no delay, no bugs.

JASS:

library OneTimer initializer init

    globals
        // At what period is recalls
        private constant real Period = 0.001
        // The global Timer
        private timer Timer = CreateTimer()
        // Instances Count
        private integer Count = 0
        // Globals array
        private integer array Counts
        private integer array Maxs
        private string array Names
    endglobals
    
    public function AddFunction takes string fctname, real period returns nothing
    // I know this will need recycling and to be re-done...
        set Names[Count] = fctname
        set Counts[Count] = 0
        set Maxs[Count] = R2I(period / Period)
        set Count = Count + 1
    endfunction
    
    private function Periodic takes nothing returns nothing
        local integer i = 0
        loop
            if (Counts<i> &gt;= Maxs<i>) then
                call ExecuteFunc(Names<i>)
                set Counts<i> = 0
            endif
            set Counts<i> = Counts<i> + 1
            exitwhen i == Count
            set i = i + 1
        endloop
    endfunction

    private function init takes nothing returns nothing
        call TimerStart(Timer, Period, true, function Periodic)
    endfunction
    
endlibrary
</i></i></i></i></i></i>


At 0.001, String leaks starts to make it laggy but it isn't the system at all thats lags...

JASS:

function First takes nothing returns nothing
    call BJDebugMsg(&quot;Instance : 0.50&quot;)
endfunction

function Second takes nothing returns nothing
    call BJDebugMsg(&quot;Instance : 1.00&quot;)
endfunction

function Third takes nothing returns nothing
    call BJDebugMsg(&quot;Instance : 1.50&quot;)
endfunction

function Fourth takes nothing returns nothing
    call BJDebugMsg(&quot;Instance : 2.00&quot;)
endfunction

function Fifth takes nothing returns nothing
    call BJDebugMsg(&quot;Instance : 2.50&quot;)
endfunction

function Sixth takes nothing returns nothing
    call BJDebugMsg(&quot;Instance : 3.00&quot;)
endfunction

function Seventh takes nothing returns nothing
    call BJDebugMsg(&quot;Instance : 3.50&quot;)
endfunction

function Eighth takes nothing returns nothing
    call BJDebugMsg(&quot;Instance : 4.00&quot;)
endfunction

function Nineth takes nothing returns nothing
    call BJDebugMsg(&quot;Instance : 4.50&quot;)
endfunction

function fast takes nothing returns nothing
    //call BJDebugMsg(&quot;FAST&quot;)
    // Because when it&#039;s working, it makes too many string leaks
    // and make map buggy as hell
endfunction

function InitTrig_test takes nothing returns nothing
    call OneTimer_AddFunction(&quot;fast&quot;, 0.001)
    call OneTimer_AddFunction(&quot;First&quot;, 0.50)
    call OneTimer_AddFunction(&quot;Second&quot;, 1.00)
    call OneTimer_AddFunction(&quot;Third&quot;, 1.50)
    call OneTimer_AddFunction(&quot;Fourth&quot;, 2.00)
    call OneTimer_AddFunction(&quot;Fifth&quot;, 2.50)
    call OneTimer_AddFunction(&quot;Sixth&quot;, 3.00)
    call OneTimer_AddFunction(&quot;Seventh&quot;, 3.50)
    call OneTimer_AddFunction(&quot;Eighth&quot;, 4.00)
    call OneTimer_AddFunction(&quot;Nineth&quot;, 4.50)
endfunction
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
It's ugly because you have to use SCOPE_PREFIX/SCOPE_PRIVATE if your functions are public/private.
Also i didn't test myself but i've always heard that ExecuteFunc is several times slower than TriggerExecute/Evaluate ?
(Hmm i'm wondering if is not basically the same as CreateTrigger,AddAction,ExecuteTrigger,RemoveAction,DestroyTrigger)
Maybe it becomes slower and slower depends the number of functions declared inside the whole script ?

Sure, here you don't create handles, but i don't believe this thing win in speed against the same version but with TriggerAddCondition/Evaluate and a trigger array.

EDIT :
And you don't provide a way to link an integer data, which is very lame.
 

GetTriggerUnit-

DogEntrepreneur
Reaction score
129
EDIT: Here it is: The Beta 0.5 version. I'll try doing what you said about TriggerExecute BUT does it means the the function periodic would have to return boolean if I use TriggerAddCondition? Could I use both TriggerAddAction / TriggerRemoveAction to avoid action leak?

Code

JASS:

// Some parts needs to be recoded for more efficienty.
// Thats why I post it here. Once it&#039;ll be almost perfect
// and as much efficient as possible, I&#039;ll post it for real.
library OneTimer initializer init

    globals
        // Maximun OneTimers there can be at once on the map.
        private constant integer MAX_TIMER_AT_ONCE = 100
        // Period of the timer
        private constant real Period = 0.001
        //The famous OneTimer
        private timer Timer = CreateTimer()
        // For the Struct return
        private integer StructId = 0
        private integer array Structs
        // Recycle
        private boolean array Used
    endglobals
    
    struct OneTimer
        private string name
        private integer max
        private integer count
        
        static method Create takes string s, real p returns integer
            local integer i = 0
            local thistype onetimer
            loop
                if not (Used<i>) then
                    set Used<i> = true
                    set onetimer = i
                    set onetimer.max = R2I(p / Period)
                    set onetimer.count = 0
                    set onetimer.name = s
                    return i
                endif
                exitwhen i == MAX_TIMER_AT_ONCE
                set i = i + 1
            endloop
            return -1
        endmethod
        
        method Release takes nothing returns nothing
            set Used[this] = false
            set .name = &quot;&quot;
            set .max = 0
            set .count = 0
        endmethod
        
        static method Periodic takes nothing returns nothing
            local integer i = 0
            local thistype onetimer
            loop
                if (Used<i>) then
                    set onetimer = i
                    if (onetimer.count &gt;= onetimer.max) then
                        call ExecuteFunc(onetimer.name)
                        set StructId = i
                        set onetimer.count = 0
                    endif
                    set onetimer.count = onetimer.count + 1
                endif
                exitwhen i == MAX_TIMER_AT_ONCE
                set i = i + 1
            endloop
        endmethod
    endstruct
    
    // Get the id of the current timered struct.
    
    public function SetData takes integer ot, integer data returns nothing
        set Structs[ot] = data
    endfunction

    public function GetData takes nothing returns integer
        return Structs[StructId]
    endfunction
    
    // Init
    
    private function init takes nothing returns nothing
        local integer i = 0
        loop
            set Used<i> = false
            exitwhen i == MAX_TIMER_AT_ONCE
            set i = i + 1
        endloop
        call TimerStart(Timer, Period, true, function OneTimer.Periodic)
    endfunction

endlibrary
</i></i></i></i>


Tested with

JASS:
 //Tested and worked
scope Test initializer init

    private struct data
        string name
    endstruct
    
    private function periodic takes nothing returns nothing
        local data d = OneTimer_GetData
        call BJDebugMsg(d.name)
    endfunction

    private function init takes nothing returns nothing
                                          // Only this need fixs. It could be considered has a con...
        local OneTimer ot = OneTimer.Create(&quot;Test__periodic&quot;, 0.05)
        local data d = data.create()
        set d.name = &quot;Hello GetTriggerUnit()&quot;
        call OneTimer_SetData(ot, d)
    endfunction
    
endscope
 

Romek

Super Moderator
Reaction score
963
This obsession with having as few timers as possible is becoming ridiculous.
The cost of having one timer running like this is simply incomparable to having those few extra timers running normally and efficiently.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Your one is same with Cohadar's TT.
However, your one is risky.

Jasshelper may compile private functions to :
[ljass]"Test__periodic"[/ljass]
or
[ljass]"Test___periodic"[/ljass]

That's why timer systems creators uses trigger to execute the functions, except for T32(because it is implemented in the scope, it can access the function by calling them)

If you continue to do this, the last you will get is worse edition of TT(Because you use very low period, which caused lag). Your one is incomparable with linked list, which is more efficient.

JASS:
////////////////////
//  TimedFunc v1.0
//   by kingking
//  StartPeriodic(func,data)
//  StopPeriodic()
///////////////////
library TimedFunc initializer Init
    
    globals
        constant real PERIOD = .03125
    endglobals
    
    function interface PeriodicFunc takes integer data returns nothing
    
    globals
        private PeriodicFunc array Func
        private integer array Data
        private integer array Prev
        private integer array Next
        private integer this = 0
        
        private integer Counter = 0
        private integer array NextNode
        private integer NextNodeCount = 0
    endglobals
    
    function StartPeriodic takes PeriodicFunc func, integer data returns nothing
        local integer i
        if NextNodeCount &gt; 0 then
            set i = NextNode[NextNodeCount]
            set NextNodeCount = NextNodeCount - 1
        else
            set Counter = Counter + 1
            set i = Counter
        endif
        set Prev[Next[0]] = i
        set Next<i> = Next[0]
        set Next[0] = i
        set Prev<i> = 0
        set Data<i> = data
        set Func<i> = func
    endfunction
    
    function StopPeriodic takes nothing returns nothing
        set Next[Prev[this]] = Next[this]
        set Prev[Next[this]] = Prev[this]
        set NextNodeCount = NextNodeCount + 1
        set NextNode[NextNodeCount] = this
    endfunction
    
    private function Handler takes nothing returns nothing
        set this = Next[0]
        loop
        exitwhen this == 0
            call Func[this].execute(Data[this])
            set this = Next[this]
        endloop
    endfunction
    
    private function Init takes nothing returns nothing
        call TimerStart(CreateTimer(),PERIOD,true,function Handler)
    endfunction
endlibrary
</i></i></i></i>
 

Romek

Super Moderator
Reaction score
963
@ kingkingyyk3:
Not only does it seem like you don't know what you're talking about, but the 'system' you posted does something quite different to what's described in the first post.
 

GetTriggerUnit-

DogEntrepreneur
Reaction score
129
I won't publish it, I'll use it on my own.

Just want to know.
This version is leak-free, right?
It been improoved to use TriggerEvaluate and TriggerAddCondition(for leakfreeness)

JASS:
library OneTimer initializer init

    globals
        private constant integer MAX_TIMER_AT_ONCE = 100
        private constant real Period = 0.001
        private timer Timer = CreateTimer()
        private integer array Structs
        private boolean array Used
        private integer Id
    endglobals
    
    struct OneTimer
        private trigger trig
        private integer max
        private integer count
        
        static method Create takes code func, real p returns integer
            local integer i = 0
            local thistype ot
            loop
                if not (Used<i>) then
                    set Used<i> = true
                    set ot = i
                    set ot.max = R2I(p / Period)
                    set ot.count = 0
                    set ot.trig = CreateTrigger()
                    call TriggerAddCondition(ot.trig, Condition(func))
                    return i
                endif
                exitwhen i == MAX_TIMER_AT_ONCE
                set i = i + 1
            endloop
            return -1
        endmethod
        
        method Release takes nothing returns nothing
            set Used[this] = false
            call DestroyTrigger(.trig)
            set .trig = null
            set .max = 0
            set .count = 0
        endmethod
        
        method SetData takes integer data returns nothing
            set Structs[this] = data
        endmethod
        
        method GetData takes nothing returns integer
            return Structs[this]
        endmethod
        
        static method Periodic takes nothing returns nothing
            local integer i = 0
            local thistype ot
            loop
                if (Used<i>) then
                    set ot = i
                    if (ot.count &gt;= ot.max) then
                        set Id = i
                        call TriggerEvaluate(ot.trig)
                        set ot.count = 0
                    endif
                    set ot.count = ot.count + 1
                endif
                exitwhen i == MAX_TIMER_AT_ONCE
                set i = i + 1
            endloop
        endmethod
    endstruct
    
    public function GetTimer takes nothing returns OneTimer
        return Id
    endfunction
    
    private function init takes nothing returns nothing
        local integer i = 0
        loop
            set Used<i> = false
            exitwhen i == MAX_TIMER_AT_ONCE
            set i = i + 1
        endloop
        call TimerStart(Timer, Period, true, function OneTimer.Periodic)
    endfunction

endlibrary</i></i></i></i>

JASS:
scope Test initializer init

    private struct data
        string name
        integer count
    endstruct
    
    private function periodic takes nothing returns nothing
        local data d = OneTimer_GetTimer().GetData()
        set d.count = d.count + 1
        call BJDebugMsg(d.name + &quot; &quot; + I2S(d.count))
        if (d.count &gt; 500) then
            call OneTimer_GetTimer().Release()
        endif
    endfunction

    private function init takes nothing returns nothing
        local OneTimer ot = OneTimer.Create(function periodic, 0.05)
        local data d = data.create()
        set d.name = &quot;Hello, GetTriggerUnit-&quot;
        set d.count = 0
        call ot.SetData(d)
    endfunction

endscope
 

Romek

Super Moderator
Reaction score
963
Why would you want to use something like that, even if it's only for your private projects?
I'd strongly suggest T32 and TimerUtils, or KT2 if you'd rather an all-in-one system.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Not only does it seem like you don't know what you're talking about, but the 'system' you posted does something quite different to what's described in the first post.
It is just an example of linked list timer. It can be modified to fit GetTriggerUnit-'s stuffs.
I have tried the idea of GetTriggerUnit- before, however, the inefficient caused me to stay away from it.
 

Jesus4Lyf

Good Idea™
Reaction score
397
I'd strongly suggest T32 and TimerUtils, or KT2 if you'd rather an all-in-one system.
That's pretty much it, I'd say that's nearly perfect. I'd say T32/TU is the ultimate.

I also understand completely if you want to make your own sys anyway, regardless if it is best or not. There's a few issues with what you're doing. It's very inefficient. Your Create function is O(n). [LJASS]R2I(p / Period)[/LJASS] creates an inaccuracy (ok, it's small, but exists - think measuring unit backswing points). [LJASS]set ot.count = ot.count + 1[/LJASS] can be avoided, have a global that counts up in (gametime/period) as an integer. Saves a couple of array reads and math. :thup:

Hope that helps.
Go ahead, do what you will. ;)
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Omg, you are using DestroyTrigger. >< I think you need to read how TT works, then improve your one.
 

GetTriggerUnit-

DogEntrepreneur
Reaction score
129
Well, thank much much for your help guys.

I'll go with T32.

It's magical.

I'm working on a new snippet that uses T32 and Event (<3).

I love T32 because you don't need to SetData / GetData, only call .startPeriodic / stoPeriodic and implement it.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top