Allow each caller on MergeOrDefault to discard nodes.

Use filtering ActorInfo's to drop template actors.
This commit is contained in:
Peter Antal
2018-02-25 22:29:49 -08:00
committed by abcdefg30
parent 40d7b41e84
commit d2ff5b49fd
9 changed files with 24 additions and 26 deletions

View File

@@ -22,6 +22,8 @@ namespace OpenRA
/// </summary> /// </summary>
public class ActorInfo public class ActorInfo
{ {
public const string AbstractActorPrefix = "^";
/// <summary> /// <summary>
/// The actor name can be anything, but the sprites used in the Render*: traits default to this one. /// The actor name can be anything, but the sprites used in the Render*: traits default to this one.
/// If you add an ^ in front of the name, the engine will recognize this as a collection of traits /// If you add an ^ in front of the name, the engine will recognize this as a collection of traits
@@ -38,7 +40,6 @@ namespace OpenRA
{ {
Name = name; Name = name;
var abstractActorType = name.StartsWith("^");
foreach (var t in node.Nodes) foreach (var t in node.Nodes)
{ {
try try
@@ -47,8 +48,7 @@ namespace OpenRA
} }
catch (FieldLoader.MissingFieldsException e) catch (FieldLoader.MissingFieldsException e)
{ {
if (!abstractActorType) throw new YamlException(e.Message);
throw new YamlException(e.Message);
} }
} }

View File

@@ -87,16 +87,24 @@ namespace OpenRA
public IEnumerable<KeyValuePair<string, MusicInfo>> InstalledMusic { get { return Music.Where(m => m.Value.Exists); } } public IEnumerable<KeyValuePair<string, MusicInfo>> InstalledMusic { get { return Music.Where(m => m.Value.Exists); } }
static IReadOnlyDictionary<string, T> MergeOrDefault<T>(string name, IReadOnlyFileSystem fileSystem, IEnumerable<string> files, MiniYaml additional, static IReadOnlyDictionary<string, T> MergeOrDefault<T>(string name,
IReadOnlyDictionary<string, T> defaults, Func<MiniYamlNode, T> makeObject) IReadOnlyFileSystem fileSystem,
IEnumerable<string> files,
MiniYaml additional,
IReadOnlyDictionary<string, T> defaults,
Func<MiniYamlNode, T> makeObject,
Func<MiniYamlNode, bool> filterNode = null)
{ {
if (additional == null && defaults != null) if (additional == null && defaults != null)
return defaults; return defaults;
var result = MiniYaml.Load(fileSystem, files, additional) IEnumerable<MiniYamlNode> yamlNodes = MiniYaml.Load(fileSystem, files, additional);
.ToDictionaryWithConflictLog(k => k.Key.ToLowerInvariant(), makeObject, "LoadFromManifest<" + name + ">");
return new ReadOnlyDictionary<string, T>(result); // Optionally, the caller can filter out elements from the loaded set of nodes. Default behavior is unfiltered.
if (filterNode != null)
yamlNodes = yamlNodes.Where(k => !filterNode(k));
return new ReadOnlyDictionary<string, T>(yamlNodes.ToDictionaryWithConflictLog(k => k.Key.ToLowerInvariant(), makeObject, "LoadFromManifest<" + name + ">"));
} }
public static Ruleset LoadDefaults(ModData modData) public static Ruleset LoadDefaults(ModData modData)
@@ -108,7 +116,8 @@ namespace OpenRA
Action f = () => Action f = () =>
{ {
var actors = MergeOrDefault("Manifest,Rules", fs, m.Rules, null, null, var actors = MergeOrDefault("Manifest,Rules", fs, m.Rules, null, null,
k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value)); k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value),
filterNode: n => n.Key.StartsWith(ActorInfo.AbstractActorPrefix, StringComparison.Ordinal));
var weapons = MergeOrDefault("Manifest,Weapons", fs, m.Weapons, null, null, var weapons = MergeOrDefault("Manifest,Weapons", fs, m.Weapons, null, null,
k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
@@ -166,7 +175,8 @@ namespace OpenRA
Action f = () => Action f = () =>
{ {
var actors = MergeOrDefault("Rules", fileSystem, m.Rules, mapRules, dr.Actors, var actors = MergeOrDefault("Rules", fileSystem, m.Rules, mapRules, dr.Actors,
k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value)); k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value),
filterNode: n => n.Key.StartsWith(ActorInfo.AbstractActorPrefix, StringComparison.Ordinal));
var weapons = MergeOrDefault("Weapons", fileSystem, m.Weapons, mapWeapons, dr.Weapons, var weapons = MergeOrDefault("Weapons", fileSystem, m.Weapons, mapWeapons, dr.Weapons,
k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
@@ -244,7 +254,7 @@ namespace OpenRA
MiniYaml mapRules, MiniYaml mapWeapons, MiniYaml mapVoices, MiniYaml mapNotifications, MiniYaml mapSequences) MiniYaml mapRules, MiniYaml mapWeapons, MiniYaml mapVoices, MiniYaml mapNotifications, MiniYaml mapSequences)
{ {
// Maps that define any weapon, voice, notification, or sequence overrides are always flagged // Maps that define any weapon, voice, notification, or sequence overrides are always flagged
if (AnyCustomYaml(mapWeapons) || AnyCustomYaml(mapVoices) || AnyCustomYaml(mapNotifications) || AnyCustomYaml(mapSequences)) if (AnyCustomYaml(mapWeapons) || AnyCustomYaml(mapVoices) || AnyCustomYaml(mapNotifications) || AnyCustomYaml(mapSequences))
return true; return true;
// Any trait overrides that aren't explicitly whitelisted are flagged // Any trait overrides that aren't explicitly whitelisted are flagged

View File

@@ -23,9 +23,6 @@ namespace OpenRA.Mods.Common.Lint
{ {
foreach (var actorInfo in rules.Actors) foreach (var actorInfo in rules.Actors)
{ {
if (actorInfo.Key.StartsWith("^", StringComparison.Ordinal))
continue;
var granted = new HashSet<string>(); var granted = new HashSet<string>();
var consumed = new HashSet<string>(); var consumed = new HashSet<string>();

View File

@@ -22,9 +22,6 @@ namespace OpenRA.Mods.Common.Lint
{ {
foreach (var actorInfo in rules.Actors) foreach (var actorInfo in rules.Actors)
{ {
if (actorInfo.Key.StartsWith("^"))
continue;
var count = actorInfo.Value.TraitInfos<IDefaultVisibilityInfo>().Count(); var count = actorInfo.Value.TraitInfos<IDefaultVisibilityInfo>().Count();
if (count == 0) if (count == 0)

View File

@@ -22,9 +22,6 @@ namespace OpenRA.Mods.Common.Lint
{ {
foreach (var actorInfo in rules.Actors) foreach (var actorInfo in rules.Actors)
{ {
if (actorInfo.Key.StartsWith("^", StringComparison.Ordinal))
continue;
var health = actorInfo.Value.TraitInfoOrDefault<HealthInfo>(); var health = actorInfo.Value.TraitInfoOrDefault<HealthInfo>();
if (health == null) if (health == null)
continue; continue;

View File

@@ -22,9 +22,6 @@ namespace OpenRA.Mods.Common.Lint
{ {
foreach (var actorInfo in rules.Actors) foreach (var actorInfo in rules.Actors)
{ {
if (actorInfo.Key.StartsWith("^", StringComparison.Ordinal))
continue;
var ios = actorInfo.Value.TraitInfoOrDefault<IOccupySpaceInfo>(); var ios = actorInfo.Value.TraitInfoOrDefault<IOccupySpaceInfo>();
foreach (var rsi in actorInfo.Value.TraitInfos<RevealsShroudInfo>()) foreach (var rsi in actorInfo.Value.TraitInfos<RevealsShroudInfo>())
{ {

View File

@@ -48,7 +48,7 @@ namespace OpenRA.Mods.Common.Lint
foreach (var sequenceProvider in sequenceProviders) foreach (var sequenceProvider in sequenceProviders)
{ {
var image = renderInfo.GetImage(actorInfo.Value, sequenceProvider, faction); var image = renderInfo.GetImage(actorInfo.Value, sequenceProvider, faction);
if (sequenceDefinitions.All(s => s.Key != image.ToLowerInvariant()) && !actorInfo.Value.Name.Contains("^")) if (sequenceDefinitions.All(s => s.Key != image.ToLowerInvariant()))
emitError("Sprite image {0} from actor {1} using faction {2} has no sequence definition." emitError("Sprite image {0} from actor {1} using faction {2} has no sequence definition."
.F(image, actorInfo.Value.Name, faction)); .F(image, actorInfo.Value.Name, faction));
} }

View File

@@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Lint
{ {
public void Run(Action<string> emitError, Action<string> emitWarning, Ruleset rules) public void Run(Action<string> emitError, Action<string> emitWarning, Ruleset rules)
{ {
foreach (var actorInfo in rules.Actors.Where(a => !a.Key.StartsWith("^"))) foreach (var actorInfo in rules.Actors)
{ {
try try
{ {

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
Console.WriteLine("Tileset: " + ts.Name); Console.WriteLine("Tileset: " + ts.Name);
var sc = new SpriteCache(modData.DefaultFileSystem, modData.SpriteLoaders, new SheetBuilder(SheetType.Indexed)); var sc = new SpriteCache(modData.DefaultFileSystem, modData.SpriteLoaders, new SheetBuilder(SheetType.Indexed));
var nodes = MiniYaml.Merge(modData.Manifest.Sequences.Select(s => MiniYaml.FromStream(modData.DefaultFileSystem.Open(s), s))); var nodes = MiniYaml.Merge(modData.Manifest.Sequences.Select(s => MiniYaml.FromStream(modData.DefaultFileSystem.Open(s), s)));
foreach (var n in nodes.Where(node => !node.Key.StartsWith("^"))) foreach (var n in nodes.Where(node => !node.Key.StartsWith(ActorInfo.AbstractActorPrefix, StringComparison.Ordinal)))
modData.SpriteSequenceLoader.ParseSequences(modData, ts, sc, n); modData.SpriteSequenceLoader.ParseSequences(modData, ts, sc, n);
} }