diff --git a/OpenRA.Game/FieldLoader.cs b/OpenRA.Game/FieldLoader.cs index 086d3e959f..6c4bb59bb8 100644 --- a/OpenRA.Game/FieldLoader.cs +++ b/OpenRA.Game/FieldLoader.cs @@ -33,9 +33,17 @@ namespace OpenRA throw new NotImplementedException("FieldLoader: Missing field `{0}` on `{1}`".F(s, f.Name)); }; + static readonly ConcurrentCache TypeLoadInfo = + new ConcurrentCache(BuildTypeLoadInfo); + static readonly ConcurrentCache MemberHasTranslateAttribute = + new ConcurrentCache(member => member.HasAttribute()); + + static readonly object TranslationsLock = new object(); + static Dictionary translations; + public static void Load(object self, MiniYaml my) { - var loadInfo = typeLoadInfo[self.GetType()]; + var loadInfo = TypeLoadInfo[self.GetType()]; Dictionary md = null; @@ -82,7 +90,6 @@ namespace OpenRA return t; } - static readonly object[] NoIndexes = { }; public static void LoadField(object target, string key, string value) { const BindingFlags Flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; @@ -103,7 +110,7 @@ namespace OpenRA { var sa = prop.GetCustomAttributes(false).DefaultIfEmpty(SerializeAttribute.Default).First(); if (!sa.FromYamlKey) - prop.SetValue(target, GetValue(prop.Name, prop.PropertyType, value, prop), NoIndexes); + prop.SetValue(target, GetValue(prop.Name, prop.PropertyType, value, prop), null); return; } @@ -162,7 +169,7 @@ namespace OpenRA } else if (fieldType == typeof(string)) { - if (field != null && field.HasAttribute()) + if (field != null && MemberHasTranslateAttribute[field]) return Regex.Replace(value, "@[^@]+@", m => Translate(m.Value.Substring(1, m.Value.Length - 2)), RegexOptions.Compiled); return value; } @@ -438,12 +445,10 @@ namespace OpenRA public static IEnumerable GetTypeLoadInfo(Type type, bool includePrivateByDefault = false) { - return typeLoadInfo[type].Where(fli => includePrivateByDefault || fli.Field.IsPublic || (fli.Attribute.Serialize && !fli.Attribute.IsDefault)); + return TypeLoadInfo[type].Where(fli => includePrivateByDefault || fli.Field.IsPublic || (fli.Attribute.Serialize && !fli.Attribute.IsDefault)); } - static Cache> typeLoadInfo = new Cache>(BuildTypeLoadInfo); - - static List BuildTypeLoadInfo(Type type) + static FieldLoadInfo[] BuildTypeLoadInfo(Type type) { var ret = new List(); @@ -465,7 +470,7 @@ namespace OpenRA ret.Add(fli); } - return ret; + return ret.ToArray(); } [AttributeUsage(AttributeTargets.Field)] @@ -520,17 +525,27 @@ namespace OpenRA public static string Translate(string key) { - if (Translations == null || string.IsNullOrEmpty(key)) + if (string.IsNullOrEmpty(key)) return key; - string value; - if (!Translations.TryGetValue(key, out value)) - return key; + lock (TranslationsLock) + { + if (translations == null) + return key; - return value; + string value; + if (!translations.TryGetValue(key, out value)) + return key; + + return value; + } } - public static Dictionary Translations = new Dictionary(); + public static void SetTranslations(IDictionary translations) + { + lock (TranslationsLock) + FieldLoader.translations = new Dictionary(translations); + } } [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] @@ -546,6 +561,7 @@ namespace OpenRA } // mirrors DescriptionAttribute from System.ComponentModel but we dont want to have to use that everywhere. + [AttributeUsage(AttributeTargets.All)] public sealed class DescAttribute : Attribute { public readonly string[] Lines; diff --git a/OpenRA.Game/ModData.cs b/OpenRA.Game/ModData.cs index 58f4ed46ca..d0a2b037d6 100644 --- a/OpenRA.Game/ModData.cs +++ b/OpenRA.Game/ModData.cs @@ -116,7 +116,6 @@ namespace OpenRA if (!Manifest.Translations.Any()) { Languages = new string[0]; - FieldLoader.Translations = new Dictionary(); return; } @@ -144,7 +143,7 @@ namespace OpenRA translations.Add(tkv.Key, tkv.Value); } - FieldLoader.Translations = translations; + FieldLoader.SetTranslations(translations); } public Map PrepareMap(string uid)