string[] GetFieldValues(ITraitInfo traitInfo, FieldInfo fieldInfo) { var type = fieldInfo.FieldType; if (type == typeof(string)) { return new string[] { (string)fieldInfo.GetValue(traitInfo) } } ; if (type == typeof(string[])) { return((string[])fieldInfo.GetValue(traitInfo)); } EmitError("Bad type for reference on {0}.{1}. Supported types: string, string[]" .F(traitInfo.GetType().Name, fieldInfo.Name)); return(new string[] { }); } void CheckReference <T>(ActorInfo actorInfo, ITraitInfo traitInfo, FieldInfo fieldInfo, IReadOnlyDictionary <string, T> dict, string type) { var values = GetFieldValues(traitInfo, fieldInfo); foreach (var v in values) { if (v != null && !dict.ContainsKey(v.ToLowerInvariant())) { EmitError("{0}.{1}.{2}: Missing {3} `{4}`." .F(actorInfo.Name, traitInfo.GetType().Name, fieldInfo.Name, type, v)); } } } }
void CheckTrait(ActorInfo actorInfo, ITraitInfo traitInfo, Ruleset rules) { var actualType = traitInfo.GetType(); foreach (var field in actualType.GetFields()) { if (field.HasAttribute <ActorReferenceAttribute>()) { CheckActorReference(actorInfo, traitInfo, field, rules.Actors, field.GetCustomAttributesExts <ActorReferenceAttribute>(true)[0]); } if (field.HasAttribute <WeaponReferenceAttribute>()) { CheckWeaponReference(actorInfo, traitInfo, field, rules.Weapons, field.GetCustomAttributesExts <WeaponReferenceAttribute>(true)[0]); } if (field.HasAttribute <VoiceSetReferenceAttribute>()) { CheckVoiceReference(actorInfo, traitInfo, field, rules.Voices, field.GetCustomAttributesExts <VoiceSetReferenceAttribute>(true)[0]); } } }
static IEnumerable <Type> PrerequisitesOf(ITraitInfo info) { return(info .GetType() .GetInterfaces() .Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Requires <>)) .Select(t => t.GetGenericArguments()[0])); }
void CheckReference <T>(ActorInfo actorInfo, ITraitInfo traitInfo, FieldInfo fieldInfo, IReadOnlyDictionary <string, T> dict, string type) { var values = LintExts.GetFieldValues(traitInfo, fieldInfo, emitError); foreach (var v in values) { if (v != null && !dict.ContainsKey(v.ToLowerInvariant())) { emitError("{0}.{1}.{2}: Missing {3} `{4}`." .F(actorInfo.Name, traitInfo.GetType().Name, fieldInfo.Name, type, v)); } } }
public void TraitOrderingSortsCorrectly() { var unorderedTraits = new ITraitInfo[] { new MockBInfo(), new MockCInfo(), new MockAInfo(), new MockBInfo() }; var actorInfo = new ActorInfo("test", unorderedTraits); var orderedTraits = actorInfo.TraitsInConstructOrder().ToArray(); CollectionAssert.AreEquivalent(unorderedTraits, orderedTraits); for (var i = 0; i < orderedTraits.Length; i++) { var traitTypesThatMustOccurBeforeThisTrait = ActorInfo.PrerequisitesOf(orderedTraits[i]); var traitTypesThatOccurAfterThisTrait = orderedTraits.Skip(i + 1).Select(ti => ti.GetType()); var traitTypesThatShouldOccurEarlier = traitTypesThatOccurAfterThisTrait.Intersect(traitTypesThatMustOccurBeforeThisTrait); CollectionAssert.IsEmpty(traitTypesThatShouldOccurEarlier, "Dependency order has not been satisfied."); } }
void CheckTrait(ActorInfo actorInfo, ITraitInfo traitInfo, Map map) { var actualType = traitInfo.GetType(); foreach (var field in actualType.GetFields()) { if (field.HasAttribute <ActorReferenceAttribute>()) { CheckReference(actorInfo, traitInfo, field, map.Rules.Actors, "actor"); } if (field.HasAttribute <WeaponReferenceAttribute>()) { CheckReference(actorInfo, traitInfo, field, map.Rules.Weapons, "weapon"); } if (field.HasAttribute <VoiceSetReferenceAttribute>()) { CheckReference(actorInfo, traitInfo, field, map.Rules.Voices, "voice"); } } }
void CheckVoiceReference(ActorInfo actorInfo, ITraitInfo traitInfo, FieldInfo fieldInfo, IReadOnlyDictionary <string, SoundInfo> dict, VoiceSetReferenceAttribute attribute) { var values = LintExts.GetFieldValues(traitInfo, fieldInfo, emitError); foreach (var value in values) { if (value == null) { continue; } if (!dict.ContainsKey(value.ToLower())) { emitError("{0}.{1}.{2}: Missing voice `{3}`." .F(actorInfo.Name, traitInfo.GetType().Name, fieldInfo.Name, value)); } } }
void CheckActorReference(ActorInfo actorInfo, ITraitInfo traitInfo, FieldInfo fieldInfo, IReadOnlyDictionary <string, ActorInfo> dict, ActorReferenceAttribute attribute) { var values = LintExts.GetFieldValues(traitInfo, fieldInfo, emitError); foreach (var value in values) { if (value == null) { continue; } // NOTE: Once https://github.com/OpenRA/OpenRA/issues/4124 is resolved we won't // have to .ToLower* anything here. var v = value.ToLowerInvariant(); if (!dict.ContainsKey(v)) { emitError("{0}.{1}.{2}: Missing actor `{3}`." .F(actorInfo.Name, traitInfo.GetType().Name, fieldInfo.Name, value)); continue; } foreach (var requiredTrait in attribute.RequiredTraits) { if (!dict[v].TraitsInConstructOrder().Any(t => t.GetType() == requiredTrait || t.GetType().IsSubclassOf(requiredTrait))) { emitError("Actor type {0} does not have trait {1} which is required by {2}.{3}." .F(value, requiredTrait.Name, traitInfo.GetType().Name, fieldInfo.Name)); } } } }
void CheckDefinitions(string image, SequenceReferenceAttribute sequenceReference, KeyValuePair <string, ActorInfo> actorInfo, string sequence, string faction, FieldInfo field, ITraitInfo traitInfo) { var definitions = sequenceDefinitions.FirstOrDefault(n => n.Key == image.ToLowerInvariant()); if (definitions != null) { if (sequenceReference != null && sequenceReference.Prefix) { if (!definitions.Value.Nodes.Any(n => n.Key.StartsWith(sequence))) { emitError("Sprite image {0} from actor {1} of faction {2} does not define sequence prefix {3} from field {4} of {5}" .F(image, actorInfo.Value.Name, faction, sequence, field.Name, traitInfo)); } } else if (definitions.Value.Nodes.All(n => n.Key != sequence)) { emitError("Sprite image {0} from actor {1} of faction {2} does not define sequence {3} from field {4} of {5}" .F(image, actorInfo.Value.Name, faction, sequence, field.Name, traitInfo)); } } }
static IEnumerable<Type> PrerequisitesOf(ITraitInfo info) { return info .GetType() .GetInterfaces() .Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Requires<>)) .Select(t => t.GetGenericArguments()[0]); }
static List<Type> PrerequisitesOf( ITraitInfo info ) { return info .GetType() .GetInterfaces() .Where( t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof( ITraitPrerequisite<> ) ) .Select( t => t.GetGenericArguments()[ 0 ] ) .ToList(); }
void CheckDefintions(string image, SequenceReferenceAttribute sequenceReference, KeyValuePair<string, ActorInfo> actorInfo, string sequence, string faction, FieldInfo field, ITraitInfo traitInfo) { var definitions = sequenceDefinitions.FirstOrDefault(n => n.Key == image.ToLowerInvariant()); if (definitions != null) { if (sequenceReference != null && sequenceReference.Prefix) { if (!definitions.Value.Nodes.Any(n => n.Key.StartsWith(sequence))) emitError("Sprite image {0} from actor {1} of faction {2} does not define sequence prefix {3} from field {4} of {5}" .F(image, actorInfo.Value.Name, faction, sequence, field.Name, traitInfo)); } else if (definitions.Value.Nodes.All(n => n.Key != sequence)) { emitError("Sprite image {0} from actor {1} of faction {2} does not define sequence {3} from field {4} of {5}" .F(image, actorInfo.Value.Name, faction, sequence, field.Name, traitInfo)); } } }