add logic to detect incompatible mod instructions & reject mod load (#247)
This commit is contained in:
parent
b0fab4a076
commit
6d2d90b768
|
@ -135,6 +135,14 @@ namespace StardewModdingAPI
|
||||||
return new PlatformAssemblyMap(targetPlatform, removeAssemblyReferences, targetAssemblies);
|
return new PlatformAssemblyMap(targetPlatform, removeAssemblyReferences, targetAssemblies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Get finders which match incompatible CIL instructions in mod assemblies.</summary>
|
||||||
|
internal static IEnumerable<IInstructionFinder> GetIncompatibilityFinders()
|
||||||
|
{
|
||||||
|
return new IInstructionFinder[]
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Get rewriters which fix incompatible CIL instructions in mod assemblies.</summary>
|
/// <summary>Get rewriters which fix incompatible CIL instructions in mod assemblies.</summary>
|
||||||
internal static IEnumerable<IInstructionRewriter> GetRewriters()
|
internal static IEnumerable<IInstructionRewriter> GetRewriters()
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,6 +55,7 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <summary>Preprocess and load an assembly.</summary>
|
/// <summary>Preprocess and load an assembly.</summary>
|
||||||
/// <param name="assemblyPath">The assembly file path.</param>
|
/// <param name="assemblyPath">The assembly file path.</param>
|
||||||
/// <returns>Returns the rewrite metadata for the preprocessed assembly.</returns>
|
/// <returns>Returns the rewrite metadata for the preprocessed assembly.</returns>
|
||||||
|
/// <exception cref="IncompatibleInstructionException">An incompatible CIL instruction was found while rewriting the assembly.</exception>
|
||||||
public Assembly Load(string assemblyPath)
|
public Assembly Load(string assemblyPath)
|
||||||
{
|
{
|
||||||
// get referenced local assemblies
|
// get referenced local assemblies
|
||||||
|
@ -159,6 +160,7 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <summary>Rewrite the types referenced by an assembly.</summary>
|
/// <summary>Rewrite the types referenced by an assembly.</summary>
|
||||||
/// <param name="assembly">The assembly to rewrite.</param>
|
/// <param name="assembly">The assembly to rewrite.</param>
|
||||||
/// <returns>Returns whether the assembly was modified.</returns>
|
/// <returns>Returns whether the assembly was modified.</returns>
|
||||||
|
/// <exception cref="IncompatibleInstructionException">An incompatible CIL instruction was found while rewriting the assembly.</exception>
|
||||||
private bool RewriteAssembly(AssemblyDefinition assembly)
|
private bool RewriteAssembly(AssemblyDefinition assembly)
|
||||||
{
|
{
|
||||||
ModuleDefinition module = assembly.MainModule;
|
ModuleDefinition module = assembly.MainModule;
|
||||||
|
@ -189,6 +191,22 @@ namespace StardewModdingAPI.Framework
|
||||||
this.ChangeTypeScope(type);
|
this.ChangeTypeScope(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// throw exception if assembly contains incompatible instructions can't be rewritten
|
||||||
|
{
|
||||||
|
IInstructionFinder[] finders = Constants.GetIncompatibilityFinders().ToArray();
|
||||||
|
foreach (MethodDefinition method in this.GetMethods(module))
|
||||||
|
{
|
||||||
|
foreach (Instruction instruction in method.Body.Instructions)
|
||||||
|
{
|
||||||
|
foreach (IInstructionFinder finder in finders)
|
||||||
|
{
|
||||||
|
if (finder.IsMatch(instruction, platformChanged))
|
||||||
|
throw new IncompatibleInstructionException(finder.NounPhrase, $"Found an incompatible CIL instruction ({finder.NounPhrase}) while loading assembly {assembly.Name.Name}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// rewrite incompatible instructions
|
// rewrite incompatible instructions
|
||||||
bool anyRewritten = false;
|
bool anyRewritten = false;
|
||||||
IInstructionRewriter[] rewriters = Constants.GetRewriters().ToArray();
|
IInstructionRewriter[] rewriters = Constants.GetRewriters().ToArray();
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Framework
|
||||||
|
{
|
||||||
|
/// <summary>An exception raised when an incompatible instruction is found while loading a mod assembly.</summary>
|
||||||
|
internal class IncompatibleInstructionException : Exception
|
||||||
|
{
|
||||||
|
/*********
|
||||||
|
** Accessors
|
||||||
|
*********/
|
||||||
|
/// <summary>A brief noun phrase which describes the incompatible instruction that was found.</summary>
|
||||||
|
public string NounPhrase { get; }
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Public methods
|
||||||
|
*********/
|
||||||
|
/// <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>
|
||||||
|
public IncompatibleInstructionException(string nounPhrase, string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
this.NounPhrase = nounPhrase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -453,6 +453,11 @@ namespace StardewModdingAPI
|
||||||
{
|
{
|
||||||
modAssembly = modAssemblyLoader.Load(assemblyPath);
|
modAssembly = modAssemblyLoader.Load(assemblyPath);
|
||||||
}
|
}
|
||||||
|
catch (IncompatibleInstructionException ex)
|
||||||
|
{
|
||||||
|
this.Monitor.Log($"{skippedPrefix} because it's not compatible with the latest version of the game (detected {ex.NounPhrase}). Please check for a newer version of the mod (you have v{manifest.Version}).", LogLevel.Error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
this.Monitor.Log($"{skippedPrefix} because its DLL '{manifest.EntryDll}' couldn't be loaded.\n{ex.GetLogSummary()}", LogLevel.Error);
|
this.Monitor.Log($"{skippedPrefix} because its DLL '{manifest.EntryDll}' couldn't be loaded.\n{ex.GetLogSummary()}", LogLevel.Error);
|
||||||
|
|
|
@ -154,6 +154,7 @@
|
||||||
<Compile Include="Framework\Content\ContentEventHelper.cs" />
|
<Compile Include="Framework\Content\ContentEventHelper.cs" />
|
||||||
<Compile Include="Framework\Content\ContentEventHelperForDictionary.cs" />
|
<Compile Include="Framework\Content\ContentEventHelperForDictionary.cs" />
|
||||||
<Compile Include="Framework\Content\ContentEventHelperForImage.cs" />
|
<Compile Include="Framework\Content\ContentEventHelperForImage.cs" />
|
||||||
|
<Compile Include="Framework\IncompatibleInstructionException.cs" />
|
||||||
<Compile Include="Framework\Logging\ConsoleInterceptionManager.cs" />
|
<Compile Include="Framework\Logging\ConsoleInterceptionManager.cs" />
|
||||||
<Compile Include="Framework\Logging\InterceptingTextWriter.cs" />
|
<Compile Include="Framework\Logging\InterceptingTextWriter.cs" />
|
||||||
<Compile Include="Framework\CommandHelper.cs" />
|
<Compile Include="Framework\CommandHelper.cs" />
|
||||||
|
|
Loading…
Reference in New Issue