diff options
-rw-r--r-- | release-notes.md | 1 | ||||
-rw-r--r-- | src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs | 2 | ||||
-rw-r--r-- | src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj | 14 | ||||
-rw-r--r-- | src/StardewModdingAPI.AssemblyRewriters/packages.config | 2 | ||||
-rw-r--r-- | src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj | 2 | ||||
-rw-r--r-- | src/StardewModdingAPI/App.config | 2 | ||||
-rw-r--r-- | src/StardewModdingAPI/Events/ContentEventHandler.cs | 8 | ||||
-rw-r--r-- | src/StardewModdingAPI/Events/ContentEvents.cs | 2 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/InternalExtensions.cs | 29 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/Reflection/PrivateProperty.cs | 4 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/UpdateHelper.cs | 7 | ||||
-rw-r--r-- | src/StardewModdingAPI/Program.cs | 24 | ||||
-rw-r--r-- | src/StardewModdingAPI/StardewModdingAPI.csproj | 20 | ||||
-rw-r--r-- | src/StardewModdingAPI/packages.config | 4 | ||||
-rw-r--r-- | src/TrainerMod/TrainerMod.csproj | 4 | ||||
-rw-r--r-- | src/TrainerMod/packages.config | 2 |
16 files changed, 77 insertions, 50 deletions
diff --git a/release-notes.md b/release-notes.md index f91ef733..01d49dd7 100644 --- a/release-notes.md +++ b/release-notes.md @@ -20,6 +20,7 @@ For players: * Simplified error messages when a mod can't be loaded. * Simple nested mod folders are now recognised by SMAPI (e.g. `ModName-1.0\ModName\manifest.json`). * Improved TrainerMod command handling & feedback. +* Reduced minimum .NET Framework version to 4.0 for improved compatibility on Windows 7–8.1. * Fixed game's debug output being shown in the console for all users. * Fixed the game-outdated error not pausing before exit. * Fixed installer errors for some players when deleting files. diff --git a/src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs b/src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs index fce2b187..3ca90149 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs @@ -49,7 +49,7 @@ namespace StardewModdingAPI.AssemblyRewriters // cache assembly metadata this.Targets = targetAssemblies; this.TargetReferences = this.Targets.ToDictionary(assembly => assembly, assembly => AssemblyNameReference.Parse(assembly.FullName)); - this.TargetModules = this.Targets.ToDictionary(assembly => assembly, assembly => ModuleDefinition.ReadModule(assembly.Modules.Single().FullyQualifiedName)); + this.TargetModules = this.Targets.ToDictionary(assembly => assembly, assembly => ModuleDefinition.ReadModule(assembly.GetModules().Single().FullyQualifiedName)); } } } diff --git a/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj index a3322e67..15bb15ac 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj +++ b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj @@ -9,7 +9,7 @@ <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>StardewModdingAPI.AssemblyRewriters</RootNamespace> <AssemblyName>StardewModdingAPI.AssemblyRewriters</AssemblyName> - <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> @@ -49,16 +49,16 @@ </PropertyGroup> <ItemGroup> <Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL"> - <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll</HintPath> - <Private>True</Private> + <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net40\Mono.Cecil.dll</HintPath> </Reference> <Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL"> - <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll</HintPath> - <Private>True</Private> + <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net40\Mono.Cecil.Mdb.dll</HintPath> </Reference> <Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL"> - <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll</HintPath> - <Private>True</Private> + <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net40\Mono.Cecil.Pdb.dll</HintPath> + </Reference> + <Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL"> + <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net40\Mono.Cecil.Rocks.dll</HintPath> </Reference> <Reference Include="System" /> </ItemGroup> diff --git a/src/StardewModdingAPI.AssemblyRewriters/packages.config b/src/StardewModdingAPI.AssemblyRewriters/packages.config index 88fbc79d..70ba1aed 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/packages.config +++ b/src/StardewModdingAPI.AssemblyRewriters/packages.config @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="Mono.Cecil" version="0.9.6.4" targetFramework="net452" /> + <package id="Mono.Cecil" version="0.9.6.4" targetFramework="net40" /> </packages>
\ No newline at end of file diff --git a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj index e31a1452..366e1c6e 100644 --- a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj +++ b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj @@ -9,7 +9,7 @@ <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>StardewModdingAPI.Installer</RootNamespace> <AssemblyName>StardewModdingAPI.Installer</AssemblyName> - <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> </PropertyGroup> diff --git a/src/StardewModdingAPI/App.config b/src/StardewModdingAPI/App.config index 27cdf0f7..314845f7 100644 --- a/src/StardewModdingAPI/App.config +++ b/src/StardewModdingAPI/App.config @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <configuration> <startup> - <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> + <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> <runtime> <loadFromRemoteSources enabled="true"/> diff --git a/src/StardewModdingAPI/Events/ContentEventHandler.cs b/src/StardewModdingAPI/Events/ContentEventHandler.cs new file mode 100644 index 00000000..2a7e75d1 --- /dev/null +++ b/src/StardewModdingAPI/Events/ContentEventHandler.cs @@ -0,0 +1,8 @@ +namespace StardewModdingAPI.Events +{ + /// <summary>Represents a method that will handle a content event.</summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The event arguments.</param> + /// <remarks>This deviates from <see cref="System.EventHandler{T}"/> in allowing <c>T</c> to be an interface instead of a concrete class. While .NET Framework 4.5 allows that, the current .NET Framework 4.0 targeted by SMAPI to improve compatibility does not.</remarks> + public delegate void ContentEventHandler(object sender, IContentEventHelper e); +} diff --git a/src/StardewModdingAPI/Events/ContentEvents.cs b/src/StardewModdingAPI/Events/ContentEvents.cs index 9418673a..339e90fd 100644 --- a/src/StardewModdingAPI/Events/ContentEvents.cs +++ b/src/StardewModdingAPI/Events/ContentEvents.cs @@ -28,7 +28,7 @@ namespace StardewModdingAPI.Events public static event EventHandler<EventArgsValueChanged<string>> AfterLocaleChanged; /// <summary>Raised when an XNB file is being read into the cache. Mods can change the data here before it's cached.</summary> - internal static event EventHandler<IContentEventHelper> AfterAssetLoaded; + internal static event ContentEventHandler AfterAssetLoaded; /********* diff --git a/src/StardewModdingAPI/Framework/InternalExtensions.cs b/src/StardewModdingAPI/Framework/InternalExtensions.cs index 4ca79518..46c76656 100644 --- a/src/StardewModdingAPI/Framework/InternalExtensions.cs +++ b/src/StardewModdingAPI/Framework/InternalExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using StardewModdingAPI.Events; namespace StardewModdingAPI.Framework { @@ -59,12 +60,36 @@ namespace StardewModdingAPI.Framework /// <param name="handlers">The event handlers.</param> /// <param name="sender">The event sender.</param> /// <param name="args">The event arguments.</param> - public static void SafelyRaiseGenericEvent<TEventArgs>(this IMonitor monitor, string name, IEnumerable<Delegate> handlers, object sender, TEventArgs args) + public static void SafelyRaiseGenericEvent<TEventArgs>(this IMonitor monitor, string name, IEnumerable<Delegate> handlers, object sender, TEventArgs args) where TEventArgs : EventArgs { if (handlers == null) return; - foreach (EventHandler<TEventArgs> handler in Enumerable.Cast<EventHandler<TEventArgs>>(handlers)) + foreach (EventHandler<TEventArgs> handler in handlers.Cast<EventHandler<TEventArgs>>()) + { + try + { + handler.Invoke(sender, args); + } + catch (Exception ex) + { + monitor.Log($"A mod failed handling the {name} event:\n{ex.GetLogSummary()}", LogLevel.Error); + } + } + } + + /// <summary>Safely raise an <see cref="EventHandler{TEventArgs}"/> event, and intercept any exceptions thrown by its handlers.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="name">The event name for error messages.</param> + /// <param name="handlers">The event handlers.</param> + /// <param name="sender">The event sender.</param> + /// <param name="args">The event arguments.</param> + public static void SafelyRaiseGenericEvent(this IMonitor monitor, string name, IEnumerable<Delegate> handlers, object sender, IContentEventHelper args) + { + if (handlers == null) + return; + + foreach (ContentEventHandler handler in handlers.Cast<ContentEventHandler>()) { try { diff --git a/src/StardewModdingAPI/Framework/Reflection/PrivateProperty.cs b/src/StardewModdingAPI/Framework/Reflection/PrivateProperty.cs index 08204b7e..d89e8e44 100644 --- a/src/StardewModdingAPI/Framework/Reflection/PrivateProperty.cs +++ b/src/StardewModdingAPI/Framework/Reflection/PrivateProperty.cs @@ -60,7 +60,7 @@ namespace StardewModdingAPI.Framework.Reflection { try { - return (TValue)this.PropertyInfo.GetValue(this.Parent); + return (TValue)this.PropertyInfo.GetValue(this.Parent, null); } catch (InvalidCastException) { @@ -78,7 +78,7 @@ namespace StardewModdingAPI.Framework.Reflection { try { - this.PropertyInfo.SetValue(this.Parent, value); + this.PropertyInfo.SetValue(this.Parent, value, null); } catch (InvalidCastException) { diff --git a/src/StardewModdingAPI/Framework/UpdateHelper.cs b/src/StardewModdingAPI/Framework/UpdateHelper.cs index e01e55c8..342a08cf 100644 --- a/src/StardewModdingAPI/Framework/UpdateHelper.cs +++ b/src/StardewModdingAPI/Framework/UpdateHelper.cs @@ -1,7 +1,6 @@ using System.IO; using System.Net; using System.Reflection; -using System.Threading.Tasks; using Newtonsoft.Json; using StardewModdingAPI.Framework.Models; @@ -15,17 +14,17 @@ namespace StardewModdingAPI.Framework *********/ /// <summary>Get the latest release from a GitHub repository.</summary> /// <param name="repository">The name of the repository from which to fetch releases (like "cjsu/SMAPI").</param> - public static async Task<GitRelease> GetLatestVersionAsync(string repository) + public static GitRelease GetLatestVersion(string repository) { // build request // (avoid HttpClient for Mac compatibility) - HttpWebRequest request = WebRequest.CreateHttp($"https://api.github.com/repos/{repository}/releases/latest"); + HttpWebRequest request = (HttpWebRequest)WebRequest.Create($"https://api.github.com/repos/{repository}/releases/latest"); AssemblyName assembly = typeof(UpdateHelper).Assembly.GetName(); request.UserAgent = $"{assembly.Name}/{assembly.Version}"; request.Accept = "application/vnd.github.v3+json"; // fetch data - using (WebResponse response = await request.GetResponseAsync()) + using (WebResponse response = request.GetResponse()) using (Stream responseStream = response.GetResponseStream()) using (StreamReader reader = new StreamReader(responseStream)) { diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index db7a3df6..81e6518e 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -187,7 +187,7 @@ namespace StardewModdingAPI { try { - GitRelease release = UpdateHelper.GetLatestVersionAsync(Constants.GitHubRepository).Result; + GitRelease release = UpdateHelper.GetLatestVersion(Constants.GitHubRepository); ISemanticVersion latestVersion = new SemanticVersion(release.Tag); if (latestVersion.IsNewerThan(Constants.ApiVersion)) this.Monitor.Log($"You can update SMAPI from version {Constants.ApiVersion} to {latestVersion}", LogLevel.Alert); @@ -446,26 +446,18 @@ namespace StardewModdingAPI continue; } - // validate assembly + // initialise mod try { - if (modAssembly.DefinedTypes.Count(x => x.BaseType == typeof(Mod)) == 0) + // get mod entry type + Type modEntryType = modAssembly.GetExportedTypes().FirstOrDefault(x => x.BaseType == typeof(Mod)); + if(modEntryType == null) { - this.Monitor.Log($"{skippedPrefix} because its DLL has no 'Mod' subclass.", LogLevel.Error); + this.Monitor.Log($"{skippedPrefix} because its DLL has no {typeof(Mod).FullName} entry class.", LogLevel.Error); continue; } - } - catch (Exception ex) - { - this.Monitor.Log($"{skippedPrefix} because its DLL couldn't be loaded.\n{ex.GetLogSummary()}", LogLevel.Error); - continue; - } - - // initialise mod - try - { - // get implementation - TypeInfo modEntryType = modAssembly.DefinedTypes.First(x => x.BaseType == typeof(Mod)); + + // get mod class Mod mod = (Mod)modAssembly.CreateInstance(modEntryType.ToString()); if (mod == null) { diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index dceae74e..3a2bb756 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -9,7 +9,7 @@ <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>StardewModdingAPI</RootNamespace> <AssemblyName>StardewModdingAPI</AssemblyName> - <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <IsWebBootstrapper>false</IsWebBootstrapper> <TargetFrameworkProfile /> @@ -60,7 +60,7 @@ <OutputPath>$(SolutionDir)\..\bin\Debug\SMAPI</OutputPath> <DocumentationFile>$(SolutionDir)\..\bin\Debug\SMAPI\StardewModdingAPI.xml</DocumentationFile> <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow> - <LangVersion>6</LangVersion> + <LangVersion>7</LangVersion> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"> <PlatformTarget>x86</PlatformTarget> @@ -79,19 +79,22 @@ </PropertyGroup> <ItemGroup> <Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL"> - <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll</HintPath> + <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net40\Mono.Cecil.dll</HintPath> <Private>True</Private> </Reference> <Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL"> - <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll</HintPath> + <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net40\Mono.Cecil.Mdb.dll</HintPath> <Private>True</Private> </Reference> <Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL"> - <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll</HintPath> + <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net40\Mono.Cecil.Pdb.dll</HintPath> <Private>True</Private> </Reference> + <Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL"> + <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net40\Mono.Cecil.Rocks.dll</HintPath> + </Reference> <Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> - <HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath> + <HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net40\Newtonsoft.Json.dll</HintPath> <Private>True</Private> </Reference> <Reference Include="System" /> @@ -116,6 +119,7 @@ <Link>Properties\GlobalAssemblyInfo.cs</Link> </Compile> <Compile Include="Command.cs" /> + <Compile Include="Events\ContentEventHandler.cs" /> <Compile Include="Events\ContentEvents.cs" /> <Compile Include="Events\EventArgsValueChanged.cs" /> <Compile Include="Framework\Command.cs" /> @@ -215,12 +219,10 @@ <None Include="App.config"> <SubType>Designer</SubType> </None> - <None Include="packages.config"> - <SubType>Designer</SubType> - </None> <Content Include="StardewModdingAPI.config.json"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> + <None Include="packages.config" /> <None Include="unix-launcher.sh"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> diff --git a/src/StardewModdingAPI/packages.config b/src/StardewModdingAPI/packages.config index e5fa3c3a..1dee2c2a 100644 --- a/src/StardewModdingAPI/packages.config +++ b/src/StardewModdingAPI/packages.config @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" /> - <package id="Newtonsoft.Json" version="8.0.3" targetFramework="net461" /> + <package id="Mono.Cecil" version="0.9.6.4" targetFramework="net40" /> + <package id="Newtonsoft.Json" version="8.0.3" targetFramework="net40" /> </packages>
\ No newline at end of file diff --git a/src/TrainerMod/TrainerMod.csproj b/src/TrainerMod/TrainerMod.csproj index a6303767..7845bd8c 100644 --- a/src/TrainerMod/TrainerMod.csproj +++ b/src/TrainerMod/TrainerMod.csproj @@ -9,7 +9,7 @@ <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>TrainerMod</RootNamespace> <AssemblyName>TrainerMod</AssemblyName> - <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> @@ -39,7 +39,7 @@ </PropertyGroup> <ItemGroup> <Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> - <HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath> + <HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net40\Newtonsoft.Json.dll</HintPath> <Private>True</Private> </Reference> <Reference Include="System" /> diff --git a/src/TrainerMod/packages.config b/src/TrainerMod/packages.config index 75e68e71..2c6c3f12 100644 --- a/src/TrainerMod/packages.config +++ b/src/TrainerMod/packages.config @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="Newtonsoft.Json" version="8.0.3" targetFramework="net461" /> + <package id="Newtonsoft.Json" version="8.0.3" targetFramework="net40" /> </packages>
\ No newline at end of file |