Description
Hi Doraku,
I noticed a problem in our game where entities with components assigned with SetSameAs<T>()
suddenly took the wrong component after running world.Optimize().
After some debugging, I think I found the cause of this. In the ComponentPool class there is a function ISortable.Sort which contains the following code in lines 334 - 353:
if (_links[_sortedIndex].ReferenceCount > 1 || tempLink.ReferenceCount > 1)
{
for (int i = 0; i < _mapping.Length; ++i)
{
if (_mapping[i] == minEntityId) // <--- Wrong condition.
{
_mapping[i] = _sortedIndex;
}
else if (_mapping[i] == tempLink.EntityId) // <--- Wrong condition.
{
_mapping[i] = minIndex;
}
}
}
else
{
_mapping[minEntityId] = _sortedIndex;
_mapping[tempLink.EntityId] = minIndex;
}
The else branch is correct, so sorting components without additional references is handled correctly. However, if there are multiple references, you are iterating over the entire mapping table. There you want to update the outdated references into the component array. The if and else-if clause for this is wrong. I think the corrected code should read:
if (_links[_sortedIndex].ReferenceCount > 1 || tempLink.ReferenceCount > 1)
{
for (int i = 0; i < _mapping.Length; ++i)
{
if (_mapping[i] == minIndex) // <--- The mapping table stores the index into the component array and not the entity id.
{
_mapping[i] = _sortedIndex;
}
else if (_mapping[i] == _sortedIndex) // <--- Same issue here.
{
_mapping[i] = minIndex;
}
}
}
else
{
_mapping[minEntityId] = _sortedIndex;
_mapping[tempLink.EntityId] = minIndex;
}
I hope you can have a look at it. Thanks a lot for your ECS system, we really enjoy working with it. Keep up the good work!