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 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) =>
{
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)
{
var loadInfo = TypeLoadInfo[self.GetType()];
var missing = new List<string>();
Dictionary<string, MiniYaml> md = null;
@@ -52,19 +73,33 @@ namespace OpenRA
{
object val;
if (md == null)
md = my.ToDictionary();
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
{
if (md == null)
md = my.ToDictionary();
if (!TryGetValueFromYaml(fli.YamlName, fli.Field, md, out val))
{
if (fli.Attribute.Required)
missing.Add(fli.YamlName);
continue;
}
}
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)
@@ -557,12 +592,20 @@ namespace OpenRA
: base(false) { }
}
[AttributeUsage(AttributeTargets.Field)]
public sealed class RequireAttribute : SerializeAttribute
{
public RequireAttribute()
: base(true, true) { }
}
[AttributeUsage(AttributeTargets.Field)]
public sealed class LoadUsingAttribute : SerializeAttribute
{
public LoadUsingAttribute(string loader)
public LoadUsingAttribute(string loader, bool required = false)
{
Loader = loader;
Required = required;
}
}
@@ -577,10 +620,12 @@ namespace OpenRA
public string YamlName;
public string Loader;
public bool FromYamlKey;
public bool Required;
public SerializeAttribute(bool serialize = true)
public SerializeAttribute(bool serialize = true, bool required = false)
{
Serialize = serialize;
Required = required;
}
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}"
.F(my.Value, traitName));
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;
}

View File

@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("This actor's experience increases when it has killed a GivesExperience actor.")]
public class GainsExperienceInfo : ITraitInfo, Requires<ValuedInfo>, Requires<UpgradeManagerInfo>
{
[FieldLoader.LoadUsing("LoadUpgrades")]
[Desc("Upgrades to grant at each level. (Required property)",
[FieldLoader.LoadUsing("LoadUpgrades", true)]
[Desc("Upgrades to grant at each level.",
"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")]
public readonly Dictionary<int, string[]> Upgrades = null;
@@ -36,10 +36,7 @@ namespace OpenRA.Mods.Common.Traits
static object LoadUpgrades(MiniYaml y)
{
MiniYaml upgrades;
if (!y.ToDictionary().TryGetValue("Upgrades", out upgrades))
throw new YamlException("GainsExperience is missing Upgrades.");
MiniYaml upgrades = y.ToDictionary()["Upgrades"];
return upgrades.Nodes.ToDictionary(
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 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("<td>");
foreach (var line in fieldDescLines)