log rewritten instructions (#247)
This commit is contained in:
parent
3663f70603
commit
b0fab4a076
|
@ -6,6 +6,13 @@ namespace StardewModdingAPI.AssemblyRewriters.Framework
|
||||||
/// <summary>Base class for a field finder.</summary>
|
/// <summary>Base class for a field finder.</summary>
|
||||||
public abstract class BaseFieldFinder : IInstructionFinder
|
public abstract class BaseFieldFinder : IInstructionFinder
|
||||||
{
|
{
|
||||||
|
/*********
|
||||||
|
** Accessors
|
||||||
|
*********/
|
||||||
|
/// <summary>A brief noun phrase indicating what the instruction finder matches.</summary>
|
||||||
|
public abstract string NounPhrase { get; }
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
|
|
|
@ -9,6 +9,13 @@ namespace StardewModdingAPI.AssemblyRewriters.Framework
|
||||||
/// <summary>Base class for a method finder.</summary>
|
/// <summary>Base class for a method finder.</summary>
|
||||||
public abstract class BaseMethodFinder : IInstructionFinder
|
public abstract class BaseMethodFinder : IInstructionFinder
|
||||||
{
|
{
|
||||||
|
/*********
|
||||||
|
** Accessors
|
||||||
|
*********/
|
||||||
|
/// <summary>A brief noun phrase indicating what the instruction finder matches.</summary>
|
||||||
|
public abstract string NounPhrase { get; }
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
|
|
|
@ -5,6 +5,16 @@ namespace StardewModdingAPI.AssemblyRewriters
|
||||||
/// <summary>Finds CIL instructions considered incompatible.</summary>
|
/// <summary>Finds CIL instructions considered incompatible.</summary>
|
||||||
public interface IInstructionFinder
|
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>
|
/// <summary>Get whether a CIL instruction matches.</summary>
|
||||||
/// <param name="instruction">The IL instruction.</param>
|
/// <param name="instruction">The IL instruction.</param>
|
||||||
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
/// <param name="platformChanged">Whether the mod was compiled on a different platform.</param>
|
||||||
|
|
|
@ -6,6 +6,9 @@ namespace StardewModdingAPI.AssemblyRewriters
|
||||||
/// <summary>Rewrites a CIL instruction for compatibility.</summary>
|
/// <summary>Rewrites a CIL instruction for compatibility.</summary>
|
||||||
public interface IInstructionRewriter : IInstructionFinder
|
public interface IInstructionRewriter : IInstructionFinder
|
||||||
{
|
{
|
||||||
|
/*********
|
||||||
|
** Methods
|
||||||
|
*********/
|
||||||
/// <summary>Rewrite a CIL instruction for compatibility.</summary>
|
/// <summary>Rewrite a CIL instruction for compatibility.</summary>
|
||||||
/// <param name="module">The module being rewritten.</param>
|
/// <param name="module">The module being rewritten.</param>
|
||||||
/// <param name="cil">The CIL rewriter.</param>
|
/// <param name="cil">The CIL rewriter.</param>
|
||||||
|
|
|
@ -12,6 +12,13 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters.Crossplatform
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "This class is not meant to be used directly, and is deliberately named to make it easier to know what it changes at a glance.")]
|
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "This class is not meant to be used directly, and is deliberately named to make it easier to know what it changes at a glance.")]
|
||||||
public class SpriteBatch_MethodRewriter : BaseMethodRewriter
|
public class SpriteBatch_MethodRewriter : BaseMethodRewriter
|
||||||
{
|
{
|
||||||
|
/*********
|
||||||
|
** Accessors
|
||||||
|
*********/
|
||||||
|
/// <summary>A brief noun phrase indicating what the instruction finder matches.</summary>
|
||||||
|
public override string NounPhrase { get; } = $"{nameof(SpriteBatch)} methods";
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Protected methods
|
** Protected methods
|
||||||
*********/
|
*********/
|
||||||
|
|
|
@ -11,6 +11,13 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters.SDV1_2
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "This class is not meant to be used directly, and is deliberately named to make it easier to know what it changes at a glance.")]
|
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "This class is not meant to be used directly, and is deliberately named to make it easier to know what it changes at a glance.")]
|
||||||
public class Game1_ActiveClickableMenu_FieldRewriter : BaseFieldRewriter
|
public class Game1_ActiveClickableMenu_FieldRewriter : BaseFieldRewriter
|
||||||
{
|
{
|
||||||
|
/*********
|
||||||
|
** Accessors
|
||||||
|
*********/
|
||||||
|
/// <summary>A brief noun phrase indicating what the instruction finder matches.</summary>
|
||||||
|
public override string NounPhrase { get; } = $"{nameof(Game1)}.{nameof(Game1.activeClickableMenu)} field";
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Protected methods
|
** Protected methods
|
||||||
*********/
|
*********/
|
||||||
|
|
|
@ -11,6 +11,13 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters.SDV1_2
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "This class is not meant to be used directly, and is deliberately named to make it easier to know what it changes at a glance.")]
|
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "This class is not meant to be used directly, and is deliberately named to make it easier to know what it changes at a glance.")]
|
||||||
public class Game1_GameMode_FieldRewriter : BaseFieldRewriter
|
public class Game1_GameMode_FieldRewriter : BaseFieldRewriter
|
||||||
{
|
{
|
||||||
|
/*********
|
||||||
|
** Accessors
|
||||||
|
*********/
|
||||||
|
/// <summary>A brief noun phrase indicating what the instruction finder matches.</summary>
|
||||||
|
public override string NounPhrase { get; } = $"{nameof(Game1)}.{nameof(Game1.gameMode)} field";
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Protected methods
|
** Protected methods
|
||||||
*********/
|
*********/
|
||||||
|
|
|
@ -11,6 +11,13 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters.SDV1_2
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "This class is not meant to be used directly, and is deliberately named to make it easier to know what it changes at a glance.")]
|
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "This class is not meant to be used directly, and is deliberately named to make it easier to know what it changes at a glance.")]
|
||||||
public class Game1_Player_FieldRewriter : BaseFieldRewriter
|
public class Game1_Player_FieldRewriter : BaseFieldRewriter
|
||||||
{
|
{
|
||||||
|
/*********
|
||||||
|
** Accessors
|
||||||
|
*********/
|
||||||
|
/// <summary>A brief noun phrase indicating what the instruction finder matches.</summary>
|
||||||
|
public override string NounPhrase { get; } = $"{nameof(Game1)}.{nameof(Game1.player)} field";
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Protected methods
|
** Protected methods
|
||||||
*********/
|
*********/
|
||||||
|
|
|
@ -162,6 +162,7 @@ namespace StardewModdingAPI.Framework
|
||||||
private bool RewriteAssembly(AssemblyDefinition assembly)
|
private bool RewriteAssembly(AssemblyDefinition assembly)
|
||||||
{
|
{
|
||||||
ModuleDefinition module = assembly.MainModule;
|
ModuleDefinition module = assembly.MainModule;
|
||||||
|
HashSet<string> loggedRewrites = new HashSet<string>();
|
||||||
|
|
||||||
// swap assembly references if needed (e.g. XNA => MonoGame)
|
// swap assembly references if needed (e.g. XNA => MonoGame)
|
||||||
bool platformChanged = false;
|
bool platformChanged = false;
|
||||||
|
@ -170,6 +171,7 @@ namespace StardewModdingAPI.Framework
|
||||||
// remove old assembly reference
|
// remove old assembly reference
|
||||||
if (this.AssemblyMap.RemoveNames.Any(name => module.AssemblyReferences[i].Name == name))
|
if (this.AssemblyMap.RemoveNames.Any(name => module.AssemblyReferences[i].Name == name))
|
||||||
{
|
{
|
||||||
|
this.LogOnce(this.Monitor, loggedRewrites, $"Rewriting {assembly.Name.Name} for OS...");
|
||||||
platformChanged = true;
|
platformChanged = true;
|
||||||
module.AssemblyReferences.RemoveAt(i);
|
module.AssemblyReferences.RemoveAt(i);
|
||||||
i--;
|
i--;
|
||||||
|
@ -197,14 +199,16 @@ namespace StardewModdingAPI.Framework
|
||||||
if (!canRewrite)
|
if (!canRewrite)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// prepare method
|
|
||||||
ILProcessor cil = method.Body.GetILProcessor();
|
|
||||||
|
|
||||||
// rewrite instructions
|
// rewrite instructions
|
||||||
|
ILProcessor cil = method.Body.GetILProcessor();
|
||||||
foreach (Instruction op in cil.Body.Instructions.ToArray())
|
foreach (Instruction op in cil.Body.Instructions.ToArray())
|
||||||
{
|
{
|
||||||
IInstructionRewriter rewriter = rewriters.FirstOrDefault(p => p.IsMatch(op, platformChanged));
|
IInstructionRewriter rewriter = rewriters.FirstOrDefault(p => p.IsMatch(op, platformChanged));
|
||||||
rewriter?.Rewrite(module, cil, op, this.AssemblyMap);
|
if (rewriter != null)
|
||||||
|
{
|
||||||
|
this.LogOnce(this.Monitor, loggedRewrites, $"Rewriting {assembly.Name.Name} to fix {rewriter.NounPhrase}...");
|
||||||
|
rewriter.Rewrite(module, cil, op, this.AssemblyMap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// finalise method
|
// finalise method
|
||||||
|
@ -244,5 +248,19 @@ namespace StardewModdingAPI.Framework
|
||||||
select method
|
select method
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Log a message for the player or developer the first time it occurs.</summary>
|
||||||
|
/// <param name="monitor">The monitor through which to log the message.</param>
|
||||||
|
/// <param name="hash">The hash of logged messages.</param>
|
||||||
|
/// <param name="message">The message to log.</param>
|
||||||
|
/// <param name="level">The log severity level.</param>
|
||||||
|
private void LogOnce(IMonitor monitor, HashSet<string> hash, string message, LogLevel level = LogLevel.Trace)
|
||||||
|
{
|
||||||
|
if (!hash.Contains(message))
|
||||||
|
{
|
||||||
|
this.Monitor.Log(message, level);
|
||||||
|
hash.Add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue