Snippet Trackable2

Azlier

Old World Ghost
Reaction score
461
So, let me get this straight. SIDH2I is epicly slow, but mass TriggerExecute is really fast? What madness is this?!

The only way to get rid of that O(n) search would be to use another game cache. Or some other mad way. I could very well use another cache. Does anyone see any benefit to that?

Besides, this doesn't need incredible speed. This isn't timer attachment. In fact, the only game cache calls are with making a trackable and getting the triggering trackable.
 

Jesus4Lyf

Good Idea™
Reaction score
397
>So, let me get this straight. SIDH2I is epicly slow, but mass TriggerExecute is really fast? What madness is this?!
Correct, regardless what you mean.
If you mean for setting the trigger struct, then yes becase it only happens on init.
If you mean for firing triggers instead of event, then yes because that's what events do internally anyway, pretty much.

>The only way to get rid of that O(n) search would be to use another game cache.
Ok, I'll write it myself. :)
No gamecache, no H2I, no Table.

Trackables have never been done without H2I attachment before. And it will make this more elegant than just reading the tutorial and writing it yourself.
 

Azlier

Old World Ghost
Reaction score
461
>The only way to get rid of that O(n) search would be to use another game cache.
Ahem, let me rephrase that.

The only way for me to get rid of that O(n) search without bloating code substantially would be to use another game cache.

>Trackables have never been done without H2I attachment before.
Well, that's because there's really no problem with H2I attachment.
 

Jesus4Lyf

Good Idea™
Reaction score
397
If you have no ambition, I'm happy to release it as an alternative to your snippet. The point is you should make your code the best it can be.

Anyway, below is a work in progress in case anyone wants to debug it. It should theoretically work, but it doesn't yet. I'll get back to it some time, but I can't concentrate right now.
JASS:
library Trackable2
    // The old Key Triggers implementation, by Jesus4Lyf. <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile    :)" loading="lazy" data-shortname=":)" />
    // Found on <a href="http://www.thehelper.net/forums/showthread.php?t=78493" class="link link--internal">http://www.thehelper.net/forums/showthread.php?t=78493</a>
    // Suitable only in very controlled circumstances, so it was never approved.
    private function SetTriggerData takes trigger t, integer data returns nothing
        call ResetTrigger(t)
        loop
            exitwhen data==0
            call TriggerExecute(t)
            set data=data-1
        endloop
    endfunction
    private function GetTriggerData takes trigger t returns integer
        return GetTriggerExecCount(t)
    endfunction
    // End Key Triggers implementation.
    private struct TriggerChain
        TriggerChain prev
        TriggerChain next
        trigger trig
        method add takes trigger t returns nothing
            local TriggerChain to=TriggerChain.create()
            set to.trig=t
            // Link
            set this.next=to.next
            set this.next.prev=this
            set to.next=this
            set this.prev=to
        endmethod
        static method createPointer takes nothing returns TriggerChain
            local TriggerChain c=TriggerChain.create()
            set c.next=0
            set c.prev=0
            return c
        endmethod
        method fireFromPointer takes nothing returns nothing
            loop
                set this=this.next
                exitwhen this==0
                if TriggerEvaluate(this.trig) then
                    call TriggerExecute(this.trig)
                endif
            endloop
        endmethod
    endstruct
    private struct Data
        real X
        real Y
        real Z
        real Facing
        string Model
        integer UserData = 0
        TriggerChain onHoverPointer
        TriggerChain onClickPointer
        static method create takes nothing returns Data
            local Data d=Data.allocate()
            set d.onHoverPointer=TriggerChain.createPointer()
            set d.onClickPointer=TriggerChain.createPointer()
            return d
        endmethod
    endstruct
    private struct TriggerData
        Data trackableData
        player forPlayer
    endstruct
    
    globals
        private Data TriggeringTrackable
        private player TriggeringPlayer
        //locals
        private TriggerData triggerdata
    endglobals
    
    function TrackableHover takes nothing returns boolean
        set triggerdata=GetTriggerData(GetTriggeringTrigger())
        set TriggeringTrackable=triggerdata.trackableData
        set TriggeringPlayer=triggerdata.forPlayer
        call TriggeringTrackable.onHoverPointer.fireFromPointer()
        return false // Must return false.
    endfunction
    function TrackableClick takes nothing returns boolean
        set triggerdata=GetTriggerData(GetTriggeringTrigger())
        set TriggeringTrackable=triggerdata.trackableData
        set TriggeringPlayer=triggerdata.forPlayer
        call TriggeringTrackable.onClickPointer.fireFromPointer()
        return false // Must return false.
    endfunction
    
    function RigTrackable takes Data d, player p, trackable track returns nothing
        local trigger trig
        local TriggerData td=TriggerData.create()
        set td.trackableData=d
        set td.forPlayer=p
        // Click
        set trig=CreateTrigger()
        call TriggerAddCondition(trig,Condition(function TrackableClick))
        call SetTriggerData(trig,d)
        call TriggerRegisterTrackableHitEvent(trig,track)
        // Hover
        set trig=CreateTrigger()
        call TriggerAddCondition(trig,Condition(function TrackableHover))
        call SetTriggerData(trig,d)
        call TriggerRegisterTrackableTrackEvent(trig,track)
        set trig=null // Unnecessary. *Shrugs*
    endfunction

    function CreateTrackable2 takes string modelPath, real x, real y, real z, real facing returns Data
        local Data d = Data.create()
        local string s = &quot;&quot;
        local destructable platform = CreateDestructableZ(&#039;OTip&#039;,x,y,z,0.00,1,0)
        local integer i = 11
        loop
            if GetLocalPlayer() == Player(i) then
                set s = modelPath
            else
                set s = &quot;&quot;
            endif
            // No one cares about the stupid trackable.
            // We never store it or attach to it. It&#039;s forgotten.
            call RigTrackable(d,Player(i),CreateTrackable(s, x, y, facing))
            exitwhen i == 0
            set i = i - 1
        endloop
        set d.X = x
        set d.Y = y
        set d.Z = z
        set d.Facing = facing
        set d.Model = modelPath
        call RemoveDestructable(platform)
        set platform = null
        return d
    endfunction

    function CreateTrackable2ForPlayer takes string modelPath, real x, real y, real z, real facing, player forPlayer returns Data
        local Data d = Data.create()
        local string s = &quot;&quot;
        local destructable platform = CreateDestructableZ(&#039;OTip&#039;,x,y,z,0.00,1,0)
        if GetLocalPlayer() == forPlayer then
            set s = modelPath
        endif
        // No one cares about the stupid trackable.
        // We never store it or attach to it. It&#039;s forgotten.
        call RigTrackable(d,forPlayer,CreateTrackable(s, x, y, facing))
        set d.X = x
        set d.Y = y
        set d.Z = z
        set d.Facing = facing
        set d.Model = modelPath
        call RemoveDestructable(platform)
        set platform = null
        return d
    endfunction

    function TriggerRegisterTrackable2HitEvent takes trigger whichTrigger, Data d returns nothing
        call d.onClickPointer.add(whichTrigger)
    endfunction

    function TriggerRegisterTrackable2TrackEvent takes trigger whichTrigger, Data d returns nothing
        call d.onHoverPointer.add(whichTrigger)
    endfunction

    function GetTriggeringTrackable2 takes nothing returns Data
        return TriggeringTrackable
    endfunction

    function GetTrackedPlayer takes nothing returns player
        return TriggeringPlayer
    endfunction

    function SetTrackable2Data takes Data whichTrackable, integer whatData returns nothing
        set whichTrackable.UserData = whatData
    endfunction

    function GetTrackable2Data takes Data whichTrackable returns integer
        return whichTrackable.UserData
    endfunction

    //! textmacro Trackable2_Macro takes NAME, TYPE
    function GetTrackable2$NAME$ takes Data which returns $TYPE$
        return which.$NAME$
    endfunction
    //! endtextmacro

    //! runtextmacro Trackable2_Macro (&quot;X&quot;, &quot;real&quot;)
    //! runtextmacro Trackable2_Macro (&quot;Y&quot;, &quot;real&quot;)
    //! runtextmacro Trackable2_Macro (&quot;Z&quot;, &quot;real&quot;)
    //! runtextmacro Trackable2_Macro (&quot;Facing&quot;, &quot;real&quot;)
    //! runtextmacro Trackable2_Macro (&quot;Model&quot;, &quot;string&quot;)
endlibrary
 

Azlier

Old World Ghost
Reaction score
461
Right. You lost me. Continue with this utter madness.

If it doesn't work, I'll have the witchhunters burn you at the stake. :thup: Like the British did to Joan of Arc. Sounds fun.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Finished. Or rather, it works, I should say, and finished for now. :)

JASS:
library Trackable2
    // The old Key Triggers implementation, by Jesus4Lyf. <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile    :)" loading="lazy" data-shortname=":)" />
    // Found on <a href="http://www.thehelper.net/forums/showthread.php?t=78493" class="link link--internal">http://www.thehelper.net/forums/showthread.php?t=78493</a>
    // Suitable only in very controlled circumstances, so it was never approved.
    private function SetTriggerData takes trigger t, integer data returns nothing
        //call ResetTrigger(t)
        loop
            exitwhen data==0
            call TriggerExecute(t)
            set data=data-1
        endloop
    endfunction
    private function GetTriggerData takes trigger t returns integer
        return GetTriggerExecCount(t)
    endfunction
    // End Key Triggers implementation.
    
    private struct TriggerChain
        TriggerChain prev
        TriggerChain next
        trigger trig
        method add takes trigger t returns nothing
            local TriggerChain added=TriggerChain.create()
            set added.trig=t
            // Link
            set added.next=this.next
            set this.next.prev=added
            set added.prev=this
            set this.next=added
        endmethod
        static method createPointer takes nothing returns TriggerChain
            local TriggerChain c=TriggerChain.create()
            set c.next=0
            set c.prev=0
            return c
        endmethod
        method fireFromPointer takes nothing returns nothing
            loop
                set this=this.next
                exitwhen this==0
                if TriggerEvaluate(this.trig) then
                    call TriggerExecute(this.trig)
                endif
            endloop
        endmethod
    endstruct
    private struct Data
        real X
        real Y
        real Z
        real Facing
        string Model
        integer UserData = 0
        TriggerChain onHoverPointer
        TriggerChain onClickPointer
        static method create takes nothing returns Data
            local Data d=Data.allocate()
            set d.onHoverPointer=TriggerChain.createPointer()
            set d.onClickPointer=TriggerChain.createPointer()
            return d
        endmethod
    endstruct
    private struct TriggerData
        Data trackableData
        player forPlayer
    endstruct
    
    globals
        private Data TriggeringTrackable
        private player TriggeringPlayer
        //locals
        private TriggerData triggerdata
    endglobals
    
    private function TrackableHover takes nothing returns boolean
        set triggerdata=GetTriggerData(GetTriggeringTrigger()) // Get player and trackable.
        set TriggeringTrackable=triggerdata.trackableData
        set TriggeringPlayer=triggerdata.forPlayer
        call TriggeringTrackable.onHoverPointer.fireFromPointer()
        return false // Must return false.
    endfunction
    private function TrackableClick takes nothing returns boolean
        set triggerdata=GetTriggerData(GetTriggeringTrigger()) // Get player and trackable.
        set TriggeringTrackable=triggerdata.trackableData
        set TriggeringPlayer=triggerdata.forPlayer
        call TriggeringTrackable.onClickPointer.fireFromPointer()
        return false // Must return false.
    endfunction
    
    private function RigTrackable takes Data d, player p, trackable track returns nothing
        local trigger trig
        // Contains player and trackable data
        local TriggerData td=TriggerData.create()
        set td.trackableData=d
        set td.forPlayer=p
        // Click
        set trig=CreateTrigger()
        call TriggerAddCondition(trig,Condition(function TrackableClick))
        call SetTriggerData.execute(trig,td) // Attach player and trackable.
        call TriggerRegisterTrackableHitEvent(trig,track)
        // Hover
        set trig=CreateTrigger()
        call TriggerAddCondition(trig,Condition(function TrackableHover))
        call SetTriggerData.execute(trig,td) // Attach player and trackable.
        call TriggerRegisterTrackableTrackEvent(trig,track)
        set trig=null // Unnecessary. *Shrugs*
    endfunction

    function CreateTrackable2 takes string modelPath, real x, real y, real z, real facing returns Data
        local Data d = Data.create()
        local string s = &quot;&quot;
        local destructable platform = CreateDestructableZ(&#039;OTip&#039;,x,y,z,0.00,1,0)
        local integer i = 11
        loop
            if GetLocalPlayer() == Player(i) then
                set s = modelPath
            else
                set s = &quot;&quot;
            endif
            // No one cares about the stupid trackable.
            // We never store it or attach to it. It&#039;s forgotten.
            call RigTrackable(d,Player(i),CreateTrackable(s, x, y, facing))
            exitwhen i == 0
            set i = i - 1
        endloop
        set d.X = x
        set d.Y = y
        set d.Z = z
        set d.Facing = facing
        set d.Model = modelPath
        call RemoveDestructable(platform)
        set platform = null
        return d
    endfunction

    function CreateTrackable2ForPlayer takes string modelPath, real x, real y, real z, real facing, player forPlayer returns Data
        local Data d = Data.create()
        local string s = &quot;&quot;
        local destructable platform = CreateDestructableZ(&#039;OTip&#039;,x,y,z,0.00,1,0)
        if GetLocalPlayer() == forPlayer then
            set s = modelPath
        endif
        // No one cares about the stupid trackable.
        // We never store it or attach to it. It&#039;s forgotten.
        call RigTrackable(d,forPlayer,CreateTrackable(s, x, y, facing))
        set d.X = x
        set d.Y = y
        set d.Z = z
        set d.Facing = facing
        set d.Model = modelPath
        call RemoveDestructable(platform)
        set platform = null
        return d
    endfunction

    function TriggerRegisterTrackable2HitEvent takes trigger whichTrigger, Data d returns nothing
        call d.onClickPointer.add(whichTrigger)
    endfunction

    function TriggerRegisterTrackable2TrackEvent takes trigger whichTrigger, Data d returns nothing
        call d.onHoverPointer.add(whichTrigger)
    endfunction

    function GetTriggeringTrackable2 takes nothing returns Data
        return TriggeringTrackable
    endfunction

    function GetTrackedPlayer takes nothing returns player
        return TriggeringPlayer
    endfunction

    function SetTrackable2Data takes Data whichTrackable, integer whatData returns nothing
        set whichTrackable.UserData = whatData
    endfunction

    function GetTrackable2Data takes Data whichTrackable returns integer
        return whichTrackable.UserData
    endfunction

    //! textmacro Trackable2_Macro takes NAME, TYPE
    function GetTrackable2$NAME$ takes Data which returns $TYPE$
        return which.$NAME$
    endfunction
    //! endtextmacro

    //! runtextmacro Trackable2_Macro (&quot;X&quot;, &quot;real&quot;)
    //! runtextmacro Trackable2_Macro (&quot;Y&quot;, &quot;real&quot;)
    //! runtextmacro Trackable2_Macro (&quot;Z&quot;, &quot;real&quot;)
    //! runtextmacro Trackable2_Macro (&quot;Facing&quot;, &quot;real&quot;)
    //! runtextmacro Trackable2_Macro (&quot;Model&quot;, &quot;string&quot;)
endlibrary
Victory. O(1) complexity trackables without H2I (except for O(n) storage, which should be done on init anyway because they're trackables and can't be made dynamically since they can't be destroyed).

Now THAT I'd use! :D

(Should EGUI this version instead, imo obviously. Lol XD)
 

Sevion

The DIY Ninja
Reaction score
424
JASS:
// No one cares about the stupid trackable.
        // We never store it or attach to it. It&#039;s forgotten.


EGUI does.

And that's precisely why it's in there. Thank you.
 

Azlier

Old World Ghost
Reaction score
461
Hehehe, working on a version to eliminate O(n) and increasing instance limit by 12x. Not using anything of yours, Jesus. Too much like black magic for me.

Got it ready, compiled correctly, just need to test it...
 

Sevion

The DIY Ninja
Reaction score
424
Ha ha, nice avatar. XD

I wanted to keep trackables in play because it'd be easier for GUI users to understand a Trackable rather than a Trackable Data Set.
 

Azlier

Old World Ghost
Reaction score
461
Who said they can't be used as normal trackables? You create, you register, you get information... Just like a normal handle.

Oh, update.
No more O(n) search.
Increased instance limit... sort of.
 

Azlier

Old World Ghost
Reaction score
461
You and your accursed linked lists can burn at the stake... what are linked lists :confused:
 

Kenny

Back for now.
Reaction score
202
@ Jesus4Lyf:

After reading that, i have a new found respect for your 2D Doubly Linked-list hashing table syntax candy. :p

I wish there were tutorials for learning these more advanced methods in VJASS, as i find learning them in general, then trying to re-create them in VJASS a little bit too complicated.

Sorry for off-topicness.
 

Azlier

Old World Ghost
Reaction score
461
Well, Jesus, closed that link real quick 'cause I thought it was a screamer. I hate screamers. And spiders. Spider screamers, thank God they don't exist.

So I wikipedia'd it. Confused me as much as Big O notation, it did.
 

Jesus4Lyf

Good Idea™
Reaction score
397
>After reading that, i have a new found respect for your 2D Doubly Linked-list hashing table syntax candy.
(Spoilered since it's off topic)
:D
All I can say is... YES. That was nasty. And the dimensions were not perpendicular. I was quite proud and amazed that it worked, first shot, without a hitch. ;)

Why 2D for that? Well, because on one hand the notes were added to eachother in a list for flushing an entire table in one call, and on the other hand they had to form parts of a different list for collision resolution in hashing. So when you search, if the hashed index is taken, it adds it to a list on that index... And consider that if it gets destroyed as part of a chain flush thing and it is the top of one of those hashing collision lists, that the rest of the list needs to actually move location to the hashed index so that the list is still related to it, otherwise they'd randomly get lost in rare circumstances... Yeah, that took some doing. After all that, I even made it the same speed as normal gamecache! :D

GTrigger and Key Timers 2 also use linked lists. In Key Timers 2 they're hard coded, no syntax candy. In GTrigger, they're stored in such a way that all attachments share arrays to save some RAM. And in my Trackables work here (and soon to be posted in another thread I imagine), they're used to store multiple triggers attached to one trackable event trigger. Actually, I implemented most of the theory behind GTrigger in my solution here, but in a much simpler way because I haven't bothered with event de-registration.

>I wish there were tutorials for learning these more advanced methods in VJASS
I was actually going to make a "Writing Key Timers 2" tutorial just because of the intense amount of new efficiency ideas it contains in it. I've applied what I learned writing KT2 in so many other systems now. I don't think there's actually anyone who actually understands how KT2 works internally anymore... But I could be wrong.

I could do a linked lists tutorial, but it's actually really easy. Here's how to do a simple singly linked list in vJass.
JASS:
struct ListNode
    ListNode next=0
    integer yourData // Or some other thing you want a list of.
    static method create takes ListNode addToWhichNode returns ListNode
        local ListNode result=ListNode.allocate()
        set addToWhichNode.next=result
        return result
    endmethod
endstruct

You'll notice here that you can't step backwards in the list, only forwards. So if you want to destroy an item half way through a list, the list will break because you can't set the previous node's next pointer (I call it a pointer). The solution is doubly linked lists. You can find examples of them in my code here, KT2, GT, or pretty much half the stuff I write. The simplest for you to understand would be the code I posted here.

>So I wikipedia'd it. Confused me as much as Big O notation, it did.
Can't say I'm suprised... But on that note, I imagine ALL my code will look like black magic to you.

>I thought it was a screamer
It's not. Lol. It's a Google link. And it goes straight to wikipedia anyway after teaching you how to use Google. :p
 

Azlier

Old World Ghost
Reaction score
461
Total rewrite completed. Thanks, Jesus4Lyf.

Backwards compatibility was not lost.
 
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