diff --git a/src/StardewModdingAPI.AssemblyRewriters/Finders/EventFinder.cs b/src/StardewModdingAPI.AssemblyRewriters/Finders/EventFinder.cs index 848e54ff..bcceee32 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Finders/EventFinder.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Finders/EventFinder.cs @@ -3,8 +3,8 @@ using Mono.Cecil.Cil; namespace StardewModdingAPI.AssemblyRewriters.Finders { - /// Finds CIL instructions that reference a given event. - public sealed class EventFinder : IInstructionFinder + /// Finds incompatible CIL instructions that reference a given event and throws an . + public class EventFinder : IInstructionRewriter { /********* ** Properties @@ -37,6 +37,22 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders this.NounPhrase = nounPhrase ?? $"{fullTypeName}.{eventName} event"; } + /// 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 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 /// Get whether a CIL instruction matches. /// The IL instruction. /// Whether the mod was compiled on a different platform. - public bool IsMatch(Instruction instruction, bool platformChanged) + protected bool IsMatch(Instruction instruction, bool platformChanged) { MethodReference methodRef = RewriteHelper.AsMethodReference(instruction); return diff --git a/src/StardewModdingAPI.AssemblyRewriters/Finders/FieldFinder.cs b/src/StardewModdingAPI.AssemblyRewriters/Finders/FieldFinder.cs index 068119b8..cdfc3bd5 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Finders/FieldFinder.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Finders/FieldFinder.cs @@ -3,8 +3,8 @@ using Mono.Cecil.Cil; namespace StardewModdingAPI.AssemblyRewriters.Finders { - /// Finds CIL instructions that reference a given field. - public class FieldFinder : IInstructionFinder + /// Finds incompatible CIL instructions that reference a given field and throws an . + public class FieldFinder : IInstructionRewriter { /********* ** Properties @@ -37,6 +37,22 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders this.NounPhrase = nounPhrase ?? $"{fullTypeName}.{fieldName} field"; } + /// 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 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 /// Get whether a CIL instruction matches. /// The IL instruction. /// Whether the mod was compiled on a different platform. - public bool IsMatch(Instruction instruction, bool platformChanged) + protected bool IsMatch(Instruction instruction, bool platformChanged) { FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); return diff --git a/src/StardewModdingAPI.AssemblyRewriters/Finders/MethodFinder.cs b/src/StardewModdingAPI.AssemblyRewriters/Finders/MethodFinder.cs index d174bacd..2efcbb0f 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Finders/MethodFinder.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Finders/MethodFinder.cs @@ -3,8 +3,8 @@ using Mono.Cecil.Cil; namespace StardewModdingAPI.AssemblyRewriters.Finders { - /// Finds CIL instructions that reference a given method. - public class MethodFinder : IInstructionFinder + /// Finds incompatible CIL instructions that reference a given method and throws an . + public class MethodFinder : IInstructionRewriter { /********* ** Properties @@ -37,6 +37,22 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders this.NounPhrase = nounPhrase ?? $"{fullTypeName}.{methodName} method"; } + /// 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 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 /// Get whether a CIL instruction matches. /// The IL instruction. /// Whether the mod was compiled on a different platform. - public bool IsMatch(Instruction instruction, bool platformChanged) + protected bool IsMatch(Instruction instruction, bool platformChanged) { MethodReference methodRef = RewriteHelper.AsMethodReference(instruction); return diff --git a/src/StardewModdingAPI.AssemblyRewriters/Finders/TypeFinder.cs b/src/StardewModdingAPI.AssemblyRewriters/Finders/TypeFinder.cs index 8f492d5f..96cbb229 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Finders/TypeFinder.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Finders/TypeFinder.cs @@ -4,8 +4,8 @@ using Mono.Cecil.Cil; namespace StardewModdingAPI.AssemblyRewriters.Finders { - /// Finds CIL instructions that reference a given type. - public class TypeFinder : IInstructionFinder + /// Finds incompatible CIL instructions that reference a given type and throws an . + public class TypeFinder : IInstructionRewriter { /********* ** Accessors @@ -33,10 +33,30 @@ namespace StardewModdingAPI.AssemblyRewriters.Finders this.NounPhrase = nounPhrase ?? $"{fullTypeName} type"; } + /// 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 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 + *********/ /// Get whether a CIL instruction matches. /// The IL instruction. /// Whether the mod was compiled on a different platform. - public bool IsMatch(Instruction instruction, bool platformChanged) + protected bool IsMatch(Instruction instruction, bool platformChanged) { string fullName = this.FullTypeName; diff --git a/src/StardewModdingAPI.AssemblyRewriters/IInstructionFinder.cs b/src/StardewModdingAPI.AssemblyRewriters/IInstructionFinder.cs deleted file mode 100644 index cc3006b9..00000000 --- a/src/StardewModdingAPI.AssemblyRewriters/IInstructionFinder.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Mono.Cecil.Cil; - -namespace StardewModdingAPI.AssemblyRewriters -{ - /// Finds CIL instructions considered incompatible. - public interface IInstructionFinder - { - /********* - ** Accessors - *********/ - /// A brief noun phrase indicating what the instruction finder matches. - string NounPhrase { get; } - - - /********* - ** Methods - *********/ - /// Get whether a CIL instruction matches. - /// The IL instruction. - /// Whether the mod was compiled on a different platform. - bool IsMatch(Instruction instruction, bool platformChanged); - } -} diff --git a/src/StardewModdingAPI.AssemblyRewriters/IInstructionRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/IInstructionRewriter.cs index b230f227..3a7b1365 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/IInstructionRewriter.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/IInstructionRewriter.cs @@ -3,9 +3,16 @@ using Mono.Cecil.Cil; namespace StardewModdingAPI.AssemblyRewriters { - /// Rewrites a CIL instruction for compatibility. - public interface IInstructionRewriter : IInstructionFinder + /// Rewrites CIL instructions for compatibility. + public interface IInstructionRewriter { + /********* + ** Accessors + *********/ + /// A brief noun phrase indicating what the rewriter matches. + string NounPhrase { get; } + + /********* ** Methods *********/ @@ -14,6 +21,9 @@ namespace StardewModdingAPI.AssemblyRewriters /// The CIL rewriter. /// The instruction to rewrite. /// Metadata for mapping assemblies to the current platform. - void Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap); + /// 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. + bool Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap, bool platformChanged); } } diff --git a/src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs b/src/StardewModdingAPI.AssemblyRewriters/IncompatibleInstructionException.cs similarity index 63% rename from src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs rename to src/StardewModdingAPI.AssemblyRewriters/IncompatibleInstructionException.cs index affe2cb3..f7e6bd8f 100644 --- a/src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/IncompatibleInstructionException.cs @@ -1,9 +1,9 @@ using System; -namespace StardewModdingAPI.Framework +namespace StardewModdingAPI.AssemblyRewriters { /// An exception raised when an incompatible instruction is found while loading a mod assembly. - internal class IncompatibleInstructionException : Exception + public class IncompatibleInstructionException : Exception { /********* ** Accessors @@ -15,6 +15,14 @@ namespace StardewModdingAPI.Framework /********* ** Public methods *********/ + /// Construct an instance. + /// A brief noun phrase which describes the incompatible instruction that was found. + public IncompatibleInstructionException(string nounPhrase) + : base($"Found an incompatible CIL instruction ({nounPhrase}).") + { + this.NounPhrase = nounPhrase; + } + /// Construct an instance. /// A brief noun phrase which describes the incompatible instruction that was found. /// A message which describes the error. diff --git a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldReplaceRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldReplaceRewriter.cs index ffd22e7c..95663c49 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldReplaceRewriter.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldReplaceRewriter.cs @@ -7,16 +7,13 @@ using StardewModdingAPI.AssemblyRewriters.Finders; namespace StardewModdingAPI.AssemblyRewriters.Rewriters { /// Rewrites references to one field with another. - public class FieldReplaceRewriter : FieldFinder, IInstructionRewriter + public class FieldReplaceRewriter : FieldFinder { /********* ** 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; + /// The new field to reference. + 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."); } /// Rewrite a CIL instruction for compatibility. @@ -39,13 +37,17 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters /// 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) + /// 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) { - 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; } } } diff --git a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldToPropertyRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldToPropertyRewriter.cs index f2f99cc1..a25f3fef 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldToPropertyRewriter.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/FieldToPropertyRewriter.cs @@ -6,7 +6,7 @@ using StardewModdingAPI.AssemblyRewriters.Finders; namespace StardewModdingAPI.AssemblyRewriters.Rewriters { /// Rewrites field references into property references. - public class FieldToPropertyRewriter : FieldFinder, IInstructionRewriter + public class FieldToPropertyRewriter : FieldFinder { /********* ** Properties @@ -37,11 +37,18 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters /// 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) + /// 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, 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; } } } diff --git a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/MethodParentRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/MethodParentRewriter.cs index 24d4dff9..3ec8c704 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/MethodParentRewriter.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/MethodParentRewriter.cs @@ -43,10 +43,32 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters this.OnlyIfPlatformChanged = onlyIfPlatformChanged; } + /// 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 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 + *********/ /// Get whether a CIL instruction matches. /// The IL instruction. /// Whether the mod was compiled on a different platform. - 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); } - - /// 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) - { - MethodReference methodRef = (MethodReference)instruction.Operand; - methodRef.DeclaringType = module.Import(this.ToType); - } } } diff --git a/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj index 09fd79ed..3c3acde3 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj +++ b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj @@ -70,8 +70,8 @@ + - diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index 52be6c05..de0eab57 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -137,12 +137,15 @@ namespace StardewModdingAPI return new PlatformAssemblyMap(targetPlatform, removeAssemblyReferences, targetAssemblies); } - /// Get finders which match incompatible CIL instructions in mod assemblies. - internal static IEnumerable GetIncompatibilityFinders() + /// Get rewriters which detect or fix incompatible CIL instructions in mod assemblies. + internal static IEnumerable 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"), - /// Get rewriters which fix incompatible CIL instructions in mod assemblies. - internal static IEnumerable GetRewriters() - { - return new IInstructionRewriter[] - { + /**** + ** Rewriters change CIL as needed to fix incompatible code + ****/ // crossplatform new MethodParentRewriter(typeof(SpriteBatch), typeof(SpriteBatchWrapper), onlyIfPlatformChanged: true), diff --git a/src/StardewModdingAPI/Framework/AssemblyLoader.cs b/src/StardewModdingAPI/Framework/AssemblyLoader.cs index aee0bbb3..5d00c525 100644 --- a/src/StardewModdingAPI/Framework/AssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/AssemblyLoader.cs @@ -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); + } } } } diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index ac646b1f..25605148 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -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; diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index 091b3d90..bcd0c390 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -150,7 +150,6 @@ -