diff --git a/OpenRA.Game/GameRules/ActorInfo.cs b/OpenRA.Game/GameRules/ActorInfo.cs index 52b835e4a1..bd3c379e21 100644 --- a/OpenRA.Game/GameRules/ActorInfo.cs +++ b/OpenRA.Game/GameRules/ActorInfo.cs @@ -115,27 +115,34 @@ namespace OpenRA }).ToList(); var resolved = source.Where(s => s.Dependencies.Count == 0 && s.OptionalDependencies.Count == 0).ToList(); - var unresolved = source.Except(resolved); + var unresolved = source.ToHashSet(); + unresolved.ExceptWith(resolved); - var testResolve = new Func((a, b) => a == b || a.IsAssignableFrom(b)); + bool AreResolvable(Type a, Type b) => a.IsAssignableFrom(b); // This query detects which unresolved traits can be immediately resolved as all their direct dependencies are met. var more = unresolved.Where(u => u.Dependencies.All(d => // To be resolvable, all dependencies must be satisfied according to the following conditions: - resolved.Exists(r => testResolve(d, r.Type)) && // There must exist a resolved trait that meets the dependency. - !unresolved.Any(u1 => testResolve(d, u1.Type))) && // All matching traits that meet this dependency must be resolved first. + resolved.Exists(r => AreResolvable(d, r.Type)) && // There must exist a resolved trait that meets the dependency. + !unresolved.Any(u1 => AreResolvable(d, u1.Type))) && // All matching traits that meet this dependency must be resolved first. u.OptionalDependencies.All(d => // To be resolvable, all optional dependencies must be satisfied according to the following condition: - !unresolved.Any(u1 => testResolve(d, u1.Type)))); // All matching traits that meet this optional dependencies must be resolved first. + !unresolved.Any(u1 => AreResolvable(d, u1.Type)))); // All matching traits that meet this optional dependencies must be resolved first. // Continue resolving traits as long as possible. // Each time we resolve some traits, this means dependencies for other traits may then be possible to satisfy in the next pass. - while (more.Any()) - resolved.AddRange(more); + var readyToResolve = more.ToList(); + while (readyToResolve.Count != 0) + { + resolved.AddRange(readyToResolve); + unresolved.ExceptWith(readyToResolve); + readyToResolve.Clear(); + readyToResolve.AddRange(more); + } - if (unresolved.Any()) + if (unresolved.Count != 0) { var exceptionString = "ActorInfo(\"" + Name + "\") failed to initialize because of the following:\r\n"; - var missing = unresolved.SelectMany(u => u.Dependencies.Where(d => !source.Any(s => testResolve(d, s.Type)))).Distinct(); + var missing = unresolved.SelectMany(u => u.Dependencies.Where(d => !source.Any(s => AreResolvable(d, s.Type)))).Distinct(); exceptionString += "Missing:\r\n"; foreach (var m in missing)