• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] New Event Lib?

Status
Not open for further replies.
Level 31
Joined
Jul 10, 2007
Messages
6,306
Submitted now at http://www.hiveworkshop.com/forums/submissions-414/snippet-event-186555/

JASS:
library Event
    globals
        private real eventv = 0
        private integer count = 0
        private trigger array trig
    endglobals

    function CreateEvent takes nothing returns integer
        set count = count + 1
        set trig[count] = CreateTrigger()
        return count
    endfunction

    function TriggerRegisterEvent takes trigger t, integer ev returns nothing
        call TriggerRegisterVariableEvent(t, SCOPE_PRIVATE + "eventv", EQUAL, ev)
    endfunction

    function CodeRegisterEvent takes boolexpr c, integer ev returns nothing
        call TriggerAddCondition(trig[ev], c)
    endfunction
    
    function FireEvent takes integer ev returns nothing
        set eventv = 0
        set eventv = ev
        call TriggerEvaluate(trig[ev])
    endfunction
endlibrary

To submit or not to submit?

This needs a bench.
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
That's a sweet idea for variable event with an integer. I always thought it was limited to reals integer is also a real, so why not?

Well, I used to do it via that method... I don't know why I stopped doing it that way.

I'm just unsure of the overhead. Don't variable events run really slow?

Looking at it from a memory and object instantiation standpoint, it's a hell of a lot better than the Event lib at TH >.>. Furthermore, if variable events run faster than a linked list loop, then the Event lib at TH is trash >.<.

It could just turn into this

JASS:
library Event
    globals
        private real eventv = 0
        private integer count = 0
        private trigger array trig
    endglobals

    function CreateEvent takes nothing returns integer
        set count = count + 1
        set trig[count] = CreateTrigger()
        return count
    endfunction

    function TriggerRegisterEvent takes trigger t, integer ev returns nothing
        call TriggerRegisterVariableEvent(t, SCOPE_PREFIX + "eventv", EQUAL, ev)
    endfunction

    function CodeRegisterEvent takes boolexpr c, integer ev returns nothing
        call TriggerAddCondition(trig[ev], c)
    endfunction

    function GetTriggeringEvent takes nothing returns integer
        return eventv
    endfunction

    function FireEvent takes integer ev returns nothing
        local integer prev = eventv
        set eventv = ev
        call TriggerEvaluate(trig[ev])
        set eventv = prev
    endmethod
endlibrary

Not sure if I got the args on TriggerRegisterVariableEvent right as I just wrote that out in this post : P. Too lazy to open WE.

I have the TriggerEvaluate(ev) in there so as to prevent a TriggerExecute, thus making it as light as possible.

This script is super lightweight as well.

Now if someone could open up RtC and benchmark TH's Event as compared to this Event ; P. In the benchmark, comment out the TriggerEvaluate(ev) as that's extra for as lightweight of a system as possible.
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
Updated to have that... I was pretty close though, I shoulda remembered it was a string ;D. Also fixed LIMIT_OP. Still haven't opened WE and going to bed ; P. If you run into syntax errors, you know why : D.

anyways, can someone run some RtC benches real fast to compare it to Event lib at TH with call TriggerEvaluate(trig[ev]) commented out?
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Someone run this code for me since I can't run it.

edit
Just tested by stress testing to see which one lagged first. Event started lagging easily by 1000 registered events. This one started lagging a little tiny bit at around 1200 registered. It is clear which one wins ; P.

JASS:
library Event2
    globals
        private real eventv = 0
        private integer count = 0
        private trigger array trig
    endglobals
    function CreateEvent takes nothing returns integer
        set count = count + 1
        set trig[count] = CreateTrigger()
        return count
    endfunction
    function TriggerRegisterEvent takes trigger t, integer ev returns nothing
        call TriggerRegisterVariableEvent(t, SCOPE_PRIVATE + "eventv", EQUAL, ev)
    endfunction
    function CodeRegisterEvent takes boolexpr c, integer ev returns nothing
        call TriggerAddCondition(trig[ev], c)
    endfunction
    function FireEvent takes integer ev returns nothing
        set eventv = 0
        set eventv = ev
    endfunction
endlibrary
library Event
    private keyword destroyNode
    struct EventReg extends array
        integer data
        method clear takes nothing returns nothing
            set this.data=0
        endmethod
        method destroy takes nothing returns nothing
            call Event(this).destroyNode()
        endmethod
    endstruct
    private module Stack
        static thistype top=0
        static method increment takes nothing returns nothing
            set thistype.top=thistype(thistype.top+1)
        endmethod
        static method decrement takes nothing returns nothing
            set thistype.top=thistype(thistype.top-1)
        endmethod
    endmodule
    private struct EventStack extends array
        implement Stack
        Event current
    endstruct
    struct Event
        private trigger trig
        private thistype next
        private thistype prev
        static method getTriggeringEventReg takes nothing returns EventReg
            return EventStack.top.current
        endmethod
        static method create takes nothing returns Event
            local Event this=Event.allocate()
            set this.next=this
            set this.prev=this
            return this
        endmethod
        private static trigger currentTrigger
        method fire takes nothing returns nothing
            local thistype curr=this.next
            call EventStack.increment()
            loop
                exitwhen curr==this
                set thistype.currentTrigger=curr.trig
                if IsTriggerEnabled(thistype.currentTrigger) then
                    set EventStack.top.current=curr
                    if TriggerEvaluate(thistype.currentTrigger) then
                        call TriggerExecute(thistype.currentTrigger)
                    endif
                else
                    call EnableTrigger(thistype.currentTrigger)
                    if IsTriggerEnabled(thistype.currentTrigger) then
                        call DisableTrigger(thistype.currentTrigger)
                    else
                        set curr.next.prev=curr.prev
                        set curr.prev.next=curr.next
                        call curr.deallocate()
                    endif
                endif
                set curr=curr.next
            endloop
            call EventStack.decrement()
        endmethod
        method register takes trigger t returns EventReg
            local Event new=Event.allocate()
            set new.prev=this.prev
            set this.prev.next=new
            set this.prev=new
            set new.next=this
            set new.trig=t
            call EventReg(new).clear()
            return new
        endmethod
        method destroyNode takes nothing returns nothing // called on EventReg
            set this.prev.next=this.next
            set this.next.prev=this.prev
            call this.deallocate()
        endmethod
        method unregister takes trigger t returns nothing
            local thistype curr=this.next
            loop
                exitwhen curr==this
                if curr.trig==t then
                    set curr.next.prev=curr.prev
                    set curr.prev.next=curr.next
                    call curr.deallocate()
                    return
                endif
                set curr=curr.next
            endloop
        endmethod
        method destroy takes nothing returns nothing
            local thistype curr=this.next
            loop
                call curr.deallocate()
                exitwhen curr==this
                set curr=curr.next
            endloop
        endmethod
        method chainDestroy takes nothing returns nothing
            call this.destroy() // backwards compatability.
        endmethod
    endstruct
endlibrary
library Benchmark initializer OnInit uses Event, Event2
    native StopWatchCreate  takes nothing returns integer
    native StopWatchMark    takes integer stopwatch returns real
    native StopWatchDestroy takes integer stopwatch returns nothing
    globals
        Event e
        integer ev
    endglobals
    private function btest takes nothing returns boolean
        return true
    endfunction
    private function ctest takes nothing returns nothing
    endfunction
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        set e = Event.create()
        set ev = CreateEvent()
        call TriggerRegisterEvent(t, ev)
        call e.register(t)
        call TriggerAddCondition(t, Condition(function btest))
        call TriggerAddAction(t, function ctest)
    endfunction
    globals
    private constant string TITLE_A="Event by Nestharus"
    //! textmacro Benchmark__TestA
        call FireEvent(ev)
    //! endtextmacro
    private constant string TITLE_B="Event by jesus4lyf"
    //! textmacro Benchmark__TestB
        call e.fire()
    //! endtextmacro
    endglobals
    private function TestA1000 takes nothing returns nothing
        local integer i=100 // hence 1,000 execs
        loop
            exitwhen i==0
            set i=i-1
            //! runtextmacro Benchmark__TestA() // 1
            //! runtextmacro Benchmark__TestA() // 2
            //! runtextmacro Benchmark__TestA() // 3
            //! runtextmacro Benchmark__TestA() // 4
            //! runtextmacro Benchmark__TestA() // 5
            //! runtextmacro Benchmark__TestA() // 6
            //! runtextmacro Benchmark__TestA() // 7
            //! runtextmacro Benchmark__TestA() // 8
            //! runtextmacro Benchmark__TestA() // 9
            //! runtextmacro Benchmark__TestA() // 10
        endloop
    endfunction
    private function TestB1000 takes nothing returns nothing
        local integer i=100
        loop
            exitwhen i==0 // hence 1,000 execs
            set i=i-1
            //! runtextmacro Benchmark__TestB() // 1
            //! runtextmacro Benchmark__TestB() // 2
            //! runtextmacro Benchmark__TestB() // 3
            //! runtextmacro Benchmark__TestB() // 4
            //! runtextmacro Benchmark__TestB() // 5
            //! runtextmacro Benchmark__TestB() // 6
            //! runtextmacro Benchmark__TestB() // 7
            //! runtextmacro Benchmark__TestB() // 8
            //! runtextmacro Benchmark__TestB() // 9
            //! runtextmacro Benchmark__TestB() // 10
        endloop
    endfunction
    private function OnEsc takes nothing returns nothing
        local integer sw
        local integer i
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestA1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 1000, R2SW(StopWatchMark(sw), 100, 16))
        call StopWatchDestroy(sw)
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestB1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 1000, R2SW(StopWatchMark(sw), 100, 16))
        call StopWatchDestroy(sw)
    endfunction
    private function OnInit takes nothing returns nothing
        local trigger t=CreateTrigger()
        call TriggerRegisterPlayerEvent(t,Player(0),EVENT_PLAYER_END_CINEMATIC)
        call TriggerAddAction(t,function OnEsc)
        call Init()
    endfunction
endlibrary
 
Last edited:
Idk, the technique is interesting but the CreateEvent and TriggerRegisterEvent's of Event2 are probably slower and the latter creates a handle for each registry. They also lack some of the features. (unregister, I never found a use for it but it is still an interesting feature)

Also, when you were testing the benchmarks, you added an action. Yeah, that is possible, but a lot of the lag tested is coming from TriggerExecute alone. Once the action is removed, the lag will probably decrease significantly, which would probably be a bit more of a realistic test. ;P (unless the coder doesn't know what they are doing, lol)

I'm not saying that this event lib is bad or anything, I'm just saying that I don't know if it warrants a whole new library for negligible speed, yet less features. :(

p.s. How do you retrieve the struct data using Event2? ;P eventv is private.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Data is meant to be passed via the system, not the event ; O.

Most of the time, the instance of a struct has nothing to do with the event itself. GetTriggeringEvent is virtually useless.

Furthermore, regular trigger registration in JASS doesn't allow one to clear out events, and I've never personally had the need to clear out events, heh =P.

Also, the action is run for both stress tests (the trigger returns true), so that doesn't matter too much.

This lib has much less overhead than the one at TH (less variables, less functions, etc).

I just don't see why you need a linked list and etc when TriggerRegisterVariableEvent is way easier to do and better >.<.
 
Status
Not open for further replies.
Top