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

Leaktester

Status
Not open for further replies.
Level 5
Joined
Jul 18, 2010
Messages
159
Hello, I know Ralle is already working on new leaktester for the site, but I would ask when we can expect it? Is it more like couple of days or weeks. I saw one user asking about leaktester some time ago, but his thread was closed due to his behaviour, so maybe we'll get some answer here.

If leaktester isn't the priority or it will take a lot of time to get it working, can somebody suggest any simmilar tool to what we had on old-hive, or maybe could Ralle share the old one until there is leaktester 2.0. I've only found outdated versions that are not recomended to use anymore.

Thanks in advance for any response.
 
If you search you will probably find some jass leak checker systems out there. How ever maybe none is 100% reliable, and it should be something extra next to learning about leaks yourself. It should not replace it.

I don't think you can expect Ralle to release a new version next days or next weeks.

Is there only some interest of seeing the tool, or do you have a question? Because you're always welcome to ask questions about it.
 
Level 5
Joined
Jul 18, 2010
Messages
159
I'm working mostly in GUI so I need checker for that. The main reason I'm trying to get the tester is because my project is old so some systems from the begining of development are almost made of leaks, and newer ones are leakfree as I was learning while developing the map. There are currently 381 triggers in the map so leaktester was saving me a lot of time.
Do you think some outdated testers will serve the purpose of just pointing out triggers that leak, or should I just browse through them and look for the leaks myself until there is a good tool for it?
 
The way you create leaks does not matter for a tool. GUI or JASS should be not relevant for it.
--
I somehow doubt a tool will boost the process of leak removal. I would manualy check the triggery, one by one. Or at least all periodic triggers which do a lot of actions in game.
One-time leak triggers are nice to have fixed, but are not really relevant for your in game behaviour.
 

Ralle

Owner
Level 77
Joined
Oct 6, 2004
Messages
10,100
I can't tell. The leak tester is low priority. I mostly work on it when I am chilling with my laptop (not at my desktop). The leak detection is ready but I need to write the interface code so it will actually be useful for the site.

You can upload both maps and .j files.

I plan to make it so it shows you the actual code and you can click the stack and it will navigate to the place in the code. Right now it just dumps everything in the pastebin, which in itself already is better than the old one, but could still be much improved.

The stack is also very verbose, for every operator or block, there is a stack node.

I also plan to make it so it tells you where exactly the reference to the allocated object was lost.
 
Last edited:
Level 15
Joined
Sep 6, 2015
Messages
576
I'd given it a go and it gave me quite a nice report and I was able to remove some leaks. However, I have doubts with some of the trigger leaks, which either are irremovable, or which I don't know how to remove and which aren't listed in the Things That Leak thread, or which were shown even though I had removed them, or which I had missed somehow.
Here are the latest leak tester results for my map:
http://www.hiveworkshop.com/pastebin/d45f060ca9cc179e45e6ecd29a9675cb7372/
And here are the triggers that were shown there to have leaks:
In this one I had removed the group leaks (if I hadn't missed something), but they show in the leak tester:

  • LMD
    • Events
      • Unit - A unit Finishes construction
      • Unit - A unit Finishes an upgrade
    • Conditions
      • And - All (Conditions) are true
        • Conditions
          • ((Number of living Kodo Mill units owned by (Triggering player)) Greater than or equal to 1) or ((Number of living Kodo Mill (Gnolls) units owned by (Triggering player)) Greater than or equal to 1)
          • ((Unit-type of (Triggering unit)) Equal to Lumber Mill) or ((Unit-type of (Triggering unit)) Equal to Lumber Mill/Black Market (Gnoll))
    • Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units owned by (Triggering player) of type Kodo Mill) and do (Unit - Replace (Picked unit) with a Kodo Beast (Riderless) using The old unit's life and mana)
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units owned by (Triggering player) of type Kodo Mill (Gnolls)) and do (Unit - Replace (Picked unit) with a Kodo Beast (Riderless) using The old unit's life and mana)
Here too:

  • Pot
    • Events
      • Unit - A unit Finishes research
    • Conditions
      • ((Researched tech-type) Equal to Invincibility Potion) and (((Triggering player) controller) Equal to Computer)
    • Actions
      • Wait 1.00 seconds
      • Set UG = (Random 2 units from (Units owned by (Triggering player) of type Woodcutter))
      • If ((All units of UG are dead) Equal to True) then do (Do nothing) else do (Unit Group - Order UG to Undead Obsidian Statue - Morph Into Destroyer)
      • Custom script: call DestroyGroup(udg_UG)
      • Set UG = (Random 1 units from (Units owned by (Triggering player) of type Grunt))
      • If ((All units of UG are dead) Equal to True) then do (Do nothing) else do (Unit Group - Order UG to Undead Obsidian Statue - Morph Into Destroyer)
      • Custom script: call DestroyGroup(udg_UG)
      • Set UG = (Random 1 units from (Units owned by (Triggering player) of type Raider))
      • If ((All units of UG are dead) Equal to True) then do (Do nothing) else do (Unit Group - Order UG to Undead Obsidian Statue - Morph Into Destroyer)
      • Custom script: call DestroyGroup(udg_UG)
Here too:

  • Pot WC
    • Events
      • Unit - A unit Dies
    • Conditions
      • ((Unit-type of (Dying unit)) Equal to Mutant Woodcutter) and (((Owner of (Dying unit)) controller) Equal to Computer)
    • Actions
      • Wait 1.00 seconds
      • Set UG = (Random 1 units from (Units owned by (Triggering player) of type Woodcutter))
      • If ((All units of UG are dead) Equal to True) then do (Do nothing) else do (Unit Group - Order UG to Undead Obsidian Statue - Morph Into Destroyer)
      • Custom script: call DestroyGroup(udg_UG)
In this one too:

  • Pot R
    • Events
      • Unit - A unit Dies
    • Conditions
      • ((Unit-type of (Dying unit)) Equal to Mutant Raider) and (((Owner of (Dying unit)) controller) Equal to Computer)
    • Actions
      • Wait 1.00 seconds
      • Set UG = (Random 1 units from (Units owned by (Triggering player) of type Raider))
      • If ((All units of UG are dead) Equal to True) then do (Do nothing) else do (Unit Group - Order UG to Undead Obsidian Statue - Morph Into Destroyer)
      • Custom script: call DestroyGroup(udg_UG)
And here too:

  • Pot G
    • Events
      • Unit - A unit Dies
    • Conditions
      • ((Unit-type of (Dying unit)) Equal to Mutant Grunt) and (((Owner of (Dying unit)) controller) Equal to Computer)
    • Actions
      • Wait 1.00 seconds
      • Set UG = (Random 1 units from (Units owned by (Triggering player) of type Grunt))
      • If ((All units of UG are dead) Equal to True) then do (Do nothing) else do (Unit Group - Order UG to Undead Obsidian Statue - Morph Into Destroyer)
      • Custom script: call DestroyGroup(udg_UG)
And how to remove this "timer" leak? Just use a Wait?

  • Conditions
    • Events
      • Time - Elapsed game time is 180.00 seconds
    • Conditions
    • Actions
      • Custom script: call MeleeInitVictoryDefeatCustomized()
 

Ralle

Owner
Level 77
Joined
Oct 6, 2004
Messages
10,100
1.

I will take a look at your LMD trigger. Converted to JASS it looks like this:

JASS:
function Trig_LMD_Actions takes nothing returns nothing
    set bj_wantDestroyGroup = true
    call ForGroupBJ( GetUnitsOfPlayerAndTypeId(GetTriggerPlayer(), 'o00F'), function Trig_LMD_Func003002 )
    set bj_wantDestroyGroup = true
    call ForGroupBJ( GetUnitsOfPlayerAndTypeId(GetTriggerPlayer(), 'o00G'), function Trig_LMD_Func005002 )
endfunction

The function GetUnitsOfPlayerAndTypeId looks like this:

JASS:
function GetUnitsOfPlayerAndTypeId takes player whichPlayer, integer unitid returns group
    local group g = CreateGroup()
    set bj_groupEnumTypeId = unitid
    call GroupEnumUnitsOfPlayer(g, whichPlayer, filterGetUnitsOfPlayerAndTypeId)
    return g
endfunction

It creates one group and returns it.

Now, the function ForGroupBJ looks like this:

JASS:
function ForGroupBJ takes group whichGroup, code callback returns nothing
    // If the user wants the group destroyed, remember that fact and clear
    // the flag, in case it is used again in the callback.
    local boolean wantDestroy = bj_wantDestroyGroup
    set bj_wantDestroyGroup = false

    call ForGroup(whichGroup, callback)

    // If the user wants the group destroyed, do so now.
    if (wantDestroy) then
        call DestroyGroup(whichGroup)
    endif
endfunction

And because you set bj_wantDestroyGroup = true the group gets properly destroyed.

There is no leak. I will check my source code.

2.

The leaks in Pot, Pot WC and Pot G are the same. I will focus on the function Trig_Pot_WC_Actions. This is different, here's the source code:
JASS:
function Trig_Pot_WC_Actions takes nothing returns nothing
    call TriggerSleepAction( 1.00 )
    set udg_UG = GetRandomSubGroup(1, GetUnitsOfPlayerAndTypeId(GetTriggerPlayer(), 'opeo'))
    if ( Trig_Pot_WC_Func003001() ) then
        call DoNothing(  )
    else
        call GroupImmediateOrderBJ( udg_UG, "avengerform" )
    endif
    call DestroyGroup(udg_UG)
endfunction

We already know that GetUnitsOfPlayerAndTypeId creates a group and returns it. But here is the source code for GetRandomSubGroup:
JASS:
function GetRandomSubGroup takes integer count, group sourceGroup returns group
    local group g = CreateGroup()

    set bj_randomSubGroupGroup = g
    set bj_randomSubGroupWant  = count
    set bj_randomSubGroupTotal = CountUnitsInGroup(sourceGroup)

    if (bj_randomSubGroupWant <= 0 or bj_randomSubGroupTotal <= 0) then
        return g
    endif

    set bj_randomSubGroupChance = I2R(bj_randomSubGroupWant) / I2R(bj_randomSubGroupTotal)
    call ForGroup(sourceGroup, function GetRandomSubGroupEnum)
    return g
endfunction

It also returns a group.

Because the calls are nested inside each other, you will not deallocate the inner group. What you will have to do is something like this:
  • Set TempGroup1 = (Units owned by (Triggering player) of type Woodcutter)
  • Set TempGroup2 = (Random 1 units from (TempGroup1))
  • Custom script: call DestroyGroup(udg_TempGroup1)
  • Custom script: call DestroyGroup(udg_TempGroup2)
3.

That's not the timer leak, here it is:

JASS:
function Trig_Conditions_Actions takes nothing returns nothing
    call MeleeInitVictoryDefeatCustomized()
endfunction

function MeleeInitVictoryDefeatCustomized takes nothing returns nothing
    local trigger trig
    local integer index
    local player indexPlayer

    // Create a timer window for the "finish soon" timeout period, it has no timer
    // because it is driven by real time (outside of the game state to avoid desyncs)
    set bj_finishSoonTimerDialog = CreateTimerDialog(null)

    // Set a trigger to fire when we receive a "finish soon" game event
    set trig = CreateTrigger()
    call TriggerRegisterGameEvent(trig , EVENT_GAME_TOURNAMENT_FINISH_SOON)
    call TriggerAddAction(trig , function MeleeTriggerTournamentFinishSoon)

    // Set a trigger to fire when we receive a "finish now" game event
    set trig = CreateTrigger()
    call TriggerRegisterGameEvent(trig , EVENT_GAME_TOURNAMENT_FINISH_NOW)
    call TriggerAddAction(trig , function MeleeTriggerTournamentFinishNow)

    // Set up each player's mortality code.
    set index = 0
    loop
        set indexPlayer = Player(index)

        // Make sure this player slot is playing.
        if ( GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING ) then
            set bj_meleeDefeated[index]=false
            set bj_meleeVictoried[index]=false

            // Create a timer and timer window in case the player is crippled.
            set bj_playerIsCrippled[index]=false
            set bj_playerIsExposed[index]=false
            set bj_crippledTimer[index]=CreateTimer()
            set bj_crippledTimerWindows[index]=CreateTimerDialog(bj_crippledTimer[index])
            call TimerDialogSetTitle(bj_crippledTimerWindows[index] , MeleeGetCrippledTimerMessage(indexPlayer))

            // Set a trigger to fire whenever a building is cancelled for this player.
            set trig = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL , null)
            call TriggerAddAction(trig , function Custom_MeleeTriggerActionConstructCancel)

            // Set a trigger to fire whenever a unit dies for this player.
            set trig = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_DEATH , null)
            call TriggerAddAction(trig , function Custom_MeleeTriggerActionUnitDeath)

            // Set a trigger to fire whenever a unit begins construction for this player
            set trig = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_CONSTRUCT_START , null)
            call TriggerAddAction(trig , function Custom_MeleeTriggerActionUnitConstructionStart)

            // Set a trigger to fire whenever this player defeats-out
            set trig = CreateTrigger()
            call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_DEFEAT)
            call TriggerAddAction(trig , function MeleeTriggerActionPlayerDefeated)

            // Set a trigger to fire whenever this player leaves
            set trig = CreateTrigger()
            call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_LEAVE)
            call TriggerAddAction(trig , function MeleeTriggerActionPlayerLeft)

            // Set a trigger to fire whenever this player changes his/her alliances.
            set trig = CreateTrigger()
            call TriggerRegisterPlayerAllianceChange(trig , indexPlayer , ALLIANCE_PASSIVE)
            call TriggerRegisterPlayerStateEvent(trig , indexPlayer , PLAYER_STATE_ALLIED_VICTORY , EQUAL , 1)
            call TriggerAddAction(trig , function Custom_MeleeTriggerActionAllianceChange)
        else
            set bj_meleeDefeated[index]=true
            set bj_meleeVictoried[index]=false

            // Handle leave events for observers
            if ( IsPlayerObserver(indexPlayer) ) then
                // Set a trigger to fire whenever this player leaves
                set trig = CreateTrigger()
                call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_LEAVE)
                call TriggerAddAction(trig , function MeleeTriggerActionPlayerLeft)
            endif
        endif

        set index = index + 1
        exitwhen index == bj_MAX_PLAYERS
    endloop

    // Test for victory / defeat at startup, in case the user has already won / lost.
    // Allow for a short time to pass first, so that the map can finish loading.
    call TimerStart(CreateTimer() , 2.0 , false , function Custom_MeleeTriggerActionAllianceChange)
endfunction

Look at the last line. It creates a timer and keeps no handle to it. As far as I can tell this is the default melee trigger? In any case there is nothing to do about it, as far as I can see it only runs once. Also, the JASS checker reports anything where you don't have a variable pointing to it at the end of a function a leak. You create a timer and keep no variable, why? because you never need to stop the timer. So you can safely ignore that one.

Now, time for me to see what's wrong with my code regards to (1).
 
Level 15
Joined
Sep 6, 2015
Messages
576
Because the calls are nested inside each other, you will not deallocate the inner group. What you will have to do is something like this:
  • set.gif
    Set TempGroup1 = (Units owned by (Triggering player) of type Woodcutter)
  • set.gif
    Set TempGroup2 = (Random 1 units from (TempGroup1))
  • page.gif
    Custom script: call DestroyGroup(udg_TempGroup1)
  • page.gif
    Custom script: call DestroyGroup(udg_TempGroup2)
Ah, ok.
As far as I can tell this is the default melee trigger?
Yes, that is the default melee trigger edited by Retera to include custom Town Hall-type buildings.
 
JASS:
globals
    group g
endglobals

function foo takes nothing returns nothing
    call DestroyGroup(g)
endfunction

function bar takes nothing returns nothing
    set g = CreateGroup()
    call ExecuteFunc("foo")
  
    set g = CreateGroup()
    call ExecuteFunc("foo")
endfunction
^This throws a leak warning, while following doesen't:

JASS:
globals
    group g
endglobals

function foo takes nothing returns nothing
    call DestroyGroup(g)
endfunction

function bar takes nothing returns nothing
    set g = CreateGroup()
    call ExecuteFunc("foo")
endfunction

I understand trigger evaluations doesn't really work to catch, but is it the same with ExecuteFunc functions when values are constant?
But besides a trigger evaluation or executefunc, there is this matter with it which can be reduced to:

JASS:
globals
    group g
endglobals

function foo takes nothing returns nothing
    set g = CreateGroup()
    // Actions with g
endfunction

function bar takes nothing returns nothing
    local integer i = 0
    loop
        exitwhen i >= 5
        call foo()
        set i = i + 1
    endloop
endfunction

... which throws no error due the global variable. When using a local variable it works fine.

________________

But it seems to work pretty fast now, nice!

Could you open pastebin only by click, or so? - after clicked on "Analyse".
It throws you each time to the pastebin when you test stuff, and one needs to click always to "Return to last page" to come again to leak tester. Nothing critical, but it was a bit annoying when I uploaded a multiple times. And the pastebin was flooded in the end. ;D
 

Ralle

Owner
Level 77
Joined
Oct 6, 2004
Messages
10,100
Aloo you can do this:
  • Set UG = (Random 1 units from (Units owned by (Triggering player) of type Grunt))
  • Custom script: call DestroyGroup(bj_randomSubGroupGroup)
  • Custom script: call DestroyGroup(UG)
. That should remove the leak.

IcemanBo, I am aware it cannot report every leak. It should however not report false positives. I do plan on implementing ExecuteFunc("literal string") but only when the argument is a string literal.
 
Last edited:
Level 15
Joined
Sep 6, 2015
Messages
576
Tried it again now, and it no longer reports my LMD trigger that has
  • Custom script: set bj_wantDestroyGroup = true
, so that is fixed. However, when I tested my other map, it reported this trigger which also has the aforementioned custom script for destroying groups as a "group" leak:

  • Skeletons
    • Events
      • Unit - A unit enters Region 001 <gen>
    • Conditions
      • Or - Any (Conditions) are true
        • Conditions
          • (Entering unit) Equal to Kel'Thuzad (Lich) 0149 <gen>
          • (Entering unit) Equal to Balnazzar 0148 <gen>
          • (Entering unit) Equal to Anub'arak 0145 <gen>
    • Actions
      • Set skele = (Center of Region 001 <gen>)
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Order (Units in Region 007 <gen>) to Patrol To skele
      • Custom script: call RemoveLocation(udg_skele)
      • Quest - Display to Player Group - Player 1 (Red) the Hint message: |cff32cd32Hint|r: F...
      • Quest - Display to Player Group - Player 2 (Blue) the Hint message: |cff32cd32Hint|r: F...
      • Quest - Display to Player Group - Player 3 (Teal) the Hint message: |cff32cd32Hint|r: F...
      • Trigger - Turn off (This trigger)
Here are the results of the leak test for the map that contains this "Skeletons" trigger: http://www.hiveworkshop.com/pastebin/a007b3fd00d2d427688be31a3d7cb1807529/

There are also some new leaks called "filterfunc" which it reports in my first map now for the first time in these two triggers which are a part of UndeadImmortal's Damage and Spell Detection System:

  • Damage Engine
    • Events
      • Game - UnitIndexEvent becomes Equal to 1.00
      • Game - UnitIndexEvent becomes Equal to 2.00
    • Conditions
    • Actions
      • -------- Copy the Cheat Death Ability from Object Editor into your map and set the following variable respectively: --------
      • Set DamageBlockingAbility = Frost Attack [Infernal]
      • -------- - --------
      • Set DamageTypeSpell = 1
      • Set DamageTypeDOT = 2
      • Set DamageTypeRanged = 3
      • -------- - --------
      • Custom script: call ExecuteFunc("InitDamageEvent")
      • Custom script: endfunction
      • Custom script:
      • Custom script: function DmgEvFilter takes nothing returns boolean
      • -------- - --------
      • -------- The next conditions let you filter out unwanted units. By default, units with Locust will not pass the check. --------
      • -------- - --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (TempUnit is A structure) Equal to False
        • Then - Actions
          • Custom script: return true
        • Else - Actions
      • Custom script: return false
      • Custom script: endfunction
      • Custom script:
      • Custom script: function DmgEvRemoveAbilities takes nothing returns nothing
      • Custom script: local real r
      • Custom script: loop
      • Set DmgEvN = (DmgEvN - 1)
      • Custom script: set r = GetWidgetLife(udg_DmgEvStack[udg_DmgEvN])
      • Unit - Remove DamageBlockingAbility from DmgEvStack[DmgEvN]
      • Custom script: call SetWidgetLife(udg_DmgEvStack[udg_DmgEvN], r)
      • Set DmgEvStack[DmgEvN] = No unit
      • Custom script: exitwhen udg_DmgEvN == 0
      • Custom script: endloop
      • Custom script: endfunction
      • Custom script:
      • Custom script: function DmgEvSetVars takes nothing returns nothing
      • Set DamageEventAmount = (Damage taken)
      • Set DamageEventSource = (Damage source)
      • Set DamageEventTarget = (Triggering unit)
      • Custom script: endfunction
      • Custom script:
      • Custom script: function FireDmgEv takes nothing returns nothing
      • Custom script: local boolean b = GetUnitAbilityLevel(udg_DamageEventTarget, udg_DamageBlockingAbility) > 0
      • Custom script: local real life = 0
      • Custom script: local real pain = 0
      • Custom script: if b then
      • Custom script: set life = GetWidgetLife(udg_DamageEventTarget)
      • Unit - Remove DamageBlockingAbility from DamageEventTarget
      • Custom script: call SetWidgetLife(udg_DamageEventTarget, life)
      • Custom script: set pain = GetWidgetLife(udg_DamageEventTarget)
      • Custom script: endif
      • Set DamageEventPrevAmt = DamageEventAmount
      • Set DamageEventExplodesUnit = False
      • Set DamageEventOverride = False
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • DamageEventAmount Equal to 0.00
        • Then - Actions
          • Set DamageEvent = 2.00
        • Else - Actions
          • Set DamageModifierEvent = 1.00
          • Set DamageEvent = 1.00
      • Custom script: if b then
      • Unit - Add DamageBlockingAbility to DamageEventTarget
      • Custom script: call SetWidgetLife(udg_DamageEventTarget, life + GetWidgetLife(udg_DamageEventTarget) - pain)
      • Custom script: endif
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • DamageEventAmount Not equal to DamageEventPrevAmt
        • Then - Actions
          • Set DmgEvLife = ((Life of DamageEventTarget) + (DamageEventPrevAmt - DamageEventAmount))
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • DamageEventAmount Greater than DamageEventPrevAmt
            • Then - Actions
              • Unit - Set life of DamageEventTarget to (Max(0.41, DmgEvLife))
              • Custom script: if udg_DmgEvLife <= .405 then
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • DamageEventExplodesUnit Equal to True
                • Then - Actions
                  • Unit - Make DamageEventTarget Explode on death
                • Else - Actions
              • Trigger - Turn off DamageEventTrigger
              • Custom script: call UnitDamageTarget(udg_DamageEventSource, udg_DamageEventTarget, 999, false, false, null, null, null)
              • Trigger - Turn on DamageEventTrigger
              • Custom script: endif
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Max life of DamageEventTarget) Less than DmgEvLife
                • Then - Actions
                  • Unit - Add DamageBlockingAbility to DamageEventTarget
                  • Set DmgEvStack[DmgEvN] = DamageEventTarget
                  • Set DmgEvN = (DmgEvN + 1)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • DmgEvN Equal to 1
                    • Then - Actions
                      • Custom script: call TimerStart(udg_DmgEvTimer, 0, false, function DmgEvRemoveAbilities)
                    • Else - Actions
                • Else - Actions
              • Unit - Set life of DamageEventTarget to DmgEvLife
        • Else - Actions
      • Custom script: endfunction
      • Custom script:
      • Custom script: function FireRecursiveDmgEv takes nothing returns nothing
      • Custom script: local real d = udg_DamageEventAmount
      • Custom script: local unit s = udg_DamageEventSource
      • Custom script: local unit t = udg_DamageEventTarget
      • Custom script: local integer ptype = udg_DmgTypPrev
      • Custom script: local boolean explode = udg_DamageEventExplodesUnit
      • Custom script: local boolean override = udg_DamageEventOverride
      • Custom script: local real prev = udg_DamageEventPrevAmt
      • Custom script: call DmgEvSetVars()
      • Custom script: if udg_DamageEventTarget != t or udg_DamageEventSource != s or udg_DamageEventAmount != d or udg_DamageEventType != ptype then
      • Set DamageEvent = 0.00
      • Set DamageModifierEvent = 0.00
      • Custom script: call FireDmgEv()
      • -------- - --------
      • -------- Delete the next three lines to disable the in-game recursion crash warnings --------
      • -------- - --------
      • Custom script: else
      • Cinematic - Clear the screen of text messages for (All players)
      • Game - Display to (All players) for 999.00 seconds the text: WARNING: Recursion ...
      • -------- - --------
      • Custom script: endif
      • Custom script: set udg_DamageEventOverride = override
      • Custom script: set udg_DamageEventExplodesUnit = explode
      • Custom script: set udg_DamageEventPrevAmt = prev
      • Custom script: set udg_DmgTypPrev = ptype
      • Custom script: set udg_DamageEventAmount = d
      • Custom script: set udg_DamageEventSource = s
      • Custom script: set udg_DamageEventTarget = t
      • Custom script: set s = null
      • Custom script: set t = null
      • Custom script: endfunction
      • Custom script:
      • Custom script: function OnDmgEv takes nothing returns boolean
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • DamageEvent Equal to 0.00
        • Then - Actions
          • Set DmgTypPrev = DamageEventType
          • Custom script: call DmgEvSetVars()
          • Custom script: call FireDmgEv()
          • Set DamageModifierEvent = 0.00
          • Set DamageEvent = 0.00
          • Set DamageEventType = 0
        • Else - Actions
          • Custom script: call FireRecursiveDmgEv()
      • Custom script: return false
      • Custom script: endfunction
      • Custom script:
      • Custom script: function CreateDmgEv takes nothing returns nothing
      • Custom script: set udg_DamageEventTrigger = CreateTrigger()
      • Custom script: call TriggerAddCondition(udg_DamageEventTrigger, Filter(function OnDmgEv))
      • Custom script: endfunction
      • Custom script:
      • Custom script: function SetupDmgEv takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • UnitIndexEvent Equal to 1.00
        • Then - Actions
          • Set TempUnit = UDexUnits[UDex]
          • Custom script: if GetUnitAbilityLevel(udg_TempUnit, 'Aloc') == 0 and DmgEvFilter() then
          • Set UnitDamageRegistered[UDex] = True
          • Trigger - Add to DamageEventTrigger the event (Unit - TempUnit Takes damage)
          • Custom script: endif
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • UnitDamageRegistered[UDex] Equal to True
            • Then - Actions
              • Set UnitDamageRegistered[UDex] = False
              • Set DamageEventsWasted = (DamageEventsWasted + 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • DamageEventsWasted Equal to 15
                • Then - Actions
                  • Set DamageEventsWasted = 0
                  • Custom script: call DestroyTrigger(udg_DamageEventTrigger)
                  • Custom script: call CreateDmgEv()
                  • Set UDex = UDexNext[0]
                  • Custom script: loop
                  • Custom script: exitwhen udg_UDex == 0
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • UnitDamageRegistered[UDex] Equal to True
                    • Then - Actions
                      • Trigger - Add to DamageEventTrigger the event (Unit - UDexUnits[UDex] Takes damage)
                    • Else - Actions
                  • Set UDex = UDexNext[UDex]
                  • Custom script: endloop
                  • Custom script: set udg_UDex = pdex
                • Else - Actions
            • Else - Actions
      • Custom script: return false
      • Custom script: endfunction
      • Custom script:
      • Custom script: function InitDamageEvent takes nothing returns nothing
      • Custom script: call CreateDmgEv()
      • Custom script: call TriggerAddCondition(GetTriggeringTrigger(), Filter(function SetupDmgEv))
      • Set UnitIndexerEnabled = False
      • Custom script: set udg_TempUnit = CreateUnit(Player(15), 'uloc', 0, 0, 0)
      • Set UnitIndexerEnabled = True
      • Unit - Add DamageBlockingAbility to TempUnit
      • Unit - Remove TempUnit from the game
      • Countdown Timer - Start DmgEvTimer as a One-shot timer that will expire in 0.00 seconds
      • Trigger - Run (This trigger) (checking conditions)
  • Unit Indexer
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: call ExecuteFunc("InitializeUnitIndexer")
      • Custom script: endfunction
      • Custom script:
      • Custom script: function ClearUnitIndex takes nothing returns nothing
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Custom value of UDexUnits[UDex]) Equal to 0
        • Then - Actions
          • Set UnitIndexLock[UDex] = (UnitIndexLock[UDex] - 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • UnitIndexLock[UDex] Equal to 0
            • Then - Actions
              • Set UDexNext[UDexPrev[UDex]] = UDexNext[UDex]
              • Set UDexPrev[UDexNext[UDex]] = UDexPrev[UDex]
              • Set UDexPrev[UDex] = 0
              • Set UnitIndexEvent = 0.00
              • Set UnitIndexEvent = 2.00
              • Set UnitIndexEvent = 0.00
              • Set UDexUnits[UDex] = No unit
              • Set UDexNext[UDex] = UDexRecycle
              • Set UDexRecycle = UDex
            • Else - Actions
        • Else - Actions
      • Custom script: endfunction
      • Custom script:
      • Custom script: function IndexUnit takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • Custom script: local integer ndex
      • -------- - --------
      • -------- You can customize the following block - if conditions are false the (Matching unit) won't be indexed. --------
      • -------- - --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • UnitIndexerEnabled Equal to True
          • (Custom value of (Matching unit)) Equal to 0
        • Then - Actions
          • Set UDexWasted = (UDexWasted + 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • UDexWasted Equal to 15
            • Then - Actions
              • Set UDexWasted = 0
              • Set UDex = UDexNext[0]
              • Custom script: loop
              • Custom script: exitwhen udg_UDex == 0
              • Custom script: set ndex = udg_UDexNext[udg_UDex]
              • Custom script: call ClearUnitIndex()
              • Custom script: set udg_UDex = ndex
              • Custom script: endloop
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • UDexRecycle Equal to 0
            • Then - Actions
              • Set UDex = (UDexGen + 1)
              • Set UDexGen = UDex
            • Else - Actions
              • Set UDex = UDexRecycle
              • Set UDexRecycle = UDexNext[UDex]
          • Set UDexUnits[UDex] = (Matching unit)
          • Unit - Set the custom value of UDexUnits[UDex] to UDex
          • Set UDexPrev[UDexNext[0]] = UDex
          • Set UDexNext[UDex] = UDexNext[0]
          • Set UDexNext[0] = UDex
          • Set UnitIndexLock[UDex] = 1
          • Set UnitIndexEvent = 0.00
          • Set UnitIndexEvent = 1.00
          • Set UnitIndexEvent = 0.00
          • Custom script: set udg_UDex = pdex
        • Else - Actions
      • Custom script: return false
      • Custom script: endfunction
      • Custom script:
      • Custom script: function InitializeUnitIndexer takes nothing returns nothing
      • Custom script: local integer i = 16
      • Custom script: local boolexpr b = Filter(function IndexUnit)
      • Custom script: local region re = CreateRegion()
      • Custom script: local trigger t = GetTriggeringTrigger()
      • Custom script: local rect r = GetWorldBounds()
      • Custom script: call RegionAddRect(re, r)
      • Custom script: call TriggerRegisterEnterRegion(t, re, b)
      • Custom script: call TriggerClearActions(t)
      • Custom script: call TriggerAddAction(t, function ClearUnitIndex)
      • Set UnitIndexerEnabled = True
      • Custom script: loop
      • Custom script: set i = i - 1
      • Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), b)
      • Custom script: exitwhen i == 0
      • Custom script: endloop
      • Custom script: call RemoveRect(r)
      • Custom script: set re = null
      • Custom script: set r = null
      • Custom script: set t = null
      • Custom script: set b = null
      • Set UnitIndexEvent = 3.00
      • Set UnitIndexEvent = 0.00
I have no idea what these "filterfunc" leaks are and where exactly they are in these triggers, nor how to fix them.
Here are the leak test results for the map that contains these two D&SDS triggers: http://www.hiveworkshop.com/pastebin/c08299fed0e5e52fd30eaff6985ab3ad7531/
 

Ralle

Owner
Level 77
Joined
Oct 6, 2004
Messages
10,100
For the first one you have:
  • Custom script: set bj_wantDestroyGroup = true
  • Unit Group - Order (Units in Region 007 <gen>) to Patrol To skele
Which leaks because "bj_wantDestroyGroup" does not have any effect here and "Units in Region 007 <gen>" creates a group. You gotta set it to a variable and remove it after.

For the second one, if it is part of map initialization you shouldn't pay much attention. It is because you in runtime crate triggers and later remove them. The conditions for a trigger use filterfuncs which aren't removed. I don't think you should care much about them.
 
Status
Not open for further replies.
Top