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

Map File too big

Status
Not open for further replies.
Level 5
Joined
Jan 22, 2023
Messages
51
Need a real help here, and advice if it's fixable

I worked on a map for couple months and it's around 33mb big... Couldn't launch it on multiplayer while testing it with friends, so we found some patch fixes to increase warcraft's 8mb to more. It worked and we started playing. We played for around 30minutes and everything started lagging until it was unplayable.

Map has 1400 units, 11000 doodads, weighs 33mb, has many triggers. Can attach this map if needed

Need real help because worked on this map for sooo so long, thanks
 
Level 5
Joined
Jan 22, 2023
Messages
51
used scripts to clean everything that leaked (I think so.. I'm still little bad at this so.. maybe it can leak?)
 
Last edited:
Level 5
Joined
Jan 22, 2023
Messages
51
Would there be a slight chance you could see what else leaks there (after attaching a map)? Can't really tell what is
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
It's quite a tall order to figure out what could be causing such issues across an entire map with hundreds or thousands of lines of code. You can look directly at the process' memory usage in the Task Manager to see if/how much it's growing over time when it 'should' be relatively static.

Just run the map single player AFK for a while without doing anything and see how that goes. Then disable a bunch of triggers and run again, noting the difference in memory after the same duration. Disable more/fewer things and try again. This can help narrow down which triggers contribute to memory leak problems.
 
Level 5
Joined
Jan 22, 2023
Messages
51
Just ran the map in singleplayer, AFK'ed it, and nothing really happened, after almost an hour (we played yesterday for 30mins and it was happening). I have some questions, because I can only assume what causes issues:

1. Can a trigger leak only after using it for first time, or does it leak, if it leaks already after beginning the game? (Example: can it be that nothing leaks, but after using a custom ability it will start gradually lagging?)
2. Can it be due to high number of units on the map? I noticed that memory usage increases with every produced unit
3. After starting a map, warcraft is already at 800/850mb of memory usage, is it normal or too high for a start?
4. Can doodads cause the issue?

I'll fix all the leaks I am noticing right now in triggers, but it kind of seems like it's not the leaks that cause the issue, because memory usage isnt increasing with time

Edit: for some reason after an hour usage dropped from 800 to 400mb (??) no idea how, was afking all the time
 
Last edited:
You'll need to make the triggers happen in order for the leaks to accumulate in order to see leaks when watching the memory.
Things that run with a short timer (every 1.0 seconds or shorter interval or something like that) and spells that you "spam" a lot will likely cause more issues when they leak rather than "after 10 minutes, do this one thing" that leak.

Speaking of "lowering" memory, this is classic case of you operating system returning memory that wasn't really used. the 800 it "gobbled up" because you had it available and started using more and more. If you only use 400 of those for a while, the OS will "return" the unused parts to be used for other things.
Task manager can only be used as an approximation.
 
Level 5
Joined
Jan 22, 2023
Messages
51
I have couple triggers that run with a command "every 1.0 seconds" because it's a boss health reset trigger, so it's checking every second if there's nearby, if not, reset boss health. Is there any way to change it to lag less then? maybe making it check every 60sec or something? (i have like 10 of such triggers)

also there are some kind of spammable, but I guess theres no way to go around it to reduce the issue, right?

And if I understood correctly I shouldn't rely on task manager to determine how much of system memory it's using?
 
Level 5
Joined
Jan 22, 2023
Messages
51
I think I took care of every trigger on the map right now, but kind of scared of timers, does that one leak in any way?

  • Health Reset for Doggy guy
    • Events
      • Time - Every 60.00 seconds of game time
    • Conditions
      • (DogBoss is alive) Equal to True
    • Actions
      • Set DB_Point = (Position of DogBoss 0423 <gen>)
      • Set DB_AoE = 1000.00
      • Set DB_Tempgroup = (Units within DB_AoE of DB_Point matching (((Matching unit) belongs to an ally of Player 1 (Red)) Equal to True))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in DB_Tempgroup) Equal to 0
        • Then - Actions
          • Unit - Set life of DogBoss 0423 <gen> to 100.00%
          • Unit - Order DBBoss to Move (Center of DogBoss <gen>)
        • Else - Actions
      • Custom script: call DestroyGroup(udg_MO_Tempgroup)
      • Custom script: call RemoveLocation(udg_MO_Point)
Also do Real variables leak?
 
Level 5
Joined
Jan 22, 2023
Messages
51
Thanks, fixed that one, should work fine now. I'll re-edit this post if I get the map to work without lagging after some more tweaks!
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
You definitely don't need to change Periodic Intervals from 1.00 second to 60.00 seconds, that's not the cause of this problem.

You would notice an immediate performance drop if you did a heavy task too often, for example enumerating over 1000 units every 0.01 seconds and maybe running several Actions for each (Picked unit).

As others have said, memory leaks are what will cause the gradual reduction in map performance. The key word here being gradual.

I'm going to assume that you still have a lot of memory leaks in your map. Or, a handful of really nasty ones. It's very easy to leak Unit Groups so I would be on the lookout for those.

Also, try to find Events that happen often like:
A unit Dies
A unit is Attacked
A unit casts an Ability

These would be bad places to have a memory leak since they're running all of the time (assuming your map has a lot of combat).
 
Last edited:
Level 5
Joined
Jan 22, 2023
Messages
51
Umm well I fixed triggers with unit groups like that
  • Forest Slumber
    • Events
      • Unit - A unit starts an effect of the ability
    • Conditions
      • (Ability being cast) Equal to Forest Slumber
    • Actions
      • Set Temppoint = (Target point of ability being cast)
      • Set Caster = (Casting unit)
      • Set Tempgroup = (Units within 300.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
              • ((Owner of (Picked unit)) is an enemy of (Owner of Caster)) Equal to True
            • Then - Actions
              • Unit - Create 1 dummy for (Owner of Caster) at Temppoint facing generic building degrees
              • Unit - Set level of Forest Slumber (dummy) for (Last created unit) to (Level of Forest Slumber for (Triggering unit))
              • Unit - Order (Last created unit) to Undead Dreadlord - Sleep (Picked unit)
              • Unit - Make (Last created unit) Invulnerable
              • Unit - Add a 2.00 second generic expiration timer to (Last created unit)
            • Else - Actions
      • Custom script: call DestroyGroup(udg_Tempgroup)
      • Custom script: call RemoveLocation(udg_Temppoint)
And for triggers that use "Dies" event I do
  • AS Summon
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Level of Heavens Fury for (Triggering unit)) Higher than 0
      • ((Triggering unit) is in AS_CooldownGroup) Equal to False
    • Actions
      • Set AS_Caster = (Triggering unit)
      • Set AS_Temppoint = (Position of (Triggering unit))
      • Unit - Create 1 dummy for (Owner of AS_caster) at AS_Temppoint facing generic building degrees
      • Unit - Set level of Heavens Fury dummy for (Last created unit) to (Level of Heavens Fury for (Triggering unit))
      • Unit - Order (Last created unit) to Undead Dreadlord Inferno AS_Temppoint
      • Unit - Add a 2.00 second generic expiration timer to (Last created unit)
      • Unit Group - Add (Triggering unit) to AS_CooldownGroup
      • Wait 300.00 game-time seconds
      • Unit Group - Remove (Triggering unit) from AS_CooldownGroup
      • Custom script: call RemoveLocation(udg_AS_Temppoint)
Kind of the same for attacked event. I think it doesn't leak, but may be wrong, kind of got afraid when Uncle listed those Events lmao
 
Level 5
Joined
Jan 22, 2023
Messages
51
Why will the variable itself leak? Good call, didnt notice that I've put the remove after wait, it would take too long for game to remove it

Attacked event looks like this
  • Nature's Wrath
    • Events
      • Unit - A unit is Attacked
    • Conditions
      • ((Attacked unit) has buff Nature's Wrath ) Equal to True
      • ((Owner of (Attacked unit)) is an enemy of (Owner of (Attacking unit))) Equal to True
    • Actions
      • Set Temppoint = (Position of (Attacking unit))
      • Unit - Create 1 dummy for (Owner of (Attacked unit)) at GN_Point facing deafult building degrees
      • Custom script: call RemoveLocation(udg_Tempoint)
      • Unit - Set level of Entangling Roots dummy for (Last created unit) to (Level of Nature's Wrath for (Triggering unit))
      • Unit - Add a 2.00 second OgĂłlny expiration timer to (Last created unit)
      • Unit - Order (Last created unit) to Night Elf Keeper of the Grove Entangling Roots (Attacking unit)
 
Why will the variable itself leak? Good call, didnt notice that I've put the remove after wait, it would take too long for game to remove it
I formulated myself in a bad way, the reason is remove after wait.
If this trigger can (for some reason) trigger again within 300 seconds, it will leak. I guessed that was the case.
 
Level 5
Joined
Jan 22, 2023
Messages
51
I formulated myself in a bad way, the reason is remove after wait.
If this trigger can (for some reason) trigger again within 300 seconds, it will leak. I guessed that was the case.
I see, moved the remove so it removes before the wait command, won't leak anymore. Anyway in this case it's not likely that it would run withing 300 seconds again, but good to keep it leakless
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
A good practice is to clean up your leaks (variables) the moment you're done using them. For example:
  • Set Point = (Center of map)
  • Unit - Create 1 Dummy at Point...
  • Custom script: call RemoveLocation(udg_Point)
  • Unit - Add some ability to (Last created unit)
  • Unit - Add a 2.00 second expiration timer to (Last created unit)
  • // etc... //
People tend to put their Custom Script at the bottom of the trigger for organizational purposes but it's not really a good habit.

And you say you're cleaning up the Unit Group leaks, but are you aware of every Condition and Action that creates them? There's a lot of different functions that can create a Unit Group leak as well as a Point leak.

 
Last edited:
Level 5
Joined
Jan 22, 2023
Messages
51
People tend to put their Custom Script at the bottom of the trigger for organization purposes but it's not really a good habit.
So I should to put the Custom Script into "If" command right after the trigger stops using the variable? Somewhere heard that it's better to put it outside "if" but I'm a bot in this, and might have read a bad advice
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
That's not what I'm saying.

My point is simple: You should clean up your memory leaks as soon as possible.

In your AS Summon trigger you made the mistake of cleaning up the Point at the end of the trigger, which also happened after a Wait action. Had you cleaned up the Point immediately after it was done being used, which was after you ordered the Dummy unit to cast Inferno, you wouldn't have had this issue.

I'm suggesting that you form a habit of doing this so that you can avoid similar issues in the future.

The order of Actions is very important!
 
Last edited:
Level 5
Joined
Jan 22, 2023
Messages
51
I've fixed that already, didn't notice I've put the Custom Script after Wait Action. I have also put now all Remove actions right after trigger stops using the Variable so it should be kind of cleaned.

What do you exactly mean by this?
And you say you're cleaning up the Unit Group leaks, but are you aware of every Condition and Action that creates them? There's a lot of different functions that can create a Unit Group leak as well as a Point leak.
I actually have read these posts that you linked and talking about Unit Group/Player Group leaks they said to put it to variable and destroy with either
  • Custom script: call DestroyForce(udg_PlayerGroup)
for PlayerGroup, and
  • Custom script: call DestroyGroup(udg_Group)
To destroy Unit Groups, which I think I've done in the trigger above
Or I absolutely misunderstood what you said
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
Uncle is referring to things like this:
  • Conditions
    • (Number of units in (Units in SOME REGION <gen>)) greater than 0
    • (Distance between (Position of (Triggering Unit)) and (Position of (Target unit of ability being cast))) less than 250.00
That’s a unit group and a couple points that will become leaks when used in these ways. You have to set variables before checking them in conditions and then clean them up afterward. If this sort of a check happens in a trigger condition then you’ll have to move the condition to an If-block that contains all the actions and then do your setup/cleanup before/after the block.
 
Level 5
Joined
Jan 22, 2023
Messages
51
So I should leave the conditions empty, set the variable for them and put these conditions into If Action, right?
 
Level 5
Joined
Jan 22, 2023
Messages
51
If that's right then does these two leak? since there's no Points and Unit Groups
  • (Level of Heavens Fury for (Triggering unit)) Higher than 0
  • ((Triggering unit) is in AS_CooldownGroup) Equal to False

  • ((Attacked unit) has buff Nature's Wrath ) Equal to True
  • ((Owner of (Attacked unit)) is an enemy of (Owner of (Attacking unit))) Equal to True
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
So I should leave the conditions empty, set the variable for them and put these conditions into If Action, right?
^ You are correct.

And no, neither of those examples leak.

I recommend reading more about memory leaks if you're struggling to understand the concept. Those two links I posted should clear everything up. In the second link I mention a rule of thumb that you can follow which should keep you on the right track.
 
Level 5
Joined
Jan 22, 2023
Messages
51
I'm in the middle of studying those two links as we speak :xxd: also reading other posts to understand it even more. Thank you for your help! At the moment as I see, my triggers don't leak!
 
Level 5
Joined
Jan 22, 2023
Messages
51
Sorry for coming back to this thread but.. is this one leaking? Everytime I use it it starts hella lagging, until it's unplayable.. then I wat around 30seconds and everything goes back to smooth gameplay
  • Weakened Morals
    • Events
      • Unit - A unit starts the effect of an Ability
    • Conditions
      • (Ability being cast) Equal to Weakened Morals
    • Actions
      • Set Temppoint = (Target point of ability being cast)
      • Set caster = (Casting unit)
      • Set Tempgroup = (Units within 500.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
              • ((Owner of (Picked unit)) is an enemy of (Owner of caster)) Equal to True
            • Then - Actions
              • Unit - Create 1 dummy for (Owner of caster) at Temppoint facing default building facing degrees
              • Unit - Set level of Weakened Morals (dummy) for (Last created unit) to (Level of Weakened Morals for (Triggering unit))
              • Unit - Order (Last created unit) to Undead Necromancer Banish (Picked unit)
              • Unit - Make (Last created unit) Invulnerable
              • Unit - Add a 2.00 second generic expiration timer to (Last created unit)
            • Else - Actions
      • Custom script: call DestroyGroup(udg_Tempgroup)
      • Custom script: call RemoveLocation(udg_Temppoint)
And I also has a weird.. weird going on. I have a trigger that works fine when I test it myself, but when I tried it with friends today... He was spawning these mobs every second, not just once... can't understand why

Edit: Tested now using more units to attack the boss and the issue occured, but Boss was randomly spawning the unit, even though I removed the spell from the Boss and he wasn't taking any damage

  • Faze 1 Summon
    • Events
      • Unit - Faceless Brain 0372 <gen>'s life becomes Lesser than or Equal to 65000.00
    • Conditions
    • Actions
      • Trigger - Turn off (This trigger)
      • Set MO_Point = (Position of (Triggering unit))
      • Unit - Add Summoning 1 to MOBoss
      • Unit - Order MOBoss to Undead Dreadlord Inferno MO_Point
      • Custom script: call RemoveLocation(udg_MO_Point)
      • Unit - Make MOBoss Invulnerable
  • Faze Vuln
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Triggering unit) Equal to Summon
    • Actions
      • Unit - Make MOBoss Vulnerable
      • Unit - Remove Summoning 1 from MOBoss
MOBoss is a set variable in other trigger to the boss
"Summon" is a variable set to the unit-type that the boss summons
Also we played today with friends and no more performance drops! Everything works fine!!! The only thing that wasn't working was Weakened Morals spell and that Boss trigger. We weren't using the spell because it was lagging too much. Thank you all for advices with leaks etc, because of that my map is saved! :thumbs_up:
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
No, it wasn't leaking, but here's an improved version of your Weakened Morals trigger that should help:
  • Weakened Morals
    • Events
      • Unit - A unit starts the effect of an Ability
    • Conditions
      • (Ability being cast) Equal to Weakened Morals
    • Actions
      • Set Caster = (Casting unit)
      • Set CastingPlayer = (Triggering player)
      • Set TempPoint = (Target point of ability being cast)
      • Set TempGroup = (Units within 500.00 of TempPoint)
      • Unit - Create 1 Dummy (Uncle version) for CastingPlayer at TempPoint facing default building facing degrees
      • Custom script: call RemoveLocation(udg_TempPoint)
      • Set Dummy = (Last created unit)
      • Unit - Add Weakened Morals (dummy) to Dummy
      • Unit - Set level of Weakened Morals (dummy) for Dummy to (Level of Weakened Morals for Caster)
      • Unit - Add a 0.20 second generic expiration timer to Dummy
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • Set Target = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Target is Alive) Equal to True
              • (Target belongs to an enemy of CastingPlayer) Equal to True
            • Then - Actions
              • Unit - Order Dummy to Undead Necromancer Banish Target
            • Else - Actions
      • Custom script: call DestroyGroup(udg_TempGroup)
Make sure your Dummy unit is based on the Locust unit with the following settings:
Movement Type = None, Speed Base = 0, Attacks Enabled = None, Model = None, Shadow = None

You really only need 1 Dummy unit with these settings for most if not all of your custom spells. It can cast any number of spells instantly without issue.
That being said, some custom spells use Dummy units as moving missiles which may require different settings than these.

And remember that units have AI that will order them to cast certain spells under certain circumstances. I image Inferno is coded to cast when there are multiple targets nearby. What you can do is disable this ability whenever it's not being manually forced to cast.

Also, Summon looks like a Unit variable, not a Unit-Type variable, so it's not "Set to the unit-type that the boss summons" like you said. Unless there's just a weird translation error or something. A Unit-Type comparison is what you want to use here.
 
Last edited:
Level 5
Joined
Jan 22, 2023
Messages
51
No, it wasn't leaking, but here's an improved version of your Weakened Morals trigger that should help:
  • Weakened Morals
    • Events
      • Unit - A unit starts the effect of an Ability
    • Conditions
      • (Ability being cast) Equal to Weakened Morals
    • Actions
      • Set TempPoint = (Target point of ability being cast)
      • Set Caster = (Casting unit)
      • Set CastingPlayer = (Triggering player)
      • Set TempGroup = (Units within 500.00 of TempPoint)
      • Unit - Create 1 Dummy (Uncle version) for CastingPlayer at TempPoint facing default building facing degrees
      • Custom script: call RemoveLocation(udg_TempPoint)
      • Set Dummy = (Last created unit)
      • Unit - Set level of Weakened Morals (dummy) for Dummy to (Level of Weakened Morals for Caster)
      • Unit - Add a 0.20 second generic expiration timer to Dummy
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • Set Target = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Target is Alive) Equal to True
              • (Target belongs to an enemy of CastingPlayer) Equal to True
            • Then - Actions
              • Unit - Order Dummy to Undead Necromancer Banish Target
            • Else - Actions
      • Custom script: call DestroyGroup(udg_TempGroup)
Make sure your Dummy unit is based on the Locust unit with the following settings:
Movement Type = None, Speed Base = 0, Attacks Enabled = None, Model = None, Shadow = None

You really only need 1 Dummy unit with these settings for most if not all of your custom spells. It can cast any number of spells instantly without issue.
That being said, some custom spells use Dummy units as moving missiles which may require different settings than these.

And remember that units have AI that will order them to cast certain spells under certain circumstances. I image Inferno is coded to cast when there are multiple targets nearby. What you can do is disable this ability whenever it's not being manually forced to cast.

Also, Summon looks like a Unit variable, not a Unit-Type variable, so it's not "Set to the unit-type that the boss summons" like you said. Unless there's just a weird translation error or something. A Unit-Type comparison is what you want to use here.


I will try that tomorrow, because it's late for me already. Do you think that this improvement will fix the lag? Because I don't know what causes it if you say it wasn't leaking

About Dummy, it's set correctly

And about that inferno spell - I've put a really long cooldown (because during whole encounter he casts it only once) and I've put a cooldown reset Action in the Boss Reset trigger so I think it'll do the trick

I think that with the Unit-type I just gave myself extra work for absolutely no reason. In the other trigger I've set Summon variable to the unit that the boss summons... and then in the main trigger decided to make a Unit comparision instead of straight up using Unit-Type comparison, that's my bad, gonna fixed it tomorrow, thanks for noticing

My only concern is that Weakened Morals spell and the lag it causes, but going to try with the improved version of the trigger tomorrow, will leave feedback after fixing it, thanks!
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
So your trigger looked pretty normal aside from some inefficient use of Actions/Conditions/Variables. The only thing that stood out was the Action making the Dummy unit Invulnerable, which isn't needed and could very well cause the weird performance issue. Another possibility is that you have another trigger that runs when the Dummy unit casts Banish that contains the source of the performance issues.

At the very least the trigger will be more efficient now because you're creating 1 Dummy unit instead of potentially 100's of them (if there were 100 enemy targets for example). You weren't excluding Dead units which meant the corpses were creating Dummy units as well. You can imagine things could potentially go wrong if you try to tell a Unit to do something impossible like cast Banish on a Structure or a Dead unit. Warcraft 3 can be good about handling these impossible requests but it's still a good idea to avoid giving the request in the first place.
 
Last edited:
Level 5
Joined
Jan 22, 2023
Messages
51
Just tried with your trigger and seems like it's not affecting enemies at all, trying to figure out now why, its just affecting them with the flamestrike buff (because Weakened Morals is based on Flamestrike) but it's not giving them the Weakened Morals dummy (based on banish)
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
You'll have to post your trigger for me to be able to figure out why. Anyway, it sounds like a Dummy unit issue if you're 100% sure you did the trigger correctly.

The Banish ability needs to have 99999 cast range, 0 mana cost, 0 cooldown, correct Targets Allowed, no requirements, etc...

The Dummy unit needs to be able to cast spells instantly, which I described how to do.

Also, I assumed your Dummy unit already had the ability in the Object Editor, which your first trigger implied, so I wasn't Adding the ability to it. If that's not the case then you'll obviously have to Add the ability to the Dummy through triggers. This is the proper method anyway, your Dummy unit should only have the Locust ability in the Object Editor.
 
Level 5
Joined
Jan 22, 2023
Messages
51
I think it was the range of the banish that messed that up, or the thing that I removed the ability from the dummy in object editor and added it via trigger. Anyways everything works now, thank you so much!
 
Status
Not open for further replies.
Top