• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

Question related to dead unit in a group.

Status
Not open for further replies.

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
I can confirm that units that die and are even removed by fully decaying are not removed from group objects. When you iterate through all elements of the group (the GUI pick every unit in group action) you will get picked unit as null for such units.

There are two solutions.
1. Remove the units from the group on death, this can be difficult to do at times as there is no direct mapping for groups a unit is in.
2. Periodically check through the group and flush dead units from it. Since all you get is a null pointer this requires one to swap the group with a new one built from the filtered results of the old group.

I would advise using one as it is the most efficient but requires you to specifically manage unit deaths (can be hard if groups are instance related or if you have a lot of them). Two on the other hand is much more easy to do and you could use an timer or a simple process counter (how many times the group was accessed) to determine when to garbage collect but it is considerably less efficient as you may end up processing groups that do not need processing as they have no dead units in them and each process is an O(n) operation.

Performing the clear group function on a group will remove all units from it, even dead units, and so return a group back to initial creation state. This means you can also get around the problem by clearing and rebuilding a group, a useful process for caches where there is a distinct correlation between all members of a group (such as all farm type units on the entire map). Obviously this is not viable for very weakly correlated groups or groups made from non-deterministic results such as a group consisting of important quest units (specific units that have no correlation) or a group made from a random subset of a larger group (the random subset is not deterministic when rebuilt so will be different).
 
Level 11
Joined
Oct 11, 2012
Messages
711
No it is not.

Also this should be in World Editor Help Zone not in Triggers and Scripts forum.

I can confirm that units that die and are even removed by fully decaying are not removed from group objects. When you iterate through all elements of the group (the GUI pick every unit in group action) you will get picked unit as null for such units.

There are two solutions.
1. Remove the units from the group on death, this can be difficult to do at times as there is no direct mapping for groups a unit is in.
2. Periodically check through the group and flush dead units from it. Since all you get is a null pointer this requires one to swap the group with a new one built from the filtered results of the old group.

I would advise using one as it is the most efficient but requires you to specifically manage unit deaths (can be hard if groups are instance related or if you have a lot of them). Two on the other hand is much more easy to do and you could use an timer or a simple process counter (how many times the group was accessed) to determine when to garbage collect but it is considerably less efficient as you may end up processing groups that do not need processing as they have no dead units in them and each process is an O(n) operation.

Performing the clear group function on a group will remove all units from it, even dead units, and so return a group back to initial creation state. This means you can also get around the problem by clearing and rebuilding a group, a useful process for caches where there is a distinct correlation between all members of a group (such as all farm type units on the entire map). Obviously this is not viable for very weakly correlated groups or groups made from non-deterministic results such as a group consisting of important quest units (specific units that have no correlation) or a group made from a random subset of a larger group (the random subset is not deterministic when rebuilt so will be different).

Thanks for the answer guys, +Rep
 
Level 12
Joined
Feb 22, 2010
Messages
1,115
How can a removed unit be inside a unit group :vw_wtf: I always heard but never encountered(how lucky I am)
If I have 1 bugged and 1 normal unit in group, ForGroup runs 2 times?And GetEnumUnit returns null inside ForGroup?
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
How can a removed unit be inside a unit group I always heard but never encountered(how lucky I am)
If I have 1 bugged and 1 normal unit in group, ForGroup runs 2 times?And GetEnumUnit returns null inside ForGroup?
WC3 JASS access complex structures like units via something called a "handle". Handles act as a level of abstraction from the physical structures they represent like Java object identifiers do in the Java programming language. The theory behind this is that the objects can be managed separately from their handles which allow some very useful behaviour traits that I will outline.

In C++ if you destroy an object directly it can potentially cause future attempts to access the object to throw a virtual memory access exception as the page the object was on is no longer allocated (this is a process crash usually) or the object may become corrupt as the space is allocated for another purpose now (different object/objects). By using an intermediate abstraction (like handle) you can mark the handle as deallocated so attempting to resolve it can be handled gracefully as a special case (JASS returns null).

Since the direct mapping between handles and their memory is controlled by the virtual machine, you can do processes like garbage collection (where objects are moved around) without needing to change the handle values. This is used in JAVA to allow objects to be moved around without having to update all references to them. JASS does not appear to use this to my knowledge.

Groups are collections of unit handles. When the unit is removed the handle still exists but it is set to an invalid mapping. When such a mapping is encountered the handle evaluates to null (not always) which is a nice safe value. The reason units are not removed from the group automatically is there is no mapping from unit to the groups they are in which can be used to remove it from the groups on death (such mapping systems could be made but will add overhead).

This also brings up another problem and often the biggest source of performance problems in leaky maps. Destroying an object in a leakless way has two parts, first destroying the underlying structure itself and then freeing the handle mapping to that structure. Freeing the structure is done via calls to destructors like RemoveLocation and DestroyGroup and are the user responsibility. Freeing the handle index is done automatically by a reference counter (when nothing points at the handle, groups and variable included, it is recycled) and can only be implied by the user by removing all references to a freed handle. However it is easy to leak such references via the JASS local handle bug (local handles declared with the local statement do not decrement the handle counter automatically on return) or by leaving them permanently in globals or in containers like groups. The result is that a handle index becomes permanently blocked which slows down some operations.

Do not worry about immediately recycling handle indexes. As long as you eventually clean up all references to a freed object there will be no leak.
 
Status
Not open for further replies.
Top