From a6071feaf84518c436fba0d148e3ea7d547663da Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 2 Nov 2017 01:34:21 -0400 Subject: fix custom asset loads failing on Linux/Mac (#383) --- src/SMAPI/Framework/ModHelpers/ContentHelper.cs | 22 +---------- src/SMAPI/Framework/SContentManager.cs | 52 ++++++++++++------------- 2 files changed, 28 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs index be9594ee..7665eb78 100644 --- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs @@ -26,9 +26,6 @@ namespace StardewModdingAPI.Framework.ModHelpers /// The absolute path to the mod folder. private readonly string ModFolderPath; - /// The path to the mod's folder, relative to the game's content folder (e.g. "../Mods/ModName"). - private readonly string ModFolderPathFromContent; - /// The friendly mod name for use in errors. private readonly string ModName; @@ -73,7 +70,6 @@ namespace StardewModdingAPI.Framework.ModHelpers this.ContentManager = contentManager; this.ModFolderPath = modFolderPath; this.ModName = modName; - this.ModFolderPathFromContent = this.ContentManager.GetRelativePath(modFolderPath); this.Monitor = monitor; } @@ -102,7 +98,7 @@ namespace StardewModdingAPI.Framework.ModHelpers throw GetContentError($"there's no matching file at path '{file.FullName}'."); // get asset path - string assetName = this.GetModAssetPath(key, file.FullName); + string assetName = this.ContentManager.GetAssetNameFromFilePath(file.FullName); // try cache if (this.ContentManager.IsLoaded(assetName)) @@ -151,7 +147,7 @@ namespace StardewModdingAPI.Framework.ModHelpers case ContentSource.ModFolder: FileInfo file = this.GetModFile(key); - return this.ContentManager.NormaliseAssetName(this.GetModAssetPath(key, file.FullName)); + return this.ContentManager.NormaliseAssetName(this.ContentManager.GetAssetNameFromFilePath(file.FullName)); default: throw new NotSupportedException($"Unknown content source '{source}'."); @@ -356,19 +352,5 @@ namespace StardewModdingAPI.Framework.ModHelpers // get file return new FileInfo(path); } - - /// Get the asset path which loads a mod folder through a content manager. - /// The file path relative to the mod's folder. - /// The absolute file path. - private string GetModAssetPath(string localPath, string absolutePath) - { -#if SMAPI_FOR_WINDOWS - // XNA doesn't allow absolute asset paths, so get a path relative to the content folder - return Path.Combine(this.ModFolderPathFromContent, localPath); -#else - // MonoGame is weird about relative paths on Mac, but allows absolute paths - return absolutePath; -#endif - } } } diff --git a/src/SMAPI/Framework/SContentManager.cs b/src/SMAPI/Framework/SContentManager.cs index a755a6df..524b2d17 100644 --- a/src/SMAPI/Framework/SContentManager.cs +++ b/src/SMAPI/Framework/SContentManager.cs @@ -102,7 +102,7 @@ namespace StardewModdingAPI.Framework this.Monitor = monitor ?? throw new ArgumentNullException(nameof(monitor)); this.Cache = new ContentCache(this, reflection, SContentManager.PossiblePathSeparators, SContentManager.PreferredPathSeparator); this.GetKeyLocale = reflection.GetPrivateMethod(this, "languageCode"); - this.ModContentPrefix = this.GetRelativePath(Constants.ModPath); + this.ModContentPrefix = this.GetAssetNameFromFilePath(Constants.ModPath); // get asset data this.CoreAssets = new CoreAssets(this.NormaliseAssetName); @@ -140,19 +140,17 @@ namespace StardewModdingAPI.Framework throw new ArgumentException("The asset key or local path contains invalid characters."); } - /// Get a directory path relative to the content root. - /// The target file path. - public string GetRelativePath(string targetPath) + /// Convert an absolute file path into a appropriate asset name. + /// The absolute path to the file. + public string GetAssetNameFromFilePath(string absolutePath) { - // convert to URIs - Uri from = new Uri(this.FullRootDirectory + "/"); - Uri to = new Uri(targetPath + "/"); - if (from.Scheme != to.Scheme) - throw new InvalidOperationException($"Can't get path for '{targetPath}' relative to '{this.FullRootDirectory}'."); - - // get relative path - return Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString()) - .Replace(Path.DirectorySeparatorChar == '/' ? '\\' : '/', Path.DirectorySeparatorChar); // use correct separator for platform +#if SMAPI_FOR_WINDOWS + // XNA doesn't allow absolute asset paths, so get a path relative to the content folder + return this.GetRelativePath(absolutePath); +#else + // MonoGame is weird about relative paths on Mac, but allows absolute paths + return absolutePath; +#endif } /**** @@ -395,6 +393,21 @@ namespace StardewModdingAPI.Framework /**** ** Asset name/key handling ****/ + /// Get a directory or file path relative to the content root. + /// The target file path. + private string GetRelativePath(string targetPath) + { + // convert to URIs + Uri from = new Uri(this.FullRootDirectory + "/"); + Uri to = new Uri(targetPath + "/"); + if (from.Scheme != to.Scheme) + throw new InvalidOperationException($"Can't get path for '{targetPath}' relative to '{this.FullRootDirectory}'."); + + // get relative path + return Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString()) + .Replace(Path.DirectorySeparatorChar == '/' ? '\\' : '/', Path.DirectorySeparatorChar); // use correct separator for platform + } + /// Get the locale codes (like ja-JP) used in asset keys. /// Simplifies access to private game code. private IDictionary GetKeyLocales(Reflector reflection) @@ -551,19 +564,6 @@ namespace StardewModdingAPI.Framework return file; } - /// Get a file from the game's content folder. - /// The asset key. - private FileInfo GetContentFolderFile(string key) - { - // get file path - string path = Path.Combine(this.FullRootDirectory, key); - if (!path.EndsWith(".xnb")) - path += ".xnb"; - - // get file - return new FileInfo(path); - } - /// Load the initial asset from the registered . /// The basic asset metadata. /// Returns the loaded asset metadata, or null if no loader matched. -- cgit From c0f0e1ba8e74d5f22be9664740a4dc51aa824bf6 Mon Sep 17 00:00:00 2001 From: volchek2 Date: Fri, 3 Nov 2017 23:31:56 -0500 Subject: Allow raw and upload popups to be closed with escape key and clicking outside of them --- src/SMAPI.Web/wwwroot/Content/js/log-parser.js | 31 +++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js index 8e30ae12..7a4d2d60 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js +++ b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js @@ -37,6 +37,14 @@ smapi.logParser = function(sectionUrl, pasteID) { $("#input").val(""); $("#popup-upload").fadeIn(); }); + + var closeUploadPopUp = function () { + $("#popup-upload").fadeOut(400, function () { + $("#input").val(memory); + memory = ""; + }); + }; + $("#popup-upload").on({ 'dragover dragenter': function(e) { e.preventDefault(); @@ -58,6 +66,10 @@ smapi.logParser = function(sectionUrl, pasteID) { }, this, file, $("#input")); reader.readAsText(file); } + }, + 'click': function (e) { + if (e.target.id === "popup-upload") + closeUploadPopUp(); } }); @@ -91,15 +103,24 @@ smapi.logParser = function(sectionUrl, pasteID) { $("#uploader").fadeOut(); } }); - $("#cancel").on("click", function() { - $("#popup-upload").fadeOut(400, function() { - $("#input").val(memory); - memory = ""; - }); + + $(document).on("keydown", function (e) { + if (e.which == 27) { + closeUploadPopUp(); + $("#popup-raw").fadeOut(400); + } }); + $("#cancel").on("click", closeUploadPopUp); + $("#closeraw").on("click", function() { $("#popup-raw").fadeOut(400); }); + + $("#popup-raw").on("click", function (e) { + if (e.target.id === "popup-raw") + $("#popup-raw").fadeOut(400); + }); + if (pasteID) { getData(pasteID); } -- cgit From 99278f0be19c63a32a7d5eba94d7a0cd88dd288c Mon Sep 17 00:00:00 2001 From: volchek2 Date: Fri, 3 Nov 2017 23:32:52 -0500 Subject: Fix braces --- src/SMAPI.Web/wwwroot/Content/js/log-parser.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js index 7a4d2d60..c6073f31 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js +++ b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js @@ -117,8 +117,9 @@ smapi.logParser = function(sectionUrl, pasteID) { }); $("#popup-raw").on("click", function (e) { - if (e.target.id === "popup-raw") + if (e.target.id === "popup-raw") { $("#popup-raw").fadeOut(400); + } }); if (pasteID) { -- cgit From 31002a7e52f7360e0979d9ddf1380c55451311eb Mon Sep 17 00:00:00 2001 From: volchek2 Date: Sat, 4 Nov 2017 00:28:59 -0500 Subject: check whether the popup is open before closing it with esc --- src/SMAPI.Web/wwwroot/Content/js/log-parser.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js index c6073f31..19287c24 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js +++ b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js @@ -106,7 +106,10 @@ smapi.logParser = function(sectionUrl, pasteID) { $(document).on("keydown", function (e) { if (e.which == 27) { - closeUploadPopUp(); + if ($("#popup-upload").css("display") !== "none" && $("#popup-upload").css("opacity") == 1) { + closeUploadPopUp(); + } + $("#popup-raw").fadeOut(400); } }); -- cgit From 7dc7f010a64ef0cf057a67bbee85196ce1d695c0 Mon Sep 17 00:00:00 2001 From: YonKuma Date: Wed, 8 Nov 2017 22:51:25 -0500 Subject: Added code to suppress mouse clicks issue Pathoschild/SMAPI#384 --- src/SMAPI/Events/EventArgsInput.cs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src') diff --git a/src/SMAPI/Events/EventArgsInput.cs b/src/SMAPI/Events/EventArgsInput.cs index ff904675..0df5275b 100644 --- a/src/SMAPI/Events/EventArgsInput.cs +++ b/src/SMAPI/Events/EventArgsInput.cs @@ -127,6 +127,37 @@ namespace StardewModdingAPI.Events Game1.oldPadState = new GamePadState(thumbsticks, triggers, buttons, dpad); } + + // mouse + else if (button.TryGetStardewInput(out InputButton inputButton)) + { + if (inputButton.mouseLeft) + { + Game1.oldMouseState = new MouseState( + Game1.oldMouseState.X, + Game1.oldMouseState.Y, + Game1.oldMouseState.ScrollWheelValue, + ButtonState.Pressed, + Game1.oldMouseState.MiddleButton, + Game1.oldMouseState.RightButton, + Game1.oldMouseState.XButton1, + Game1.oldMouseState.XButton2 + ); + } + else if (inputButton.mouseRight) + { + Game1.oldMouseState = new MouseState( + Game1.oldMouseState.X, + Game1.oldMouseState.Y, + Game1.oldMouseState.ScrollWheelValue, + Game1.oldMouseState.LeftButton, + Game1.oldMouseState.MiddleButton, + ButtonState.Pressed, + Game1.oldMouseState.XButton1, + Game1.oldMouseState.XButton2 + ); + } + } } } } -- cgit From b9ba645ce0cb8fe924e0c8e880ebba3d065558ef Mon Sep 17 00:00:00 2001 From: YonKuma Date: Wed, 8 Nov 2017 22:59:51 -0500 Subject: Fixing code to match SMAPI idiom --- src/SMAPI/Events/EventArgsInput.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/SMAPI/Events/EventArgsInput.cs b/src/SMAPI/Events/EventArgsInput.cs index 0df5275b..bb06430a 100644 --- a/src/SMAPI/Events/EventArgsInput.cs +++ b/src/SMAPI/Events/EventArgsInput.cs @@ -129,7 +129,7 @@ namespace StardewModdingAPI.Events } // mouse - else if (button.TryGetStardewInput(out InputButton inputButton)) + else if (this.Button.TryGetStardewInput(out InputButton inputButton)) { if (inputButton.mouseLeft) { -- cgit From 4aa3545b58ccda79863d8d2136904f2ff0995cfb Mon Sep 17 00:00:00 2001 From: Nicholas Johnson Date: Wed, 8 Nov 2017 22:52:34 -0800 Subject: Adding a date function --- src/SMAPI/Utilities/SDate.cs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/SMAPI/Utilities/SDate.cs b/src/SMAPI/Utilities/SDate.cs index 2630731a..126673eb 100644 --- a/src/SMAPI/Utilities/SDate.cs +++ b/src/SMAPI/Utilities/SDate.cs @@ -95,6 +95,12 @@ namespace StardewModdingAPI.Utilities return $"{this.Day:00} {this.Season} Y{this.Year}"; } + /// This function will return the number of days since Year 1 Spring 0 for an arbitrary date + public static int TotalNumberOfDays(SDate date) + { + return (((date.Year - 1) * 112) + (date.GetSeasonIndex() * 28) + date.Day); + } + /**** ** IEquatable ****/ -- cgit From 0330d84e990883a5bd5f98a70570bde007713414 Mon Sep 17 00:00:00 2001 From: YonKuma Date: Fri, 10 Nov 2017 16:20:25 -0500 Subject: Simplified mouse checks SuppressButton now uses the passed button rather than the object button --- src/SMAPI/Events/EventArgsInput.cs | 55 ++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/SMAPI/Events/EventArgsInput.cs b/src/SMAPI/Events/EventArgsInput.cs index bb06430a..276bfef6 100644 --- a/src/SMAPI/Events/EventArgsInput.cs +++ b/src/SMAPI/Events/EventArgsInput.cs @@ -56,11 +56,11 @@ namespace StardewModdingAPI.Events public void SuppressButton(SButton button) { // keyboard - if (this.Button.TryGetKeyboard(out Keys key)) + if (button.TryGetKeyboard(out Keys key)) Game1.oldKBState = new KeyboardState(Game1.oldKBState.GetPressedKeys().Union(new[] { key }).ToArray()); // controller - else if (this.Button.TryGetController(out Buttons controllerButton)) + else if (button.TryGetController(out Buttons controllerButton)) { var newState = GamePad.GetState(PlayerIndex.One); var thumbsticks = Game1.oldPadState.ThumbSticks; @@ -129,34 +129,31 @@ namespace StardewModdingAPI.Events } // mouse - else if (this.Button.TryGetStardewInput(out InputButton inputButton)) + else if (button == SButton.MouseLeft) { - if (inputButton.mouseLeft) - { - Game1.oldMouseState = new MouseState( - Game1.oldMouseState.X, - Game1.oldMouseState.Y, - Game1.oldMouseState.ScrollWheelValue, - ButtonState.Pressed, - Game1.oldMouseState.MiddleButton, - Game1.oldMouseState.RightButton, - Game1.oldMouseState.XButton1, - Game1.oldMouseState.XButton2 - ); - } - else if (inputButton.mouseRight) - { - Game1.oldMouseState = new MouseState( - Game1.oldMouseState.X, - Game1.oldMouseState.Y, - Game1.oldMouseState.ScrollWheelValue, - Game1.oldMouseState.LeftButton, - Game1.oldMouseState.MiddleButton, - ButtonState.Pressed, - Game1.oldMouseState.XButton1, - Game1.oldMouseState.XButton2 - ); - } + Game1.oldMouseState = new MouseState( + Game1.oldMouseState.X, + Game1.oldMouseState.Y, + Game1.oldMouseState.ScrollWheelValue, + ButtonState.Pressed, + Game1.oldMouseState.MiddleButton, + Game1.oldMouseState.RightButton, + Game1.oldMouseState.XButton1, + Game1.oldMouseState.XButton2 + ); + } + else if (button == SButton.MouseRight) + { + Game1.oldMouseState = new MouseState( + Game1.oldMouseState.X, + Game1.oldMouseState.Y, + Game1.oldMouseState.ScrollWheelValue, + Game1.oldMouseState.LeftButton, + Game1.oldMouseState.MiddleButton, + ButtonState.Pressed, + Game1.oldMouseState.XButton1, + Game1.oldMouseState.XButton2 + ); } } } -- cgit From 3a832b99bf3f82cfe39de776b5e15db6c8ddff1a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 26 Nov 2017 14:54:32 -0500 Subject: add date.DaysSinceStart property, add unit tests, update release notes (#390) --- docs/release-notes.md | 7 +++ src/SMAPI.Tests/Utilities/SDateTests.cs | 53 ++++++++++++++++++++ src/SMAPI/Framework/Models/ManifestDependency.cs | 1 + src/SMAPI/Utilities/SDate.cs | 64 ++++++++++++++---------- 4 files changed, 98 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 1a9e4681..a74b1927 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,4 +1,11 @@ # Release notes +## 2.2 +* For players: + * Fixed mods crashing when loading a custom asset on Linux/Mac. + +* For modders: + * Added `DaysSinceStart` property to `SDate` dates. + ## 2.1 * For players: * Added a log parser at [log.smapi.io](https://log.smapi.io). diff --git a/src/SMAPI.Tests/Utilities/SDateTests.cs b/src/SMAPI.Tests/Utilities/SDateTests.cs index 86a0d3d0..b89d8857 100644 --- a/src/SMAPI.Tests/Utilities/SDateTests.cs +++ b/src/SMAPI.Tests/Utilities/SDateTests.cs @@ -81,6 +81,59 @@ namespace StardewModdingAPI.Tests.Utilities Assert.Throws(() => _ = new SDate(day, season, year), "Constructing the invalid date didn't throw the expected exception."); } + /**** + ** DayOfWeek + ****/ + [Test(Description = "Assert the day of week.")] + [TestCase("01 spring Y1", ExpectedResult = System.DayOfWeek.Monday)] + [TestCase("02 spring Y2", ExpectedResult = System.DayOfWeek.Tuesday)] + [TestCase("03 spring Y3", ExpectedResult = System.DayOfWeek.Wednesday)] + [TestCase("04 spring Y4", ExpectedResult = System.DayOfWeek.Thursday)] + [TestCase("05 spring Y5", ExpectedResult = System.DayOfWeek.Friday)] + [TestCase("06 spring Y6", ExpectedResult = System.DayOfWeek.Saturday)] + [TestCase("07 spring Y7", ExpectedResult = System.DayOfWeek.Sunday)] + [TestCase("08 summer Y8", ExpectedResult = System.DayOfWeek.Monday)] + [TestCase("09 summer Y9", ExpectedResult = System.DayOfWeek.Tuesday)] + [TestCase("10 summer Y10", ExpectedResult = System.DayOfWeek.Wednesday)] + [TestCase("11 summer Y11", ExpectedResult = System.DayOfWeek.Thursday)] + [TestCase("12 summer Y12", ExpectedResult = System.DayOfWeek.Friday)] + [TestCase("13 summer Y13", ExpectedResult = System.DayOfWeek.Saturday)] + [TestCase("14 summer Y14", ExpectedResult = System.DayOfWeek.Sunday)] + [TestCase("15 fall Y15", ExpectedResult = System.DayOfWeek.Monday)] + [TestCase("16 fall Y16", ExpectedResult = System.DayOfWeek.Tuesday)] + [TestCase("17 fall Y17", ExpectedResult = System.DayOfWeek.Wednesday)] + [TestCase("18 fall Y18", ExpectedResult = System.DayOfWeek.Thursday)] + [TestCase("19 fall Y19", ExpectedResult = System.DayOfWeek.Friday)] + [TestCase("20 fall Y20", ExpectedResult = System.DayOfWeek.Saturday)] + [TestCase("21 fall Y21", ExpectedResult = System.DayOfWeek.Sunday)] + [TestCase("22 winter Y22", ExpectedResult = System.DayOfWeek.Monday)] + [TestCase("23 winter Y23", ExpectedResult = System.DayOfWeek.Tuesday)] + [TestCase("24 winter Y24", ExpectedResult = System.DayOfWeek.Wednesday)] + [TestCase("25 winter Y25", ExpectedResult = System.DayOfWeek.Thursday)] + [TestCase("26 winter Y26", ExpectedResult = System.DayOfWeek.Friday)] + [TestCase("27 winter Y27", ExpectedResult = System.DayOfWeek.Saturday)] + [TestCase("28 winter Y28" + "", ExpectedResult = System.DayOfWeek.Sunday)] + public DayOfWeek DayOfWeek(string dateStr) + { + // act + return this.GetDate(dateStr).DayOfWeek; + } + + /**** + ** DaysSinceStart + ****/ + [Test(Description = "Assert the number of days since 01 spring Y1 (inclusive).")] + [TestCase("01 spring Y1", ExpectedResult = 1)] + [TestCase("02 spring Y1", ExpectedResult = 2)] + [TestCase("28 spring Y1", ExpectedResult = 28)] + [TestCase("01 summer Y1", ExpectedResult = 29)] + [TestCase("01 summer Y2", ExpectedResult = 141)] + public int DaysSinceStart(string dateStr) + { + // act + return this.GetDate(dateStr).DaysSinceStart; + } + /**** ** ToString ****/ diff --git a/src/SMAPI/Framework/Models/ManifestDependency.cs b/src/SMAPI/Framework/Models/ManifestDependency.cs index 5646b335..97f0775a 100644 --- a/src/SMAPI/Framework/Models/ManifestDependency.cs +++ b/src/SMAPI/Framework/Models/ManifestDependency.cs @@ -15,6 +15,7 @@ namespace StardewModdingAPI.Framework.Models /// Whether the dependency must be installed to use the mod. public bool IsRequired { get; set; } + /********* ** Public methods *********/ diff --git a/src/SMAPI/Utilities/SDate.cs b/src/SMAPI/Utilities/SDate.cs index 126673eb..e589e9a4 100644 --- a/src/SMAPI/Utilities/SDate.cs +++ b/src/SMAPI/Utilities/SDate.cs @@ -35,6 +35,9 @@ namespace StardewModdingAPI.Utilities /// The day of week. public DayOfWeek DayOfWeek { get; } + /// The number of days since the game began (starting at 1 for the first day of spring in Y1). + public int DaysSinceStart { get; } + /********* ** Public methods @@ -67,7 +70,7 @@ namespace StardewModdingAPI.Utilities public SDate AddDays(int offset) { // get new hash code - int hashCode = this.GetHashCode() + offset; + int hashCode = this.DaysSinceStart + offset; if (hashCode < 1) throw new ArithmeticException($"Adding {offset} days to {this} would result in a date before 01 spring Y1."); @@ -95,12 +98,6 @@ namespace StardewModdingAPI.Utilities return $"{this.Day:00} {this.Season} Y{this.Year}"; } - /// This function will return the number of days since Year 1 Spring 0 for an arbitrary date - public static int TotalNumberOfDays(SDate date) - { - return (((date.Year - 1) * 112) + (date.GetSeasonIndex() * 28) + date.Day); - } - /**** ** IEquatable ****/ @@ -121,12 +118,7 @@ namespace StardewModdingAPI.Utilities /// Get a hash code which uniquely identifies a date. public override int GetHashCode() { - // return the number of days since 01 spring Y1 (inclusively) - int yearIndex = this.Year - 1; - return - yearIndex * this.DaysInSeason * this.SeasonsInYear - + this.GetSeasonIndex() * this.DaysInSeason - + this.Day; + return this.DaysSinceStart; } /**** @@ -138,7 +130,7 @@ namespace StardewModdingAPI.Utilities /// The equality of the dates public static bool operator ==(SDate date, SDate other) { - return date?.GetHashCode() == other?.GetHashCode(); + return date?.DaysSinceStart == other?.DaysSinceStart; } /// Get whether one date is not equal to another. @@ -146,7 +138,7 @@ namespace StardewModdingAPI.Utilities /// The other date to compare. public static bool operator !=(SDate date, SDate other) { - return date?.GetHashCode() != other?.GetHashCode(); + return date?.DaysSinceStart != other?.DaysSinceStart; } /// Get whether one date is more than another. @@ -154,7 +146,7 @@ namespace StardewModdingAPI.Utilities /// The other date to compare. public static bool operator >(SDate date, SDate other) { - return date?.GetHashCode() > other?.GetHashCode(); + return date?.DaysSinceStart > other?.DaysSinceStart; } /// Get whether one date is more than or equal to another. @@ -162,7 +154,7 @@ namespace StardewModdingAPI.Utilities /// The other date to compare. public static bool operator >=(SDate date, SDate other) { - return date?.GetHashCode() >= other?.GetHashCode(); + return date?.DaysSinceStart >= other?.DaysSinceStart; } /// Get whether one date is less than or equal to another. @@ -170,7 +162,7 @@ namespace StardewModdingAPI.Utilities /// The other date to compare. public static bool operator <=(SDate date, SDate other) { - return date?.GetHashCode() <= other?.GetHashCode(); + return date?.DaysSinceStart <= other?.DaysSinceStart; } /// Get whether one date is less than another. @@ -178,7 +170,7 @@ namespace StardewModdingAPI.Utilities /// The other date to compare. public static bool operator <(SDate date, SDate other) { - return date?.GetHashCode() < other?.GetHashCode(); + return date?.DaysSinceStart < other?.DaysSinceStart; } @@ -209,7 +201,9 @@ namespace StardewModdingAPI.Utilities this.Day = day; this.Season = season; this.Year = year; - this.DayOfWeek = this.GetDayOfWeek(); + this.DayOfWeek = this.GetDayOfWeek(day); + this.DaysSinceStart = this.GetDaysSinceStart(day, season, year); + } /// Get whether a date represents 0 spring Y1, which is the date during the in-game intro. @@ -221,10 +215,11 @@ namespace StardewModdingAPI.Utilities return day == 0 && season == "spring" && year == 1; } - /// Get the day of week for the current date. - private DayOfWeek GetDayOfWeek() + /// Get the day of week for a given date. + /// The day of month. + private DayOfWeek GetDayOfWeek(int day) { - switch (this.Day % 7) + switch (day % 7) { case 0: return DayOfWeek.Sunday; @@ -245,13 +240,28 @@ namespace StardewModdingAPI.Utilities } } - /// Get the current season index. + /// Get the number of days since the game began (starting at 1 for the first day of spring in Y1). + /// The day of month. + /// The season name. + /// The year. + private int GetDaysSinceStart(int day, string season, int year) + { + // return the number of days since 01 spring Y1 (inclusively) + int yearIndex = year - 1; + return + yearIndex * this.DaysInSeason * this.SeasonsInYear + + this.GetSeasonIndex(season) * this.DaysInSeason + + day; + } + + /// Get a season index. + /// The season name. /// The current season wasn't recognised. - private int GetSeasonIndex() + private int GetSeasonIndex(string season) { - int index = Array.IndexOf(this.Seasons, this.Season); + int index = Array.IndexOf(this.Seasons, season); if (index == -1) - throw new InvalidOperationException($"The current season '{this.Season}' wasn't recognised."); + throw new InvalidOperationException($"The season '{season}' wasn't recognised."); return index; } } -- cgit From ca13b2834c3d34be94c4d46a59cba945e62cce33 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 26 Nov 2017 15:39:41 -0500 Subject: fix e.SuppressButton() not working with some mouse buttons, update release notes (#389) --- docs/release-notes.md | 2 ++ src/SMAPI/Events/EventArgsInput.cs | 31 +++++++++---------------------- 2 files changed, 11 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index a74b1927..433050fb 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,6 +5,8 @@ * For modders: * Added `DaysSinceStart` property to `SDate` dates. + * Fixed input `e.SuppressButton(button)` method ignoring input. + * Fixed input `e.SuppressButton()` method not working with mouse buttons. ## 2.1 * For players: diff --git a/src/SMAPI/Events/EventArgsInput.cs b/src/SMAPI/Events/EventArgsInput.cs index 276bfef6..54ce9b53 100644 --- a/src/SMAPI/Events/EventArgsInput.cs +++ b/src/SMAPI/Events/EventArgsInput.cs @@ -129,30 +129,17 @@ namespace StardewModdingAPI.Events } // mouse - else if (button == SButton.MouseLeft) + else if (button == SButton.MouseLeft || button == SButton.MouseMiddle || button == SButton.MouseRight || button == SButton.MouseX1 || button == SButton.MouseX2) { Game1.oldMouseState = new MouseState( - Game1.oldMouseState.X, - Game1.oldMouseState.Y, - Game1.oldMouseState.ScrollWheelValue, - ButtonState.Pressed, - Game1.oldMouseState.MiddleButton, - Game1.oldMouseState.RightButton, - Game1.oldMouseState.XButton1, - Game1.oldMouseState.XButton2 - ); - } - else if (button == SButton.MouseRight) - { - Game1.oldMouseState = new MouseState( - Game1.oldMouseState.X, - Game1.oldMouseState.Y, - Game1.oldMouseState.ScrollWheelValue, - Game1.oldMouseState.LeftButton, - Game1.oldMouseState.MiddleButton, - ButtonState.Pressed, - Game1.oldMouseState.XButton1, - Game1.oldMouseState.XButton2 + x: Game1.oldMouseState.X, + y: Game1.oldMouseState.Y, + scrollWheel: Game1.oldMouseState.ScrollWheelValue, + leftButton: button == SButton.MouseLeft ? ButtonState.Pressed : Game1.oldMouseState.LeftButton, + middleButton: button == SButton.MouseMiddle ? ButtonState.Pressed : Game1.oldMouseState.MiddleButton, + rightButton: button == SButton.MouseRight ? ButtonState.Pressed : Game1.oldMouseState.RightButton, + xButton1: button == SButton.MouseX1 ? ButtonState.Pressed : Game1.oldMouseState.XButton1, + xButton2: button == SButton.MouseX2 ? ButtonState.Pressed : Game1.oldMouseState.XButton2 ); } } -- cgit From 1aa4098a510ce0f82e7ea7abc24e31e4f5f27225 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 26 Nov 2017 16:27:36 -0500 Subject: fix CFAutomate compatibility errors showing no URL (#393) --- docs/release-notes.md | 1 + src/SMAPI/StardewModdingAPI.config.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 4c5f49d6..da6c046d 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## 2.2 * For players: * Fixed mods crashing when loading a custom asset on Linux/Mac. + * Updated compatibility list. * For modders: * Added `DaysSinceStart` property to `SDate` dates. diff --git a/src/SMAPI/StardewModdingAPI.config.json b/src/SMAPI/StardewModdingAPI.config.json index fa3bdcc9..6718806e 100644 --- a/src/SMAPI/StardewModdingAPI.config.json +++ b/src/SMAPI/StardewModdingAPI.config.json @@ -509,7 +509,8 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": "Platonymous.CFAutomate", "Compatibility": { "~1.0.1": { "Status": "AssumeBroken" } // no longer compatible with Automate - } + }, + "AlternativeUrl": "https://www.nexusmods.com/stardewvalley/mods/991" }, { // Custom Farm Types -- cgit From fc9043c1ba80bc7d593ca9f00659b866d99e2251 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 26 Nov 2017 16:58:41 -0500 Subject: fix rare installer error on Mac due to generated mcs file (#394) --- docs/release-notes.md | 1 + src/SMAPI.Installer/InteractiveInstaller.cs | 23 +++++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index da6c046d..d2014b51 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## 2.2 * For players: * Fixed mods crashing when loading a custom asset on Linux/Mac. + * Fixed rare installer errors on Mac due to generated `mcs` file. * Updated compatibility list. * For modders: diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs index b5c2735b..83f353ae 100644 --- a/src/SMAPI.Installer/InteractiveInstaller.cs +++ b/src/SMAPI.Installer/InteractiveInstaller.cs @@ -296,7 +296,7 @@ namespace StardewModdingApi.Installer { // copy SMAPI files to game dir this.PrintDebug("Adding SMAPI files..."); - foreach (FileInfo sourceFile in packageDir.EnumerateFiles()) + foreach (FileInfo sourceFile in packageDir.EnumerateFiles().Where(this.ShouldCopyFile)) { string targetPath = Path.Combine(installDir.FullName, sourceFile.Name); this.InteractivelyDelete(targetPath); @@ -338,7 +338,7 @@ namespace StardewModdingApi.Installer targetDir.Create(); // copy files - foreach (FileInfo sourceFile in sourceDir.EnumerateFiles()) + foreach (FileInfo sourceFile in sourceDir.EnumerateFiles().Where(this.ShouldCopyFile)) sourceFile.CopyTo(Path.Combine(targetDir.FullName, sourceFile.Name)); } } @@ -684,7 +684,7 @@ namespace StardewModdingApi.Installer this.PrintDebug(" Support for mods here was dropped in SMAPI 1.0 (it was never officially supported)."); // move mods if no conflicts (else warn) - foreach (FileSystemInfo entry in modDir.EnumerateFileSystemInfos()) + foreach (FileSystemInfo entry in modDir.EnumerateFileSystemInfos().Where(this.ShouldCopyFile)) { // get type bool isDir = entry is DirectoryInfo; @@ -718,7 +718,7 @@ namespace StardewModdingApi.Installer else { this.PrintDebug(" Deleted empty directory."); - modDir.Delete(); + modDir.Delete(recursive: true); } } @@ -741,11 +741,22 @@ namespace StardewModdingApi.Installer Directory.CreateDirectory(newPath); DirectoryInfo directory = (DirectoryInfo)entry; - foreach (FileSystemInfo child in directory.EnumerateFileSystemInfos()) + foreach (FileSystemInfo child in directory.EnumerateFileSystemInfos().Where(this.ShouldCopyFile)) this.Move(child, Path.Combine(newPath, child.Name)); - directory.Delete(); + directory.Delete(recursive: true); } } + + /// Get whether a file should be copied when moving a folder. + /// The file info. + private bool ShouldCopyFile(FileSystemInfo file) + { + // ignore Mac symlink + if (file is FileInfo && file.Name == "mcs") + return false; + + return true; + } } } -- cgit From f44df025cab4c2b70bf07c6d8407c8cc465b57cb Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 26 Nov 2017 17:02:54 -0500 Subject: no longer expire saved logs after a week (#400) --- docs/release-notes.md | 1 + src/SMAPI.Web/Framework/LogParser/PastebinClient.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index d2014b51..b60dad9d 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -11,6 +11,7 @@ * Fixed input `e.SuppressButton()` method not working with mouse buttons. * For log.smapi.io: + * Saved logs no longer expire after a week. * The upload-log modal can now be closed by pressing `ESC` or clicking outside it. ## 2.1 diff --git a/src/SMAPI.Web/Framework/LogParser/PastebinClient.cs b/src/SMAPI.Web/Framework/LogParser/PastebinClient.cs index 738330d3..60441234 100644 --- a/src/SMAPI.Web/Framework/LogParser/PastebinClient.cs +++ b/src/SMAPI.Web/Framework/LogParser/PastebinClient.cs @@ -85,7 +85,7 @@ namespace StardewModdingAPI.Web.Framework.LogParser ["api_dev_key"] = this.DevKey, ["api_paste_private"] = "1", // unlisted ["api_paste_name"] = $"SMAPI log {DateTime.UtcNow:s}", - ["api_paste_expire_date"] = "1W", // one week + ["api_paste_expire_date"] = "N", // never expire ["api_paste_code"] = content })) .AsString(); -- cgit From 698c2702116507ec4b2409f5a9776518539f941e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 26 Nov 2017 18:31:04 -0500 Subject: tweak log parser startup --- src/SMAPI.Web/Program.cs | 8 +++----- src/SMAPI.Web/Startup.cs | 6 +++++- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/SMAPI.Web/Program.cs b/src/SMAPI.Web/Program.cs index eeecb791..5856fc98 100644 --- a/src/SMAPI.Web/Program.cs +++ b/src/SMAPI.Web/Program.cs @@ -1,4 +1,4 @@ -using System.IO; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; namespace StardewModdingAPI.Web @@ -14,10 +14,8 @@ namespace StardewModdingAPI.Web public static void Main(string[] args) { // configure web server - new WebHostBuilder() - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() + WebHost + .CreateDefaultBuilder(args) .UseStartup() .Build() .Run(); diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs index 0ea9f7ee..799fb0f8 100644 --- a/src/SMAPI.Web/Startup.cs +++ b/src/SMAPI.Web/Startup.cs @@ -33,7 +33,7 @@ namespace StardewModdingAPI.Web .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - .Add(new BeanstalkEnvPropsConfigProvider()) //.AddEnvironmentVariables() + .Add(new BeanstalkEnvPropsConfigProvider()) .Build(); } @@ -63,6 +63,10 @@ namespace StardewModdingAPI.Web { loggerFactory.AddConsole(this.Configuration.GetSection("Logging")); loggerFactory.AddDebug(); + + if (env.IsDevelopment()) + app.UseDeveloperExceptionPage(); + app .UseCors(policy => policy .AllowAnyHeader() -- cgit From 49bc98fa4c2432277647c968f57e81b63c474860 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 26 Nov 2017 21:13:38 -0500 Subject: fix player_add command not handling upgrade level (#397) --- docs/release-notes.md | 1 + .../Framework/Commands/Player/AddCommand.cs | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index b60dad9d..1b06f86f 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,6 +3,7 @@ * For players: * Fixed mods crashing when loading a custom asset on Linux/Mac. * Fixed rare installer errors on Mac due to generated `mcs` file. + * Fixed `player_add` command not handling tool upgrade levels. * Updated compatibility list. * For modders: diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs index 81167747..14a519fb 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using StardewModdingAPI.Mods.ConsoleCommands.Framework.ItemData; using StardewValley; @@ -49,10 +49,14 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player return; } - // apply count & quality + // apply count match.Item.Stack = count; + + // apply quality if (match.Item is Object obj) obj.quality = quality; + else if (match.Item is Tool tool) + tool.UpgradeLevel = quality; // add to inventory Game1.player.addItemByMenuIfNecessary(match.Item); -- cgit From 5ae28b2a8caf764e0df0e3bfeca8941db5f4be87 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 27 Nov 2017 22:19:23 -0500 Subject: fix error when a mod has an invalid filename in the EntryDLL manifest field (#402) --- docs/release-notes.md | 11 +++++------ src/SMAPI/Framework/ModLoading/ModResolver.cs | 12 ++++++++++++ src/SMAPI/Program.cs | 10 +++++----- 3 files changed, 22 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 1b06f86f..f371e5d4 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,20 +1,19 @@ # Release notes ## 2.2 * For players: - * Fixed mods crashing when loading a custom asset on Linux/Mac. - * Fixed rare installer errors on Mac due to generated `mcs` file. + * Fixed error when a mod loads custom assets on Linux/Mac. + * Fixed error when a mod has an invalid `EntryDLL` manifest value format. + * Fixed rare error when Mac adds an `mcs` file to the installer package. * Fixed `player_add` command not handling tool upgrade levels. * Updated compatibility list. + * (log.smapi.io) Saved logs no longer expire after a week. + * (log.smapi.io) The upload-log modal can now be closed by pressing `ESC` or clicking outside it. * For modders: * Added `DaysSinceStart` property to `SDate` dates. * Fixed input `e.SuppressButton(button)` method ignoring input. * Fixed input `e.SuppressButton()` method not working with mouse buttons. -* For log.smapi.io: - * Saved logs no longer expire after a week. - * The upload-log modal can now be closed by pressing `ESC` or clicking outside it. - ## 2.1 * For players: * Added a log parser at [log.smapi.io](https://log.smapi.io). diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index d0ef1b08..9802d9e9 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -142,6 +142,18 @@ namespace StardewModdingAPI.Framework.ModLoading continue; } + // validate DLL value + if (string.IsNullOrWhiteSpace(mod.Manifest.EntryDll)) + { + mod.SetStatus(ModMetadataStatus.Failed, "its manifest has no EntryDLL field."); + continue; + } + if (mod.Manifest.EntryDll.Intersect(Path.GetInvalidFileNameChars()).Any()) + { + mod.SetStatus(ModMetadataStatus.Failed, $"its manifest has invalid filename '{mod.Manifest.EntryDll}' for the EntryDLL field."); + continue; + } + // validate DLL path string assemblyPath = Path.Combine(mod.DirectoryPath, mod.Manifest.EntryDll); if (!File.Exists(assemblyPath)) diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index b742467b..3ba35e43 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -653,11 +653,8 @@ namespace StardewModdingAPI { // get basic info IManifest manifest = metadata.Manifest; - string assemblyPath = metadata.Manifest?.EntryDll != null - ? Path.Combine(metadata.DirectoryPath, metadata.Manifest.EntryDll) - : null; - this.Monitor.Log(assemblyPath != null - ? $"Loading {metadata.DisplayName} from {assemblyPath.Replace(Constants.ModPath, "").TrimStart(Path.DirectorySeparatorChar)}..." + this.Monitor.Log(metadata.Manifest?.EntryDll != null + ? $"Loading {metadata.DisplayName} from {metadata.DirectoryPath.Replace(Constants.ModPath, "").TrimStart(Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{metadata.Manifest.EntryDll}..." // don't use Path.Combine here, since EntryDLL might not be valid : $"Loading {metadata.DisplayName}...", LogLevel.Trace); // validate status @@ -669,6 +666,9 @@ namespace StardewModdingAPI } // preprocess & load mod assembly + string assemblyPath = metadata.Manifest?.EntryDll != null + ? Path.Combine(metadata.DirectoryPath, metadata.Manifest.EntryDll) + : null; Assembly modAssembly; try { -- cgit From c81520e0bc3433ca7165fbea9b8eaa31eb53a694 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 28 Nov 2017 18:34:27 -0500 Subject: update for 2.2 release --- build/GlobalAssemblyInfo.cs | 4 ++-- docs/release-notes.md | 10 ++++++---- src/SMAPI/Constants.cs | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/build/GlobalAssemblyInfo.cs b/build/GlobalAssemblyInfo.cs index 9af704e0..65211aad 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.1.0.0")] -[assembly: AssemblyFileVersion("2.1.0.0")] +[assembly: AssemblyVersion("2.2.0.0")] +[assembly: AssemblyFileVersion("2.2.0.0")] diff --git a/docs/release-notes.md b/docs/release-notes.md index f371e5d4..338a0f9e 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,12 +2,12 @@ ## 2.2 * For players: * Fixed error when a mod loads custom assets on Linux/Mac. - * Fixed error when a mod has an invalid `EntryDLL` manifest value format. + * Fixed error when a mod has an invalid `EntryDLL` filename. * Fixed rare error when Mac adds an `mcs` file to the installer package. * Fixed `player_add` command not handling tool upgrade levels. * Updated compatibility list. - * (log.smapi.io) Saved logs no longer expire after a week. - * (log.smapi.io) The upload-log modal can now be closed by pressing `ESC` or clicking outside it. + * The [log parser][] no longer expires logs after a week. + * The [log parser][] now lets you close modals with `ESC` or a click outside it. * For modders: * Added `DaysSinceStart` property to `SDate` dates. @@ -16,7 +16,7 @@ ## 2.1 * For players: - * Added a log parser at [log.smapi.io](https://log.smapi.io). + * Added a [log parser][] site. * Added better Steam instructions to the SMAPI installer. * Renamed the bundled _TrainerMod_ to _ConsoleCommands_ to make its purpose clearer. * Removed the game's test messages from the console log. @@ -558,3 +558,5 @@ For SMAPI developers: * 0.3 (2016-03-01, [log](https://github.com/Pathoschild/SMAPI/compare/Alpha0.2...0.3)) * 0.2 (2016-02-29, [log](https://github.com/Pathoschild/SMAPI/compare/Alpha0.1...Alpha0.2) * 0.1 (2016-02-28) + +[log parser]: https://log.smapi.io diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index a2dbdd98..c9f9be41 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -29,7 +29,7 @@ namespace StardewModdingAPI ** Public ****/ /// SMAPI's current semantic version. - public static ISemanticVersion ApiVersion { get; } = new SemanticVersion(2, 1, 0); + public static ISemanticVersion ApiVersion { get; } = new SemanticVersion(2, 2, 0); /// The minimum supported version of Stardew Valley. public static ISemanticVersion MinimumGameVersion { get; } = new SemanticVersion("1.2.30"); -- cgit From 051b0c9bdacd86c18fe4b2a3419fe469e732c9ed Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 28 Nov 2017 18:53:08 -0500 Subject: fix API always redirecting to HTTPS when accessed via subdomain --- docs/release-notes.md | 7 ++++--- src/SMAPI.Web/Startup.cs | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 338a0f9e..833f96b4 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,7 +3,8 @@ * For players: * Fixed error when a mod loads custom assets on Linux/Mac. * Fixed error when a mod has an invalid `EntryDLL` filename. - * Fixed rare error when Mac adds an `mcs` file to the installer package. + * Fixed error when checking for updates on Linux/Mac due to API HTTPS redirect. + * Fixed error when Mac adds an `mcs` symlink to the installer package. * Fixed `player_add` command not handling tool upgrade levels. * Updated compatibility list. * The [log parser][] no longer expires logs after a week. @@ -11,8 +12,8 @@ * For modders: * Added `DaysSinceStart` property to `SDate` dates. - * Fixed input `e.SuppressButton(button)` method ignoring input. - * Fixed input `e.SuppressButton()` method not working with mouse buttons. + * Fixed input events' `e.SuppressButton(button)` method ignoring specified button. + * Fixed input events' `e.SuppressButton()` method not working with mouse buttons. ## 2.1 * For players: diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs index 799fb0f8..16952124 100644 --- a/src/SMAPI.Web/Startup.cs +++ b/src/SMAPI.Web/Startup.cs @@ -80,6 +80,7 @@ namespace StardewModdingAPI.Web shouldRewrite: req => req.Host.Host != "localhost" && !req.Path.StartsWithSegments("/api") + && !req.Host.Host.StartsWith("api.") )) // convert subdomain.smapi.io => smapi.io/subdomain for routing -- cgit From 08f4a6fa0b9166f5c70715ffe9dab6ac4daf1a02 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 30 Nov 2017 16:54:50 -0500 Subject: fix log parser error when uploading very large logs --- docs/release-notes.md | 1 + .../Framework/LogParser/PastebinClient.cs | 41 +++++++++++++++------- 2 files changed, 30 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 833f96b4..683e97b8 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -9,6 +9,7 @@ * Updated compatibility list. * The [log parser][] no longer expires logs after a week. * The [log parser][] now lets you close modals with `ESC` or a click outside it. + * Fixed [log parser][] error when uploading very large logs. * For modders: * Added `DaysSinceStart` property to `SDate` dates. diff --git a/src/SMAPI.Web/Framework/LogParser/PastebinClient.cs b/src/SMAPI.Web/Framework/LogParser/PastebinClient.cs index 60441234..1cfaed17 100644 --- a/src/SMAPI.Web/Framework/LogParser/PastebinClient.cs +++ b/src/SMAPI.Web/Framework/LogParser/PastebinClient.cs @@ -3,7 +3,9 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; +using System.Text; using System.Threading.Tasks; +using System.Web; using Pathoschild.Http.Client; namespace StardewModdingAPI.Web.Framework.LogParser @@ -67,6 +69,8 @@ namespace StardewModdingAPI.Web.Framework.LogParser } } + /// Save a paste to Pastebin. + /// The paste content. public async Task PostAsync(string content) { try @@ -77,18 +81,18 @@ namespace StardewModdingAPI.Web.Framework.LogParser // post to API string response = await this.Client - .PostAsync("api/api_post.php") - .WithBodyContent(new FormUrlEncodedContent(new Dictionary - { - ["api_option"] = "paste", - ["api_user_key"] = this.UserKey, - ["api_dev_key"] = this.DevKey, - ["api_paste_private"] = "1", // unlisted - ["api_paste_name"] = $"SMAPI log {DateTime.UtcNow:s}", - ["api_paste_expire_date"] = "N", // never expire - ["api_paste_code"] = content - })) - .AsString(); + .PostAsync("api/api_post.php") + .WithBodyContent(this.GetFormUrlEncodedContent(new Dictionary + { + ["api_option"] = "paste", + ["api_user_key"] = this.UserKey, + ["api_dev_key"] = this.DevKey, + ["api_paste_private"] = "1", // unlisted + ["api_paste_name"] = $"SMAPI log {DateTime.UtcNow:s}", + ["api_paste_expire_date"] = "N", // never expire + ["api_paste_code"] = content + })) + .AsString(); // handle Pastebin errors if (string.IsNullOrWhiteSpace(response)) @@ -113,5 +117,18 @@ namespace StardewModdingAPI.Web.Framework.LogParser { this.Client.Dispose(); } + + + /********* + ** Private methods + *********/ + /// Build an HTTP content body with form-url-encoded content. + /// The content to encode. + /// This bypasses an issue where restricts the body length to the maximum size of a URL, which isn't applicable here. + private HttpContent GetFormUrlEncodedContent(IDictionary data) + { + string body = string.Join("&", from arg in data select $"{HttpUtility.UrlEncode(arg.Key)}={HttpUtility.UrlEncode(arg.Value)}"); + return new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded"); + } } } -- cgit From 424578539408aea2685c86d0f46b87573c37363a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 1 Dec 2017 22:41:16 -0500 Subject: tweak log parser instructions to avoid confusion --- docs/release-notes.md | 2 +- src/SMAPI.Web/Views/LogParser/Index.cshtml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 683e97b8..53ec07c6 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -8,8 +8,8 @@ * Fixed `player_add` command not handling tool upgrade levels. * Updated compatibility list. * The [log parser][] no longer expires logs after a week. - * The [log parser][] now lets you close modals with `ESC` or a click outside it. * Fixed [log parser][] error when uploading very large logs. + * Slightly improved the [log parser][] UI. * For modders: * Added `DaysSinceStart` property to `SDate` dates. diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml index 49688d78..d90f1e35 100644 --- a/src/SMAPI.Web/Views/LogParser/Index.cshtml +++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml @@ -95,7 +95,7 @@

Upload log file

    -
  1. Find your SMAPI log.
  2. +
  3. Find your SMAPI log file (not the console text).
  4. Drag the file onto the textbox below (or paste the text in).
  5. Click Parse.
  6. Share the URL of the new page.
  7. -- cgit From 01131cb50e36cb6884a43a5a32ec4fff69a92085 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 1 Dec 2017 22:55:42 -0500 Subject: rm unneeded log parser debug info --- src/SMAPI.Web/wwwroot/Content/js/log-parser.js | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js index 19287c24..d5c6974a 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js +++ b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js @@ -270,11 +270,8 @@ smapi.logParser = function(sectionUrl, pasteID) { function loadData() { try { stage = "loadData.Pre"; - var start = performance.now(); parseData(); renderData(); - var end = performance.now(); - $(".always").prepend("
    Log processed in: " + (Math.round((end - start) * 100) / 100) + ' ms (View raw)

    '); $("#viewraw").on("click", function() { $("#dataraw").val($("#input").val()); $("#popup-raw").fadeIn(); -- cgit From 188cd2403df315087ac646e04ba7d10449b7f709 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 1 Dec 2017 23:36:53 -0500 Subject: rename log parser tabs ID --- src/SMAPI.Web/Views/LogParser/Index.cshtml | 2 +- src/SMAPI.Web/wwwroot/Content/css/log-parser.css | 14 +++++++------- src/SMAPI.Web/wwwroot/Content/js/log-parser.js | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml index d90f1e35..705ed961 100644 --- a/src/SMAPI.Web/Views/LogParser/Index.cshtml +++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml @@ -23,7 +23,7 @@ @if (Model.PasteID != null) {

    Parsed log

    -
      +
      • TRACE
      • DEBUG
      • INFO
      • diff --git a/src/SMAPI.Web/wwwroot/Content/css/log-parser.css b/src/SMAPI.Web/wwwroot/Content/css/log-parser.css index 975e9c2e..9affa79e 100644 --- a/src/SMAPI.Web/wwwroot/Content/css/log-parser.css +++ b/src/SMAPI.Web/wwwroot/Content/css/log-parser.css @@ -124,7 +124,7 @@ input[type="button"] { color: green; } -#tabs { +#filters { border-bottom: 0; display: block; margin: 0; @@ -132,7 +132,7 @@ input[type="button"] { background: linear-gradient(to bottom, rgba(255, 255, 255, 1) 0%, rgba(210, 235, 249, 1) 100%); } -#tabs li { +#filters li { margin: 5px 1px 0 0; height: 25px; display: inline-block; @@ -152,24 +152,24 @@ input[type="button"] { box-shadow: inset 0px 0px 1px 1px rgba(0, 0, 0, .2); } -#tabs li:hover { +#filters li:hover { background-color: #fee; } -#tabs li:first-child { +#filters li:first-child { margin-left: 5px; } -#tabs li.active { +#filters li.active { background: #cfc; border-color: #008800; } -#tabs li.active:hover { +#filters li.active:hover { background: #efe; } -#tabs li.notice { +#filters li.notice { color: #000000; background: transparent; border: 0; diff --git a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js index d5c6974a..b2bea673 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js +++ b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js @@ -27,7 +27,7 @@ smapi.logParser = function(sectionUrl, pasteID) { regexDate = /\[\d{2}:\d{2}:\d{2} TRACE SMAPI\] Log started at (.*?) UTC/g, regexPath = /\[\d{2}:\d{2}:\d{2} DEBUG SMAPI\] Mods go here: (.*?)(?:\n|$)/g; - $("#tabs li:not(.notice)").on("click", function(evt) { + $("#filters li").on("click", function(evt) { var t = $(evt.currentTarget); t.toggleClass("active"); $("#output").toggleClass(t.text().toLowerCase()); -- cgit From e2b19d8a6ba5deb5a3e04c21c8e35cc04aea16b3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 2 Dec 2017 01:05:12 -0500 Subject: rm body template so filters can be moved into the output area --- src/SMAPI.Web/Views/LogParser/Index.cshtml | 70 +++++++++++++------------- src/SMAPI.Web/wwwroot/Content/js/log-parser.js | 42 ++++++++++------ 2 files changed, 64 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml index 705ed961..a18586a9 100644 --- a/src/SMAPI.Web/Views/LogParser/Index.cshtml +++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml @@ -33,39 +33,41 @@
      • Click tabs to toggle message visibility
      } -
      - +
      +
@@ -102,8 +104,8 @@
- - + +
diff --git a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js index b2bea673..95949a8b 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js +++ b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js @@ -8,6 +8,7 @@ smapi.logParser = function(sectionUrl, pasteID) { var stage, flags = $("#modflags"), output = $("#output"), + error = $("#error"), filters = 0, memory = "", versionInfo, @@ -15,7 +16,6 @@ smapi.logParser = function(sectionUrl, pasteID) { modMap, modErrors, logInfo, - templateBody = $("#template-body").text(), templateModentry = $("#template-modentry").text(), templateCss = $("#template-css").text(), templateLogentry = $("#template-logentry").text(), @@ -30,7 +30,7 @@ smapi.logParser = function(sectionUrl, pasteID) { $("#filters li").on("click", function(evt) { var t = $(evt.currentTarget); t.toggleClass("active"); - $("#output").toggleClass(t.text().toLowerCase()); + output.toggleClass(t.text().toLowerCase()); }); $("#upload-button").on("click", function() { memory = $("#input").val() || ""; @@ -38,13 +38,13 @@ smapi.logParser = function(sectionUrl, pasteID) { $("#popup-upload").fadeIn(); }); - var closeUploadPopUp = function () { - $("#popup-upload").fadeOut(400, function () { + var closeUploadPopUp = function() { + $("#popup-upload").fadeOut(400, function() { $("#input").val(memory); memory = ""; }); }; - + $("#popup-upload").on({ 'dragover dragenter': function(e) { e.preventDefault(); @@ -67,7 +67,7 @@ smapi.logParser = function(sectionUrl, pasteID) { reader.readAsText(file); } }, - 'click': function (e) { + 'click': function(e) { if (e.target.id === "popup-upload") closeUploadPopUp(); } @@ -89,12 +89,12 @@ smapi.logParser = function(sectionUrl, pasteID) { }) .fail(function(xhr, textStatus) { $("#uploader").fadeOut(); - $("#output").html('

Parsing failed!

Parsing of the log failed, details follow.
 

Stage: Upload

Error: ' + textStatus + ': ' + xhr.responseText + "
" + $("#input").val() + "
"); + error.html('

Parsing failed!

Parsing of the log failed, details follow.
 

Stage: Upload

Error: ' + textStatus + ': ' + xhr.responseText + "
" + $("#input").val() + "
"); }) .then(function(data) { $("#uploader").fadeOut(); if (!data.success) - $("#output").html('

Parsing failed!

Parsing of the log failed, details follow.
 

Stage: Upload

Error: ' + data.error + "
" + $("#input").val() + "
"); + error.html('

Parsing failed!

Parsing of the log failed, details follow.
 

Stage: Upload

Error: ' + data.error + "
" + $("#input").val() + "
"); else location.href = (sectionUrl.replace(/\/$/, "") + "/" + data.id); }); @@ -104,7 +104,7 @@ smapi.logParser = function(sectionUrl, pasteID) { } }); - $(document).on("keydown", function (e) { + $(document).on("keydown", function(e) { if (e.which == 27) { if ($("#popup-upload").css("display") !== "none" && $("#popup-upload").css("opacity") == 1) { closeUploadPopUp(); @@ -119,7 +119,7 @@ smapi.logParser = function(sectionUrl, pasteID) { $("#popup-raw").fadeOut(400); }); - $("#popup-raw").on("click", function (e) { + $("#popup-raw").on("click", function(e) { if (e.target.id === "popup-raw") { $("#popup-raw").fadeOut(400); } @@ -201,7 +201,13 @@ smapi.logParser = function(sectionUrl, pasteID) { ]; stage = "parseData.parseInfo"; var date = dataDate ? new Date(dataDate[1] + "Z") : null; - versionInfo = [dataInfo[1], dataInfo[2], dataInfo[3], date ? date.getFullYear() + "-" + ("0" + date.getMonth().toString()).substr(-2) + "-" + ("0" + date.getDay().toString()).substr(-2) + " at " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + " " + date.toLocaleTimeString("en-us", { timeZoneName: "short" }).split(" ")[2] : "No timestamp found", dataPath[1]]; + versionInfo = { + apiVersion: dataInfo[1], + gameVersion: dataInfo[2], + platform: dataInfo[3], + logDate: date ? date.getFullYear() + "-" + ("0" + date.getMonth().toString()).substr(-2) + "-" + ("0" + date.getDay().toString()).substr(-2) + " at " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + " " + date.toLocaleTimeString("en-us", { timeZoneName: "short" }).split(" ")[2] : "No timestamp found", + modsPath: dataPath[1] + }; stage = "parseData.parseMods"; while ((match = regexMod.exec(dataMods))) { modErrors[match[1]] = 0; @@ -221,7 +227,13 @@ smapi.logParser = function(sectionUrl, pasteID) { function renderData() { stage = "renderData.pre"; - output.html(prepare(templateBody, versionInfo)); + + output.find("#api-version").text(versionInfo.apiVersion); + output.find("#game-version").text(versionInfo.gameVersion); + output.find("#platform").text(versionInfo.platform); + output.find("#log-started").text(versionInfo.logDate); + output.find("#mods-path").text(versionInfo.modsPath); + var modslist = $("#modslist"), log = $("#log"), modCache = [], y = 0; for (; y < modInfo.length; y++) { var errors = modErrors[modInfo[y][0]], @@ -258,6 +270,8 @@ smapi.logParser = function(sectionUrl, pasteID) { log.append(logCache.join("")); $("#modlink-r").on("click", removeFilter); $("#modlink-a").on("click", selectAll); + + $("#log-data").show(); } function prepare(str, arr) { @@ -279,7 +293,7 @@ smapi.logParser = function(sectionUrl, pasteID) { stage = "loadData.Post"; } catch (err) { - $("#output").html('

Parsing failed!

Parsing of the log failed, details follow.
 

Stage: ' + stage + "

" + err + '
'); + error.html('

Parsing failed!

Parsing of the log failed, details follow.
 

Stage: ' + stage + "

" + err + '
');
             $("#rawlog").text($("#input").val());
         }
     }
@@ -291,7 +305,7 @@ smapi.logParser = function(sectionUrl, pasteID) {
                 $("#input").val(data.content);
                 loadData();
             } else {
-                $("#output").html('

Fetching the log failed!

' + data.error + '

'); + error.html('

Fetching the log failed!

' + data.error + '

');
                 $("#rawlog").text($("#input").val());
             }
             $("#uploader").fadeOut();
-- 
cgit 


From 3927014d701bf7ee1a824ccaf613fb7ca2f8185d Mon Sep 17 00:00:00 2001
From: Jesse Plamondon-Willard 
Date: Sat, 2 Dec 2017 01:26:28 -0500
Subject: redesign log parser filters

---
 src/SMAPI.Web/Views/LogParser/Index.cshtml       | 77 ++++++++++++------------
 src/SMAPI.Web/wwwroot/Content/css/log-parser.css | 43 +++----------
 src/SMAPI.Web/wwwroot/Content/js/log-parser.js   |  2 +-
 3 files changed, 45 insertions(+), 77 deletions(-)

(limited to 'src')

diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml
index a18586a9..50e86ee6 100644
--- a/src/SMAPI.Web/Views/LogParser/Index.cshtml
+++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml
@@ -23,49 +23,46 @@
 @if (Model.PasteID != null)
 {
     

Parsed log

-
    -
  • TRACE
  • -
  • DEBUG
  • -
  • INFO
  • -
  • ALERT
  • -
  • WARN
  • -
  • ERROR
  • -
  • Click tabs to toggle message visibility
  • -
}
- - +