diff options
| author | Jesse Plamondon-Willard <github@jplamondonw.com> | 2017-12-26 00:31:36 -0500 |
|---|---|---|
| committer | Jesse Plamondon-Willard <github@jplamondonw.com> | 2017-12-26 00:31:36 -0500 |
| commit | 15d4b6310e3dd15c62f3faedbf1290b2db26fb59 (patch) | |
| tree | 47d49a9c69628f0df1e688361f46bc5b46b3c0fd | |
| parent | 5cc5f089b9645a60385ff293b5a7202f260bfc0f (diff) | |
| parent | f19cc3aac1a781bf2f2d20bc9577c2fe929b1e96 (diff) | |
| download | SMAPI-15d4b6310e3dd15c62f3faedbf1290b2db26fb59.tar.gz SMAPI-15d4b6310e3dd15c62f3faedbf1290b2db26fb59.tar.bz2 SMAPI-15d4b6310e3dd15c62f3faedbf1290b2db26fb59.zip | |
Merge branch 'develop' into stable
70 files changed, 1744 insertions, 681 deletions
diff --git a/build/GlobalAssemblyInfo.cs b/build/GlobalAssemblyInfo.cs index 65211aad..bcfdc124 100644 --- a/build/GlobalAssemblyInfo.cs +++ b/build/GlobalAssemblyInfo.cs @@ -2,5 +2,5 @@ using System.Reflection; using System.Runtime.InteropServices; [assembly: ComVisible(false)] -[assembly: AssemblyVersion("2.2.0.0")] -[assembly: AssemblyFileVersion("2.2.0.0")] +[assembly: AssemblyVersion("2.3.0.0")] +[assembly: AssemblyFileVersion("2.3.0.0")] diff --git a/docs/release-notes.md b/docs/release-notes.md index 4cf8efa2..165e7d4e 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,4 +1,24 @@ # Release notes +## 2.3 +* For players: + * Added a user-friendly [download page](https://smapi.io). + * Improved cryptic libgdiplus errors on Mac when Mono isn't installed. + * Fixed mod UIs hidden when menu backgrounds are enabled. + +* For modders: + * **Added mod-provided APIs** to allow simple integrations between mods, even without direct assembly references. + * Added `GameEvents.FirstUpdateTick` event (called once after all mods are initialised). + * Added `IsSuppressed` to input events so mods can optionally avoid handling keys another mod has already handled. + * Added trace message for mods with no update keys. + * Adjusted reflection API to match actual usage (e.g. renamed `GetPrivate*` to `Get*`), and deprecated previous methods. + * Fixed `GraphicsEvents.OnPostRenderEvent` not being raised in some specialised cases. + * Fixed reflection API error for properties missing a `get` and `set`. + * Fixed issue where a mod could change the cursor position reported to other mods. + * Updated compatibility list. + +* For the [log parser][]: + * Fixed broken favicon. + ## 2.2 * For players: * Fixed error when a mod loads custom assets on Linux/Mac. diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs index 83f353ae..43d31eea 100644 --- a/src/SMAPI.Installer/InteractiveInstaller.cs +++ b/src/SMAPI.Installer/InteractiveInstaller.cs @@ -97,8 +97,8 @@ namespace StardewModdingApi.Installer yield return GetInstallPath("StardewModdingAPI.pdb"); // obsolete - yield return GetInstallPath("Mods/.cache"); // 1.3-1.4 - yield return GetInstallPath("Mods/TrainerMod"); // *–2.0 (renamed to ConsoleCommands) + yield return GetInstallPath(Path.Combine("Mods", ".cache")); // 1.3-1.4 + yield return GetInstallPath(Path.Combine("Mods", "TrainerMod")); // *–2.0 (renamed to ConsoleCommands) yield return GetInstallPath("Mono.Cecil.Rocks.dll"); // 1.3–1.8 yield return GetInstallPath("StardewModdingAPI-settings.json"); // 1.0-1.4 if (modsDir.Exists) diff --git a/src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj b/src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj index f228bb25..a65ad72c 100644 --- a/src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj +++ b/src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj @@ -41,10 +41,6 @@ <Private>False</Private> </Reference> <Reference Include="System" /> - <Reference Include="System.Core" /> - <Reference Include="System.Xml.Linq" /> - <Reference Include="Microsoft.CSharp" /> - <Reference Include="System.Data" /> <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index 664dfabf..06ab1b54 100644 --- a/src/SMAPI.Mods.ConsoleCommands/manifest.json +++ b/src/SMAPI.Mods.ConsoleCommands/manifest.json @@ -3,7 +3,7 @@ "Author": "SMAPI", "Version": { "MajorVersion": 2, - "MinorVersion": 0, + "MinorVersion": 3, "PatchVersion": 0, "Build": null }, diff --git a/src/SMAPI.Web/Controllers/IndexController.cs b/src/SMAPI.Web/Controllers/IndexController.cs new file mode 100644 index 00000000..5d45118f --- /dev/null +++ b/src/SMAPI.Web/Controllers/IndexController.cs @@ -0,0 +1,93 @@ +using System; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Caching.Memory; +using StardewModdingAPI.Web.Framework.Clients.GitHub; +using StardewModdingAPI.Web.ViewModels; + +namespace StardewModdingAPI.Web.Controllers +{ + /// <summary>Provides an info/download page about SMAPI.</summary> + [Route("")] + [Route("install")] + internal class IndexController : Controller + { + /********* + ** Properties + *********/ + /// <summary>The cache in which to store release data.</summary> + private readonly IMemoryCache Cache; + + /// <summary>The GitHub API client.</summary> + private readonly IGitHubClient GitHub; + + /// <summary>The cache time for release info.</summary> + private readonly TimeSpan CacheTime = TimeSpan.FromMinutes(5); + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="cache">The cache in which to store release data.</param> + /// <param name="github">The GitHub API client.</param> + public IndexController(IMemoryCache cache, IGitHubClient github) + { + this.Cache = cache; + this.GitHub = github; + } + + /// <summary>Display the index page.</summary> + [HttpGet] + public async Task<ViewResult> Index() + { + // fetch latest SMAPI release + GitRelease release = await this.Cache.GetOrCreateAsync("latest-smapi-release", async entry => + { + entry.AbsoluteExpiration = DateTimeOffset.UtcNow.Add(this.CacheTime); + return await this.GitHub.GetLatestReleaseAsync("Pathoschild/SMAPI"); + }); + string downloadUrl = this.GetMainDownloadUrl(release); + string devDownloadUrl = this.GetDevDownloadUrl(release); + + // render view + var model = new IndexModel(release.Name, release.Body, downloadUrl, devDownloadUrl); + return this.View(model); + } + + + /********* + ** Private methods + *********/ + /// <summary>Get the main download URL for a SMAPI release.</summary> + /// <param name="release">The SMAPI release.</param> + private string GetMainDownloadUrl(GitRelease release) + { + // get main download URL + foreach (GitAsset asset in release.Assets ?? new GitAsset[0]) + { + if (Regex.IsMatch(asset.FileName, @"SMAPI-[\d\.]+-installer.zip")) + return asset.DownloadUrl; + } + + // fallback just in case + return "https://github.com/pathoschild/SMAPI/releases"; + } + + /// <summary>Get the for-developers download URL for a SMAPI release.</summary> + /// <param name="release">The SMAPI release.</param> + private string GetDevDownloadUrl(GitRelease release) + { + // get dev download URL + foreach (GitAsset asset in release.Assets ?? new GitAsset[0]) + { + if (Regex.IsMatch(asset.FileName, @"SMAPI-[\d\.]+-installer-for-developers.zip")) + return asset.DownloadUrl; + } + + // fallback just in case + return "https://github.com/pathoschild/SMAPI/releases"; + } + } +} diff --git a/src/SMAPI.Web/Controllers/LogParserController.cs b/src/SMAPI.Web/Controllers/LogParserController.cs index 454440bb..04a11a82 100644 --- a/src/SMAPI.Web/Controllers/LogParserController.cs +++ b/src/SMAPI.Web/Controllers/LogParserController.cs @@ -6,8 +6,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using StardewModdingAPI.Web.Framework; +using StardewModdingAPI.Web.Framework.Clients.Pastebin; using StardewModdingAPI.Web.Framework.ConfigModels; -using StardewModdingAPI.Web.Framework.LogParser; using StardewModdingAPI.Web.ViewModels; namespace StardewModdingAPI.Web.Controllers @@ -19,10 +19,10 @@ namespace StardewModdingAPI.Web.Controllers ** Properties *********/ /// <summary>The log parser config settings.</summary> - private readonly LogParserConfig Config; + private readonly ContextConfig Config; /// <summary>The underlying Pastebin client.</summary> - private readonly PastebinClient PastebinClient; + private readonly IPastebinClient Pastebin; /// <summary>The first bytes in a valid zip file.</summary> /// <remarks>See <a href="https://en.wikipedia.org/wiki/Zip_(file_format)#File_headers"/>.</remarks> @@ -36,14 +36,12 @@ namespace StardewModdingAPI.Web.Controllers ** Constructor ***/ /// <summary>Construct an instance.</summary> - /// <param name="configProvider">The log parser config settings.</param> - public LogParserController(IOptions<LogParserConfig> configProvider) + /// <param name="contextProvider">The context config settings.</param> + /// <param name="pastebin">The Pastebin API client.</param> + public LogParserController(IOptions<ContextConfig> contextProvider, IPastebinClient pastebin) { - // init Pastebin client - this.Config = configProvider.Value; - string version = this.GetType().Assembly.GetName().Version.ToString(3); - string userAgent = string.Format(this.Config.PastebinUserAgent, version); - this.PastebinClient = new PastebinClient(this.Config.PastebinBaseUrl, userAgent, this.Config.PastebinUserKey, this.Config.PastebinDevKey); + this.Config = contextProvider.Value; + this.Pastebin = pastebin; } /*** @@ -52,12 +50,11 @@ namespace StardewModdingAPI.Web.Controllers /// <summary>Render the log parser UI.</summary> /// <param name="id">The paste ID.</param> [HttpGet] - [Route("")] [Route("log")] [Route("log/{id}")] public ViewResult Index(string id = null) { - return this.View("Index", new LogParserModel(this.Config.SectionUrl, id)); + return this.View("Index", new LogParserModel(this.Config.LogParserUrl, id)); } /*** @@ -67,9 +64,9 @@ namespace StardewModdingAPI.Web.Controllers /// <param name="id">The Pastebin paste ID.</param> [HttpGet, Produces("application/json")] [Route("log/fetch/{id}")] - public async Task<GetPasteResponse> GetAsync(string id) + public async Task<PasteInfo> GetAsync(string id) { - GetPasteResponse response = await this.PastebinClient.GetAsync(id); + PasteInfo response = await this.Pastebin.GetAsync(id); response.Content = this.DecompressString(response.Content); return response; } @@ -78,10 +75,10 @@ namespace StardewModdingAPI.Web.Controllers /// <param name="content">The log content to save.</param> [HttpPost, Produces("application/json"), AllowLargePosts] [Route("log/save")] - public async Task<SavePasteResponse> PostAsync([FromBody] string content) + public async Task<SavePasteResult> PostAsync([FromBody] string content) { content = this.CompressString(content); - return await this.PastebinClient.PostAsync(content); + return await this.Pastebin.PostAsync(content); } diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs index a600662c..dcb4ec52 100644 --- a/src/SMAPI.Web/Controllers/ModsApiController.cs +++ b/src/SMAPI.Web/Controllers/ModsApiController.cs @@ -7,6 +7,9 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using StardewModdingAPI.Common.Models; +using StardewModdingAPI.Web.Framework.Clients.Chucklefish; +using StardewModdingAPI.Web.Framework.Clients.GitHub; +using StardewModdingAPI.Web.Framework.Clients.Nexus; using StardewModdingAPI.Web.Framework.ConfigModels; using StardewModdingAPI.Web.Framework.ModRepositories; @@ -39,39 +42,22 @@ namespace StardewModdingAPI.Web.Controllers /// <summary>Construct an instance.</summary> /// <param name="cache">The cache in which to store mod metadata.</param> /// <param name="configProvider">The config settings for mod update checks.</param> - public ModsApiController(IMemoryCache cache, IOptions<ModUpdateCheckConfig> configProvider) + /// <param name="chucklefish">The Chucklefish API client.</param> + /// <param name="github">The GitHub API client.</param> + /// <param name="nexus">The Nexus API client.</param> + public ModsApiController(IMemoryCache cache, IOptions<ModUpdateCheckConfig> configProvider, IChucklefishClient chucklefish, IGitHubClient github, INexusClient nexus) { ModUpdateCheckConfig config = configProvider.Value; this.Cache = cache; this.CacheMinutes = config.CacheMinutes; this.VersionRegex = config.SemanticVersionRegex; - - string version = this.GetType().Assembly.GetName().Version.ToString(3); this.Repositories = new IModRepository[] { - new ChucklefishRepository( - vendorKey: config.ChucklefishKey, - userAgent: string.Format(config.ChucklefishUserAgent, version), - baseUrl: config.ChucklefishBaseUrl, - modPageUrlFormat: config.ChucklefishModPageUrlFormat - ), - new GitHubRepository( - vendorKey: config.GitHubKey, - baseUrl: config.GitHubBaseUrl, - releaseUrlFormat: config.GitHubReleaseUrlFormat, - userAgent: string.Format(config.GitHubUserAgent, version), - acceptHeader: config.GitHubAcceptHeader, - username: config.GitHubUsername, - password: config.GitHubPassword - ), - new NexusRepository( - vendorKey: config.NexusKey, - userAgent: config.NexusUserAgent, - baseUrl: config.NexusBaseUrl, - modUrlFormat: config.NexusModUrlFormat - ) + new ChucklefishRepository(config.ChucklefishKey, chucklefish), + new GitHubRepository(config.GitHubKey, github), + new NexusRepository(config.NexusKey, nexus) } .ToDictionary(p => p.VendorKey, StringComparer.CurrentCultureIgnoreCase); } diff --git a/src/SMAPI.Web/Framework/Clients/Chucklefish/ChucklefishClient.cs b/src/SMAPI.Web/Framework/Clients/Chucklefish/ChucklefishClient.cs new file mode 100644 index 00000000..6772672c --- /dev/null +++ b/src/SMAPI.Web/Framework/Clients/Chucklefish/ChucklefishClient.cs @@ -0,0 +1,83 @@ +using System; +using System.Net; +using System.Threading.Tasks; +using HtmlAgilityPack; +using Pathoschild.Http.Client; + +namespace StardewModdingAPI.Web.Framework.Clients.Chucklefish +{ + /// <summary>An HTTP client for fetching mod metadata from the Chucklefish mod site.</summary> + internal class ChucklefishClient : IChucklefishClient + { + /********* + ** Properties + *********/ + /// <summary>The base URL for the Chucklefish mod site.</summary> + private readonly string BaseUrl; + + /// <summary>The URL for a mod page excluding the base URL, where {0} is the mod ID.</summary> + private readonly string ModPageUrlFormat; + + /// <summary>The underlying HTTP client.</summary> + private readonly IClient Client; + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="userAgent">The user agent for the API client.</param> + /// <param name="baseUrl">The base URL for the Chucklefish mod site.</param> + /// <param name="modPageUrlFormat">The URL for a mod page excluding the <paramref name="baseUrl"/>, where {0} is the mod ID.</param> + public ChucklefishClient(string userAgent, string baseUrl, string modPageUrlFormat) + { + this.BaseUrl = baseUrl; + this.ModPageUrlFormat = modPageUrlFormat; + this.Client = ne |
