From a39cd7a8ef63cab8579a96d4b25c8ff694553647 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 17 Sep 2025 22:42:42 +0100 Subject: [PATCH] Fix: Variant cycle detection in FinaliseEngineArray (#14629) --- src/newgrf.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 547b1bbc43..b6444a8e06 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -904,12 +904,18 @@ static void FinaliseEngineArray() } /* Check engine variants don't point back on themselves (either directly or via a loop) then set appropriate flags - * on variant engine. This is performed separately as all variant engines need to have been resolved. */ + * on variant engine. This is performed separately as all variant engines need to have been resolved. + * Use Floyd's cycle-detection algorithm to handle the case where a cycle is present but does + * not include the starting engine ID. */ for (Engine *e : Engine::Iterate()) { EngineID parent = e->info.variant_id; + EngineID parent_slow = parent; + bool update_slow = false; while (parent != EngineID::Invalid()) { parent = Engine::Get(parent)->info.variant_id; - if (parent != e->index) continue; + if (update_slow) parent_slow = Engine::Get(parent_slow)->info.variant_id; + update_slow = !update_slow; + if (parent != e->index && parent != parent_slow) continue; /* Engine looped back on itself, so clear the variant. */ e->info.variant_id = EngineID::Invalid();