From cecd17ec3c5a46ac37caf926a74eff03d49740a1 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 27 Mar 2020 21:03:47 -0400 Subject: update schema for Content Patcher 1.13 --- src/SMAPI.Web/wwwroot/schemas/content-patcher.json | 72 ++++++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/SMAPI.Web/wwwroot/schemas/content-patcher.json b/src/SMAPI.Web/wwwroot/schemas/content-patcher.json index e6cd4e65..f627ab95 100644 --- a/src/SMAPI.Web/wwwroot/schemas/content-patcher.json +++ b/src/SMAPI.Web/wwwroot/schemas/content-patcher.json @@ -11,9 +11,9 @@ "title": "Format version", "description": "The format version. You should always use the latest version to enable the latest features and avoid obsolete behavior.", "type": "string", - "const": "1.11.0", + "const": "1.13.0", "@errorMessages": { - "const": "Incorrect value '@value'. This should be set to the latest format version, currently '1.11.0'." + "const": "Incorrect value '@value'. This should be set to the latest format version, currently '1.13.0'." } }, "ConfigSchema": { @@ -268,6 +268,48 @@ "type": "string" } }, + "MapTiles": { + "title": "Map tiles", + "description": "The individual map tiles to add, edit, or remove.", + "type": "array", + "items": { + "type": "object", + "properties": { + "Layer": { + "description": "The map layer name to change.", + "type": "string" + }, + "Position": { + "description": "The tile coordinates to change. You can use the Debug Mode mod to see tile coordinates in-game.", + "$ref": "#/definitions/Position" + }, + "SetTilesheet": { + "title": "Set tilesheet", + "description": "Sets the tilesheet ID for the tile index.", + "type": "string" + }, + "SetIndex": { + "title": "Set tile index", + "description": "Sets the tile index in the tilesheet.", + "type": [ "string", "number" ] + }, + "SetProperties": { + "title": "Set tile properties", + "description": "The properties to set or remove. This is merged into the existing tile properties, if any. To remove a property, set its value to `null` (not \"null\" in quotes).", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Remove": { + "description": "Whether to remove the current tile and all its properties on that layer. If combined with the other fields, a new tile is created from the other fields as if the tile didn't previously exist.", + "type": "boolean" + } + }, + + "required": [ "Layer", "Position" ] + } + }, "When": { "title": "When", "description": "Only apply the patch if the given conditions match.", @@ -335,7 +377,7 @@ } }, "propertyNames": { - "enum": [ "Action", "Target", "LogName", "Enabled", "When", "FromFile", "FromArea", "ToArea", "MapProperties" ] + "enum": [ "Action", "Target", "LogName", "Enabled", "When", "FromFile", "FromArea", "ToArea", "MapProperties", "MapTiles" ] } } } @@ -361,17 +403,37 @@ "type": [ "boolean", "string" ] } }, + "Position": { + "type": "object", + "properties": { + "X": { + "title": "X position", + "description": "The X position, measured in pixels for a texture or tiles for a map. This can contain tokens.", + "type": [ "integer", "string" ], + "minimum:": 0 + }, + "Y": { + "title": "Y position", + "description": "The Y position, measured in pixels for a texture or tiles for a map. This can contain tokens.", + "type": [ "integer", "string" ], + "minimum:": 0 + } + }, + + "required": [ "X", "Y" ], + "additionalProperties": false + }, "Rectangle": { "type": "object", "properties": { "X": { - "title": "X-Coordinate", + "title": "X position", "description": "The X position of the area's top-left corner, measured in pixels for a texture or tiles for a map. This can contain tokens.", "type": [ "integer", "string" ], "minimum:": 0 }, "Y": { - "title": "Y-Coordinate", + "title": "Y position", "description": "The Y position of the area's top-left corner, measured in pixels for a texture or tiles for a map. This can contain tokens.", "type": [ "integer", "string" ], "minimum:": 0 -- cgit From 3e54ac88579ba202d9bac34ca88c1dcb25f90a64 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 29 Mar 2020 12:08:56 -0400 Subject: fix path segmenting on Linux/Mac in asset propagation --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 83e553ff..30b96c1d 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -5,6 +5,7 @@ using System.Linq; using Microsoft.Xna.Framework.Graphics; using Netcode; using StardewModdingAPI.Framework.Reflection; +using StardewModdingAPI.Toolkit.Utilities; using StardewValley; using StardewValley.BellsAndWhistles; using StardewValley.Buildings; @@ -1037,9 +1038,9 @@ namespace StardewModdingAPI.Metadata /// The path to check. private string[] GetSegments(string path) { - if (path == null) - return new string[0]; - return path.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + return path != null + ? PathUtilities.GetSegments(path) + : new string[0]; } /// Count the number of segments in a path (e.g. 'a/b' is 2). -- cgit From 6f8fb2a68b3e45763c1b71e7f420fd7f174ffc60 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 29 Mar 2020 14:40:17 -0400 Subject: fix AutoQualityPatch version in compatibility list --- src/SMAPI.Web/wwwroot/SMAPI.metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json index 3101fdf1..179ef42a 100644 --- a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json +++ b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json @@ -155,7 +155,7 @@ *********/ "Auto Quality Patch": { "ID": "SilentOak.AutoQualityPatch", - "~2.1.3-unofficial.7 | Status": "AssumeBroken" // runtime errors + "~2.1.3-unofficial.7-mizzion | Status": "AssumeBroken" // runtime errors }, "Fix Dice": { -- cgit From 96ec4de7275ae4e0ffc92ca8058c5e04b8ddd20d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 1 Apr 2020 20:09:44 -0400 Subject: fix marriage dialogue left in invalid state after dialogue propagation --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 30b96c1d..0a14086b 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -892,11 +892,13 @@ namespace StardewModdingAPI.Metadata // doesn't store the text itself. foreach (NPC villager in villagers) { + bool shouldSayMarriageDialogue = villager.shouldSayMarriageDialogue.Value; MarriageDialogueReference[] marriageDialogue = villager.currentMarriageDialogue.ToArray(); villager.resetSeasonalDialogue(); // doesn't only affect seasonal dialogue villager.resetCurrentDialogue(); + villager.shouldSayMarriageDialogue.Set(shouldSayMarriageDialogue); villager.currentMarriageDialogue.Set(marriageDialogue); } -- cgit From c9b6b04a7502215b94a00560fad905786b144bb2 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 5 Apr 2020 13:38:59 -0400 Subject: fix rare intermittent "CGI application encountered an error" errors --- src/SMAPI.Web/Program.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/SMAPI.Web/Program.cs b/src/SMAPI.Web/Program.cs index 5d13cdf3..70082160 100644 --- a/src/SMAPI.Web/Program.cs +++ b/src/SMAPI.Web/Program.cs @@ -18,6 +18,7 @@ namespace StardewModdingAPI.Web .CreateDefaultBuilder(args) .CaptureStartupErrors(true) .UseSetting("detailedErrors", "true") + .UseKestrel().UseIISIntegration() // must be used together; fixes intermittent errors on Azure: https://stackoverflow.com/a/38312175/262123 .UseStartup() .Build() .Run(); -- cgit From b363e0b6b745b869a684c72b69c713d4817257cf Mon Sep 17 00:00:00 2001 From: Kevin Daughtridge Date: Fri, 10 Apr 2020 12:41:35 -0700 Subject: set daysPlayed in world_set{day,season,year} commands --- src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetDayCommand.cs | 1 + .../Framework/Commands/World/SetSeasonCommand.cs | 1 + .../Framework/Commands/World/SetYearCommand.cs | 1 + 3 files changed, 3 insertions(+) (limited to 'src') diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetDayCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetDayCommand.cs index 8d6bd759..5fd1b8d4 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetDayCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetDayCommand.cs @@ -32,6 +32,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World // handle Game1.dayOfMonth = day; + Game1.stats.DaysPlayed = (uint)(Game1.dayOfMonth + 28 * (Utility.getSeasonNumber(Game1.currentSeason) + 4 * (Game1.year - 1))); monitor.Log($"OK, the date is now {Game1.currentSeason} {Game1.dayOfMonth}.", LogLevel.Info); } } diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs index 0615afe7..a28fa2c3 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs @@ -40,6 +40,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World // handle Game1.currentSeason = season.ToLower(); Game1.setGraphicsForSeason(); + Game1.stats.DaysPlayed = (uint)(Game1.dayOfMonth + 28 * (Utility.getSeasonNumber(Game1.currentSeason) + 4 * (Game1.year - 1))); monitor.Log($"OK, the date is now {Game1.currentSeason} {Game1.dayOfMonth}.", LogLevel.Info); } } diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetYearCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetYearCommand.cs index 66abd6dc..dceb95af 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetYearCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetYearCommand.cs @@ -32,6 +32,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World // handle Game1.year = year; + Game1.stats.DaysPlayed = (uint)(Game1.dayOfMonth + 28 * (Utility.getSeasonNumber(Game1.currentSeason) + 4 * (Game1.year - 1))); monitor.Log($"OK, the year is now {Game1.year}.", LogLevel.Info); } } -- cgit From e370b084834246b2a0a7e6443f9b8d6e11e94912 Mon Sep 17 00:00:00 2001 From: Kevin Daughtridge Date: Sat, 11 Apr 2020 13:25:12 -0700 Subject: use SDate to set DaysPlayed --- .../Framework/Commands/World/SetDayCommand.cs | 3 ++- .../Framework/Commands/World/SetSeasonCommand.cs | 3 ++- .../Framework/Commands/World/SetYearCommand.cs | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetDayCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetDayCommand.cs index 5fd1b8d4..23c266ea 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetDayCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetDayCommand.cs @@ -1,4 +1,5 @@ using System.Linq; +using StardewModdingAPI.Utilities; using StardewValley; namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World @@ -32,7 +33,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World // handle Game1.dayOfMonth = day; - Game1.stats.DaysPlayed = (uint)(Game1.dayOfMonth + 28 * (Utility.getSeasonNumber(Game1.currentSeason) + 4 * (Game1.year - 1))); + Game1.stats.DaysPlayed = (uint)SDate.Now().DaysSinceStart; monitor.Log($"OK, the date is now {Game1.currentSeason} {Game1.dayOfMonth}.", LogLevel.Info); } } diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs index a28fa2c3..676369fe 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetSeasonCommand.cs @@ -1,4 +1,5 @@ using System.Linq; +using StardewModdingAPI.Utilities; using StardewValley; namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World @@ -40,7 +41,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World // handle Game1.currentSeason = season.ToLower(); Game1.setGraphicsForSeason(); - Game1.stats.DaysPlayed = (uint)(Game1.dayOfMonth + 28 * (Utility.getSeasonNumber(Game1.currentSeason) + 4 * (Game1.year - 1))); + Game1.stats.DaysPlayed = (uint)SDate.Now().DaysSinceStart; monitor.Log($"OK, the date is now {Game1.currentSeason} {Game1.dayOfMonth}.", LogLevel.Info); } } diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetYearCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetYearCommand.cs index dceb95af..648830c1 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetYearCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetYearCommand.cs @@ -1,4 +1,5 @@ using System.Linq; +using StardewModdingAPI.Utilities; using StardewValley; namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World @@ -32,7 +33,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World // handle Game1.year = year; - Game1.stats.DaysPlayed = (uint)(Game1.dayOfMonth + 28 * (Utility.getSeasonNumber(Game1.currentSeason) + 4 * (Game1.year - 1))); + Game1.stats.DaysPlayed = (uint)SDate.Now().DaysSinceStart; monitor.Log($"OK, the year is now {Game1.year}.", LogLevel.Info); } } -- cgit From 5f73d47fb9dfe7ac2733a0a5fe57cf96639594f9 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 12 Apr 2020 12:35:34 -0400 Subject: add config option to disable console colors (#707) --- src/SMAPI.Installer/InteractiveInstaller.cs | 4 ++-- .../ConsoleWriting/ColorfulConsoleWriter.cs | 16 ++++++++++++---- src/SMAPI.Internal/ConsoleWriting/IConsoleWriter.cs | 11 +++++++++++ src/SMAPI.Internal/ConsoleWriting/MonitorColorScheme.cs | 5 ++++- src/SMAPI.Internal/SMAPI.Internal.projitems | 1 + src/SMAPI.sln | 6 ++++++ src/SMAPI/Framework/Monitor.cs | 4 ++-- src/SMAPI/SMAPI.config.json | 1 + 8 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 src/SMAPI.Internal/ConsoleWriting/IConsoleWriter.cs (limited to 'src') diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs index 2d58baf0..5b0c6e1f 100644 --- a/src/SMAPI.Installer/InteractiveInstaller.cs +++ b/src/SMAPI.Installer/InteractiveInstaller.cs @@ -88,8 +88,8 @@ namespace StardewModdingApi.Installer yield return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley", "ErrorLogs"); // remove old log files } - /// Handles writing color-coded text to the console. - private ColorfulConsoleWriter ConsoleWriter; + /// Handles writing text to the console. + private IConsoleWriter ConsoleWriter; /********* diff --git a/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs b/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs index aefda9b6..b5bd4600 100644 --- a/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs +++ b/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs @@ -4,8 +4,8 @@ using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Internal.ConsoleWriting { - /// Provides a wrapper for writing color-coded text to the console. - internal class ColorfulConsoleWriter + /// Writes color-coded text to the console. + internal class ColorfulConsoleWriter : IConsoleWriter { /********* ** Fields @@ -30,8 +30,16 @@ namespace StardewModdingAPI.Internal.ConsoleWriting /// The colors to use for text written to the SMAPI console. public ColorfulConsoleWriter(Platform platform, ColorSchemeConfig colorConfig) { - this.SupportsColor = this.TestColorSupport(); - this.Colors = this.GetConsoleColorScheme(platform, colorConfig); + if (colorConfig.UseScheme == MonitorColorScheme.None) + { + this.SupportsColor = false; + this.Colors = null; + } + else + { + this.SupportsColor = this.TestColorSupport(); + this.Colors = this.GetConsoleColorScheme(platform, colorConfig); + } } /// Write a message line to the log. diff --git a/src/SMAPI.Internal/ConsoleWriting/IConsoleWriter.cs b/src/SMAPI.Internal/ConsoleWriting/IConsoleWriter.cs new file mode 100644 index 00000000..fbcf161c --- /dev/null +++ b/src/SMAPI.Internal/ConsoleWriting/IConsoleWriter.cs @@ -0,0 +1,11 @@ +namespace StardewModdingAPI.Internal.ConsoleWriting +{ + /// Writes text to the console. + internal interface IConsoleWriter + { + /// Write a message line to the log. + /// The message to log. + /// The log level. + void WriteLine(string message, ConsoleLogLevel level); + } +} diff --git a/src/SMAPI.Internal/ConsoleWriting/MonitorColorScheme.cs b/src/SMAPI.Internal/ConsoleWriting/MonitorColorScheme.cs index bccb56d7..994ea6a5 100644 --- a/src/SMAPI.Internal/ConsoleWriting/MonitorColorScheme.cs +++ b/src/SMAPI.Internal/ConsoleWriting/MonitorColorScheme.cs @@ -10,6 +10,9 @@ namespace StardewModdingAPI.Internal.ConsoleWriting DarkBackground, /// Use darker text colors that look better on a white or light background. - LightBackground + LightBackground, + + /// Disable console color. + None } } diff --git a/src/SMAPI.Internal/SMAPI.Internal.projitems b/src/SMAPI.Internal/SMAPI.Internal.projitems index 7fcebc94..0d583a6d 100644 --- a/src/SMAPI.Internal/SMAPI.Internal.projitems +++ b/src/SMAPI.Internal/SMAPI.Internal.projitems @@ -12,6 +12,7 @@ + \ No newline at end of file diff --git a/src/SMAPI.sln b/src/SMAPI.sln index 62eaa777..f9c537c4 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -81,7 +81,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web.LegacyRedirects", EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution + SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{0a9bb24f-15ff-4c26-b1a2-81f7ae316518}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{1b3821e6-d030-402c-b3a1-7ca45c2800ea}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{80efd92f-728f-41e0-8a5b-9f6f49a91899}*SharedItemsImports = 5 SMAPI.Internal\SMAPI.Internal.projitems*{85208f8d-6fd1-4531-be05-7142490f59fe}*SharedItemsImports = 13 + SMAPI.Internal\SMAPI.Internal.projitems*{cd53ad6f-97f4-4872-a212-50c2a0fd3601}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{e6da2198-7686-4f1d-b312-4a4dc70884c0}*SharedItemsImports = 5 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/src/SMAPI/Framework/Monitor.cs b/src/SMAPI/Framework/Monitor.cs index f630c7fe..44eeabe6 100644 --- a/src/SMAPI/Framework/Monitor.cs +++ b/src/SMAPI/Framework/Monitor.cs @@ -15,8 +15,8 @@ namespace StardewModdingAPI.Framework /// The name of the module which logs messages using this instance. private readonly string Source; - /// Handles writing color-coded text to the console. - private readonly ColorfulConsoleWriter ConsoleWriter; + /// Handles writing text to the console. + private readonly IConsoleWriter ConsoleWriter; /// Manages access to the console output. private readonly ConsoleInterceptionManager ConsoleInterceptor; diff --git a/src/SMAPI/SMAPI.config.json b/src/SMAPI/SMAPI.config.json index 57b4f885..a426b0ef 100644 --- a/src/SMAPI/SMAPI.config.json +++ b/src/SMAPI/SMAPI.config.json @@ -73,6 +73,7 @@ copy all the settings, or you may cause bugs due to overridden changes in future * automatically on Linux or Windows. * - LightBackground: use darker text colors that look better on a white or light background. * - DarkBackground: use lighter text colors that look better on a black or dark background. + * - None: disables all colors, so everything is written in the default terminal color. * * For available color codes, see https://docs.microsoft.com/en-us/dotnet/api/system.consolecolor. * -- cgit From 49c2ee517d3276b4547bb25ceda3ebf5e9707887 Mon Sep 17 00:00:00 2001 From: Kevin Daughtridge Date: Mon, 13 Apr 2020 15:42:00 -0700 Subject: SDate: Add WorldDate conversions and features - SeasonIndex - FromWorldDate() - FromDaysSinceStart() - ToLocaleString() - ToWorldDate() --- src/SMAPI/Utilities/SDate.cs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'src') diff --git a/src/SMAPI/Utilities/SDate.cs b/src/SMAPI/Utilities/SDate.cs index 0ab37aa0..301ea9d2 100644 --- a/src/SMAPI/Utilities/SDate.cs +++ b/src/SMAPI/Utilities/SDate.cs @@ -29,6 +29,9 @@ namespace StardewModdingAPI.Utilities /// The season name. public string Season { get; } + /// The season index. + public int SeasonIndex { get; } + /// The year. public int Year { get; } @@ -63,6 +66,20 @@ namespace StardewModdingAPI.Utilities return new SDate(Game1.dayOfMonth, Game1.currentSeason, Game1.year, allowDayZero: true); } + /// Get the date equivalent to the given WorldDate. + /// A date returned from a core game property or method. + public static SDate FromWorldDate(WorldDate worldDate) + { + return new SDate(worldDate.DayOfMonth, worldDate.Season, worldDate.Year, allowDayZero: true); + } + + /// Get the date falling the given number of days after 0 spring Y1. + /// The number of days since 0 spring Y1. + public static SDate FromDaysSinceStart(int daysSinceStart) + { + return new SDate(0, "spring", 1, allowDayZero: true).AddDays(daysSinceStart); + } + /// Get a new date with the given number of days added. /// The number of days to add. /// Returns the resulting date. @@ -98,6 +115,18 @@ namespace StardewModdingAPI.Utilities return $"{this.Day:00} {this.Season} Y{this.Year}"; } + /// Get a string representation of the date in the current game locale. + public string ToLocaleString() + { + return this.ToWorldDate().Localize(); + } + + /// Get the date as an instance of the game's WorldDate class. This is intended for passing to core game methods. + public WorldDate ToWorldDate() + { + return new WorldDate(this.Year, this.Season, this.Day); + } + /**** ** IEquatable ****/ @@ -200,6 +229,7 @@ namespace StardewModdingAPI.Utilities // initialize this.Day = day; this.Season = season; + this.SeasonIndex = this.GetSeasonIndex(season); this.Year = year; this.DayOfWeek = this.GetDayOfWeek(day); this.DaysSinceStart = this.GetDaysSinceStart(day, season, year); -- cgit From 7a60dc4ee9d32831f55fe066c20729ca8e9dc8a1 Mon Sep 17 00:00:00 2001 From: Kevin Daughtridge Date: Mon, 13 Apr 2020 23:29:56 -0700 Subject: SDate: fixes to new methods - FromWorldDate: replace with explicit operator SDate - ToWorldDate: replace with explicit operator WorldDate - ToLocaleString: use Utility.getDateStringFor directly - FromDaysSinceStart: reinterpret exception to an appropriate one --- src/SMAPI/Utilities/SDate.cs | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/SMAPI/Utilities/SDate.cs b/src/SMAPI/Utilities/SDate.cs index 301ea9d2..8cb55891 100644 --- a/src/SMAPI/Utilities/SDate.cs +++ b/src/SMAPI/Utilities/SDate.cs @@ -66,18 +66,18 @@ namespace StardewModdingAPI.Utilities return new SDate(Game1.dayOfMonth, Game1.currentSeason, Game1.year, allowDayZero: true); } - /// Get the date equivalent to the given WorldDate. - /// A date returned from a core game property or method. - public static SDate FromWorldDate(WorldDate worldDate) - { - return new SDate(worldDate.DayOfMonth, worldDate.Season, worldDate.Year, allowDayZero: true); - } - /// Get the date falling the given number of days after 0 spring Y1. /// The number of days since 0 spring Y1. public static SDate FromDaysSinceStart(int daysSinceStart) { - return new SDate(0, "spring", 1, allowDayZero: true).AddDays(daysSinceStart); + try + { + return new SDate(0, "spring", 1, allowDayZero: true).AddDays(daysSinceStart); + } + catch (ArithmeticException) + { + throw new ArgumentException($"Invalid daysSinceStart '{daysSinceStart}', must be at least 1."); + } } /// Get a new date with the given number of days added. @@ -118,13 +118,7 @@ namespace StardewModdingAPI.Utilities /// Get a string representation of the date in the current game locale. public string ToLocaleString() { - return this.ToWorldDate().Localize(); - } - - /// Get the date as an instance of the game's WorldDate class. This is intended for passing to core game methods. - public WorldDate ToWorldDate() - { - return new WorldDate(this.Year, this.Season, this.Day); + return Utility.getDateStringFor(this.Day, this.SeasonIndex, this.Year); } /**** @@ -153,6 +147,19 @@ namespace StardewModdingAPI.Utilities /**** ** Operators ****/ + /// Get the SDate equivalent to the given WorldDate. + /// A date returned from a core game property or method. + public static explicit operator SDate(WorldDate worldDate) + { + return new SDate(worldDate.DayOfMonth, worldDate.Season, worldDate.Year, allowDayZero: true); + } + + /// Get the SDate as an instance of the game's WorldDate class. This is intended for passing to core game methods. + public static explicit operator WorldDate(SDate date) + { + return new WorldDate(date.Year, date.Season, date.Day); + } + /// Get whether one date is equal to another. /// The base date to compare. /// The other date to compare. -- cgit From 421bcfcd3e1dcd79c4ab9f9c44c300126ce01fe9 Mon Sep 17 00:00:00 2001 From: Kevin Daughtridge Date: Tue, 14 Apr 2020 00:31:47 -0700 Subject: SDateTests: cover new field and methods --- src/SMAPI.Tests/Utilities/SDateTests.cs | 102 ++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'src') diff --git a/src/SMAPI.Tests/Utilities/SDateTests.cs b/src/SMAPI.Tests/Utilities/SDateTests.cs index d25a101a..3fca9b29 100644 --- a/src/SMAPI.Tests/Utilities/SDateTests.cs +++ b/src/SMAPI.Tests/Utilities/SDateTests.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Text.RegularExpressions; using NUnit.Framework; using StardewModdingAPI.Utilities; +using StardewValley; +using LC = StardewValley.LocalizedContentManager.LanguageCode; namespace SMAPI.Tests.Utilities { @@ -81,6 +83,21 @@ namespace SMAPI.Tests.Utilities Assert.Throws(() => _ = new SDate(day, season, year), "Constructing the invalid date didn't throw the expected exception."); } + /**** + ** SeasonIndex + ****/ + [Test(Description = "Assert the numeric index of the season.")] + [TestCase("01 spring Y1", ExpectedResult = 0)] + [TestCase("02 summer Y1", ExpectedResult = 1)] + [TestCase("28 fall Y1", ExpectedResult = 2)] + [TestCase("01 winter Y1", ExpectedResult = 3)] + [TestCase("01 winter Y2", ExpectedResult = 3)] + public int SeasonIndex(string dateStr) + { + // act + return this.GetDate(dateStr).SeasonIndex; + } + /**** ** DayOfWeek ****/ @@ -147,6 +164,58 @@ namespace SMAPI.Tests.Utilities return this.GetDate(dateStr).ToString(); } + /**** + ** ToLocaleString + ****/ + // TODO: Provide an appropriate XNA/MonoGame context to run this in, or else remove the test. + // [Test(Description = "Assert that ToLocaleString returns the expected string in various locales.")] + // [TestCase("14 spring Y1", LC.en, ExpectedResult = "Day 14 of Spring, Year 1")] + // [TestCase("01 summer Y16", LC.en, ExpectedResult = "Day 1 of Summer, Year 16")] + // [TestCase("28 fall Y10", LC.en, ExpectedResult = "Day 28 of Fall, Year 10")] + // [TestCase("01 winter Y1", LC.en, ExpectedResult = "Day 1 of Winter, Year 1")] + // [TestCase("14 spring Y1", LC.es, ExpectedResult = "Día 14 de primavera, año 1")] + // [TestCase("01 summer Y16", LC.es, ExpectedResult = "Día 1 de verano, año 16")] + // [TestCase("28 fall Y10", LC.es, ExpectedResult = "Día 28 de otoño, año 10")] + // [TestCase("01 winter Y1", LC.es, ExpectedResult = "Día 1 de invierno, año 1")] + // public string ToLocaleString(string dateStr, LC langCode) + // { + // LC oldCode = LocalizedContentManager.CurrentLanguageCode; + // try + // { + // LocalizedContentManager.CurrentLanguageCode = langCode; + // return this.GetDate(dateStr).ToLocaleString(); + // } + // finally + // { + // LocalizedContentManager.CurrentLanguageCode = oldCode; + // } + // } + + /**** + ** FromDaysSinceStart + ****/ + [Test(Description = "Assert that FromDaysSinceStart returns the expected date.")] + [TestCase(1, ExpectedResult = "01 spring Y1")] + [TestCase(2, ExpectedResult = "02 spring Y1")] + [TestCase(28, ExpectedResult = "28 spring Y1")] + [TestCase(29, ExpectedResult = "01 summer Y1")] + [TestCase(141, ExpectedResult = "01 summer Y2")] + public string FromDaysSinceStart(int daysSinceStart) + { + // act + return SDate.FromDaysSinceStart(daysSinceStart).ToString(); + } + + [Test(Description = "Assert that FromDaysSinceStart throws an exception if the number of days is invalid.")] + [TestCase(-1)] // day < 0 + [TestCase(0)] // day == 0 + [SuppressMessage("ReSharper", "AssignmentIsFullyDiscarded", Justification = "Deliberate for unit test.")] + public void FromDaysSinceStart_RejectsInvalidValues(int daysSinceStart) + { + // act & assert + Assert.Throws(() => _ = SDate.FromDaysSinceStart(daysSinceStart), "Passing the invalid number of days didn't throw the expected exception."); + } + /**** ** AddDays ****/ @@ -166,6 +235,17 @@ namespace SMAPI.Tests.Utilities return this.GetDate(dateStr).AddDays(addDays).ToString(); } + [Test(Description = "Assert that AddDays throws an exception if the number of days is invalid.")] + [TestCase("01 spring Y1", -1)] + [TestCase("01 summer Y1", -29)] + [TestCase("01 spring Y2", -113)] + [SuppressMessage("ReSharper", "AssignmentIsFullyDiscarded", Justification = "Deliberate for unit test.")] + public void AddDays_RejectsInvalidValues(string dateStr, int addDays) + { + // act & assert + Assert.Throws(() => _ = this.GetDate(dateStr).AddDays(addDays), "Passing the invalid number of days didn't throw the expected exception."); + } + /**** ** GetHashCode ****/ @@ -194,6 +274,28 @@ namespace SMAPI.Tests.Utilities } } + [Test(Description = "Assert that the SDate operator for WorldDates returns the corresponding SDate.")] + [TestCase(0, ExpectedResult = "01 spring Y1")] + [TestCase(1, ExpectedResult = "02 spring Y1")] + [TestCase(27, ExpectedResult = "28 spring Y1")] + [TestCase(28, ExpectedResult = "01 summer Y1")] + [TestCase(140, ExpectedResult = "01 summer Y2")] + public string Operators_SDate_WorldDate(int totalDays) + { + return ((SDate)new WorldDate { TotalDays = totalDays }).ToString(); + } + + [Test(Description = "Assert that the WorldDate operator returns the corresponding WorldDate.")] + [TestCase("01 spring Y1", ExpectedResult = 0)] + [TestCase("02 spring Y1", ExpectedResult = 1)] + [TestCase("28 spring Y1", ExpectedResult = 27)] + [TestCase("01 summer Y1", ExpectedResult = 28)] + [TestCase("01 summer Y2", ExpectedResult = 140)] + public int Operators_WorldDate(string dateStr) + { + return ((WorldDate)this.GetDate(dateStr)).TotalDays; + } + [Test(Description = "Assert that the == operator returns the expected values. We only need a few test cases, since it's based on GetHashCode which is tested more thoroughly.")] [TestCase(Dates.Now, null, ExpectedResult = false)] [TestCase(Dates.Now, Dates.PrevDay, ExpectedResult = false)] -- cgit From 97821362daeaa3dd34e3728680760d44043825be Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 15 Apr 2020 18:06:37 -0400 Subject: prevent object.loadDisplayName errors due to invalid/missing item data --- src/SMAPI/Framework/Patching/PatchHelper.cs | 34 +++++++++++++++++++++++++ src/SMAPI/Patches/DialogueErrorPatch.cs | 9 +++---- src/SMAPI/Patches/EventErrorPatch.cs | 9 +++---- src/SMAPI/Patches/ObjectErrorPatch.cs | 39 +++++++++++++++++++++++++++++ src/SMAPI/Patches/ScheduleErrorPatch.cs | 9 +++---- 5 files changed, 82 insertions(+), 18 deletions(-) create mode 100644 src/SMAPI/Framework/Patching/PatchHelper.cs (limited to 'src') diff --git a/src/SMAPI/Framework/Patching/PatchHelper.cs b/src/SMAPI/Framework/Patching/PatchHelper.cs new file mode 100644 index 00000000..4cb436f0 --- /dev/null +++ b/src/SMAPI/Framework/Patching/PatchHelper.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; + +namespace StardewModdingAPI.Framework.Patching +{ + /// Provides generic methods for implementing Harmony patches. + internal class PatchHelper + { + /********* + ** Fields + *********/ + /// The interception keys currently being intercepted. + private static readonly HashSet InterceptingKeys = new HashSet(StringComparer.OrdinalIgnoreCase); + + + /********* + ** Public methods + *********/ + /// Track a method that will be intercepted. + /// The intercept key. + /// Returns false if the method was already marked for interception, else true. + public static bool StartIntercept(string key) + { + return PatchHelper.InterceptingKeys.Add(key); + } + + /// Track a method as no longer being intercepted. + /// The intercept key. + public static void StopIntercept(string key) + { + PatchHelper.InterceptingKeys.Remove(key); + } + } +} diff --git a/src/SMAPI/Patches/DialogueErrorPatch.cs b/src/SMAPI/Patches/DialogueErrorPatch.cs index 24f97259..1e49826d 100644 --- a/src/SMAPI/Patches/DialogueErrorPatch.cs +++ b/src/SMAPI/Patches/DialogueErrorPatch.cs @@ -24,9 +24,6 @@ namespace StardewModdingAPI.Patches /// Simplifies access to private code. private static Reflector Reflection; - /// Whether the getter is currently being intercepted. - private static bool IsInterceptingCurrentDialogue; - /********* ** Accessors @@ -112,12 +109,12 @@ namespace StardewModdingAPI.Patches /// Returns whether to execute the original method. private static bool Before_NPC_CurrentDialogue(NPC __instance, ref Stack __result, MethodInfo __originalMethod) { - if (DialogueErrorPatch.IsInterceptingCurrentDialogue) + const string key = nameof(Before_NPC_CurrentDialogue); + if (!PatchHelper.StartIntercept(key)) return true; try { - DialogueErrorPatch.IsInterceptingCurrentDialogue = true; __result = (Stack)__originalMethod.Invoke(__instance, new object[0]); return false; } @@ -129,7 +126,7 @@ namespace StardewModdingAPI.Patches } finally { - DialogueErrorPatch.IsInterceptingCurrentDialogue = false; + PatchHelper.StopIntercept(key); } } } diff --git a/src/SMAPI/Patches/EventErrorPatch.cs b/src/SMAPI/Patches/EventErrorPatch.cs index 1dc7e8c3..504d1d2e 100644 --- a/src/SMAPI/Patches/EventErrorPatch.cs +++ b/src/SMAPI/Patches/EventErrorPatch.cs @@ -18,9 +18,6 @@ namespace StardewModdingAPI.Patches /// Writes messages to the console and log file on behalf of the game. private static IMonitor MonitorForGame; - /// Whether the method is currently being intercepted. - private static bool IsIntercepted; - /********* ** Accessors @@ -61,12 +58,12 @@ namespace StardewModdingAPI.Patches /// Returns whether to execute the original method. private static bool Before_GameLocation_CheckEventPrecondition(GameLocation __instance, ref int __result, string precondition, MethodInfo __originalMethod) { - if (EventErrorPatch.IsIntercepted) + const string key = nameof(Before_GameLocation_CheckEventPrecondition); + if (!PatchHelper.StartIntercept(key)) return true; try { - EventErrorPatch.IsIntercepted = true; __result = (int)__originalMethod.Invoke(__instance, new object[] { precondition }); return false; } @@ -78,7 +75,7 @@ namespace StardewModdingAPI.Patches } finally { - EventErrorPatch.IsIntercepted = false; + PatchHelper.StopIntercept(key); } } } diff --git a/src/SMAPI/Patches/ObjectErrorPatch.cs b/src/SMAPI/Patches/ObjectErrorPatch.cs index d716b29b..d3b8800a 100644 --- a/src/SMAPI/Patches/ObjectErrorPatch.cs +++ b/src/SMAPI/Patches/ObjectErrorPatch.cs @@ -1,4 +1,6 @@ +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Reflection; using Harmony; using StardewModdingAPI.Framework.Patching; using StardewValley; @@ -33,6 +35,12 @@ namespace StardewModdingAPI.Patches prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.Before_Object_GetDescription)) ); + // object.getDisplayName + harmony.Patch( + original: AccessTools.Method(typeof(SObject), "loadDisplayName"), + prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.Before_Object_loadDisplayName)) + ); + // IClickableMenu.drawToolTip harmony.Patch( original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.drawToolTip)), @@ -60,6 +68,37 @@ namespace StardewModdingAPI.Patches return true; } + /// The method to call instead of . + /// The instance being patched. + /// The patched method's return value. + /// The method being wrapped. + /// Returns whether to execute the original method. + private static bool Before_Object_loadDisplayName(SObject __instance, ref string __result, MethodInfo __originalMethod) + { + const string key = nameof(Before_Object_loadDisplayName); + if (!PatchHelper.StartIntercept(key)) + return true; + + try + { + __result = (string)__originalMethod.Invoke(__instance, new object[0]); + return false; + } + catch (TargetInvocationException ex) when (ex.InnerException is KeyNotFoundException) + { + __result = "???"; + return false; + } + catch + { + return true; + } + finally + { + PatchHelper.StopIntercept(key); + } + } + /// The method to call instead of . /// The instance being patched. /// The item for which to draw a tooltip. diff --git a/src/SMAPI/Patches/ScheduleErrorPatch.cs b/src/SMAPI/Patches/ScheduleErrorPatch.cs index a23aa645..799fcb40 100644 --- a/src/SMAPI/Patches/ScheduleErrorPatch.cs +++ b/src/SMAPI/Patches/ScheduleErrorPatch.cs @@ -19,9 +19,6 @@ namespace StardewModdingAPI.Patches /// Writes messages to the console and log file on behalf of the game. private static IMonitor MonitorForGame; - /// Whether the target is currently being intercepted. - private static bool IsIntercepting; - /********* ** Accessors @@ -62,12 +59,12 @@ namespace StardewModdingAPI.Patches /// Returns whether to execute the original method. private static bool Before_NPC_parseMasterSchedule(string rawData, NPC __instance, ref Dictionary __result, MethodInfo __originalMethod) { - if (ScheduleErrorPatch.IsIntercepting) + const string key = nameof(Before_NPC_parseMasterSchedule); + if (!PatchHelper.StartIntercept(key)) return true; try { - ScheduleErrorPatch.IsIntercepting = true; __result = (Dictionary)__originalMethod.Invoke(__instance, new object[] { rawData }); return false; } @@ -79,7 +76,7 @@ namespace StardewModdingAPI.Patches } finally { - ScheduleErrorPatch.IsIntercepting = false; + PatchHelper.StopIntercept(key); } } } -- cgit From 3a247fa75c56f315d82ea55143e89d28d61c064c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 15 Apr 2020 19:20:53 -0400 Subject: tweak new code, update release notes --- src/SMAPI.Tests/Utilities/SDateTests.cs | 117 +++++++++++++++----------------- src/SMAPI/Utilities/SDate.cs | 36 +++++----- 2 files changed, 73 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/src/SMAPI.Tests/Utilities/SDateTests.cs b/src/SMAPI.Tests/Utilities/SDateTests.cs index 3fca9b29..0461952e 100644 --- a/src/SMAPI.Tests/Utilities/SDateTests.cs +++ b/src/SMAPI.Tests/Utilities/SDateTests.cs @@ -6,7 +6,6 @@ using System.Text.RegularExpressions; using NUnit.Framework; using StardewModdingAPI.Utilities; using StardewValley; -using LC = StardewValley.LocalizedContentManager.LanguageCode; namespace SMAPI.Tests.Utilities { @@ -83,6 +82,46 @@ namespace SMAPI.Tests.Utilities Assert.Throws(() => _ = new SDate(day, season, year), "Constructing the invalid date didn't throw the expected exception."); } + /**** + ** FromDaysSinceStart + ****/ + [Test(Description = "Assert that FromDaysSinceStart returns the expected date.")] + [TestCase(1, ExpectedResult = "01 spring Y1")] + [TestCase(2, ExpectedResult = "02 spring Y1")] + [TestCase(28, ExpectedResult = "28 spring Y1")] + [TestCase(29, ExpectedResult = "01 summer Y1")] + [TestCase(141, ExpectedResult = "01 summer Y2")] + public string FromDaysSinceStart(int daysSinceStart) + { + // act + return SDate.FromDaysSinceStart(daysSinceStart).ToString(); + } + + [Test(Description = "Assert that FromDaysSinceStart throws an exception if the number of days is invalid.")] + [TestCase(-1)] // day < 0 + [TestCase(0)] // day == 0 + [SuppressMessage("ReSharper", "AssignmentIsFullyDiscarded", Justification = "Deliberate for unit test.")] + public void FromDaysSinceStart_RejectsInvalidValues(int daysSinceStart) + { + // act & assert + Assert.Throws(() => _ = SDate.FromDaysSinceStart(daysSinceStart), "Passing the invalid number of days didn't throw the expected exception."); + } + + /**** + ** From + ****/ + [Test(Description = "Assert that SDate.From constructs the correct instance for a given date.")] + [TestCase(0, ExpectedResult = "01 spring Y1")] + [TestCase(1, ExpectedResult = "02 spring Y1")] + [TestCase(27, ExpectedResult = "28 spring Y1")] + [TestCase(28, ExpectedResult = "01 summer Y1")] + [TestCase(140, ExpectedResult = "01 summer Y2")] + public string From_WorldDate(int totalDays) + { + return SDate.From(new WorldDate { TotalDays = totalDays }).ToString(); + } + + /**** ** SeasonIndex ****/ @@ -98,6 +137,7 @@ namespace SMAPI.Tests.Utilities return this.GetDate(dateStr).SeasonIndex; } + /**** ** DayOfWeek ****/ @@ -136,6 +176,7 @@ namespace SMAPI.Tests.Utilities return this.GetDate(dateStr).DayOfWeek; } + /**** ** DaysSinceStart ****/ @@ -151,6 +192,7 @@ namespace SMAPI.Tests.Utilities return this.GetDate(dateStr).DaysSinceStart; } + /**** ** ToString ****/ @@ -164,57 +206,6 @@ namespace SMAPI.Tests.Utilities return this.GetDate(dateStr).ToString(); } - /**** - ** ToLocaleString - ****/ - // TODO: Provide an appropriate XNA/MonoGame context to run this in, or else remove the test. - // [Test(Description = "Assert that ToLocaleString returns the expected string in various locales.")] - // [TestCase("14 spring Y1", LC.en, ExpectedResult = "Day 14 of Spring, Year 1")] - // [TestCase("01 summer Y16", LC.en, ExpectedResult = "Day 1 of Summer, Year 16")] - // [TestCase("28 fall Y10", LC.en, ExpectedResult = "Day 28 of Fall, Year 10")] - // [TestCase("01 winter Y1", LC.en, ExpectedResult = "Day 1 of Winter, Year 1")] - // [TestCase("14 spring Y1", LC.es, ExpectedResult = "Día 14 de primavera, año 1")] - // [TestCase("01 summer Y16", LC.es, ExpectedResult = "Día 1 de verano, año 16")] - // [TestCase("28 fall Y10", LC.es, ExpectedResult = "Día 28 de otoño, año 10")] - // [TestCase("01 winter Y1", LC.es, ExpectedResult = "Día 1 de invierno, año 1")] - // public string ToLocaleString(string dateStr, LC langCode) - // { - // LC oldCode = LocalizedContentManager.CurrentLanguageCode; - // try - // { - // LocalizedContentManager.CurrentLanguageCode = langCode; - // return this.GetDate(dateStr).ToLocaleString(); - // } - // finally - // { - // LocalizedContentManager.CurrentLanguageCode = oldCode; - // } - // } - - /**** - ** FromDaysSinceStart - ****/ - [Test(Description = "Assert that FromDaysSinceStart returns the expected date.")] - [TestCase(1, ExpectedResult = "01 spring Y1")] - [TestCase(2, ExpectedResult = "02 spring Y1")] - [TestCase(28, ExpectedResult = "28 spring Y1")] - [TestCase(29, ExpectedResult = "01 summer Y1")] - [TestCase(141, ExpectedResult = "01 summer Y2")] - public string FromDaysSinceStart(int daysSinceStart) - { - // act - return SDate.FromDaysSinceStart(daysSinceStart).ToString(); - } - - [Test(Description = "Assert that FromDaysSinceStart throws an exception if the number of days is invalid.")] - [TestCase(-1)] // day < 0 - [TestCase(0)] // day == 0 - [SuppressMessage("ReSharper", "AssignmentIsFullyDiscarded", Justification = "Deliberate for unit test.")] - public void FromDaysSinceStart_RejectsInvalidValues(int daysSinceStart) - { - // act & assert - Assert.Throws(() => _ = SDate.FromDaysSinceStart(daysSinceStart), "Passing the invalid number of days didn't throw the expected exception."); - } /**** ** AddDays @@ -246,6 +237,7 @@ namespace SMAPI.Tests.Utilities Assert.Throws(() => _ = this.GetDate(dateStr).AddDays(addDays), "Passing the invalid number of days didn't throw the expected exception."); } + /**** ** GetHashCode ****/ @@ -274,28 +266,25 @@ namespace SMAPI.Tests.Utilities } } - [Test(Description = "Assert that the SDate operator for WorldDates returns the corresponding SDate.")] - [TestCase(0, ExpectedResult = "01 spring Y1")] - [TestCase(1, ExpectedResult = "02 spring Y1")] - [TestCase(27, ExpectedResult = "28 spring Y1")] - [TestCase(28, ExpectedResult = "01 summer Y1")] - [TestCase(140, ExpectedResult = "01 summer Y2")] - public string Operators_SDate_WorldDate(int totalDays) - { - return ((SDate)new WorldDate { TotalDays = totalDays }).ToString(); - } + /**** + ** ToWorldDate + ****/ [Test(Description = "Assert that the WorldDate operator returns the corresponding WorldDate.")] [TestCase("01 spring Y1", ExpectedResult = 0)] [TestCase("02 spring Y1", ExpectedResult = 1)] [TestCase("28 spring Y1", ExpectedResult = 27)] [TestCase("01 summer Y1", ExpectedResult = 28)] [TestCase("01 summer Y2", ExpectedResult = 140)] - public int Operators_WorldDate(string dateStr) + public int ToWorldDate(string dateStr) { - return ((WorldDate)this.GetDate(dateStr)).TotalDays; + return this.GetDate(dateStr).ToWorldDate().TotalDays; } + + /**** + ** Operators + ****/ [Test(Description = "Assert that the == operator returns the expected values. We only need a few test cases, since it's based on GetHashCode which is tested more thoroughly.")] [TestCase(Dates.Now, null, ExpectedResult = false)] [TestCase(Dates.Now, Dates.PrevDay, ExpectedResult = false)] diff --git a/src/SMAPI/Utilities/SDate.cs b/src/SMAPI/Utilities/SDate.cs index 8cb55891..36907714 100644 --- a/src/SMAPI/Utilities/SDate.cs +++ b/src/SMAPI/Utilities/SDate.cs @@ -29,7 +29,8 @@ namespace StardewModdingAPI.Utilities /// The season name. public string Season { get; } - /// The season index. + /// The index of the season (where 0 is spring, 1 is summer, 2 is fall, and 3 is winter). + /// This is used in some game calculations (e.g. seasonal game sprites) and methods (e.g. ). public int SeasonIndex { get; } /// The year. @@ -66,7 +67,7 @@ namespace StardewModdingAPI.Utilities return new SDate(Game1.dayOfMonth, Game1.currentSeason, Game1.year, allowDayZero: true); } - /// Get the date falling the given number of days after 0 spring Y1. + /// Get a date from the number of days after 0 spring Y1. /// The number of days since 0 spring Y1. public static SDate FromDaysSinceStart(int daysSinceStart) { @@ -80,6 +81,16 @@ namespace StardewModdingAPI.Utilities } } + /// Get a date from a game date instance. + /// The world date. + public static SDate From(WorldDate date) + { + if (date == null) + return null; + + return new SDate(date.DayOfMonth, date.Season, date.Year, allowDayZero: true); + } + /// Get a new date with the given number of days added. /// The number of days to add. /// Returns the resulting date. @@ -109,13 +120,19 @@ namespace StardewModdingAPI.Utilities return new SDate(day, this.Seasons[seasonIndex], year); } + /// Get a game date representation of the date. + public WorldDate ToWorldDate() + { + return new WorldDate(this.Year, this.Season, this.Day); + } + /// Get a string representation of the date. This is mainly intended for debugging or console messages. public override string ToString() { return $"{this.Day:00} {this.Season} Y{this.Year}"; } - /// Get a string representation of the date in the current game locale. + /// Get a translated string representation of the date in the current game locale. public string ToLocaleString() { return Utility.getDateStringFor(this.Day, this.SeasonIndex, this.Year); @@ -147,19 +164,6 @@ namespace StardewModdingAPI.Utilities /**** ** Operators ****/ - /// Get the SDate equivalent to the given WorldDate. - /// A date returned from a core game property or method. - public static explicit operator SDate(WorldDate worldDate) - { - return new SDate(worldDate.DayOfMonth, worldDate.Season, worldDate.Year, allowDayZero: true); - } - - /// Get the SDate as an instance of the game's WorldDate class. This is intended for passing to core game methods. - public static explicit operator WorldDate(SDate date) - { - return new WorldDate(date.Year, date.Season, date.Day); - } - /// Get whether one date is equal to another. /// The base date to compare. /// The other date to compare. -- cgit From de4d4e0bcb2d69622ef9f2e616648f4310047f5f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 15 Apr 2020 19:21:30 -0400 Subject: update unit test --- src/SMAPI.Tests/Core/ModResolverTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/SMAPI.Tests/Core/ModResolverTests.cs b/src/SMAPI.Tests/Core/ModResolverTests.cs index a9c88c60..45b3673b 100644 --- a/src/SMAPI.Tests/Core/ModResolverTests.cs +++ b/src/SMAPI.Tests/Core/ModResolverTests.cs @@ -73,7 +73,7 @@ namespace SMAPI.Tests.Core [nameof(IManifest.Description)] = Sample.String(), [nameof(IManifest.UniqueID)] = $"{Sample.String()}.{Sample.String()}", [nameof(IManifest.EntryDll)] = $"{Sample.String()}.dll", - [nameof(IManifest.MinimumApiVersion)] = $"{Sample.Int()}.{Sample.Int()}-{Sample.String()}", + [nameof(IManifest.MinimumApiVersion)] = $"{Sample.Int()}.{Sample.Int()}.{Sample.Int()}-{Sample.String()}", [nameof(IManifest.Dependencies)] = new[] { originalDependency }, ["ExtraString"] = Sample.String(), ["ExtraInt"] = Sample.Int() -- cgit From 841f85a74331a02bd45f3d40ea1b50e4bc9dd3eb Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 17 Apr 2020 17:21:34 -0400 Subject: use better short date translations --- src/SMAPI/Framework/SCore.cs | 3 +++ src/SMAPI/Program.cs | 4 ++-- src/SMAPI/Utilities/SDate.cs | 25 ++++++++++++++++++++++--- src/SMAPI/i18n/de.json | 8 +++++++- src/SMAPI/i18n/default.json | 7 ++++++- src/SMAPI/i18n/es.json | 7 ++++++- src/SMAPI/i18n/fr.json | 7 ++++++- src/SMAPI/i18n/hu.json | 7 ++++++- src/SMAPI/i18n/it.json | 7 ++++++- src/SMAPI/i18n/ja.json | 7 ++++++- src/SMAPI/i18n/ko.json | 8 ++++++++ src/SMAPI/i18n/pt.json | 7 ++++++- src/SMAPI/i18n/ru.json | 7 ++++++- src/SMAPI/i18n/tr.json | 7 ++++++- src/SMAPI/i18n/zh.json | 7 ++++++- 15 files changed, 102 insertions(+), 16 deletions(-) create mode 100644 src/SMAPI/i18n/ko.json (limited to 'src') diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 50e6ea1c..de9c955d 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -32,6 +32,7 @@ using StardewModdingAPI.Toolkit.Framework.Clients.WebApi; using StardewModdingAPI.Toolkit.Framework.ModData; using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities; +using StardewModdingAPI.Utilities; using StardewValley; using Object = StardewValley.Object; using ThreadState = System.Threading.ThreadState; @@ -176,6 +177,8 @@ namespace StardewModdingAPI.Framework SCore.DeprecationManager = new DeprecationManager(this.Monitor, this.ModRegistry); + SDate.Translations = this.Translator; + // redirect direct console output if (this.MonitorForGame.WriteToConsole) this.ConsoleManager.OnMessageIntercepted += message => this.HandleConsoleMessage(this.MonitorForGame, message); diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index c26ae29a..715c8553 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -143,8 +143,8 @@ namespace StardewModdingAPI } // load SMAPI - using (SCore core = new SCore(modsPath, writeToConsole)) - core.RunInteractively(); + using SCore core = new SCore(modsPath, writeToConsole); + core.RunInteractively(); } /// Write an error directly to the console and exit. diff --git a/src/SMAPI/Utilities/SDate.cs b/src/SMAPI/Utilities/SDate.cs index 36907714..4d4920ab 100