I had this idea about a system

Viikuna

No Marlo no game.
Reaction score
265
Tomorrow when I woke up I had this idea bout creating a StaticTimerLoop system which would work a lil bit like Cohadars TT.

I wrote this and I would like to hear some comments and get help for finding bugs etc.

Post something now.

edit. I edited those codes a little.

edit. Added delete method for struct destroying

SystemCode:
JASS:
library StaticTimerLoop

globals
//=============================================================================
   // This is the frequency of our timer:
   public constant real PERIOD = 0.03
      
//      This is Static Timer Loop system.     
//      It is used to execute some actions every PERIOD seconds.
//      You might find this usefull for stuff like knockbacks and everything      
//      which needs high frequency timers.
//
//      HOW TO USE:
//        
//          This system is actually pretty easy to use.
//          You just need to make your struct extend StaticTimerLoop
//                   
//          Because this system uses interfaces
//          your periodict action must be named: loopAction
//
// You struct must have a method loopAction, which takes nothing returns nothing
//
//          private struct Data extends StaticTimerLoop
// 
//          method loopAction takes nothing returns nothing
//              // some actions
//          endmethod
//          
//          endstruct
//
//        To start your periodict executions you simple use boolean member Loop
//        
//        local Data D=Data.create()  // create your Data first
//
//        set D.Loop=true  // This starts your timer. 
//                   // Now method loopAction is called every PERDIOD seconds
//
//        set D.Loop=false // This stops our timer.
//               // method loopAction is no longer called every PERIOD seconds. 
//
//        To destroy your struct you need to use .delete()
//        Do not use .destroy()
// 
// 
//               
//=============================================================================       
//=============================================================================
//  System code:

    private timer T=CreateTimer()
    public integer Total=0
endglobals

private interface Face
    method loopAction takes nothing returns nothing defaults nothing
endinterface

struct StaticTimerLoop extends Face
    private boolean l=false
    private boolean d=false
    
    private static StaticTimerLoop array STL
    
    private static method TimerLoop takes nothing returns nothing
        local integer i=1
        loop
            exitwhen i>Total
            if .STL<i>.l==false then
                if .STL<i>.d==true then
                   call .STL<i>.destroy()
                endif
                set .STL<i>=.STL[Total]
                set Total=Total-1
            else
                call .STL<i>.loopAction()
            endif
            set i=i+1
        endloop
        if Total==0 then
            call PauseTimer(T)
        endif
    endmethod
    
    method delete takes nothing returns nothing
       if this.l==false then
          call this.destroy()
       else
           set this.d=true
           set this.l=false
       endif
    endmethod
    
    method operator Loop takes nothing returns boolean
        return this.l
    endmethod
    
    method operator Loop= takes boolean b returns nothing
        if b==false then
            set this.l=false
        else
            set this.l=true
            if Total==0 then
                call TimerStart(T,PERIOD,true,function StaticTimerLoop.TimerLoop)
            endif
            set Total=Total+1
            set .STL[Total]=this
        endif
    endmethod
endstruct

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


a small example:
JASS:
scope Test initializer Init

private struct Data extends StaticTimerLoop
    
    integer count=0
    integer endcount=0
    
    string a=&quot;&quot;
    
    method loopAction takes nothing returns nothing
    
        call BJDebugMsg(this.a)

        set this.count=this.count+1
        if this.count==this.endcount then
              call this.delete()
        endif
    endmethod
    
    method onDestroy takes nothing returns nothing
        call BJDebugMsg(&quot;destroyed&quot;)
    endmethod
    
endstruct

private function Action takes nothing returns nothing
    local Data d=Data.create()
    set d.a=&quot;it works&quot;
    set d.endcount=GetRandomInt(75,150)
    set d.Loop=true
endfunction

private function Init takes nothing returns nothing
    local trigger t=CreateTrigger()
    call TriggerRegisterPlayerEventEndCinematic(t,Player(0))
    call TriggerAddAction(t,function Action)
endfunction

endscope
 
Reaction score
91
> need to make your atruct extend StaticTimerLoop
> your periodict action must be named: loopAction
> You struct must have a method loopAction
Seems decent and is a good idea, however there are too much obligations. This system causes you to make methods/actions just to make it work, instead of just using a few provided functions to store/retrieve data. In some cases it would be quite annoying but I guess some users wouldn't mind that.

> set D.Destroy=true
Instead of using set D.Loop=false, why not make .Destroy stop the periodic executions? One line less and more user-friendly.

Btw, I'm not sure if it would be possible but could you make the calls with .execute()? I guess this will make it a lot faster instead of waiting each thread to finish one by one.

If you can simplify it a bit then maybe there would be a good usage of it. :thup:
 

Viikuna

No Marlo no game.
Reaction score
265
I dont think that .execute would make it any faster, since it .execute takes some time too, so it is probably faster without it.

edit. Doesnt Jass run only a one thread at the time?

Destroying a struct is bit of a problem. I would like to have a possibility to stop timer loop by setting Loop=false and then maybe start it again by setting Loop=true, without destroying a struct.

And yea, vJass interfaces can be a lil´ confusing. Most users probably find some simple Set/GetData functions easier to use.

Using structs and methods is not really a problem IMO, because most people use them anyways.
 

Kenny

Back for now.
Reaction score
202
I think this is pretty cool. But i wonder why people havent thought of this before...

It seems similar to something i have seen spell on hiveworkshop use, but this one is a bit easier to understand.

I think the extra work required isnt too much to ask, seeing as Data arrays are fast and safe, unlike timer attaching. Dont quote me on that, i think i just read vex saying it somewhere.

Well good work, once you get it submitted i think try it out on a few spells. + rep.
 
Reaction score
91
> by setting Loop=false
What I meant is that you could provide only .Loop = true and .Destroy = true and remove .Loop = false (which could be set automatically to false when .Destroy is set to true). One line less.

> I dont think that .execute would make it any faster
I guess it would since it is started in a new thread, independant from other calls which means the script won't wait for it to finish. Though the difference wouldn't be big so there isn't really a need to change it. Keep it as it is if you want.

Btw, you can do some benchmarking and see if it's faster than some systems (try both normal calls and .execute()). :p
Some people are really speed freaks...
 

Viikuna

No Marlo no game.
Reaction score
265
I like to use Static Timer Loop for my spells and thingies, so if those interfaces dont slow this down too much and I can get this code working without bugs, I think Im going to start using this.

Now I just need some Jass pro to tell me why this sucks ( If it does. ( I hope it doesnt. ) )
 
Reaction score
91
Call Vex to review this or post at wc3campaigns.net. There are some skilled admins like Anitarf or Captain Griffen that can tell you if it's worth for this system. Though I think it's really cool, shouldn't bug and if properly used it can be really useful. Plus, it relies more on struct usage and methods which is far more better than normal functions.
 

Viikuna

No Marlo no game.
Reaction score
265
Okay.

Do you guys think that it would look better if I used simple data.start() and data.stop() methods, instead of boolean Loop.

I just like to play with method operators, but I think that .start and .stop methods would be easier to understand.
 
Reaction score
91
> Do you guys think that it would look better if I used simple data.start() and data.stop() methods, instead of boolean Loop.
I agree on this if .stop() gets rid of .Destroy = true/false. :p
 

quraji

zap
Reaction score
144
Haha, I have one of these:

JASS:

library tiddlywidget

    // tiddlywidget (by quraji) - example on interfaces/struct &quot;attaching&quot; to timer:
    //
    // To use, create a struct following the rules of the tiddlywidget interface, then call tiddleAdd(..)
    // -tiddle is the method that is called, so put what you want to be repeated in there
    // -returning false causes the struct to be removed (not destroyed)
    // -setting tiddlePause to true will temporarily pause the struct (not remove or destroy it)
    
    
    globals
        private constant real staticInterval = .03 // set this to the desired timer period
    endglobals
    
    // ==============================================
    
    interface tiddlywidget
        public boolean tiddlePause
        public method tiddle takes nothing returns boolean
    endinterface
    
    globals
        private tiddlywidget array TW
        private integer Top = 0
        private timer Timmy = CreateTimer()
    endglobals

    private function staticTiddle takes nothing returns nothing
        local integer i=0
        local tiddlywidget tw
        
        loop
         exitwhen i == Top
         
           set tw=TW<i>
           
           if tw.tiddlePause then
             set i=i+1
           else
           
             if tw.tiddle() then
               set i=i+1
             else
               set Top=Top-1
               
               if Top==0 then
                 call PauseTimer(Timmy)
                 return
               endif
               
               set TW<i>=TW[Top]
             endif
             
           endif
           
        endloop           
        
    endfunction
    
    public function tiddleAdd takes tiddlywidget tw returns nothing
        set TW[Top]=tw
        set Top = Top+1
        
        if Top == 1 then
            call TimerStart(Timmy, staticInterval, true, function staticTiddle)
        endif
    endfunction
        
endlibrary</i></i>


Mine is a bit simpler if you look, because the cycling method returns a boolean which makes it easy to see if the struct should be detached (it returns false). And you don't need to destroy the struct just because it's done :p

I had a better one that could handle dynamic timer periods, not sure where it went though :rolleyes:

Anyways, if you plan on it being a useful thing you should probably add that (ability to start dynamic period timers).
Also, keep in mind something that I realized after working on this: the timer is not reset while you are adding actions. In other words, if you had a period of 10 seconds, and you added a struct at 6 seconds, your first interval would be 4 seconds, which could screw things up.

Good luck.
 

Viikuna

No Marlo no game.
Reaction score
265
Hey thanks.

That one looks pretty cool. I guess Im gonna experiment with this a bit.

I see now that I dont need my StaticTimerLoop struct. Interface array will do it.

One with dynamic periods would be pretty cool, but I dont really know how it should be done. Only way I can think of right now, is some lame textmacro, which creates different timers for different intervals.

edit. Actually this tiddlywidget is so cool that Im probably going to start using it. ^^

edit2. I made a textmacro version of tiddlwidget for my own use.

//! textmacro StaticTimerLoop takes NAME, INTERVAL

NAME is the name of both the interface and the library and INTERVAL is ofcourse timers interval.
 

quraji

zap
Reaction score
144
>One with dynamic periods would be pretty cool, but I dont really know how it should be done. Only way I can think of right now, is some lame textmacro, which creates different timers for different intervals.

You could simply create new timers for each interval that each have their own loop. Textmacro wouldn't be bad if the user only needed a few different intervals.

>Actually this tiddlywidget is so cool that Im probably going to start using it.

:thup:

>I made a textmacro version of tiddlwidget for my own use.

Can I sees it? :)


Edit: I found the other version with dynamic periods. It's a demo map so you can load it right up and see it in action :p
 
Reaction score
456
JASS:
library StaticTimer
    
    globals
        private timer Timer = CreateTimer()

        private StaticTimer array Array
        private boolean array WantStop
        private integer Counter = 0
    endglobals
    
    private function Handler takes nothing returns nothing
        local integer i = 0
        
        loop
            exitwhen i == Counter
            if WantStop[Array<i>] then
                set Array<i> = Array[Counter - 1]
                set Counter = Counter - 1
                
                set i = i - 1
            else
                if Array<i>.onLoop.exists then
                    call Array<i>.onLoop()
                endif
            endif
            set i = i + 1
        endloop
    endfunction

    private interface EventHandlers
        method onLoop takes nothing returns nothing defaults nothing
    endinterface

    struct StaticTimer extends EventHandlers
        method start takes nothing returns nothing
            set Array[Counter] = this
            set WantStop[this] = false
            set Counter = Counter + 1
            
            if Counter == 1 then
                call TimerStart(Timer, 0.03125, true, function Handler)
            endif
        endmethod
        
        method stop takes nothing returns nothing
            set WantStop[this] = true
        endmethod
    endstruct

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

Being simpler than the previous ones. Method stop sets boolean WantStop to true, and next time it loops, the struct gets removed from the array.

Usage:
JASS:
scope Initialization initializer Init

    struct MyStruct extends StaticTimer //You have to extend
        method onLoop takes nothing returns nothing //&lt;-- This isn&#039;t required method, but it&#039;d be kinda pointless to extend StaticTimer if you&#039;re not going to use it.
            if GetRandomInt(1, 10) &lt;= 2 then
                call .destroy()
            endif
        endmethod
        
        method onDestroy takes nothing returns nothing
            call .stop() // &lt;-- Method of StaticTimer
        endmethod
    endstruct

    private function Init takes nothing returns nothing
        local MyStruct obj1 = MyStruct.create()
        local MyStruct obj2 = MyStruct.create()
        
        call obj1.start() // &lt;-- Method of StaticTimer
        call obj2.start() // &lt;--
    endfunction

endscope


...

However, I am not very sure how useful this kind of code is :p...

EDIT:// And of course, I just tested this once. But by looking at the code, it should work fine.
 

Viikuna

No Marlo no game.
Reaction score
265
My textmacro experiement was just a tiddlywidget edited so that everything else expect interface was moved inside a textmacro.

It worked fine, but its a pretty ugly solution. I think I could improve it, but that might need some gamecache usage and Im not sure at all if it is worth of it. Afterall systems like TimerUtils are pretty much everything I need.

Anyways, Thanks for that Cycle thing, Im gonna go and study it a little now.
It looks interesting.

edit. I have found this map most interesting and Im sure it will teach me a lot. This Cycle system is pretty cool stuff. Gotta study this further.

edit. I guess that system like tiddlywidget could be usefull for some cases, but since timer attaching is so easy by just using some system which just converts handle id to array index, I dont really find this worth of developing.

Anyways, if I need a 0.03 timer, tiddlywidget is a good choise. Its pretty easy to use and everything.
 

quraji

zap
Reaction score
144
>I guess that system like tiddlywidget could be usefull for some cases, but since timer attaching is so easy by just using some system which just converts handle id to array index, I dont really find this worth of developing.

Right on. It's an interesting thing to explore but not worth it in the long run to dwell on.

>Anyways, if I need a 0.03 timer, tiddlywidget is a good choise. Its pretty easy to use and everything.

Yeah, with a relatively small code it can simplify your own coding by a lot if you're using that period often.
 

Sooda

Diversity enchants
Reaction score
318
> Only way I can think of right now, is some lame textmacro, which creates different timers for different intervals.

No need to create many timers. Use time elapsed array to keep time, when timer expires add time to it. When something needs to happen set elapsed time array to zero and repeat process. If struct needs to wait less than current timeout, pause timer and tweak timeout. All professionally done triggered abilities use same concept. Otherwise seems nice.
 

Trollvottel

never aging title
Reaction score
262
have you tested hitting the op-limit? i dont see the code making new threads in the loop.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      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