Merge pull request #9182 from penev92/bleed_dicts
Add support for Dictionary to FieldLoader and FieldSaver
This commit is contained in:
@@ -110,13 +110,8 @@ namespace OpenRA
|
||||
if (!md.TryGetValue(yamlName, out yaml))
|
||||
return false;
|
||||
|
||||
if (yaml.Nodes.Count == 0)
|
||||
{
|
||||
ret = GetValue(field.Name, field.FieldType, yaml.Value, field);
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("TryGetValueFromYaml: unable to load field {0} (of type {1})".F(yamlName, field.FieldType));
|
||||
ret = GetValue(field.Name, field.FieldType, yaml, field);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static T Load<T>(MiniYaml y) where T : new()
|
||||
@@ -165,6 +160,12 @@ namespace OpenRA
|
||||
|
||||
public static object GetValue(string fieldName, Type fieldType, string value, MemberInfo field)
|
||||
{
|
||||
return GetValue(fieldName, fieldType, new MiniYaml(value), field);
|
||||
}
|
||||
|
||||
public static object GetValue(string fieldName, Type fieldType, MiniYaml yaml, MemberInfo field)
|
||||
{
|
||||
var value = yaml.Value;
|
||||
if (value != null) value = value.Trim();
|
||||
|
||||
if (fieldType == typeof(int))
|
||||
@@ -441,6 +442,21 @@ namespace OpenRA
|
||||
addMethod.Invoke(set, new[] { GetValue(fieldName, fieldType.GetGenericArguments()[0], parts[i].Trim(), field) });
|
||||
return set;
|
||||
}
|
||||
else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||
{
|
||||
var dict = Activator.CreateInstance(fieldType);
|
||||
var arguments = fieldType.GetGenericArguments();
|
||||
var addMethod = fieldType.GetMethod("Add", arguments);
|
||||
|
||||
foreach (var node in yaml.Nodes)
|
||||
{
|
||||
var key = GetValue(fieldName, arguments[0], node.Key, field);
|
||||
var val = GetValue(fieldName, arguments[1], node.Value, field);
|
||||
addMethod.Invoke(dict, new[] { key, val });
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
else if (fieldType == typeof(Size))
|
||||
{
|
||||
if (value != null)
|
||||
@@ -588,7 +604,7 @@ namespace OpenRA
|
||||
|
||||
var loader = sa.GetLoader(type);
|
||||
if (loader == null && sa.FromYamlKey)
|
||||
loader = (yaml) => GetValue(yamlName, field.FieldType, yaml.Value, field);
|
||||
loader = yaml => GetValue(yamlName, field.FieldType, yaml, field);
|
||||
|
||||
var fli = new FieldLoadInfo(field, sa, yamlName, loader);
|
||||
ret.Add(fli);
|
||||
@@ -632,6 +648,7 @@ namespace OpenRA
|
||||
public string YamlName;
|
||||
public string Loader;
|
||||
public bool FromYamlKey;
|
||||
public bool DictionaryFromYamlKey;
|
||||
public bool Required;
|
||||
|
||||
public SerializeAttribute(bool serialize = true, bool required = false)
|
||||
@@ -694,6 +711,17 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
// Special-cases FieldFromYamlKeyAttribute for use with Dictionary<K,V>.
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public sealed class DictionaryFromYamlKeyAttribute : FieldLoader.SerializeAttribute
|
||||
{
|
||||
public DictionaryFromYamlKeyAttribute()
|
||||
{
|
||||
FromYamlKey = true;
|
||||
DictionaryFromYamlKey = true;
|
||||
}
|
||||
}
|
||||
|
||||
// mirrors DescriptionAttribute from System.ComponentModel but we dont want to have to use that everywhere.
|
||||
[AttributeUsage(AttributeTargets.All)]
|
||||
public sealed class DescAttribute : Attribute
|
||||
|
||||
@@ -28,7 +28,18 @@ namespace OpenRA
|
||||
|
||||
foreach (var info in FieldLoader.GetTypeLoadInfo(o.GetType(), includePrivateByDefault))
|
||||
{
|
||||
if (info.Attribute.FromYamlKey)
|
||||
if (info.Attribute.DictionaryFromYamlKey)
|
||||
{
|
||||
var dict = (System.Collections.IDictionary)info.Field.GetValue(o);
|
||||
foreach (var kvp in dict)
|
||||
{
|
||||
var key = ((System.Collections.DictionaryEntry)kvp).Key;
|
||||
var value = ((System.Collections.DictionaryEntry)kvp).Value;
|
||||
|
||||
nodes.Add(new MiniYamlNode(FormatValue(key, key.GetType()), FormatValue(value, value.GetType())));
|
||||
}
|
||||
}
|
||||
else if (info.Attribute.FromYamlKey)
|
||||
root = FormatValue(o, info.Field);
|
||||
else
|
||||
nodes.Add(new MiniYamlNode(info.YamlName, FormatValue(o, info.Field)));
|
||||
@@ -99,6 +110,25 @@ namespace OpenRA
|
||||
return ((System.Collections.IEnumerable)v).Cast<object>().JoinWith(", ");
|
||||
}
|
||||
|
||||
// This is only for documentation generation
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||
{
|
||||
var result = "";
|
||||
var dict = (System.Collections.IDictionary)v;
|
||||
foreach (var kvp in dict)
|
||||
{
|
||||
var key = ((System.Collections.DictionaryEntry)kvp).Key;
|
||||
var value = ((System.Collections.DictionaryEntry)kvp).Value;
|
||||
|
||||
var formattedKey = FormatValue(key, key.GetType());
|
||||
var formattedValue = FormatValue(value, value.GetType());
|
||||
|
||||
result += "{0}: {1}{2}".F(formattedKey, formattedValue, Environment.NewLine);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(OpenRA.Primitives.Cache<,>))
|
||||
return ""; // TODO
|
||||
|
||||
|
||||
@@ -16,33 +16,21 @@ namespace OpenRA.GameRules
|
||||
{
|
||||
public class SoundInfo
|
||||
{
|
||||
[FieldLoader.Ignore] public readonly Dictionary<string, string[]> Variants;
|
||||
[FieldLoader.Ignore] public readonly Dictionary<string, string[]> Prefixes;
|
||||
[FieldLoader.Ignore] public readonly Dictionary<string, string[]> Voices;
|
||||
[FieldLoader.Ignore] public readonly Dictionary<string, string[]> Notifications;
|
||||
public readonly Dictionary<string, string[]> Variants = new Dictionary<string, string[]>();
|
||||
public readonly Dictionary<string, string[]> Prefixes = new Dictionary<string, string[]>();
|
||||
public readonly Dictionary<string, string[]> Voices = new Dictionary<string, string[]>();
|
||||
public readonly Dictionary<string, string[]> Notifications = new Dictionary<string, string[]>();
|
||||
public readonly string DefaultVariant = ".aud";
|
||||
public readonly string DefaultPrefix = "";
|
||||
public readonly string[] DisableVariants = { };
|
||||
public readonly string[] DisablePrefixes = { };
|
||||
|
||||
static Dictionary<string, string[]> Load(MiniYaml y, string name)
|
||||
{
|
||||
var nd = y.ToDictionary();
|
||||
return nd.ContainsKey(name)
|
||||
? nd[name].ToDictionary(my => FieldLoader.GetValue<string[]>("(value)", my.Value))
|
||||
: new Dictionary<string, string[]>();
|
||||
}
|
||||
|
||||
public readonly Lazy<Dictionary<string, SoundPool>> VoicePools;
|
||||
public readonly Lazy<Dictionary<string, SoundPool>> NotificationsPools;
|
||||
|
||||
public SoundInfo(MiniYaml y)
|
||||
{
|
||||
FieldLoader.Load(this, y);
|
||||
Variants = Load(y, "Variants");
|
||||
Prefixes = Load(y, "Prefixes");
|
||||
Voices = Load(y, "Voices");
|
||||
Notifications = Load(y, "Notifications");
|
||||
|
||||
VoicePools = Exts.Lazy(() => Voices.ToDictionary(a => a.Key, a => new SoundPool(a.Value)));
|
||||
NotificationsPools = Exts.Lazy(() => Notifications.ToDictionary(a => a.Key, a => new SoundPool(a.Value)));
|
||||
|
||||
@@ -114,23 +114,18 @@ namespace OpenRA.Mods.Common.AI
|
||||
string IBotInfo.Name { get { return this.Name; } }
|
||||
|
||||
[Desc("What units to the AI should build.", "What % of the total army must be this type of unit.")]
|
||||
[FieldLoader.LoadUsing("LoadUnits")]
|
||||
public readonly Dictionary<string, float> UnitsToBuild = null;
|
||||
|
||||
[Desc("What buildings to the AI should build.", "What % of the total base must be this type of building.")]
|
||||
[FieldLoader.LoadUsing("LoadBuildings")]
|
||||
public readonly Dictionary<string, float> BuildingFractions = null;
|
||||
|
||||
[Desc("Tells the AI what unit types fall under the same common name.")]
|
||||
[FieldLoader.LoadUsing("LoadUnitsCommonNames")]
|
||||
public readonly Dictionary<string, string[]> UnitsCommonNames = null;
|
||||
|
||||
[Desc("Tells the AI what building types fall under the same common name.")]
|
||||
[FieldLoader.LoadUsing("LoadBuildingsCommonNames")]
|
||||
public readonly Dictionary<string, string[]> BuildingCommonNames = null;
|
||||
|
||||
[Desc("What buildings should the AI have max limits n.", "What is the limit of the building.")]
|
||||
[FieldLoader.LoadUsing("LoadBuildingLimits")]
|
||||
public readonly Dictionary<string, int> BuildingLimits = null;
|
||||
|
||||
// TODO Update OpenRA.Utility/Command.cs#L300 to first handle lists and also read nested ones
|
||||
@@ -138,22 +133,6 @@ namespace OpenRA.Mods.Common.AI
|
||||
[FieldLoader.LoadUsing("LoadDecisions")]
|
||||
public readonly List<SupportPowerDecision> PowerDecisions = new List<SupportPowerDecision>();
|
||||
|
||||
static object LoadList<T>(MiniYaml y, string field)
|
||||
{
|
||||
var nd = y.ToDictionary();
|
||||
return nd.ContainsKey(field)
|
||||
? nd[field].ToDictionary(my => FieldLoader.GetValue<T>(field, my.Value))
|
||||
: new Dictionary<string, T>();
|
||||
}
|
||||
|
||||
static object LoadUnits(MiniYaml y) { return LoadList<float>(y, "UnitsToBuild"); }
|
||||
static object LoadBuildings(MiniYaml y) { return LoadList<float>(y, "BuildingFractions"); }
|
||||
|
||||
static object LoadUnitsCommonNames(MiniYaml y) { return LoadList<string[]>(y, "UnitsCommonNames"); }
|
||||
static object LoadBuildingsCommonNames(MiniYaml y) { return LoadList<string[]>(y, "BuildingCommonNames"); }
|
||||
|
||||
static object LoadBuildingLimits(MiniYaml y) { return LoadList<int>(y, "BuildingLimits"); }
|
||||
|
||||
static object LoadDecisions(MiniYaml yaml)
|
||||
{
|
||||
var ret = new List<SupportPowerDecision>();
|
||||
|
||||
@@ -28,40 +28,19 @@ namespace OpenRA.Mods.Common
|
||||
public readonly string PackageToExtractFromCD = null;
|
||||
public readonly bool OverwriteFiles = true;
|
||||
|
||||
[FieldLoader.LoadUsing("LoadFilesToExtract")]
|
||||
public readonly Dictionary<string, string[]> ExtractFilesFromCD = new Dictionary<string, string[]>();
|
||||
|
||||
[FieldLoader.LoadUsing("LoadFilesToCopy")]
|
||||
public readonly Dictionary<string, string[]> CopyFilesFromCD = new Dictionary<string, string[]>();
|
||||
public readonly Dictionary<string, string[]> ExtractFilesFromCD = new Dictionary<string, string[]>();
|
||||
|
||||
public readonly string PackageMirrorList = null;
|
||||
|
||||
public readonly string MusicPackageMirrorList = null;
|
||||
public readonly int ShippedSoundtracks = 0;
|
||||
|
||||
/// <summary> InstallShield .cab File Ids, used to extract Mod specific files </summary>
|
||||
/// <summary> InstallShield .cab File Ids, used to extract Mod specific files. </summary>
|
||||
public readonly int[] InstallShieldCABFileIds = { };
|
||||
|
||||
/// <summary> InstallShield .cab File Ids, used to extract Mod specific archives and extract contents of ExtractFilesFromCD </summary>
|
||||
/// <summary> InstallShield .cab File Ids, used to extract Mod specific archives and extract contents of ExtractFilesFromCD. </summary>
|
||||
public readonly string[] InstallShieldCABFilePackageIds = { };
|
||||
|
||||
public static Dictionary<string, string[]> LoadFilesToExtract(MiniYaml yaml)
|
||||
{
|
||||
var md = yaml.ToDictionary();
|
||||
|
||||
return md.ContainsKey("ExtractFilesFromCD")
|
||||
? md["ExtractFilesFromCD"].ToDictionary(my => FieldLoader.GetValue<string[]>("(value)", my.Value))
|
||||
: new Dictionary<string, string[]>();
|
||||
}
|
||||
|
||||
public static Dictionary<string, string[]> LoadFilesToCopy(MiniYaml yaml)
|
||||
{
|
||||
var md = yaml.ToDictionary();
|
||||
|
||||
return md.ContainsKey("CopyFilesFromCD")
|
||||
? md["CopyFilesFromCD"].ToDictionary(my => FieldLoader.GetValue<string[]>("(value)", my.Value))
|
||||
: new Dictionary<string, string[]>();
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstallUtils
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Effects;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
@@ -20,7 +19,7 @@ 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", true)]
|
||||
[FieldLoader.Require]
|
||||
[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")]
|
||||
@@ -33,15 +32,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public readonly bool SuppressLevelupAnimation = true;
|
||||
|
||||
public object Create(ActorInitializer init) { return new GainsExperience(init, this); }
|
||||
|
||||
static object LoadUpgrades(MiniYaml y)
|
||||
{
|
||||
MiniYaml upgrades = y.ToDictionary()["Upgrades"];
|
||||
|
||||
return upgrades.Nodes.ToDictionary(
|
||||
kv => FieldLoader.GetValue<int>("(key)", kv.Key),
|
||||
kv => FieldLoader.GetValue<string[]>("(value)", kv.Value.Value));
|
||||
}
|
||||
}
|
||||
|
||||
public class GainsExperience : ISync, IResolveOrder
|
||||
|
||||
@@ -28,7 +28,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Damage types that trigger prone state. Defined on the warheads.")]
|
||||
public readonly string[] DamageTriggers = null;
|
||||
|
||||
[FieldLoader.LoadUsing("LoadModifiers")]
|
||||
[Desc("Damage modifiers for each damage type (defined on the warheads) while the unit is prone.")]
|
||||
public readonly Dictionary<string, int> DamageModifiers = new Dictionary<string, int>();
|
||||
|
||||
@@ -37,15 +36,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[SequenceReference(null, true)] public readonly string ProneSequencePrefix = "prone-";
|
||||
|
||||
public override object Create(ActorInitializer init) { return new TakeCover(init, this); }
|
||||
|
||||
public static object LoadModifiers(MiniYaml yaml)
|
||||
{
|
||||
var md = yaml.ToDictionary();
|
||||
|
||||
return md.ContainsKey("DamageModifiers")
|
||||
? md["DamageModifiers"].ToDictionary(my => FieldLoader.GetValue<int>("(value)", my.Value))
|
||||
: new Dictionary<string, int>();
|
||||
}
|
||||
}
|
||||
|
||||
public class TakeCover : Turreted, INotifyDamage, IDamageModifier, ISpeedModifier, ISync, IRenderInfantrySequenceModifier
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Warheads;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -17,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public class TerrainModifiesDamageInfo : ITraitInfo
|
||||
{
|
||||
[FieldLoader.LoadUsing("LoadPercents", true)]
|
||||
[FieldLoader.Require]
|
||||
[Desc("Damage percentage for specific terrain types. 120 = 120%, 80 = 80%, etc.")]
|
||||
public readonly Dictionary<string, int> TerrainModifier = null;
|
||||
|
||||
@@ -25,13 +24,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public readonly bool ModifyHealing = false;
|
||||
|
||||
public object Create(ActorInitializer init) { return new TerrainModifiesDamage(init.Self, this); }
|
||||
|
||||
static object LoadPercents(MiniYaml y)
|
||||
{
|
||||
return y.ToDictionary()["TerrainModifier"].Nodes.ToDictionary(
|
||||
kv => FieldLoader.GetValue<string>("(key)", kv.Key),
|
||||
kv => FieldLoader.GetValue<int>("(value)", kv.Value.Value));
|
||||
}
|
||||
}
|
||||
|
||||
public class TerrainModifiesDamage : IDamageModifier
|
||||
|
||||
@@ -29,7 +29,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("The sequence name that defines the actor sprites. Defaults to the actor name.")]
|
||||
public readonly string Image = null;
|
||||
|
||||
[FieldLoader.LoadUsing("LoadFactionImages")]
|
||||
[Desc("A dictionary of faction-specific image overrides.")]
|
||||
public readonly Dictionary<string, string> FactionImages = null;
|
||||
|
||||
@@ -42,16 +41,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Change the sprite image size.")]
|
||||
public readonly float Scale = 1f;
|
||||
|
||||
protected static object LoadFactionImages(MiniYaml y)
|
||||
{
|
||||
MiniYaml images;
|
||||
|
||||
if (!y.ToDictionary().TryGetValue("FactionImages", out images))
|
||||
return null;
|
||||
|
||||
return images.Nodes.ToDictionary(kv => kv.Key, kv => kv.Value.Value);
|
||||
}
|
||||
|
||||
public virtual object Create(ActorInitializer init) { return new RenderSprites(init, this); }
|
||||
|
||||
public IEnumerable<IActorPreview> RenderPreview(ActorPreviewInitializer init)
|
||||
|
||||
Reference in New Issue
Block a user