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

unit - create 1 unit memory leak

Level 4
Joined
May 28, 2023
Messages
36
hello hive workshop! :)

I've begun the great memory leak purge and I just want to know if I'm doing it correctly so I don't have to go back and fix it again... (because I have to edit over 1k of these, time consuming)

Also is there a faster way of doing this?

Attachment: "leakfix"
 

Attachments

  • leakfix.png
    leakfix.png
    70.5 KB · Views: 28
Level 20
Joined
Feb 27, 2019
Messages
593
Hello thar.

That specific trigger looks good enough on its own. If a leak fixing trigger should be more efficiently constructed then I believe thats up to that specific trigger. Overall that is how you will have to do it.

That said there are a few leaks that can be hard to spot. Some examples are using a unit group without first setting it to a variable which is what you are doing with (Units in (Playable map area)). I suggest you create the units with a random angle instead but if you do want to use what you are using you can set (Units in (Playable map area)) to a TempGroup and destroy it after use. Another common leak that is missed is setting a location at a polar offset to another location. Whats good to remember on all of these is simply, if a unit group, location or player group is used without it being a variable it probably leaks. With the exception of permanent game variables such as (All players).
 
Level 25
Joined
Sep 26, 2009
Messages
2,381
The moment I would need to copy paste those actions multiple times, I would go for something like this:
  • Map Ini
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet DesertSpawns[1] = Desert Spawn 1 <gen>
      • Set VariableSet DesertSpawns[2] = Desert Spawn 2 <gen>
      • Set VariableSet DesertSpawns[3] = Desert Spawn 3 <gen>
      • Set VariableSet DesertSpawns[4] = Desert Spawn 4 <gen>
      • Set VariableSet HowMany[1] = 3
      • Set VariableSet HowMany[2] = 4
      • Set VariableSet HowMany[3] = 2
      • Set VariableSet HowMany[4] = 4
      • -------- ------------------------------ --------
      • For each (Integer index) from 1 to 4, do (Actions)
        • Loop - Actions
          • For each (Integer A) from 1 to HowMany[index], do (Actions)
            • Loop - Actions
              • Set VariableSet loc = (Random point in DesertSpawns[index])
              • Unit - Create 1 Footman for Player 1 (Red) at loc facing (Random angle) degrees
              • Custom script: call RemoveLocation(udg_loc)
Variables:
  • index: integer
  • DesertSpawns: region array
  • HowMany: integer array
Values in HowMany array represent how many units you want to spawn in a region with same index (number in square brackets "[n]" )
 
Level 4
Joined
May 28, 2023
Messages
36
Another common leak that is missed is setting a location at a polar offset to another location. Whats good to remember on all of these is simply, if a unit group, location or player group is used without it being a variable it probably leaks. With the exception of permanent game variables such as (All players).
Ah good reply, I understood most of it (hopefully lol) so changing them to Math - Random angle is the better solution?
Reason I use this a bit awkward facing of (Facing of (Random unit from (Units in (Playable map area)))) degrees is because I do not know which one to pick haha

The last part you wrote confused me a little. Polar offset to another location? I simply try using variables whenever I can? :)

Loop - Actions
Set VariableSet loc = (Random point in DesertSpawns[index])
Unit - Create 1 Footman for Player 1 (Red) at loc facing (Random angle) degrees
Custom script: call RemoveLocation(udg_loc)
Interesting trigger!

But this trigger only spawn the same units for all the regions, right? I have to spawn a bunch of different units and it's not entirely random what goes where. If I precisely needs to tell the trigger in what region I want what, the trigger would look a bit more advanced I think?
 
Last edited:
Level 25
Joined
Sep 26, 2009
Messages
2,381
But this trigger only spawn the same units for all the regions, right? I have to spawn a bunch of different units and it's not entirely random what goes where. If I precisely needs to tell the trigger in what region I want what, the trigger would look a bit more advanced I think?
Ah, I missed that the trigger creates different types of units. It's hard to say what would be optimal in this case - depending on how many different types of units you create and how many different regions you want to create the units in, some ways may suite you better than other.

One option could be to use a new TypeToSpawn variable (of type 'unit-type'), have the spawning part (the ForEach) in a separate trigger and use the map initialization trigger to set which unit-type you want to spawn and how many you want them to spawn in each region.

  • Map Ini
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet DesertSpawns[1] = Desert Spawn 1 <gen>
      • Set VariableSet DesertSpawns[2] = Desert Spawn 2 <gen>
      • Set VariableSet DesertSpawns[3] = Desert Spawn 3 <gen>
      • Set VariableSet DesertSpawns[4] = Desert Spawn 4 <gen>
      • -------- --------------------------------------------- --------
      • Set VariableSet TypeToSpawn = Footman
      • Set VariableSet HowMany[1] = 2
      • Set VariableSet HowMany[2] = 1
      • Set VariableSet HowMany[3] = 1
      • Set VariableSet HowMany[4] = 3
      • Trigger - Run Spawn Type <gen> (checking conditions)
      • -------- --------------------------------------------- --------
      • Set VariableSet TypeToSpawn = Knight
      • Set VariableSet HowMany[1] = 1
      • Set VariableSet HowMany[2] = 0
      • Set VariableSet HowMany[3] = 0
      • Set VariableSet HowMany[4] = 0
      • Trigger - Run Spawn Type <gen> (checking conditions)
      • -------- --------------------------------------------- --------
      • Set VariableSet TypeToSpawn = Rifleman
      • Set VariableSet HowMany[1] = 0
      • Set VariableSet HowMany[2] = 3
      • Set VariableSet HowMany[3] = 1
      • Set VariableSet HowMany[4] = 0
      • Trigger - Run Spawn Type <gen> (checking conditions)
      • -------- --------------------------------------------- --------
      • Set VariableSet TypeToSpawn = Siege Engine
      • Set VariableSet HowMany[1] = 0
      • Set VariableSet HowMany[2] = 0
      • Set VariableSet HowMany[3] = 0
      • Set VariableSet HowMany[4] = 1
      • Trigger - Run Spawn Type <gen> (checking conditions)
  • Spawn Type
    • Events
    • Conditions
    • Actions
      • For each (Integer index) from 1 to 4, do (Actions)
        • Loop - Actions
          • For each (Integer A) from 1 to HowMany[index], do (Actions)
            • Loop - Actions
              • Set VariableSet loc = (Random point in DesertSpawns[index])
              • Unit - Create 1 TypeToSpawn for Player 1 (Red) at loc facing (Random angle) degrees
              • Custom script: call RemoveLocation(udg_loc)
You can see that for each unit type I need to set values into the HowMany variables, so if you have too many types of units or too many regions, this trigger can get big.
The advantage, on the other hand, is that you can quite easily determine how many of what you spawn where and can make modifications quite easily.
It's also re-usable for any other similar triggers that spawn units (if you have for example other spawn locations than the Desert Spawn regions)
 
Level 4
Joined
May 28, 2023
Messages
36
Ah, I missed that the trigger creates different types of units...
This trigger you posted... As always... is like Alien Tech Nichilus! :D

But man... I got around 500 regions, most of them are for this... And I'm using a lot of different units... This trigger will get very big xD


So my question is now: Do I create this new trigger or use my time on creating the simple one I was doing, fixed with math - random angle?
 
Level 25
Joined
Sep 26, 2009
Messages
2,381
I got around 500 regions, most of them are for this
That seems like an excessive number of regions for spawning units. For example the first map in the Orc expansion campaign (where you play as Rexxar) has ~550 regions total, but only about 100 of them for spawning creeps. You may want to check those maps to see how Blizz did it.
You may also want to consider if some locations cannot be calculated (like instead of 10 regions you leave only the center one and spawn units offset by random distance towards random angle from that location) or if some regions cannot be merged together.

What I showed in my previous post is one of the options to manage spawning units. It's not the only option - as I wrote earlier, depending on how your map is set up, some approaches may be better than others.
If you have many regions, then the question may be how many units per region do you spawn. If the average is low number, then you could use a completely different approach for spawning units.
Instead of setting one specific unit-type you want to spawn and then configure in the HowMany array how many of that unit you want to spawn in each region, you could instead set one specific region and provide an array of unit-types you want to spawn there. It would look something like this:
  • Map Ini 2
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet RegionToSpawn = Desert Spawn 1 <gen>
      • Set VariableSet UnitTypesToSpawn[1] = Footman
      • Set VariableSet UnitTypesToSpawn[2] = Footman
      • Set VariableSet UnitTypesToSpawn[3] = Knight
      • Set VariableSet NumberOfUnitTypes = 3
      • Trigger - Run Spawn Type 2 <gen> (checking conditions)
      • -------- --------------------------------------------- --------
      • Set VariableSet RegionToSpawn = Desert Spawn 2 <gen>
      • Set VariableSet UnitTypesToSpawn[1] = Footman
      • Set VariableSet UnitTypesToSpawn[2] = Rifleman
      • Set VariableSet UnitTypesToSpawn[3] = Rifleman
      • Set VariableSet UnitTypesToSpawn[4] = Rifleman
      • Set VariableSet NumberOfUnitTypes = 4
      • Trigger - Run Spawn Type 2 <gen> (checking conditions)
      • -------- --------------------------------------------- --------
      • Set VariableSet RegionToSpawn = Desert Spawn 3 <gen>
      • Set VariableSet UnitTypesToSpawn[1] = Footman
      • Set VariableSet UnitTypesToSpawn[2] = Rifleman
      • Set VariableSet NumberOfUnitTypes = 2
      • Trigger - Run Spawn Type 2 <gen> (checking conditions)
      • -------- --------------------------------------------- --------
      • Set VariableSet RegionToSpawn = Desert Spawn 4 <gen>
      • Set VariableSet UnitTypesToSpawn[1] = Footman
      • Set VariableSet UnitTypesToSpawn[2] = Footman
      • Set VariableSet UnitTypesToSpawn[3] = Footman
      • Set VariableSet UnitTypesToSpawn[4] = Siege Engine
      • Set VariableSet NumberOfUnitTypes = 4
      • Trigger - Run Spawn Type 2 <gen> (checking conditions)
  • Spawn Type 2
    • Events
    • Conditions
    • Actions
      • For each (Integer index) from 1 to NumberOfUnitTypes, do (Actions)
        • Loop - Actions
          • Set VariableSet loc = (Random point in RegionToSpawn)
          • Unit - Create 1 UnitTypesToSpawn[index] for Player 1 (Red) at loc facing (Random angle) degrees
          • Custom script: call RemoveLocation(udg_loc)
From the triggers above, 2 Footmen and 1 Knight will be spawned in Desert Region 1, etc.
The variables here are
  • RegionToSpawn: region
  • UnitTypesToSpawn: unit-type array
  • NumberOfUnitTypes: integer
  • index: integer

Do I create this new trigger or use my time on creating the simple one I was doing
At the end of the day, it depends. There's functionally nothing wrong with the way you have it, but you should consider readability of your triggers and how prone to error your trigger is. For example I know my trigger will not leak, because the only place it could leak is only the small "Spawn Type" trigger and I can also quite easily see where I spawn what.
On the other hand your trigger is prone to human error - for example by accident picking up different point variable when creating unit and then trying to investigate in a hundreds-line long trigger which unit is the one spawning in wrong place, etc.
You should also ask yourself questions like: Can I easily understand all the things that are going on in my trigger? Will I (or a friend) be able to easily understand that trigger 2 months later when I want to update it?

This trigger will get very big xD
You should divide such triggers into smaller, more manageable, parts.
For example divide your spawn triggers by the area. If you have for example Desert Spawn regions and Forest Spawn regions, then have separate trigger for each area and a single trigger with "Map Initialization" event which will run those triggers. I mean something like this:
  • Map Ini
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Trigger - Run Spawn Desert Creeps <gen> (checking conditions)
      • Trigger - Run Spawn Forest Creeps <gen> (checking conditions)
  • Spawn Desert Creeps
    • Events
    • Conditions
    • Actions
      • Set VariableSet RegionToSpawn = Desert Spawn 1 <gen>
      • -------- ... would continue on with spawning creeps in Desert Regions --------
  • Spawn Forest Creeps
    • Events
    • Conditions
    • Actions
      • Set VariableSet RegionToSpawn = Forest Spawn 1 <gen>
      • -------- ... would continue on with spawning creeps in Forest Regions --------
 
Level 4
Joined
May 28, 2023
Messages
36
That seems like an excessive number of regions for spawning units.
Uhhh it might be. I'm tired right now so I cannot commit to a decision on what to do at this moment.
Good idea on looking at the orc campaign map. As far as I remember they changed maps from time to time.
I could easily merge some of the regions together, but it would still be a lot of regions!
Is there a reason why I can't have like 1000 regions?

Also do you want to check out my map so you can take a peek at my trigger mess and excessive number of regions? :p

EDIT: I'm looking at the orc campaiign atm. there is much to learn here! But this is still a singleplayer map for 1 player and I'm creating a multiplayer map for 12 (maybe even more) players... Can't rly compare the two can we? :)
 
Last edited:
Level 20
Joined
Feb 27, 2019
Messages
593
so changing them to Math - Random angle is the better solution?
Yes.
The last part you wrote confused me a little. Polar offset to another location? I simply try using variables whenever I can? :)
If a location is used without first setting it to a variable then the location will leak. The function Point With Polar Offset is often set incorrectly so that it looks like this:
  • Set VariableSet TempPoint = ((Center of (Playable map area)) offset by 256.00 towards 0.00 degrees.)
  • Use TempPoint
  • Custom script: call RemoveLocation(udg_TempPoint)
It should look like this:
  • Set VariableSet TempPoint = (Center of (Playable map area))
  • Set VariableSet TempPoint2 = (TempPoint offset by 256.00 towards 0.00 degrees.)
  • Use TempPoint2
  • Custom script: call RemoveLocation(udg_TempPoint)
  • Custom script: call RemoveLocation(udg_TempPoint2)
The same goes for unit groups in conditions. Theyre often set incorrectly like this:
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • (Number of units in (Units in (Playable map area))) Equal to 0
    • Then - Actions
    • Else - Actions
It should look like this:
  • Set VariableSet TempGroup = (Units in (Playable map area))
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • (Number of units in TempGroup) Equal to 0
    • Then - Actions
    • Else - Actions
  • Custom script: call DestroyGroup(udg_TempGroup)
 
Level 4
Joined
May 28, 2023
Messages
36
If a location is used without first setting it to a variable then the location will leak.
See, this is why I made this post! But this is also sad information, that means that most logical simple triggers leaks lol -_-

It should look like this:
  • set.gif
    Set VariableSet TempPoint = (Center of (Playable map area))
  • set.gif
    Set VariableSet TempPoint2 = (TempPoint offset by 256.00 towards 0.00 degrees.)
  • if.gif
    Use TempPoint2
  • page.gif
    Custom script: call RemoveLocation(udg_TempPoint)
  • page.gif
    Custom script: call RemoveLocation(udg_TempPoint2)
So my simple trigger is not good enough, I also have to setup a extra variable and remove the same leak but offset a little from the region? What? Uh.. I'll take your word for it but damn, who made this mess? xD

Ty Duckfa... farter? lol. This is very useful information.
 
Last edited:
Level 20
Joined
Feb 27, 2019
Messages
593
See, this is why I made this post! But this is also sad information, that means that most logical simple triggers leaks lol -_-
As with coding back then I guess it was the norm to remove leaks manually. I have a theory why Blizzard didnt opt to remove leaks in their functions, that theory is that they wanted to keep their functions simple and efficient so that they could stitch them together more easily. If a location is removed when its used by a function, but then a new location is supposed to be put at an offset of that location in another function then the removal of that location cant be placed inside the first function since it would cause the second function to have a null location. It would also render it impossible to set a location to a variable using a function that also removes the location, unless they had separate functions for setting a variable and using a variable. Its not a dumb solution for simplicities sake considering the fact that each individual leak hardly affects the game at all but when leaks are stacked to an unreasonable level they start to matter a lot. This is all speculation though.

So my simple trigger is not good enough, I also have to setup a extra variable and remove the same leak but offset a little from the region? What? Uh.. I'll take your word for it but damn, who made this mess? xD
To clarify, that specific example is not relevant to your trigger. If all that is needed is to use a single location then setting a single variable does the job, but if using the specific or similar function as what in gui is called "Point With Polar Offset" which uses two locations then two variables have to be set. After all gui was made to make triggering more accesible not more efficient or better.
 
Level 4
Joined
May 28, 2023
Messages
36
As with coding back then...
Hmm your theory does sound logical. My theory is they setup a trap for me to learn the Editor and then BOOM "You are not prepared!"

Thank you for the clarification, saved me over 1k edits hehe :D I'll keep this in mind!

Now I just need to figure out why Nichilus don't like my 500+ regions haha
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,567
Hmm your theory does sound logical. My theory is they setup a trap for me to learn the Editor and then BOOM "You are not prepared!"

Thank you for the clarification, saved me over 1k edits hehe :D I'll keep this in mind!

Now I just need to figure out why Nichilus don't like my 500+ regions haha
I've heard of funky things happening when one has too many regions, some related to performance issues as well as things just outright breaking. So it's good practice to avoid creating too many when possible. 500 or 1000 regions sounds crazy high to me but maybe your map really needs that many. At the same time, I imagine you can combine some regions or use better practices like Point With Polar Offset (Duck mentioned this function when explaining how to handle it's memory leak problem) to avoid creating an entirely new Region. It's also good for organization, less regions = better editor performance and a cleaner editor (makes finding a Region far easier to do).

Cleaning up memory leaks, keeping variable counts/trigger counts in check, avoiding too many preplaced units and regions, all of these acts go towards improving your mapmaking experience as well as your gameplay experience. Do note though that when it comes to Memory Leaks it's really only the nasty leaks that cause problems, for example, leaking several Unit Groups 100 times per second. I find this issue is most common in triggers for custom spells and boss fights. So that's where I would divert my focus if I was you. In other words, don't rip your hair out trying to squash every memory leak, instead, search for the really bad ones and deal with those. Then if you experience performance problems while playing your map you can come back and revisit the leak situation, although, most of the time the performance issues will be coming from things like too many Units/Special Effects being created at once.
 
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
I've heard of funky things happening when one has too many regions, some related to performance issues as well as things just outright breaking. So it's good practice to avoid creating too many when possible. 500 or 1000 regions sounds crazy high to me but maybe your map really needs that many. At the same time, I imagine you can combine some regions or use better practices like Point With Polar Offset (Duck mentioned this function when explaining how to handle it's memory leak problem)
Ahhh now I get why he told me about the offset regions... xD
About the many regions, I've been looking around for more information but I can't seem to find anything useful to my situation.. Funky you say! Do you know somewhere maybe on this forum where I could learn more about this issue?

And I think you told me not to worry too much about leaks before. I'll go easy on them for now then :)
 
Level 4
Joined
May 28, 2023
Messages
36
Tsch, a horrible lack of etiquette on this forum. It's rude to leave conversations without properly ending them first... w/e I just gotta lower my expectations here lol.
 
Do you know somewhere maybe on this forum where I could learn more about this issue?
 
Top