diff --git a/OpenRA.FileFormats/FieldLoader.cs b/OpenRA.FileFormats/FieldLoader.cs index 6329ea7231..a727ebb3c6 100644 --- a/OpenRA.FileFormats/FieldLoader.cs +++ b/OpenRA.FileFormats/FieldLoader.cs @@ -27,6 +27,16 @@ namespace OpenRA.FileFormats { public static class FieldLoader { + public static Func InvalidValueAction = (s,t,f) => + { + throw new InvalidOperationException("FieldLoader: Cannot parse `{0}` into `{1}.{2}` ".F(s,f,t) ); + }; + + public static Action UnknownFieldAction = (s,f) => + { + throw new NotImplementedException( "FieldLoader: Missing field `{0}` on `{1}`".F( s, f.Name ) ); + }; + public static void Load(object self, IniSection ini) { foreach (var x in ini) @@ -59,22 +69,39 @@ namespace OpenRA.FileFormats public static void LoadField( object self, string key, string value ) { var field = self.GetType().GetField( key.Trim() ); - if( field == null ) - throw new NotImplementedException( "Missing field `{0}` on `{1}`".F( key.Trim(), self.GetType().Name ) ); - field.SetValue( self, GetValue( field.FieldType, value ) ); - } - public static object GetValue( Type fieldType, string x ) + if( field == null ) + UnknownFieldAction(key.Trim(), self.GetType()); + else + field.SetValue( self, GetValue( field.Name, field.FieldType, value ) ); + } + + public static object GetValue( string field, Type fieldType, string x ) { if (x != null) x = x.Trim(); if( fieldType == typeof( int ) ) - return int.Parse( x ); + { + int res; + if (int.TryParse(x,out res)) + return res; + return InvalidValueAction(x,fieldType, field); + } else if( fieldType == typeof( ushort ) ) - return ushort.Parse( x ); + { + ushort res; + if (ushort.TryParse(x,out res)) + return res; + return InvalidValueAction(x,fieldType, field); + } else if (fieldType == typeof(float)) - return float.Parse(x.Replace("%","")) * (x.Contains( '%' ) ? 0.01f : 1f); + { + float res; + if (float.TryParse(x.Replace("%",""), out res)) + return res * (x.Contains( '%' ) ? 0.01f : 1f); + return InvalidValueAction(x,fieldType, field); + } else if (fieldType == typeof(string)) return x; @@ -82,14 +109,21 @@ namespace OpenRA.FileFormats else if (fieldType == typeof(System.Drawing.Color)) { var parts = x.Split(','); + if (parts.Length != 3) + return InvalidValueAction(x,fieldType, field); + return System.Drawing.Color.FromArgb(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2])); } else if (fieldType.IsEnum) + { + if (!Enum.GetNames(fieldType).Select(a => a.ToLower()).Contains(x.ToLower())) + return InvalidValueAction(x,fieldType, field); return Enum.Parse(fieldType, x, true); - + } + else if (fieldType == typeof(bool)) - return ParseYesNo(x); + return ParseYesNo(x, fieldType, field); else if (fieldType.IsArray) { @@ -100,7 +134,7 @@ namespace OpenRA.FileFormats var ret = Array.CreateInstance(fieldType.GetElementType(), parts.Length); for (int i = 0; i < parts.Length; i++) - ret.SetValue(GetValue(fieldType.GetElementType(), parts[i].Trim()), i); + ret.SetValue(GetValue(field, fieldType.GetElementType(), parts[i].Trim()), i); return ret; } else if (fieldType == typeof(int2)) @@ -108,18 +142,19 @@ namespace OpenRA.FileFormats var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); return new int2(int.Parse(parts[0]), int.Parse(parts[1])); } - else - throw new InvalidOperationException("FieldLoader: don't know how to load field of type " + fieldType.ToString()); + + UnknownFieldAction("[Type] {0}".F(x),fieldType); + return null; } - static bool ParseYesNo( string p ) + static object ParseYesNo( string p, System.Type fieldType, string field ) { p = p.ToLowerInvariant(); if( p == "yes" ) return true; if( p == "true" ) return true; if( p == "no" ) return false; if( p == "false" ) return false; - throw new InvalidOperationException(); + return InvalidValueAction(p,fieldType, field); } } diff --git a/OpenRA.Game/GameRules/UserSettings.cs b/OpenRA.Game/GameRules/UserSettings.cs index cd6db11e37..ab7745dfd7 100644 --- a/OpenRA.Game/GameRules/UserSettings.cs +++ b/OpenRA.Game/GameRules/UserSettings.cs @@ -69,6 +69,22 @@ namespace OpenRA.GameRules defaults = new UserSettings(); SettingsFile = Game.SupportDir + "settings.yaml"; + // Override settings loading to not crash + var err1 = FieldLoader.UnknownFieldAction; + var err2 = FieldLoader.InvalidValueAction; + + FieldLoader.InvalidValueAction = (s,t,f) => + { + object ret = defaults.GetType().GetField(f).GetValue(defaults); + System.Console.WriteLine("FieldLoader: Cannot parse `{0}` into `{2}:{1}`; substituting default `{3}`".F(s,t.Name,f,ret) ); + return ret; + }; + + FieldLoader.UnknownFieldAction = (s,f) => + { + System.Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) ); + }; + if (File.Exists(SettingsFile)) { System.Console.WriteLine("Loading settings file {0}",SettingsFile); @@ -79,6 +95,9 @@ namespace OpenRA.GameRules foreach (var f in this.GetType().GetFields()) if (args.Contains(f.Name)) OpenRA.FileFormats.FieldLoader.LoadField( this, f.Name, args.GetValue(f.Name, "") ); + + FieldLoader.UnknownFieldAction = err1; + FieldLoader.InvalidValueAction = err2; } public void Save()