• 🏆 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] Indexing Try

Status
Not open for further replies.
Level 17
Joined
Dec 11, 2014
Messages
2,004
This is vJASS but it is so simple that it can be recalled as a JASS thing.

I'm trying to learn index recycling, but I can't test it. Will this work correctly? What I'm trying to achieve is to when something is nulled, the index is added to a recycling list. On indexing (think of cast) it checks for the recycled index and if it exists, it uses the recycled index instead of creating a new one. My indexes start with 1.

What I'm creating is a walk/jump system.

On index:
JASS:
        static method slide takes unit u, real height, real dur, location where returns nothing
            local location l = GetUnitLoc(u)
            local real ddur = dur / 2
            local real dx = GetLocationX(where) - GetLocationX(l)
            local real dy = GetLocationY(where) - GetLocationY(l)

            if height > 0 then

                if height != 0 then
                    if RecyclerMax > 0 then
                        set SlideUnit[Recycler[RecyclerMax]] = u
                        set SlideReal[Recycler[RecyclerMax]] = ddur
                        set RecyclerMax = RecyclerMax - 1
                    else
                        set SlideInt = SlideInt + 1
                        set SlideUnit[SlideInt] = u
                        set SlideReal[SlideInt] = ddur
                    endif

                    call SetUnitFlyHeight(u, height, height / ddur)
                    call TimerStart(CreateTimer(), ddur, false, function Cinema.goDown)
                endif

                set udg_Knockback2DAngle = bj_RADTODEG * Atan2(GetLocationY(where) - GetLocationY(l), GetLocationX(where) - GetLocationX(l))
                //timed movement settings, using a knockback by bribe
                set udg_Knockback2DTime = dur
                set udg_Knockback2DDistance = SquareRoot(dx * dx + dy * dy)
                set udg_Knockback2DUnit = u
                set udg_Knockback2DCollision = -1.00
                set udg_Knockback2DSimple = true
                call TriggerExecute(gg_trg_Knockback_2D)
            endif

            call RemoveLocation(l)
        endmethod

Deindex:
JASS:
        private static method goDown takes nothing returns nothing
            local integer i = 1
            loop
                exitwhen i > SlideInt
                if SlideUnit[i] != null then
                    call SetUnitFlyHeight(SlideUnit[i], 0, (GetUnitFlyHeight(SlideUnit[i]) / SlideReal[SlideInt]))
                    set SlideUnit[i] = null
                    set SlideReal[i] = 0
                    set RecyclerMax = RecyclerMax + 1
                    set Recycler[RecyclerMax] = i
                endif
                set i = i + 1
            endloop
        endmethod
 
Level 7
Joined
Oct 19, 2015
Messages
286
vJass structs already do index recycling for you, so there's no need to write it on your own if you're already using vJass.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
JASS:
//! textmacro NewDataStack takes name, type, CreateFunction
struct $name$Stack extends array
    
    private static integer size = 0
    private static $type$ array stack
    
    public static method push takes $type$ data returns nothing
        set .stack[.size] = data
        set .size = .size +1
    endmethod
    
    public static method pull takes nothing returns $type$
        if .size > 0 then
            set .size = .size -1
            return .stack[.size]
        endif
        return $CreateFunction$
    endmethod
    
endstruct
//! endtextmacro

//! runtextmacro NewDataStack("Trigger", "trigger", "CreateTrigger()")
//! runtextmacro NewDataStack("Timer", "timer", "CreateTimer()")
//! runtextmacro NewDataStack("Group", "group", "CreateGroup()")
//! runtextmacro NewDataStack("Location", "location", "Location(0, 0)")
//! runtextmacro NewDataStack("Polygon", "Polygon", "Polygon.create()")
//! runtextmacro NewDataStack("Dummy", "unit", "CreateUnit(DUMMY_PLAYER, DUMMY_UNIT_TYPE_ID, 0, 0, 0)")

This creates a stack which you can pull from and push data to.
Also works with structs etc.

Its very simple, when you deindex your object, you simply push the data on the stack.
The stack will be piled up and when you want a new object, it will give you the last one that is added to the stack, if the stack is empty, it creates a new one.
 
Level 17
Joined
Dec 11, 2014
Messages
2,004
OK I'm trying to use this and I get an error:

JASS:
library Cinema
    globals 
        private Cinema cin
    endglobals

    struct Cinema //does not extend array for now 
        private unit SlideUnit
        private real SlideReal

        private static method goDown takes nothing returns nothing
            local thistype this = 1
            local thistype this2 = cin
            loop
                exitwhen this > this2 // error pops on here
                if this.SlideUnit != null then
                    call SetUnitFlyHeight(SlideUnit[i], 0, (GetUnitFlyHeight(SlideUnit[i]) / SlideReal[SlideInt]))
                    set cin.SlideUnit = null
                    set cin.SlideReal = 0
                    call cin.destroy()
                endif
                set this = this + 1
            endloop
        endmethod

        static method slide takes unit u, real height, real dur, location where returns nothing
            local location l = GetUnitLoc(u)
            local real ddur = dur / 2
            local real dx = GetLocationX(where) - GetLocationX(l)
            local real dy = GetLocationY(where) - GetLocationY(l) 

            if height > 0 then
                if height != 0 then
                    set cin = Cinema.create()
                    set cin.SlideUnit = u
                    set cin.SlideReal = ddur
                    call SetUnitFlyHeight(u, height, height / ddur)
                    call TimerStart(CreateTimer(), ddur, false, function Cinema.goDown)
                endif

                set udg_Knockback2DAngle = bj_RADTODEG * Atan2(GetLocationY(where) - GetLocationY(l), GetLocationX(where) - GetLocationX(l))
                set udg_Knockback2DTime = dur
                set udg_Knockback2DDistance = SquareRoot(dx * dx + dy * dy)
                set udg_Knockback2DUnit = u
                set udg_Knockback2DCollision = -1.00
                set udg_Knockback2DSimple = true
                call TriggerExecute(gg_trg_Knockback_2D)
            endif

            call RemoveLocation(l)
        endmethod
    endstruct
endlibrary

Error:

"Cinema does not overload a < operator"

I don't know how to use operators -__-
 
Level 7
Joined
Oct 19, 2015
Messages
286
Internally, structs are basically just array indexes, but from the outside, they are more abstract, so you can't compare them like you would compare integers. If you want to do that, you need to first explicitly typecast them like this: exitwhen integer(this) > integer(this2).

However, the logic you are trying to use will not work correctly, on several levels. First, you appear to be trying to loop through all instances in the timer callback, but looping up to cin may not catch all the instances since cin contains the last allocated index which may not be the highest allocated index. Second, I don't know why you're even trying to loop through all instances when the timer expires, since you create a separate timer for each instance. My guess is you only want to destroy the instance for which the timer expired.

Bribe said:
Mostly. Structs produce the OnDestroy trigger regardless of if you specified an OnDestroy method.
"one trigger" is not the same as "a lot of junk data".
 
Level 7
Joined
Oct 19, 2015
Messages
286
The best way to do this is to attach the instance to the timer. Since you can always get the expired timer in the callback function by using GetExpiredTimer(), you can then also get the instance for which it expired. TimerUtils is the most commonly used library for doing this.
 
Level 17
Joined
Dec 11, 2014
Messages
2,004
How does this look like? Correct?
JASS:
        private static method goDown takes nothing returns nothing
            local Cinema cin = thistype(GetTimerData(GetExpiredTimer()))

            call SetUnitFlyHeight(cin.SlideUnit, 0, (GetUnitFlyHeight(cin.SlideUnit) / cin.SlideReal))
            set cin.SlideUnit = null
            set cin.SlideReal = 0
            call cin.destroy()
        endmethod

        static method slide takes unit u, real height, real dur, location where returns nothing
            local location l = GetUnitLoc(u)
            local real ddur = dur / 2
            local real dx = GetLocationX(where) - GetLocationX(l)
            local real dy = GetLocationY(where) - GetLocationY(l)
            local Cinema cin = Cinema.create()

            if height > 0 then
                if height != 0 then
                    set cin.SlideUnit = u
                    set cin.SlideReal = ddur
                    call SetUnitFlyHeight(u, height, height / ddur)
                    call TimerStart(NewTimerEx(integer(cin)), ddur, false, function Cinema.goDown)
                endif

                set udg_Knockback2DAngle = bj_RADTODEG * Atan2(GetLocationY(where) - GetLocationY(l), GetLocationX(where) - GetLocationX(l))
                set udg_Knockback2DTime = dur
                set udg_Knockback2DDistance = SquareRoot(dx * dx + dy * dy)
                set udg_Knockback2DUnit = u
                set udg_Knockback2DCollision = -1.00
                set udg_Knockback2DSimple = true
                call TriggerExecute(gg_trg_Knockback_2D)
            endif

            call RemoveLocation(l)
        endmethod
 
Level 17
Joined
Dec 11, 2014
Messages
2,004
So this?

JASS:
        private static method goDown takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local Cinema cin = thistype(GetTimerData(t))

            call SetUnitFlyHeight(cin.SlideUnit, 0, (GetUnitFlyHeight(cin.SlideUnit) / cin.SlideReal))
            set cin.SlideUnit = null
            set cin.SlideReal = 0
            call cin.destroy()
            call ReleaseTimer(t)
        endmethod

        static method slide takes unit u, real height, real dur, location where returns nothing
            local location l = GetUnitLoc(u)
            local real ddur = dur / 2
            local real dx = GetLocationX(where) - GetLocationX(l)
            local real dy = GetLocationY(where) - GetLocationY(l)
            local Cinema cin = Cinema.create()

            if height > 0 then
                if height != 0 then
                    set cin.SlideUnit = u
                    set cin.SlideReal = ddur
                    call SetUnitFlyHeight(u, height, height / ddur)
                    call TimerStart(NewTimerEx(integer(cin)), ddur, false, function Cinema.goDown)
                endif

                set udg_Knockback2DAngle = bj_RADTODEG * Atan2(GetLocationY(where) - GetLocationY(l), GetLocationX(where) - GetLocationX(l))
                set udg_Knockback2DTime = dur
                set udg_Knockback2DDistance = SquareRoot(dx * dx + dy * dy)
                set udg_Knockback2DUnit = u
                set udg_Knockback2DCollision = -1.00
                set udg_Knockback2DSimple = true
                call TriggerExecute(gg_trg_Knockback_2D)
            endif

            call RemoveLocation(l)
        endmethod
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
The next step is to null local handle variables to prevent permanent leaks in data.

For example in:
static method slide takes unit u, real height, real dur, location where returns nothing

^Here you create a local location handle l.
You probably learned in GUI locations are removed via RemoveLocation.
As JASS / vJass'er this is an insufficient cleanup, because most local handle variables
must be nulled before the end of the function.

JASS:
    function Example takes nothing returns nothing
        local location loc = Location(0, 0)
        // 
        call RemoveLocation(loc)
        set loc = null// Clears the handle leak.
    endfunction
^ That is so because most handles are reference counted.
If you assign a certain handle ( for example a location ) to a variable the counter goes up by one.
Nulling or overriding that variable value with another value decreases that counter by one.
A handle can only be freed if the counter is 0.

In method goDown the local timer should also be nulled in the end.
This is slightly different here, because a timer created by TimerUtils normally
doesn't create what we call a leak. However I still recommend to null these timer handles.
I also do so in my code.
 
Level 17
Joined
Dec 11, 2014
Messages
2,004
The next step is to null local handle variables to prevent permanent leaks in data.

For example in:
static method slide takes unit u, real height, real dur, location where returns nothing

^Here you create a local location handle l.
You probably learned in GUI locations are removed via RemoveLocation.
As JASS / vJass'er this is an insufficient cleanup, because most local handle variables
must be nulled before the end of the function.

JASS:
    function Example takes nothing returns nothing
        local location loc = Location(0, 0)
        // 
        call RemoveLocation(loc)
        set loc = null// Clears the handle leak.
    endfunction
^ That is so because most handles are reference counted.
If you assign a certain handle ( for example a location ) to a variable the counter goes up by one.
Nulling or overriding that variable value with another value decreases that counter by one.
A handle can only be freed if the counter is 0.

In method goDown the local timer should also be nulled in the end.
This is slightly different here, because a timer created by TimerUtils normally
doesn't create what we call a leak. However I still recommend to null these timer handles.
I also do so in my code.

Yeah I knew about reference leaks... Thanks for reminding though :p forgot to clean them up. Thanks for the post!
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
I would use the one I submitted. It has no dependencies unless you want debug features. It also has great debugging capabilities should you want to take advantage of them. It features the latest algorithm in 3 different flavors too : ).


I usually deal with A LOT of data being created and destroyed all over the place, so I use the debugging features to make sure that a lib or map doesn't leak and to find those leaks quickly. It has certainly made my life easier.
 
Level 17
Joined
Dec 11, 2014
Messages
2,004
I would use the one I submitted. It has no dependencies unless you want debug features. It also has great debugging capabilities should you want to take advantage of them. It features the latest algorithm in 3 different flavors too : ).


I usually deal with A LOT of data being created and destroyed all over the place, so I use the debugging features to make sure that a lib or map doesn't leak and to find those leaks quickly. It has certainly made my life easier.

OK, I'll try to learn how to work with yours as soon as possible.
 
Status
Not open for further replies.
Top