using System; using Mono.Cecil; using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Rewriters { /// Rewrites static field references into constant values. /// The constant value type. internal class StaticFieldToConstantRewriter : BaseInstructionHandler { /********* ** Fields *********/ /// The type containing the field to which references should be rewritten. private readonly Type Type; /// The field name to which references should be rewritten. private readonly string FromFieldName; /// The constant value to replace with. private readonly TValue Value; /********* ** Public methods *********/ /// Construct an instance. /// The type whose field to which references should be rewritten. /// The field name to rewrite. /// The constant value to replace with. public StaticFieldToConstantRewriter(Type type, string fieldName, TValue value) : base(defaultPhrase: $"{type.FullName}.{fieldName} field") { this.Type = type; this.FromFieldName = fieldName; this.Value = value; } /// Rewrite a CIL instruction reference if needed. /// The assembly module containing the instruction. /// The CIL processor. /// The CIL instruction to handle. /// Replaces the CIL instruction with a new one. /// Returns whether the instruction was changed. public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction, Action replaceWith) { // get field reference FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); if (!RewriteHelper.IsFieldReferenceTo(fieldRef, this.Type.FullName, this.FromFieldName)) return false; // rewrite to constant replaceWith(this.CreateConstantInstruction(cil, this.Value)); return this.MarkRewritten(); } /********* ** Private methods *********/ /// Create a CIL constant value instruction. /// The CIL processor. /// The constant value to set. private Instruction CreateConstantInstruction(ILProcessor cil, object value) { if (typeof(TValue) == typeof(int)) return cil.Create(OpCodes.Ldc_I4, (int)value); if (typeof(TValue) == typeof(string)) return cil.Create(OpCodes.Ldstr, (string)value); throw new NotSupportedException($"Rewriting to constant values of type {typeof(TValue)} isn't currently supported."); } } }