- Joined
- Jun 13, 2016
- Messages
- 586
I haven't seen this being mentioned anywhere else, so here it is.
When working on my map, I was having some issues with groups. In particular, I was using the FoG method to iterate over groups. If you don't know what it is, consider the following:
It has it's own issues, but they are not relevant here. I was using groups across time, i.e. I was saving some units in a group, and using them later on for something else.
However, I discovered a very troublesome bug when using FoG in this manner.
If you have units in a group, and then one of these units is removed some time later, then the FoG method will not iterate over the entire group anymore. In particular, any units that were added to the group after the removed unit will not be iterated over.
Using ForGroup works fine, but FoG does not.
This code replicates the issue at it's finest:
After removing u4, u5 will not be iterated by the FoG method, while still showing up in ForGroup.
If you remove u2, then u3,u4,u5 will not be iterated over.
If you remove u1, then no units will be iterated over, while ForGroup will still work correctly.
From this, we can conclude that FirstOfGroup uses some sort of linked list, and works differently from how ForGroup operates. After removing a unit, the linked list isn't properly restored, and thus, FirstOfGroup stops operating correctly.
This invalidates the use of the FoG iterating method for groups that are stored across time. It is still fine for cases where you create a group and you can reliably expect no units in the group to die/be removed.
P.S. Now, I am not saying this isn't impossible to circumvent, but this is something that should be considered either way.
When working on my map, I was having some issues with groups. In particular, I was using the FoG method to iterate over groups. If you don't know what it is, consider the following:
JASS:
// zinc code, but you should get the idea
function FoG(group g) {
unit fog = FirstOfGroup(g);
while (fog != null) {
// some action with the unit
GroupRemoveUnit(g, fog);
fog = FirstOfGroup(g);
}
}
However, I discovered a very troublesome bug when using FoG in this manner.
If you have units in a group, and then one of these units is removed some time later, then the FoG method will not iterate over the entire group anymore. In particular, any units that were added to the group after the removed unit will not be iterated over.
Using ForGroup works fine, but FoG does not.
This code replicates the issue at it's finest:
JASS:
//! zinc
library Test {
function printGroup_aux() {
unit u = GetEnumUnit();
BJDebugMsg(GetUnitName(u));
}
function printGroup(group g) {
BJDebugMsg("------ForGroup Test------");
ForGroup(g, function printGroup_aux);
BJDebugMsg("------ForGroup TestEnd------");
}
function printGroup2(group g) {
unit fog = FirstOfGroup(g);
BJDebugMsg("------FoG Test------");
while (fog != null) {
BJDebugMsg(GetUnitName(fog));
GroupRemoveUnit(g, fog);
fog = FirstOfGroup(g);
}
BJDebugMsg("------FoG TestEnd------");
}
function onInit() {
group g;
unit u1;
unit u2;
unit u3;
unit u4;
unit u5;
player p = Player(0);
g = CreateGroup();
u1 = CreateUnit(p, 'hfoo', 0, 0, 0);
u2 = CreateUnit(p, 'hfoo', 0, 0, 0);
u3 = CreateUnit(p, 'hfoo', 0, 0, 0);
u4 = CreateUnit(p, 'hfoo', 0, 0, 0);
u5 = CreateUnit(p, 'hfoo', 0, 0, 0);
GroupAddUnit(g, u1);
GroupAddUnit(g, u2);
GroupAddUnit(g, u3);
GroupAddUnit(g, u4);
GroupAddUnit(g, u5);
RemoveUnit(u4);
TriggerSleepAction(4);
printGroup(g);
printGroup2(g);
}
}
//! endzinc
If you remove u2, then u3,u4,u5 will not be iterated over.
If you remove u1, then no units will be iterated over, while ForGroup will still work correctly.
From this, we can conclude that FirstOfGroup uses some sort of linked list, and works differently from how ForGroup operates. After removing a unit, the linked list isn't properly restored, and thus, FirstOfGroup stops operating correctly.
This invalidates the use of the FoG iterating method for groups that are stored across time. It is still fine for cases where you create a group and you can reliably expect no units in the group to die/be removed.
P.S. Now, I am not saying this isn't impossible to circumvent, but this is something that should be considered either way.
Last edited: