diff --git a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/TypeReferenceRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/TypeReferenceRewriter.cs
new file mode 100644
index 00000000..da6d9bc9
--- /dev/null
+++ b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/TypeReferenceRewriter.cs
@@ -0,0 +1,157 @@
+using System;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using StardewModdingAPI.AssemblyRewriters.Finders;
+
+namespace StardewModdingAPI.AssemblyRewriters.Rewriters
+{
+ /// Rewrites all references to a type.
+ public class TypeReferenceRewriter : TypeFinder
+ {
+ /*********
+ ** Properties
+ *********/
+ /// The full type name to which to find references.
+ private readonly string FromTypeName;
+
+ /// The new type to reference.
+ private readonly Type ToType;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Construct an instance.
+ /// The full type name to which to find references.
+ /// The new type to reference.
+ /// A brief noun phrase indicating what the instruction finder matches (or null to generate one).
+ public TypeReferenceRewriter(string fromTypeFullName, Type toType, string nounPhrase = null)
+ : base(fromTypeFullName, nounPhrase)
+ {
+ this.FromTypeName = fromTypeFullName;
+ this.ToType = toType;
+ }
+
+ /// Rewrite a method definition for compatibility.
+ /// The module being rewritten.
+ /// The method definition to rewrite.
+ /// Metadata for mapping assemblies to the current platform.
+ /// Whether the mod was compiled on a different platform.
+ /// Returns whether the instruction was rewritten.
+ /// The CIL instruction is not compatible, and can't be rewritten.
+ public override bool Rewrite(ModuleDefinition module, MethodDefinition method, PlatformAssemblyMap assemblyMap, bool platformChanged)
+ {
+ bool rewritten = false;
+
+ // return type
+ if (this.IsMatch(method.ReturnType))
+ {
+ method.ReturnType = this.RewriteIfNeeded(module, method.ReturnType);
+ rewritten = true;
+ }
+
+ // parameters
+ foreach (ParameterDefinition parameter in method.Parameters)
+ {
+ if (this.IsMatch(parameter.ParameterType))
+ {
+ parameter.ParameterType = this.RewriteIfNeeded(module, parameter.ParameterType);
+ rewritten = true;
+ }
+ }
+
+ // generic parameters
+ for (int i = 0; i < method.GenericParameters.Count; i++)
+ {
+ var parameter = method.GenericParameters[i];
+ if (this.IsMatch(parameter))
+ {
+ TypeReference newType = this.RewriteIfNeeded(module, parameter);
+ if (newType != parameter)
+ method.GenericParameters[i] = new GenericParameter(parameter.Name, newType);
+ rewritten = true;
+ }
+ }
+
+ // local variables
+ foreach (VariableDefinition variable in method.Body.Variables)
+ {
+ if (this.IsMatch(variable.VariableType))
+ {
+ variable.VariableType = this.RewriteIfNeeded(module, variable.VariableType);
+ rewritten = true;
+ }
+ }
+
+ return rewritten;
+ }
+
+ /// 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.
+ /// Whether the mod was compiled on a different platform.
+ /// Returns whether the instruction was rewritten.
+ /// The CIL instruction is not compatible, and can't be rewritten.
+ public override bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged)
+ {
+ if (!this.IsMatch(instruction) && !instruction.ToString().Contains(this.FromTypeName))
+ return false;
+
+ // field reference
+ FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
+ if (fieldRef != null)
+ {
+ fieldRef.DeclaringType = this.RewriteIfNeeded(module, fieldRef.DeclaringType);
+ fieldRef.FieldType = this.RewriteIfNeeded(module, fieldRef.FieldType);
+ }
+
+ // method reference
+ MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
+ if (methodRef != null)
+ {
+ methodRef.DeclaringType = this.RewriteIfNeeded(module, methodRef.DeclaringType);
+ methodRef.ReturnType = this.RewriteIfNeeded(module, methodRef.ReturnType);
+ foreach (var parameter in methodRef.Parameters)
+ parameter.ParameterType = this.RewriteIfNeeded(module, parameter.ParameterType);
+ }
+
+ // type reference
+ if (instruction.Operand is TypeReference typeRef)
+ {
+ TypeReference newRef = this.RewriteIfNeeded(module, typeRef);
+ if (typeRef != newRef)
+ cil.Replace(instruction, cil.Create(instruction.OpCode, newRef));
+ }
+
+ return true;
+ }
+
+ /*********
+ ** Private methods
+ *********/
+ /// Get the adjusted type reference if it matches, else the same value.
+ /// The module being rewritten.
+ /// The type to replace if it matches.
+ private TypeReference RewriteIfNeeded(ModuleDefinition module, TypeReference type)
+ {
+ // root type
+ if (type.FullName == this.FromTypeName)
+ return module.Import(this.ToType);
+
+ // generic arguments
+ if (type is GenericInstanceType genericType)
+ {
+ for (int i = 0; i < genericType.GenericArguments.Count; i++)
+ genericType.GenericArguments[i] = this.RewriteIfNeeded(module, genericType.GenericArguments[i]);
+ }
+
+ // generic parameters (e.g. constraints)
+ for (int i = 0; i < type.GenericParameters.Count; i++)
+ type.GenericParameters[i] = new GenericParameter(this.RewriteIfNeeded(module, type.GenericParameters[i]));
+
+ return type;
+ }
+ }
+}
diff --git a/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj
index 3c3acde3..775de9f2 100644
--- a/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj
+++ b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj
@@ -76,6 +76,7 @@
+