summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release-notes.md1
-rw-r--r--src/StardewModdingAPI.AssemblyRewriters/PlatformAssemblyMap.cs2
-rw-r--r--src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj14
-rw-r--r--src/StardewModdingAPI.AssemblyRewriters/packages.config2
-rw-r--r--src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj2
-rw-r--r--src/StardewModdingAPI/App.config2
-rw-r--r--src/StardewModdingAPI/Events/ContentEventHandler.cs8
-rw-r--r--src/StardewModdingAPI/Events/ContentEvents.cs2
-rw-r--r--src/StardewModdingAPI/Framework/InternalExtensions.cs29
-rw-r--r--src/StardewModdingAPI/Framework/Reflection/PrivateProperty.cs4
-rw-r--r--src/StardewModdingAPI/Framework/UpdateHelper.cs7
-rw-r--r--src/StardewModdingAPI/Program.cs24
-rw-r--r--src/StardewModdingAPI/StardewModdingAPI.csproj20
-rw-r--r--src/StardewModdingAPI/packages.config4
-rw-r--r--src/TrainerMod/TrainerMod.csproj4
-rw-r--r--src/TrainerMod/packages.config2
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