Snippet Trackable2

Azlier

Old World Ghost
Reaction score
461
I know the basic process, but how to do it is where I'm lost. How do I turn the execution count into the struct? Where does the ClickTrigger come from?

EDIT: Nevermind. I found another way. Update, can now support multiple events on the same trigger (The answer? More H2I!)
 

Azlier

Old World Ghost
Reaction score
461
Well, I do what I understand. It's not like H2I is horribly unstable. Sure, after enough handles, trackables will no longer fit into the array. But these were not meant to be created dynamically. Even if you're paranoid, you can always increase the array size to something ungodly high.
 

Jesus4Lyf

Good Idea™
Reaction score
397
I've worked on a real map that had 10,000 handles at map init. This code would blatantly not work. Besides, there's an alternative...
JASS:
library Trackable2

private keyword Data

globals
    private Data array Trackables
    private Data TriggeringTrackable
endglobals

private struct Data
    trackable array Trackers [12]
    trigger ClickFire
    trigger TrackFire
    trigger OnClick // change to arrays or w/e to support multi-trigs
    trigger OnTrack // change to arrays or w/e to support multi-trigs
    real X
    real Y
    real Z
    real Facing
    string Model
    player ForPlayer = null
endstruct

// Unreliable piece of junk... j/k
//private constant function H2I takes handle h returns integer
//    return h
//    return 0
//endfunction

// The old Key Triggers implementation. <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile    :)" loading="lazy" data-shortname=":)" />
// Fount 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.

function ClickFireCond takes nothing returns boolean
    set TriggeringTrackable=GetTriggerData(GetTriggeringTrigger())
    // The below can be done in a loop to support multi-trigger
    if TriggerEvaluate(TriggeringTrackable.OnClick) then
        call TriggerExecute(TriggeringTrackable.OnClick)
    endif
    return false // Must be false so attached data never changes. Do not use real actions.
endfunction
function TrackFireCond takes nothing returns boolean
    set TriggeringTrackable=GetTriggerData(GetTriggeringTrigger())
    // The below can be done in a loop to support multi-trigger
    if TriggerEvaluate(TriggeringTrackable.OnTrack) then
        call TriggerExecute(TriggeringTrackable.OnTrack)
    endif
    return false // Must be false so attached data never changes. Do not use real actions.
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; // I honestly believe the alternative could desynch, as &quot;&quot; did not exist - Jesus4Lyf
    local destructable platform = CreateDestructableZ(&#039;OTip&#039;,x,y,z,0.00,1,0)
    local integer i = 11
    loop
        exitwhen i &lt; 0
        if GetLocalPlayer() == Player(i) then
            set s = modelPath
        else
            set s = &quot;&quot;
        endif
        set d.Trackers<i> = CreateTrackable(s, x, y, facing)
        //set Trackables[H2I(d.Trackers<i>) - 0x100000] = d
        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
    // Added by Jesus4Lyf
    set d.ClickFire=CreateTrigger()
    set d.TrackFire=CreateTrigger()
    call SetTriggerData(d.ClickFire,d)
    call SetTriggerData(d.TrackFire,d)
    call TriggerAddCondition(d.ClickFire,Condition(function ClickFireCond))
    call TriggerAddCondition(d.TrackFire,Condition(function TrackFireCond))
    set i = 11
    loop
        exitwhen i &lt; 0
        call TriggerRegisterTrackableHitEvent(d.ClickFire, d.Trackers<i>)
        call TriggerRegisterTrackableTrackEvent(d.TrackFire, d.Trackers<i>)
        set i = i - 1
    endloop
    // End addition
    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 = modelPath
    local destructable platform = CreateDestructableZ(&#039;OTip&#039;,x,y,z,0.00,1,0)
    if GetLocalPlayer() != forPlayer then
        set s = &quot;&quot;
    endif
    set d.Trackers[1] = CreateTrackable(s, x, y, facing)
    //set Trackables[H2I(d.Trackers[1]) - 0x100000] = d
    set d.ForPlayer = forPlayer
    set d.X = x
    set d.Y = y
    set d.Z = z
    set d.Facing = facing
    set d.Model = modelPath
    // Added by Jesus4Lyf
    set d.ClickFire=CreateTrigger()
    set d.TrackFire=CreateTrigger()
    call SetTriggerData(d.ClickFire,d)
    call SetTriggerData(d.TrackFire,d)
    call TriggerAddCondition(d.ClickFire,Condition(function ClickFireCond))
    call TriggerAddCondition(d.TrackFire,Condition(function TrackFireCond))
    call TriggerRegisterTrackableHitEvent(d.ClickFire, d.Trackers[1])
    call TriggerRegisterTrackableTrackEvent(d.TrackFire, d.Trackers[1])
    // End addition
    call RemoveDestructable(platform)
    set platform = null
    return d
endfunction

function TriggerRegisterTrackable2HitEvent takes trigger whichTrigger, Data d returns nothing
    set d.OnClick=whichTrigger
endfunction

function TriggerRegisterTrackable2TrackEvent takes trigger whichTrigger, Data d returns nothing
    set d.OnTrack=whichTrigger
endfunction

// Noooiez. H2I is naughty like that. Unstable! <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite7" alt=":p" title="Stick Out Tongue    :p" loading="lazy" data-shortname=":p" />
//function GetTriggeringTrackable2 takes nothing returns Data
//    return Trackables[H2I(GetTriggeringTrackable()) - 0x100000]
//endfunction

function GetTrackedPlayer takes Data d returns player
    local integer i
    local trackable t
    if d.ForPlayer == null then
        set i = 11
        set t = GetTriggeringTrackable()
        loop
            exitwhen i &lt; 0
            if t == d.Trackers<i> then
                set t = null
                return Player(i)
            endif
            set i = i - 1
        endloop
    else
        return d.ForPlayer
    endif
    return null
endfunction
        

//! textmacro Trackable2_Macro takes NAME, TYPE
function GetTrackable2$NAME$ takes nothing returns $TYPE$
    return TriggeringTrackable.$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;)
//! runtextmacro Trackable2_Macro (&quot;ForPlayer&quot;, &quot;player&quot;)

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


That's your head start. Oh, this breaks your get tracking player thing. You can fix this by creating one trigger for each player in a wrapper struct, then have the current data in a substruct.

You'll figure it out. Go have some fun. :D
And master the TriggerExecCount princible. :cool:
While TriggerExecCount needs the author to be very cautious to work, it's great when encapsulated in a library like this, because the end user doesn't care what's in it, as long as it works. This will make your code much more stable. :D

PS. The code needs a lot of cleanup work and such, such as some of the funcs arent even private. But that's not my job. :p
 

Azlier

Old World Ghost
Reaction score
461
Bah, it's just too complicated for what is meant to be an interface for what is already possible.

Are you really sure that you should create a trigger at creation instead of event registry? Seems like a waste of a trigger.

I'll try to throw something together. If all fails, I fall back on H2I. Possibly put in a MIN_HANDLE_ID constant in case your map has far too many preplaced handles.

EDIT: Nevermind. I can't figure out how to make it work for a single trigger using your deranged method.
 

Jesus4Lyf

Good Idea™
Reaction score
397
>Are you really sure that you should create a trigger at creation instead of event registry? Seems like a waste of a trigger.

Why would you ever create a trackable without any events attached (I can actually think of only one reason; click blocking)? Besides, you can indeed create the trigger later if you like.

Sorry if you think I'm being overzealous, but this issue really means something to me. I believe nothing in WC3 needs to use H2I, and hence everything can be more stable (and often faster). Trackables, in my mind, struck me as the one thing that you couldn't get down to O(1) complexity without H2I. I thought of a way to get around that, and hence had to post that.

I have actually written two maps with trackables before, years ago. I used your methods, exactly (you probably saw the same tutorial on it). So I'm quite familiar with all the issues involved. No offense, but I personally would never use this while it still contains H2I or O(n) complexity (for loading data), knowing that it can be better. Other people have lesser requirements than me, however. So carry on... :D

PS. Going on your last edit time (6 minutes after original post), it seems you gave up after 6 minutes. That diagram took 15 minutes, and that code took 25. =/ But it's your snippet, not mine. :)
 

Viikuna

No Marlo no game.
Reaction score
265
Are you talking about H2I or I2H?

IMO H2I is maybe the coolest single function wc3 modders have ever invented.

edit. Actually, have you done any testing about the speed of I2H ? Since, I2Trackable is safe, it could be the fastest way to get attached data from trackable.

edit2. And you can always calculate your ID_OFFSET before creating trackables, instead of using 0x100000 as an ID_OFFSET.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Excuse the off topic.

>IMO H2I is maybe the coolest single function wc3 modders have ever invented

IMO, H2I is fast food. It hits the spot, it's quick to implement, and it's unhealthy in the long run.

I earnestly believe that H2I is practically never necessary, and hence I don't use it, nor use anything that uses it. But most mappers are OK with it. :)

As for I2H, that's just ridiculous. An array call can handle that for you. And if not, an array call with hashing can. But I never need this either because I have no H2I in the first place.

Viikuna's edit --> I wouldn't even consider speed (within reason) in a system like this. As long as it's O(1) complexity to run, it's fine. But you may notice my code doesn't even attach to trackables. That's why it's clever. The reality is that after creating the trackable, you can drop it from memory completely and store no references to it, which is what I strongly suggest doing.

Furthermore, "Since, I2Trackable is safe, it could be the fastest way to get attached data from trackable" doesn't make sense as all it can do is get the trackable. Not data from it.
 

Viikuna

No Marlo no game.
Reaction score
265
It depends how you use H2I.

Actually, I just realized that the only place where I use H2I in my map, is TimerStack. This is the fastest method, faster than hashing, and has only one downside: limited amount of timers. Luckily this is not a problem, because limit is till big enough for my needs.

I might also need Table too for something. Even if it is slow, it has no other downsides, so it works perfectly in situations where you dont need speed.

Furthermore, "Since, I2Trackable is safe, it could be the fastest way to get attached data from trackable" doesn't make sense as all it can do is get the trackable. Not data from it.
Makes sense. I dont know what Im writing anymore.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Yeah. Refer to KT2 as you know for no H2I timers (not that you're interested in that), and Table is why I said -nearly- no reason for H2I ever. Sometimes you need to attach wierd stuff. And Table is slow but reliable (I assume). No limits.

Let's leave the off-topic there. :thup:

PS.
>Bah, it's just too complicated for what is meant to be an interface for what is already possible.

When it comes to code, things usually grow. ;)
 

Azlier

Old World Ghost
Reaction score
461
I still don't understand the trigger method, but I will look into Table. Seems to be good for those who don't want to just adjust the MIN_HANDLE_ID :p.
 

Azlier

Old World Ghost
Reaction score
461
I can think of a way to do it, but it limits the amount of events to one trigger. I can't have that. Usability over speed, always.

EDIT: Wait, no! The entire reason I did this was to avoid lots of gamecache. Besides, I can't get Table with WC3C down. Increasing MIN_HANDLE_ID and/or extending the Trackables array some works just fine.

H2I is not unstable! Now I2H, that's a problem.

Besides, I need to attach data to strings in my map. I can't find a way to do that without H2I or an O(n) search. In fact, the only O(n) search in Trackable2 is through a stack of 12 trackables to find which one was triggered.
 

Azlier

Old World Ghost
Reaction score
461
Ability data. I need to tie the name to a raw code. Use it to add an ability from a string to a unit in an RP map. I don't see any other method.
 

Azlier

Old World Ghost
Reaction score
461
Why use gamecache when H2I works perfectly? Yes, this question may drive you insane.
 

Jesus4Lyf

Good Idea™
Reaction score
397
... You are so confused! XD

You generally DO use H2I to use gamecache. I don't use either. BUT for people who do, I have a better idea! So pleaseeeee post Table here for a sec so I can grab it and make it way better, but use the same interface so you can replace it completely, directly. I'm really excited.

>Ability data. I need to tie the name to a raw code. Use it to add an ability from a string to a unit in an RP map. I don't see any other method.

You yourself just stated a reason for gamecache, without H2I.

Seriously, you need to understand this. This will implement right over gamecache without the efficiency loss. Sounds stupid, but IT'S ME. I break things properly! :D

EDIT: Nvm, got it.
 

Azlier

Old World Ghost
Reaction score
461
The real reason for game cache is because there is no array limit, isn't it like that? I don't see how you can replace that without hax, <censored>, and bribes.

Let me restate my last post. Ahem
Why use game cache when I can use H2I alone without flaw?
 
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