From 9bc53145150d9209fb5b13e82857afb6c155b7a5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 6 Jun 2018 21:42:09 -0400 Subject: add Harmony DLL (#541) --- src/SMAPI/StardewModdingAPI.csproj | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/SMAPI') diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 7eb5f95a..d2a65f48 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -53,6 +53,10 @@ icon.ico + + False + ..\lib\0Harmony.dll + ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll True -- cgit From cd62dcc8cfa35a9b423f4d15359ec3083b4c6d44 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 6 Jun 2018 21:45:03 -0400 Subject: add simple Harmony wrapper for validation, error-handling, etc (#541) --- src/SMAPI/Constants.cs | 3 ++ src/SMAPI/Framework/Patching/GamePatcher.cs | 45 +++++++++++++++++++++++++++ src/SMAPI/Framework/Patching/IHarmonyPatch.cs | 15 +++++++++ src/SMAPI/Program.cs | 14 ++++----- src/SMAPI/StardewModdingAPI.csproj | 2 ++ 5 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 src/SMAPI/Framework/Patching/GamePatcher.cs create mode 100644 src/SMAPI/Framework/Patching/IHarmonyPatch.cs (limited to 'src/SMAPI') diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 786c1a39..d96c5839 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -103,6 +103,9 @@ namespace StardewModdingAPI /// The target game platform. internal static Platform Platform { get; } = EnvironmentUtility.DetectPlatform(); + /// The game's assembly name. + internal static string GameAssemblyName => Constants.Platform == Platform.Windows ? "Stardew Valley" : "StardewValley"; + /********* ** Internal methods diff --git a/src/SMAPI/Framework/Patching/GamePatcher.cs b/src/SMAPI/Framework/Patching/GamePatcher.cs new file mode 100644 index 00000000..71ca8e55 --- /dev/null +++ b/src/SMAPI/Framework/Patching/GamePatcher.cs @@ -0,0 +1,45 @@ +using System; +using Harmony; + +namespace StardewModdingAPI.Framework.Patching +{ + /// Encapsulates applying Harmony patches to the game. + internal class GamePatcher + { + /********* + ** Properties + *********/ + /// Encapsulates monitoring and logging. + private readonly IMonitor Monitor; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Encapsulates monitoring and logging. + public GamePatcher(IMonitor monitor) + { + this.Monitor = monitor; + } + + /// Apply all loaded patches to the game. + /// The patches to apply. + public void Apply(params IHarmonyPatch[] patches) + { + HarmonyInstance harmony = HarmonyInstance.Create("io.smapi"); + foreach (IHarmonyPatch patch in patches) + { + try + { + patch.Apply(harmony); + } + catch (Exception ex) + { + this.Monitor.Log($"Couldn't apply runtime patch '{patch.Name}' to the game. Some SMAPI features may not work correctly. See log file for details.", LogLevel.Error); + this.Monitor.Log(ex.GetLogSummary(), LogLevel.Trace); + } + } + } + } +} diff --git a/src/SMAPI/Framework/Patching/IHarmonyPatch.cs b/src/SMAPI/Framework/Patching/IHarmonyPatch.cs new file mode 100644 index 00000000..cb42f40e --- /dev/null +++ b/src/SMAPI/Framework/Patching/IHarmonyPatch.cs @@ -0,0 +1,15 @@ +using Harmony; + +namespace StardewModdingAPI.Framework.Patching +{ + /// A Harmony patch to apply. + internal interface IHarmonyPatch + { + /// A unique name for this patch. + string Name { get; } + + /// Apply the Harmony patch. + /// The Harmony instance. + void Apply(HarmonyInstance harmony); + } +} diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index cc59c0cd..bf673fe6 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -24,6 +24,7 @@ using StardewModdingAPI.Framework.ModData; using StardewModdingAPI.Framework.Models; using StardewModdingAPI.Framework.ModHelpers; using StardewModdingAPI.Framework.ModLoading; +using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Framework.Serialisation; using StardewModdingAPI.Internal; @@ -152,6 +153,10 @@ namespace StardewModdingAPI }; this.EventManager = new EventManager(this.Monitor, this.ModRegistry); + // apply game patches + new GamePatcher(this.Monitor).Apply( + ); + // init JSON parser JsonConverter[] converters = { new StringEnumConverter(), @@ -359,14 +364,7 @@ namespace StardewModdingAPI Console.ResetColor(); Program.PressAnyKeyToExit(showMessage: true); } - - // get game assembly name - const string gameAssemblyName = -#if SMAPI_FOR_WINDOWS - "Stardew Valley"; -#else - "StardewValley"; -#endif + string gameAssemblyName = Constants.GameAssemblyName; // game not present if (Type.GetType($"StardewValley.Game1, {gameAssemblyName}", throwOnError: false) == null) diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index d2a65f48..125e7746 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -107,6 +107,8 @@ + + -- cgit From a2d8a1be23f2351384a562b64807d2ce9c83170e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 6 Jun 2018 21:48:23 -0400 Subject: add Harmony patch to fix custom tilesheet handling (#541) --- docs/release-notes.md | 2 + src/SMAPI/Framework/Patching/GameLocationPatch.cs | 60 +++++++++++++++++++++++ src/SMAPI/Program.cs | 1 + src/SMAPI/StardewModdingAPI.csproj | 1 + 4 files changed, 64 insertions(+) create mode 100644 src/SMAPI/Framework/Patching/GameLocationPatch.cs (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 11a2a04c..e62f5e7c 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -29,6 +29,8 @@ * Added `Context.IsMultiplayer` and `Context.IsMainPlayer` flags. * Added `Constants.TargetPlatform` which says whether the game is running on Linux, Mac, or Windows. * Added `semanticVersion.IsPrerelease()` method. + * Added Harmony DLL managed by SMAPI. + * Fixed error when loading an unpacked `.tbin` map that references custom seasonal tilesheets. * Fixed error if a mod loads a PNG while the game is loading (e.g. custom map tilesheets via `IAssetLoader`). * Fixed assets loaded by temporary content managers not being editable by mods. * Fixed assets not reloaded consistently when the player switches language. diff --git a/src/SMAPI/Framework/Patching/GameLocationPatch.cs b/src/SMAPI/Framework/Patching/GameLocationPatch.cs new file mode 100644 index 00000000..669c700a --- /dev/null +++ b/src/SMAPI/Framework/Patching/GameLocationPatch.cs @@ -0,0 +1,60 @@ +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Reflection; +using Harmony; +using StardewValley; +using xTile.Tiles; + +namespace StardewModdingAPI.Framework.Patching +{ + /// A Harmony patch for the method. + internal class GameLocationPatch : IHarmonyPatch + { + /********* + ** Accessors + *********/ + /// A unique name for this patch. + public string Name => $"{nameof(GameLocation)}.{nameof(GameLocation.updateSeasonalTileSheets)}"; + + + /********* + ** Public methods + *********/ + /// Apply the Harmony patch. + /// The Harmony instance. + public void Apply(HarmonyInstance harmony) + { + MethodInfo method = AccessTools.Method(typeof(GameLocation), nameof(GameLocation.updateSeasonalTileSheets)); + MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(GameLocationPatch.Prefix)); + + harmony.Patch(method, new HarmonyMethod(prefix), null); + } + + + /********* + ** Private methods + *********/ + /// An implementation of which correctly handles custom map tilesheets. + /// The location instance being patched. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument name is defined by Harmony.")] + private static bool Prefix(ref GameLocation __instance) + { + if (!__instance.IsOutdoors || __instance.Name.Equals("Desert")) + return false; + foreach (TileSheet tilesheet in __instance.Map.TileSheets) + { + string imageSource = tilesheet.ImageSource; + string imageFile = Path.GetFileName(imageSource); + if (imageFile.StartsWith("spring_") || imageFile.StartsWith("summer_") || imageFile.StartsWith("fall_") || imageFile.StartsWith("winter_")) + { + string imageDir = Path.GetDirectoryName(imageSource); + if (string.IsNullOrWhiteSpace(imageDir)) + imageDir = "Maps"; + tilesheet.ImageSource = Path.Combine(imageDir, Game1.currentSeason + "_" + imageFile.Split('_')[1]); + } + } + + return false; + } + } +} diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index bf673fe6..85306641 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -155,6 +155,7 @@ namespace StardewModdingAPI // apply game patches new GamePatcher(this.Monitor).Apply( + new GameLocationPatch() ); // init JSON parser diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 125e7746..2df3e63f 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -285,6 +285,7 @@ + -- cgit From a555c15babc80c87b9d49570fda43323f10539bf Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 6 Jun 2018 22:12:22 -0400 Subject: rm unneeded ref (#541) --- src/SMAPI/Framework/Patching/GameLocationPatch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/Patching/GameLocationPatch.cs b/src/SMAPI/Framework/Patching/GameLocationPatch.cs index 669c700a..c0216b8f 100644 --- a/src/SMAPI/Framework/Patching/GameLocationPatch.cs +++ b/src/SMAPI/Framework/Patching/GameLocationPatch.cs @@ -37,7 +37,7 @@ namespace StardewModdingAPI.Framework.Patching /// An implementation of which correctly handles custom map tilesheets. /// The location instance being patched. [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument name is defined by Harmony.")] - private static bool Prefix(ref GameLocation __instance) + private static bool Prefix(GameLocation __instance) { if (!__instance.IsOutdoors || __instance.Name.Equals("Desert")) return false; -- cgit From dd7887e0beb94179886494d40359b02db8e6dbe4 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 6 Jun 2018 22:26:04 -0400 Subject: fix incorrect type alias --- src/SMAPI/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index 85306641..83ce6f99 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -33,7 +33,7 @@ using StardewModdingAPI.Toolkit.Serialisation; using StardewModdingAPI.Toolkit.Serialisation.Converters; using StardewModdingAPI.Toolkit.Utilities; using StardewValley; -using Keys = System.Windows.Forms.Keys; +using Keys = Microsoft.Xna.Framework.Input.Keys; using Monitor = StardewModdingAPI.Framework.Monitor; using SObject = StardewValley.Object; using ThreadState = System.Threading.ThreadState; -- cgit