System Periodic Module

Jesus4Lyf

Good Idea™
Reaction score
397
A standard timer loop module. Written by Cohadar and myself.

Here's a well optimised and standardised timer loop module.

JASS:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Periodic Module ~~ By Jesus4Lyf & Cohadar ~~ Version 1.01 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  What is Periodic Module?
//         - Periodic Module is a module that implements a fully optimised timer
//           loop for a struct.
//         - Instances can be added to the loop, which will call .periodic every
//           PERIOD until it returns true.
//
//    =Pros=
//         - Efficient.
//         - Standardised.
//
//    =Cons=
//         - Only allows one period and periodic function per struct type.
//         - Inaccurate for higher periods.
//         - The called method must be named ".periodic".
//
//    Methods:
//         - struct.startPeriodic()
//         - structtype.setPeriod(real period)
//           Only call setPeriod on initialisation.
//
//         - private method periodic takes nothing returns boolean
//
//           This must be defined in structs that implement Periodic Module.
//           It will be executed by the module every PERIOD until it returns true.
//
//  Details:
//         - Uses one timer per struct type that iterates through all "started" instances.
//
//         - While .periodic() returns false the timer will continue to call it each period
//           Once .periodic() returns true the instance will be excluded from iteration.
//
//         - When there are no active instances, the timer for that struct type will
//           pause itself.
//
//  How to import:
//         - Create a trigger named PM.
//         - Convert it to custom text and replace the whole trigger text with this.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library PeriodicModule
module Periodic
    private static timer PM_Timer=CreateTimer()
    private static integer PM_DataMax=0
    private static thistype array PM_Data
    static real PERIOD=0.03125
    
    private static method PM_PeriodicLoop takes nothing returns nothing
        local integer i=.PM_DataMax
        loop
            exitwhen i==0
            if thistype(.PM_Data<i>).periodic() then
                set .PM_Data<i>=.PM_Data[.PM_DataMax]
                set .PM_DataMax=.PM_DataMax-1
            endif
            set i=i-1
        endloop
        if .PM_DataMax==0 then
            call PauseTimer(.PM_Timer)
        endif
    endmethod

    method startPeriodic takes nothing returns nothing
        set .PM_DataMax=.PM_DataMax+1
        set .PM_Data[.PM_DataMax]=this
        if .PM_DataMax==1 then
            call TimerStart(.PM_Timer,.PERIOD,true,function thistype.PM_PeriodicLoop)
        endif
    endmethod
    
    static method setPeriod takes real period returns nothing // Only call on intialisation.
        set .PERIOD=period
    endmethod
endmodule
endlibrary
</i></i>


Demonstration:
JASS:
scope Test initializer Init

//===========================================================================
struct Data
    unit u

    // lowercase
    private method periodic takes nothing returns boolean   // &lt;-------&lt;&lt;
        call SetUnitX(.u, GetUnitX(.u) + 100.0* this.PERIOD )
        if ( GetUnitX(.u) &gt;= 5000) then
            call this.destroy()
            return true
        endif

     return false
    endmethod

    implement Periodic // &lt;-------&lt;&lt;

    static method create takes unit u returns Data
        local Data data= Data.allocate()
        set data.u = u
        call data.startPeriodic()  // &lt;-------&lt;&lt;
        return data
    endmethod

endstruct

//===========================================================================
private function Init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( trig, Condition( function Conditions ) )
    call TriggerAddAction( trig, function Actions )
    
    // optional
    call Data.setPeriod(0.04)  // &lt;-------&lt;&lt;
endfunction

endscope
 

emjlr3

Change can be a good thing
Reaction score
395
isnt that just TT?

spoilers work as intended
 

Cohadar

master of fugue
Reaction score
209
Yo. Having trouble making modules compile. At all. This actually compiles on the previous version of jasshelper if you make a struct named "thistype" and copy the contents of this in. Doesn't seem to compile on the latest version at the time of this post, however.
Yo. Try not to use unstable jasshelper versions to write code, 90% of people don't update it until new NewGen is out.

I'm trying to throw together some kind of standard module for timer loops before someone makes a mess of it instead.
From this day on you will be known as Jesus4Lyf the Savior.
 

Jesus4Lyf

Good Idea™
Reaction score
397
>Yo. Try not to use unstable jasshelper versions to write code, 90% of people don't update it until new NewGen is out.
Like myself. I saw your posts on the wc3c jasshelper thread, Cohadar. And I agree. I don't see the point in modules. KT1 acomplished this fine with a textmacro. Compared to KT2, the speed gain in this is worthless, the interface is terrible and the coding is a hack job. But if I don't do it, I can bet you someone else can do it worse and run around going "IT'S FAST LOL".

>are you sure you got JH 09G0 installed?
Yes.

>isnt that just TT?
Pretty close. It's actually modified from the KT1 textmacro though, which came before TT. But Cohadar helped heaps in KT1 anyway.
 

Viikuna

No Marlo no game.
Reaction score
265
Vexorian just posted a timer member module here

And I already wrote my own too :D

These modules might turn out to be someting really cool. I cant wait to see what kind of plans Vexorian has for them.

edit. shee-it. Theres already 3 modules submitted in wc3c. That Linked List module could be really useful actually.
 

Viikuna

No Marlo no game.
Reaction score
265
Im not fan of it either, thats why I made my own.

edit. Still working with ti, but it will be soemthing like this:

JASS:
module TimerMember    
    
    public static real TIMEOUT = .025
    
    // You must have this method in your struct:
    
    // method timerAction takes nothing returns boolean
    
    private static timer timer=CreateTimer()
    private static thistype array array
    private static integer Total=0
    
    private static method periodic takes nothing returns nothing
        local integer i=0
        loop
            exitwhen i&gt;=.Total
            if .array<i>.timerAction() then
                set .Total=.Total-1
                if .Total&gt;0 then
                    set .array<i>=.array[.Total]
                    set i=i-1
                else
                    call PauseTimer(.timer)
                endif
            endif
            set i=i+1
        endloop
    endmethod
    
    
    method timerStart takes nothing returns nothing
         if .Total==0 then
             call TimerStart(.timer,TIMEOUT,true,function thistype.periodic)
         endif
         set .array[.Total]=this
         set .Total=.Total+1
    endmethod

    static method setPeriod takes real period returns nothing
        set .TIMEOUT=period
    endmethod
    
endmodule</i></i>
 

Cohadar

master of fugue
Reaction score
209
Implementation of this is great (much better than Vexorians) but the interface is crap.
Key Timers is a name that has no logical association with the subject so:
JASS:

module Periodic // Implement a periodic method that returns true on release.
    private static timer KT_Timer=CreateTimer()
    private static integer KT_DataMax=0
    private static thistype array KT_Data
    private static thistype KT_Current
    static real PERIOD=0.03125  // period should be public DOH
    
    private static method KeyTimerLoop takes nothing returns nothing
        local integer i=.KT_DataMax
        loop
            exitwhen i==0
            if thistype(.KT_Data<i>).timerAction() then
                set .KT_Data<i>=.KT_Data[.KT_DataMax]
                set .KT_DataMax=.KT_DataMax-1
            endif
            set i=i-1
        endloop
        if .KT_DataMax==0 then
            call PauseTimer(.KT_Timer)
        endif
    endmethod

    method startPeriodic takes nothing returns nothing
        set .KT_DataMax=.KT_DataMax+1
        set .KT_Data[.KT_DataMax]=this
        if .KT_DataMax==1 then
            call TimerStart(.KT_Timer,.KT_Period,true,function thistype.KeyTimerLoop)
        endif
    endmethod
    
    static method setPeriod takes real period returns nothing // Only call on intialisation.
        set .KT_Period=period
    endmethod
endmodule
</i></i>


and you use it like this:
JASS:

scope Test initializer Init

//===========================================================================
struct Data
    unit u

    // lowercase
    private method periodic takes nothing returns boolean   // &lt;-------&lt;&lt;
        call SetUnitX(u, GetUnitX(u) + 100.0* Periodic_PERIOD )
        if ( GetUnitX(u) &gt;= 5000) then
            call this.destroy()
            return true
        endif

     return false
    endmethod

    implement Periodic // &lt;-------&lt;&lt;

    static method create takes unit u returns Data
        local Data data= Data.allocate()
        set data.u = u
        call data.startPeriodic()  // &lt;-------&lt;&lt;
        return data
    endmethod

endstruct

//===========================================================================
private function Init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( trig, Condition( function Conditions ) )
    call TriggerAddAction( trig, function Actions )
    
    // optional
    call Data.setPeriod(0.04)  // &lt;-------&lt;&lt;
endfunction

endscope
 

Jesus4Lyf

Good Idea™
Reaction score
397
I'm happy with that. Let's standardise.

I put your name up because we practically worked on this together, I figure. If you have any objections I'll take it down.

Can this thread be moved to Systems, please?

PS. Now KT is just used as a prefix for encapsulation and to avoid issues with other modules. We can change this if we like.
 

Tom Jones

N/A
Reaction score
437
JASS:
// Implement a method named &quot;periodic&quot; that returns true on release.
// Written by Jesus4Lyf and Cohadar.
Your example does the opposite?

Back on track. I haven't read up on modules, anyway to bypass the naming limitation?
 

Cohadar

master of fugue
Reaction score
209
[/JASS]Your example does the opposite?

It was an edit of vexorians example, fixed.

The main issue here is not the implementation, it is the interface.
Since there is a real danger that this will escalate into a system war with hundreds of versions that are all similar yet all incompatible with each other I propose a standard interface:

JASS:

module Periodic

static real PERIOD = 0.03125

method startPeriodic takes nothing returns nothing

static method setPeriod takes real period returns nothing

// create a method named &quot;periodic&quot; that returns true on release.
private method periodic takes nothing returns boolean

// implement the module after your periodic method
implement Periodic

Whatever you do inside this moodule is entirely up to you.

So I am backing Jesus4Lyf on this one.
 

Viikuna

No Marlo no game.
Reaction score
265
Its actually kinda neat, since I've been using method name periodic for struct stack loops for ages.

Anyways, I still like my own more. Its has nicer variable names.
 

emjlr3

Change can be a good thing
Reaction score
395
one thing I liked about TT is that I could use several functions to seperate my operations

for instance: if my spell is at any given time, dealing periodic damage, moving a projectile in a straight line, and creating novas - i could have a function for each, ot make things easier to read and code

doesn't look possible here

also - I think I would prefer a method where instead of one global timer to run everything from - if I could have 1 timer/spell, where I can set it speed individually

that might actually be better IMO
 

Viikuna

No Marlo no game.
Reaction score
265
also - I think I would prefer a method where instead of one global timer to run everything from - if I could have 1 timer/spell, where I can set it speed individually

This is 1 timer per struct type, and you can change period, for example, in onInit method.
 

Jesus4Lyf

Good Idea™
Reaction score
397
The period changing should ONLY be done on init, so that different structs can have different periods. That's all.

>doesn't look possible here
This is a rather limiting method. It just has some speed bonuses. :)

>instead of one global timer
This uses one timer per struct type.

>that might actually be better IMO
If you're saying one timer per instance, isn't that what timer systems are for? Don't need modules...
 
General chit-chat
Help Users

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top