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

[General] How do I reduce lag on my map (Especially during combat)?

Status
Not open for further replies.
Level 4
Joined
Nov 16, 2019
Messages
55
So I've been working a long time on a huge RPG adventure map, and have started using a lot of triggers as well. I think I'm finally getting somewhat of a grip on the trigger-mechanics, however I am not too keen with what triggers that potentially could cause lag-spikes.

Now when I'm testing the map, it starts lagging immensely as soon as I enter combat against any enemy on the map. At all other times, it runs fine. It is only during combat. So hence the question, how do I reduce this lag? And what things cause lagging in custom maps usually? I really need to optimize and fix this, cause the lag-spikes I'm getting makes the map unplayable. (I use version 1.31 btw)


Fx. can triggers with the event: "A unit is attacked" cause a lot of lag during combat, even if conditions have specified only a specific unit or unit-type triggers it? I am well aware that you don't want to many triggers running at the same time, and should therefore turn off/on triggers. But a trigger like the one below here; can it cause lag during combat with all other units that aren't the "Wyvern"?

upload_2020-12-28_20-34-33.png


Also I have say; a demon mini-boss, which happens to be placed multiple places around the map. It has a "Fan Of Knives" ability called Reaping Flames, which also causes a flamestrike underneath each enemy hero when used. I'm using the "A unit finishes casting an ability" event here, and the trigger is turned on always, so does this also interfere in all other combat, despite having specified when to trigger in conditions?

upload_2020-12-28_20-31-45.png


(Just for clarification, the triggers shown work as intended, but if they can be optimized in case they could be causing the spikes, I'd like to hear your suggestions)

If these triggers should be alright, what kind of triggers would cause the most lag during combat? And are there other factors that would cause lag-spikes while fighting?
 
Last edited:
It's because of shockwaves (and possibly warstomp or earthquake abilities). I see in the first trigger that you order a unit to shockwave every time it is attacked. Shockwave (In addition to warstomp, earthquake and thunder clap) causes terrain deformation, which is known to cause massive lag spikes in more recent patches.

Secondly, you have a point and a unit group leak in your "Reaping Flames Druuvn" trigger. Before picking every unit you should save the location of the casting unit, then make a temporary unit group variable. Destroy/remove the variables when you are done with them.

EDIT: Here's how your trigger should optimally look (I also added some additional condition checks):

  • Reaping Flames Druuvn
    • Events
      • Unit - A unit Finishes casting an ability
    • Conditions
      • (Ability being cast) Equal to Reaping Flames (Druuvn)
    • Actions
      • Set TempLoc[0] = (Position of (Triggering unit))
      • Set TempGroup = (Units within 1500.00 of TempLoc[0])
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is alive) Equal to True
              • ((Picked unit) belongs to an enemy of (Owner of (Triggering unit))) Equal to True
              • ((Picked unit) is invulnerable) Equal to False
              • ((Picked unit) is A Hero) Equal to True
            • Then - Actions
              • Set TempLoc[1] = (Position of (Picked unit))
              • Unit - Create 1 Dummy - Druuvn (Reaping Flames) for Player 1 (Red) at TempLoc[1] facing Default building facing degrees
              • Unit - Add a 3.00 second Generic expiration timer to (Last created unit)
              • Unit - Add Scorch (Druuvn) to (Last created unit)
              • Unit - Order (Last created unit) to Human Blood Mage - Flame Strike TempLoc[1]
              • Custom script: call RemoveLocation (udg_TempLoc[1])
            • Else - Actions
      • Custom script: call RemoveLocation (udg_TempLoc[0])
      • Custom script: call DestroyGroup (udg_TempGroup)
 
Last edited:
Level 4
Joined
Nov 16, 2019
Messages
55
It's because of shockwaves (and possibly warstomp or earthquake abilities). I see in the first trigger that you order a unit to shockwave every time it is attacked. Shockwave causes terrain deformation, which is known to cause massive lag spikes in more recent patches.

Secondly, you have a point and a unit group leak in your "Reaping Flames Druuvn" trigger. Before picking every unit you should save the location of the casting unit, then make a temporary unit group variable. Destroy/remove the variables when you are done with them.

I am well aware of the shockwaves, however as I said in the beginning, the lag spikes apply to all mobs, including mobs without these kinds of spells. So the shockwaves aren't the main issue here.

Can you tell me how to do the temporary unit group thing you just talked about though? Because that could be really useful, as I have loads of these triggers.
 
Well then you should either A) Post your map so someone can take a look at it, or B) Post all triggers that relates to combat, and list all mobs/units and their abilities. Give more information so people can more accurately troubleshoot the issue.

Some other courses of action you can take is to delete/disable triggers one by one to see which one causes the lag.
 
Level 4
Joined
Nov 16, 2019
Messages
55
Well then you should either A) Post your map so someone can take a look at it, or B) Post all triggers that relates to combat, and list all mobs/units and their abilities. Give more information so people can more accurately troubleshoot the issue.

Some other courses of action you can take is to delete/disable triggers one by one to see which one causes the lag.


I'll try implementing the trigger you made, thanks!

I'll try and find all the potential lag-causing triggers as well and post them.
 
Level 4
Joined
Nov 16, 2019
Messages
55
@FeelsGoodMan

Here's another example trigger. This one is a priest, who resurrects his fellow bandits if they die before he does in a fight. I think the constant trigger-usage could be reduced greatly, if I knew of a way to limit especially periodic time events like this one. How would you make a trigger that activates this trigger, only whenever a controlled player unit is within range:1000?

upload_2020-12-28_21-39-11.png



I have a similar trigger here (In terms of it being periodic). The two triggers underneath it was a way I tried to limit the usage of Footsteps Of Doom (Where a flame-strike spawns underneath the boss every 3 seconds). Again, it would be easier, if I knew how to make a trigger, that activates the periodic trigger as long as a controlled player unit is within range. Also this would help in terms of all the triggers I have with "A unit is attacked" events.

Also in terms of optimization, is there any way you'd optimize this one here?:

upload_2020-12-28_21-40-46.png

upload_2020-12-28_21-41-18.png

upload_2020-12-28_21-41-39.png



Lastly I have this charge-ability, which is used by 3 mobs in 3 different variations of the same ability. I know it's a shockwave, but I was wondering if there was a way to make it turn off the periodic event after usage of the spell without interrupting it moving with the shockwave. Because right now, the trigger basically does, so the Wyvern is moved to the current point of the shockwave every 0.4 seconds. I made this trigger after watching a guide somewhere on how to make a charge-spell, but it seems incomplete, when the "Savage Charge Loop" trigger has to stay on forever afterwards.

upload_2020-12-28_21-59-25.png

upload_2020-12-28_22-0-7.png
 

Attachments

  • upload_2020-12-28_21-37-57.png
    upload_2020-12-28_21-37-57.png
    776.6 KB · Views: 21
  • upload_2020-12-28_21-38-9.png
    upload_2020-12-28_21-38-9.png
    776.6 KB · Views: 19
Level 4
Joined
Nov 16, 2019
Messages
55
@FeelsGoodMan

I also just tried to run the map while having most of the periodic time triggers turned off, and it doesn't lag now. (Not the charge though, but mainly events like the resurrection, the footsteps of doom and others that would be turned on most of the time)

Edit: I also tried just turning off just 3 triggers, these:

upload_2020-12-28_23-8-9.png


upload_2020-12-28_23-8-28.png


upload_2020-12-28_23-8-53.png


Turning off just these 3 triggers actually removed lag-spikes completely.

So if you could help come up with a trigger, that makes all of these periodic or "A unit is attacked" triggers turn on, ONLY when a controlled player-hero is nearby, then I think the lag might go away entirely. :)
 
Last edited:
Level 23
Joined
Jun 26, 2020
Messages
1,838
To add things:
Is not recomendable use "Unit is dead" condition, at least the units are heros, because after a time, if the unit dies it will desapear, so there is no unit to check if is alive, instead do.
  • Trigger1
    • Events
      • Unit - A unit dies
    • Conditions
      • (Dying unit) Equal to "Your unit"
    • Actions
      • Set "Your boolean" = True
  • Trigger2
    • Events
      • Time - Every 3.00 seconds of game-time
    • Conditions
      • "Your boolean" Equal to true
    • Actions
Also, where is TempPoint to remove it?
To this triggers
You should turn on and turn off when you are not using them:
  • Footsteps On
    • Events
      • Unit - A unit comes within 300.00 of Argunos the Desecrator (Standard) 0339 <gen>
    • Conditions
      • ((Triggering unit) is A Hero) Equal to true
    • Actions
      • Trigger - Turn On Footsteps Of Doom <gen>
      • Trigger - Turn On Footsteps Off <gen>
      • Trigger - Turn Off (This trigger)
  • Footsteps On
    • Events
      • Unit - A unit leaves Throne Chamber <gen>
    • Conditions
      • ((Triggering unit) is A Hero) Equal to true
    • Actions
      • Trigger - Turn Off Footsteps Of Doom <gen>
      • Trigger - Turn On Footsteps On <gen>
      • Trigger - Turn Off (This trigger)
For your spell, you must search for charge abilities.
 
Level 4
Joined
Nov 16, 2019
Messages
55
Is not recomendable use "Unit is dead" condition, at least the units are heros, because after a time, if the unit dies it will desapear, so there is no unit to check if is alive, instead do.

I'm not sure I understand what you're saying, because as of right now, I am able to check if the unit dies, without it disappearing because the "Hjelmir" unit resurrects them. I haven't had an issue in terms of the ressurrection.

Also, where is TempPoint to remove it?

Yea I actually noticed that about an hour ago and fixed the custom script haha :peasant-thumbs-up:

You should turn on and turn off when you are not using them:

Thanks! For whatever reason I had completely forgotten I could do that here.

For your spell, you must search for charge abilities.

It's not a spell I've downloaded, it's a shockwave ability, where a trigger has been attached to it, so you move with it each 0.4 seconds to the location of the wave cast. What I need help with, is to turn off the trigger below, but without stopping the trigger prematurely, as using "Unit finishes casting an ability" would likely stop it too early, as the ability is finished casting while the wave is travelling its distance... aaaand writing this I just thought to myself that maybe the "Unit finishes casting an ability" event might be useful anyways, and I could just add a "Wait" action before doing a "Turn off trigger". If it gets to wait like 1,5 seconds, it won't end the charge prematurely.
 
Level 23
Joined
Jun 26, 2020
Messages
1,838
It's not a spell I've downloaded, it's a shockwave ability, where a trigger has been attached to it, so you move with it each 0.4 seconds to the location of the wave cast. What I need help with, is to turn off the trigger below, but without stopping the trigger prematurely, as using "Unit finishes casting an ability" would likely stop it too early, as the ability is finished casting while the wave is travelling its distance... aaaand writing this I just thought to myself that maybe the "Unit finishes casting an ability" event might be useful anyways, and I could just add a "Wait" action before doing a "Turn off trigger". If it gets to wait like 1,5 seconds, it won't end the charge prematurely.
I didn't say your spell is downloaded, I said you must look for similar spells to look how they works, I recommend this: Unexpected Charge
 

Uncle

Warcraft Moderator
Level 63
Joined
Aug 10, 2018
Messages
6,457
Use the Unit-Type condition. You're creating a TON of Unit Groups which leak whenever you use this condition: "Random unit from units of type...".

  • Events:
  • Unit - A unit Is attacked
  • Conditions:
  • (Unit-type of (Attacked unit)) Equal to Wyvern
^This runs whenever a Wyvern is attacked.
 
Last edited:

Uncle

Warcraft Moderator
Level 63
Joined
Aug 10, 2018
Messages
6,457
Definitely, and these Unit Groups are leaking, meaning they never get removed from the game's memory.

Let's say you have a battle between 5 units.

Each unit attacks once per second.

Now let's say you have 5 triggers with the "A unit is attacked" Event, and each one of them uses the "Random unit from units of type..." Condition.

This would result in the creation of 25 Unit Groups per second.

This is a small sample size, I imagine your map could be creating 1000's of Unit Groups every minute. And these are permanent Unit Groups that remain in the game's memory taking up unnecessary space.

Check this out for more information about leaks: Memory Leaks

And here's how you should structure those "A unit is attacked" triggers:
  • example
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Unit-type of (Attacked unit)) Equal to Footman
    • Actions
      • -------- do stuff --------
So don't use "Random unit..." as a Comparison in a condition like you were doing. It's not the correct condition you were looking for and it leaks when used like this.

Do use it when you want to find a random UNIT (not unit-type) from a group of units. For example, if you had an ability that killed a random nearby enemy unit, this would be a good use of the function. However, you need to make sure that you structure the trigger correctly so that it doesn't leak the Unit Group. This concept is explained in Memory Leaks.

To break it down for you:
When you use "Random unit from units of type Wyvern", first a Unit Group is created, then the game search's through every single unit on the map, and for each unit it asks the question "Is this unit a Wyvern?", if this question returns True (yes, it is a Wyvern) then it adds that Wyvern to the newly created Unit Group. Once that's all said and done it then looks into the Unit Group and picks from it one unit at random, which in this case should almost always be a Wyvern (unless it found no Wyverns on the map).

In your case this whole process was completely unnecessary as the randomization and unit group were complete wastes of times and effort and resulted in unnecessary leaks.
 
Last edited:
Level 4
Joined
Nov 16, 2019
Messages
55
Definitely, and these Unit Groups are leaking, meaning they never get removed from the game's memory.

Let's say you have a battle between 5 units.

Each unit attacks once per second.

Now let's say you have 5 triggers with the "A unit is attacked" Event, and each one of them uses the "Random unit from units of type..." Condition.

This would result in the creation of 25 Unit Groups per second.

This is a small sample size, I imagine your map could be creating 1000's of Unit Groups every minute. And these are permanent Unit Groups that remain in the game's memory taking up unnecessary space.

Check this out for more information about leaks: Memory Leaks

And here's how you should structure those "A unit is attacked" triggers:
  • example
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Unit-type of (Attacked unit)) Equal to Footman
    • Actions
      • -------- do stuff --------

Thank you! This certainly explains a lot. So if I'm forced to use unit groups in a trigger, I should definitely delete the unit group afterwards if possible? Like @FeelsGoodMan did in his optimization of my Reaping Flames spell?
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,180
Your "Charge" trigger makes no sense. Not only is it leaking a group, one of the worst kinds of leak, but it is also is unlikely to do what you want it to.

Random unit in group literally means a random unit is selected from the group and then the test run on that unit. This will result in inconsistent behaviour due to the nature of randomness. For example a unit under attack which should cast the ability may never do so because it just happens to never be the one random unit that gets picked for the condition.

You likely are meaning to test if the attacked unit is inside the unit group. This should be a boolean test. Additionally you will want to cache the unit group as generating it each time without destruction not only causes a leak, but also is a computationally intensive operation on maps with a lot of units.
 

Uncle

Warcraft Moderator
Level 63
Joined
Aug 10, 2018
Messages
6,457
Thank you! This certainly explains a lot. So if I'm forced to use unit groups in a trigger, I should definitely delete the unit group afterwards if possible? Like @FeelsGoodMan did in his optimization of my Reaping Flames spell?
Yes. Here's an example of handing a Unit Group properly. It's also taking advantage of the correct Condition. Whenever a Footman is attacked, a random living enemy unit within 600 range of it is killed. I manually create the Point and Unit Group myself, which is necessary to avoid creating leaks, and then I manually clean them up by removing/destroying them at the end.
  • example
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Unit-type of (Attacked unit)) Equal to Footman
    • Actions
      • Set Variable TempPoint = (Position of (Attacked unit))
      • Set Variable TempGroup = (Units within 600.00 of TempPoint matching ((((Matching unit) is alive) Equal to True) and (((Matching unit) belongs to an enemy of (Owner of (Attacked unit)).) Equal to True)).)
      • Unit - Kill (Random unit from TempGroup)
      • -------- --------
      • -------- Clean up the memory leaks (Point + Unit Group): --------
      • Custom script: call RemoveLocation (udg_TempPoint)
      • Custom script: call DestroyGroup (udg_TempGroup)
Here's the same trigger but structured differently. I prefer this approach because I HATE working with the Matching unit conditions. It's much easier to add/remove Conditions this way, and you end up with the same result:
  • example
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Unit-type of (Attacked unit)) Equal to Footman
    • Actions
      • Set Variable TempPoint = (Position of (Attacked unit))
      • Set Variable TempGroup = (Units within 600.00 of TempPoint.)
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • ((Picked unit) is dead) Equal to True
                  • ((Picked unit) belongs to an ally of (Owner of (Attacked unit)).) Equal to True
            • Then - Actions
              • Unit Group - Remove (Picked unit) from TempGroup.
            • Else - Actions
      • Unit - Kill (Random unit from TempGroup)
      • -------- --------
      • -------- Clean up the memory leaks (Point + Unit Group): --------
      • Custom script: call RemoveLocation (udg_TempPoint)
      • Custom script: call DestroyGroup (udg_TempGroup)
Also, in regards to your first post, in most cases you want to use the Event "A unit STARTS the effect of an ability". This Event happens at the exact moment that an ability is executed (mana is spent, it goes on cooldown, it's effects happen).

Begins casting/Starts the effect/Begins channeling: These all allow you to reference Target unit of ability being cast and Target point of ability being cast.

Finishes casting/Stops casting: At this stage you no longer have access to that information.

Begins casting is useful for cases such as when you want to cancel an ability before it goes off (maybe you can only cast the ability if you have >= 1000 gold for example), Finishes casting can be useful for certain timing related situations but it can also have unwanted results.
 
Last edited:
Status
Not open for further replies.
Top