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

Fixing and understanding leaks

Status
Not open for further replies.
Level 2
Joined
Mar 7, 2008
Messages
14
Hello Hive!

My map starts getting really nasty lag spikes after about 10-30 seconds, so I'm pretty sure it's because of leaks.

I'm sure I have several leaky triggers, but I have found one trigger in particular, and when I disable it I get no lag issues, so this is where I want to start troubleshooting and asking for help.

I've been through several threads about leaks including:

Memory Leaks Memory Leaks
Things That Leak Things That Leak
Triggers - Memory Leaks and Custom Scripts Triggers - Memory Leaks and Custom Scripts

So I've made an effort, redoing the whole trigger while trying to store everything in variables and clearing the variables after use, but the problem persists.

The trigger in question is "WolfMainBehaviour Scared" in the folder "Monsters". It's not a big map and I haven't come far so everything should be fairly easy to find.

To reproduce lag spikes, simply start the map and wait 6 seconds for the wolves to start attacking the character. Lag spikes should appear after an additional 10-30 seconds.

Here's a screenshot of the trigger. I know you prefer actual code, but it's quite heavy to write and I don't know how to export it, and I've included the whole map as well.

upload_2019-11-2_23-6-27.png


I would very much like to learn why and where it's leaking and how I can fix it.

I hope this post is informative enough to help you help me.

Thanks in advance!
 

Attachments

  • Project Campfire.w3x
    207.4 KB · Views: 29
  • upload_2019-11-2_23-3-22.png
    upload_2019-11-2_23-3-22.png
    90.6 KB · Views: 48
Level 39
Joined
Feb 27, 2007
Messages
5,013
How To Post Your Trigger

There's no reason to do this with an integer a loop like you've done, you can simply use the Unit Group - Pick... action. An object is only a memory leak if you no longer intend to use it and have lost all reference to it; in this case you will be reusing the group periodically so you do not need to destroy it. There are other triggers in your map (PoI setup, some wolf stuff) where you use this type of "add units to group, use int loop from 1 to number of units in group, get random unit in group, remove unit from group" loop nonsense and you definitively not have to do that. Reread the sections on unit groups in the tutorial threads you mentioned if you still don't understand. Most unit group leaks can be preemptively cleaned with the set bj_wantDestroyGroup = true method.

I looked at the triggers and there are still many simple leaks that you're probably not aware of. This one:
  • Selected Unit
    • Events
      • Player - Player 1 (Red) Selects a unit
    • Conditions
    • Actions
      • Set SelectedUnit = (Random unit from (Units currently selected by Player 1 (Red)))
Leaks a group every time p1 selects anything. I realize this is just a test/debug trigger for now but to show how to avoid these leaks it should be this:
  • Selected Unit
    • Events
      • Player - Player 1 (Red) Selects a unit
    • Conditions
    • Actions
      • Set SelectedUnit = (Triggering Unit)
Next up:
  • Spawn Trees
    • Events
      • Map initialization
    • Conditions
    • Actions
      • For each (Integer A) from 3 to 14, do (Actions)
        • Loop - Actions
          • For each (Integer B) from 1 to ((Integer A) x 36), do (Actions)
            • Loop - Actions
              • Destructible - Create a Tree at ((Center of (Playable map area)) offset by (Random real number between ((TreeGenDistanceInterval x (Real((Integer A)))) + (Random real number between -75.00 and 75.00)) and ((TreeGenDistanceInterval + (Random real number between -75.00 and 75.00)) + (TreeGenDi) facing (Random angle) with scale 1.00 and variation 0
      • For each (Integer A) from 14 to 20, do (Actions)
        • Loop - Actions
          • For each (Integer B) from 1 to ((Integer A) x 72), do (Actions)
            • Loop - Actions
              • Destructible - Create a Tree at ((Center of (Playable map area)) offset by (Random real number between ((TreeGenDistanceInterval x (Real((Integer A)))) + (Random real number between -75.00 and 75.00)) and ((TreeGenDistanceInterval + (Random real number between -75.00 and 75.00)) + (TreeGenDi) facing (Random angle) with scale 1.00 and variation 0
This trigger leaks two points per tree for a total of 24480 points. You need to set variables for the two points (center of playable map and the offset point) and remove them appropriately (I didn't want to try to correct this in the trigger editor because of how convoluted your offset parameters are, which would be a pain to recreate). This is a prime example of why not to use the "map init" event ever, especially for things like this. If you crash the map init thread at any point nothing else that runs at map init will happen, and here you are getting dangerously close to the op limit of ~30,000.

A similar type of point leak combo happens in the Spawn Wolves trigger, though the numbers aren't nearly as high.

And then we get to the Wolves triggers. Hoooooh boy they are a mess.
  • You should just have one or maybe two main triggers running that control all of the periodic wolf stuff. Right now you have 5 or 6. I realize they are on different intervals, but that can be worked around. You can make the trigger go every 0.50 seconds and in that trigger set an integer variable = itself + 1. If that variable is 2, reset it to 0 and run your "every 1 second" stuff.
  • The "random real number between..." you're using in the periodic events doesn't work the way you think it does. The game randomizes that number at map init (when triggers are created) and it's set permanently for the rest of the game. It will never even try to choose a random number again. If you want a fluctuating period you'll have to do something like this:
    • Events
      • Time - Elapsed game-time is 1.00 seconds //so it runs the first time, or you can start the timer yourself somewhere else
      • Countdown Timer - TIMER expires
    • Conditions
    • Actions
      • -------- Do stuff --------
      • Countdown timer - Start TIMER as a one-shot timer that will expire in (Random real between 1.80 and 2.60 seconds)
  • The Do Nothing command is useless and never needs to be put anywhere. You can leave your Elses blank.
  • It's not necessary to 'null' variables by doing things like Set SourceOfFire = No unit unless the variable is a locally shadowed global and would thus be a reference leak at the end of the trigger.
  • In general you don't need to nest your if statements like you are doing. It's fine to just put them sequentially un-nested. They'll all be evaluated anyway.
  • In HastenWolves you should also check that the wolf does not already have the ability before adding it.
  • Instead of having a separate trigger for day and night actions you should just have one trigger with different logic depending on if it's day or night. You can use a boolean variable like IsDay and change its value to true/false with your triggers that detect day/night changes. Then check the value of this variable to do different things.
  • In IlluminateDarkenWolvesNight:
    • You're adding the wolves to WolvesDarkened twice?
    • This trigger has the weird loop bologna happening which should be fixed. On that note: why are you doing Unit Group - Pick every unit in (Random 1 units from SourceOfFireGroup) and do (Actions)??? That leaks a unit group per source of fire per trigger execution.
    • It leaks an absolutely ludicrous number of points. Between 2 and 10 points per wolf... per fire source. Instead of recomputing the distance each time (distance uses Sqrt which is relatively computationally expensive) you should compute it once and store the value in a real, then check that real vs all the appropriate distances.
    • The logic on adding wolves to groups is kinda weird. If a wolf is close enough to be in WolvesIlluminated[4] then it will also be in groups 1-3. Thus its fear doesn't go up by just +3... it goes up by 3+3+3+2+4=15 per trigger execution. Same goes for the levels of its abilities. This could be avoided by checking distances in reverse order (closest first) and skipping the remaining checks when the condition is matched. This would be an instance where nested ifs would probably be useful.
  • You could introduce checks in your ability level setting in various triggers to make sure it doesn't go below 1 or above the max (I assume 100). The game's probably smart enough not to crash when giving a negative ability level but hey you never know.
  • In WolfMainBehavior Bold:
    • You cleaned the first group leak properly! But... there's no reason to loop that way and the group is unnecessary. Just use a Unit Group - Pick every unit in WolvesBold and do (Actions) loop instead.
    • For every wolf that doesn't have the attack order, this leaks a location and a group (you cleaned one loc leak properly)
  • In WolfMainBehavior Scared:
    • Just use a Unit Group - Pick every unit in WolvesScared and do (Actions) loop instead.
    • You have an if block with empty conditions here...?
    • This leaks a group in the if conditions before ordering the wolf to move. Also the logic here seems funky but I'm not sure what exactly you had in mind so I can't say.
 
Level 2
Joined
Mar 7, 2008
Messages
14
Hey, I just wanted to say thank you for your lengthy and detailed reply. I'm trying to work through the triggers but it's taking some time :)
 
Status
Not open for further replies.
Top