• 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.

UnitGroup parallel periodic trigger update

Level 2
Joined
May 27, 2024
Messages
13
Hi,

I have the following issues with unit groups (simplified examples):
  • SpellName Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to SpellName
    • Actions
      • Unit Group - Add (Triggering unit) to UnitGroupName
  • SpellName Loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in UnitGroupName and do (Actions)
        • // Some action to the unit, does not matter what
The issue is the second trigger always sees the unit group UnitGroupName as empty. I've printed the count, no matter how many units I add or remove from the unit group, count of UnitGroupName in the second trigger is always zero.

Why is this and how can I work around this?

For more context, I am trying to make a charge spell. Initially I was using a dummy thunder bolt to stun the caster with a custom buff, and checked Units in Playable Map Area that match condition Matching unit has Buff CustomBuff. This worked, however I wanted to "drag along" units found along the way with a similar dummy thunder bolt spell and what I found was that it took too long to cast the spell, and my unit would collide and stop in said units instead of draggin them along. So I'm trying to rework the spell to use unit groups because unit groups are faster, but it seems there is a synchronization issue between the two triggers.

Any and all help greatly appreciated!
 
Last edited:
Level 2
Joined
May 27, 2024
Messages
13
Update: It seems the issue is also present during the first trigger, as if the unit group does not exist at all. I've tried at map initialization to set the group to "Units in <No Region>" so that it is created, and then just to test the following as a sanity check:
  • SpellName Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to SpellName
    • Actions
      • Unit Group - Add all units of (Units in (Playable map area)) to UnitGroupName
      • Game - Display to (All players) the text: (String((Number of units in UnitGroupName)))
Game shows "0". :( I don't understand why...

And no, this variable is not used anywhere else.
 
Level 2
Joined
May 27, 2024
Messages
13
Solved! I turned on the "Every 0.03 seconds of game time" triggers after 1s elapsed time instead of having them on from the get-go. I think the trigger would start too fast and not see the unit group as created? If anyone knows the reason for this, please post in this thread, but yeah that was the solution.:
  • SpellName Init
    • Events
      • Time - Elapsed game time is 1.00 seconds
    • Conditions
    • Actions
      • Trigger - Turn on SpellName Loop <gen>
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,867
My guess is that you're destroying the Unit Group somewhere. You can't Add a unit to a Unit Group that doesn't exist anymore. However, if you SET a Unit Group variable then it will work again because you're creating a new Unit Group object for that variable to keep track of.

To clarify:
Unit Group variables simply track Unit Group objects, so there's actually two separate things at work here.
The variable itself is NOT the actual Unit Group, it just references it.
Here's an example of creating a Unit Group object, destroying it, and then trying to add a unit to it. This WON'T work:
  • Set MyGroup = (Units in playable map area)
  • Custom script: call DestroyGroup(udg_MyGroup)
  • Unit - Create 1 Footman
  • Unit Group - Add (Last created unit) to MyGroup
There is no Unit Group to be Added to since it has been destroyed.

The only way to get MyGroup to work again is by Setting it to something else:
  • Set MyGroup = ...
By doing this, we're creating a new Unit Group object for MyGroup to keep track of.

Also, there's a rare bug where your variables can lose their variable type and stop working. This one is tricky because you can still reference the variable in your triggers as normal but these references won't work in-game. The fix is to check the variable types of your variables inside of the variable editor or on the left-hand side of the trigger editor. If the variable type is blank then you will know that it is broken and can fix it by giving it a new type. Unfortunately, this will also break all of it's trigger related references.
 
Last edited:
Level 13
Joined
Jan 2, 2016
Messages
978
I'd guess that the game didn't have enough time to initialize everything. But what I would do instead is:
Make a timer and in your first trigger, check if the group is empty (or something... before adding the unit to the group, that is), and if it is - start the timer.
And make the second trigger execute when the timer you created expires.
You can also stop the timer, if there are no more units in the group. You'll make your code a lot more efficient this way.
 
Level 2
Joined
May 27, 2024
Messages
13
This smells like an erroneous/premature set bj_wantDestroyGroup = true that is destroying the group unexpectedly.
Hey man, it wasn't, I removed all the `set bj_wantDestroyGroup = true`commands. It was the initialization. What fixed it was turning on the trigger after 1s of time instead of keeping it on initially. It's strange but 🤷‍♂️.
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
It's strange but 🤷‍♂️.
Sure, but even in WC3 stuff does not just happen randomly without explanation. The fix you implemented might have avoided the problem, but it didn't stop or change whatever was happening so to say that it was a 'correct' solution is not true.

I probably sound hostile/condescending, and that is not my intent. I am trying to steer you away from "IDK that's some weirdass bug but doing this unrelated thing fixed it" and toward "okay, how could changing this logically affect what I'm doing, and what does that imply about what is really going on under the surface?" Taking such an approach in mapmaking will save you headache over time, make you a better troubleshooter, and expand your knowledge of WC3's intricacies.

In this scenario here are the irrefutable facts:
  1. Variables are initialized with a default value in the variable editor. As long as the map init thread doesn't crash (unlikely, and you'd notice if it did), all non-array variables will be assigned their default value before any game-time has elapsed.
  2. Adding a unit to a group then immediately counting the units in the group and getting a 0 count means the group variable you attempted to do that with was null.
  3. A null group variable either means it was never initialized (like a group array could be) or has been destroyed with DestroyGroup(). The bj_wantDestroyGroup check in many BJs invokes a DestroyGroup if that boolean is set to true.

By 1 we know that the group variable was initialized to <empty group>, since that would always happen. Crashing the init thread would be very obvious since other things you expect to run wouldn't be running (the periodic trigger is one of them). By 2 we know that the group has been destroyed at some time before the periodic trigger runs. By 3 we know the only ways in GUI to destroy a group are by manually calling DestroyGroup or by setting that bj_wantDestroyGroup flag, so that must be happening somewhere.

As silly as it sounds based on what you said, this is the line of inquiry that leads you to understand what actually happened when you delayed the periodic trigger. Something is either destroying the group or reassigning the group variable to something else; it's the only explanation. The group won't destroy itself, and it wouldn't start empty.
  • Set YourGroup = (Units in (No region)) //don't use this, maybe it doesn't like being passed the null region
  • -------- you can use units of type or units owned by player instead --------
 
Last edited:
Level 2
Joined
May 27, 2024
Messages
13
Hm, you're right, it has to make sense. My issue is I have no idea how the map editor works. It's not like I have a rulebook or the source code to it, to understand how it works down to a T. 😅 I assumed for example that maybe global variables are not initialized immediately at time elapsed t=0.0, and that triggers are optimized to turn off if the trigger encounters an inexisting global variable at runtime the first time it runs (or something to that effect). Does it sound ridiculous? Yes. Is it based on any evidence? Not really, more like a presumptious top-down explanation based on a severe lack of understanding in the inner workings of the map editor. 😁

But I think you're right in this case. I worked very messily. For example, I remember printing the usergroup unit count immediately after adding a unit to it, and it showing "0". But it's very possible that in parallel, the every 0.03s periodic trigger still had that destroy group call in it. I don't remember whether it had it or not, I was in a frenzy throwing shit at the wall and seeing what sticks. 😅 Then I printed the count again, and it showed "1". So yeah.

In the end, I reverted back to the old approach of debuffing units and constructing a dynamic user group based on buff every 0.03s and using that. In the meanwhile I've added two more custom spells, a knock-up and a leap, both made from the ground up and using periodic triggers and usergroups like the approach in the OP of this thread. Both worked wonderfully, unlike the custom spell that I reference in this thread. It is very possible that I made several mistakes and was accidentally deleting the usergroup somewhere else. It is very possible that if I went back and re-made the trigger like in the OP, except paying more attention this time, that it'd work just as fine. So I agree wholeheartedly. If I ever re-do it, I will necro this thread to confirm this.

P.S. I have also considered the possibility of the unit indexer I'm using not updating the custom values of the units fast enough, and while that is not the case here thank God (I tested), I think it's good to remember generally to check external dependencies used in triggers for potential issues like that.
 
Top