System Abct

Cohadar

master of fugue
Reaction score
209
This system is obsolete.
It has been merged with TT. <========<<

JASS:
//==============================================================================
//  ABCT - Timer library by Cohadar - v3.0
//==============================================================================
//
//  PURPOUSE OF ABCT:
//       * Passing data to timers
//
//  PROS: 
//       * It is easier than using attaching
//       * It is in fact doing a LOT of dirty work for you
//
//  CONS:
//       * Every Start call creates a new timer
//         so for high-frequency timers it is more efficient to use TT
//         Opposite is also true: for low-frequency timers ABCT is better than TT
//
//  FUNCTIONS:
//       * ABCT_Start(userFunc, struct, period)
//       * ABCT_Zero(userFunc, struct)
//       * ABCT_GetData() -&gt; struct
//
//       * userFunc is a user function that takes nothing and return boolean
//         userFunc should return true to stop timer.
//
//       * ABCT_Start will periodically call userFunc until it returns true.
//       * ABCT_Zero will call userFunc only once after current thread is completed.
//         userFunc that is called with ABCT_Zero MUST return true or it will leak.
//
//       * ABCT_GetData() is a function that can be used inside userFunc
//         ABCT_GetData() will return struct passed to Start function
//
//  DETAILS:
//       * ABCT is using smart timer and trigger preloading and simple hash
//         When colliding timer handle is found that timer is simply discarded
//
//  HOW TO IMPORT:
//       * Just create a trigger named ABCT
//       * convert it to text and replace the whole trigger text with this one
//==============================================================================
library ABCT initializer Init

globals
    // how many timers and triggers to preload
    private integer PRELOAD = 128 

    // we can safely use dummy hashing here because timers are preloaded
    public constant integer HASH = 8191
    
    // passing data
    private integer bj_data
    private integer array Dataz
    private trigger array Triggerz
    private timer array Timerz
    
    // recycling
    private integer array Indexz
    private integer N = PRELOAD
endglobals


//==============================================================================
private function H2I takes handle h returns integer
    return h
    return 0
endfunction

//==============================================================================
// note how colliding timer handles are discarded
// so ABCT would work properly even after preload limit break
//==============================================================================
private function NewIndex takes nothing returns integer
    local integer i
    local timer t
    if (N==0) then  
    loop
        call BJDebugMsg(&quot;WARNING: ABCT reached preloaded timer limit!&quot;)
        set t = CreateTimer()
        set i = H2I(t)
        set i = i - (i / HASH) * HASH // dummy modulo hash
        if Timerz<i> == null then
            set Timerz<i> = t
            set Triggerz<i> = CreateTrigger()
            return i
        endif
	endloop
    endif  
    set N = N - 1 
    return Indexz[N]
endfunction

//==============================================================================
//  This is where userFunctions actually get called.
//==============================================================================
private function Periodic takes nothing returns nothing
    local integer i = H2I(GetExpiredTimer())
    set i = i - (i / HASH) * HASH // dummy modulo hash
    set bj_data = Dataz<i>
    if TriggerEvaluate(Triggerz<i>) then
        // recycle the trigger and timer
        call TriggerClearConditions(Triggerz<i>)
        call PauseTimer(Timerz<i>)
        set Indexz[N] = i
        set N = N + 1
    endif
endfunction

//==============================================================================
//  Blizzard should have made a native like this.
//==============================================================================
public function Start takes code userFunc, integer data, real period returns nothing
    local integer i
    debug if userFunc == null then
    debug     call BJDebugMsg(&quot;ERROR: ABCT_Start - null userFunc&quot;)
    debug     return
    debug endif
    set i = NewIndex()
    call TriggerAddCondition(Triggerz<i>, Condition(userFunc))
    set Dataz<i> = data
    call TimerStart(Timerz<i>, period, true, function Periodic)
endfunction

//==============================================================================
//  Used in places where TriggerSleepAction(0.0) does not work.
//==============================================================================
public function Zero takes code userFunc, integer data returns nothing
    local integer i
    debug if userFunc == null then
    debug     call BJDebugMsg(&quot;ERROR: ABCT_Zero - null userFunc&quot;)
    debug     return
    debug endif
    set i = NewIndex()
    call TriggerAddCondition(Triggerz<i>, Condition(userFunc))
    set Dataz<i> = data
    call TimerStart(Timerz<i>, 0.0, false, function Periodic)
endfunction

//==============================================================================
//  Use this only inside your userFunc.
//==============================================================================
public function GetData takes nothing returns integer
    return bj_data
endfunction

//==============================================================================
//  Smart Preloading. (avoids hash collision)
//==============================================================================
private function Init takes nothing returns nothing
    local integer i
    local timer t
    local integer j = 0
    loop
        exitwhen j&gt;=PRELOAD
        set t = CreateTimer()
        set i = H2I(t)
        set i = i - (i / HASH) * HASH // dummy modulo hash        
        if Timerz<i> == null then
            set Timerz<i> = t
            set Triggerz<i> = CreateTrigger()
            set Indexz[j] = i
            set j = j + 1
        endif        
    endloop
endfunction

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


This was once an extension library for ABC but now it is a standalone system.
It combines the algorithmic speed and power of ABC with ease of use of TT.

ABCT and TT are complementary systems.
 

Attachments

  • ABCT_v3.0.w3x
    39.8 KB · Views: 308

Cohadar

master of fugue
Reaction score
209
Ok so I don't need to use TT anymore?

Ah damn it creates billions of timers.

No you got it wrong, let me explain this a little:

JASS:
    TT_Start(userFunc, struct)
    TT_GetData() -&gt; struct

    ABCT_Start(userFunc, struct, period)
    ABCT_GetData() -&gt; struct


As you can see ABCT has one more parameter - the period of timer.
So yes theoretically ABCT is a superset of TT,
but TT is more efficient for high-frequency timers (0.04 and similar)

So for slide and jump spells TT is better,
for DOT spells (damage every second) ABCT is better.

In practice you can use ABCT for everything
(it is optimized enough for all purposes)
and only replace it with TT when you really really need speed improvement somewhere.

Generally TT_Start(userFunc, struct) is faster than ABCT_Start(userFunc, struct, 0.04)

Read headers of both systems for further info.
 

GoGo-Boy

You can change this now in User CP
Reaction score
40
So in general you could take every periodic speed you want with ABCT but when it gets equal or below 0,04 seconds, the TT stuff provides better optimization?
 

Cohadar

master of fugue
Reaction score
209
No it isn't.
But if you have say 30 timers (that do some heavy spells) using ABCT at 0.04 at the same time it will start to lag.

If you convert it to TT it will not.
 

emjlr3

Change can be a good thing
Reaction score
395
i really dont know how this systems works, per say

does this use 1 timer/interval? or 1 timer/instance?

I know that keytimers I believe uses 1 timer/interval

I thought that was pretty neat

its like TT but with dynamically declared speeds
 

Cohadar

master of fugue
Reaction score
209
TT use one timer for all, ABCT uses multiple timers.

Keytimers system has a flawed trigger attaching mechanism.
It will work for one or two spells but if you try to make a map with it - it fails.

It is not possible to make "efficient" system that will both:
1. work with different periods
2. use only one timer.

People like me and Vexorian and countless others have been trying to do that for quite some time now...

ABCT and TT are products of that conflict between conditions 1 and 2.

ABCT works with different periods but uses multiple timers,
TT uses one timer but has a fixed period.

So the final solution is - use them both in their appropriate areas.

If you are lazy use ABCT for everything, it is good enough for most spells,
and converting it to TT if comes a need for that is a piece of cake.
 

emjlr3

Change can be a good thing
Reaction score
395
perhaps u misunderstand me

say u have a spell to run at .04, and then want another at .04
does this create two timers, or use the 1 timer for both the spells?

obviously if u got a spell at .03 and 1 at .04, they will not use the same timer, that is not what i meant

I still seem to be confused
 

0zaru

Learning vJASS ;)
Reaction score
60
If you are using TT then It's always the same timer. If you use ABCT then it creates two timers.
 

Cohadar

master of fugue
Reaction score
209
say u have a spell to run at .04, and then want another at .04
does this create two timers, or use the 1 timer for both the spells?

ABCT_Start(function A, data, 0.04)
ABCT_Start(function B, data, 0.04)

Creates 2 timers

EDIT:
For 95% of timed spells it is much better to use TT, in fact I would always prefer TT over ABCT if possible.
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
Sweet, you made it independant to ABC. However, is it faster than ABC?
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
I just can't understand when is ABCT_Zero(userFunc, struct) used? It has no wait interval. Is it used in the function that uses ABCT_GetData()?
 

Cohadar

master of fugue
Reaction score
209
ummmm, how to explain this....

One example where you would use ABCT_Zero is for shield spells.
Imagine you are making a custom mana shield.

So you register onDamage event on hero and when hero gets hit for 100 damage, you heal him for 100 and than substract the 100 from mana.
Sounds simple so far.

Now imagine hero has 1000 hp, 1000 mana and he gets hit for 1900 damage.
So your hero with 1000 hp gets hit for 1900 and then you heal him for 1900 ?...
Not good is it, shield is not good, you will die before it saves you...

So to avoid this situation mappers do something called a damage fix
In onDamage event (just before hero with manashield takes damage) you add him ability that gives 10000 hp.

So 10000 + 1000 - 1900 = no problem.
And then after zero seconds (using ABCT_Zero) you remove the 10000 buff.

All this happens instantly so noone will notice that hero suddenly got and lost 10000 life just so the manashield would work ok.

That is how manashield in pyramidal works.
(I had to make a custom one so it does not conflict with other shield spells)

There are other ABCT_Zero uses and they are all equally advanced.
Generally almost all TriggerSleepAction(0.0) cases.
 

Cohadar

master of fugue
Reaction score
209
They have the same speed and ABCT is easier so I guess there is none...
 
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