From ec5fbb06113b29342e6d4b213144f4dc3e358b03 Mon Sep 17 00:00:00 2001 From: Chase Warrington Date: Sun, 29 Aug 2021 15:48:28 -0400 Subject: Rewrite 32-bit assemblies for 64-bit --- src/SMAPI/Framework/ModLoading/AssemblyLoader.cs | 7 +++++ .../ModLoading/Framework/BaseInstructionHandler.cs | 6 ++++ .../ModLoading/Framework/RecursiveRewriter.cs | 13 ++++++++- .../Framework/ModLoading/IInstructionHandler.cs | 5 ++++ .../Rewriters/ArchitectureAssemblyRewriter.cs | 34 ++++++++++++++++++++++ 5 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index 3e35c9dd..ae42909c 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -336,6 +336,13 @@ namespace StardewModdingAPI.Framework.ModLoading IInstructionHandler[] handlers = new InstructionMetadata().GetHandlers(this.ParanoidMode, platformChanged, this.RewriteMods).ToArray(); RecursiveRewriter rewriter = new RecursiveRewriter( module: module, + rewriteModule: (module) => + { + bool rewritten = false; + foreach (IInstructionHandler handler in handlers) + rewritten |= handler.Handle(module); + return rewritten; + }, rewriteType: (type, replaceWith) => { bool rewritten = false; diff --git a/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs b/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs index 624113b3..d5d1b38e 100644 --- a/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs +++ b/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs @@ -24,6 +24,12 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework /********* ** Public methods *********/ + /// + public virtual bool Handle(ModuleDefinition module) + { + return false; + } + /// public virtual bool Handle(ModuleDefinition module, TypeReference type, Action replaceWith) { diff --git a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs index 10f68f0d..52f4003c 100644 --- a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs @@ -13,6 +13,11 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework /********* ** Delegates *********/ + /// Rewrite a module definition in the assembly code. + /// The current module definition. + /// Returns whether the module was changed. + public delegate bool RewriteModuleDelegate(ModuleDefinition module); + /// Rewrite a type reference in the assembly code. /// The current type reference. /// Replaces the type reference with the given type. @@ -32,6 +37,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework /// The module to rewrite. public ModuleDefinition Module { get; } + /// Handle or rewrite a type reference if needed. + public RewriteModuleDelegate RewriteModuleImpl { get; } + /// Handle or rewrite a type reference if needed. public RewriteTypeDelegate RewriteTypeImpl { get; } @@ -46,9 +54,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework /// The module to rewrite. /// Handle or rewrite a type reference if needed. /// Handle or rewrite a CIL instruction if needed. - public RecursiveRewriter(ModuleDefinition module, RewriteTypeDelegate rewriteType, RewriteInstructionDelegate rewriteInstruction) + public RecursiveRewriter(ModuleDefinition module, RewriteModuleDelegate rewriteModule, RewriteTypeDelegate rewriteType, RewriteInstructionDelegate rewriteInstruction) { this.Module = module; + this.RewriteModuleImpl = rewriteModule; this.RewriteTypeImpl = rewriteType; this.RewriteInstructionImpl = rewriteInstruction; } @@ -63,6 +72,8 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework try { + changed |= this.RewriteModuleImpl( this.Module ); + foreach (var type in types) changed |= this.RewriteTypeDefinition(type); } diff --git a/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs b/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs index 17c9ba68..d41732f8 100644 --- a/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs +++ b/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs @@ -24,6 +24,11 @@ namespace StardewModdingAPI.Framework.ModLoading /********* ** Methods *********/ + /// Rewrite a module definition if needed. + /// The assembly module. + /// Returns whether the module was changed. + bool Handle(ModuleDefinition module); + /// Rewrite a type reference if needed. /// The assembly module containing the instruction. /// The type definition to handle. diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs new file mode 100644 index 00000000..216c042a --- /dev/null +++ b/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs @@ -0,0 +1,34 @@ +using System; +using HarmonyLib; +using Mono.Cecil; +using Mono.Cecil.Cil; +using StardewModdingAPI.Framework.ModLoading.Framework; +using StardewModdingAPI.Framework.ModLoading.RewriteFacades; + +namespace StardewModdingAPI.Framework.ModLoading.Rewriters +{ + /// Rewrites Harmony 1.x assembly references to work with Harmony 2.x. + internal class ArchitectureAssemblyRewriter : BaseInstructionHandler + { + /********* + ** Public methods + *********/ + /// Construct an instance. + public ArchitectureAssemblyRewriter() + : base(defaultPhrase: "32-bit architecture") { } + + + /// + public override bool Handle( ModuleDefinition module ) + { + if ( module.Attributes.HasFlag( ModuleAttributes.Required32Bit ) ) + { + module.Attributes = module.Attributes & ~ModuleAttributes.Required32Bit; + this.MarkRewritten(); + return true; + } + return false; + } + + } +} -- cgit From 6edcfb1358e470a636a9e97780e05f2a0dcb6752 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 29 Aug 2021 23:01:47 -0400 Subject: tweak new code --- src/SMAPI/Framework/ModLoading/AssemblyLoader.cs | 4 ++-- .../Framework/ModLoading/Framework/RecursiveRewriter.cs | 5 +++-- .../ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs | 13 +++++-------- src/SMAPI/Framework/SCore.cs | 2 +- 4 files changed, 11 insertions(+), 13 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index ae42909c..7668e8a9 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -336,11 +336,11 @@ namespace StardewModdingAPI.Framework.ModLoading IInstructionHandler[] handlers = new InstructionMetadata().GetHandlers(this.ParanoidMode, platformChanged, this.RewriteMods).ToArray(); RecursiveRewriter rewriter = new RecursiveRewriter( module: module, - rewriteModule: (module) => + rewriteModule: curModule => { bool rewritten = false; foreach (IInstructionHandler handler in handlers) - rewritten |= handler.Handle(module); + rewritten |= handler.Handle(curModule); return rewritten; }, rewriteType: (type, replaceWith) => diff --git a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs index 52f4003c..4f14a579 100644 --- a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs @@ -37,7 +37,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework /// The module to rewrite. public ModuleDefinition Module { get; } - /// Handle or rewrite a type reference if needed. + /// Handle or rewrite a module definition if needed. public RewriteModuleDelegate RewriteModuleImpl { get; } /// Handle or rewrite a type reference if needed. @@ -52,6 +52,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework *********/ /// Construct an instance. /// The module to rewrite. + /// Handle or rewrite a module if needed. /// Handle or rewrite a type reference if needed. /// Handle or rewrite a CIL instruction if needed. public RecursiveRewriter(ModuleDefinition module, RewriteModuleDelegate rewriteModule, RewriteTypeDelegate rewriteType, RewriteInstructionDelegate rewriteInstruction) @@ -72,7 +73,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework try { - changed |= this.RewriteModuleImpl( this.Module ); + changed |= this.RewriteModuleImpl(this.Module); foreach (var type in types) changed |= this.RewriteTypeDefinition(type); diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs index 216c042a..cc830216 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs @@ -1,13 +1,9 @@ -using System; -using HarmonyLib; using Mono.Cecil; -using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; -using StardewModdingAPI.Framework.ModLoading.RewriteFacades; namespace StardewModdingAPI.Framework.ModLoading.Rewriters { - /// Rewrites Harmony 1.x assembly references to work with Harmony 2.x. + /// Removes the 32-bit-only from loaded assemblies. internal class ArchitectureAssemblyRewriter : BaseInstructionHandler { /********* @@ -19,14 +15,15 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters /// - public override bool Handle( ModuleDefinition module ) + public override bool Handle(ModuleDefinition module) { - if ( module.Attributes.HasFlag( ModuleAttributes.Required32Bit ) ) + if (module.Attributes.HasFlag(ModuleAttributes.Required32Bit)) { - module.Attributes = module.Attributes & ~ModuleAttributes.Required32Bit; + module.Attributes &= ~ModuleAttributes.Required32Bit; this.MarkRewritten(); return true; } + return false; } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index c1aa3721..61fb77b2 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -1732,7 +1732,7 @@ namespace StardewModdingAPI.Framework { errorReasonPhrase = "its DLL couldn't be loaded."; #if SMAPI_FOR_WINDOWS_64BIT_HACK - if (!EnvironmentUtility.Is64BitAssembly(assemblyPath)) + if (ex is BadImageFormatException && !EnvironmentUtility.Is64BitAssembly(assemblyPath)) errorReasonPhrase = "it needs to be updated for 64-bit mode."; #endif errorDetails = $"Error: {ex.GetLogSummary()}"; -- cgit From 8bfab94213e86c4245961150bd3423ee85213c5d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 31 Aug 2021 01:13:22 -0400 Subject: reduce unneeded operations when scanning/rewriting mod DLLs --- src/SMAPI/Framework/ModLoading/AssemblyLoader.cs | 15 +-- .../Framework/ModLoading/Finders/EventFinder.cs | 57 ++++---- .../Framework/ModLoading/Finders/FieldFinder.cs | 34 +++-- .../ReferenceToMemberWithUnexpectedTypeFinder.cs | 6 +- .../Finders/ReferenceToMissingMemberFinder.cs | 6 +- .../Framework/ModLoading/Finders/TypeFinder.cs | 27 +++- .../Rewriters/Harmony1AssemblyRewriter.cs | 129 ------------------- .../ModLoading/Rewriters/HarmonyRewriter.cs | 143 +++++++++++++++++++++ .../ModLoading/Rewriters/HeuristicFieldRewriter.cs | 6 +- .../Rewriters/HeuristicMethodRewriter.cs | 6 +- 10 files changed, 241 insertions(+), 188 deletions(-) delete mode 100644 src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs create mode 100644 src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index 7668e8a9..57a76a35 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -300,10 +300,10 @@ namespace StardewModdingAPI.Framework.ModLoading // remove old assembly reference if (this.AssemblyMap.RemoveNames.Any(name => module.AssemblyReferences[i].Name == name)) { - this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Rewriting {filename} for OS..."); platformChanged = true; module.AssemblyReferences.RemoveAt(i); i--; + this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Rewrote {filename} for OS..."); } } if (platformChanged) @@ -394,7 +394,7 @@ namespace StardewModdingAPI.Framework.ModLoading break; case InstructionHandleResult.DetectedGamePatch: - template = $"{logPrefix}Detected game patcher ($phrase) in assembly {filename}."; + template = $"{logPrefix}Detected game patcher in assembly {filename}."; // no need for phrase, which would confusingly be 'Harmony 1.x' here mod.SetWarning(ModWarning.PatchesGame); break; @@ -438,13 +438,10 @@ namespace StardewModdingAPI.Framework.ModLoading return; // format messages - if (handler.Phrases.Any()) - { - foreach (string message in handler.Phrases) - this.Monitor.LogOnce(loggedMessages, template.Replace("$phrase", message)); - } - else - this.Monitor.LogOnce(loggedMessages, template.Replace("$phrase", handler.DefaultPhrase ?? handler.GetType().Name)); + string phrase = handler.Phrases.Any() + ? string.Join(", ", handler.Phrases) + : handler.DefaultPhrase ?? handler.GetType().Name; + this.Monitor.LogOnce(loggedMessages, template.Replace("$phrase", phrase)); } /// Get the correct reference to use for compatibility with the current platform. diff --git a/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs index 01ed153b..a2ea3232 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using System.Linq; using Mono.Cecil; using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; @@ -13,8 +15,8 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders /// The full type name for which to find references. private readonly string FullTypeName; - /// The event name for which to find references. - private readonly string EventName; + /// The method names for which to find references. + private readonly ISet MethodNames; /// The result to return for matching instructions. private readonly InstructionHandleResult Result; @@ -25,38 +27,47 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders *********/ /// Construct an instance. /// The full type name for which to find references. - /// The event name for which to find references. + /// The event names for which to find references. /// The result to return for matching instructions. - public EventFinder(string fullTypeName, string eventName, InstructionHandleResult result) - : base(defaultPhrase: $"{fullTypeName}.{eventName} event") + public EventFinder(string fullTypeName, string[] eventNames, InstructionHandleResult result) + : base(defaultPhrase: $"{string.Join(", ", eventNames.Select(p => $"{fullTypeName}.{p}"))} event{(eventNames.Length != 1 ? "s" : "")}") // default phrase should never be used { this.FullTypeName = fullTypeName; - this.EventName = eventName; this.Result = result; + + this.MethodNames = new HashSet(); + foreach (string name in eventNames) + { + this.MethodNames.Add($"add_{name}"); + this.MethodNames.Add($"remove_{name}"); + } } + /// Construct an instance. + /// The full type name for which to find references. + /// The event name for which to find references. + /// The result to return for matching instructions. + public EventFinder(string fullTypeName, string eventName, InstructionHandleResult result) + : this(fullTypeName, new[] { eventName }, result) { } + /// public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction) { - if (!this.Flags.Contains(this.Result) && this.IsMatch(instruction)) - this.MarkFlag(this.Result); - - return false; - } + if (this.MethodNames.Any()) + { + MethodReference methodRef = RewriteHelper.AsMethodReference(instruction); + if (methodRef is not null && methodRef.DeclaringType.FullName == this.FullTypeName && this.MethodNames.Contains(methodRef.Name)) + { + string eventName = methodRef.Name.Split(new[] { '_' }, 2)[1]; + this.MethodNames.Remove($"add_{eventName}"); + this.MethodNames.Remove($"remove_{eventName}"); + this.MarkFlag(this.Result); + this.Phrases.Add($"{this.FullTypeName}.{eventName} event"); + } + } - /********* - ** Protected methods - *********/ - /// Get whether a CIL instruction matches. - /// The IL instruction. - protected bool IsMatch(Instruction instruction) - { - MethodReference methodRef = RewriteHelper.AsMethodReference(instruction); - return - methodRef != null - && methodRef.DeclaringType.FullName == this.FullTypeName - && (methodRef.Name == "add_" + this.EventName || methodRef.Name == "remove_" + this.EventName); + return false; } } } diff --git a/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs index 2c062243..0947062c 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using System.Linq; using Mono.Cecil; using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; @@ -13,8 +15,8 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders /// The full type name for which to find references. private readonly string FullTypeName; - /// The field name for which to find references. - private readonly string FieldName; + /// The field names for which to find references. + private readonly ISet FieldNames; /// The result to return for matching instructions. private readonly InstructionHandleResult Result; @@ -25,21 +27,37 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders *********/ /// Construct an instance. /// The full type name for which to find references. - /// The field name for which to find references. + /// The field names for which to find references. /// The result to return for matching instructions. - public FieldFinder(string fullTypeName, string fieldName, InstructionHandleResult result) - : base(defaultPhrase: $"{fullTypeName}.{fieldName} field") + public FieldFinder(string fullTypeName, string[] fieldNames, InstructionHandleResult result) + : base(defaultPhrase: $"{string.Join(", ", fieldNames.Select(p => $"{fullTypeName}.{p}"))} field{(fieldNames.Length != 1 ? "s" : "")}") // default phrase should never be used { this.FullTypeName = fullTypeName; - this.FieldName = fieldName; + this.FieldNames = new HashSet(fieldNames); this.Result = result; } + /// Construct an instance. + /// The full type name for which to find references. + /// The field name for which to find references. + /// The result to return for matching instructions. + public FieldFinder(string fullTypeName, string fieldName, InstructionHandleResult result) + : this(fullTypeName, new[] { fieldName }, result) { } + /// public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction) { - if (!this.Flags.Contains(this.Result) && RewriteHelper.IsFieldReferenceTo(instruction, this.FullTypeName, this.FieldName)) - this.MarkFlag(this.Result); + if (this.FieldNames.Any()) + { + FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); + if (fieldRef is not null && fieldRef.DeclaringType.FullName == this.FullTypeName && this.FieldNames.Contains(fieldRef.Name)) + { + this.FieldNames.Remove(fieldRef.Name); + + this.MarkFlag(this.Result); + this.Phrases.Add($"{this.FullTypeName}.{fieldRef.Name} field"); + } + } return false; } diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs index b01a3240..8c1cae2b 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs @@ -14,7 +14,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders ** Fields *********/ /// The assembly names to which to heuristically detect broken references. - private readonly HashSet ValidateReferencesToAssemblies; + private readonly ISet ValidateReferencesToAssemblies; /********* @@ -22,10 +22,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders *********/ /// Construct an instance. /// The assembly names to which to heuristically detect broken references. - public ReferenceToMemberWithUnexpectedTypeFinder(string[] validateReferencesToAssemblies) + public ReferenceToMemberWithUnexpectedTypeFinder(ISet validateReferencesToAssemblies) : base(defaultPhrase: "") { - this.ValidateReferencesToAssemblies = new HashSet(validateReferencesToAssemblies); + this.ValidateReferencesToAssemblies = validateReferencesToAssemblies; } /// diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs index b64a255e..d305daf4 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs @@ -13,7 +13,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders ** Fields *********/ /// The assembly names to which to heuristically detect broken references. - private readonly HashSet ValidateReferencesToAssemblies; + private readonly ISet ValidateReferencesToAssemblies; /********* @@ -21,10 +21,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders *********/ /// Construct an instance. /// The assembly names to which to heuristically detect broken references. - public ReferenceToMissingMemberFinder(string[] validateReferencesToAssemblies) + public ReferenceToMissingMemberFinder(ISet validateReferencesToAssemblies) : base(defaultPhrase: "") { - this.ValidateReferencesToAssemblies = new HashSet(validateReferencesToAssemblies); + this.ValidateReferencesToAssemblies = validateReferencesToAssemblies; } /// diff --git a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs index bbd081e8..260a8df8 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Mono.Cecil; using StardewModdingAPI.Framework.ModLoading.Framework; @@ -10,8 +11,8 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders /********* ** Fields *********/ - /// The full type name to match. - private readonly string FullTypeName; + /// The full type names remaining to match. + private readonly ISet FullTypeNames; /// The result to return for matching instructions. private readonly InstructionHandleResult Result; @@ -24,22 +25,34 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders ** Public methods *********/ /// Construct an instance. - /// The full type name to match. + /// The full type names to match. /// The result to return for matching instructions. /// Get whether a matched type should be ignored. - public TypeFinder(string fullTypeName, InstructionHandleResult result, Func shouldIgnore = null) - : base(defaultPhrase: $"{fullTypeName} type") + public TypeFinder(string[] fullTypeNames, InstructionHandleResult result, Func shouldIgnore = null) + : base(defaultPhrase: $"{string.Join(", ", fullTypeNames)} type{(fullTypeNames.Length != 1 ? "s" : "")}") // default phrase should never be used { - this.FullTypeName = fullTypeName; + this.FullTypeNames = new HashSet(fullTypeNames); this.Result = result; this.ShouldIgnore = shouldIgnore; } + /// Construct an instance. + /// The full type name to match. + /// The result to return for matching instructions. + /// Get whether a matched type should be ignored. + public TypeFinder(string fullTypeName, InstructionHandleResult result, Func shouldIgnore = null) + : this(new[] { fullTypeName }, result, shouldIgnore) { } + /// public override bool Handle(ModuleDefinition module, TypeReference type, Action replaceWith) { - if (type.FullName == this.FullTypeName && this.ShouldIgnore?.Invoke(type) != true) + if (this.FullTypeNames.Contains(type.FullName) && this.ShouldIgnore?.Invoke(type) != true) + { + this.FullTypeNames.Remove(type.FullName); + this.MarkFlag(this.Result); + this.Phrases.Add($"{type.FullName} type"); + } return false; } diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs deleted file mode 100644 index 7a3b428d..00000000 --- a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System; -using HarmonyLib; -using Mono.Cecil; -using Mono.Cecil.Cil; -using StardewModdingAPI.Framework.ModLoading.Framework; -using StardewModdingAPI.Framework.ModLoading.RewriteFacades; - -namespace StardewModdingAPI.Framework.ModLoading.Rewriters -{ - /// Rewrites Harmony 1.x assembly references to work with Harmony 2.x. - internal class Harmony1AssemblyRewriter : BaseInstructionHandler - { - /********* - ** Fields - *********/ - /// Whether any Harmony 1.x types were replaced. - private bool ReplacedTypes; - - - /********* - ** Public methods - *********/ - /// Construct an instance. - public Harmony1AssemblyRewriter() - : base(defaultPhrase: "Harmony 1.x") { } - - /// - public override bool Handle(ModuleDefinition module, TypeReference type, Action replaceWith) - { - // rewrite Harmony 1.x type to Harmony 2.0 type - if (type.Scope is AssemblyNameReference { Name: "0Harmony" } scope && scope.Version.Major == 1) - { - Type targetType = this.GetMappedType(type); - replaceWith(module.ImportReference(targetType)); - this.OnChanged(); - this.ReplacedTypes = true; - return true; - } - - return false; - } - - /// - public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction) - { - // rewrite Harmony 1.x methods to Harmony 2.0 - MethodReference methodRef = RewriteHelper.AsMethodReference(instruction); - if (this.TryRewriteMethodsToFacade(module, methodRef)) - { - this.OnChanged(); - return true; - } - - // rewrite renamed fields - FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); - if (fieldRef != null) - { - if (fieldRef.DeclaringType.FullName == "HarmonyLib.HarmonyMethod" && fieldRef.Name == "prioritiy") - { - fieldRef.Name = nameof(HarmonyMethod.priority); - this.OnChanged(); - } - } - - return false; - } - - - /********* - ** Private methods - *********/ - /// Update the mod metadata when any Harmony 1.x code is migrated. - private void OnChanged() - { - this.MarkRewritten(); - this.MarkFlag(InstructionHandleResult.DetectedGamePatch); - } - - /// Rewrite methods to use Harmony facades if needed. - /// The assembly module containing the method reference. - /// The method reference to map. - private bool TryRewriteMethodsToFacade(ModuleDefinition module, MethodReference methodRef) - { - if (!this.ReplacedTypes) - return false; // not Harmony (or already using Harmony 2.0) - - // get facade type - Type toType = methodRef?.DeclaringType.FullName switch - { - "HarmonyLib.Harmony" => typeof(HarmonyInstanceFacade), - "HarmonyLib.AccessTools" => typeof(AccessToolsFacade), - "HarmonyLib.HarmonyMethod" => typeof(HarmonyMethodFacade), - _ => null - }; - if (toType == null) - return false; - - // map if there's a matching method - if (RewriteHelper.HasMatchingSignature(toType, methodRef)) - { - methodRef.DeclaringType = module.ImportReference(toType); - return true; - } - - return false; - } - - /// Get an equivalent Harmony 2.x type. - /// The Harmony 1.x type. - private Type GetMappedType(TypeReference type) - { - return type.FullName switch - { - "Harmony.HarmonyInstance" => typeof(Harmony), - "Harmony.ILCopying.ExceptionBlock" => typeof(ExceptionBlock), - _ => this.GetMappedTypeByConvention(type) - }; - } - - /// Get an equivalent Harmony 2.x type using the convention expected for most types. - /// The Harmony 1.x type. - private Type GetMappedTypeByConvention(TypeReference type) - { - string fullName = type.FullName.Replace("Harmony.", "HarmonyLib."); - string targetName = typeof(Harmony).AssemblyQualifiedName!.Replace(typeof(Harmony).FullName!, fullName); - return Type.GetType(targetName, throwOnError: true); - } - } -} diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs new file mode 100644 index 00000000..38ab3d80 --- /dev/null +++ b/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs @@ -0,0 +1,143 @@ +using System; +using HarmonyLib; +using Mono.Cecil; +using Mono.Cecil.Cil; +using StardewModdingAPI.Framework.ModLoading.Framework; +using StardewModdingAPI.Framework.ModLoading.RewriteFacades; + +namespace StardewModdingAPI.Framework.ModLoading.Rewriters +{ + /// Detects Harmony references, and rewrites Harmony 1.x assembly references to work with Harmony 2.x. + internal class HarmonyRewriter : BaseInstructionHandler + { + /********* + ** Fields + *********/ + /// Whether any Harmony 1.x types were replaced. + private bool ReplacedTypes; + + /// Whether to rewrite Harmony 1.x code. + private readonly bool ShouldRewrite; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + public HarmonyRewriter(bool shouldRewrite = true) + : base(defaultPhrase: "Harmony 1.x") + { + this.ShouldRewrite = shouldRewrite; + } + + /// + public override bool Handle(ModuleDefinition module, TypeReference type, Action replaceWith) + { + // detect Harmony + if (type.Scope is not AssemblyNameReference { Name: "0Harmony" } scope) + return false; + + // rewrite Harmony 1.x type to Harmony 2.0 type + if (this.ShouldRewrite && scope.Version.Major == 1) + { + Type targetType = this.GetMappedType(type); + replaceWith(module.ImportReference(targetType)); + this.OnChanged(); + this.ReplacedTypes = true; + return true; + } + + this.MarkFlag(InstructionHandleResult.DetectedGamePatch); + return false; + } + + /// + public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction) + { + if (this.ShouldRewrite) + { + // rewrite Harmony 1.x methods to Harmony 2.0 + MethodReference methodRef = RewriteHelper.AsMethodReference(instruction); + if (this.TryRewriteMethodsToFacade(module, methodRef)) + { + this.OnChanged(); + return true; + } + + // rewrite renamed fields + FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); + if (fieldRef != null) + { + if (fieldRef.DeclaringType.FullName == "HarmonyLib.HarmonyMethod" && fieldRef.Name == "prioritiy") + { + fieldRef.Name = nameof(HarmonyMethod.priority); + this.OnChanged(); + } + } + } + + return false; + } + + + /********* + ** Private methods + *********/ + /// Update the mod metadata when any Harmony 1.x code is migrated. + private void OnChanged() + { + this.MarkRewritten(); + this.MarkFlag(InstructionHandleResult.DetectedGamePatch); + } + + /// Rewrite methods to use Harmony facades if needed. + /// The assembly module containing the method reference. + /// The method reference to map. + private bool TryRewriteMethodsToFacade(ModuleDefinition module, MethodReference methodRef) + { + if (!this.ReplacedTypes) + return false; // not Harmony (or already using Harmony 2.0) + + // get facade type + Type toType = methodRef?.DeclaringType.FullName switch + { + "HarmonyLib.Harmony" => typeof(HarmonyInstanceFacade), + "HarmonyLib.AccessTools" => typeof(AccessToolsFacade), + "HarmonyLib.HarmonyMethod" => typeof(HarmonyMethodFacade), + _ => null + }; + if (toType == null) + return false; + + // map if there's a matching method + if (RewriteHelper.HasMatchingSignature(toType, methodRef)) + { + methodRef.DeclaringType = module.ImportReference(toType); + return true; + } + + return false; + } + + /// Get an equivalent Harmony 2.x type. + /// The Harmony 1.x type. + private Type GetMappedType(TypeReference type) + { + return type.FullName switch + { + "Harmony.HarmonyInstance" => typeof(Harmony), + "Harmony.ILCopying.ExceptionBlock" => typeof(ExceptionBlock), + _ => this.GetMappedTypeByConvention(type) + }; + } + + /// Get an equivalent Harmony 2.x type using the convention expected for most types. + /// The Harmony 1.x type. + private Type GetMappedTypeByConvention(TypeReference type) + { + string fullName = type.FullName.Replace("Harmony.", "HarmonyLib."); + string targetName = typeof(Harmony).AssemblyQualifiedName!.Replace(typeof(Harmony).FullName!, fullName); + return Type.GetType(targetName, throwOnError: true); + } + } +} diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs index f59a6ab1..57f1dd17 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs @@ -13,7 +13,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters ** Fields *********/ /// The assembly names to which to rewrite broken references. - private readonly HashSet RewriteReferencesToAssemblies; + private readonly ISet RewriteReferencesToAssemblies; /********* @@ -21,10 +21,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters *********/ /// Construct an instance. /// The assembly names to which to rewrite broken references. - public HeuristicFieldRewriter(string[] rewriteReferencesToAssemblies) + public HeuristicFieldRewriter(ISet rewriteReferencesToAssemblies) : base(defaultPhrase: "field changed to property") // ignored since we specify phrases { - this.RewriteReferencesToAssemblies = new HashSet(rewriteReferencesToAssemblies); + this.RewriteReferencesToAssemblies = rewriteReferencesToAssemblies; } /// diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs index e133b6fa..89de437e 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs @@ -13,7 +13,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters ** Fields *********/ /// The assembly names to which to rewrite broken references. - private readonly HashSet RewriteReferencesToAssemblies; + private readonly ISet RewriteReferencesToAssemblies; /********* @@ -21,10 +21,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters *********/ /// Construct an instance. /// The assembly names to which to rewrite broken references. - public HeuristicMethodRewriter(string[] rewriteReferencesToAssemblies) + public HeuristicMethodRewriter(ISet rewriteReferencesToAssemblies) : base(defaultPhrase: "methods with missing parameters") // ignored since we specify phrases { - this.RewriteReferencesToAssemblies = new HashSet(rewriteReferencesToAssemblies); + this.RewriteReferencesToAssemblies = rewriteReferencesToAssemblies; } /// -- cgit From 1240cb21024c3b715a6dacb2bec170a588a08791 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 1 Sep 2021 20:58:21 -0400 Subject: fix translations not initialized for temporary content packs --- src/SMAPI/Framework/ContentPack.cs | 10 ++++-- src/SMAPI/Framework/IModMetadata.cs | 7 ++++ src/SMAPI/Framework/ModLoading/ModMetadata.cs | 18 ++++++++++ src/SMAPI/Framework/SCore.cs | 50 ++++++++++++++++++++++----- 4 files changed, 74 insertions(+), 11 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ContentPack.cs b/src/SMAPI/Framework/ContentPack.cs index 0660a367..b6add7b5 100644 --- a/src/SMAPI/Framework/ContentPack.cs +++ b/src/SMAPI/Framework/ContentPack.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using StardewModdingAPI.Framework.ModHelpers; using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities; @@ -32,7 +33,10 @@ namespace StardewModdingAPI.Framework public IManifest Manifest { get; } /// - public ITranslationHelper Translation { get; } + public ITranslationHelper Translation => this.TranslationImpl; + + /// The underlying translation helper. + internal TranslationHelper TranslationImpl { get; set; } /********* @@ -44,12 +48,12 @@ namespace StardewModdingAPI.Framework /// Provides an API for loading content assets. /// Provides translations stored in the content pack's i18n folder. /// Encapsulates SMAPI's JSON file parsing. - public ContentPack(string directoryPath, IManifest manifest, IContentHelper content, ITranslationHelper translation, JsonHelper jsonHelper) + public ContentPack(string directoryPath, IManifest manifest, IContentHelper content, TranslationHelper translation, JsonHelper jsonHelper) { this.DirectoryPath = directoryPath; this.Manifest = manifest; this.Content = content; - this.Translation = translation; + this.TranslationImpl = translation; this.JsonHelper = jsonHelper; foreach (string path in Directory.EnumerateFiles(this.DirectoryPath, "*", SearchOption.AllDirectories)) diff --git a/src/SMAPI/Framework/IModMetadata.cs b/src/SMAPI/Framework/IModMetadata.cs index f5babafb..cb876ee4 100644 --- a/src/SMAPI/Framework/IModMetadata.cs +++ b/src/SMAPI/Framework/IModMetadata.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using StardewModdingAPI.Framework.ModHelpers; using StardewModdingAPI.Framework.ModLoading; @@ -64,6 +65,9 @@ namespace StardewModdingAPI.Framework /// The update-check metadata for this mod (if any). ModEntryModel UpdateCheckData { get; } + /// The fake content packs created by this mod, if any. + ISet> FakeContentPacks { get; } + /********* ** Public methods @@ -135,5 +139,8 @@ namespace StardewModdingAPI.Framework /// Get a relative path which includes the root folder name. string GetRelativePathWithRoot(); + + /// Get the currently live fake content packs created by this mod. + IEnumerable GetFakeContentPacks(); } } diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs index 0ace084f..9e6bc61f 100644 --- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs +++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs @@ -83,6 +83,9 @@ namespace StardewModdingAPI.Framework.ModLoading /// public bool IsContentPack => this.Manifest?.ContentPackFor != null; + /// The fake content packs created by this mod, if any. + public ISet> FakeContentPacks { get; } = new HashSet>(); + /********* ** Public methods @@ -244,6 +247,21 @@ namespace StardewModdingAPI.Framework.ModLoading return Path.Combine(rootFolderName, this.RelativeDirectoryPath); } + /// Get the currently live fake content packs created by this mod. + public IEnumerable GetFakeContentPacks() + { + foreach (var reference in this.FakeContentPacks.ToArray()) + { + if (!reference.TryGetTarget(out ContentPack pack)) + { + this.FakeContentPacks.Remove(reference); + continue; + } + + yield return pack; + } + } + /********* ** Private methods diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 61fb77b2..f7efc89e 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -49,6 +49,7 @@ using StardewModdingAPI.Utilities; using StardewValley; using xTile.Display; using MiniMonoModHotfix = MonoMod.Utils.MiniMonoModHotfix; +using PathUtilities = StardewModdingAPI.Toolkit.Utilities.PathUtilities; using SObject = StardewValley.Object; namespace StardewModdingAPI.Framework @@ -1060,7 +1061,12 @@ namespace StardewModdingAPI.Framework // update mod translation helpers foreach (IModMetadata mod in this.ModRegistry.GetAll()) + { mod.Translations.SetLocale(locale, languageCode); + + foreach (ContentPack contentPack in mod.GetFakeContentPacks()) + contentPack.TranslationImpl.SetLocale(locale, languageCode); + } } /// Raised when the low-level stage while loading a save changes. @@ -1772,8 +1778,12 @@ namespace StardewModdingAPI.Framework { IMonitor packMonitor = this.LogManager.GetMonitor(packManifest.Name); IContentHelper packContentHelper = new ContentHelper(contentCore, packDirPath, packManifest.UniqueID, packManifest.Name, packMonitor); - ITranslationHelper packTranslationHelper = new TranslationHelper(packManifest.UniqueID, contentCore.GetLocale(), contentCore.Language); - return new ContentPack(packDirPath, packManifest, packContentHelper, packTranslationHelper, this.Toolkit.JsonHelper); + TranslationHelper packTranslationHelper = new TranslationHelper(packManifest.UniqueID, contentCore.GetLocale(), contentCore.Language); + + ContentPack contentPack = new ContentPack(packDirPath, packManifest, packContentHelper, packTranslationHelper, this.Toolkit.JsonHelper); + this.ReloadTranslationsForTemporaryContentPack(mod, contentPack); + mod.FakeContentPacks.Add(new WeakReference(contentPack)); + return contentPack; } IModEvents events = new ModEvents(mod, this.EventManager); @@ -1867,17 +1877,41 @@ namespace StardewModdingAPI.Framework // mod translations foreach (IModMetadata metadata in mods) { - var translations = this.ReadTranslationFiles(Path.Combine(metadata.DirectoryPath, "i18n"), out IList errors); - if (errors.Any()) + // top-level mod { - metadata.LogAsMod("Mod couldn't load some translation files:", LogLevel.Warn); - foreach (string error in errors) - metadata.LogAsMod($" - {error}", LogLevel.Warn); + var translations = this.ReadTranslationFiles(Path.Combine(metadata.DirectoryPath, "i18n"), out IList errors); + if (errors.Any()) + { + metadata.LogAsMod("Mod couldn't load some translation files:", LogLevel.Warn); + foreach (string error in errors) + metadata.LogAsMod($" - {error}", LogLevel.Warn); + } + + metadata.Translations.SetTranslations(translations); } - metadata.Translations.SetTranslations(translations); + + // fake content packs + foreach (ContentPack pack in metadata.GetFakeContentPacks()) + this.ReloadTranslationsForTemporaryContentPack(metadata, pack); } } + /// Load or reload translations for a temporary content pack created by a mod. + /// The parent mod which created the content pack. + /// The content pack instance. + private void ReloadTranslationsForTemporaryContentPack(IModMetadata parentMod, ContentPack contentPack) + { + var translations = this.ReadTranslationFiles(Path.Combine(contentPack.DirectoryPath, "i18n"), out IList errors); + if (errors.Any()) + { + parentMod.LogAsMod($"Generated content pack at '{PathUtilities.GetRelativePath(Constants.ModsPath, contentPack.DirectoryPath)}' couldn't load some translation files:", LogLevel.Warn); + foreach (string error in errors) + parentMod.LogAsMod($" - {error}", LogLevel.Warn); + } + + contentPack.TranslationImpl.SetTranslations(translations); + } + /// Read translations from a directory containing JSON translation files. /// The folder path to search. /// The errors indicating why translation files couldn't be parsed, indexed by translation filename. -- cgit From 8789b7efa816aab0f4ce9d3149c26b8033e0b0a5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 2 Sep 2021 18:54:56 -0400 Subject: prepare path utilities for the upcoming Stardew Valley 1.5.5 The game will use Linux-style paths for assets on all platforms, which will break the current equivalence between path and asset name formats. --- src/SMAPI/Framework/Content/AssetDataForMap.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/Content/AssetDataForMap.cs b/src/SMAPI/Framework/Content/AssetDataForMap.cs index 20f0ed0f..4f810948 100644 --- a/src/SMAPI/Framework/Content/AssetDataForMap.cs +++ b/src/SMAPI/Framework/Content/AssetDataForMap.cs @@ -153,9 +153,9 @@ namespace StardewModdingAPI.Framework.Content if (string.IsNullOrWhiteSpace(path)) return string.Empty; - path = PathUtilities.NormalizePath(path); - if (path.StartsWith($"Maps{PathUtilities.PreferredPathSeparator}", StringComparison.OrdinalIgnoreCase)) - path = path.Substring($"Maps{PathUtilities.PreferredPathSeparator}".Length); + path = PathUtilities.NormalizeAssetName(path); + if (path.StartsWith($"Maps{PathUtilities.PreferredAssetSeparator}", StringComparison.OrdinalIgnoreCase)) + path = path.Substring($"Maps{PathUtilities.PreferredAssetSeparator}".Length); if (path.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) path = path.Substring(0, path.Length - 4); -- cgit From 0ce8939988159723851e4e64eeb82b026f982ef5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 2 Sep 2021 19:27:49 -0400 Subject: avoid duplicate update key parsing logic, fix unit tests --- src/SMAPI/Framework/ModLoading/ModResolver.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index 2f506571..4b05d1e5 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -5,6 +5,7 @@ using System.Linq; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Toolkit.Framework.ModData; using StardewModdingAPI.Toolkit.Framework.ModScanning; +using StardewModdingAPI.Toolkit.Framework.UpdateData; using StardewModdingAPI.Toolkit.Serialization.Models; using StardewModdingAPI.Toolkit.Utilities; @@ -82,9 +83,9 @@ namespace StardewModdingAPI.Framework.ModLoading // get update URLs List updateUrls = new List(); - foreach (string key in mod.Manifest.UpdateKeys) + foreach (UpdateKey key in mod.GetUpdateKeys(validOnly: true)) { - string url = getUpdateUrl(key); + string url = getUpdateUrl(key.ToString()); if (url != null) updateUrls.Add(url); } -- cgit From 169ce01810a66cbaaf793adaad1659809721336d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 2 Sep 2021 21:24:10 -0400 Subject: fix build errors on Linux --- src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs | 2 +- src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs | 2 +- src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs index a2ea3232..124951a5 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs @@ -56,7 +56,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders if (this.MethodNames.Any()) { MethodReference methodRef = RewriteHelper.AsMethodReference(instruction); - if (methodRef is not null && methodRef.DeclaringType.FullName == this.FullTypeName && this.MethodNames.Contains(methodRef.Name)) + if (methodRef != null && methodRef.DeclaringType.FullName == this.FullTypeName && this.MethodNames.Contains(methodRef.Name)) { string eventName = methodRef.Name.Split(new[] { '_' }, 2)[1]; this.MethodNames.Remove($"add_{eventName}"); diff --git a/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs index 0947062c..68415123 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs @@ -50,7 +50,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders if (this.FieldNames.Any()) { FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); - if (fieldRef is not null && fieldRef.DeclaringType.FullName == this.FullTypeName && this.FieldNames.Contains(fieldRef.Name)) + if (fieldRef != null && fieldRef.DeclaringType.FullName == this.FullTypeName && this.FieldNames.Contains(fieldRef.Name)) { this.FieldNames.Remove(fieldRef.Name); diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs index 38ab3d80..922d4bc4 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs @@ -34,7 +34,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters public override bool Handle(ModuleDefinition module, TypeReference type, Action replaceWith) { // detect Harmony - if (type.Scope is not AssemblyNameReference { Name: "0Harmony" } scope) + if (!(type.Scope is AssemblyNameReference scope) || scope.Name != "0Harmony") return false; // rewrite Harmony 1.x type to Harmony 2.0 type -- cgit From bbaa260007f67d6e3c88c1aae387b42b0c237063 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 2 Sep 2021 23:01:40 -0400 Subject: drop support for unofficial 64-bit mode --- src/SMAPI/Framework/Content/ContentCache.cs | 2 -- src/SMAPI/Framework/Logging/LogManager.cs | 22 +--------------------- src/SMAPI/Framework/SCore.cs | 18 ++++++++---------- 3 files changed, 9 insertions(+), 33 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/Content/ContentCache.cs b/src/SMAPI/Framework/Content/ContentCache.cs index 5c7ad778..7edc9ab9 100644 --- a/src/SMAPI/Framework/Content/ContentCache.cs +++ b/src/SMAPI/Framework/Content/ContentCache.cs @@ -57,8 +57,6 @@ namespace StardewModdingAPI.Framework.Content IReflectedMethod method = reflection.GetMethod(typeof(TitleContainer), "GetCleanPath"); this.NormalizeAssetNameForPlatform = path => method.Invoke(path); } - else if (EarlyConstants.IsWindows64BitHack) - this.NormalizeAssetNameForPlatform = PathUtilities.NormalizePath; else this.NormalizeAssetNameForPlatform = key => key.Replace('\\', '/'); // based on MonoGame's ContentManager.Load logic } diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index c6faa90d..6fe44d98 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -291,13 +291,7 @@ namespace StardewModdingAPI.Framework.Logging public void LogIntro(string modsPath, IDictionary customSettings) { // log platform & patches - { - this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GameVersion} on {EnvironmentUtility.GetFriendlyPlatformName(Constants.Platform)}", LogLevel.Info); - - string[] patchLabels = this.GetPatchLabels().ToArray(); - if (patchLabels.Any()) - this.Monitor.Log($"Detected custom version: {string.Join(", ", patchLabels)}", LogLevel.Info); - } + this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GameVersion} on {EnvironmentUtility.GetFriendlyPlatformName(Constants.Platform)}", LogLevel.Info); // log basic info this.Monitor.Log($"Mods go here: {modsPath}", LogLevel.Info); @@ -416,20 +410,6 @@ namespace StardewModdingAPI.Framework.Logging gameMonitor.Log(message, level); } - /// Get human-readable labels to log for detected SMAPI and Stardew Valley customizations. - private IEnumerable GetPatchLabels() - { - // custom game framework - if (EarlyConstants.IsWindows64BitHack) - yield return $"running 64-bit SMAPI with {Constants.GameFramework}"; - else if ((Constants.GameFramework == GameFramework.Xna) != (Constants.Platform == Platform.Windows)) - yield return $"running {Constants.GameFramework}"; - - // patched by Stardew64Installer - if (Constants.IsPatchedByStardew64Installer(out