• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[Solved] Action picking unit matcing condition not working

Level 4
Joined
Dec 12, 2018
Messages
35
So, I'm trying to remove all units owned by Player 4 that are not structures and I thought it would be an easy "Pick every unit matching condition and do action" line but, for some reason, it's not working. It's deleting also all the structures.

Here's the action.
1729596225157.png


Can somebody help?
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,877
I would always use the Do Multiple Actions option:
1729597250381.png

It's far more flexible and easier to work with.

This approach works fine for me and fixes the memory leak as well:
  • Remove
    • Events
      • Time - Elapsed game time is 2.00 seconds
    • Conditions
    • Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units owned by Player 4 (Purple).) and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is A structure) Equal to False
            • Then - Actions
              • Unit - Remove (Picked unit) from the game
            • Else - Actions
 

Attachments

  • Remove Units.w3m
    17.4 KB · Views: 4
Level 4
Joined
Dec 12, 2018
Messages
35
Thanks! That did it perfectly.

About leaks, I confess I don't understand them entirely. I usually create a variable with the unit group I'm using and destroy it after whatever I was trying to do with it has finished. Something like this:

1729600079850.png


After that I would use the same variable to whatever I need again.


Is that a valid way to avoid leaks? I acknowledge I'm kinda afraid of using custom scripts because I have basically no idea about Jass.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,877
Thanks! That did it perfectly.
No problem. I'm not too sure what was wrong with your original method to be honest.

Is that a valid way to avoid leaks?
Unfortunately, that does NOT avoid the memory leak.

About leaks, I confess I don't understand them entirely.
First off: A memory leak is just some information (data) that your computer is keeping track of even though it's no longer needed. It's sort of like a file you've forgotten to delete.

So this Action here is what's creating the Unit Group memory leak:
  • Set unitgroup = (Units in (Playable map area) owned by Player 4 (Purple))
This Action runs code that does the following:
1) It creates a brand new Unit Group object. Think of it like if you created a brand new Unit. Your unitgroup variable then tracks that object.
2) It fills this Unit Group object with the Units that match your filter -> (Units owned by Player 4).
3) You can then use the Pick Every Unit action to interact with the units inside of this specific Unit Group object. You can do this at anytime as long as you're tracking the object in a Unit Group variable (like unitgroup).

With that in mind, understand that this memory leak only occurs when you lose track of the Unit Group object without Destroying it first.

Here is the main way to successfully Destroy a Unit Group object and fix the memory leak (I used an alternative method in my first post):
  • Actions
    • Set unitgroup = (Units in (Playable map area) owned by Player 4 (Purple))
    • Custom script: call DestroyGroup( udg_unitgroup )
When you run that Custom Script you're not destroying the unitgroup variable, you're destroying the Unit Group OBJECT that was being TRACKED by that variable. Hopefully that makes sense.

Here's an example of losing track of a Unit Group object:
  • Actions
    • Set unitgroup = (Units in (Playable map area) owned by Player 4 (Purple))
    • Set unitgroup = (Units in (Playable map area) owned by Player 1 (Red))
    • Custom script: call DestroyGroup( udg_unitgroup )
We've created two Unit Group objects in this trigger, since each time you use "Set unitgroup" it creates a brand new object. The issue here is that we've lost track of the first object since our unitgroup variable has been assigned to track the second Unit Group object. This means that we can NEVER get rid of the first Unit Group object since our Custom Script is only able to reference and destroy the second Unit Group object. So we've made a mistake and accidentally created 1 memory leak here. To fix this you would need to introduce another Custom Script after the first "Set unitgroup".

Now keep in mind that practically every map has memory leaks and most of the time they aren't going to cause noticeable damage since they take up such a small amount of space. But if you're not careful with your triggers then you may end up creating A LOT of leaks, for example maybe you have a Timer that runs every 0.01 second which then runs a Trigger that unintentionally creates 10 Memory Leaks. That's 10 * 100 = 1000 Memory Leaks per second! It could really add up over time. It'd be like if you created 1000 almost-empty text files on your computer every second, they may take up a VERY SMALL amount of space but eventually they will start to eat up your computer's storage.

That's why you should try to delete (Destroy/Remove) them. Or as we say, "clean up" your memory leaks.

Also, here are the main kinds of memory leaks you'll deal with most of the time:
Points, Unit Groups, Player Groups, Special Effects.
If you take care of these your map should be fine. (It'll probably be fine regardless)
 
Last edited:
Level 4
Joined
Dec 12, 2018
Messages
35
Thank you so much. I've tried from some time ago understanding the issue with leaks but always thought using variables would clean them.

As you say, I don't think those leaks would be a significant problem (most complex triggers I use are for cinematics and quests and they usually only trigger once) but it's really nice starting to get a grasp here.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,877
Thank you so much. I've tried from some time ago understanding the issue with leaks but always thought using variables would clean them.

As you say, I don't think those leaks would be a significant problem (most complex triggers I use are for cinematics and quests and they usually only trigger once) but it's really nice starting to get a grasp here.
You're welcome.

I should mention that you can manage your Unit Groups in a way where you never have to worry about memory leaks. The same is true for Player Groups.

For example, here I am creating ONE single Unit Group object. This works as long as I NEVER Set this variable again:
  • Events
    • Time - Elapsed game time is 0.00 seconds
  • Conditions
  • Actions
    • Set Player_4_Unit_Group = (Units in (Playable map area)) owned by Player 4 (Purple))
This captures any pre-placed units owned by P4.

We can then manage this Unit Group object throughout the entire game, Adding new units to it as they come into play:
  • Events
    • Unit - A unit Enters (playable map area)
  • Conditions
    • (Owner of (Triggering unit)) Equal to Player 4 (Purple)
  • Actions
    • Unit Group - Add (Triggering unit) to Player_4_Unit_Group
And Removing units from it as they die:
  • Events
    • Unit - A unit Dies
  • Conditions
    • (Owner of (Triggering unit)) Equal to Player 4 (Purple)
  • Actions
    • Unit Group - Remove (Triggering unit) from Player_4_Unit_Group
With this setup you will have access to Player 4's living units at ALL times. This makes your life much easier and it's quite efficient.

You can now interact with these Units in ANY trigger and it'll work as expected without leaks:
  • Events
    • Unit - A unit Starts the effect of an ability
  • Conditions
    • (Ability being cast) Equal to My Cool Custom Ability
  • Actions
    • Unit Group - Pick every unit in Player_4_Unit_Group and do (Actions)
      • Loop - Actions
        • Unit - Kill (Picked unit)


Keep in mind that the "A unit Dies" Event won't happen if you Remove the units from the game since they technically didn't "die":
  • Actions
    • Unit - Remove (Some unit) from the game
That means the removed Units will remain in your Unit Group even though they're gone, which could cause issues. This isn't too difficult to fix, you can use a system to detect when a unit is Removed from the game or just do this wherever you remove them:
  • Actions
    • Unit - Kill (Some unit)
    • Unit - Remove (Some unit) from the game
That'll cause the "Dies" Event to run, Removing the unit from the Unit Group, while also removing the unit from the game. You won't see or hear it's death, but it did technically die. Alternatively, you can avoid the "Dies" Event and just Remove them from the group manually:
  • Actions
    • Unit Group - Remove (Some unit) from Player_4_Unit_Group
    • Unit - Remove (Some unit) from the game
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,877
That's great to hear.

You can even take it a step further by changing your Unit Group variable to an Array. That would allow those three triggers to work for everyone:
  • Events
    • Time - Elapsed game time is 0.00 seconds
  • Conditions
  • Actions
    • Player Group - Pick every player in (All players) and do (Actions)
      • Loop - Actions
        • Set PN = (Player number of (Picked player))
        • Set Player_Unit_Group[PN] = (Units in (Playable map area)) owned by (Picked player))
  • Events
    • Unit - A unit Enters (Playable map area)
  • Conditions
  • Actions
    • Set PN = (Player number of (Owner of (Triggering unit))
    • Unit Group - Add (Triggering unit) to Player_Unit_Group[PN]
  • Events
    • Unit - A unit Dies
  • Conditions
  • Actions
    • Set PN = (Player number of (Owner of (Triggering unit))
    • Unit Group - Remove (Triggering unit) from Player_Unit_Group[PN]
So Player_Unit_Group[1] = Player 1's units, Player_Unit_Group[4] = Player 4's units, etc.

You just need to ensure that you've set the Size of your Array to 28 inside of the Variable Editor. That creates 28 Unit Group objects ready to be used at indexes [1] -> [28]. (You can also use [0] as well)

Take this same design pattern and try to apply it wherever possible and you'll find that most if not all of your triggers will become easier to work with as well as perform better. I think of it like having a solid foundation to build on.

This "Event-based triggering" is much better than what "rookies" have a natural tendency to do: Every 0.10 seconds -> Create a brand new Unit Group -> Fill it with the same units over and over again. Not to bash them, we've all been there and it's the obvious choice for someone who doesn't know all of the quirks of the editor just yet.
 
Last edited:
Top