diff options
Diffstat (limited to 'src/SMAPI/Framework')
-rw-r--r-- | src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs | 24 | ||||
-rw-r--r-- | src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs | 54 |
2 files changed, 29 insertions, 49 deletions
diff --git a/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs b/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs index 60bbd2c7..d7cb2471 100644 --- a/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs +++ b/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs @@ -13,7 +13,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework ** Fields *********/ /// <summary>The comparer which heuristically compares type definitions.</summary> - private static readonly TypeReferenceComparer TypeDefinitionComparer = new TypeReferenceComparer(); + private static readonly TypeReferenceComparer TypeDefinitionComparer = new(); /********* @@ -28,28 +28,6 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework : null; } - /// <summary>Get whether the field is a reference to the expected type and field.</summary> - /// <param name="instruction">The IL instruction.</param> - /// <param name="fullTypeName">The full type name containing the expected field.</param> - /// <param name="fieldName">The name of the expected field.</param> - public static bool IsFieldReferenceTo(Instruction instruction, string fullTypeName, string fieldName) - { - FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); - return RewriteHelper.IsFieldReferenceTo(fieldRef, fullTypeName, fieldName); - } - - /// <summary>Get whether the field is a reference to the expected type and field.</summary> - /// <param name="fieldRef">The field reference to check.</param> - /// <param name="fullTypeName">The full type name containing the expected field.</param> - /// <param name="fieldName">The name of the expected field.</param> - public static bool IsFieldReferenceTo(FieldReference fieldRef, string fullTypeName, string fieldName) - { - return - fieldRef != null - && fieldRef.DeclaringType.FullName == fullTypeName - && fieldRef.Name == fieldName; - } - /// <summary>Get the method reference from an instruction if it matches.</summary> /// <param name="instruction">The IL instruction.</param> public static MethodReference AsMethodReference(Instruction instruction) diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs index 0b679e9d..857a2230 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Reflection; using Mono.Cecil; using Mono.Cecil.Cil; @@ -12,54 +13,55 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters /********* ** Fields *********/ - /// <summary>The type containing the field to which references should be rewritten.</summary> - private readonly Type Type; - - /// <summary>The field name to which references should be rewritten.</summary> - private readonly string FromFieldName; - - /// <summary>The new field to reference.</summary> - private readonly FieldInfo ToField; + /// <summary>The new fields to reference indexed by the old field/type names.</summary> + private readonly Dictionary<string, Dictionary<string, FieldInfo>> FieldMaps = new(); /********* ** Public methods *********/ /// <summary>Construct an instance.</summary> + public FieldReplaceRewriter() + : base(defaultPhrase: "field replacement") { } // will be overridden when a field is replaced + + /// <summary>Add a field to replace.</summary> /// <param name="fromType">The type whose field to rewrite.</param> /// <param name="fromFieldName">The field name to rewrite.</param> /// <param name="toType">The new type which will have the field.</param> /// <param name="toFieldName">The new field name to reference.</param> - public FieldReplaceRewriter(Type fromType, string fromFieldName, Type toType, string toFieldName) - : base(defaultPhrase: $"{fromType.FullName}.{fromFieldName} field") + public FieldReplaceRewriter AddField(Type fromType, string fromFieldName, Type toType, string toFieldName) { - this.Type = fromType; - this.FromFieldName = fromFieldName; - this.ToField = toType.GetField(toFieldName); - if (this.ToField == null) + // get full type name + string fromTypeName = fromType?.FullName; + if (fromTypeName == null) + throw new InvalidOperationException($"Can't replace field for invalid type reference {toType}."); + + // get target field + FieldInfo toField = toType.GetField(toFieldName); + if (toField == null) throw new InvalidOperationException($"The {toType.FullName} class doesn't have a {toFieldName} field."); - } - /// <summary>Construct an instance.</summary> - /// <param name="type">The type whose field to rewrite.</param> - /// <param name="fromFieldName">The field name to rewrite.</param> - /// <param name="toFieldName">The new field name to reference.</param> - public FieldReplaceRewriter(Type type, string fromFieldName, string toFieldName) - : this(type, fromFieldName, type, toFieldName) - { + // add mapping + if (!this.FieldMaps.TryGetValue(fromTypeName, out var fieldMap)) + this.FieldMaps[fromTypeName] = fieldMap = new(); + fieldMap[fromFieldName] = toField; + + return this; } /// <inheritdoc /> public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction) { - // get field reference FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); - if (!RewriteHelper.IsFieldReferenceTo(fieldRef, this.Type.FullName, this.FromFieldName)) + string declaringType = fieldRef?.DeclaringType?.FullName; + + // get mapped field + if (declaringType == null || !this.FieldMaps.TryGetValue(declaringType, out var fieldMap) || !fieldMap.TryGetValue(fieldRef.Name, out FieldInfo toField)) return false; // replace with new field - instruction.Operand = module.ImportReference(this.ToField); - + this.Phrases.Add($"{fieldRef.DeclaringType.Name}.{fieldRef.Name} field"); + instruction.Operand = module.ImportReference(toField); return this.MarkRewritten(); } } |