• 🏆 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!

[vJASS] attaching a struct to a enumdestructable callback?

Status
Not open for further replies.
Level 14
Joined
Apr 20, 2009
Messages
1,543
Is it possible to do this?

Basically I need to be able to attach a struct to a enumdestructable callback function.

My struct needs to be destroyed whenever there is a destructable of some type in range of a unit.
(This will be transfered from within a very fast timer towards the callback function of a customized enumDestructablesInCircle, I know it's slow but as of now I couldn't find a better solution)

How would I go about doing this? I have no idea to which handle I could attach the struct in order to transfer the data to the callback.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
As long as there is no delay (such as a timer) involved you should be good to just set a global and store it in a local in the callback function (and then reset it at the end of the callback function, to avoid potential issues from something within the callback function firing a trigger or otherwise causing a situation where the global could be overwritten).
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
There is indeed no delay involved with the enumDestructable function however, it is inside a timer. My scenario looks somewhat like this:

JASS:
//This is just an example :)

struct structname
endstruct

function needsData takes nothing returns nothing
    //storing the struct in a global would be okay to retrieve it in this case?
    //I can imagine it is, but still if this executes slower then 0.02 sec the global will be overwritten I suppose?
endfunction

function someFilter takes nothing returns boolean
    return some_destructable_type equals enumdestructable blah
endfunction

function someTimer takes nothing returns nothing
    local structname data = GetTimerStructA(GetExpiredTimer())
    local rect r
    set r = Rect(x - 100, y - 100, x + 100, y + 100)
    //problem arises that I am unabled to SetTimerStructA to any handle...
    //there is no delay here, however it is inside the callback of the timer...
    call EnumDestructablesInRect(r, Filter(function someFilter), function needsData)
    //some more functions will be called over here...
endfunction

function someInitFunction takes nothing returns nothing
    local structname data = structname.create()
    local timer t = CreateTimer()
    call SetTimerStructA(t, data)
    call TimerStart(t, 0.02, true, function someTimer) //0.02 is quite fast for this scenario O_0
endfunction

Would it cause problems to use a global in this case?
The event I got attached is for whenever a unit starts the effect of an ability.
So imagine 2 units casting this at the same time.
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
Nope, it would never cause problems.
There is no "at the same time" because wc3 only has one big thread.
Just attach the struct instance to the timer (as you already have) and you are free to go.

Awesome :D so I can simply make my structname "variable" global and problem solved ^.^?

+rep to the both of you for this great help :)
 
Hashjie, wait.
You didn't understand I think.
Any delay will make it non-mui.
But since you already attach the data to the timer and then use the timers data to work with your values, it will work.
In your someTimer you set the global variable and then use it in the someFilter function.

Just like this:

JASS:
globals
   StructName GlobalVar = 0
endglobals

private function filterFunc 
    Use GlobalVar here
endfunction

private function execFunc
    Get Expired Timer
    Get Attached Struct Instance
    Set GlobalVar
    Execute filterFunc
endfunction
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
It's worth noting that you probably want to store the global in a local at the start of filterfunc, and then set the global to that local at the end of it, if there's any chance that problematic triggers could be fired by anything within the filterfunc (since that would interrupt the execution and thus provide a chance for the global to be overwritten if it was a trigger which used said global).
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
Just like this:

JASS:
globals
   StructName GlobalVar
endglobals

private function filterFunc 
    Use GlobalVar here
endfunction

private function execFunc
    Get Expired Timer
    Get Attached Struct Instance
    Set GlobalVar
    Execute filterFunc
endfunction

erm actually, that was exactly what I was thinking xD
And yes, I do know that delay is a no-go when creating MUI spells thank you ;)

It's worth noting that you probably want to store the global in a local at the start of filterfunc, and then set the global to that local at the end of it, if there's any chance that problematic triggers could be fired by anything within the filterfunc (since that would interrupt the execution and thus provide a chance for the global to be overwritten if it was a trigger which used said global).

so something like?:
JASS:
globals
   StructName GlobalVar
endglobals

struct StructName
endstruct

private function filterFunc takes nothing returns nothing
    local StructName mystruct = GlobalVar
    //do something here
    set GlobalVar = mystruct
endfunction

private function execFunc
    Get Expired Timer
    Get Attached Struct Instance
    Set GlobalVar = Attached Struct Instance
    Execute filterFunc
endfunction

I see, thanks guys :D
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
It's worth noting that you probably want to store the global in a local at the start of filterfunc, and then set the global to that local at the end of it, if there's any chance that problematic triggers could be fired by anything within the filterfunc (since that would interrupt the execution and thus provide a chance for the global to be overwritten if it was a trigger which used said global).

You may index an enumeration loop with a simple counter btw.

JASS:
function SomeEnumFunction takes nothing returns nothing
    local integer indexOfTheEnumerationIBelongTo = COUNTER
endfunction

function ForGroupEx takes group g, function a returns nothing
    set COUNTER = COUNTER + 1

    call ForGroup(g, a)

    set COUNTER = COUNTER - 1
endfunction

because the enumeration will have been expired before returning to the parent and thus it's even recursion-safe.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
You may index an enumeration loop with a simple counter btw.

JASS:
function SomeEnumFunction takes nothing returns nothing
    local integer indexOfTheEnumerationIBelongTo = COUNTER
endfunction

function ForGroupEx takes group g, function a returns nothing
    set COUNTER = COUNTER + 1

    call ForGroup(g, a)

    set COUNTER = COUNTER - 1
endfunction

because the enumeration will have been expired before returning to the parent and thus it's even recursion-safe.
That requires you be storing in a global array or somesuch which is kind of pointless and not avoiding the issue.

Search TimerData by Vexorian on wc3c, that is what you are looking for.
Unless something changed since I left warcraft 3 modding, TUtils doesn't support attaching structs to group enumerations (nor should it).

---

Hashjie, looks fine.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
That requires you be storing in a global array or somesuch which is kind of pointless and not avoiding the issue.

You do not need to instantly transfer everything to locals other than the index nor to restore the global at the end of the function then. And it does not break from thread halts, ofc the counter would leak in this case but that may be fixed with a periodic timer releasing remaining stuff somewhen.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
You do not need to instantly transfer everything to locals other than the index nor to restore the global at the end of the function then. And it does not break from thread halts, ofc the counter would leak in this case but that may be fixed with a periodic timer releasing remaining stuff somewhen.
Just use a struct if you need to pass a nontrivial amount of data. It reads and is organized much better and works the same.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
Just use a struct if you need to pass a nontrivial amount of data. It reads and is organized much better and works the same.

It is the same.

JASS:
function ForGroupEx takes group g, action a, integer structData returns nothing
    set COUNTER = COUNTER + 1

    set DATA[COUNTER] = structData

    call ForGroup(g, a)

    set COUNTER = COUNTER - 1
endfunction

function Enum takes nothing returns nothing
    local structType data = DATA[COUNTER]

    //do actions

    //no need to reset the global for next iteration
endfunction

Just saying that writing the Enum function is the application, so you may want to avoid sources of trouble there.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
It is the same.

JASS:
function ForGroupEx takes group g, action a, integer structData returns nothing
    set COUNTER = COUNTER + 1

    set DATA[COUNTER] = structData

    call ForGroup(g, a)

    set COUNTER = COUNTER - 1
endfunction

function Enum takes nothing returns nothing
    local structType data = DATA[COUNTER]

    //do actions

    //no need to reset the global for next iteration
endfunction

Just saying that writing the Enum function is the application, so you may want to avoid sources of trouble there.
Oh, whoops, missed that you were proposing having a function which handled all these cases for you. That makes more sense.
 
Status
Not open for further replies.
Top