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

heavy trigger?

Status
Not open for further replies.
Level 17
Joined
Aug 19, 2007
Messages
1,380
Hi,

Can the following transport trigger result in lags? E.g. if the AI has many units and transports? Its an old and ugly trigger so it can result in eye cancer:

  • AI transport load units
    • Events
      • Time - Every 8.00 seconds of game time
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Player 2 (Blue) controller) Equal to Computer
          • AI_Player2_Air Equal to 1
        • Then - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Number of living Aurochs units owned by Player 2 (Blue)) Greater than 0
            • Then - Actions
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units owned by Player 2 (Blue) matching (((Unit-type of (Matching unit)) Equal to Aurochs) and (((Current order of (Matching unit)) Not equal to (Order(load))) and ((Current order of (Matching unit)) Not equal to (Order(unloadall)))))) and do (Unit - Order (Picked unit) to Load (Random unit from (Units owned by (Owner of (Picked unit)) matching (((Unit-type of (Matching unit)) Equal to Bionic Marine) or ((Unit-type of (Matching unit)) Equal to Chemical Bot)))))
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Number of living Broodmother units owned by Player 2 (Blue)) Greater than 0
            • Then - Actions
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units owned by Player 2 (Blue) matching (((Unit-type of (Matching unit)) Equal to Broodmother) and (((Current order of (Matching unit)) Not equal to (Order(load))) and ((Current order of (Matching unit)) Not equal to (Order(unloadall)))))) and do (Unit - Order (Picked unit) to Load (Random unit from (Units owned by (Owner of (Picked unit)) matching (((Unit-type of (Matching unit)) Equal to Zombie) or ((Unit-type of (Matching unit)) Equal to Infested Terran)))))
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units owned by Player 2 (Blue) matching (((Unit-type of (Matching unit)) Equal to Broodmother) and (((Current order of (Matching unit)) Not equal to (Order(load))) and ((Current order of (Matching unit)) Not equal to (Order(unloadall)))))) and do (Unit - Order (Picked unit) to Load (Random unit from (Units owned by (Owner of (Picked unit)) matching (((Unit-type of (Matching unit)) Equal to Zombie) or ((Unit-type of (Matching unit)) Equal to Infested Terran)))))
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Number of living Overlord of the Void units owned by Player 2 (Blue)) Greater than 0
            • Then - Actions
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units owned by Player 2 (Blue) matching (((Unit-type of (Matching unit)) Equal to Overlord of the Void) and (((Current order of (Matching unit)) Not equal to (Order(load))) and ((Current order of (Matching unit)) Not equal to (Order(unloadall)))))) and do (Unit - Order (Picked unit) to Load (Random unit from (Units owned by (Owner of (Picked unit)) matching (((Unit-type of (Matching unit)) Equal to Minion) or (((Unit-type of (Matching unit)) Equal to Minion (splitted)) or ((Unit-type of (Matching unit)) Equal
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units owned by Player 2 (Blue) matching (((Unit-type of (Matching unit)) Equal to Overlord of the Void) and (((Current order of (Matching unit)) Not equal to (Order(load))) and ((Current order of (Matching unit)) Not equal to (Order(unloadall)))))) and do (Unit - Order (Picked unit) to Load (Random unit from (Units owned by (Owner of (Picked unit)) matching (((Unit-type of (Matching unit)) Equal to Minion) or (((Unit-type of (Matching unit)) Equal to Minion (splitted)) or ((Unit-type of (Matching unit)) Equal
            • Else - Actions
        • Else - Actions
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,180
It leaks so it can cause game performance to degrade over time.

These lines leak...
  • (Number of living Aurochs units owned by Player 2 (Blue)) Greater than 0
  • (Number of living Broodmother units owned by Player 2 (Blue)) Greater than 0
  • (Number of living Overlord of the Void units owned by Player 2 (Blue)) Greater than 0
All of them leak a handle reference index as a result of the "local declared local handle reference counter leak on return" error.

JASS:
function CountLivingPlayerUnitsOfTypeId takes integer unitId,player whichPlayer returns integer
    local group g
    local integer matchedCount
    set g = CreateGroup()
    set bj_livingPlayerUnitsTypeId = unitId
    call GroupEnumUnitsOfPlayer(g, whichPlayer, filterLivingPlayerUnitsOfTypeId)
    set matchedCount = CountUnitsInGroup(g)
    call DestroyGroup(g)
    return matchedCount
endfunction
As can be seen above, the local declared local group g is set to a new group, the group is destroyed but the variable is not nulled. As such the handle index used by the group cannot ever be recycled. Below a fixed version of the BJ is provided.
JASS:
function CountLivingPlayerUnitsOfTypeId takes integer unitId,player whichPlayer returns integer
    local group g = CreateGroup()
    local integer matchedCount
    set bj_livingPlayerUnitsTypeId = unitId
    call GroupEnumUnitsOfPlayer(g, whichPlayer, filterLivingPlayerUnitsOfTypeId)
    set matchedCount = CountUnitsInGroup(g)
    call DestroyGroup(g)
    set g = null
    return matchedCount
endfunction
 
Level 17
Joined
Aug 19, 2007
Messages
1,380
Hi ty for the fast reactions,

I actually have unit indexer trigger (right below, not selfmade though), is that enough for counting units entering/exiting the map? Could I use that to delete the leak?


This trigger works in two key phases:

1) During map initialization, enumerate all units of all players to give them an index.
2) Adds a second event to itself to index new units as they enter the map.

As a unit enters the map, check for any old units that may have been removed at some point in order to free their index.

  • Unit Indexer
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: call ExecuteFunc("InitializeUnitIndexer")
      • Custom script: endfunction
      • -------- --------
      • -------- This is the most important function - it provides an index for units as they enter the map --------
      • -------- --------
      • Custom script: function IndexUnit takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • -------- --------
      • -------- You can use the boolean UnitIndexerEnabled to protect some of your undesirable units from being indexed --------
      • -------- - Example: --------
      • -------- -- Set UnitIndexerEnabled = False --------
      • -------- -- Unit - Create 1 Dummy for (Triggering player) at TempLoc facing 0.00 degrees --------
      • -------- -- Set UnitIndexerEnabled = True --------
      • -------- --------
      • -------- You can also 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
        • Then - Actions
          • -------- --------
          • -------- Generate a unique integer index for this unit --------
          • -------- --------
          • 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]
          • -------- --------
          • -------- Link index to unit, unit to index --------
          • -------- --------
          • Set UDexUnits[UDex] = (Matching unit)
          • Unit - Set the custom value of UDexUnits[UDex] to UDex
          • -------- --------
          • -------- Use a doubly-linked list to store all active indexes --------
          • -------- --------
          • Set UDexPrev[UDexNext[0]] = UDex
          • Set UDexNext[UDex] = UDexNext[0]
          • Set UDexNext[0] = UDex
          • -------- --------
          • -------- Fire index event for UDex --------
          • -------- --------
          • 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
      • -------- --------
      • -------- The next function is called each time a unit enters the map --------
      • -------- --------
      • Custom script: function IndexNewUnit takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • Custom script: local integer ndex
      • -------- --------
      • -------- Recycle indices of units no longer in-play every (15) units created --------
      • -------- --------
      • 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
          • 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
              • -------- --------
              • -------- Remove index from linked list --------
              • -------- --------
              • Custom script: set ndex = udg_UDexNext[udg_UDex]
              • Custom script: set udg_UDexNext[udg_UDexPrev[udg_UDex]] = ndex
              • Custom script: set udg_UDexPrev[ndex] = udg_UDexPrev[udg_UDex]
              • Set UDexPrev[UDex] = 0
              • -------- --------
              • -------- Fire deindex event for UDex --------
              • -------- --------
              • Set UnitIndexEvent = 2.00
              • Set UnitIndexEvent = 0.00
              • -------- --------
              • -------- Recycle the index for later use --------
              • -------- --------
              • Set UDexUnits[UDex] = No unit
              • Set UDexNext[UDex] = UDexRecycle
              • Set UDexRecycle = UDex
              • Custom script: set udg_UDex = ndex
            • Else - Actions
              • Set UDex = UDexNext[UDex]
          • Custom script: endloop
          • Custom script: set udg_UDex = pdex
        • Else - Actions
      • -------- --------
      • -------- Handle the entering unit (Matching unit) --------
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Custom value of (Matching unit)) Equal to 0
        • Then - Actions
          • Custom script: call IndexUnit()
        • Else - Actions
      • Custom script: return false
      • Custom script: endfunction
      • -------- --------
      • -------- The next function initializes the core of the system --------
      • -------- --------
      • Custom script: function InitializeUnitIndexer takes nothing returns nothing
      • Custom script: local integer i = 0
      • Custom script: local region re = CreateRegion()
      • Custom script: local rect r = GetWorldBounds()
      • Set UnitIndexerEnabled = True
      • Custom script: call RegionAddRect(re, r)
      • Custom script: call TriggerRegisterEnterRegion(CreateTrigger(), re, Filter(function IndexNewUnit))
      • Custom script: call RemoveRect(r)
      • Custom script: set re = null
      • Custom script: set r = null
      • Custom script: loop
      • Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), Filter(function IndexUnit))
      • Custom script: set i = i + 1
      • Custom script: exitwhen i == 16
      • Custom script: endloop
      • -------- --------
      • -------- This is the "Unit Indexer Initialized" event, use it instead of "Map Initialization" for best results --------
      • -------- --------
      • Set UnitIndexEvent = 3.00
      • Set UnitIndexEvent = 0.00


As can be seen above, the local declared local group g is set to a new group, the group is destroyed but the variable is not nulled. As such the handle index used by the group cannot ever be recycled. Below a fixed version of the BJ is provided.
, forgive my noobness; how can I implement/use this? Should I copy the fixed function to the custom map script window?
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
Unit Enters Region (Entire Map Area), increase count and on death decrease count. Provided nothing else happens with the unit that should change the count. Or you could copy Dr Super Goods fixed function (might need to change the name) into the map header and call it via a custom script before checking the conditions.
 
Level 17
Joined
Aug 19, 2007
Messages
1,380
Hi, get 2 errors, 1 is 'invalid number of arguments' and an 'expected endif'. I have copied Dr Super Good fixed function to the header;


JASS:
//===========================================================================
// Fixes leak for pick every unit condition

function FixCountLivingPlayerUnitsOfTypeId takes integer unitId,player whichPlayer returns integer
    local group g = CreateGroup()
    local integer matchedCount
    set bj_livingPlayerUnitsTypeId = unitId
    call GroupEnumUnitsOfPlayer(g, whichPlayer, filterLivingPlayerUnitsOfTypeId)
    set matchedCount = CountUnitsInGroup(g)
    call DestroyGroup(g)
    set g = null
    return matchedCount
endfunction


And placed the custom script for each condition.


  • AI transport load units
    • Events
      • Time - Every 8.00 seconds of game time
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Player 2 (Blue) controller) Equal to Computer
          • AI_Player2_Air Equal to 1
        • Then - Actions
          • Custom script: call FixCountLivingPlayerUnitsOfTypeId()
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Number of living Aurochs units owned by Player 2 (Blue)) Greater than 0
            • Then - Actions
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units owned by Player 2 (Blue) matching (((Unit-type of (Matching unit)) Equal to Aurochs) and (((Current order of (Matching unit)) Not equal to (Order(load))) and ((Current order of (Matching unit)) Not equal to (Order(unloadall)))))) and do (Unit - Order (Picked unit) to Load (Random unit from (Units owned by (Owner of (Picked unit)) matching (((Unit-type of (Matching unit)) Equal to Bionic Marine) or ((Unit-type of (Matching unit)) Equal to Chemical Bot)))))
            • Else - Actions
          • Custom script: call FixCountLivingPlayerUnitsOfTypeId()
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Number of living Broodmother units owned by Player 2 (Blue)) Greater than 0
            • Then - Actions
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units owned by Player 2 (Blue) matching (((Unit-type of (Matching unit)) Equal to Broodmother) and (((Current order of (Matching unit)) Not equal to (Order(load))) and ((Current order of (Matching unit)) Not equal to (Order(unloadall)))))) and do (Unit - Order (Picked unit) to Load (Random unit from (Units owned by (Owner of (Picked unit)) matching (((Unit-type of (Matching unit)) Equal to Zombie) or ((Unit-type of (Matching unit)) Equal to Infested Terran)))))
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units owned by Player 2 (Blue) matching (((Unit-type of (Matching unit)) Equal to Broodmother) and (((Current order of (Matching unit)) Not equal to (Order(load))) and ((Current order of (Matching unit)) Not equal to (Order(unloadall)))))) and do (Unit - Order (Picked unit) to Load (Random unit from (Units owned by (Owner of (Picked unit)) matching (((Unit-type of (Matching unit)) Equal to Zombie) or ((Unit-type of (Matching unit)) Equal to Infested Terran)))))
            • Else - Actions
          • Custom script: call FixCountLivingPlayerUnitsOfTypeId()
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Number of living Overlord of the Void units owned by Player 2 (Blue)) Greater than 0
            • Then - Actions
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units owned by Player 2 (Blue) matching (((Unit-type of (Matching unit)) Equal to Overlord of the Void) and (((Current order of (Matching unit)) Not equal to (Order(load))) and ((Current order of (Matching unit)) Not equal to (Order(unloadall)))))) and do (Unit - Order (Picked unit) to Load (Random unit from (Units owned by (Owner of (Picked unit)) matching (((Unit-type of (Matching unit)) Equal to Minion) or (((Unit-type of (Matching unit)) Equal to Minion (splitted)) or ((Unit-type of (Matching unit)) Equal
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units owned by Player 2 (Blue) matching (((Unit-type of (Matching unit)) Equal to Overlord of the Void) and (((Current order of (Matching unit)) Not equal to (Order(load))) and ((Current order of (Matching unit)) Not equal to (Order(unloadall)))))) and do (Unit - Order (Picked unit) to Load (Random unit from (Units owned by (Owner of (Picked unit)) matching (((Unit-type of (Matching unit)) Equal to Minion) or (((Unit-type of (Matching unit)) Equal to Minion (splitted)) or ((Unit-type of (Matching unit)) Equal
            • Else - Actions
        • Else - Actions


Probably some stupid mistake of mine...
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
If you look into the function you have copied:
JASS:
function FixCountLivingPlayerUnitsOfTypeId takes integer unitId, player whichPlayer returns integer

Note in the code above that it takes these parameters (unitId and whichPlayer) so you need to pass it into the function just like any other GUI function.

- Create a new variable of type integer and call it tempCount
- You need to use it by declaring (setting) a variable to to the value returned. So in your custom script: set udg_tempCount = FixCountLivingPlayerUnitsOfTypeId ('hhou', Player(1)). In this example I'm counting number of farms for player blue. So find the UnitId-code for your units. (Go into the object editor menu and press ctrl+d.)
- After that in your if-statement only check if tempCount > 0
- Repeat the process only changing the unitId in the parameter.

Note that you can use this variable any time you want to count something temporarily.

_________________
Any one know how to adjust the message box on the forums, I have to scroll to the side when reading posts and such? - it doesn't break the text to fit my screen just long long lines. PM Me.
 
Last edited:
Level 17
Joined
Aug 19, 2007
Messages
1,380
Your farm example works. But I am now having trouble getting it to work with custom units (in this case the unit is based on the human gyrocopter / flying machine):

  • Custom script: set udg_tempCount = FixCountLivingPlayerUnitsOfTypeId ('h001:hgyr', Player(1))
Thanks for your patience by the way.
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
[K40$]-Spectre;2685277 said:
Your farm example works. But I am now having trouble getting it to work with custom units (in this case the unit is based on the human gyrocopter / flying machine):

  • Custom script: set udg_tempCount = FixCountLivingPlayerUnitsOfTypeId ('h001:hgyr', Player(1))
Thanks for your patience by the way.

A unit-id is always 4 characters. In this case 'h001' is the id and 'hgyr' is what you copied.
 
Level 17
Joined
Aug 19, 2007
Messages
1,380
Oh that makes sense. Thanks. I have one final question than I promise to shut up and give +rep :grin: :

If I want to send picked player instead of e.g. player(1) how to do that?

I tried through player variable and string variable but both give an expected name error:

  • Set tempPlayer = (Picked player)
  • Custom script: set udg_tempCount = FixCountLivingPlayerUnitsOfTypeId ('h001', tempPlayer)
  • Set tempPlayer = (Name of (Picked player))
  • Custom script: set udg_tempCount = FixCountLivingPlayerUnitsOfTypeId ('h001', tempPlayer)
 
Status
Not open for further replies.
Top