diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2022-05-31 21:23:44 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2022-05-31 21:23:44 -0400 |
commit | bf960ce283d794a11885a5fde6f123a4e6827853 (patch) | |
tree | 00986f30b162bc511f3e010c54a0057dffdddc81 | |
parent | 9992915f565578949cad8d9bb8ceb360e0db5c85 (diff) | |
download | SMAPI-bf960ce283d794a11885a5fde6f123a4e6827853.tar.gz SMAPI-bf960ce283d794a11885a5fde6f123a4e6827853.tar.bz2 SMAPI-bf960ce283d794a11885a5fde6f123a4e6827853.zip |
add backwards compatibility for mods using now-unused dependencies
-rw-r--r-- | build/common.targets | 5 | ||||
-rwxr-xr-x | build/unix/prepare-install-package.sh | 5 | ||||
-rw-r--r-- | build/windows/prepare-install-package.ps1 | 5 | ||||
-rw-r--r-- | src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs | 11 | ||||
-rw-r--r-- | src/SMAPI/Framework/IModMetadata.cs | 4 | ||||
-rw-r--r-- | src/SMAPI/Framework/ModLoading/AssemblyLoader.cs | 38 | ||||
-rw-r--r-- | src/SMAPI/Framework/ModLoading/Finders/LegacyAssemblyFinder.cs | 49 | ||||
-rw-r--r-- | src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs | 11 | ||||
-rw-r--r-- | src/SMAPI/Framework/ModLoading/ModMetadata.cs | 7 | ||||
-rw-r--r-- | src/SMAPI/Framework/SCore.cs | 25 | ||||
-rw-r--r-- | src/SMAPI/Metadata/InstructionMetadata.cs | 3 | ||||
-rw-r--r-- | src/SMAPI/SMAPI.csproj | 3 |
12 files changed, 164 insertions, 2 deletions
diff --git a/build/common.targets b/build/common.targets index b2441af8..10b94d7e 100644 --- a/build/common.targets +++ b/build/common.targets @@ -70,6 +70,11 @@ <!-- .NET dependencies --> <Copy SourceFiles="$(TargetDir)\System.Management.dll" DestinationFolder="$(GamePath)\smapi-internal" Condition="$(OS) == 'Windows_NT'" /> + + <!-- Legacy .NET dependencies (remove in SMAPI 4.0.0) --> + <Copy SourceFiles="$(TargetDir)\System.Configuration.ConfigurationManager.dll" DestinationFolder="$(GamePath)\smapi-internal" /> + <Copy SourceFiles="$(TargetDir)\System.Runtime.Caching.dll" DestinationFolder="$(GamePath)\smapi-internal" /> + <Copy SourceFiles="$(TargetDir)\System.Security.Permissions.dll" DestinationFolder="$(GamePath)\smapi-internal" /> </Target> <Target Name="CopyDefaultMods" Condition="'$(MSBuildProjectName)' == 'SMAPI.Mods.ConsoleCommands' OR '$(MSBuildProjectName)' == 'SMAPI.Mods.ErrorHandler' OR '$(MSBuildProjectName)' == 'SMAPI.Mods.SaveBackup'"> diff --git a/build/unix/prepare-install-package.sh b/build/unix/prepare-install-package.sh index 01c3a0ec..01cd2080 100755 --- a/build/unix/prepare-install-package.sh +++ b/build/unix/prepare-install-package.sh @@ -151,6 +151,11 @@ for folder in ${folders[@]}; do cp "$smapiBin/System.Management.dll" "$bundlePath/smapi-internal" fi + # copy legacy .NET dependencies (remove in SMAPI 4.0.0) + cp "$smapiBin/System.Configuration.ConfigurationManager.dll" "$bundlePath/smapi-internal" + cp "$smapiBin/System.Runtime.Caching.dll" "$bundlePath/smapi-internal" + cp "$smapiBin/System.Security.Permissions.dll" "$bundlePath/smapi-internal" + # copy bundled mods for modName in ${bundleModNames[@]}; do fromPath="src/SMAPI.Mods.$modName/bin/$buildConfig/$runtime/publish" diff --git a/build/windows/prepare-install-package.ps1 b/build/windows/prepare-install-package.ps1 index 6731486b..7e3c6c86 100644 --- a/build/windows/prepare-install-package.ps1 +++ b/build/windows/prepare-install-package.ps1 @@ -172,6 +172,11 @@ foreach ($folder in $folders) { cp "$smapiBin/System.Management.dll" "$bundlePath/smapi-internal" } + # copy legacy .NET dependencies (remove in SMAPI 4.0.0) + cp "$smapiBin/System.Configuration.ConfigurationManager.dll" "$bundlePath/smapi-internal" + cp "$smapiBin/System.Runtime.Caching.dll" "$bundlePath/smapi-internal" + cp "$smapiBin/System.Security.Permissions.dll" "$bundlePath/smapi-internal" + # copy bundled mods foreach ($modName in $bundleModNames) { $fromPath = "src/SMAPI.Mods.$modName/bin/$buildConfig/$runtime/publish" diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs b/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs index cf804df4..32c2ed6d 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs @@ -35,6 +35,15 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData AccessesFilesystem = 128, /// <summary>Uses .NET APIs for shell or process access.</summary> - AccessesShell = 256 + AccessesShell = 256, + + /// <summary>References the legacy <c>System.Configuration.ConfigurationManager</c> assembly and doesn't include a copy in the mod folder, so it'll break in SMAPI 4.0.0.</summary> + DetectedLegacyConfigurationDll = 512, + + /// <summary>References the legacy <c>System.Runtime.Caching</c> assembly and doesn't include a copy in the mod folder, so it'll break in SMAPI 4.0.0.</summary> + DetectedLegacyCachingDll = 1024, + + /// <summary>References the legacy <c>System.Security.Permissions</c> assembly and doesn't include a copy in the mod folder, so it'll break in SMAPI 4.0.0.</summary> + DetectedLegacyPermissionsDll = 2048 } } diff --git a/src/SMAPI/Framework/IModMetadata.cs b/src/SMAPI/Framework/IModMetadata.cs index 7cee20b9..be25c070 100644 --- a/src/SMAPI/Framework/IModMetadata.cs +++ b/src/SMAPI/Framework/IModMetadata.cs @@ -88,6 +88,10 @@ namespace StardewModdingAPI.Framework /// <param name="warning">The warning to set.</param> IModMetadata SetWarning(ModWarning warning); + /// <summary>Remove a warning flag for the mod.</summary> + /// <param name="warning">The warning to remove.</param> + IModMetadata RemoveWarning(ModWarning warning); + /// <summary>Set the mod instance.</summary> /// <param name="mod">The mod instance to set.</param> /// <param name="translations">The translations for this mod (if loaded).</param> diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index fb5ebc01..e5aaa8ee 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -163,6 +163,29 @@ namespace StardewModdingAPI.Framework.ModLoading this.AssemblyDefinitionResolver.Add(assembly.Definition); } + // special case: clear legacy-DLL warnings if the mod bundles a copy + if (mod.Warnings.HasFlag(ModWarning.DetectedLegacyCachingDll)) + { + if (File.Exists(Path.Combine(mod.DirectoryPath, "System.Runtime.Caching.dll"))) + mod.RemoveWarning(ModWarning.DetectedLegacyCachingDll); + else + { + // remove duplicate warnings (System.Runtime.Caching.dll references these) + mod.RemoveWarning(ModWarning.DetectedLegacyConfigurationDll); + mod.RemoveWarning(ModWarning.DetectedLegacyPermissionsDll); + } + } + if (mod.Warnings.HasFlag(ModWarning.DetectedLegacyConfigurationDll)) + { + if (File.Exists(Path.Combine(mod.DirectoryPath, "System.Configuration.ConfigurationManager.dll"))) + mod.RemoveWarning(ModWarning.DetectedLegacyConfigurationDll); + } + if (mod.Warnings.HasFlag(ModWarning.DetectedLegacyPermissionsDll)) + { + if (File.Exists(Path.Combine(mod.DirectoryPath, "System.Security.Permissions.dll"))) + mod.RemoveWarning(ModWarning.DetectedLegacyPermissionsDll); + } + // throw if incompatibilities detected if (!assumeCompatible && mod.Warnings.HasFlag(ModWarning.BrokenCodeLoaded)) throw new IncompatibleInstructionException(); @@ -429,6 +452,21 @@ namespace StardewModdingAPI.Framework.ModLoading mod.SetWarning(ModWarning.AccessesShell); break; + case InstructionHandleResult.DetectedLegacyCachingDll: + template = $"{logPrefix}Detected reference to System.Runtime.Caching.dll, which will be removed in SMAPI 4.0.0."; + mod.SetWarning(ModWarning.DetectedLegacyCachingDll); + break; + + case InstructionHandleResult.DetectedLegacyConfigurationDll: + template = $"{logPrefix}Detected reference to System.Configuration.ConfigurationManager.dll, which will be removed in SMAPI 4.0.0."; + mod.SetWarning(ModWarning.DetectedLegacyConfigurationDll); + break; + + case InstructionHandleResult.DetectedLegacyPermissionsDll: + template = $"{logPrefix}Detected reference to System.Security.Permissions.dll, which will be removed in SMAPI 4.0.0."; + mod.SetWarning(ModWarning.DetectedLegacyPermissionsDll); + break; + case InstructionHandleResult.None: break; diff --git a/src/SMAPI/Framework/ModLoading/Finders/LegacyAssemblyFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/LegacyAssemblyFinder.cs new file mode 100644 index 00000000..d3437b05 --- /dev/null +++ b/src/SMAPI/Framework/ModLoading/Finders/LegacyAssemblyFinder.cs @@ -0,0 +1,49 @@ +using Mono.Cecil; +using StardewModdingAPI.Framework.ModLoading.Framework; + +namespace StardewModdingAPI.Framework.ModLoading.Finders +{ + /// <summary>Detects assembly references which will break in SMAPI 4.0.0.</summary> + internal class LegacyAssemblyFinder : BaseInstructionHandler + { + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + public LegacyAssemblyFinder() + : base(defaultPhrase: "legacy assembly references") { } + + + /// <inheritdoc /> + public override bool Handle(ModuleDefinition module) + { + foreach (AssemblyNameReference assembly in module.AssemblyReferences) + { + InstructionHandleResult flag = this.GetFlag(assembly); + if (flag is InstructionHandleResult.None) + continue; + + this.MarkFlag(flag); + } + + return false; + } + + + /********* + ** Private methods + *********/ + /// <summary>Get the instruction handle flag for the given assembly reference, if any.</summary> + /// <param name="assemblyRef">The assembly reference.</param> + private InstructionHandleResult GetFlag(AssemblyNameReference assemblyRef) + { + return assemblyRef.Name switch + { + "System.Configuration.ConfigurationManager" => InstructionHandleResult.DetectedLegacyConfigurationDll, + "System.Runtime.Caching" => InstructionHandleResult.DetectedLegacyCachingDll, + "System.Security.Permission" => InstructionHandleResult.DetectedLegacyPermissionsDll, + _ => InstructionHandleResult.None + }; + } + } +} diff --git a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs index e3f108cb..476c30d0 100644 --- a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs +++ b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs @@ -30,6 +30,15 @@ namespace StardewModdingAPI.Framework.ModLoading DetectedFilesystemAccess, /// <summary>The instruction accesses the OS shell or processes directly.</summary> - DetectedShellAccess + DetectedShellAccess, + + /// <summary>The module references the legacy <c>System.Configuration.ConfigurationManager</c> assembly and doesn't include a copy in the mod folder, so it'll break in SMAPI 4.0.0.</summary> + DetectedLegacyConfigurationDll, + + /// <summary>The module references the legacy <c>System.Runtime.Caching</c> assembly and doesn't include a copy in the mod folder, so it'll break in SMAPI 4.0.0.</summary> + DetectedLegacyCachingDll, + + /// <summary>The module references the legacy <c>System.Security.Permissions</c> assembly and doesn't include a copy in the mod folder, so it'll break in SMAPI 4.0.0.</summary> + DetectedLegacyPermissionsDll } } diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs index fe54634b..aa4d2d8c 100644 --- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs +++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs @@ -139,6 +139,13 @@ namespace StardewModdingAPI.Framework.ModLoading } /// <inheritdoc /> + public IModMetadata RemoveWarning(ModWarning warning) + { + this.ActualWarnings &= ~warning; + return this; + } + + /// <inheritdoc /> public IModMetadata SetMod(IMod mod, TranslationHelper translations) { if (this.ContentPack != null) diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index c453562f..731731d4 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -1679,6 +1679,31 @@ namespace StardewModdingAPI.Framework } #pragma warning restore CS0612, CS0618 + // log deprecation warnings + if (metadata.HasWarnings(ModWarning.DetectedLegacyCachingDll, ModWarning.DetectedLegacyConfigurationDll, ModWarning.DetectedLegacyPermissionsDll)) + { + string?[] referenced = + new[] + { + metadata.Warnings.HasFlag(ModWarning.DetectedLegacyConfigurationDll) ? "System.Configuration.ConfigurationManager" : null, + metadata.Warnings.HasFlag(ModWarning.DetectedLegacyCachingDll) ? "System.Runtime.Caching" : null, + metadata.Warnings.HasFlag(ModWarning.DetectedLegacyPermissionsDll) ? "System.Security.Permissions" : null + } + .Where(p => p is not null) + .ToArray(); + + foreach (string? name in referenced) + { + DeprecationManager.Warn( + metadata, + $"using {name} without bundling it", + "3.14.7", + DeprecationLevel.Notice, + logStackTrace: false + ); + } + } + // call entry method Context.HeuristicModsRunningCode.Push(metadata); try diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index 4d512546..dce0c6b1 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -53,6 +53,9 @@ namespace StardewModdingAPI.Metadata // detect Harmony & rewrite for SMAPI 3.12 (Harmony 1.x => 2.0 update) yield return new HarmonyRewriter(); + + // detect issues for SMAPI 4.0.0 + yield return new LegacyAssemblyFinder(); } else yield return new HarmonyRewriter(shouldRewrite: false); diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index 95249bfd..a0ca54cc 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -28,6 +28,9 @@ <PackageReference Include="Pintail" Version="2.1.0" /> <PackageReference Include="Platonymous.TMXTile" Version="1.5.9" /> <PackageReference Include="System.Reflection.Emit" Version="4.7.0" /> + + <!-- legacy package; remove in SMAPI 4.0.0 --> + <PackageReference Include="System.Runtime.Caching" Version="5.0.0" /> </ItemGroup> <ItemGroup> |