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

[JASS] Leak Help

Status
Not open for further replies.
Level 9
Joined
Nov 28, 2008
Messages
704
Hi, Ive been reading the tutorials on leaks, and I never did find a speicif way or answer on how to remove a local unit or player variable, or anything like that.

Lets say I do

JASS:
local unit TempUnit
local player TempPlayer

insidie of a trigger. At the end, is there a thing like RemoveLocation() for Units or Players? Obviously the RemoveUnit() doesnt work, because that will remove the unit it refers to.

Should I just set them to null? Like

JASS:
set TempUnit = null

Can I do that for other things as well? Do you HAVE to do

JASS:
call RemoveLocation(TempPoint)

? Can you just do

JASS:
set TempPoint = null

?

Sorry if this is actually answered in the tutorials, I found a list with all the commands to destroy handles, but I couldnt find anything to destroy a player or unit local variable.

Thanks for any help.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
RemoveUnit() and DestroyPlayer() are the 2 to use. Obviously they deystroy the object but that must be what you are after.

Anyway, players do not leak and neithor do units really. With players, nulling them in the end is pointless as well as it will only block atmost 16 handle slots as the players remain constant throuout the game. Units on the other hand you definatly have to null the locals for as there could be over 3000 units created and destroyed in a single gameplay and that could leak over 3000 handle values if you are not careful.

Basically, with those objects you do not want to remove and destroy them until you are done with them and thus they have not leaked as they are still usable. However you have to null their local handles after using the locals as that is a different kind of leak.

Part of the system for asigning unique handle values counts the number of references to that object that are currently stored. Locals however are added to the count but not automatically remove by default at the end of a function. Thus they leak a count and result in that handle index becomming unusable by any object ever again after the object that was using it is destroyed. You however stop this by nulling the local handle at the end of a function, which forces it to remove one from the counter of the handle value and thus keeps it accurate and lets it be reused after the object is destroyed.

Thus you only need to null local handles at the end of a function and not any other kind of local.

Remember also that if you are done using a hidden object that can not be fetched again and will not be used again to remove or destroy it to prevent leaks.

A leak is when something becomes stuck in RAM permantly and will never be used but can no longer be removed.
 
Level 9
Joined
Nov 28, 2008
Messages
704
I do not want to remove the unit. The unit Im storing in there is a reference to a unit I want to ressurect 30 seconds later, however, since the trigger handles multiple units, I wanted it MUI and thus made local variables.

Should I or should I not remove the unit? Should I be setting the local variable to null then doing RemoveUnit()?

I dont want to units I revive with this trigger to be removed.

So far this is my trigger for what I have. Is this or is this not leaking?

JASS:
function Trig_Saucy_Conditions takes nothing returns boolean
    if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'H000' ) ) then
        return false
    endif
    return true
endfunction

function Trig_Saucy_Actions takes nothing returns nothing
    local location TempPoint
    local unit TempUnit
    local player TempPlayer
    set TempUnit = GetTriggerUnit()
    set TempPlayer = GetTriggerPlayer()
    call DisplayTimedTextToForce( GetPlayersAll(), 30, "A seal has died and will be revived in 30 seconds!" )
    call TriggerSleepAction( 30.00 )
    if IsPlayerAlly(TempPlayer, Player(10)) == true then
        set TempPoint = GetRectCenter(gg_rct_StartTL)
        call ReviveHeroLoc( TempUnit, TempPoint, true )
    else
        set TempPoint = GetRectCenter(gg_rct_StartBR)
        call ReviveHeroLoc( TempUnit, TempPoint, true )
    endif
    call RemoveLocation(TempPoint)
    set TempUnit = null
    set TempPlayer = null
endfunction

//===========================================================================
function InitTrig_Revive takes nothing returns nothing
    set gg_trg_Revive = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Revive, EVENT_PLAYER_UNIT_DEATH )
    call TriggerAddCondition( gg_trg_Revive, Condition( function Trig_Saucy_Conditions ) )
    call TriggerAddAction( gg_trg_Revive, function Trig_Saucy_Actions )
endfunction

Thanks again for your help.
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
The point is, RemoveLocation is to remove the LOCATION, setting a location variable to null is simply nulling the pointer which points to the address where the location is in the memory.
This means that if you try to remove a unit with the same method it will literally remove the unit (a.k.a: RemoveUnit).
So, no, you don't need to destroy/remove units. When they die their info will die with them.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
JASS:
function Trig_Saucy_Conditions takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) == 'H000'
endfunction

function Trig_Saucy_Actions takes nothing returns nothing
    local location TempPoint
    local unit TempUnit = GetTriggerUnit()
    local player TempPlayer = GetTriggerPlayer()  //this makes no sense as there is no triggering player as it is a unit even and not a player event thus this variable will be set to null so your trigger is broken.
    //To fix you need to set it to an existing player and not null.
    call DisplayTimedTextToForce( GetPlayersAll(), 30, "A seal has died and will be revived in 30 seconds!" )
    call TriggerSleepAction( 30 ) //Will bug in multiplayer by taking 25-50% longer than the time specified, I recomend using polled wait for slightly better timeing accuracy.
    if IsPlayerAlly(TempPlayer, Player(10)) then
        set TempPoint = GetRectCenter(gg_rct_StartTL)
        call ReviveHeroLoc( TempUnit, TempPoint, true )//Why not use X/Y and avoid a location completely?
    else
        set TempPoint = GetRectCenter(gg_rct_StartBR)
        call ReviveHeroLoc( TempUnit, TempPoint, true )//Why not use X/Y and avoid a location completely?
    endif
    call RemoveLocation(TempPoint)
    set TempPoint = null//nulls the location local to free up its handle index.
    set TempUnit = null//nulls the unit local to prvent its hande index becomming bugged so when it is finally removed (if it ever is), the handle index will be resuable.
    set TempPlayer = null //This is technically pointless as Players can not leak as there are 16 of them predifined and so atmost 16 handle indexes will leak at which point the game ends as there would be no one playing.   However it could be considered good practice nulling all local handles just to get used to it.
endfunction

function InitTrig_Revive takes nothing returns nothing
    set gg_trg_Revive = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Revive, EVENT_PLAYER_UNIT_DEATH )
    call TriggerAddCondition( gg_trg_Revive, Condition( function Trig_Saucy_Conditions ) )
    call TriggerAddAction( gg_trg_Revive, function Trig_Saucy_Actions )
endfunction
 
Level 9
Joined
Nov 28, 2008
Messages
704
Ahh, thanks much. I dont quite understand why the local handle variable for a player wouldnt leak, and yes, that trigger is slightly bugged. Trigger player should be equal to the owner of the triggering unit, but anyways :D...

Thanks again, DSG. Ill give you rep after I spread it around.
 
Status
Not open for further replies.
Top