System Timer32

Jesus4Lyf

Good Idea™
Reaction score
397
(Using an older patch is not a good idea)
>This will only work with version 1.24.0.6366 which is the latest beta at the time of writing (connect to Westfall to grab it).

? (I have 1.24.6372 and don't believe that patch is accessible anymore.)

I benchmarked this on 1.21b. It uses no H2I stuff, its all basic JASS function calls. I used the stopwatch natives for 1.21b.

Why don't you benchmark it? Reading the code should show you it is fast.
 

Tom Jones

N/A
Reaction score
437
>This will only work with version 1.24.0.6366 which is the latest beta at the time of writing (connect to Westfall to grab it).

? (I have 1.24.6372 and don't believe that patch is accessible anymore.)

I benchmarked this on 1.21b. It uses no H2I stuff, its all basic JASS function calls. I used the stopwatch natives for 1.21b.

Why don't you benchmark it? Reading the code should show you it is fast.
It's been updated to the latest patch, scroll down to Earth-Fury's post.

I really just wanted to see the principle.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
Why don't you benchmark it? Reading the code should show you it is fast.
I'm not the one who claim how much it is fast, i don't call you a liar, but i think it's obvious when you say something to prove it, it's not to us to prove something.

So post benchmarks again other systems should be fine.
 

Jesus4Lyf

Good Idea™
Reaction score
397
I can't get the 1.24 stopwatch natives working at all. I even tried redownloading newgen and copying in the files and running it straight, and it still went to the Frozen Throne splash screen instead of loading the map.
(Tried inject.exe too, same thing.)

Still trying things, but I can only benchmark on 1.21b until I get this working.

Edit: Yeah, tried on 2 computers.
 

Executor

I see you
Reaction score
57
JASS:
library T32 initializer OnInit
    globals
        public constant real PERIOD=0.03125
        public constant integer FPS=R2I(1/PERIOD)
        
//==============================================================================
        private trigger Trig=CreateTrigger()
    endglobals
    
    module T32
        private thistype next
        
        private static method PeriodicLoop takes nothing returns boolean
            local thistype last = this
            local thistype this=thistype(0).next
            loop
                exitwhen this==0
                if this.periodic() then
                    // This is some real magic.
                    set last.next = this.next
                    // This will even work for the starting element.
                    debug set this.next=0
                endif
                set this=this.next
            endloop
            return false
        endmethod

        method startPeriodic takes nothing returns nothing
            debug if this.next!=0 then
            debug   call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
            debug endif
            set this.next=thistype(0).next
            set thistype(0).next=this
        endmethod
        
        private static method onInit takes nothing returns nothing
            call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
        endmethod
    endmodule
    
    private function OnInit takes nothing returns nothing
        call TriggerRegisterTimerEvent(Trig,PERIOD,true)
    endfunction
endlibrary


What about this solution?

I didn't test it, but if it fails I think you can see what I mean.
I don't know whether an array more or less per structtype is essential.
But I don't think this looping will be that much slower and the stopping progress will be even faster.
 

Jesus4Lyf

Good Idea™
Reaction score
397
I respect you as a mapper who knows his stuff (lol, saying that 'bout someone with 12 posts - hope to see you 'round more), but that will indeed reduce the looping speed. In one version, as said I removed a single "-1" and it increased the speed by 6%.

In your code you have forgotten to set "last" when you iterate, and there is no "this" to set to to begin with. Should be
JASS:
        private static method PeriodicLoop takes nothing returns boolean
            local thistype last=thistype(0)
            local thistype this=thistype(0).next
            loop
                exitwhen this==0
                if this.periodic() then
                    // This is some real magic.
                    set last.next = this.next
                    // This will even work for the starting element.
                    debug set this.next=0
                else
                    set last=this
                endif
                set this=last.next
            endloop
            return false
        endmethod

The speed diff is a variable set. The current alternative is an integer array per struct. The problem is you're moving the processing from the add/remove part (called once each per startPeriodic) to the looping section (called n times per startPeriodic).

So efficiencywise this is a loss, and RAM wise nobody cares. :p
But thanks for the suggestion (which I'd actually already thought of). :)
 

Executor

I see you
Reaction score
57
Well, this is the point I wasn't sure about whether an array more or less is essential. But yea you're right.
And due to the fact I forgot this line, I couldn't see that there are actually more commands in the main loop..my lapse^^
 

Azlier

Old World Ghost
Reaction score
461
It needs a loop? It loops through all active instances of the T32 struct and fires the periodic method from them. A simple if-then can't do that.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Sad face. You updated to add a constant and some debug messages, but not to make this compatible with a majority of spells/systems that use structs and the onInit method. I wouldn't mind seeing some compatibility here until JassHelper is fixed.
THIS IS AWESOME!

It has been fixed in JassHelper (released a couple of hours ago). See the link for a demo map of AIDS/T32 in action. 17 lines of code for a sick flying units system.
 

Vexorian

Why no custom sig?
Reaction score
187
Isn't it a problem that a trigger evaluate will run for each spell using this module even when there are no active instances for it? Also add the fact it never stops the timer... I mean, imagine 24 spells such in the map, and nobody is casting any of them, this timer will still do 24 TriggerEvaluates each 0.03125 seconds...

Is the performance increase of running only one timer worth this trade-off?

the interface is ok but, how do you destroy the struct? I guess you have to call .deallocate an instant before returning false. In any sane language that would be wrong. I guess it is a good thing that vJass is not sane at all.
 

Jesus4Lyf

Good Idea™
Reaction score
397
>the interface is ok but, how do you destroy the struct? I guess you have to call .deallocate an instant before returning false. In any sane language that would be wrong. I guess it is a good thing that vJass is not sane at all.

All correct. And we have to deal with that to get maps produced ;).
I'm starting to think I may add a stopPeriodic() method also.

>will still do 24 TriggerEvaluates each 0.03125 seconds...
Nay. It is 1 trigger evaluate regardless how many structs you have with the module. All "conditions" are on one trigger - it's much faster than x trigger evaluates, equivalent roughly of that many DoNothing calls instead.

Either way, the way the interface it has allows me to upgrade it to make it add/remove trigger conditions for each instance. I could also provide two modules, one that does this and one that doesn't, you could swap the module without changing your code...

I actually considered that for things like particle emitters, the performance gain on add/remove speed was better than the performance loss for having the timer constantly firing that many conditions.

Thanks for your feedback. :)

Edit:
I've been thinking about this. I think the current design is not as good as it shoudl be. I will be writing a new T32 module (probably called T32X or T32Ex) which will provide [LJASS].startPeriodic()[/LJASS], [LJASS].stopPeriodic[/LJASS], and call a [LJASS].periodic()[/LJASS] method which returns [LJASS]nothing[/LJASS]. This should also sleep up the loop. It will also mean you can remotely stop the periodic effect, for example if a unit was to die or something.

I will keep supporting the T32 module, but will provide an additional module and deprecate the old one. :)

Also, I intend to add a [LJASS]T32_Tick[/LJASS] integer or [LJASS]T32_GetTick()[/LJASS] function. Probably the latter, which should inline into a global call. It doesn't make sense for a hundred different structs to all be counting in their little [LJASS].ticks[/LJASS] array when they could just store when their last tick should be, and compare that to a global that the system increments.
 

Jesus4Lyf

Good Idea™
Reaction score
397
- Version 1.06: Deprecated T32 module, added T32x module with .stopPeriodic instead of return true/false stopping. Added T32xs module, which is similar to T32x but has .stopPeriodic/.startPeriodic safety, meaning these can be called regardless of the state of the struct, and if it is already stopped/started respectively, the call will be ignored.
Exactly as the previous post stated. Version 1.06 is here, T32x. :p
 

quraji

zap
Reaction score
144
I like how you split off and made T32xs just so you could avoid putting a pesky if-statement in T32x that was making T32 so damned slow :p

I like the stopPeriodic...the few times I've used T32 the whole destroy struct then return true thing was annoying.
 

Jesus4Lyf

Good Idea™
Reaction score
397
>I like how you split off and made T32xs just so you could avoid putting a pesky if-statement in T32x that was making T32 so damned slow :p
All of that was correct but the bolded bit: that statement was not in T32. It didn't need protection because it relied on return true. :)

I added T32xs because I was going to add T32xns (no safety) and put safety in T32x. Then I realised people would aspire to always use T32xns probably, and it would look retarded. Better to add T32xs instead. *Shrugs*

>the few times I've used T32 the whole destroy struct then return true thing was annoying.
Yea. That started to annoy me a lot with AIDS/T32 structs. They were suddenly possible and very impractical. And I realised the design didn't make sense. :p
 

quraji

zap
Reaction score
144
>All of that was correct but the bolded bit: that statement was not in T32. It didn't need protection because it relied on return true. :)

Bolded bit was sarcasm :p

To be honest I find it a bit silly to have the two versions. I mean, how much speed could you possibly gain from T32x over T32xs? The burden of efficiency at that point is really on the periodic function.
Oh well...I'll use T32x anyways because I'm confident I won't make the mistake. I guess I just defeated my own argument..

Anyways, thanks again for the much needed stopPeriodic.

Edit: On an unrelated note...there was a thread around here about using other numbers for PlayerColor() or something that gave units funky textures...I can't find it. Help? (I remember you posted in it)
 

Jesus4Lyf

Good Idea™
Reaction score
397
Requested thread.

>To be honest I find it a bit silly to have the two versions.
XD Yea. But it costs nothing to give users the option. The interface is completely the same, meaning no readability difference, and there is no extra code or anything because it is copied in using a module... so... :D
 
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