From 15f829e48c1ee9731a812798841ee102e024775d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 12 Jun 2022 12:26:51 -0400 Subject: patch PyTK temporarily to fix scale-up compatibility in SMAPI 3.15 --- src/SMAPI.Mods.ErrorHandler/ModEntry.cs | 7 +- .../ModPatches/PyTkPatcher.cs | 79 ++++++++++++++++++++++ .../SMAPI.Mods.ErrorHandler.csproj | 3 - src/SMAPI.sln | 4 +- src/SMAPI/Framework/SCore.cs | 2 + src/SMAPI/Properties/AssemblyInfo.cs | 1 + 6 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 src/SMAPI.Mods.ErrorHandler/ModPatches/PyTkPatcher.cs (limited to 'src') diff --git a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs index bfbfd2dc..22e68421 100644 --- a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs +++ b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs @@ -2,6 +2,7 @@ using System; using System.Reflection; using StardewModdingAPI.Events; using StardewModdingAPI.Internal.Patching; +using StardewModdingAPI.Mods.ErrorHandler.ModPatches; using StardewModdingAPI.Mods.ErrorHandler.Patches; using StardewValley; @@ -29,6 +30,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler // apply patches HarmonyPatcher.Apply(this.ModManifest.UniqueID, this.Monitor, + // game patches new DialoguePatcher(monitorForGame, this.Helper.Reflection), new EventPatcher(monitorForGame), new GameLocationPatcher(monitorForGame), @@ -37,7 +39,10 @@ namespace StardewModdingAPI.Mods.ErrorHandler new ObjectPatcher(), new SaveGamePatcher(this.Monitor, this.OnSaveContentRemoved), new SpriteBatchPatcher(), - new UtilityPatcher() + new UtilityPatcher(), + + // mod patches + new PyTkPatcher(helper.ModRegistry) ); // hook events diff --git a/src/SMAPI.Mods.ErrorHandler/ModPatches/PyTkPatcher.cs b/src/SMAPI.Mods.ErrorHandler/ModPatches/PyTkPatcher.cs new file mode 100644 index 00000000..9ee864db --- /dev/null +++ b/src/SMAPI.Mods.ErrorHandler/ModPatches/PyTkPatcher.cs @@ -0,0 +1,79 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using HarmonyLib; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using StardewModdingAPI.Framework; +using StardewModdingAPI.Framework.Content; +using StardewModdingAPI.Internal; +using StardewModdingAPI.Internal.Patching; + +// +// This is part of a three-part fix for PyTK 1.23.0 and earlier. When removing this, search +// 'Platonymous.Toolkit' to find the other part in SMAPI and Content Patcher. +// + +namespace StardewModdingAPI.Mods.ErrorHandler.ModPatches +{ + /// Harmony patches for the PyTK mod for compatibility with newer SMAPI versions. + /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "StringLiteralTypo", Justification = "'Platonymous' is part of the mod ID.")] + internal class PyTkPatcher : BasePatcher + { + /********* + ** Fields + *********/ + /// The PyTK mod metadata, if it's installed. + private static IModMetadata? PyTk; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The mod registry from which to read PyTK metadata. + public PyTkPatcher(IModRegistry modRegistry) + { + IModMetadata? pyTk = (IModMetadata?)modRegistry.Get(@"Platonymous.Toolkit"); + if (pyTk is not null && !pyTk.Manifest.Version.IsNewerThan("1.23.0")) + PyTkPatcher.PyTk = pyTk; + } + + /// + public override void Apply(Harmony harmony, IMonitor monitor) + { + try + { + // get mod info + IModMetadata? pyTk = PyTkPatcher.PyTk; + if (pyTk is null) + return; + + // get patch method + const string patchMethodName = "PatchImage"; + MethodInfo? patch = AccessTools.Method(pyTk.Mod!.GetType(), patchMethodName); + if (patch is null) + { + monitor.Log("Failed applying compatibility patch for PyTK. Its image scaling feature may not work correctly.", LogLevel.Warn); + monitor.Log($"Couldn't find patch method '{pyTk.Mod.GetType().FullName}.{patchMethodName}'."); + return; + } + + // apply patch + harmony = new($"{harmony.Id}.compatibility-patches.PyTK"); + harmony.Patch( + original: AccessTools.Method(typeof(AssetDataForImage), nameof(AssetDataForImage.PatchImage), new[] { typeof(Texture2D), typeof(Rectangle), typeof(Rectangle), typeof(PatchMode) }), + prefix: new HarmonyMethod(patch) + ); + } + catch (Exception ex) + { + monitor.Log("Failed applying compatibility patch for PyTK. Its image scaling feature may not work correctly.", LogLevel.Warn); + monitor.Log(ex.GetLogSummary()); + } + } + } +} diff --git a/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj b/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj index 78cdb315..53c37e97 100644 --- a/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj +++ b/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj @@ -24,7 +24,4 @@ - - - diff --git a/src/SMAPI.sln b/src/SMAPI.sln index d9f60a5c..2e5ba0ea 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -103,14 +103,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{3B5BF14D-F61 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiProvider", "SMAPI.Tests.ModApiProvider\SMAPI.Tests.ModApiProvider.csproj", "{239AEEAC-07D1-4A3F-AA99-8C74F5038F50}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMAPI.Tests.ModApiConsumer", "SMAPI.Tests.ModApiConsumer\SMAPI.Tests.ModApiConsumer.csproj", "{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiConsumer", "SMAPI.Tests.ModApiConsumer\SMAPI.Tests.ModApiConsumer.csproj", "{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5 SMAPI.Internal\SMAPI.Internal.projitems*{0a9bb24f-15ff-4c26-b1a2-81f7ae316518}*SharedItemsImports = 5 - SMAPI.Internal.Patching\SMAPI.Internal.Patching.projitems*{491e775b-ead0-44d4-b6ca-f1fc3e316d33}*SharedItemsImports = 5 - SMAPI.Internal\SMAPI.Internal.projitems*{491e775b-ead0-44d4-b6ca-f1fc3e316d33}*SharedItemsImports = 5 SMAPI.Internal.Patching\SMAPI.Internal.Patching.projitems*{6c16e948-3e5c-47a7-bf4b-07a7469a87a5}*SharedItemsImports = 13 SMAPI.Internal\SMAPI.Internal.projitems*{80efd92f-728f-41e0-8a5b-9f6f49a91899}*SharedItemsImports = 5 SMAPI.Internal\SMAPI.Internal.projitems*{85208f8d-6fd1-4531-be05-7142490f59fe}*SharedItemsImports = 13 diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 7792c64a..0fbf6525 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -1637,6 +1637,8 @@ namespace StardewModdingAPI.Framework this.ReloadTranslations(loaded); // set temporary PyTK compatibility mode + // This is part of a three-part fix for PyTK 1.23.0 and earlier. When removing this, + // search 'Platonymous.Toolkit' to find the other part in SMAPI and Content Patcher. { IModInfo? pyTk = this.ModRegistry.Get("Platonymous.Toolkit"); ModContentManager.EnablePyTkLegacyMode = pyTk is not null && pyTk.Manifest.Version.IsOlderThan("1.23.1"); diff --git a/src/SMAPI/Properties/AssemblyInfo.cs b/src/SMAPI/Properties/AssemblyInfo.cs index daa58943..afff16b8 100644 --- a/src/SMAPI/Properties/AssemblyInfo.cs +++ b/src/SMAPI/Properties/AssemblyInfo.cs @@ -3,3 +3,4 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("SMAPI.Tests")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] // Moq for unit testing [assembly: InternalsVisibleTo("ContentPatcher")] +[assembly: InternalsVisibleTo("ErrorHandler")] -- cgit