merge CIL finders & rewriters into one interface (#254)
This commit is contained in:
parent
23443721cd
commit
85ed488090
|
@ -3,8 +3,8 @@ using Mono.Cecil.Cil;
|
|||
|
||||
namespace StardewModdingAPI.AssemblyRewriters.Finders
|
||||
{
|
||||
/// <summary>Finds CIL instructions that reference a given event.</summary>
|
||||
public sealed class EventFinder : IInstructionFinder
|
||||
/// <summary>Finds incompatible CIL instructions that reference a given event and throws an <see cref="IncompatibleInstructionException"/>.</summary>
|
||||
public class EventFinder : IInstructionRewriter
|
||||
{
|
||||
/*********
|
||||
** Properties
|
||||
|
@ -37,6 +37,22 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders
|
|||
this.NounPhrase = nounPhrase ?? $"{fullTypeName}.{eventName} event";
|
||||
}
|
||||
|
||||
/// <summary>Rewrite a CIL instruction for compatibility.</summary>
|
||||
/// <param name="module">The module being rewritten.</param>
|
||||
/// <param name="cil">The CIL rewriter.</param>
|
||||
/// <param name="instruction">The instruction to rewrite.</param>
|
||||
/// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param>
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
/// <returns>Returns whether the instruction was rewritten.</returns>
|
||||
/// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception>
|
||||
public bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged)
|
||||
{
|
||||
if (!this.IsMatch(instruction, platformChanged))
|
||||
return false;
|
||||
|
||||
throw new IncompatibleInstructionException(this.NounPhrase);
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** Protected methods
|
||||
|
@ -44,7 +60,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders
|
|||
/// <summary>Get whether a CIL instruction matches.</summary>
|
||||
/// <param name="instruction">The IL instruction.</param>
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
public bool IsMatch(Instruction instruction, bool platformChanged)
|
||||
protected bool IsMatch(Instruction instruction, bool platformChanged)
|
||||
{
|
||||
MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
|
||||
return
|
||||
|
|
|
@ -3,8 +3,8 @@ using Mono.Cecil.Cil;
|
|||
|
||||
namespace StardewModdingAPI.AssemblyRewriters.Finders
|
||||
{
|
||||
/// <summary>Finds CIL instructions that reference a given field.</summary>
|
||||
public class FieldFinder : IInstructionFinder
|
||||
/// <summary>Finds incompatible CIL instructions that reference a given field and throws an <see cref="IncompatibleInstructionException"/>.</summary>
|
||||
public class FieldFinder : IInstructionRewriter
|
||||
{
|
||||
/*********
|
||||
** Properties
|
||||
|
@ -37,6 +37,22 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders
|
|||
this.NounPhrase = nounPhrase ?? $"{fullTypeName}.{fieldName} field";
|
||||
}
|
||||
|
||||
/// <summary>Rewrite a CIL instruction for compatibility.</summary>
|
||||
/// <param name="module">The module being rewritten.</param>
|
||||
/// <param name="cil">The CIL rewriter.</param>
|
||||
/// <param name="instruction">The instruction to rewrite.</param>
|
||||
/// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param>
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
/// <returns>Returns whether the instruction was rewritten.</returns>
|
||||
/// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception>
|
||||
public virtual bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged)
|
||||
{
|
||||
if (!this.IsMatch(instruction, platformChanged))
|
||||
return false;
|
||||
|
||||
throw new IncompatibleInstructionException(this.NounPhrase);
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** Protected methods
|
||||
|
@ -44,7 +60,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders
|
|||
/// <summary>Get whether a CIL instruction matches.</summary>
|
||||
/// <param name="instruction">The IL instruction.</param>
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
public bool IsMatch(Instruction instruction, bool platformChanged)
|
||||
protected bool IsMatch(Instruction instruction, bool platformChanged)
|
||||
{
|
||||
FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
|
||||
return
|
||||
|
|
|
@ -3,8 +3,8 @@ using Mono.Cecil.Cil;
|
|||
|
||||
namespace StardewModdingAPI.AssemblyRewriters.Finders
|
||||
{
|
||||
/// <summary>Finds CIL instructions that reference a given method.</summary>
|
||||
public class MethodFinder : IInstructionFinder
|
||||
/// <summary>Finds incompatible CIL instructions that reference a given method and throws an <see cref="IncompatibleInstructionException"/>.</summary>
|
||||
public class MethodFinder : IInstructionRewriter
|
||||
{
|
||||
/*********
|
||||
** Properties
|
||||
|
@ -37,6 +37,22 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders
|
|||
this.NounPhrase = nounPhrase ?? $"{fullTypeName}.{methodName} method";
|
||||
}
|
||||
|
||||
/// <summary>Rewrite a CIL instruction for compatibility.</summary>
|
||||
/// <param name="module">The module being rewritten.</param>
|
||||
/// <param name="cil">The CIL rewriter.</param>
|
||||
/// <param name="instruction">The instruction to rewrite.</param>
|
||||
/// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param>
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
/// <returns>Returns whether the instruction was rewritten.</returns>
|
||||
/// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception>
|
||||
public bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged)
|
||||
{
|
||||
if (!this.IsMatch(instruction, platformChanged))
|
||||
return false;
|
||||
|
||||
throw new IncompatibleInstructionException(this.NounPhrase);
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** Protected methods
|
||||
|
@ -44,7 +60,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders
|
|||
/// <summary>Get whether a CIL instruction matches.</summary>
|
||||
/// <param name="instruction">The IL instruction.</param>
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
public bool IsMatch(Instruction instruction, bool platformChanged)
|
||||
protected bool IsMatch(Instruction instruction, bool platformChanged)
|
||||
{
|
||||
MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
|
||||
return
|
||||
|
|
|
@ -4,8 +4,8 @@ using Mono.Cecil.Cil;
|
|||
|
||||
namespace StardewModdingAPI.AssemblyRewriters.Finders
|
||||
{
|
||||
/// <summary>Finds CIL instructions that reference a given type.</summary>
|
||||
public class TypeFinder : IInstructionFinder
|
||||
/// <summary>Finds incompatible CIL instructions that reference a given type and throws an <see cref="IncompatibleInstructionException"/>.</summary>
|
||||
public class TypeFinder : IInstructionRewriter
|
||||
{
|
||||
/*********
|
||||
** Accessors
|
||||
|
@ -33,10 +33,30 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders
|
|||
this.NounPhrase = nounPhrase ?? $"{fullTypeName} type";
|
||||
}
|
||||
|
||||
/// <summary>Rewrite a CIL instruction for compatibility.</summary>
|
||||
/// <param name="module">The module being rewritten.</param>
|
||||
/// <param name="cil">The CIL rewriter.</param>
|
||||
/// <param name="instruction">The instruction to rewrite.</param>
|
||||
/// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param>
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
/// <returns>Returns whether the instruction was rewritten.</returns>
|
||||
/// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception>
|
||||
public virtual bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged)
|
||||
{
|
||||
if (!this.IsMatch(instruction, platformChanged))
|
||||
return false;
|
||||
|
||||
throw new IncompatibleInstructionException(this.NounPhrase);
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** Protected methods
|
||||
*********/
|
||||
/// <summary>Get whether a CIL instruction matches.</summary>
|
||||
/// <param name="instruction">The IL instruction.</param>
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
public bool IsMatch(Instruction instruction, bool platformChanged)
|
||||
protected bool IsMatch(Instruction instruction, bool platformChanged)
|
||||
{
|
||||
string fullName = this.FullTypeName;
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
using Mono.Cecil.Cil;
|
||||
|
||||
namespace StardewModdingAPI.AssemblyRewriters
|
||||
{
|
||||
/// <summary>Finds CIL instructions considered incompatible.</summary>
|
||||
public interface IInstructionFinder
|
||||
{
|
||||
/*********
|
||||
** Accessors
|
||||
*********/
|
||||
/// <summary>A brief noun phrase indicating what the instruction finder matches.</summary>
|
||||
string NounPhrase { get; }
|
||||
|
||||
|
||||
/*********
|
||||
** Methods
|
||||
*********/
|
||||
/// <summary>Get whether a CIL instruction matches.</summary>
|
||||
/// <param name="instruction">The IL instruction.</param>
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
bool IsMatch(Instruction instruction, bool platformChanged);
|
||||
}
|
||||
}
|
|
@ -3,9 +3,16 @@ using Mono.Cecil.Cil;
|
|||
|
||||
namespace StardewModdingAPI.AssemblyRewriters
|
||||
{
|
||||
/// <summary>Rewrites a CIL instruction for compatibility.</summary>
|
||||
public interface IInstructionRewriter : IInstructionFinder
|
||||
/// <summary>Rewrites CIL instructions for compatibility.</summary>
|
||||
public interface IInstructionRewriter
|
||||
{
|
||||
/*********
|
||||
** Accessors
|
||||
*********/
|
||||
/// <summary>A brief noun phrase indicating what the rewriter matches.</summary>
|
||||
string NounPhrase { get; }
|
||||
|
||||
|
||||
/*********
|
||||
** Methods
|
||||
*********/
|
||||
|
@ -14,6 +21,9 @@ namespace StardewModdingAPI.AssemblyRewriters
|
|||
/// <param name="cil">The CIL rewriter.</param>
|
||||
/// <param name="instruction">The instruction to rewrite.</param>
|
||||
/// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param>
|
||||
void Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap);
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
/// <returns>Returns whether the instruction was rewritten.</returns>
|
||||
/// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception>
|
||||
bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace StardewModdingAPI.Framework
|
||||
namespace StardewModdingAPI.AssemblyRewriters
|
||||
{
|
||||
/// <summary>An exception raised when an incompatible instruction is found while loading a mod assembly.</summary>
|
||||
internal class IncompatibleInstructionException : Exception
|
||||
public class IncompatibleInstructionException : Exception
|
||||
{
|
||||
/*********
|
||||
** Accessors
|
||||
|
@ -15,6 +15,14 @@ namespace StardewModdingAPI.Framework
|
|||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="nounPhrase">A brief noun phrase which describes the incompatible instruction that was found.</param>
|
||||
public IncompatibleInstructionException(string nounPhrase)
|
||||
: base($"Found an incompatible CIL instruction ({nounPhrase}).")
|
||||
{
|
||||
this.NounPhrase = nounPhrase;
|
||||
}
|
||||
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="nounPhrase">A brief noun phrase which describes the incompatible instruction that was found.</param>
|
||||
/// <param name="message">A message which describes the error.</param>
|
|
@ -7,16 +7,13 @@ using StardewModdingAPI.AssemblyRewriters.Finders;
|
|||
namespace StardewModdingAPI.AssemblyRewriters.Rewriters
|
||||
{
|
||||
/// <summary>Rewrites references to one field with another.</summary>
|
||||
public class FieldReplaceRewriter : FieldFinder, IInstructionRewriter
|
||||
public class FieldReplaceRewriter : FieldFinder
|
||||
{
|
||||
/*********
|
||||
** Properties
|
||||
*********/
|
||||
/// <summary>The type whose field to which references should be rewritten.</summary>
|
||||
private readonly Type Type;
|
||||
|
||||
/// <summary>The new field name to reference.</summary>
|
||||
private readonly string ToFieldName;
|
||||
/// <summary>The new field to reference.</summary>
|
||||
private readonly FieldInfo ToField;
|
||||
|
||||
|
||||
/*********
|
||||
|
@ -30,8 +27,9 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters
|
|||
public FieldReplaceRewriter(Type type, string fromFieldName, string toFieldName, string nounPhrase = null)
|
||||
: base(type.FullName, fromFieldName, nounPhrase)
|
||||
{
|
||||
this.Type = type;
|
||||
this.ToFieldName = toFieldName;
|
||||
this.ToField = type.GetField(toFieldName);
|
||||
if (this.ToField == null)
|
||||
throw new InvalidOperationException($"The {type.FullName} class doesn't have a {toFieldName} field.");
|
||||
}
|
||||
|
||||
/// <summary>Rewrite a CIL instruction for compatibility.</summary>
|
||||
|
@ -39,13 +37,17 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters
|
|||
/// <param name="cil">The CIL rewriter.</param>
|
||||
/// <param name="instruction">The instruction to rewrite.</param>
|
||||
/// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param>
|
||||
public void Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap)
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
/// <returns>Returns whether the instruction was rewritten.</returns>
|
||||
/// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception>
|
||||
public override bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged)
|
||||
{
|
||||
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);
|
||||
if (!this.IsMatch(instruction, platformChanged))
|
||||
return false;
|
||||
|
||||
FieldReference newRef = module.Import(this.ToField);
|
||||
cil.Replace(instruction, cil.Create(instruction.OpCode, newRef));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ using StardewModdingAPI.AssemblyRewriters.Finders;
|
|||
namespace StardewModdingAPI.AssemblyRewriters.Rewriters
|
||||
{
|
||||
/// <summary>Rewrites field references into property references.</summary>
|
||||
public class FieldToPropertyRewriter : FieldFinder, IInstructionRewriter
|
||||
public class FieldToPropertyRewriter : FieldFinder
|
||||
{
|
||||
/*********
|
||||
** Properties
|
||||
|
@ -37,11 +37,18 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters
|
|||
/// <param name="cil">The CIL rewriter.</param>
|
||||
/// <param name="instruction">The instruction to rewrite.</param>
|
||||
/// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param>
|
||||
public void Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap)
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
/// <returns>Returns whether the instruction was rewritten.</returns>
|
||||
/// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception>
|
||||
public override bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged)
|
||||
{
|
||||
if (!this.IsMatch(instruction, platformChanged))
|
||||
return false;
|
||||
|
||||
string methodPrefix = instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld ? "get" : "set";
|
||||
MethodReference propertyRef = module.Import(this.Type.GetMethod($"{methodPrefix}_{this.FieldName}"));
|
||||
cil.Replace(instruction, cil.Create(OpCodes.Call, propertyRef));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,10 +43,32 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters
|
|||
this.OnlyIfPlatformChanged = onlyIfPlatformChanged;
|
||||
}
|
||||
|
||||
/// <summary>Rewrite a CIL instruction for compatibility.</summary>
|
||||
/// <param name="module">The module being rewritten.</param>
|
||||
/// <param name="cil">The CIL rewriter.</param>
|
||||
/// <param name="instruction">The instruction to rewrite.</param>
|
||||
/// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param>
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
/// <returns>Returns whether the instruction was rewritten.</returns>
|
||||
/// <exception cref="IncompatibleInstructionException">The CIL instruction is not compatible, and can't be rewritten.</exception>
|
||||
public bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged)
|
||||
{
|
||||
if (!this.IsMatch(instruction, platformChanged))
|
||||
return false;
|
||||
|
||||
MethodReference methodRef = (MethodReference)instruction.Operand;
|
||||
methodRef.DeclaringType = module.Import(this.ToType);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** Protected methods
|
||||
*********/
|
||||
/// <summary>Get whether a CIL instruction matches.</summary>
|
||||
/// <param name="instruction">The IL instruction.</param>
|
||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||
public bool IsMatch(Instruction instruction, bool platformChanged)
|
||||
protected bool IsMatch(Instruction instruction, bool platformChanged)
|
||||
{
|
||||
MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
|
||||
return
|
||||
|
@ -55,16 +77,5 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters
|
|||
&& methodRef.DeclaringType.FullName == this.FromType.FullName
|
||||
&& RewriteHelper.HasMatchingSignature(this.ToType, methodRef);
|
||||
}
|
||||
|
||||
/// <summary>Rewrite a CIL instruction for compatibility.</summary>
|
||||
/// <param name="module">The module being rewritten.</param>
|
||||
/// <param name="cil">The CIL rewriter.</param>
|
||||
/// <param name="instruction">The instruction to rewrite.</param>
|
||||
/// <param name="assemblyMap">Metadata for mapping assemblies to the current platform.</param>
|
||||
public void Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap)
|
||||
{
|
||||
MethodReference methodRef = (MethodReference)instruction.Operand;
|
||||
methodRef.DeclaringType = module.Import(this.ToType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,8 +70,8 @@
|
|||
<Compile Include="Finders\FieldFinder.cs" />
|
||||
<Compile Include="Finders\MethodFinder.cs" />
|
||||
<Compile Include="Finders\TypeFinder.cs" />
|
||||
<Compile Include="IncompatibleInstructionException.cs" />
|
||||
<Compile Include="RewriteHelper.cs" />
|
||||
<Compile Include="IInstructionFinder.cs" />
|
||||
<Compile Include="IInstructionRewriter.cs" />
|
||||
<Compile Include="Platform.cs" />
|
||||
<Compile Include="PlatformAssemblyMap.cs" />
|
||||
|
|
|
@ -137,12 +137,15 @@ namespace StardewModdingAPI
|
|||
return new PlatformAssemblyMap(targetPlatform, removeAssemblyReferences, targetAssemblies);
|
||||
}
|
||||
|
||||
/// <summary>Get finders which match incompatible CIL instructions in mod assemblies.</summary>
|
||||
internal static IEnumerable<IInstructionFinder> GetIncompatibilityFinders()
|
||||
/// <summary>Get rewriters which detect or fix incompatible CIL instructions in mod assemblies.</summary>
|
||||
internal static IEnumerable<IInstructionRewriter> GetRewriters()
|
||||
{
|
||||
return new IInstructionFinder[]
|
||||
return new IInstructionRewriter[]
|
||||
{
|
||||
// changes in Stardew Valley 1.2 (that don't have rewriters)
|
||||
/****
|
||||
** Finders throw an exception when incompatible code is found.
|
||||
****/
|
||||
// changes in Stardew Valley 1.2 (with no rewriters)
|
||||
new FieldFinder("StardewValley.Item", "set_Name"),
|
||||
|
||||
// APIs removed in SMAPI 1.9
|
||||
|
@ -161,15 +164,11 @@ namespace StardewModdingAPI
|
|||
new EventFinder("StardewModdingAPI.Events.GraphicsEvents", "OnPostRenderHudEventNoCheck"),
|
||||
new EventFinder("StardewModdingAPI.Events.GraphicsEvents", "OnPostRenderGuiEventNoCheck"),
|
||||
new EventFinder("StardewModdingAPI.Events.GraphicsEvents", "OnPreRenderHudEventNoCheck"),
|
||||
new EventFinder("StardewModdingAPI.Events.GraphicsEvents", "OnPreRenderGuiEventNoCheck")
|
||||
};
|
||||
}
|
||||
new EventFinder("StardewModdingAPI.Events.GraphicsEvents", "OnPreRenderGuiEventNoCheck"),
|
||||
|
||||
/// <summary>Get rewriters which fix incompatible CIL instructions in mod assemblies.</summary>
|
||||
internal static IEnumerable<IInstructionRewriter> GetRewriters()
|
||||
{
|
||||
return new IInstructionRewriter[]
|
||||
{
|
||||
/****
|
||||
** Rewriters change CIL as needed to fix incompatible code
|
||||
****/
|
||||
// crossplatform
|
||||
new MethodParentRewriter(typeof(SpriteBatch), typeof(SpriteBatchWrapper), onlyIfPlatformChanged: true),
|
||||
|
||||
|
|
|
@ -193,33 +193,30 @@ namespace StardewModdingAPI.Framework
|
|||
this.ChangeTypeScope(type);
|
||||
}
|
||||
|
||||
// find incompatible instructions
|
||||
// find (and optionally rewrite) incompatible instructions
|
||||
bool anyRewritten = false;
|
||||
IInstructionFinder[] finders = Constants.GetIncompatibilityFinders().ToArray();
|
||||
IInstructionRewriter[] rewriters = Constants.GetRewriters().ToArray();
|
||||
foreach (MethodDefinition method in this.GetMethods(module))
|
||||
{
|
||||
ILProcessor cil = method.Body.GetILProcessor();
|
||||
foreach (Instruction instruction in cil.Body.Instructions.ToArray())
|
||||
{
|
||||
// throw exception if instruction is incompatible but can't be rewritten
|
||||
IInstructionFinder finder = finders.FirstOrDefault(p => p.IsMatch(instruction, platformChanged));
|
||||
if (finder != null)
|
||||
{
|
||||
if (!assumeCompatible)
|
||||
throw new IncompatibleInstructionException(finder.NounPhrase, $"Found an incompatible CIL instruction ({finder.NounPhrase}) while loading assembly {assembly.Name.Name}.");
|
||||
this.LogOnce(this.Monitor, loggedMessages, $"Found an incompatible CIL instruction ({finder.NounPhrase}) while loading assembly {assembly.Name.Name}, but SMAPI is configured to allow it anyway. The mod may crash or behave unexpectedly.", LogLevel.Warn);
|
||||
}
|
||||
|
||||
// rewrite instruction if needed
|
||||
foreach (IInstructionRewriter rewriter in rewriters)
|
||||
{
|
||||
if (!rewriter.IsMatch(instruction, platformChanged))
|
||||
continue;
|
||||
|
||||
this.LogOnce(this.Monitor, loggedMessages, $"Rewriting {assembly.Name.Name} to fix {rewriter.NounPhrase}...");
|
||||
rewriter.Rewrite(module, cil, instruction, this.AssemblyMap);
|
||||
anyRewritten = true;
|
||||
try
|
||||
{
|
||||
if (rewriter.Rewrite(module, cil, instruction, this.AssemblyMap, platformChanged))
|
||||
{
|
||||
this.LogOnce(this.Monitor, loggedMessages, $"Rewrote {assembly.Name.Name} to fix {rewriter.NounPhrase}...");
|
||||
anyRewritten = true;
|
||||
}
|
||||
}
|
||||
catch (IncompatibleInstructionException)
|
||||
{
|
||||
if (!assumeCompatible)
|
||||
throw new IncompatibleInstructionException(rewriter.NounPhrase, $"Found an incompatible CIL instruction ({rewriter.NounPhrase}) while loading assembly {assembly.Name.Name}.");
|
||||
this.LogOnce(this.Monitor, loggedMessages, $"Found an incompatible CIL instruction ({rewriter.NounPhrase}) while loading assembly {assembly.Name.Name}, but SMAPI is configured to allow it anyway. The mod may crash or behave unexpectedly.", LogLevel.Warn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ using System.Windows.Forms;
|
|||
#endif
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Newtonsoft.Json;
|
||||
using StardewModdingAPI.AssemblyRewriters;
|
||||
using StardewModdingAPI.Events;
|
||||
using StardewModdingAPI.Framework;
|
||||
using StardewModdingAPI.Framework.Logging;
|
||||
|
|
|
@ -150,7 +150,6 @@
|
|||
<Compile Include="Framework\Content\ContentEventHelper.cs" />
|
||||
<Compile Include="Framework\Content\ContentEventHelperForDictionary.cs" />
|
||||
<Compile Include="Framework\Content\ContentEventHelperForImage.cs" />
|
||||
<Compile Include="Framework\IncompatibleInstructionException.cs" />
|
||||
<Compile Include="Framework\Logging\ConsoleInterceptionManager.cs" />
|
||||
<Compile Include="Framework\Logging\InterceptingTextWriter.cs" />
|
||||
<Compile Include="Framework\CommandHelper.cs" />
|
||||
|
|
Loading…
Reference in New Issue