using System;
using System.Reflection;
using Mono.Cecil;
using Mono.Cecil.Cil;
using StardewModdingAPI.AssemblyRewriters.Finders;
namespace StardewModdingAPI.AssemblyRewriters.Rewriters
{
/// Rewrites references to one field with another.
public class FieldReplaceRewriter : FieldFinder, IInstructionRewriter
{
/*********
** Properties
*********/
/// The type whose field to which references should be rewritten.
private readonly Type Type;
/// The new field name to reference.
private readonly string ToFieldName;
/*********
** Public methods
*********/
/// Construct an instance.
/// The type whose field to which references should be rewritten.
/// The field name to rewrite.
/// The new field name to reference.
/// A brief noun phrase indicating what the instruction finder matches (or null to generate one).
public FieldReplaceRewriter(Type type, string fromFieldName, string toFieldName, string nounPhrase = null)
: base(type.FullName, fromFieldName, nounPhrase)
{
this.Type = type;
this.ToFieldName = toFieldName;
}
/// Rewrite a CIL instruction for compatibility.
/// The module being rewritten.
/// The CIL rewriter.
/// The instruction to rewrite.
/// Metadata for mapping assemblies to the current platform.
public void Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap)
{
FieldInfo field = this.Type.GetField(this.ToFieldName);
if (field == null)
throw new InvalidOperationException($"The {this.Type.FullName} class doesn't have a {this.ToFieldName} field.");
FieldReference newRef = module.Import(field);
cil.Replace(instruction, cil.Create(instruction.OpCode, newRef));
}
}
}