The script VM does not actually have any “For Loop”, “For Each Loop”, “While Loop” etc. concept. These are just high level flow control mechanisms built on top. They essentially all function the same way:
- evaluate some condition whether we are done and jump to either 2. or 3.
- if not yet done
2.1 execute some custom logic
2.2. possibly update internal state (e.g. for loop would increment its counter)
2.3 go back to 1. - otherwise we are done and can return
So how does the script engine detect infinite loops then? Well it knows what branches are (jump). So since it cannot count iterations it counts jumps instead. So really the “infinite loop” in the error message is very misleading (internally the counter is called Runaway
). While it intends to detect infinite loops it detects when too many jumps are executed which can happen if too much stuff happens in the same tick even if the code executed by the script VM may be perfectly fine and not have any infinite loop (such as yours). You can inspect the code generated for your blueprint with the following (not very well known) command DISASMSCRIPT NameOfYourBlueprint
and then search for “jump”. Be warned the output is fairly hard to read. You’ll notice there are already multiple jumps in this function. One hides in the For Each Loop
, another two in the Compare Int
macro. Then there are the two plain branches as well. So each iteration of your loop has a minimum of three jumps (For Each Loop
, first branch, then either second branch or first branch inside the Compare Int
macro).
Now one can argue that the infinite loop detection is most likely to report the place that executes the most jumps but it could also just be a very simple function if that happens to hit the limit.
I believe the limit is a project setting so you could just increase that. However I would not recommend doing that as you’re likely to keep expanding the game and would hit the limit again eventually. Another common solution to hitting the runaway limit is to separate expensive (in terms of number of jumps) operations over multiple ticks. E.g. rather than processing all 5k Tiles in one go, process 5 batches of 1k Tiles instead. If you haven’t done so already you might also come up with a different datastructure that allows you to get surrounding tiles faster, for example by grouping tiles using a quadtree and only looking at the tiles in quadtree nodes that are in the desired range. Hitting the runaway limit may also indicate a performance issue so your code might benefit from being moved to C++ as well.