wc3campaigns
WC3C Homepage - www.wc3c.netUser Control Panel (Requires Log-In)Engage in discussions with other users and join contests in the WC3C forums!Read one of our many tutorials, ranging in difficulty from beginner to advanced!Show off your artistic talents in the WC3C Gallery!Download quality models, textures, spells (vJASS/JASS), systems, and scripts!Download maps that have passed through our rigorous approval process!

Go Back   Wc3C.net > Warcraft III Modding > Developer's Corner > Triggers & Scripts
User Name
Password
Register Rules Get Hosted! Chat Pastebin FAQ and Rules Members List Calendar



Reply
 
Thread Tools Search this Thread
Old 06-25-2011, 10:21 PM   #1
Yrth
User
 
Yrth's Avatar
 
Join Date: Jul 2010
Posts: 76

Yrth has little to show at this moment (4)

Default Several Function Questions

First off: destroying triggers
Hidden information:
I read somewhere that doing so for one shot triggers is great for performance, which makes total sense.
I read somewhere else that destroying triggers has side effects including (but not limited to) opening the gates of hell, syphillis, and death by firing squad
So I was wondering when I should destroy a trigger
For example, i've got a few triggers that serve just to group functions (there isn't actually any trigger to it) so I just have

Collapse JASS:
function Function1 takes nothing returns nothing
endfunction

function Function2 takes nothing returns nothing
endfunction

//etc

//===========================================================================
function InitTrig_FunctionLibrary takes nothing returns nothing
    call DestroyTrigger(gg_trg_FunctionLibrary)
endfunction


in other cases the trigger will actually do something (on map init) following which it destroys itself (suicide style)


Question 2: ihateyou,
Collapse JASS:
TriggerRegisterUnitInRange
Hidden information:
so first off, lol
Collapse JASS:
TriggerRegisterUnitInRangeSimple
switches the order of arguments for the regular function around and just adds null
why on earth did blizzard include this

but second off
this function is a fickle whore
I'm just gonna go through what I've done (mostly stuff that didn't work)
but first a bit of background: I'm trying to make an efficient way to do collision in mazes
what I've tried
Collapse JASS:
function redColEx takes nothing returns nothing
    local trigger redcol = CreateTrigger()
    
    TriggerRegisterUnitInRange(redcol, udg_Mazers[0], 35.00, null)
    //...
endfunction
so this didn't work (syntax error on the register line) and I'm guessing it's because
Collapse JASS:
udg_Mazers[0]
isn't always the same unit, and that function needs a solid static unit rather than a variable unit given by a pointer

So then I tried
Collapse JASS:
function redColEx takes nothing returns nothing
    local trigger redcol = CreateTrigger()
    
    TriggerRegisterUnitInRange(redcol, gg_unit_Edem_0001, 35.00, null)
    //...
endfunction
but that still had a syntax error
so I wasn't sure if it was something weird with it needing to be a global trigger so I tried

Collapse JASS:
globals
    trigger redcol
endglobals

function redColEx takes nothing returns nothing
    set redcol = CreateTrigger()
    
    TriggerRegisterUnitInRange(redcol, gg_unit_Edem_0001, 35.00, null)
    //...
endfunction
but that still didn't work (same error)

then I tried putting it in the on map init trigger and that still didn't work
(this was still using a trigger declared as a global)

finally I tried:
Collapse JASS:
function InitTrig_CollisionRedTest takes nothing returns nothing
    set gg_trg_CollisionRedTest = CreateTrigger(  )
    call TriggerRegisterUnitInRange(gg_trg_CollisionRedTest, gg_unit_Edem_0001, 35.00, null)
    //...
endfunction
just to see if it was completely broken
but it worked just fine (CollisionRedTest is the name of the trigger)
I'm super baffled, like
whaaaaaaaaaaaaaaaaaaaaaat


Question 2b
is there a difference between a trigger you make in the trigger editor and a trigger you declare as a global?

Last question
Why can't you register functions that have arguments to triggers simply
Like instead of doing TriggerAddAction(t, function f(<arguments>))
you have to through a dummy function (which takes nothing) in there which calls f<arguments> and nothing else

so those are my questions
sorry for throwing so much out at once
also I'm going camping so I might not get a chance to respond for ~a week, but still in advanced - many many thank you's
Yrth is offline   Reply With Quote
Sponsored Links - Login to hide this ad!
Old 06-26-2011, 01:05 AM   #2
Captain Griffen
Dread Lord of the Cookies
 
Captain Griffen's Avatar


Content Director
 
Join Date: Sep 2003
Posts: 5,375

Submissions (2)

Captain Griffen is a glorious beacon of light (497)Captain Griffen is a glorious beacon of light (497)Captain Griffen is a glorious beacon of light (497)Captain Griffen is a glorious beacon of light (497)Captain Griffen is a glorious beacon of light (497)

Approved Map: Warlords[Quicksilver #2] - 1st Place

Default

Question 1: Never. The only justification for needing to is damage detection.

Question 2:

Quote:
isn't always the same unit, and that function needs a solid static unit rather than a variable unit given by a pointer

False. You forgot "call" before the line. Also false because it does not pass a pointer to the native. It passes the current value of the variable.

(Qualification: It does pass a pointer, but that's the handle. Different thing.)

Question 2b:

This question makes no sense. You cannot declare a trigger. You declare a global variable, when can then have the value of a trigger (well, of the handle). If you understood the difference between an object and a variable you wouldn't have asked the question, go read up on that.

Last question:

Arguments might be dynamic. Conceptually it makes no sense within the framework of Jass. Say the arguments were local variables. Those locals would be local to a function which is not being run when the event triggers the action. Hence wtf would it be doing?

Non-dynamic arguments would fail for a lot of arguments which were function calls, as the behaviour would be wrong.
__________________
Quote:
Originally Posted by Earth-Fury
Griffen is correct, you are not.
Quote:
[13:32] <Akolyt0r> hmm.. stil i want to have some unused women
Captain Griffen is offline   Reply With Quote
Old 06-26-2011, 11:28 AM   #3
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

Quote:
Originally Posted by Yrth
For example, i've got a few triggers that serve just to group functions (there isn't actually any trigger to it) so I just have

Collapse JASS:
function Function1 takes nothing returns nothing
endfunction

function Function2 takes nothing returns nothing
endfunction

//etc

//===========================================================================
function InitTrig_FunctionLibrary takes nothing returns nothing
    call DestroyTrigger(gg_trg_FunctionLibrary)
endfunction
That is not needed at all. The gg_trg_FunctionLibrary variable does not point to a trigger by default, the trigger must be explicity created. When you create a new GUI trigger and convert it to custom text, you get this:
Collapse JASS:
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
endfunction

//===========================================================================
function InitTrig_Untitled_Trigger_001 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_001 = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions )
endfunction

By deleting the highlighted text, you have already prevented the trigger from being created in the first place, so there is nothing there to destroy.

Quote:
in other cases the trigger will actually do something (on map init) following which it destroys itself (suicide style)
You can do stuff on map init without using a trigger (unless you're using GUI but in that case, why care about leaking single handles like initialization triggers when you're likely leaking a whole lot more elsewhere?). You have the InitTrig_* functions in JASS and scope/library/struct/module initializers in vJass.


Quote:
is there a difference between a trigger you make in the trigger editor and a trigger you declare as a global?
As shown above, triggers that you make in the trigger editor end up being created the same way as you'd create your own triggers in JASS. As Griffen already suggested, you should get a better understanding of variables and handles since you seem to be conflating the two a lot. When you pass a unit variable to a function that takes a unit argument (like the TriggerRegisterUnitInRange example you used), what you are doing is actually passing the current value of that variable (a unit) to the function, not the variable itself (as noted, the function takes a unit, not a unit variable). Instead of a variable, you could have used a function that returns a unit - it doesn't matter, it's the unit itself that ends up being received by the function.

Likewise, having a trigger variable does not mean you also have a trigger. Like any other handle object, a trigger must be created by calling the appropriate function, the variable is just a way to reference the trigger once it's created. You can have multiple variables referencing the same trigger (or unit, or group, or special effect, or any other handle), you can have variables that don't reference anything (variables which haven't been initialized or whose value has been set to null) and you can end up having handles that aren't referenced by any variables, in which case you may have what we call a memory leak since there's no way to destroy handles which you can't reference (the exception here are non-hero units which will remove themselves automatically once they have decayed).

Quote:
Why can't you register functions that have arguments to triggers simply
Like instead of doing TriggerAddAction(t, function f(<arguments>))
you have to through a dummy function (which takes nothing) in there which calls f<arguments> and nothing else
Triggers can not use functions that take arguments as actions. If they could, what would you expect the values passed as those arguments to be? As I already explained, the values that you would give when calling TriggerAddAction like you do in your example could only be constant - if you used a function like GetTriggerUnit() like I'm guessing you'd want to do, the unit that would be used would be the value of that function when the trigger action was added to the trigger, not when the trigger executes.

On the other hand, if you don't want dynamic arguments like that, but just want to attach constant data to a trigger, there are other ways of doing it. Of course, the only reason to do such data attachment is if you're using dynamic triggers which there's really no reason to do (besides damage detection). For example, your maze collision could be done by periodically enumerating units in range of your unit instead of using a unit-in-range trigger. The former approach has been shown to be no less efficient than the latter.
__________________
Anitarf is offline   Reply With Quote
Old 06-30-2011, 12:18 AM   #4
Yrth
User
 
Yrth's Avatar
 
Join Date: Jul 2010
Posts: 76

Yrth has little to show at this moment (4)

Default

Quote:
Never. The only justification for needing to is damage detection.
i was hoping for a bit more of an in depth answer
does it have glitches, negative effects, etc?
is it just considered bad practice to need to use trigger destruction (similar to the views on the break keyword)?
i assume by damage detection you mean like if i were to create a local trigger that kept track of the moment a specific unit died, then after the event/action; i should destroy it

Quote:
False. You forgot "call" before the line. Also false because it does not pass a pointer to the native. It passes the current value of the variable.
hehe woops
i think i made that mistake another time i was stumped
i always forget 1 languages quirks after just having programmed in another

Quote:
Arguments might be dynamic. Conceptually it makes no sense within the framework of Jass. Say the arguments were local variables. Those locals would be local to a function which is not being run when the event triggers the action. Hence wtf would it be doing?

one or both of us is/has misunderstood what the other meant
what i was saying is the function is being passed the vars
exactly what the function is being passed (for my purpose) would be completely static after compile time.
perhaps what the pointers are pointing to might change, but it'd always use the same pointers
its not by any means necessary
but it'd save time and make sense

Quote:
By deleting the highlighted text, you have already prevented the trigger from being created in the first place, so there is nothing there to destroy.
oh cool, ty that answers a lot of questions
if i wanted to get rid of the trigger handle floating around, would i have to use a vjass library/scope/module?

Quote:
For example, your maze collision could be done by periodically enumerating units in range of your unit instead of using a unit-in-range trigger. The former approach has been shown to be no less efficient than the latter.
thats super interesting
i had hoped that unit-in-range was one of those magic functions that languages are made having in mind (and thus ran really efficiently)
any idea how often the periodic can run before its on the same level efficiency wise?
and how do you compare efficiency of jass functions in wc?
like what do you use to benchmark?

if i were to do this i'd have an option to add a filterfunc to check which units in range of the mazer should be considered
are filterfuncs more efficient than an equivalent outermost if statement in the group function?



and real quick
basically,
anything that isnt an atom is a handle?
Yrth is offline   Reply With Quote
Old 06-30-2011, 01:34 AM   #5
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

Quote:
Originally Posted by Yrth
i was hoping for a bit more of an in depth answer
does it have glitches, negative effects, etc?
Destroying triggers could cause obscure and gamebreaking bugs. Search the site for "handle stack corruption" if you wish to learn more. I don't know much about it myself because after I stopped using dynamic triggers, I also stopped caring about what exactly causes the bug. It might be possible to use dynamic triggers while avoiding that bug, but why risk it when using dynamic triggers doesn't allow you to code anything that you couldn't code without them (aside from a leakless generic damage event).

Quote:
one or both of us is/has misunderstood what the other meant
what i was saying is the function is being passed the vars
exactly what the function is being passed (for my purpose) would be completely static after compile time.
perhaps what the pointers are pointing to might change, but it'd always use the same pointers
That's the point, though, JASS functions don't take pointers as arguments, they take values. When you use a handle variable as an argument, it's not that variable but the value it stores that gets passed to the function. What you're describing suggests that the trigger action's arguments should be the values of variables when the trigger runs rather than the values of those variables when the action was registered. In any case, this is a moot point, trigger actions must take nothing.

Quote:
if i wanted to get rid of the trigger handle floating around, would i have to use a vjass library/scope/module?
I'm not sure what you mean. The handle won't be floating around unless you create it using CreateTrigger(). The trigger variable does get autogenerated by the world editor whenever you make a new GUI trigger, but presumably unused variables can be removed by the map optimizer the same way unused functions are.


Quote:
any idea how often the periodic can run before its on the same level efficiency wise?
and how do you compare efficiency of jass functions in wc?
like what do you use to benchmark?
I'm not sure at what period the two are equivalent. You would need to test it by writing two versions of a collision library with the same functionality, one that does periodic checks and one that uses the unit in range trigger. Use the latter while adding units to the map (some of them should probably have some random patrol orders so that collisions occur at approximately the same rate per unit that they would in a map where you need this) until the framerate drops (you can see the framerate in WC3 using the "/fps" chat command). Then, using the same unit configuration, switch to the periodic version of the library and increase the frequency of the periodic timer until you get the same framerate drop. I'm pretty sure that the frequency you get to will end up being faster than the one used internally by the unit in range triggers.

Quote:
if i were to do this i'd have an option to add a filterfunc to check which units in range of the mazer should be considered
are filterfuncs more efficient than an equivalent outermost if statement in the group function?
Well, group enums use filter functions as well, so I think those would be equivalent.

Quote:
basically,
anything that isnt an atom is a handle?
Pretty much. Integer, real, boolean are atomic types. Strings are something special, they use a data structure where each unique string you use causes an increase in memory use, but reusing the same string has no effect. Code is also a special type, back when we were still able to typecast to integer it was shown that code variables point to operation addresses in the compiled code, if I remember correctly it was possible to start running a function in the middle by converting a code type to integer, adding a number and then converting it back to code. The rest are all handles or pseudo-handles.

All handles are stored in the handle stack where each newly created handle gets a unique address, either by increasing the last new address given by 1 or by reusing the address of a handle that was previously destroyed. We used to use the return bug to get the address of a handle, which was useful for all sorts of things like testing for memory leaks and attaching data to handles. When Blizzard fixed the return bug because of the exploits that it made possible with the code type as mentioned above, they gave us the GetHandleId( h ) native so we could continue to use the handle addresses like before.

Pseudo-handles like lightnings and texttags have a similar address allocation to handles, except that they don't share the same address space, but have their own stack. You can see all the types at the start of the common.j file, the latest version of which you can extract from the war3patch.mpq. Note the agent subtype which is a reference counted handle, which means that it keeps track of how many variables are pointing to its handle address and the address will only get recycled for a new handle once the old one is destroyed and no more variables point tot address (this is why we set local handle variables to null to avoid leaks - due to a WC3 bug, the reference counter isn't properly decreased for local variables when a function ends).
__________________
Anitarf is offline   Reply With Quote
Old 06-30-2011, 11:23 PM   #6
Yrth
User
 
Yrth's Avatar
 
Join Date: Jul 2010
Posts: 76

Yrth has little to show at this moment (4)

Default

Quote:
Destroying triggers could cause obscure and gamebreaking bugs. Search the site for "handle stack corruption" if you wish to learn more. I don't know much about it myself because after I stopped using dynamic triggers, I also stopped caring about what exactly causes the bug. It might be possible to use dynamic triggers while avoiding that bug, but why risk it when using dynamic triggers doesn't allow you to code anything that you couldn't code without them (aside from a leakless generic damage event).

oh ok
that sounds pretty awful
and from the few things i read on it, is pretty awful

Quote:
but presumably unused variables can be removed by the map optimizer the same way unused functions are.

wow
<3s for the tip about map optimizer
thats gonna save me so much time

Quote:
I'm not sure at what period the two are equivalent. You would need to test it by writing two versions of a collision library with the same functionality, one that does periodic checks and one that uses the unit in range trigger. Use the latter while adding units to the map (some of them should probably have some random patrol orders so that collisions occur at approximately the same rate per unit that they would in a map where you need this) until the framerate drops (you can see the framerate in WC3 using the "/fps" chat command). Then, using the same unit configuration, switch to the periodic version of the library and increase the frequency of the periodic timer until you get the same framerate drop. I'm pretty sure that the frequency you get to will end up being faster than the one used internally by the unit in range triggers.

k
ill check it out this weekend and maybe post the results back here if anyone is interested

Quote:
Well, group enums use filter functions as well, so I think those would be equivalent.
i phrased it badly
are filter functions more efficient than an equivalent if then?
or are they just a way to easily pass a condition to an enumeration?

Quote:
Pretty much. Integer, real, boolean are atomic types. Strings are something special, they use a data structure where each unique string you use causes an increase in memory use, but reusing the same string has no effect. Code is also a special type, back when we were still able to typecast to integer it was shown that code variables point to operation addresses in the compiled code, if I remember correctly it was possible to start running a function in the middle by converting a code type to integer, adding a number and then converting it back to code. The rest are all handles or pseudo-handles.
why would they ever get rid of type casting
especially to integers
it'd be so cool to be able to modify/access triggers like that

Quote:
Pseudo-handles like lightnings and texttags have a similar address allocation to handles, except that they don't share the same address space, but have their own stack. You can see all the types at the start of the common.j file, the latest version of which you can extract from the war3patch.mpq. Note the agent subtype which is a reference counted handle, which means that it keeps track of how many variables are pointing to its handle address and the address will only get recycled for a new handle once the old one is destroyed and no more variables point tot address (this is why we set local handle variables to null to avoid leaks - due to a WC3 bug, the reference counter isn't properly decreased for local variables when a function ends).

wow that is a lot of types
i thought there were a bunch
but wow

also the needing to null locals makes a lot more sense now
ty
Yrth is offline   Reply With Quote
Old 07-01-2011, 12:04 AM   #7
Fledermaus
default string
 
Fledermaus's Avatar
 
Join Date: May 2006
Posts: 705

Submissions (1)

Fledermaus is a jewel in the rough (194)Fledermaus is a jewel in the rough (194)Fledermaus is a jewel in the rough (194)

Send a message via MSN to Fledermaus
Default

Quote:
Originally Posted by Yrth
why would they ever get rid of type casting
especially to integers
it'd be so cool to be able to modify/access triggers like that

http://www.wc3c.net/showthread.php?t=105677
Fledermaus is offline   Reply With Quote
Old 07-01-2011, 12:06 PM   #8
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

Quote:
Originally Posted by Yrth
i phrased it badly
are filter functions more efficient than an equivalent if then?
or are they just a way to easily pass a condition to an enumeration?
They're usually used to run all the needed code on enumeration, thus never needing to actually populate the group.

Quote:
why would they ever get rid of type casting
especially to integers
it'd be so cool to be able to modify/access triggers like that
Unfortunately, it was too cool for this sinful earth.
__________________
Anitarf is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off


All times are GMT. The time now is 05:09 PM.


Affiliates
The Hubb The JASS Vault Clan WEnW Campaign Creations Clan CBS GamesModding Flixreel Videos

Powered by vBulletin (Copyright ©2000 - 2019, Jelsoft Enterprises Ltd).
Hosted by www.OICcam.com
IT Support and Services provided by Executive IT Services