RemoveAt should *Always* remove items from a list #441
Replies: 4 comments 3 replies
-
So this hapepned as clientHost? On which version? Because something similar was already fixed. |
Beta Was this translation helpful? Give feedback.
-
Can you show the code? Is it happening on the server side I assume? |
Beta Was this translation helpful? Give feedback.
-
So you are ultimately just doing a for loop and using RemoveAt on the server? Is this server only issue, or also as clientHost? |
Beta Was this translation helpful? Give feedback.
-
Unable to reproduce. Possibly solved by #505 There was another bug reported recently and solved in 3.11.8 where the client was getting duplicate entries under the following scenario: This scenario occurs in the same tick.
As a resolution I made it so clients ignore potential duplicate entries such as this. I am wondering if this also resolved your bug because I cannot now replicate it. Hopefully these changes did fix your problem. I'm going to close this out as unable to replicate and link the resolved issue. If you are still having the problem in 3.11.8 (releasing soon) please let me know/re-open this. I'll need you to also include a test project please. Here's my test code... [Range(2, 10)]
public int RemoveCount = 2;
public bool RemoveTest;
[SyncObject]
private readonly SyncList<int> _removeAtBug = new SyncList<int>();
private void Awake()
{
AddEntries(10);
}
private void Update()
{
TryRemoveTest();
}
private void AddEntries(int value)
{
for (int i = 0; i < value; i++)
_removeAtBug.Add(i);
}
private void TryRemoveTest()
{
if (!RemoveTest)
return;
RemoveTest = false;
if (RemoveCount < _removeAtBug.Count)
AddEntries((_removeAtBug.Count - RemoveCount) * 2);
int removed = 0;
//Remove from the start and to try and force error.
for (int i = 0; i < _removeAtBug.Count; i++)
{
if (i == 0 || i == (_removeAtBug.Count - 1))
_removeAtBug.RemoveAt(i);
removed++;
if (removed == RemoveCount)
break;
}
Debug.Log($"Removed {removed} entries.");
} |
Beta Was this translation helpful? Give feedback.
-
Just got kicked in the nuts by a race condition error where sometimes, after calling Despawn on an object, in the same frame other scripts would not be updated on the IsServer and InDeinitializing fields, and I was calling [SyncList].RemoveAt(i), followed by i-- in a for loop.
I never thought RemoveAt could possibly fail to remove an item from a list in any case, so my game was freezing in an endless loop.
All that was wrapped in an if (IsServer && !IsDeinitializing)
Solved it by comparing the old count of items with the new count of items to make sure the item got removed, but spent plenty of time debugging 🤣
Based on that experience, I believe that all list manipulation functions should be reliable and always work as expected. Silently ignoring is the worst option possible IMO. At least throw an exception, so any erroneous code won't allow the programmer to get the game/editor stuck in an endless loop.
Beta Was this translation helpful? Give feedback.
All reactions