diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index b5552b7e1c..bcffb806a5 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -39,7 +39,7 @@ namespace OpenRa Info = Rules.Info[name.ToLowerInvariant()]; Health = this.GetMaxHP(); - foreach (var trait in Info.Traits.WithInterface()) + foreach (var trait in Info.TraitsInConstructOrder()) traits.Add(trait.Create(this)); } } diff --git a/OpenRa.Game/GameRules/ActorInfo.cs b/OpenRa.Game/GameRules/ActorInfo.cs index 3ceff0ef88..625a5dcfa9 100644 --- a/OpenRa.Game/GameRules/ActorInfo.cs +++ b/OpenRa.Game/GameRules/ActorInfo.cs @@ -79,5 +79,39 @@ namespace OpenRa.GameRules throw new InvalidOperationException("Cannot locate trait: {0}".F(traitName)); } + + public IEnumerable TraitsInConstructOrder() + { + var ret = new List(); + var t = Traits.WithInterface().ToList(); + int index = 0; + while( t.Count != 0 ) + { + if( index >= t.Count ) + throw new InvalidOperationException( "Trait prerequisites not satisfied (or prerequisite loop)" ); + + var prereqs = PrerequisitesOf( t[ index ] ); + if( prereqs.Count == 0 || prereqs.All( n => ret.Any( x => x.GetType().IsSubclassOf( n ) ) ) ) + { + ret.Add( t[ index ] ); + t.RemoveAt( index ); + index = 0; + } + else + ++index; + } + + return ret; + } + + static List PrerequisitesOf( ITraitInfo info ) + { + return info + .GetType() + .GetInterfaces() + .Where( t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof( ITraitPrerequisite<> ) ) + .Select( t => t.GetGenericArguments()[ 0 ] ) + .ToList(); + } } } diff --git a/OpenRa.Game/Traits/RenderBuildingWarFactory.cs b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs index 67756fda8b..7eef90b6e3 100644 --- a/OpenRa.Game/Traits/RenderBuildingWarFactory.cs +++ b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs @@ -4,7 +4,7 @@ using OpenRa.Graphics; namespace OpenRa.Traits { - class RenderWarFactoryInfo : ITraitInfo + class RenderWarFactoryInfo : ITraitInfo, ITraitPrerequisite { public object Create(Actor self) { return new RenderWarFactory(self); } } diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs index 5eef1992f6..be362813bf 100644 --- a/OpenRa.Game/Traits/TraitsInterfaces.cs +++ b/OpenRa.Game/Traits/TraitsInterfaces.cs @@ -94,4 +94,5 @@ namespace OpenRa.Traits public object Create(Actor self) { return Instance.Value; } } + interface ITraitPrerequisite { } }