diff --git a/OpenRA.FileFormats/Exts.cs b/OpenRA.FileFormats/Exts.cs index 2fe8478c2b..867c64489e 100644 --- a/OpenRA.FileFormats/Exts.cs +++ b/OpenRA.FileFormats/Exts.cs @@ -73,5 +73,17 @@ namespace OpenRA { return mi.GetCustomAttributes(typeof(T), true).Length != 0; } + + public static T[] GetCustomAttributes( this MemberInfo mi, bool inherit ) + where T : class + { + return (T[])mi.GetCustomAttributes( typeof( T ), inherit ); + } + + public static T[] GetCustomAttributes( this ParameterInfo mi ) + where T : class + { + return (T[])mi.GetCustomAttributes( typeof( T ), true ); + } } } diff --git a/OpenRA.FileFormats/FieldLoader.cs b/OpenRA.FileFormats/FieldLoader.cs index f80c09acdb..927c1c28fb 100644 --- a/OpenRA.FileFormats/FieldLoader.cs +++ b/OpenRA.FileFormats/FieldLoader.cs @@ -179,9 +179,9 @@ namespace OpenRA.FileFormats foreach( var field in type.GetFields() ) { - var load = (LoadAttribute[])field.GetCustomAttributes( typeof( LoadAttribute ), false ); - var loadUsing = (LoadUsingAttribute[])field.GetCustomAttributes( typeof( LoadUsingAttribute ), false ); - var fromYamlKey = (FieldFromYamlKeyAttribute[])field.GetCustomAttributes( typeof( FieldFromYamlKeyAttribute ), false ); + var load = field.GetCustomAttributes( false ); + var loadUsing = field.GetCustomAttributes( false ); + var fromYamlKey = field.GetCustomAttributes( false ); if( loadUsing.Length != 0 ) ret[ field ] = ( _1, fieldType, yaml ) => loadUsing[ 0 ].LoaderFunc( field )( yaml ); else if( fromYamlKey.Length != 0 ) diff --git a/OpenRA.Game/ObjectCreator.cs b/OpenRA.Game/ObjectCreator.cs index 2ac3e2d4ba..e5ac5ba61c 100755 --- a/OpenRA.Game/ObjectCreator.cs +++ b/OpenRA.Game/ObjectCreator.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Reflection; using OpenRA.FileFormats; +using System.Collections.Generic; namespace OpenRA { @@ -30,19 +31,61 @@ namespace OpenRA public static Action MissingTypeAction = s => { throw new InvalidOperationException("Cannot locate type: {0}".F(s)); }; - public T CreateObject(string classname) + public T CreateObject(string className) { - foreach (var mod in ModAssemblies) - { - var fullTypeName = mod.Second + "." + classname; - var obj = mod.First.CreateInstance(fullTypeName); - if (obj != null) - return (T)obj; - } + return CreateObject( className, new Dictionary() ); + } - MissingTypeAction(classname); + public T CreateObject( string className, Dictionary args ) + { + foreach( var mod in ModAssemblies ) + { + var type = mod.First.GetType( mod.Second + "." + className, false ); + if( type == null ) continue; + var ctors = type.GetConstructors().Where( x => x.HasAttribute() ).ToList(); + if( ctors.Count == 0 ) + return (T)CreateBasic( type ); + else if( ctors.Count == 1 ) + return (T)CreateUsingArgs( ctors[ 0 ], args ); + else + throw new InvalidOperationException( "ObjectCreator: UseCtor on multiple constructors; invalid." ); + } + MissingTypeAction(className); return default(T); } + public object CreateBasic( Type type ) + { + return type.GetConstructor( new Type[ 0 ] ).Invoke( new object[ 0 ] ); + } + + public object CreateUsingArgs( ConstructorInfo ctor, Dictionary args ) + { + var p = ctor.GetParameters(); + var a = new object[ p.Length ]; + for( int i = 0 ; i < p.Length ; i++ ) + { + var attrs = p[ i ].GetCustomAttributes(); + if( attrs.Length != 1 ) throw new InvalidOperationException( "ObjectCreator: argument in [UseCtor] doesn't have [Param]" ); + a[ i ] = args[ attrs[ 0 ].ParamName ]; + } + return ctor.Invoke( a ); + } + + [AttributeUsage( AttributeTargets.Parameter )] + public class ParamAttribute : Attribute + { + public string ParamName { get; private set; } + + public ParamAttribute( string paramName ) + { + ParamName = paramName; + } + } + + [AttributeUsage( AttributeTargets.Constructor )] + public class UseCtorAttribute : Attribute + { + } } }