I have an array of 16 player starts. I am choosing random PlayerStarts from the array to spawn in an actor per player in response to OnPostLogin() in my GameMode. I remove that PlayerStart from the array each time.
Later in repsonse to a HUD button press by the host player, I spawn in neutral actors in each of the other PlayerStarts remaining in the array.
The problem is, that the removed PlayerStarts do not correspond with the ones the connected players already claimed, infact it seems entirely random which elements get removed. The correct amount are removed, I’ve checked that thoroughly, but not the correct elements.
Below is the macro getting a random PlayerStart showing two methods I’ve tried that should both achieve the same thing:
Here is where that macro is executed and then the returned data is used to spawn the player city actor, and remove the PlayerStart from the list. I’ve tried both of the array removal methods with same buged results:
Then later this is called to fill the rest of the PlayerStarts with neutral unclaimed cities, triggered by a UI button press (and definitely way after the initial palyer cities are added) preceeded by a check of the array lenght to clarify the correct amount were remove:
After playing and pressing said button, I can click through the player starts and clearly see a lot of the time that some have no cities associated with them, and the ones with the player controlled cities often have neutral cities spawned on them aswell (the exact proportions of each issue balancing out to make 16 cities in total each time which is the correct amount). I’ve spent a while on this, and I can’t see a good reason why this simple operation should go wrong in this way.
It would obviously be insane for the array::remove() functions to be wrong after so many years of UE5 blueprints through so many versions, but I’m struggling to see what else it could be that fits the nature of this bug
The problem (or rather the feature) is that “pure” nodes (without execution pins), including “random”, are executed every time a value is needed somewhere. So you get two different values ​​of “random”.
You need to cache “random” and then use that value.
Ah. I had that in mind when I collapsed the random getting part into a dedicated macro… I assumed the macro would have the random value cached already after execution. Is that not the case?
In Unreal Engine (UE5.4.4), when attempting to remove an element from an array and the wrong element is removed, this is often related to the following common causes:
1. Index Mismatch:
Arrays in Unreal Engine are zero-indexed, meaning the first element has an index of 0, the second has an index of 1, and so on.
If you’re removing an element by index (e.g., Array.RemoveAt(Index)), ensure that the Index is accurate. If you’re using dynamic logic to get the index, debug it to confirm it’s returning the expected value.
Solution:
Double-check that the index you’re passing is correct. Log the index before the removal to confirm.
UE_LOG(LogTemp, Warning, TEXT("Removing element at index: %d"), Index);
2. Array Modification During Iteration:
If you’re modifying the array while iterating through it (e.g., in a loop), this can cause issues. Removing elements shifts the remaining elements, which can result in skipping or removing incorrect elements.
Solution:
If you’re modifying an array while iterating, consider iterating backward, as this prevents shifting issues:
for (int32 i = Array.Num() - 1; i >= 0; i--)
{
if (ShouldRemove(Array[i]))
{
Array.RemoveAt(i);
}
}
3. Removing by Value:
If you’re using Array.Remove(Value), ensure that the Value you’re passing is correct and that the type matches.
Unreal Engine’s Remove() method will remove the first occurrence of the element that matches the value.
Solution:
Double-check that the value you’re passing in Remove(Value) is the one you expect to remove. Also, ensure that any potential type casting or conversions are handled properly.
MyArray.Remove(ExpectedValue);
4. Reference vs Value Types:
If your array contains pointers or objects (not primitive data types), there can be confusion between object references and values. Make sure you’re comparing the actual object references when removing or using custom comparison logic.
Solution:
For complex types like structs or objects, ensure that the comparison operator (==) behaves as expected, or define a custom comparator if necessary.
5. Async Tasks or Threads:
If you’re running asynchronous tasks that modify the array, there’s a chance of race conditions where the array is modified at an unexpected moment, leading to unexpected behavior when elements are removed.
Solution:
Ensure that all operations on the array are properly synchronized or occur on the main thread where necessary.
Debugging Tips:
Log the Array Contents: Before and after removal, log the array contents to ensure you’re removing the correct element.
for (int32 i = 0; i < Array.Num(); i++)
{
UE_LOG(LogTemp, Warning, TEXT("Element %d: %s"), i, *Array[i].ToString());
}
Breakpoints: Set breakpoints in your code before the removal operation to inspect the current state of the array and the index or value being passed for removal.
By carefully verifying the index or value and ensuring the array isn’t being modified unexpectedly, you should be able to resolve the issue of removing the wrong element.