summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/ModLoading
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2021-09-03 18:36:39 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2021-09-03 18:36:39 -0400
commitc5b8cd626489dad6210fe629658314dfc85f4d08 (patch)
tree3e30c3172e6c0bb3e422036581684593156fad22 /src/SMAPI/Framework/ModLoading
parent4ee96a20bb6c74bc7ff6176a03e7f15d47cddfa8 (diff)
parent6d4ea7f0bd584602632e6e308d52bb369b30006f (diff)
downloadSMAPI-c5b8cd626489dad6210fe629658314dfc85f4d08.tar.gz
SMAPI-c5b8cd626489dad6210fe629658314dfc85f4d08.tar.bz2
SMAPI-c5b8cd626489dad6210fe629658314dfc85f4d08.zip
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI/Framework/ModLoading')
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyLoader.cs22
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs57
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs34
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs6
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs6
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs27
-rw-r--r--src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs6
-rw-r--r--src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs14
-rw-r--r--src/SMAPI/Framework/ModLoading/IInstructionHandler.cs5
-rw-r--r--src/SMAPI/Framework/ModLoading/ModMetadata.cs18
-rw-r--r--src/SMAPI/Framework/ModLoading/ModResolver.cs5
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs31
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs (renamed from src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs)50
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs6
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs6
15 files changed, 213 insertions, 80 deletions
diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
index 3e35c9dd..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)
@@ -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: curModule =>
+ {
+ bool rewritten = false;
+ foreach (IInstructionHandler handler in handlers)
+ rewritten |= handler.Handle(curModule);
+ return rewritten;
+ },
rewriteType: (type, replaceWith) =>
{
bool rewritten = false;
@@ -387,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;
@@ -431,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));
}
/// <summary>Get the correct reference to use for compatibility with the current platform.</summary>
diff --git a/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs
index 01ed153b..124951a5 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
/// <summary>The full type name for which to find references.</summary>
private readonly string FullTypeName;
- /// <summary>The event name for which to find references.</summary>
- private readonly string EventName;
+ /// <summary>The method names for which to find references.</summary>
+ private readonly ISet<string> MethodNames;
/// <summary>The result to return for matching instructions.</summary>
private readonly InstructionHandleResult Result;
@@ -25,38 +27,47 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
*********/
/// <summary>Construct an instance.</summary>
/// <param name="fullTypeName">The full type name for which to find references.</param>
- /// <param name="eventName">The event name for which to find references.</param>
+ /// <param name="eventNames">The event names for which to find references.</param>
/// <param name="result">The result to return for matching instructions.</param>
- 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<string>();
+ foreach (string name in eventNames)
+ {
+ this.MethodNames.Add($"add_{name}");
+ this.MethodNames.Add($"remove_{name}");
+ }
}
+ /// <summary>Construct an instance.</summary>
+ /// <param name="fullTypeName">The full type name for which to find references.</param>
+ /// <param name="eventName">The event name for which to find references.</param>
+ /// <param name="result">The result to return for matching instructions.</param>
+ public EventFinder(string fullTypeName, string eventName, InstructionHandleResult result)
+ : this(fullTypeName, new[] { eventName }, result) { }
+
/// <inheritdoc />
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 != 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
- *********/
- /// <summary>Get whether a CIL instruction matches.</summary>
- /// <param name="instruction">The IL instruction.</param>
- 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..68415123 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
/// <summary>The full type name for which to find references.</summary>
private readonly string FullTypeName;
- /// <summary>The field name for which to find references.</summary>
- private readonly string FieldName;
+ /// <summary>The field names for which to find references.</summary>
+ private readonly ISet<string> FieldNames;
/// <summary>The result to return for matching instructions.</summary>
private readonly InstructionHandleResult Result;
@@ -25,21 +27,37 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
*********/
/// <summary>Construct an instance.</summary>
/// <param name="fullTypeName">The full type name for which to find references.</param>
- /// <param name="fieldName">The field name for which to find references.</param>
+ /// <param name="fieldNames">The field names for which to find references.</param>
/// <param name="result">The result to return for matching instructions.</param>
- 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<string>(fieldNames);
this.Result = result;
}
+ /// <summary>Construct an instance.</summary>
+ /// <param name="fullTypeName">The full type name for which to find references.</param>
+ /// <param name="fieldName">The field name for which to find references.</param>
+ /// <param name="result">The result to return for matching instructions.</param>
+ public FieldFinder(string fullTypeName, string fieldName, InstructionHandleResult result)
+ : this(fullTypeName, new[] { fieldName }, result) { }
+
/// <inheritdoc />
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 != 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
*********/
/// <summary>The assembly names to which to heuristically detect broken references.</summary>
- private readonly HashSet<string> ValidateReferencesToAssemblies;
+ private readonly ISet<string> ValidateReferencesToAssemblies;
/*********
@@ -22,10 +22,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
*********/
/// <summary>Construct an instance.</summary>
/// <param name="validateReferencesToAssemblies">The assembly names to which to heuristically detect broken references.</param>
- public ReferenceToMemberWithUnexpectedTypeFinder(string[] validateReferencesToAssemblies)
+ public ReferenceToMemberWithUnexpectedTypeFinder(ISet<string> validateReferencesToAssemblies)
: base(defaultPhrase: "")
{
- this.ValidateReferencesToAssemblies = new HashSet<string>(validateReferencesToAssemblies);
+ this.ValidateReferencesToAssemblies = validateReferencesToAssemblies;
}
/// <inheritdoc />
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
*********/
/// <summary>The assembly names to which to heuristically detect broken references.</summary>
- private readonly HashSet<string> ValidateReferencesToAssemblies;
+ private readonly ISet<string> ValidateReferencesToAssemblies;
/*********
@@ -21,10 +21,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
*********/
/// <summary>Construct an instance.</summary>
/// <param name="validateReferencesToAssemblies">The assembly names to which to heuristically detect broken references.</param>
- public ReferenceToMissingMemberFinder(string[] validateReferencesToAssemblies)
+ public ReferenceToMissingMemberFinder(ISet<string> validateReferencesToAssemblies)
: base(defaultPhrase: "")
{
- this.ValidateReferencesToAssemblies = new HashSet<string>(validateReferencesToAssemblies);
+ this.ValidateReferencesToAssemblies = validateReferencesToAssemblies;
}
/// <inheritdoc />
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
*********/
- /// <summary>The full type name to match.</summary>
- private readonly string FullTypeName;
+ /// <summary>The full type names remaining to match.</summary>
+ private readonly ISet<string> FullTypeNames;
/// <summary>The result to return for matching instructions.</summary>
private readonly InstructionHandleResult Result;
@@ -24,22 +25,34 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
** Public methods
*********/
/// <summary>Construct an instance.</summary>
- /// <param name="fullTypeName">The full type name to match.</param>
+ /// <param name="fullTypeNames">The full type names to match.</param>
/// <param name="result">The result to return for matching instructions.</param>
/// <param name="shouldIgnore">Get whether a matched type should be ignored.</param>
- public TypeFinder(string fullTypeName, InstructionHandleResult result, Func<TypeReference, bool> shouldIgnore = null)
- : base(defaultPhrase: $"{fullTypeName} type")
+ public TypeFinder(string[] fullTypeNames, InstructionHandleResult result, Func<TypeReference, bool> 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<string>(fullTypeNames);
this.Result = result;
this.ShouldIgnore = shouldIgnore;
}
+ /// <summary>Construct an instance.</summary>
+ /// <param name="fullTypeName">The full type name to match.</param>
+ /// <param name="result">The result to return for matching instructions.</param>
+ /// <param name="shouldIgnore">Get whether a matched type should be ignored.</param>
+ public TypeFinder(string fullTypeName, InstructionHandleResult result, Func<TypeReference, bool> shouldIgnore = null)
+ : this(new[] { fullTypeName }, result, shouldIgnore) { }
+
/// <inheritdoc />
public override bool Handle(ModuleDefinition module, TypeReference type, Action<TypeReference> 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/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
@@ -25,6 +25,12 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
** Public methods
*********/
/// <inheritdoc />
+ public virtual bool Handle(ModuleDefinition module)
+ {
+ return false;
+ }
+
+ /// <inheritdoc />
public virtual bool Handle(ModuleDefinition module, TypeReference type, Action<TypeReference> replaceWith)
{
return false;
diff --git a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs
index 10f68f0d..4f14a579 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
*********/
+ /// <summary>Rewrite a module definition in the assembly code.</summary>
+ /// <param name="module">The current module definition.</param>
+ /// <returns>Returns whether the module was changed.</returns>
+ public delegate bool RewriteModuleDelegate(ModuleDefinition module);
+
/// <summary>Rewrite a type reference in the assembly code.</summary>
/// <param name="type">The current type reference.</param>
/// <param name="replaceWith">Replaces the type reference with the given type.</param>
@@ -32,6 +37,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
/// <summary>The module to rewrite.</summary>
public ModuleDefinition Module { get; }
+ /// <summary>Handle or rewrite a module definition if needed.</summary>
+ public RewriteModuleDelegate RewriteModuleImpl { get; }
+
/// <summary>Handle or rewrite a type reference if needed.</summary>
public RewriteTypeDelegate RewriteTypeImpl { get; }
@@ -44,11 +52,13 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
*********/
/// <summary>Construct an instance.</summary>
/// <param name="module">The module to rewrite.</param>
+ /// <param name="rewriteModule">Handle or rewrite a module if needed.</param>
/// <param name="rewriteType">Handle or rewrite a type reference if needed.</param>
/// <param name="rewriteInstruction">Handle or rewrite a CIL instruction if needed.</param>
- 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 +73,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
*********/
+ /// <summary>Rewrite a module definition if needed.</summary>
+ /// <param name="module">The assembly module.</param>
+ /// <returns>Returns whether the module was changed.</returns>
+ bool Handle(ModuleDefinition module);
+
/// <summary>Rewrite a type reference if needed.</summary>
/// <param name="module">The assembly module containing the instruction.</param>
/// <param name="type">The type definition to handle.</param>
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
/// <inheritdoc />
public bool IsContentPack => this.Manifest?.ContentPackFor != null;
+ /// <summary>The fake content packs created by this mod, if any.</summary>
+ public ISet<WeakReference<ContentPack>> FakeContentPacks { get; } = new HashSet<WeakReference<ContentPack>>();
+
/*********
** Public methods
@@ -244,6 +247,21 @@ namespace StardewModdingAPI.Framework.ModLoading
return Path.Combine(rootFolderName, this.RelativeDirectoryPath);
}
+ /// <summary>Get the currently live fake content packs created by this mod.</summary>
+ public IEnumerable<ContentPack> 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/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<string> updateUrls = new List<string>();
- 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);
}
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs
new file mode 100644
index 00000000..cc830216
--- /dev/null
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs
@@ -0,0 +1,31 @@
+using Mono.Cecil;
+using StardewModdingAPI.Framework.ModLoading.Framework;
+
+namespace StardewModdingAPI.Framework.ModLoading.Rewriters
+{
+ /// <summary>Removes the 32-bit-only from loaded assemblies.</summary>
+ internal class ArchitectureAssemblyRewriter : BaseInstructionHandler
+ {
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ public ArchitectureAssemblyRewriter()
+ : base(defaultPhrase: "32-bit architecture") { }
+
+
+ /// <inheritdoc />
+ public override bool Handle(ModuleDefinition module)
+ {
+ if (module.Attributes.HasFlag(ModuleAttributes.Required32Bit))
+ {
+ module.Attributes &= ~ModuleAttributes.Required32Bit;
+ this.MarkRewritten();
+ return true;
+ }
+
+ return false;
+ }
+
+ }
+}
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs
index 7a3b428d..922d4bc4 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs
@@ -7,8 +7,8 @@ using StardewModdingAPI.Framework.ModLoading.RewriteFacades;
namespace StardewModdingAPI.Framework.ModLoading.Rewriters
{
- /// <summary>Rewrites Harmony 1.x assembly references to work with Harmony 2.x.</summary>
- internal class Harmony1AssemblyRewriter : BaseInstructionHandler
+ /// <summary>Detects Harmony references, and rewrites Harmony 1.x assembly references to work with Harmony 2.x.</summary>
+ internal class HarmonyRewriter : BaseInstructionHandler
{
/*********
** Fields
@@ -16,19 +16,29 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
/// <summary>Whether any Harmony 1.x types were replaced.</summary>
private bool ReplacedTypes;
+ /// <summary>Whether to rewrite Harmony 1.x code.</summary>
+ private readonly bool ShouldRewrite;
+
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
- public Harmony1AssemblyRewriter()
- : base(defaultPhrase: "Harmony 1.x") { }
+ public HarmonyRewriter(bool shouldRewrite = true)
+ : base(defaultPhrase: "Harmony 1.x")
+ {
+ this.ShouldRewrite = shouldRewrite;
+ }
/// <inheritdoc />
public override bool Handle(ModuleDefinition module, TypeReference type, Action<TypeReference> replaceWith)
{
+ // detect Harmony
+ if (!(type.Scope is AssemblyNameReference scope) || scope.Name != "0Harmony")
+ return false;
+
// rewrite Harmony 1.x type to Harmony 2.0 type
- if (type.Scope is AssemblyNameReference { Name: "0Harmony" } scope && scope.Version.Major == 1)
+ if (this.ShouldRewrite && scope.Version.Major == 1)
{
Type targetType = this.GetMappedType(type);
replaceWith(module.ImportReference(targetType));
@@ -37,28 +47,32 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
return true;
}
+ this.MarkFlag(InstructionHandleResult.DetectedGamePatch);
return false;
}
/// <inheritdoc />
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 (this.ShouldRewrite)
{
- if (fieldRef.DeclaringType.FullName == "HarmonyLib.HarmonyMethod" && fieldRef.Name == "prioritiy")
+ // rewrite Harmony 1.x methods to Harmony 2.0
+ MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
+ if (this.TryRewriteMethodsToFacade(module, methodRef))
{
- fieldRef.Name = nameof(HarmonyMethod.priority);
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();
+ }
}
}
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
*********/
/// <summary>The assembly names to which to rewrite broken references.</summary>
- private readonly HashSet<string> RewriteReferencesToAssemblies;
+ private readonly ISet<string> RewriteReferencesToAssemblies;
/*********
@@ -21,10 +21,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
*********/
/// <summary>Construct an instance.</summary>
/// <param name="rewriteReferencesToAssemblies">The assembly names to which to rewrite broken references.</param>
- public HeuristicFieldRewriter(string[] rewriteReferencesToAssemblies)
+ public HeuristicFieldRewriter(ISet<string> rewriteReferencesToAssemblies)
: base(defaultPhrase: "field changed to property") // ignored since we specify phrases
{
- this.RewriteReferencesToAssemblies = new HashSet<string>(rewriteReferencesToAssemblies);
+ this.RewriteReferencesToAssemblies = rewriteReferencesToAssemblies;
}
/// <inheritdoc />
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
*********/
/// <summary>The assembly names to which to rewrite broken references.</summary>
- private readonly HashSet<string> RewriteReferencesToAssemblies;
+ private readonly ISet<string> RewriteReferencesToAssemblies;
/*********
@@ -21,10 +21,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
*********/
/// <summary>Construct an instance.</summary>
/// <param name="rewriteReferencesToAssemblies">The assembly names to which to rewrite broken references.</param>
- public HeuristicMethodRewriter(string[] rewriteReferencesToAssemblies)
+ public HeuristicMethodRewriter(ISet<string> rewriteReferencesToAssemblies)
: base(defaultPhrase: "methods with missing parameters") // ignored since we specify phrases
{
- this.RewriteReferencesToAssemblies = new HashSet<string>(rewriteReferencesToAssemblies);
+ this.RewriteReferencesToAssemblies = rewriteReferencesToAssemblies;
}
/// <inheritdoc />