Added FieldLoader.SerializeAttribute.Required to require fields in MiniYaml

This commit is contained in:
atlimit8
2015-07-11 09:49:35 -05:00
parent f5d7df621f
commit 7881ff40bf
4 changed files with 66 additions and 14 deletions

View File

@@ -24,6 +24,26 @@ namespace OpenRA
{ {
public static class FieldLoader public static class FieldLoader
{ {
public class MissingFieldsException : YamlException
{
public readonly string[] Missing;
public readonly string Header;
public override string Message
{
get
{
return (string.IsNullOrEmpty(Header) ? "" : Header + ": ") + Missing[0]
+ string.Concat(Missing.Skip(1).Select(m => ", " + m));
}
}
public MissingFieldsException(string[] missing, string header = null, string headerSingle = null) : base(null)
{
Header = missing.Length > 1 ? header : headerSingle ?? header;
Missing = missing;
}
}
public static Func<string, Type, string, object> InvalidValueAction = (s, t, f) => public static Func<string, Type, string, object> InvalidValueAction = (s, t, f) =>
{ {
throw new InvalidOperationException("FieldLoader: Cannot parse `{0}` into `{1}.{2}` ".F(s, f, t)); throw new InvalidOperationException("FieldLoader: Cannot parse `{0}` into `{1}.{2}` ".F(s, f, t));
@@ -45,6 +65,7 @@ namespace OpenRA
public static void Load(object self, MiniYaml my) public static void Load(object self, MiniYaml my)
{ {
var loadInfo = TypeLoadInfo[self.GetType()]; var loadInfo = TypeLoadInfo[self.GetType()];
var missing = new List<string>();
Dictionary<string, MiniYaml> md = null; Dictionary<string, MiniYaml> md = null;
@@ -52,19 +73,33 @@ namespace OpenRA
{ {
object val; object val;
if (md == null)
md = my.ToDictionary();
if (fli.Loader != null) if (fli.Loader != null)
val = fli.Loader(my); {
if (!fli.Attribute.Required || md.ContainsKey(fli.YamlName))
val = fli.Loader(my);
else
{
missing.Add(fli.YamlName);
continue;
}
}
else else
{ {
if (md == null)
md = my.ToDictionary();
if (!TryGetValueFromYaml(fli.YamlName, fli.Field, md, out val)) if (!TryGetValueFromYaml(fli.YamlName, fli.Field, md, out val))
{
if (fli.Attribute.Required)
missing.Add(fli.YamlName);
continue; continue;
}
} }
fli.Field.SetValue(self, val); fli.Field.SetValue(self, val);
} }
if (missing.Any())
throw new MissingFieldsException(missing.ToArray());
} }
static bool TryGetValueFromYaml(string yamlName, FieldInfo field, Dictionary<string, MiniYaml> md, out object ret) static bool TryGetValueFromYaml(string yamlName, FieldInfo field, Dictionary<string, MiniYaml> md, out object ret)
@@ -557,12 +592,20 @@ namespace OpenRA
: base(false) { } : base(false) { }
} }
[AttributeUsage(AttributeTargets.Field)]
public sealed class RequireAttribute : SerializeAttribute
{
public RequireAttribute()
: base(true, true) { }
}
[AttributeUsage(AttributeTargets.Field)] [AttributeUsage(AttributeTargets.Field)]
public sealed class LoadUsingAttribute : SerializeAttribute public sealed class LoadUsingAttribute : SerializeAttribute
{ {
public LoadUsingAttribute(string loader) public LoadUsingAttribute(string loader, bool required = false)
{ {
Loader = loader; Loader = loader;
Required = required;
} }
} }
@@ -577,10 +620,12 @@ namespace OpenRA
public string YamlName; public string YamlName;
public string Loader; public string Loader;
public bool FromYamlKey; public bool FromYamlKey;
public bool Required;
public SerializeAttribute(bool serialize = true) public SerializeAttribute(bool serialize = true, bool required = false)
{ {
Serialize = serialize; Serialize = serialize;
Required = required;
} }
internal Func<MiniYaml, object> GetLoader(Type type) internal Func<MiniYaml, object> GetLoader(Type type)

View File

@@ -94,7 +94,16 @@ namespace OpenRA
throw new YamlException("Junk value `{0}` on trait node {1}" throw new YamlException("Junk value `{0}` on trait node {1}"
.F(my.Value, traitName)); .F(my.Value, traitName));
var info = Game.CreateObject<ITraitInfo>(traitName + "Info"); var info = Game.CreateObject<ITraitInfo>(traitName + "Info");
FieldLoader.Load(info, my); try
{
FieldLoader.Load(info, my);
}
catch (FieldLoader.MissingFieldsException e)
{
var header = "Trait name " + traitName + ": " + (e.Missing.Length > 1 ? "Required properties missing" : "Required property missing");
throw new FieldLoader.MissingFieldsException(e.Missing, header);
}
return info; return info;
} }

View File

@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("This actor's experience increases when it has killed a GivesExperience actor.")] [Desc("This actor's experience increases when it has killed a GivesExperience actor.")]
public class GainsExperienceInfo : ITraitInfo, Requires<ValuedInfo>, Requires<UpgradeManagerInfo> public class GainsExperienceInfo : ITraitInfo, Requires<ValuedInfo>, Requires<UpgradeManagerInfo>
{ {
[FieldLoader.LoadUsing("LoadUpgrades")] [FieldLoader.LoadUsing("LoadUpgrades", true)]
[Desc("Upgrades to grant at each level. (Required property)", [Desc("Upgrades to grant at each level.",
"Key is the XP requirements for each level as a percentage of our own value.", "Key is the XP requirements for each level as a percentage of our own value.",
"Value is a list of the upgrade types to grant")] "Value is a list of the upgrade types to grant")]
public readonly Dictionary<int, string[]> Upgrades = null; public readonly Dictionary<int, string[]> Upgrades = null;
@@ -36,10 +36,7 @@ namespace OpenRA.Mods.Common.Traits
static object LoadUpgrades(MiniYaml y) static object LoadUpgrades(MiniYaml y)
{ {
MiniYaml upgrades; MiniYaml upgrades = y.ToDictionary()["Upgrades"];
if (!y.ToDictionary().TryGetValue("Upgrades", out upgrades))
throw new YamlException("GainsExperience is missing Upgrades.");
return upgrades.Nodes.ToDictionary( return upgrades.Nodes.ToDictionary(
kv => FieldLoader.GetValue<int>("(key)", kv.Key), kv => FieldLoader.GetValue<int>("(key)", kv.Key),

View File

@@ -86,7 +86,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
var fieldDescLines = info.Field.GetCustomAttributes<DescAttribute>(true).SelectMany(d => d.Lines); var fieldDescLines = info.Field.GetCustomAttributes<DescAttribute>(true).SelectMany(d => d.Lines);
var fieldType = FriendlyTypeName(info.Field.FieldType); var fieldType = FriendlyTypeName(info.Field.FieldType);
var defaultValue = FieldSaver.SaveField(liveTraitInfo, info.Field.Name).Value.Value; var loadInfo = info.Field.GetCustomAttributes<FieldLoader.SerializeAttribute>(true).FirstOrDefault();
var defaultValue = loadInfo != null && loadInfo.Required ? "<em>(required)</em>" : FieldSaver.SaveField(liveTraitInfo, info.Field.Name).Value.Value;
doc.Append("<tr><td>{0}</td><td>{1}</td><td>{2}</td>".F(info.YamlName, defaultValue, fieldType)); doc.Append("<tr><td>{0}</td><td>{1}</td><td>{2}</td>".F(info.YamlName, defaultValue, fieldType));
doc.Append("<td>"); doc.Append("<td>");
foreach (var line in fieldDescLines) foreach (var line in fieldDescLines)