fix typos and inconsistent spelling
This commit is contained in:
parent
3f6865e830
commit
fd77ae93d5
|
@ -1,3 +1,3 @@
|
||||||
# normalise line endings
|
# normalize line endings
|
||||||
* text=auto
|
* text=auto
|
||||||
README.txt text=crlf
|
README.txt text=crlf
|
||||||
|
|
|
@ -29,6 +29,7 @@ These changes have not been released yet.
|
||||||
* Fixed map reloads resetting tilesheet seasons.
|
* Fixed map reloads resetting tilesheet seasons.
|
||||||
* Fixed map reloads not updating door warps.
|
* Fixed map reloads not updating door warps.
|
||||||
* Fixed outdoor tilesheets being seasonalised when added to an indoor location.
|
* Fixed outdoor tilesheets being seasonalised when added to an indoor location.
|
||||||
|
* Fixed typos and inconsistent spelling.
|
||||||
|
|
||||||
* For the mod compatibility list:
|
* For the mod compatibility list:
|
||||||
* Now loads faster (since data is fetched in a background service).
|
* Now loads faster (since data is fetched in a background service).
|
||||||
|
@ -43,7 +44,7 @@ These changes have not been released yet.
|
||||||
* Added support for referencing a schema in a JSON Schema-compatible text editor.
|
* Added support for referencing a schema in a JSON Schema-compatible text editor.
|
||||||
|
|
||||||
* For modders:
|
* For modders:
|
||||||
* Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialised when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialised).
|
* Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialized when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialized).
|
||||||
* Added support for content pack translations.
|
* Added support for content pack translations.
|
||||||
* Added fields and methods: `IContentPack.HasFile`, `Context.IsGameLaunched`, and `SemanticVersion.TryParse`.
|
* Added fields and methods: `IContentPack.HasFile`, `Context.IsGameLaunched`, and `SemanticVersion.TryParse`.
|
||||||
* Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose.
|
* Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose.
|
||||||
|
@ -53,7 +54,7 @@ These changes have not been released yet.
|
||||||
* Trace logs when loading mods are now more clear.
|
* Trace logs when loading mods are now more clear.
|
||||||
* Clarified update-check errors for mods with multiple update keys.
|
* Clarified update-check errors for mods with multiple update keys.
|
||||||
* Fixed custom maps loaded from `.xnb` files not having their tilesheet paths automatically adjusted.
|
* Fixed custom maps loaded from `.xnb` files not having their tilesheet paths automatically adjusted.
|
||||||
* Fixed custom maps loaded from the mod folder with tilesheets in a subfolder not working crossplatform. All tilesheet paths are now normalised for the OS automatically.
|
* Fixed custom maps loaded from the mod folder with tilesheets in a subfolder not working crossplatform. All tilesheet paths are now normalized for the OS automatically.
|
||||||
* Removed all deprecated APIs.
|
* Removed all deprecated APIs.
|
||||||
* Removed the `Monitor.ExitGameImmediately` method.
|
* Removed the `Monitor.ExitGameImmediately` method.
|
||||||
* Updated dependencies (including Json.NET 11.0.2 → 12.0.2, Mono.Cecil 0.10.1 → 0.10.4).
|
* Updated dependencies (including Json.NET 11.0.2 → 12.0.2, Mono.Cecil 0.10.1 → 0.10.4).
|
||||||
|
@ -73,7 +74,7 @@ Released 13 September 2019 for Stardew Valley 1.3.36.
|
||||||
* For the web UI:
|
* For the web UI:
|
||||||
* When filtering the mod list, clicking a mod link now automatically adds it to the visible mods.
|
* When filtering the mod list, clicking a mod link now automatically adds it to the visible mods.
|
||||||
* Added log parser instructions for Android.
|
* Added log parser instructions for Android.
|
||||||
* Fixed log parser failing in some cases due to time format localisation.
|
* Fixed log parser failing in some cases due to time format localization.
|
||||||
|
|
||||||
* For modders:
|
* For modders:
|
||||||
* `this.Monitor.Log` now defaults to the `Trace` log level instead of `Debug`. The change will only take effect when you recompile the mod.
|
* `this.Monitor.Log` now defaults to the `Trace` log level instead of `Debug`. The change will only take effect when you recompile the mod.
|
||||||
|
@ -141,12 +142,12 @@ Released 09 January 2019 for Stardew Valley 1.3.32–33.
|
||||||
* Added locale to context trace logs.
|
* Added locale to context trace logs.
|
||||||
* Fixed error loading custom map tilesheets in some cases.
|
* Fixed error loading custom map tilesheets in some cases.
|
||||||
* Fixed error when swapping maps mid-session for a location with interior doors.
|
* Fixed error when swapping maps mid-session for a location with interior doors.
|
||||||
* Fixed `Constants.SaveFolderName` and `CurrentSavePath` not available during early load stages when using `Specialised.LoadStageChanged` event.
|
* Fixed `Constants.SaveFolderName` and `CurrentSavePath` not available during early load stages when using `Specialized.LoadStageChanged` event.
|
||||||
* Fixed `LoadStage.SaveParsed` raised before the parsed save data is available.
|
* Fixed `LoadStage.SaveParsed` raised before the parsed save data is available.
|
||||||
* Fixed 'unknown mod' deprecation warnings showing the wrong stack trace.
|
* Fixed 'unknown mod' deprecation warnings showing the wrong stack trace.
|
||||||
* Fixed `e.Cursor` in input events showing wrong grab tile when player using a controller moves without moving the viewpoint.
|
* Fixed `e.Cursor` in input events showing wrong grab tile when player using a controller moves without moving the viewpoint.
|
||||||
* Fixed incorrect 'bypassed safety checks' warning for mods using the new `Specialised.LoadStageChanged` event in 2.10.
|
* Fixed incorrect 'bypassed safety checks' warning for mods using the new `Specialized.LoadStageChanged` event in 2.10.
|
||||||
* Deprecated `EntryDll` values whose capitalisation don't match the actual file. (This works on Windows, but causes errors for Linux/Mac players.)
|
* Deprecated `EntryDll` values whose capitalization don't match the actual file. (This works on Windows, but causes errors for Linux/Mac players.)
|
||||||
|
|
||||||
## 2.10.1
|
## 2.10.1
|
||||||
Released 30 December 2018 for Stardew Valley 1.3.32–33.
|
Released 30 December 2018 for Stardew Valley 1.3.32–33.
|
||||||
|
@ -163,9 +164,9 @@ Released 29 December 2018 for Stardew Valley 1.3.32–33.
|
||||||
* Tweaked installer to reduce antivirus false positives.
|
* Tweaked installer to reduce antivirus false positives.
|
||||||
|
|
||||||
* For modders:
|
* For modders:
|
||||||
* Added [events](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Events): `GameLoop.OneSecondUpdateTicking`, `GameLoop.OneSecondUpdateTicked`, and `Specialised.LoadStageChanged`.
|
* Added [events](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Events): `GameLoop.OneSecondUpdateTicking`, `GameLoop.OneSecondUpdateTicked`, and `Specialized.LoadStageChanged`.
|
||||||
* Added `e.IsCurrentLocation` event arg to `World` events.
|
* Added `e.IsCurrentLocation` event arg to `World` events.
|
||||||
* You can now use `helper.Data.Read/WriteSaveData` as soon as the save is loaded (instead of once the world is initialised).
|
* You can now use `helper.Data.Read/WriteSaveData` as soon as the save is loaded (instead of once the world is initialized).
|
||||||
* Increased deprecation levels to _info_ for the upcoming SMAPI 3.0.
|
* Increased deprecation levels to _info_ for the upcoming SMAPI 3.0.
|
||||||
|
|
||||||
* For the web UI:
|
* For the web UI:
|
||||||
|
@ -338,7 +339,7 @@ Released 14 August 2018 for Stardew Valley 1.3.28.
|
||||||
* dialogue;
|
* dialogue;
|
||||||
* map tilesheets.
|
* map tilesheets.
|
||||||
* Added `--mods-path` CLI command-line argument to switch between mod folders.
|
* Added `--mods-path` CLI command-line argument to switch between mod folders.
|
||||||
* All enums are now JSON-serialised by name instead of numeric value. (Previously only a few enums were serialised that way. JSON files which already have numeric enum values will still be parsed fine.)
|
* All enums are now JSON-serialized by name instead of numeric value. (Previously only a few enums were serialized that way. JSON files which already have numeric enum values will still be parsed fine.)
|
||||||
* Fixed false compatibility error when constructing multidimensional arrays.
|
* Fixed false compatibility error when constructing multidimensional arrays.
|
||||||
* Fixed `.ToSButton()` methods not being public.
|
* Fixed `.ToSButton()` methods not being public.
|
||||||
|
|
||||||
|
@ -365,7 +366,7 @@ Released 01 August 2018 for Stardew Valley 1.3.27.
|
||||||
* Improved the Console Commands mod:
|
* Improved the Console Commands mod:
|
||||||
* Added `player_add name`, which adds items to your inventory by name instead of ID.
|
* Added `player_add name`, which adds items to your inventory by name instead of ID.
|
||||||
* Fixed `world_setseason` not running season-change logic.
|
* Fixed `world_setseason` not running season-change logic.
|
||||||
* Fixed `world_setseason` not normalising the season value.
|
* Fixed `world_setseason` not normalizing the season value.
|
||||||
* Fixed `world_settime` sometimes breaking NPC schedules (e.g. so they stay in bed).
|
* Fixed `world_settime` sometimes breaking NPC schedules (e.g. so they stay in bed).
|
||||||
* Removed the `player_setlevel` and `player_setspeed` commands, which weren't implemented in a useful way. Use a mod like CJB Cheats Menu if you need those.
|
* Removed the `player_setlevel` and `player_setspeed` commands, which weren't implemented in a useful way. Use a mod like CJB Cheats Menu if you need those.
|
||||||
* Fixed `SEHException` errors for some players.
|
* Fixed `SEHException` errors for some players.
|
||||||
|
@ -456,7 +457,7 @@ Released 11 April 2018 for Stardew Valley 1.2.30–1.2.33.
|
||||||
* Fixed mod update alerts not shown if one mod has an invalid remote version.
|
* Fixed mod update alerts not shown if one mod has an invalid remote version.
|
||||||
* Fixed SMAPI update alerts linking to the GitHub repository instead of [smapi.io](https://smapi.io).
|
* Fixed SMAPI update alerts linking to the GitHub repository instead of [smapi.io](https://smapi.io).
|
||||||
* Fixed SMAPI update alerts for draft releases.
|
* Fixed SMAPI update alerts for draft releases.
|
||||||
* Fixed error when two content packs use different capitalisation for the same required mod ID.
|
* Fixed error when two content packs use different capitalization for the same required mod ID.
|
||||||
* Fixed rare crash if the game duplicates an item.
|
* Fixed rare crash if the game duplicates an item.
|
||||||
|
|
||||||
* For the [log parser](https://log.smapi.io):
|
* For the [log parser](https://log.smapi.io):
|
||||||
|
@ -531,8 +532,8 @@ Released 24 February 2018 for Stardew Valley 1.2.30–1.2.33.
|
||||||
* For modders:
|
* For modders:
|
||||||
* Added support for content packs and new APIs to read them.
|
* Added support for content packs and new APIs to read them.
|
||||||
* Added support for `ISemanticVersion` in JSON models.
|
* Added support for `ISemanticVersion` in JSON models.
|
||||||
* Added `SpecialisedEvents.UnvalidatedUpdateTick` event for specialised use cases.
|
* Added `SpecializedEvents.UnvalidatedUpdateTick` event for specialized use cases.
|
||||||
* Added path normalising to `ReadJsonFile` and `WriteJsonFile` helpers (so no longer need `Path.Combine` with those).
|
* Added path normalizing to `ReadJsonFile` and `WriteJsonFile` helpers (so no longer need `Path.Combine` with those).
|
||||||
* Fixed deadlock in rare cases with asset loaders.
|
* Fixed deadlock in rare cases with asset loaders.
|
||||||
* Fixed unhelpful error when a mod exposes a non-public API.
|
* Fixed unhelpful error when a mod exposes a non-public API.
|
||||||
* Fixed unhelpful error when a translation file has duplicate keys due to case-insensitivity.
|
* Fixed unhelpful error when a translation file has duplicate keys due to case-insensitivity.
|
||||||
|
@ -585,11 +586,11 @@ Released 26 December 2017 for Stardew Valley 1.2.30–1.2.33.
|
||||||
|
|
||||||
* For modders:
|
* For modders:
|
||||||
* **Added mod-provided APIs** to allow simple integrations between mods, even without direct assembly references.
|
* **Added mod-provided APIs** to allow simple integrations between mods, even without direct assembly references.
|
||||||
* Added `GameEvents.FirstUpdateTick` event (called once after all mods are initialised).
|
* Added `GameEvents.FirstUpdateTick` event (called once after all mods are initialized).
|
||||||
* Added `IsSuppressed` to input events so mods can optionally avoid handling keys another mod has already handled.
|
* Added `IsSuppressed` to input events so mods can optionally avoid handling keys another mod has already handled.
|
||||||
* Added trace message for mods with no update keys.
|
* Added trace message for mods with no update keys.
|
||||||
* Adjusted reflection API to match actual usage (e.g. renamed `GetPrivate*` to `Get*`), and deprecated previous methods.
|
* Adjusted reflection API to match actual usage (e.g. renamed `GetPrivate*` to `Get*`), and deprecated previous methods.
|
||||||
* Fixed `GraphicsEvents.OnPostRenderEvent` not being raised in some specialised cases.
|
* Fixed `GraphicsEvents.OnPostRenderEvent` not being raised in some specialized cases.
|
||||||
* Fixed reflection API error for properties missing a `get` and `set`.
|
* Fixed reflection API error for properties missing a `get` and `set`.
|
||||||
* Fixed issue where a mod could change the cursor position reported to other mods.
|
* Fixed issue where a mod could change the cursor position reported to other mods.
|
||||||
* Updated compatibility list.
|
* Updated compatibility list.
|
||||||
|
@ -614,7 +615,7 @@ Released 02 December 2017 for Stardew Valley 1.2.30–1.2.33.
|
||||||
* Slightly improved the UI.
|
* Slightly improved the UI.
|
||||||
|
|
||||||
* For modders:
|
* For modders:
|
||||||
* Added `helper.Content.NormaliseAssetName` method.
|
* Added `helper.Content.NormalizeAssetName` method.
|
||||||
* Added `SDate.DaysSinceStart` property.
|
* Added `SDate.DaysSinceStart` property.
|
||||||
* Fixed input events' `e.SuppressButton(button)` method ignoring specified button.
|
* Fixed input events' `e.SuppressButton(button)` method ignoring specified button.
|
||||||
* Fixed input events' `e.SuppressButton()` method not working with mouse buttons.
|
* Fixed input events' `e.SuppressButton()` method not working with mouse buttons.
|
||||||
|
@ -769,7 +770,7 @@ For mod developers:
|
||||||
* Added content helper properties for the game's current language.
|
* Added content helper properties for the game's current language.
|
||||||
* Fixed `Context.IsPlayerFree` being false if the player is performing an action.
|
* Fixed `Context.IsPlayerFree` being false if the player is performing an action.
|
||||||
* Fixed `GraphicsEvents.Resize` being raised before the game updates its window data.
|
* Fixed `GraphicsEvents.Resize` being raised before the game updates its window data.
|
||||||
* Fixed `SemanticVersion` not being deserialisable through Json.NET.
|
* Fixed `SemanticVersion` not being deserializable through Json.NET.
|
||||||
* Fixed terminal not launching on Xfce Linux.
|
* Fixed terminal not launching on Xfce Linux.
|
||||||
|
|
||||||
For SMAPI developers:
|
For SMAPI developers:
|
||||||
|
@ -840,7 +841,7 @@ For modders:
|
||||||
* SMAPI now automatically fixes tilesheet references for maps loaded from the mod folder.
|
* SMAPI now automatically fixes tilesheet references for maps loaded from the mod folder.
|
||||||
<small>_When loading a map from the mod folder, SMAPI will automatically use tilesheets relative to the map file if they exists. Otherwise it will default to tilesheets in the game content._</small>
|
<small>_When loading a map from the mod folder, SMAPI will automatically use tilesheets relative to the map file if they exists. Otherwise it will default to tilesheets in the game content._</small>
|
||||||
* Added `Context.IsPlayerFree` for mods that need to check if the player can act (i.e. save is loaded, no menu is displayed, no cutscene is in progress, etc).
|
* Added `Context.IsPlayerFree` for mods that need to check if the player can act (i.e. save is loaded, no menu is displayed, no cutscene is in progress, etc).
|
||||||
* Added `Context.IsInDrawLoop` for specialised mods.
|
* Added `Context.IsInDrawLoop` for specialized mods.
|
||||||
* Fixed `smapi-crash.txt` being copied from the default log even if a different path is specified with `--log-path`.
|
* Fixed `smapi-crash.txt` being copied from the default log even if a different path is specified with `--log-path`.
|
||||||
* Fixed the content API not matching XNB filenames with two dots (like `a.b.xnb`) if you don't specify the `.xnb` extension.
|
* Fixed the content API not matching XNB filenames with two dots (like `a.b.xnb`) if you don't specify the `.xnb` extension.
|
||||||
* Fixed `debug` command output not printed to console.
|
* Fixed `debug` command output not printed to console.
|
||||||
|
@ -867,7 +868,7 @@ For players:
|
||||||
|
|
||||||
For mod developers:
|
For mod developers:
|
||||||
* Added a `Context.IsWorldReady` flag for mods to use.
|
* Added a `Context.IsWorldReady` flag for mods to use.
|
||||||
<small>_This indicates whether a save is loaded and the world is finished initialising, which starts at the same point that `SaveEvents.AfterLoad` and `TimeEvents.AfterDayStarted` are raised. This is mainly useful for events which can be raised before the world is loaded (like update tick)._</small>
|
<small>_This indicates whether a save is loaded and the world is finished initializing, which starts at the same point that `SaveEvents.AfterLoad` and `TimeEvents.AfterDayStarted` are raised. This is mainly useful for events which can be raised before the world is loaded (like update tick)._</small>
|
||||||
* Added a `debug` console command which lets you run the game's debug commands (e.g. `debug warp FarmHouse 1 1` warps you to the farmhouse).
|
* Added a `debug` console command which lets you run the game's debug commands (e.g. `debug warp FarmHouse 1 1` warps you to the farmhouse).
|
||||||
* Added basic context info to logs to simplify troubleshooting.
|
* Added basic context info to logs to simplify troubleshooting.
|
||||||
* Added a `Mod.Dispose` method which can be overriden to clean up before exit. This method isn't guaranteed to be called on every exit.
|
* Added a `Mod.Dispose` method which can be overriden to clean up before exit. This method isn't guaranteed to be called on every exit.
|
||||||
|
@ -905,8 +906,8 @@ For players:
|
||||||
For mod developers:
|
For mod developers:
|
||||||
* Added a content API which loads custom textures/maps/data from the mod's folder (`.xnb` or `.png` format) or game content.
|
* Added a content API which loads custom textures/maps/data from the mod's folder (`.xnb` or `.png` format) or game content.
|
||||||
* `Console.Out` messages are now written to the log file.
|
* `Console.Out` messages are now written to the log file.
|
||||||
* `Monitor.ExitGameImmediately` now aborts SMAPI initialisation and events more quickly.
|
* `Monitor.ExitGameImmediately` now aborts SMAPI initialization and events more quickly.
|
||||||
* Fixed value-changed events being raised when the player loads a save due to values being initialised.
|
* Fixed value-changed events being raised when the player loads a save due to values being initialized.
|
||||||
|
|
||||||
## 1.10
|
## 1.10
|
||||||
Released 24 April 2017 for Stardew Valley 1.2.26.
|
Released 24 April 2017 for Stardew Valley 1.2.26.
|
||||||
|
@ -922,7 +923,7 @@ For players:
|
||||||
* Replaced `player_addmelee` with `player_addweapon` with support for non-melee weapons.
|
* Replaced `player_addmelee` with `player_addweapon` with support for non-melee weapons.
|
||||||
|
|
||||||
For mod developers:
|
For mod developers:
|
||||||
* Mods are now initialised after the `Initialize`/`LoadContent` phase, which means the `GameEvents.Initialize` and `GameEvents.LoadContent` events are deprecated. You can move any logic in those methods to your mod's `Entry` method.
|
* Mods are now initialized after the `Initialize`/`LoadContent` phase, which means the `GameEvents.Initialize` and `GameEvents.LoadContent` events are deprecated. You can move any logic in those methods to your mod's `Entry` method.
|
||||||
* Added `IsBetween` and string overloads to the `ISemanticVersion` methods.
|
* Added `IsBetween` and string overloads to the `ISemanticVersion` methods.
|
||||||
* Fixed mouse-changed event never updating prior mouse position.
|
* Fixed mouse-changed event never updating prior mouse position.
|
||||||
* Fixed `monitor.ExitGameImmediately` not working correctly.
|
* Fixed `monitor.ExitGameImmediately` not working correctly.
|
||||||
|
@ -961,7 +962,7 @@ For mod developers:
|
||||||
* The SMAPI log now has a simpler filename.
|
* The SMAPI log now has a simpler filename.
|
||||||
* The SMAPI log now shows the OS caption (like "Windows 10") instead of its internal version when available.
|
* The SMAPI log now shows the OS caption (like "Windows 10") instead of its internal version when available.
|
||||||
* The SMAPI log now always uses `\r\n` line endings to simplify crossplatform viewing.
|
* The SMAPI log now always uses `\r\n` line endings to simplify crossplatform viewing.
|
||||||
* Fixed `SaveEvents.AfterLoad` being raised during the new-game intro before the player is initialised.
|
* Fixed `SaveEvents.AfterLoad` being raised during the new-game intro before the player is initialized.
|
||||||
* Fixed SMAPI not recognising `Mod` instances that don't subclass `Mod` directly.
|
* Fixed SMAPI not recognising `Mod` instances that don't subclass `Mod` directly.
|
||||||
* Several obsolete APIs have been removed (see [migration guides](https://stardewvalleywiki.com/Modding:Index#Migration_guides)),
|
* Several obsolete APIs have been removed (see [migration guides](https://stardewvalleywiki.com/Modding:Index#Migration_guides)),
|
||||||
and all _notice_-level deprecations have been increased to _info_.
|
and all _notice_-level deprecations have been increased to _info_.
|
||||||
|
@ -1006,7 +1007,7 @@ For mod developers:
|
||||||
* Added a mod registry which provides metadata about loaded mods.
|
* Added a mod registry which provides metadata about loaded mods.
|
||||||
* The `Entry(…)` method is now deferred until all mods are loaded.
|
* The `Entry(…)` method is now deferred until all mods are loaded.
|
||||||
* Fixed `SaveEvents.BeforeSave` and `.AfterSave` not triggering on days when the player shipped something.
|
* Fixed `SaveEvents.BeforeSave` and `.AfterSave` not triggering on days when the player shipped something.
|
||||||
* Fixed `PlayerEvents.LoadedGame` and `SaveEvents.AfterLoad` being fired before the world finishes initialising.
|
* Fixed `PlayerEvents.LoadedGame` and `SaveEvents.AfterLoad` being fired before the world finishes initializing.
|
||||||
* Fixed some `LocationEvents`, `PlayerEvents`, and `TimeEvents` being fired during game startup.
|
* Fixed some `LocationEvents`, `PlayerEvents`, and `TimeEvents` being fired during game startup.
|
||||||
* Increased deprecation levels for `SObject`, `LogWriter` (not `Log`), and `Mod.Entry(ModHelper)` (not `Mod.Entry(IModHelper)`) to _pending removal_. Increased deprecation levels for `Mod.PerSaveConfigFolder`, `Mod.PerSaveConfigPath`, and `Version.VersionString` to _info_.
|
* Increased deprecation levels for `SObject`, `LogWriter` (not `Log`), and `Mod.Entry(ModHelper)` (not `Mod.Entry(IModHelper)`) to _pending removal_. Increased deprecation levels for `Mod.PerSaveConfigFolder`, `Mod.PerSaveConfigPath`, and `Version.VersionString` to _info_.
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ namespace StardewModdingApi.Installer
|
||||||
/// <summary>Run the install or uninstall script.</summary>
|
/// <summary>Run the install or uninstall script.</summary>
|
||||||
/// <param name="args">The command line arguments.</param>
|
/// <param name="args">The command line arguments.</param>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Initialisation flow:
|
/// Initialization flow:
|
||||||
/// 1. Collect information (mainly OS and install path) and validate it.
|
/// 1. Collect information (mainly OS and install path) and validate it.
|
||||||
/// 2. Ask the user whether to install or uninstall.
|
/// 2. Ask the user whether to install or uninstall.
|
||||||
///
|
///
|
||||||
|
@ -218,7 +218,7 @@ namespace StardewModdingApi.Installer
|
||||||
****/
|
****/
|
||||||
// get theme writers
|
// get theme writers
|
||||||
var lightBackgroundWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.LightBackground);
|
var lightBackgroundWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.LightBackground);
|
||||||
var darkDarkgroundWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.DarkBackground);
|
var darkBackgroundWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.DarkBackground);
|
||||||
|
|
||||||
// print question
|
// print question
|
||||||
this.PrintPlain("Which text looks more readable?");
|
this.PrintPlain("Which text looks more readable?");
|
||||||
|
@ -226,7 +226,7 @@ namespace StardewModdingApi.Installer
|
||||||
Console.Write(" [1] ");
|
Console.Write(" [1] ");
|
||||||
lightBackgroundWriter.WriteLine("Dark text on light background", ConsoleLogLevel.Info);
|
lightBackgroundWriter.WriteLine("Dark text on light background", ConsoleLogLevel.Info);
|
||||||
Console.Write(" [2] ");
|
Console.Write(" [2] ");
|
||||||
darkDarkgroundWriter.WriteLine("Light text on dark background", ConsoleLogLevel.Info);
|
darkBackgroundWriter.WriteLine("Light text on dark background", ConsoleLogLevel.Info);
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
|
|
||||||
// handle choice
|
// handle choice
|
||||||
|
@ -239,7 +239,7 @@ namespace StardewModdingApi.Installer
|
||||||
break;
|
break;
|
||||||
case "2":
|
case "2":
|
||||||
scheme = MonitorColorScheme.DarkBackground;
|
scheme = MonitorColorScheme.DarkBackground;
|
||||||
this.ConsoleWriter = darkDarkgroundWriter;
|
this.ConsoleWriter = darkBackgroundWriter;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException($"Unexpected action key '{choice}'.");
|
throw new InvalidOperationException($"Unexpected action key '{choice}'.");
|
||||||
|
@ -646,7 +646,7 @@ namespace StardewModdingApi.Installer
|
||||||
|
|
||||||
/// <summary>Delete a file or folder regardless of file permissions, and block until deletion completes.</summary>
|
/// <summary>Delete a file or folder regardless of file permissions, and block until deletion completes.</summary>
|
||||||
/// <param name="entry">The file or folder to reset.</param>
|
/// <param name="entry">The file or folder to reset.</param>
|
||||||
/// <remarks>This method is mirred from <c>FileUtilities.ForceDelete</c> in the toolkit.</remarks>
|
/// <remarks>This method is mirrored from <c>FileUtilities.ForceDelete</c> in the toolkit.</remarks>
|
||||||
private void ForceDelete(FileSystemInfo entry)
|
private void ForceDelete(FileSystemInfo entry)
|
||||||
{
|
{
|
||||||
// ignore if already deleted
|
// ignore if already deleted
|
||||||
|
@ -762,7 +762,7 @@ namespace StardewModdingApi.Installer
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalise path
|
// normalize path
|
||||||
if (platform == Platform.Windows)
|
if (platform == Platform.Windows)
|
||||||
path = path.Replace("\"", ""); // in Windows, quotes are used to escape spaces and aren't part of the file path
|
path = path.Replace("\"", ""); // in Windows, quotes are used to escape spaces and aren't part of the file path
|
||||||
if (platform == Platform.Linux || platform == Platform.Mac)
|
if (platform == Platform.Linux || platform == Platform.Mac)
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace StardewModdingApi.Installer
|
||||||
FileInfo zipFile = new FileInfo(Path.Combine(Program.InstallerPath, $"{(platform == PlatformID.Win32NT ? "windows" : "unix")}-install.dat"));
|
FileInfo zipFile = new FileInfo(Path.Combine(Program.InstallerPath, $"{(platform == PlatformID.Win32NT ? "windows" : "unix")}-install.dat"));
|
||||||
if (!zipFile.Exists)
|
if (!zipFile.Exists)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Oops! Some of the installer files are missing; try redownloading the installer. (Missing file: {zipFile.FullName})");
|
Console.WriteLine($"Oops! Some of the installer files are missing; try re-downloading the installer. (Missing file: {zipFile.FullName})");
|
||||||
Console.ReadLine();
|
Console.ReadLine();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@ namespace StardewModdingAPI.Internal.ConsoleWriting
|
||||||
case ConsoleColor.Black:
|
case ConsoleColor.Black:
|
||||||
case ConsoleColor.Blue:
|
case ConsoleColor.Blue:
|
||||||
case ConsoleColor.DarkBlue:
|
case ConsoleColor.DarkBlue:
|
||||||
case ConsoleColor.DarkMagenta: // Powershell
|
case ConsoleColor.DarkMagenta: // PowerShell
|
||||||
case ConsoleColor.DarkRed:
|
case ConsoleColor.DarkRed:
|
||||||
case ConsoleColor.Red:
|
case ConsoleColor.Red:
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
namespace Netcode
|
namespace Netcode
|
||||||
{
|
{
|
||||||
/// <summary>A simplified version of Stardew Valley's <c>Netcode.NetFieldBase</c> for unit testing.</summary>
|
/// <summary>A simplified version of Stardew Valley's <c>Netcode.NetFieldBase</c> for unit testing.</summary>
|
||||||
/// <typeparam name="T">The type of the synchronised value.</typeparam>
|
/// <typeparam name="T">The type of the synchronized value.</typeparam>
|
||||||
/// <typeparam name="TSelf">The type of the current instance.</typeparam>
|
/// <typeparam name="TSelf">The type of the current instance.</typeparam>
|
||||||
public class NetFieldBase<T, TSelf> where TSelf : NetFieldBase<T, TSelf>
|
public class NetFieldBase<T, TSelf> where TSelf : NetFieldBase<T, TSelf>
|
||||||
{
|
{
|
||||||
|
|
|
@ -199,7 +199,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer
|
||||||
/*********
|
/*********
|
||||||
** Private methods
|
** Private methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Analyse a member access syntax node and add a diagnostic message if applicable.</summary>
|
/// <summary>Analyze a member access syntax node and add a diagnostic message if applicable.</summary>
|
||||||
/// <param name="context">The analysis context.</param>
|
/// <param name="context">The analysis context.</param>
|
||||||
/// <returns>Returns whether any warnings were added.</returns>
|
/// <returns>Returns whether any warnings were added.</returns>
|
||||||
private void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context)
|
private void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context)
|
||||||
|
@ -231,7 +231,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Analyse an explicit cast or 'x as y' node and add a diagnostic message if applicable.</summary>
|
/// <summary>Analyze an explicit cast or 'x as y' node and add a diagnostic message if applicable.</summary>
|
||||||
/// <param name="context">The analysis context.</param>
|
/// <param name="context">The analysis context.</param>
|
||||||
/// <returns>Returns whether any warnings were added.</returns>
|
/// <returns>Returns whether any warnings were added.</returns>
|
||||||
private void AnalyzeCast(SyntaxNodeAnalysisContext context)
|
private void AnalyzeCast(SyntaxNodeAnalysisContext context)
|
||||||
|
@ -248,7 +248,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Analyse a binary comparison syntax node and add a diagnostic message if applicable.</summary>
|
/// <summary>Analyze a binary comparison syntax node and add a diagnostic message if applicable.</summary>
|
||||||
/// <param name="context">The analysis context.</param>
|
/// <param name="context">The analysis context.</param>
|
||||||
/// <returns>Returns whether any warnings were added.</returns>
|
/// <returns>Returns whether any warnings were added.</returns>
|
||||||
private void AnalyzeBinaryComparison(SyntaxNodeAnalysisContext context)
|
private void AnalyzeBinaryComparison(SyntaxNodeAnalysisContext context)
|
||||||
|
@ -288,7 +288,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Handle exceptions raised while analyzing a node.</summary>
|
/// <summary>Handle exceptions raised while analyzing a node.</summary>
|
||||||
/// <param name="node">The node being analysed.</param>
|
/// <param name="node">The node being analyzed.</param>
|
||||||
/// <param name="action">The callback to invoke.</param>
|
/// <param name="action">The callback to invoke.</param>
|
||||||
private void HandleErrors(SyntaxNode node, Action action)
|
private void HandleErrors(SyntaxNode node, Action action)
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer
|
||||||
/*********
|
/*********
|
||||||
** Private methods
|
** Private methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Analyse a syntax node and add a diagnostic message if it references an obsolete field.</summary>
|
/// <summary>Analyze a syntax node and add a diagnostic message if it references an obsolete field.</summary>
|
||||||
/// <param name="context">The analysis context.</param>
|
/// <param name="context">The analysis context.</param>
|
||||||
private void AnalyzeObsoleteFields(SyntaxNodeAnalysisContext context)
|
private void AnalyzeObsoleteFields(SyntaxNodeAnalysisContext context)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,8 +3,8 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation;
|
using StardewModdingAPI.Toolkit.Serialization;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation.Models;
|
using StardewModdingAPI.Toolkit.Serialization.Models;
|
||||||
using StardewModdingAPI.Toolkit.Utilities;
|
using StardewModdingAPI.Toolkit.Utilities;
|
||||||
|
|
||||||
namespace StardewModdingAPI.ModBuildConfig.Framework
|
namespace StardewModdingAPI.ModBuildConfig.Framework
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
|
||||||
/// <summary>Provides methods for searching and constructing items.</summary>
|
/// <summary>Provides methods for searching and constructing items.</summary>
|
||||||
private readonly ItemRepository Items = new ItemRepository();
|
private readonly ItemRepository Items = new ItemRepository();
|
||||||
|
|
||||||
/// <summary>The type names recognised by this command.</summary>
|
/// <summary>The type names recognized by this command.</summary>
|
||||||
private readonly string[] ValidTypes = Enum.GetNames(typeof(ItemType)).Concat(new[] { "Name" }).ToArray();
|
private readonly string[] ValidTypes = Enum.GetNames(typeof(ItemType)).Concat(new[] { "Name" }).ToArray();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using StardewModdingAPI.Mods.ConsoleCommands.Framework.ItemData;
|
using StardewModdingAPI.Mods.ConsoleCommands.Framework.ItemData;
|
||||||
|
@ -58,7 +58,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
|
||||||
/// <param name="searchWords">The search string to find.</param>
|
/// <param name="searchWords">The search string to find.</param>
|
||||||
private IEnumerable<SearchableItem> GetItems(string[] searchWords)
|
private IEnumerable<SearchableItem> GetItems(string[] searchWords)
|
||||||
{
|
{
|
||||||
// normalise search term
|
// normalize search term
|
||||||
searchWords = searchWords?.Where(word => !string.IsNullOrWhiteSpace(word)).ToArray();
|
searchWords = searchWords?.Where(word => !string.IsNullOrWhiteSpace(word)).ToArray();
|
||||||
if (searchWords?.Any() == false)
|
if (searchWords?.Any() == false)
|
||||||
searchWords = null;
|
searchWords = null;
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World
|
||||||
{
|
{
|
||||||
for (int i = 0; i > intervals; i--)
|
for (int i = 0; i > intervals; i--)
|
||||||
{
|
{
|
||||||
Game1.timeOfDay = FromTimeSpan(ToTimeSpan(Game1.timeOfDay).Subtract(TimeSpan.FromMinutes(20))); // offset 20 mins so game updates to next interval
|
Game1.timeOfDay = FromTimeSpan(ToTimeSpan(Game1.timeOfDay).Subtract(TimeSpan.FromMinutes(20))); // offset 20 minutes so game updates to next interval
|
||||||
Game1.performTenMinuteClockUpdate();
|
Game1.performTenMinuteClockUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ using StardewModdingAPI.Framework;
|
||||||
using StardewModdingAPI.Framework.ModLoading;
|
using StardewModdingAPI.Framework.ModLoading;
|
||||||
using StardewModdingAPI.Toolkit;
|
using StardewModdingAPI.Toolkit;
|
||||||
using StardewModdingAPI.Toolkit.Framework.ModData;
|
using StardewModdingAPI.Toolkit.Framework.ModData;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation.Models;
|
using StardewModdingAPI.Toolkit.Serialization.Models;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Tests.Core
|
namespace StardewModdingAPI.Tests.Core
|
||||||
{
|
{
|
||||||
|
@ -55,7 +55,7 @@ namespace StardewModdingAPI.Tests.Core
|
||||||
Assert.IsNotNull(mod.Error, "The mod metadata did not have an error message set.");
|
Assert.IsNotNull(mod.Error, "The mod metadata did not have an error message set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test(Description = "Assert that the resolver correctly reads manifest data from a randomised file.")]
|
[Test(Description = "Assert that the resolver correctly reads manifest data from a randomized file.")]
|
||||||
public void ReadBasicManifest_CanReadFile()
|
public void ReadBasicManifest_CanReadFile()
|
||||||
{
|
{
|
||||||
// create manifest data
|
// create manifest data
|
||||||
|
@ -468,7 +468,7 @@ namespace StardewModdingAPI.Tests.Core
|
||||||
return Path.Combine(Path.GetTempPath(), "smapi-unit-tests", Guid.NewGuid().ToString("N"));
|
return Path.Combine(Path.GetTempPath(), "smapi-unit-tests", Guid.NewGuid().ToString("N"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a randomised basic manifest.</summary>
|
/// <summary>Get a randomized basic manifest.</summary>
|
||||||
/// <param name="id">The <see cref="IManifest.UniqueID"/> value, or <c>null</c> for a generated value.</param>
|
/// <param name="id">The <see cref="IManifest.UniqueID"/> value, or <c>null</c> for a generated value.</param>
|
||||||
/// <param name="name">The <see cref="IManifest.Name"/> value, or <c>null</c> for a generated value.</param>
|
/// <param name="name">The <see cref="IManifest.Name"/> value, or <c>null</c> for a generated value.</param>
|
||||||
/// <param name="version">The <see cref="IManifest.Version"/> value, or <c>null</c> for a generated value.</param>
|
/// <param name="version">The <see cref="IManifest.Version"/> value, or <c>null</c> for a generated value.</param>
|
||||||
|
@ -492,14 +492,14 @@ namespace StardewModdingAPI.Tests.Core
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a randomised basic manifest.</summary>
|
/// <summary>Get a randomized basic manifest.</summary>
|
||||||
/// <param name="uniqueID">The mod's name and unique ID.</param>
|
/// <param name="uniqueID">The mod's name and unique ID.</param>
|
||||||
private Mock<IModMetadata> GetMetadata(string uniqueID)
|
private Mock<IModMetadata> GetMetadata(string uniqueID)
|
||||||
{
|
{
|
||||||
return this.GetMetadata(this.GetManifest(uniqueID, "1.0"));
|
return this.GetMetadata(this.GetManifest(uniqueID, "1.0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a randomised basic manifest.</summary>
|
/// <summary>Get a randomized basic manifest.</summary>
|
||||||
/// <param name="uniqueID">The mod's name and unique ID.</param>
|
/// <param name="uniqueID">The mod's name and unique ID.</param>
|
||||||
/// <param name="dependencies">The dependencies this mod requires.</param>
|
/// <param name="dependencies">The dependencies this mod requires.</param>
|
||||||
/// <param name="allowStatusChange">Whether the code being tested is allowed to change the mod status.</param>
|
/// <param name="allowStatusChange">Whether the code being tested is allowed to change the mod status.</param>
|
||||||
|
@ -509,7 +509,7 @@ namespace StardewModdingAPI.Tests.Core
|
||||||
return this.GetMetadata(manifest, allowStatusChange);
|
return this.GetMetadata(manifest, allowStatusChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a randomised basic manifest.</summary>
|
/// <summary>Get a randomized basic manifest.</summary>
|
||||||
/// <param name="manifest">The mod manifest.</param>
|
/// <param name="manifest">The mod manifest.</param>
|
||||||
/// <param name="allowStatusChange">Whether the code being tested is allowed to change the mod status.</param>
|
/// <param name="allowStatusChange">Whether the code being tested is allowed to change the mod status.</param>
|
||||||
private Mock<IModMetadata> GetMetadata(IManifest manifest, bool allowStatusChange = false)
|
private Mock<IModMetadata> GetMetadata(IManifest manifest, bool allowStatusChange = false)
|
||||||
|
|
|
@ -245,7 +245,7 @@ namespace StardewModdingAPI.Tests.Core
|
||||||
[TestCase("{{value}}", "value")]
|
[TestCase("{{value}}", "value")]
|
||||||
[TestCase("{{VaLuE}}", "vAlUe")]
|
[TestCase("{{VaLuE}}", "vAlUe")]
|
||||||
[TestCase("{{VaLuE }}", " vAlUe")]
|
[TestCase("{{VaLuE }}", " vAlUe")]
|
||||||
public void Translation_Tokens_KeysAreNormalised(string text, string key)
|
public void Translation_Tokens_KeysAreNormalized(string text, string key)
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
string value = Guid.NewGuid().ToString("N");
|
string value = Guid.NewGuid().ToString("N");
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace StardewModdingAPI.Tests.Toolkit
|
||||||
return string.Join("|", PathUtilities.GetSegments(path));
|
return string.Join("|", PathUtilities.GetSegments(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test(Description = "Assert that NormalisePathSeparators returns the expected values.")]
|
[Test(Description = "Assert that NormalizePathSeparators returns the expected values.")]
|
||||||
#if SMAPI_FOR_WINDOWS
|
#if SMAPI_FOR_WINDOWS
|
||||||
[TestCase("", ExpectedResult = "")]
|
[TestCase("", ExpectedResult = "")]
|
||||||
[TestCase("/", ExpectedResult = "")]
|
[TestCase("/", ExpectedResult = "")]
|
||||||
|
@ -47,9 +47,9 @@ namespace StardewModdingAPI.Tests.Toolkit
|
||||||
[TestCase("C:/boop", ExpectedResult = "C:/boop")]
|
[TestCase("C:/boop", ExpectedResult = "C:/boop")]
|
||||||
[TestCase(@"C:\usr\bin//.././boop.exe", ExpectedResult = "C:/usr/bin/.././boop.exe")]
|
[TestCase(@"C:\usr\bin//.././boop.exe", ExpectedResult = "C:/usr/bin/.././boop.exe")]
|
||||||
#endif
|
#endif
|
||||||
public string NormalisePathSeparators(string path)
|
public string NormalizePathSeparators(string path)
|
||||||
{
|
{
|
||||||
return PathUtilities.NormalisePathSeparators(path);
|
return PathUtilities.NormalizePathSeparators(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test(Description = "Assert that GetRelativePath returns the expected values.")]
|
[Test(Description = "Assert that GetRelativePath returns the expected values.")]
|
||||||
|
|
|
@ -243,19 +243,19 @@ namespace StardewModdingAPI.Tests.Utilities
|
||||||
}
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Serialisable
|
** Serializable
|
||||||
****/
|
****/
|
||||||
[Test(Description = "Assert that SemanticVersion can be round-tripped through JSON with no special configuration.")]
|
[Test(Description = "Assert that SemanticVersion can be round-tripped through JSON with no special configuration.")]
|
||||||
[TestCase("1.0")]
|
[TestCase("1.0")]
|
||||||
public void Serialisable(string versionStr)
|
public void Serializable(string versionStr)
|
||||||
{
|
{
|
||||||
// act
|
// act
|
||||||
string json = JsonConvert.SerializeObject(new SemanticVersion(versionStr));
|
string json = JsonConvert.SerializeObject(new SemanticVersion(versionStr));
|
||||||
SemanticVersion after = JsonConvert.DeserializeObject<SemanticVersion>(json);
|
SemanticVersion after = JsonConvert.DeserializeObject<SemanticVersion>(json);
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.IsNotNull(after, "The semantic version after deserialisation is unexpectedly null.");
|
Assert.IsNotNull(after, "The semantic version after deserialization is unexpectedly null.");
|
||||||
Assert.AreEqual(versionStr, after.ToString(), "The semantic version after deserialisation doesn't match the input version.");
|
Assert.AreEqual(versionStr, after.ToString(), "The semantic version after deserialization doesn't match the input version.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace StardewModdingAPI
|
||||||
/*********
|
/*********
|
||||||
** Accessors
|
** Accessors
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Whether this is a pre-release version.</summary>
|
/// <summary>Whether this is a prerelease version.</summary>
|
||||||
bool IsPrerelease();
|
bool IsPrerelease();
|
||||||
|
|
||||||
/// <summary>Get whether this version is older than the specified version.</summary>
|
/// <summary>Get whether this version is older than the specified version.</summary>
|
||||||
|
|
|
@ -48,7 +48,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
public WikiCompatibilityStatus? CompatibilityStatus { get; set; }
|
public WikiCompatibilityStatus? CompatibilityStatus { get; set; }
|
||||||
|
|
||||||
/// <summary>The human-readable summary of the compatibility status or workaround, without HTML formatitng.</summary>
|
/// <summary>The human-readable summary of the compatibility status or workaround, without HTML formatting.</summary>
|
||||||
public string CompatibilitySummary { get; set; }
|
public string CompatibilitySummary { get; set; }
|
||||||
|
|
||||||
/// <summary>The game or SMAPI version which broke this mod, if applicable.</summary>
|
/// <summary>The game or SMAPI version which broke this mod, if applicable.</summary>
|
||||||
|
@ -62,7 +62,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
public WikiCompatibilityStatus? BetaCompatibilityStatus { get; set; }
|
public WikiCompatibilityStatus? BetaCompatibilityStatus { get; set; }
|
||||||
|
|
||||||
/// <summary>The human-readable summary of the compatibility status or workaround for the Stardew Valley beta (if any), without HTML formatitng.</summary>
|
/// <summary>The human-readable summary of the compatibility status or workaround for the Stardew Valley beta (if any), without HTML formatting.</summary>
|
||||||
public string BetaCompatibilitySummary { get; set; }
|
public string BetaCompatibilitySummary { get; set; }
|
||||||
|
|
||||||
/// <summary>The beta game or SMAPI version which broke this mod, if applicable.</summary>
|
/// <summary>The beta game or SMAPI version which broke this mod, if applicable.</summary>
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
|
||||||
/// <summary>Construct an empty instance.</summary>
|
/// <summary>Construct an empty instance.</summary>
|
||||||
public ModSearchModel()
|
public ModSearchModel()
|
||||||
{
|
{
|
||||||
// needed for JSON deserialising
|
// needed for JSON deserializing
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Construct an instance.</summary>
|
/// <summary>Construct an instance.</summary>
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
|
||||||
/// <summary>Construct an empty instance.</summary>
|
/// <summary>Construct an empty instance.</summary>
|
||||||
public ModSearchEntryModel()
|
public ModSearchEntryModel()
|
||||||
{
|
{
|
||||||
// needed for JSON deserialising
|
// needed for JSON deserializing
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Construct an instance.</summary>
|
/// <summary>Construct an instance.</summary>
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation;
|
using StardewModdingAPI.Toolkit.Serialization;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
|
namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning
|
||||||
IEnumerable<string> paths = this
|
IEnumerable<string> paths = this
|
||||||
.GetCustomInstallPaths(platform)
|
.GetCustomInstallPaths(platform)
|
||||||
.Concat(this.GetDefaultInstallPaths(platform))
|
.Concat(this.GetDefaultInstallPaths(platform))
|
||||||
.Select(PathUtilities.NormalisePathSeparators)
|
.Select(PathUtilities.NormalizePathSeparators)
|
||||||
.Distinct(StringComparer.InvariantCultureIgnoreCase);
|
.Distinct(StringComparer.InvariantCultureIgnoreCase);
|
||||||
|
|
||||||
// yield valid folders
|
// yield valid folders
|
||||||
|
|
|
@ -112,8 +112,8 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
||||||
/*********
|
/*********
|
||||||
** Private methods
|
** Private methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>The method invoked after JSON deserialisation.</summary>
|
/// <summary>The method invoked after JSON deserialization.</summary>
|
||||||
/// <param name="context">The deserialisation context.</param>
|
/// <param name="context">The deserialization context.</param>
|
||||||
[OnDeserialized]
|
[OnDeserialized]
|
||||||
private void OnDeserialized(StreamingContext context)
|
private void OnDeserialized(StreamingContext context)
|
||||||
{
|
{
|
||||||
|
|
|
@ -68,7 +68,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a semantic local version for update checks.</summary>
|
/// <summary>Get a semantic local version for update checks.</summary>
|
||||||
/// <param name="version">The remote version to normalise.</param>
|
/// <param name="version">The remote version to normalize.</param>
|
||||||
public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version)
|
public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version)
|
||||||
{
|
{
|
||||||
return this.MapLocalVersions != null && this.MapLocalVersions.TryGetValue(version.ToString(), out string newVersion)
|
return this.MapLocalVersions != null && this.MapLocalVersions.TryGetValue(version.ToString(), out string newVersion)
|
||||||
|
@ -77,10 +77,10 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a semantic remote version for update checks.</summary>
|
/// <summary>Get a semantic remote version for update checks.</summary>
|
||||||
/// <param name="version">The remote version to normalise.</param>
|
/// <param name="version">The remote version to normalize.</param>
|
||||||
public string GetRemoteVersionForUpdateChecks(string version)
|
public string GetRemoteVersionForUpdateChecks(string version)
|
||||||
{
|
{
|
||||||
// normalise version if possible
|
// normalize version if possible
|
||||||
if (SemanticVersion.TryParse(version, out ISemanticVersion parsed))
|
if (SemanticVersion.TryParse(version, out ISemanticVersion parsed))
|
||||||
version = parsed.ToString();
|
version = parsed.ToString();
|
||||||
|
|
||||||
|
|
|
@ -32,14 +32,14 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Get a semantic local version for update checks.</summary>
|
/// <summary>Get a semantic local version for update checks.</summary>
|
||||||
/// <param name="version">The remote version to normalise.</param>
|
/// <param name="version">The remote version to normalize.</param>
|
||||||
public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version)
|
public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version)
|
||||||
{
|
{
|
||||||
return this.DataRecord.GetLocalVersionForUpdateChecks(version);
|
return this.DataRecord.GetLocalVersionForUpdateChecks(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a semantic remote version for update checks.</summary>
|
/// <summary>Get a semantic remote version for update checks.</summary>
|
||||||
/// <param name="version">The remote version to normalise.</param>
|
/// <param name="version">The remote version to normalize.</param>
|
||||||
public ISemanticVersion GetRemoteVersionForUpdateChecks(ISemanticVersion version)
|
public ISemanticVersion GetRemoteVersionForUpdateChecks(ISemanticVersion version)
|
||||||
{
|
{
|
||||||
if (version == null)
|
if (version == null)
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
||||||
BrokenCodeLoaded = 1,
|
BrokenCodeLoaded = 1,
|
||||||
|
|
||||||
/// <summary>The mod affects the save serializer in a way that may make saves unloadable without the mod.</summary>
|
/// <summary>The mod affects the save serializer in a way that may make saves unloadable without the mod.</summary>
|
||||||
ChangesSaveSerialiser = 2,
|
ChangesSaveSerializer = 2,
|
||||||
|
|
||||||
/// <summary>The mod patches the game in a way that may impact stability.</summary>
|
/// <summary>The mod patches the game in a way that may impact stability.</summary>
|
||||||
PatchesGame = 4,
|
PatchesGame = 4,
|
||||||
|
@ -21,7 +21,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
||||||
/// <summary>The mod uses the <c>dynamic</c> keyword which won't work on Linux/Mac.</summary>
|
/// <summary>The mod uses the <c>dynamic</c> keyword which won't work on Linux/Mac.</summary>
|
||||||
UsesDynamic = 8,
|
UsesDynamic = 8,
|
||||||
|
|
||||||
/// <summary>The mod references specialised 'unvalided update tick' events which may impact stability.</summary>
|
/// <summary>The mod references specialized 'unvalidated update tick' events which may impact stability.</summary>
|
||||||
UsesUnvalidatedUpdateTick = 16,
|
UsesUnvalidatedUpdateTick = 16,
|
||||||
|
|
||||||
/// <summary>The mod has no update keys set.</summary>
|
/// <summary>The mod has no update keys set.</summary>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation.Models;
|
using StardewModdingAPI.Toolkit.Serialization.Models;
|
||||||
using StardewModdingAPI.Toolkit.Utilities;
|
using StardewModdingAPI.Toolkit.Utilities;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Framework.ModScanning
|
namespace StardewModdingAPI.Toolkit.Framework.ModScanning
|
||||||
|
|
|
@ -3,8 +3,8 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation;
|
using StardewModdingAPI.Toolkit.Serialization;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation.Models;
|
using StardewModdingAPI.Toolkit.Serialization.Models;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Framework.ModScanning
|
namespace StardewModdingAPI.Toolkit.Framework.ModScanning
|
||||||
{
|
{
|
||||||
|
@ -118,7 +118,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalise display fields
|
// normalize display fields
|
||||||
if (manifest != null)
|
if (manifest != null)
|
||||||
{
|
{
|
||||||
manifest.Name = this.StripNewlines(manifest.Name);
|
manifest.Name = this.StripNewlines(manifest.Name);
|
||||||
|
|
|
@ -8,7 +8,7 @@ using StardewModdingAPI.Toolkit.Framework.Clients.Wiki;
|
||||||
using StardewModdingAPI.Toolkit.Framework.GameScanning;
|
using StardewModdingAPI.Toolkit.Framework.GameScanning;
|
||||||
using StardewModdingAPI.Toolkit.Framework.ModData;
|
using StardewModdingAPI.Toolkit.Framework.ModData;
|
||||||
using StardewModdingAPI.Toolkit.Framework.ModScanning;
|
using StardewModdingAPI.Toolkit.Framework.ModScanning;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation;
|
using StardewModdingAPI.Toolkit.Serialization;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit
|
namespace StardewModdingAPI.Toolkit
|
||||||
{
|
{
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace StardewModdingAPI.Toolkit
|
||||||
this.MajorVersion = major;
|
this.MajorVersion = major;
|
||||||
this.MinorVersion = minor;
|
this.MinorVersion = minor;
|
||||||
this.PatchVersion = patch;
|
this.PatchVersion = patch;
|
||||||
this.PrereleaseTag = this.GetNormalisedTag(prereleaseTag);
|
this.PrereleaseTag = this.GetNormalizedTag(prereleaseTag);
|
||||||
|
|
||||||
this.AssertValid();
|
this.AssertValid();
|
||||||
}
|
}
|
||||||
|
@ -89,16 +89,16 @@ namespace StardewModdingAPI.Toolkit
|
||||||
if (!match.Success)
|
if (!match.Success)
|
||||||
throw new FormatException($"The input '{version}' isn't a valid semantic version.");
|
throw new FormatException($"The input '{version}' isn't a valid semantic version.");
|
||||||
|
|
||||||
// initialise
|
// initialize
|
||||||
this.MajorVersion = int.Parse(match.Groups["major"].Value);
|
this.MajorVersion = int.Parse(match.Groups["major"].Value);
|
||||||
this.MinorVersion = match.Groups["minor"].Success ? int.Parse(match.Groups["minor"].Value) : 0;
|
this.MinorVersion = match.Groups["minor"].Success ? int.Parse(match.Groups["minor"].Value) : 0;
|
||||||
this.PatchVersion = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0;
|
this.PatchVersion = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0;
|
||||||
this.PrereleaseTag = match.Groups["prerelease"].Success ? this.GetNormalisedTag(match.Groups["prerelease"].Value) : null;
|
this.PrereleaseTag = match.Groups["prerelease"].Success ? this.GetNormalizedTag(match.Groups["prerelease"].Value) : null;
|
||||||
|
|
||||||
this.AssertValid();
|
this.AssertValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version.</summary>
|
/// <summary>Get an integer indicating whether this version precedes (less than 0), supersedes (more than 0), or is equivalent to (0) the specified version.</summary>
|
||||||
/// <param name="other">The version to compare with this instance.</param>
|
/// <param name="other">The version to compare with this instance.</param>
|
||||||
/// <exception cref="ArgumentNullException">The <paramref name="other"/> value is null.</exception>
|
/// <exception cref="ArgumentNullException">The <paramref name="other"/> value is null.</exception>
|
||||||
public int CompareTo(ISemanticVersion other)
|
public int CompareTo(ISemanticVersion other)
|
||||||
|
@ -116,7 +116,7 @@ namespace StardewModdingAPI.Toolkit
|
||||||
return other != null && this.CompareTo(other) == 0;
|
return other != null && this.CompareTo(other) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Whether this is a pre-release version.</summary>
|
/// <summary>Whether this is a prerelease version.</summary>
|
||||||
public bool IsPrerelease()
|
public bool IsPrerelease()
|
||||||
{
|
{
|
||||||
return !string.IsNullOrWhiteSpace(this.PrereleaseTag);
|
return !string.IsNullOrWhiteSpace(this.PrereleaseTag);
|
||||||
|
@ -206,15 +206,15 @@ namespace StardewModdingAPI.Toolkit
|
||||||
/*********
|
/*********
|
||||||
** Private methods
|
** Private methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Get a normalised build tag.</summary>
|
/// <summary>Get a normalized build tag.</summary>
|
||||||
/// <param name="tag">The tag to normalise.</param>
|
/// <param name="tag">The tag to normalize.</param>
|
||||||
private string GetNormalisedTag(string tag)
|
private string GetNormalizedTag(string tag)
|
||||||
{
|
{
|
||||||
tag = tag?.Trim();
|
tag = tag?.Trim();
|
||||||
return !string.IsNullOrWhiteSpace(tag) ? tag : null;
|
return !string.IsNullOrWhiteSpace(tag) ? tag : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version.</summary>
|
/// <summary>Get an integer indicating whether this version precedes (less than 0), supersedes (more than 0), or is equivalent to (0) the specified version.</summary>
|
||||||
/// <param name="otherMajor">The major version to compare with this instance.</param>
|
/// <param name="otherMajor">The major version to compare with this instance.</param>
|
||||||
/// <param name="otherMinor">The minor version to compare with this instance.</param>
|
/// <param name="otherMinor">The minor version to compare with this instance.</param>
|
||||||
/// <param name="otherPatch">The patch version to compare with this instance.</param>
|
/// <param name="otherPatch">The patch version to compare with this instance.</param>
|
||||||
|
@ -235,7 +235,7 @@ namespace StardewModdingAPI.Toolkit
|
||||||
if (this.PrereleaseTag == otherTag)
|
if (this.PrereleaseTag == otherTag)
|
||||||
return same;
|
return same;
|
||||||
|
|
||||||
// stable supercedes pre-release
|
// stable supersedes prerelease
|
||||||
bool curIsStable = string.IsNullOrWhiteSpace(this.PrereleaseTag);
|
bool curIsStable = string.IsNullOrWhiteSpace(this.PrereleaseTag);
|
||||||
bool otherIsStable = string.IsNullOrWhiteSpace(otherTag);
|
bool otherIsStable = string.IsNullOrWhiteSpace(otherTag);
|
||||||
if (curIsStable)
|
if (curIsStable)
|
||||||
|
@ -243,12 +243,12 @@ namespace StardewModdingAPI.Toolkit
|
||||||
if (otherIsStable)
|
if (otherIsStable)
|
||||||
return curOlder;
|
return curOlder;
|
||||||
|
|
||||||
// compare two pre-release tag values
|
// compare two prerelease tag values
|
||||||
string[] curParts = this.PrereleaseTag.Split('.', '-');
|
string[] curParts = this.PrereleaseTag.Split('.', '-');
|
||||||
string[] otherParts = otherTag.Split('.', '-');
|
string[] otherParts = otherTag.Split('.', '-');
|
||||||
for (int i = 0; i < curParts.Length; i++)
|
for (int i = 0; i < curParts.Length; i++)
|
||||||
{
|
{
|
||||||
// longer prerelease tag supercedes if otherwise equal
|
// longer prerelease tag supersedes if otherwise equal
|
||||||
if (otherParts.Length <= i)
|
if (otherParts.Length <= i)
|
||||||
return curNewer;
|
return curNewer;
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation.Models;
|
using StardewModdingAPI.Toolkit.Serialization.Models;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Serialisation.Converters
|
namespace StardewModdingAPI.Toolkit.Serialization.Converters
|
||||||
{
|
{
|
||||||
/// <summary>Handles deserialisation of <see cref="ManifestContentPackFor"/> arrays.</summary>
|
/// <summary>Handles deserialization of <see cref="ManifestContentPackFor"/> arrays.</summary>
|
||||||
public class ManifestContentPackForConverter : JsonConverter
|
public class ManifestContentPackForConverter : JsonConverter
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
|
@ -2,11 +2,11 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation.Models;
|
using StardewModdingAPI.Toolkit.Serialization.Models;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Serialisation.Converters
|
namespace StardewModdingAPI.Toolkit.Serialization.Converters
|
||||||
{
|
{
|
||||||
/// <summary>Handles deserialisation of <see cref="ManifestDependency"/> arrays.</summary>
|
/// <summary>Handles deserialization of <see cref="ManifestDependency"/> arrays.</summary>
|
||||||
internal class ManifestDependencyArrayConverter : JsonConverter
|
internal class ManifestDependencyArrayConverter : JsonConverter
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
|
@ -2,9 +2,9 @@ using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Serialisation.Converters
|
namespace StardewModdingAPI.Toolkit.Serialization.Converters
|
||||||
{
|
{
|
||||||
/// <summary>Handles deserialisation of <see cref="ISemanticVersion"/>.</summary>
|
/// <summary>Handles deserialization of <see cref="ISemanticVersion"/>.</summary>
|
||||||
internal class SemanticVersionConverter : JsonConverter
|
internal class SemanticVersionConverter : JsonConverter
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
|
@ -2,10 +2,10 @@ using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Serialisation.Converters
|
namespace StardewModdingAPI.Toolkit.Serialization.Converters
|
||||||
{
|
{
|
||||||
/// <summary>The base implementation for simplified converters which deserialise <typeparamref name="T"/> without overriding serialisation.</summary>
|
/// <summary>The base implementation for simplified converters which deserialize <typeparamref name="T"/> without overriding serialization.</summary>
|
||||||
/// <typeparam name="T">The type to deserialise.</typeparam>
|
/// <typeparam name="T">The type to deserialize.</typeparam>
|
||||||
internal abstract class SimpleReadOnlyConverter<T> : JsonConverter
|
internal abstract class SimpleReadOnlyConverter<T> : JsonConverter
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Serialisation
|
namespace StardewModdingAPI.Toolkit.Serialization
|
||||||
{
|
{
|
||||||
/// <summary>Provides extension methods for parsing JSON.</summary>
|
/// <summary>Provides extension methods for parsing JSON.</summary>
|
||||||
public static class JsonExtensions
|
public static class JsonExtensions
|
|
@ -3,9 +3,9 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation.Converters;
|
using StardewModdingAPI.Toolkit.Serialization.Converters;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Serialisation
|
namespace StardewModdingAPI.Toolkit.Serialization
|
||||||
{
|
{
|
||||||
/// <summary>Encapsulates SMAPI's JSON file parsing.</summary>
|
/// <summary>Encapsulates SMAPI's JSON file parsing.</summary>
|
||||||
public class JsonHelper
|
public class JsonHelper
|
||||||
|
@ -13,7 +13,7 @@ namespace StardewModdingAPI.Toolkit.Serialisation
|
||||||
/*********
|
/*********
|
||||||
** Accessors
|
** Accessors
|
||||||
*********/
|
*********/
|
||||||
/// <summary>The JSON settings to use when serialising and deserialising files.</summary>
|
/// <summary>The JSON settings to use when serializing and deserializing files.</summary>
|
||||||
public JsonSerializerSettings JsonSettings { get; } = new JsonSerializerSettings
|
public JsonSerializerSettings JsonSettings { get; } = new JsonSerializerSettings
|
||||||
{
|
{
|
||||||
Formatting = Formatting.Indented,
|
Formatting = Formatting.Indented,
|
||||||
|
@ -31,7 +31,7 @@ namespace StardewModdingAPI.Toolkit.Serialisation
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Read a JSON file.</summary>
|
/// <summary>Read a JSON file.</summary>
|
||||||
/// <typeparam name="TModel">The model type.</typeparam>
|
/// <typeparam name="TModel">The model type.</typeparam>
|
||||||
/// <param name="fullPath">The absolete file path.</param>
|
/// <param name="fullPath">The absolute file path.</param>
|
||||||
/// <param name="result">The parsed content model.</param>
|
/// <param name="result">The parsed content model.</param>
|
||||||
/// <returns>Returns false if the file doesn't exist, else true.</returns>
|
/// <returns>Returns false if the file doesn't exist, else true.</returns>
|
||||||
/// <exception cref="ArgumentException">The given <paramref name="fullPath"/> is empty or invalid.</exception>
|
/// <exception cref="ArgumentException">The given <paramref name="fullPath"/> is empty or invalid.</exception>
|
||||||
|
@ -54,10 +54,10 @@ namespace StardewModdingAPI.Toolkit.Serialisation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// deserialise model
|
// deserialize model
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = this.Deserialise<TModel>(json);
|
result = this.Deserialize<TModel>(json);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -77,7 +77,7 @@ namespace StardewModdingAPI.Toolkit.Serialisation
|
||||||
|
|
||||||
/// <summary>Save to a JSON file.</summary>
|
/// <summary>Save to a JSON file.</summary>
|
||||||
/// <typeparam name="TModel">The model type.</typeparam>
|
/// <typeparam name="TModel">The model type.</typeparam>
|
||||||
/// <param name="fullPath">The absolete file path.</param>
|
/// <param name="fullPath">The absolute file path.</param>
|
||||||
/// <param name="model">The model to save.</param>
|
/// <param name="model">The model to save.</param>
|
||||||
/// <exception cref="InvalidOperationException">The given path is empty or invalid.</exception>
|
/// <exception cref="InvalidOperationException">The given path is empty or invalid.</exception>
|
||||||
public void WriteJsonFile<TModel>(string fullPath, TModel model)
|
public void WriteJsonFile<TModel>(string fullPath, TModel model)
|
||||||
|
@ -95,14 +95,14 @@ namespace StardewModdingAPI.Toolkit.Serialisation
|
||||||
Directory.CreateDirectory(dir);
|
Directory.CreateDirectory(dir);
|
||||||
|
|
||||||
// write file
|
// write file
|
||||||
string json = this.Serialise(model);
|
string json = this.Serialize(model);
|
||||||
File.WriteAllText(fullPath, json);
|
File.WriteAllText(fullPath, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Deserialize JSON text if possible.</summary>
|
/// <summary>Deserialize JSON text if possible.</summary>
|
||||||
/// <typeparam name="TModel">The model type.</typeparam>
|
/// <typeparam name="TModel">The model type.</typeparam>
|
||||||
/// <param name="json">The raw JSON text.</param>
|
/// <param name="json">The raw JSON text.</param>
|
||||||
public TModel Deserialise<TModel>(string json)
|
public TModel Deserialize<TModel>(string json)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -126,9 +126,9 @@ namespace StardewModdingAPI.Toolkit.Serialisation
|
||||||
|
|
||||||
/// <summary>Serialize a model to JSON text.</summary>
|
/// <summary>Serialize a model to JSON text.</summary>
|
||||||
/// <typeparam name="TModel">The model type.</typeparam>
|
/// <typeparam name="TModel">The model type.</typeparam>
|
||||||
/// <param name="model">The model to serialise.</param>
|
/// <param name="model">The model to serialize.</param>
|
||||||
/// <param name="formatting">The formatting to apply.</param>
|
/// <param name="formatting">The formatting to apply.</param>
|
||||||
public string Serialise<TModel>(TModel model, Formatting formatting = Formatting.Indented)
|
public string Serialize<TModel>(TModel model, Formatting formatting = Formatting.Indented)
|
||||||
{
|
{
|
||||||
return JsonConvert.SerializeObject(model, formatting, this.JsonSettings);
|
return JsonConvert.SerializeObject(model, formatting, this.JsonSettings);
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation.Converters;
|
using StardewModdingAPI.Toolkit.Serialization.Converters;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Serialisation.Models
|
namespace StardewModdingAPI.Toolkit.Serialization.Models
|
||||||
{
|
{
|
||||||
/// <summary>A manifest which describes a mod for SMAPI.</summary>
|
/// <summary>A manifest which describes a mod for SMAPI.</summary>
|
||||||
public class Manifest : IManifest
|
public class Manifest : IManifest
|
|
@ -1,4 +1,4 @@
|
||||||
namespace StardewModdingAPI.Toolkit.Serialisation.Models
|
namespace StardewModdingAPI.Toolkit.Serialization.Models
|
||||||
{
|
{
|
||||||
/// <summary>Indicates which mod can read the content pack represented by the containing manifest.</summary>
|
/// <summary>Indicates which mod can read the content pack represented by the containing manifest.</summary>
|
||||||
public class ManifestContentPackFor : IManifestContentPackFor
|
public class ManifestContentPackFor : IManifestContentPackFor
|
|
@ -1,4 +1,4 @@
|
||||||
namespace StardewModdingAPI.Toolkit.Serialisation.Models
|
namespace StardewModdingAPI.Toolkit.Serialization.Models
|
||||||
{
|
{
|
||||||
/// <summary>A mod dependency listed in a mod manifest.</summary>
|
/// <summary>A mod dependency listed in a mod manifest.</summary>
|
||||||
public class ManifestDependency : IManifestDependency
|
public class ManifestDependency : IManifestDependency
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Serialisation
|
namespace StardewModdingAPI.Toolkit.Serialization
|
||||||
{
|
{
|
||||||
/// <summary>A format exception which provides a user-facing error message.</summary>
|
/// <summary>A format exception which provides a user-facing error message.</summary>
|
||||||
internal class SParseException : FormatException
|
internal class SParseException : FormatException
|
|
@ -6,7 +6,7 @@ using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Toolkit.Utilities
|
namespace StardewModdingAPI.Toolkit.Utilities
|
||||||
{
|
{
|
||||||
/// <summary>Provides utilities for normalising file paths.</summary>
|
/// <summary>Provides utilities for normalizing file paths.</summary>
|
||||||
public static class PathUtilities
|
public static class PathUtilities
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
||||||
|
@ -15,14 +15,14 @@ namespace StardewModdingAPI.Toolkit.Utilities
|
||||||
/// <summary>The possible directory separator characters in a file path.</summary>
|
/// <summary>The possible directory separator characters in a file path.</summary>
|
||||||
private static readonly char[] PossiblePathSeparators = new[] { '/', '\\', Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }.Distinct().ToArray();
|
private static readonly char[] PossiblePathSeparators = new[] { '/', '\\', Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }.Distinct().ToArray();
|
||||||
|
|
||||||
/// <summary>The preferred directory separator chaeacter in an asset key.</summary>
|
/// <summary>The preferred directory separator character in an asset key.</summary>
|
||||||
private static readonly string PreferredPathSeparator = Path.DirectorySeparatorChar.ToString();
|
private static readonly string PreferredPathSeparator = Path.DirectorySeparatorChar.ToString();
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Get the segments from a path (e.g. <c>/usr/bin/boop</c> => <c>usr</c>, <c>bin</c>, and <c>boop</c>).</summary>
|
/// <summary>Get the segments from a path (e.g. <c>/usr/bin/example</c> => <c>usr</c>, <c>bin</c>, and <c>example</c>).</summary>
|
||||||
/// <param name="path">The path to split.</param>
|
/// <param name="path">The path to split.</param>
|
||||||
/// <param name="limit">The number of segments to match. Any additional segments will be merged into the last returned part.</param>
|
/// <param name="limit">The number of segments to match. Any additional segments will be merged into the last returned part.</param>
|
||||||
public static string[] GetSegments(string path, int? limit = null)
|
public static string[] GetSegments(string path, int? limit = null)
|
||||||
|
@ -32,16 +32,16 @@ namespace StardewModdingAPI.Toolkit.Utilities
|
||||||
: path.Split(PathUtilities.PossiblePathSeparators, StringSplitOptions.RemoveEmptyEntries);
|
: path.Split(PathUtilities.PossiblePathSeparators, StringSplitOptions.RemoveEmptyEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Normalise path separators in a file path.</summary>
|
/// <summary>Normalize path separators in a file path.</summary>
|
||||||
/// <param name="path">The file path to normalise.</param>
|
/// <param name="path">The file path to normalize.</param>
|
||||||
[Pure]
|
[Pure]
|
||||||
public static string NormalisePathSeparators(string path)
|
public static string NormalizePathSeparators(string path)
|
||||||
{
|
{
|
||||||
string[] parts = PathUtilities.GetSegments(path);
|
string[] parts = PathUtilities.GetSegments(path);
|
||||||
string normalised = string.Join(PathUtilities.PreferredPathSeparator, parts);
|
string normalized = string.Join(PathUtilities.PreferredPathSeparator, parts);
|
||||||
if (path.StartsWith(PathUtilities.PreferredPathSeparator))
|
if (path.StartsWith(PathUtilities.PreferredPathSeparator))
|
||||||
normalised = PathUtilities.PreferredPathSeparator + normalised; // keep root slash
|
normalized = PathUtilities.PreferredPathSeparator + normalized; // keep root slash
|
||||||
return normalised;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a directory or file path relative to a given source path.</summary>
|
/// <summary>Get a directory or file path relative to a given source path.</summary>
|
||||||
|
@ -57,7 +57,7 @@ namespace StardewModdingAPI.Toolkit.Utilities
|
||||||
throw new InvalidOperationException($"Can't get path for '{targetPath}' relative to '{sourceDir}'.");
|
throw new InvalidOperationException($"Can't get path for '{targetPath}' relative to '{sourceDir}'.");
|
||||||
|
|
||||||
// get relative path
|
// get relative path
|
||||||
string relative = PathUtilities.NormalisePathSeparators(Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString()));
|
string relative = PathUtilities.NormalizePathSeparators(Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString()));
|
||||||
if (relative == "")
|
if (relative == "")
|
||||||
relative = "./";
|
relative = "./";
|
||||||
return relative;
|
return relative;
|
||||||
|
|
|
@ -11,7 +11,7 @@ using StardewModdingAPI.Web.Framework.Caching.Wiki;
|
||||||
namespace StardewModdingAPI.Web
|
namespace StardewModdingAPI.Web
|
||||||
{
|
{
|
||||||
/// <summary>A hosted service which runs background data updates.</summary>
|
/// <summary>A hosted service which runs background data updates.</summary>
|
||||||
/// <remarks>Task methods need to be static, since otherwise Hangfire will try to serialise the entire instance.</remarks>
|
/// <remarks>Task methods need to be static, since otherwise Hangfire will try to serialize the entire instance.</remarks>
|
||||||
internal class BackgroundService : IHostedService, IDisposable
|
internal class BackgroundService : IHostedService, IDisposable
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
||||||
|
@ -94,8 +94,8 @@ namespace StardewModdingAPI.Web
|
||||||
/*********
|
/*********
|
||||||
** Private method
|
** Private method
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Initialise the background service if it's not already initialised.</summary>
|
/// <summary>Initialize the background service if it's not already initialized.</summary>
|
||||||
/// <exception cref="InvalidOperationException">The background service is already initialised.</exception>
|
/// <exception cref="InvalidOperationException">The background service is already initialized.</exception>
|
||||||
private void TryInit()
|
private void TryInit()
|
||||||
{
|
{
|
||||||
if (BackgroundService.JobServer != null)
|
if (BackgroundService.JobServer != null)
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace StardewModdingAPI.Web.Controllers
|
||||||
[Route("json/{schemaName}/{id}")]
|
[Route("json/{schemaName}/{id}")]
|
||||||
public async Task<ViewResult> Index(string schemaName = null, string id = null)
|
public async Task<ViewResult> Index(string schemaName = null, string id = null)
|
||||||
{
|
{
|
||||||
schemaName = this.NormaliseSchemaName(schemaName);
|
schemaName = this.NormalizeSchemaName(schemaName);
|
||||||
|
|
||||||
var result = new JsonValidatorModel(this.SectionUrl, id, schemaName, this.SchemaFormats);
|
var result = new JsonValidatorModel(this.SectionUrl, id, schemaName, this.SchemaFormats);
|
||||||
if (string.IsNullOrWhiteSpace(id))
|
if (string.IsNullOrWhiteSpace(id))
|
||||||
|
@ -143,8 +143,8 @@ namespace StardewModdingAPI.Web.Controllers
|
||||||
if (request == null)
|
if (request == null)
|
||||||
return this.View("Index", new JsonValidatorModel(this.SectionUrl, null, null, this.SchemaFormats).SetUploadError("The request seems to be invalid."));
|
return this.View("Index", new JsonValidatorModel(this.SectionUrl, null, null, this.SchemaFormats).SetUploadError("The request seems to be invalid."));
|
||||||
|
|
||||||
// normalise schema name
|
// normalize schema name
|
||||||
string schemaName = this.NormaliseSchemaName(request.SchemaName);
|
string schemaName = this.NormalizeSchemaName(request.SchemaName);
|
||||||
|
|
||||||
// get raw log text
|
// get raw log text
|
||||||
string input = request.Content;
|
string input = request.Content;
|
||||||
|
@ -178,9 +178,9 @@ namespace StardewModdingAPI.Web.Controllers
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a normalised schema name, or the <see cref="DefaultSchemaID"/> if blank.</summary>
|
/// <summary>Get a normalized schema name, or the <see cref="DefaultSchemaID"/> if blank.</summary>
|
||||||
/// <param name="schemaName">The raw schema name to normalise.</param>
|
/// <param name="schemaName">The raw schema name to normalize.</param>
|
||||||
private string NormaliseSchemaName(string schemaName)
|
private string NormalizeSchemaName(string schemaName)
|
||||||
{
|
{
|
||||||
schemaName = schemaName?.Trim().ToLower();
|
schemaName = schemaName?.Trim().ToLower();
|
||||||
return !string.IsNullOrWhiteSpace(schemaName)
|
return !string.IsNullOrWhiteSpace(schemaName)
|
||||||
|
@ -192,7 +192,7 @@ namespace StardewModdingAPI.Web.Controllers
|
||||||
/// <param name="id">The schema ID.</param>
|
/// <param name="id">The schema ID.</param>
|
||||||
private FileInfo FindSchemaFile(string id)
|
private FileInfo FindSchemaFile(string id)
|
||||||
{
|
{
|
||||||
// normalise ID
|
// normalize ID
|
||||||
id = id?.Trim().ToLower();
|
id = id?.Trim().ToLower();
|
||||||
if (string.IsNullOrWhiteSpace(id))
|
if (string.IsNullOrWhiteSpace(id))
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -120,7 +120,7 @@ namespace StardewModdingAPI.Web.Controllers
|
||||||
/// <returns>Returns the mod data if found, else <c>null</c>.</returns>
|
/// <returns>Returns the mod data if found, else <c>null</c>.</returns>
|
||||||
private async Task<ModEntryModel> GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata)
|
private async Task<ModEntryModel> GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata)
|
||||||
{
|
{
|
||||||
// crossreference data
|
// cross-reference data
|
||||||
ModDataRecord record = this.ModDatabase.Get(search.ID);
|
ModDataRecord record = this.ModDatabase.Get(search.ID);
|
||||||
WikiModEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.InvariantCultureIgnoreCase));
|
WikiModEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.InvariantCultureIgnoreCase));
|
||||||
UpdateKey[] updateKeys = this.GetUpdateKeys(search.UpdateKeys, record, wikiEntry).ToArray();
|
UpdateKey[] updateKeys = this.GetUpdateKeys(search.UpdateKeys, record, wikiEntry).ToArray();
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace StardewModdingAPI.Web.Framework
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Called early in the filter pipeline to confirm request is authorized.</summary>
|
/// <summary>Called early in the filter pipeline to confirm request is authorized.</summary>
|
||||||
/// <param name="context">The authorisation filter context.</param>
|
/// <param name="context">The authorization filter context.</param>
|
||||||
public void OnAuthorization(AuthorizationFilterContext context)
|
public void OnAuthorization(AuthorizationFilterContext context)
|
||||||
{
|
{
|
||||||
IFeatureCollection features = context.HttpContext.Features;
|
IFeatureCollection features = context.HttpContext.Features;
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace StardewModdingAPI.Web.Framework.Caching.Mods
|
||||||
public bool TryGetMod(ModRepositoryKey site, string id, out CachedMod mod, bool markRequested = true)
|
public bool TryGetMod(ModRepositoryKey site, string id, out CachedMod mod, bool markRequested = true)
|
||||||
{
|
{
|
||||||
// get mod
|
// get mod
|
||||||
id = this.NormaliseId(id);
|
id = this.NormalizeId(id);
|
||||||
mod = this.Mods.Find(entry => entry.ID == id && entry.Site == site).FirstOrDefault();
|
mod = this.Mods.Find(entry => entry.ID == id && entry.Site == site).FirstOrDefault();
|
||||||
if (mod == null)
|
if (mod == null)
|
||||||
return false;
|
return false;
|
||||||
|
@ -62,7 +62,7 @@ namespace StardewModdingAPI.Web.Framework.Caching.Mods
|
||||||
/// <param name="cachedMod">The stored mod record.</param>
|
/// <param name="cachedMod">The stored mod record.</param>
|
||||||
public void SaveMod(ModRepositoryKey site, string id, ModInfoModel mod, out CachedMod cachedMod)
|
public void SaveMod(ModRepositoryKey site, string id, ModInfoModel mod, out CachedMod cachedMod)
|
||||||
{
|
{
|
||||||
id = this.NormaliseId(id);
|
id = this.NormalizeId(id);
|
||||||
|
|
||||||
cachedMod = this.SaveMod(new CachedMod(site, id, mod));
|
cachedMod = this.SaveMod(new CachedMod(site, id, mod));
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ namespace StardewModdingAPI.Web.Framework.Caching.Mods
|
||||||
/// <param name="mod">The mod data.</param>
|
/// <param name="mod">The mod data.</param>
|
||||||
public CachedMod SaveMod(CachedMod mod)
|
public CachedMod SaveMod(CachedMod mod)
|
||||||
{
|
{
|
||||||
string id = this.NormaliseId(mod.ID);
|
string id = this.NormalizeId(mod.ID);
|
||||||
|
|
||||||
this.Mods.ReplaceOne(
|
this.Mods.ReplaceOne(
|
||||||
entry => entry.ID == id && entry.Site == mod.Site,
|
entry => entry.ID == id && entry.Site == mod.Site,
|
||||||
|
@ -94,9 +94,9 @@ namespace StardewModdingAPI.Web.Framework.Caching.Mods
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Normalise a mod ID for case-insensitive search.</summary>
|
/// <summary>Normalize a mod ID for case-insensitive search.</summary>
|
||||||
/// <param name="id">The mod ID.</param>
|
/// <param name="id">The mod ID.</param>
|
||||||
public string NormaliseId(string id)
|
public string NormalizeId(string id)
|
||||||
{
|
{
|
||||||
return id.Trim().ToLower();
|
return id.Trim().ToLower();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ using MongoDB.Bson.Serialization.Serializers;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Web.Framework.Caching
|
namespace StardewModdingAPI.Web.Framework.Caching
|
||||||
{
|
{
|
||||||
/// <summary>Serialises <see cref="DateTimeOffset"/> to a UTC date field instead of the default array.</summary>
|
/// <summary>Serializes <see cref="DateTimeOffset"/> to a UTC date field instead of the default array.</summary>
|
||||||
public class UtcDateTimeOffsetSerializer : StructSerializerBase<DateTimeOffset>
|
public class UtcDateTimeOffsetSerializer : StructSerializerBase<DateTimeOffset>
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
||||||
|
|
|
@ -2,7 +2,7 @@ using Hangfire.Dashboard;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Web.Framework
|
namespace StardewModdingAPI.Web.Framework
|
||||||
{
|
{
|
||||||
/// <summary>Authorises requests to access the Hangfire job dashboard.</summary>
|
/// <summary>Authorizes requests to access the Hangfire job dashboard.</summary>
|
||||||
internal class JobDashboardAuthorizationFilter : IDashboardAuthorizationFilter
|
internal class JobDashboardAuthorizationFilter : IDashboardAuthorizationFilter
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
||||||
|
@ -15,7 +15,7 @@ namespace StardewModdingAPI.Web.Framework
|
||||||
/*********
|
/*********
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Authorise a request.</summary>
|
/// <summary>Authorize a request.</summary>
|
||||||
/// <param name="context">The dashboard context.</param>
|
/// <param name="context">The dashboard context.</param>
|
||||||
public bool Authorize(DashboardContext context)
|
public bool Authorize(DashboardContext context)
|
||||||
{
|
{
|
||||||
|
|
|
@ -221,7 +221,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// finalise log
|
// finalize log
|
||||||
gameMod.Version = log.GameVersion;
|
gameMod.Version = log.GameVersion;
|
||||||
log.Mods = new[] { gameMod, smapiMod }.Concat(mods.Values.OrderBy(p => p.Name)).ToArray();
|
log.Mods = new[] { gameMod, smapiMod }.Concat(mods.Values.OrderBy(p => p.Name)).ToArray();
|
||||||
return log;
|
return log;
|
||||||
|
|
|
@ -34,9 +34,9 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories
|
||||||
this.VendorKey = vendorKey;
|
this.VendorKey = vendorKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Normalise a version string.</summary>
|
/// <summary>Normalize a version string.</summary>
|
||||||
/// <param name="version">The version to normalise.</param>
|
/// <param name="version">The version to normalize.</param>
|
||||||
protected string NormaliseVersion(string version)
|
protected string NormalizeVersion(string version)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(version))
|
if (string.IsNullOrWhiteSpace(version))
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories
|
||||||
{
|
{
|
||||||
var mod = await this.Client.GetModAsync(realID);
|
var mod = await this.Client.GetModAsync(realID);
|
||||||
return mod != null
|
return mod != null
|
||||||
? new ModInfoModel(name: mod.Name, version: this.NormaliseVersion(mod.Version), url: mod.Url)
|
? new ModInfoModel(name: mod.Name, version: this.NormalizeVersion(mod.Version), url: mod.Url)
|
||||||
: new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, "Found no Chucklefish mod with this ID.");
|
: new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, "Found no Chucklefish mod with this ID.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
@ -65,7 +65,7 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories
|
||||||
}
|
}
|
||||||
|
|
||||||
// return data
|
// return data
|
||||||
return result.SetVersions(version: this.NormaliseVersion(latest.Tag), previewVersion: this.NormaliseVersion(preview?.Tag));
|
return result.SetVersions(version: this.NormalizeVersion(latest.Tag), previewVersion: this.NormalizeVersion(preview?.Tag));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,7 +48,7 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories
|
||||||
return new ModInfoModel().SetError(remoteStatus, mod.Error);
|
return new ModInfoModel().SetError(remoteStatus, mod.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ModInfoModel(name: mod.Name, version: this.NormaliseVersion(mod.Version), previewVersion: mod.LatestFileVersion?.ToString(), url: mod.Url);
|
return new ModInfoModel(name: mod.Name, version: this.NormalizeVersion(mod.Version), previewVersion: mod.LatestFileVersion?.ToString(), url: mod.Url);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||||
using MongoDB.Bson.Serialization;
|
using MongoDB.Bson.Serialization;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation;
|
using StardewModdingAPI.Toolkit.Serialization;
|
||||||
using StardewModdingAPI.Web.Framework;
|
using StardewModdingAPI.Web.Framework;
|
||||||
using StardewModdingAPI.Web.Framework.Caching;
|
using StardewModdingAPI.Web.Framework.Caching;
|
||||||
using StardewModdingAPI.Web.Framework.Caching.Mods;
|
using StardewModdingAPI.Web.Framework.Caching.Mods;
|
||||||
|
|
|
@ -81,7 +81,7 @@ namespace StardewModdingAPI.Web.ViewModels
|
||||||
.ToDictionary(group => group.Key, group => group.ToArray());
|
.ToDictionary(group => group.Key, group => group.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a sanitised mod name that's safe to use in anchors, attributes, and URLs.</summary>
|
/// <summary>Get a sanitized mod name that's safe to use in anchors, attributes, and URLs.</summary>
|
||||||
/// <param name="modName">The mod name.</param>
|
/// <param name="modName">The mod name.</param>
|
||||||
public string GetSlug(string modName)
|
public string GetSlug(string modName)
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,7 +120,7 @@ smapi.jsonValidator = function (sectionUrl, pasteID) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise the JSON validator page.
|
* Initialize the JSON validator page.
|
||||||
*/
|
*/
|
||||||
var init = function () {
|
var init = function () {
|
||||||
// set initial code formatting
|
// set initial code formatting
|
||||||
|
|
|
@ -107,7 +107,7 @@
|
||||||
},
|
},
|
||||||
"Target": {
|
"Target": {
|
||||||
"title": "Target asset",
|
"title": "Target asset",
|
||||||
"description": "The game asset you want to patch (or multiple comma-delimited assets). This is the file path inside your game's Content folder, without the file extension or language (like Animals/Dinosaur to edit Content/Animals/Dinosaur.xnb). This field supports tokens and capitalisation doesn't matter. Your changes are applied in all languages unless you specify a language condition.",
|
"description": "The game asset you want to patch (or multiple comma-delimited assets). This is the file path inside your game's Content folder, without the file extension or language (like Animals/Dinosaur to edit Content/Animals/Dinosaur.xnb). This field supports tokens and capitalization doesn't matter. Your changes are applied in all languages unless you specify a language condition.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"not": {
|
"not": {
|
||||||
"pattern": "^ *[cC][oO][nN][tT][eE][nN][tT]/|\\.[xX][nN][bB] *$|\\.[a-zA-Z][a-zA-Z]-[a-zA-Z][a-zA-Z](?:.xnb)? *$"
|
"pattern": "^ *[cC][oO][nN][tT][eE][nN][tT]/|\\.[xX][nN][bB] *$|\\.[a-zA-Z][a-zA-Z]-[a-zA-Z][a-zA-Z](?:.xnb)? *$"
|
||||||
|
@ -140,7 +140,7 @@
|
||||||
},
|
},
|
||||||
"FromFile": {
|
"FromFile": {
|
||||||
"title": "Source file",
|
"title": "Source file",
|
||||||
"description": "The relative file path in your content pack folder to load instead (like 'assets/dinosaur.png'). This can be a .json (data), .png (image), .tbin (map), or .xnb file. This field supports tokens and capitalisation doesn't matter.",
|
"description": "The relative file path in your content pack folder to load instead (like 'assets/dinosaur.png'). This can be a .json (data), .png (image), .tbin (map), or .xnb file. This field supports tokens and capitalization doesn't matter.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{
|
{
|
||||||
|
@ -310,7 +310,7 @@
|
||||||
"then": {
|
"then": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"FromFile": {
|
"FromFile": {
|
||||||
"description": "The relative path to the map in your content pack folder from which to copy (like assets/town.tbin). This can be a .tbin or .xnb file. This field supports tokens and capitalisation doesn't matter.\nContent Patcher will handle tilesheets referenced by the FromFile map for you if it's a .tbin file:\n - If a tilesheet isn't referenced by the target map, Content Patcher will add it for you (with a z_ ID prefix to avoid conflicts with hardcoded game logic). If the source map has a custom version of a tilesheet that's already referenced, it'll be added as a separate tilesheet only used by your tiles.\n - If you include the tilesheet file in your mod folder, Content Patcher will use that one automatically; otherwise it will be loaded from the game's Content/Maps folder."
|
"description": "The relative path to the map in your content pack folder from which to copy (like assets/town.tbin). This can be a .tbin or .xnb file. This field supports tokens and capitalization doesn't matter.\nContent Patcher will handle tilesheets referenced by the FromFile map for you if it's a .tbin file:\n - If a tilesheet isn't referenced by the target map, Content Patcher will add it for you (with a z_ ID prefix to avoid conflicts with hardcoded game logic). If the source map has a custom version of a tilesheet that's already referenced, it'll be added as a separate tilesheet only used by your tiles.\n - If you include the tilesheet file in your mod folder, Content Patcher will use that one automatically; otherwise it will be loaded from the game's Content/Maps folder."
|
||||||
},
|
},
|
||||||
"FromArea": {
|
"FromArea": {
|
||||||
"description": "The part of the source map to copy. Defaults to the whole source map."
|
"description": "The part of the source map to copy. Defaults to the whole source map."
|
||||||
|
|
|
@ -23,4 +23,46 @@
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=analytics/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Chucklefish/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=clickable/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=craftable/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=craftables/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=crossplatform/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=cutscene/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=decoratable/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=devs/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=fallbacks/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=filenames/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=gamepad/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Hangfire/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=initializers/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Junimo/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=modder/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=modders/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Mongo/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=multiplayer/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Netcode/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=overworld/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pastebin/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pathoschild/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=premultiplied/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=premultiply/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=prerelease/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=pufferchick/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=rewriter/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=rewriters/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=SMAPI/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=spawnable/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=spritesheet/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=stackable/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stardew/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=subdomain/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=synchronised/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=textbox/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=thumbstick/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=tilesheet/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=tilesheets/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=unloadable/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=virally/@EntryIndexedValue">True</s:Boolean>
|
||||||
</wpf:ResourceDictionary>
|
</wpf:ResourceDictionary>
|
|
@ -14,10 +14,10 @@ namespace StardewModdingAPI
|
||||||
/****
|
/****
|
||||||
** Public
|
** Public
|
||||||
****/
|
****/
|
||||||
/// <summary>Whether the game has performed core initialisation. This becomes true right before the first update tick..</summary>
|
/// <summary>Whether the game has performed core initialization. This becomes true right before the first update tick.</summary>
|
||||||
public static bool IsGameLaunched { get; internal set; }
|
public static bool IsGameLaunched { get; internal set; }
|
||||||
|
|
||||||
/// <summary>Whether the player has loaded a save and the world has finished initialising.</summary>
|
/// <summary>Whether the player has loaded a save and the world has finished initializing.</summary>
|
||||||
public static bool IsWorldReady { get; internal set; }
|
public static bool IsWorldReady { get; internal set; }
|
||||||
|
|
||||||
/// <summary>Whether <see cref="IsWorldReady"/> is true and the player is free to act in the world (no menu is displayed, no cutscene is in progress, etc).</summary>
|
/// <summary>Whether <see cref="IsWorldReady"/> is true and the player is free to act in the world (no menu is displayed, no cutscene is in progress, etc).</summary>
|
||||||
|
|
|
@ -6,10 +6,10 @@ namespace StardewModdingAPI.Enums
|
||||||
/// <summary>A save is not loaded or loading.</summary>
|
/// <summary>A save is not loaded or loading.</summary>
|
||||||
None,
|
None,
|
||||||
|
|
||||||
/// <summary>The game is creating a new save slot, and has initialised the basic save info.</summary>
|
/// <summary>The game is creating a new save slot, and has initialized the basic save info.</summary>
|
||||||
CreatedBasicInfo,
|
CreatedBasicInfo,
|
||||||
|
|
||||||
/// <summary>The game is creating a new save slot, and has initialised the in-game locations.</summary>
|
/// <summary>The game is creating a new save slot, and has initialized the in-game locations.</summary>
|
||||||
CreatedLocations,
|
CreatedLocations,
|
||||||
|
|
||||||
/// <summary>The game is creating a new save slot, and has created the physical save files.</summary>
|
/// <summary>The game is creating a new save slot, and has created the physical save files.</summary>
|
||||||
|
@ -18,7 +18,7 @@ namespace StardewModdingAPI.Enums
|
||||||
/// <summary>The game is loading a save slot, and has read the raw save data into <see cref="StardewValley.SaveGame.loaded"/>. Not applicable when connecting to a multiplayer host. This is equivalent to <see cref="StardewValley.SaveGame.getLoadEnumerator"/> value 20.</summary>
|
/// <summary>The game is loading a save slot, and has read the raw save data into <see cref="StardewValley.SaveGame.loaded"/>. Not applicable when connecting to a multiplayer host. This is equivalent to <see cref="StardewValley.SaveGame.getLoadEnumerator"/> value 20.</summary>
|
||||||
SaveParsed,
|
SaveParsed,
|
||||||
|
|
||||||
/// <summary>The game is loading a save slot, and has applied the basic save info (including player data). Not applicable when connecting to a multiplayer host. Note that some basic info (like daily luck) is not initialised at this point. This is equivalent to <see cref="StardewValley.SaveGame.getLoadEnumerator"/> value 36.</summary>
|
/// <summary>The game is loading a save slot, and has applied the basic save info (including player data). Not applicable when connecting to a multiplayer host. Note that some basic info (like daily luck) is not initialized at this point. This is equivalent to <see cref="StardewValley.SaveGame.getLoadEnumerator"/> value 36.</summary>
|
||||||
SaveLoadedBasicInfo,
|
SaveLoadedBasicInfo,
|
||||||
|
|
||||||
/// <summary>The game is loading a save slot, and has applied the in-game location data. Not applicable when connecting to a multiplayer host. This is equivalent to <see cref="StardewValley.SaveGame.getLoadEnumerator"/> value 50.</summary>
|
/// <summary>The game is loading a save slot, and has applied the in-game location data. Not applicable when connecting to a multiplayer host. This is equivalent to <see cref="StardewValley.SaveGame.getLoadEnumerator"/> value 50.</summary>
|
||||||
|
@ -27,10 +27,10 @@ namespace StardewModdingAPI.Enums
|
||||||
/// <summary>The final metadata has been loaded from the save file. This happens before the game applies problem fixes, checks for achievements, starts music, etc. Not applicable when connecting to a multiplayer host.</summary>
|
/// <summary>The final metadata has been loaded from the save file. This happens before the game applies problem fixes, checks for achievements, starts music, etc. Not applicable when connecting to a multiplayer host.</summary>
|
||||||
Preloaded,
|
Preloaded,
|
||||||
|
|
||||||
/// <summary>The save is fully loaded, but the world may not be fully initialised yet.</summary>
|
/// <summary>The save is fully loaded, but the world may not be fully initialized yet.</summary>
|
||||||
Loaded,
|
Loaded,
|
||||||
|
|
||||||
/// <summary>The save is fully loaded, the world has been initialised, and <see cref="Context.IsWorldReady"/> is now true.</summary>
|
/// <summary>The save is fully loaded, the world has been initialized, and <see cref="Context.IsWorldReady"/> is now true.</summary>
|
||||||
Ready
|
Ready
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace StardewModdingAPI.Events
|
||||||
/// <summary>Events linked to the game's update loop. The update loop runs roughly ≈60 times/second to run game logic like state changes, action handling, etc. These can be useful, but you should consider more semantic events like <see cref="IInputEvents"/> if possible.</summary>
|
/// <summary>Events linked to the game's update loop. The update loop runs roughly ≈60 times/second to run game logic like state changes, action handling, etc. These can be useful, but you should consider more semantic events like <see cref="IInputEvents"/> if possible.</summary>
|
||||||
public interface IGameLoopEvents
|
public interface IGameLoopEvents
|
||||||
{
|
{
|
||||||
/// <summary>Raised after the game is launched, right before the first update tick. This happens once per game session (unrelated to loading saves). All mods are loaded and initialised at this point, so this is a good time to set up mod integrations.</summary>
|
/// <summary>Raised after the game is launched, right before the first update tick. This happens once per game session (unrelated to loading saves). All mods are loaded and initialized at this point, so this is a good time to set up mod integrations.</summary>
|
||||||
event EventHandler<GameLaunchedEventArgs> GameLaunched;
|
event EventHandler<GameLaunchedEventArgs> GameLaunched;
|
||||||
|
|
||||||
/// <summary>Raised before the game state is updated (≈60 times per second).</summary>
|
/// <summary>Raised before the game state is updated (≈60 times per second).</summary>
|
||||||
|
@ -32,7 +32,7 @@ namespace StardewModdingAPI.Events
|
||||||
/// <summary>Raised after the game finishes writing data to the save file (except the initial save creation).</summary>
|
/// <summary>Raised after the game finishes writing data to the save file (except the initial save creation).</summary>
|
||||||
event EventHandler<SavedEventArgs> Saved;
|
event EventHandler<SavedEventArgs> Saved;
|
||||||
|
|
||||||
/// <summary>Raised after the player loads a save slot and the world is initialised.</summary>
|
/// <summary>Raised after the player loads a save slot and the world is initialized.</summary>
|
||||||
event EventHandler<SaveLoadedEventArgs> SaveLoaded;
|
event EventHandler<SaveLoadedEventArgs> SaveLoaded;
|
||||||
|
|
||||||
/// <summary>Raised after the game begins a new day (including when the player loads a save).</summary>
|
/// <summary>Raised after the game begins a new day (including when the player loads a save).</summary>
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace StardewModdingAPI.Events
|
||||||
/// <summary>Events raised when something changes in the world.</summary>
|
/// <summary>Events raised when something changes in the world.</summary>
|
||||||
IWorldEvents World { get; }
|
IWorldEvents World { get; }
|
||||||
|
|
||||||
/// <summary>Events serving specialised edge cases that shouldn't be used by most mods.</summary>
|
/// <summary>Events serving specialized edge cases that shouldn't be used by most mods.</summary>
|
||||||
ISpecialisedEvents Specialised { get; }
|
ISpecializedEvents Specialized { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ using System;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Events
|
namespace StardewModdingAPI.Events
|
||||||
{
|
{
|
||||||
/// <summary>Events serving specialised edge cases that shouldn't be used by most mods.</summary>
|
/// <summary>Events serving specialized edge cases that shouldn't be used by most mods.</summary>
|
||||||
public interface ISpecialisedEvents
|
public interface ISpecializedEvents
|
||||||
{
|
{
|
||||||
/// <summary>Raised when the low-level stage in the game's loading process has changed. This is an advanced event for mods which need to run code at specific points in the loading process. The available stages or when they happen might change without warning in future versions (e.g. due to changes in the game's load process), so mods using this event are more likely to break or have bugs. Most mods should use <see cref="IGameLoopEvents"/> instead.</summary>
|
/// <summary>Raised when the low-level stage in the game's loading process has changed. This is an advanced event for mods which need to run code at specific points in the loading process. The available stages or when they happen might change without warning in future versions (e.g. due to changes in the game's load process), so mods using this event are more likely to break or have bugs. Most mods should use <see cref="IGameLoopEvents"/> instead.</summary>
|
||||||
event EventHandler<LoadStageChangedEventArgs> LoadStageChanged;
|
event EventHandler<LoadStageChangedEventArgs> LoadStageChanged;
|
||||||
|
|
|
@ -3,7 +3,7 @@ using StardewModdingAPI.Enums;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Events
|
namespace StardewModdingAPI.Events
|
||||||
{
|
{
|
||||||
/// <summary>Event arguments for an <see cref="ISpecialisedEvents.LoadStageChanged"/> event.</summary>
|
/// <summary>Event arguments for an <see cref="ISpecializedEvents.LoadStageChanged"/> event.</summary>
|
||||||
public class LoadStageChangedEventArgs : EventArgs
|
public class LoadStageChangedEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
||||||
|
|
|
@ -3,7 +3,7 @@ using StardewModdingAPI.Framework;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Events
|
namespace StardewModdingAPI.Events
|
||||||
{
|
{
|
||||||
/// <summary>Event arguments for an <see cref="ISpecialisedEvents.UnvalidatedUpdateTicked"/> event.</summary>
|
/// <summary>Event arguments for an <see cref="ISpecializedEvents.UnvalidatedUpdateTicked"/> event.</summary>
|
||||||
public class UnvalidatedUpdateTickedEventArgs : EventArgs
|
public class UnvalidatedUpdateTickedEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
||||||
|
|
|
@ -3,7 +3,7 @@ using StardewModdingAPI.Framework;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Events
|
namespace StardewModdingAPI.Events
|
||||||
{
|
{
|
||||||
/// <summary>Event arguments for an <see cref="ISpecialisedEvents.UnvalidatedUpdateTicking"/> event.</summary>
|
/// <summary>Event arguments for an <see cref="ISpecializedEvents.UnvalidatedUpdateTicking"/> event.</summary>
|
||||||
public class UnvalidatedUpdateTickingEventArgs : EventArgs
|
public class UnvalidatedUpdateTickingEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <exception cref="ArgumentException">There's already a command with that name.</exception>
|
/// <exception cref="ArgumentException">There's already a command with that name.</exception>
|
||||||
public void Add(IModMetadata mod, string name, string documentation, Action<string, string[]> callback, bool allowNullCallback = false)
|
public void Add(IModMetadata mod, string name, string documentation, Action<string, string[]> callback, bool allowNullCallback = false)
|
||||||
{
|
{
|
||||||
name = this.GetNormalisedName(name);
|
name = this.GetNormalizedName(name);
|
||||||
|
|
||||||
// validate format
|
// validate format
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
@ -52,7 +52,7 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <returns>Returns the matching command, or <c>null</c> if not found.</returns>
|
/// <returns>Returns the matching command, or <c>null</c> if not found.</returns>
|
||||||
public Command Get(string name)
|
public Command Get(string name)
|
||||||
{
|
{
|
||||||
name = this.GetNormalisedName(name);
|
name = this.GetNormalizedName(name);
|
||||||
this.Commands.TryGetValue(name, out Command command);
|
this.Commands.TryGetValue(name, out Command command);
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ namespace StardewModdingAPI.Framework
|
||||||
|
|
||||||
// parse input
|
// parse input
|
||||||
args = this.ParseArgs(input);
|
args = this.ParseArgs(input);
|
||||||
name = this.GetNormalisedName(args[0]);
|
name = this.GetNormalizedName(args[0]);
|
||||||
args = args.Skip(1).ToArray();
|
args = args.Skip(1).ToArray();
|
||||||
|
|
||||||
// get command
|
// get command
|
||||||
|
@ -97,8 +97,8 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <returns>Returns whether a matching command was triggered.</returns>
|
/// <returns>Returns whether a matching command was triggered.</returns>
|
||||||
public bool Trigger(string name, string[] arguments)
|
public bool Trigger(string name, string[] arguments)
|
||||||
{
|
{
|
||||||
// get normalised name
|
// get normalized name
|
||||||
name = this.GetNormalisedName(name);
|
name = this.GetNormalizedName(name);
|
||||||
if (name == null)
|
if (name == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -140,9 +140,9 @@ namespace StardewModdingAPI.Framework
|
||||||
return args.Where(item => !string.IsNullOrWhiteSpace(item)).ToArray();
|
return args.Where(item => !string.IsNullOrWhiteSpace(item)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a normalised command name.</summary>
|
/// <summary>Get a normalized command name.</summary>
|
||||||
/// <param name="name">The command name.</param>
|
/// <param name="name">The command name.</param>
|
||||||
private string GetNormalisedName(string name)
|
private string GetNormalizedName(string name)
|
||||||
{
|
{
|
||||||
name = name?.Trim().ToLower();
|
name = name?.Trim().ToLower();
|
||||||
return !string.IsNullOrWhiteSpace(name)
|
return !string.IsNullOrWhiteSpace(name)
|
||||||
|
|
|
@ -24,13 +24,13 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Construct an instance.</summary>
|
/// <summary>Construct an instance.</summary>
|
||||||
/// <param name="locale">The content's locale code, if the content is localised.</param>
|
/// <param name="locale">The content's locale code, if the content is localized.</param>
|
||||||
/// <param name="assetName">The normalised asset name being read.</param>
|
/// <param name="assetName">The normalized asset name being read.</param>
|
||||||
/// <param name="data">The content data being read.</param>
|
/// <param name="data">The content data being read.</param>
|
||||||
/// <param name="getNormalisedPath">Normalises an asset key to match the cache key.</param>
|
/// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param>
|
||||||
/// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param>
|
/// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param>
|
||||||
public AssetData(string locale, string assetName, TValue data, Func<string, string> getNormalisedPath, Action<TValue> onDataReplaced)
|
public AssetData(string locale, string assetName, TValue data, Func<string, string> getNormalizedPath, Action<TValue> onDataReplaced)
|
||||||
: base(locale, assetName, data.GetType(), getNormalisedPath)
|
: base(locale, assetName, data.GetType(), getNormalizedPath)
|
||||||
{
|
{
|
||||||
this.Data = data;
|
this.Data = data;
|
||||||
this.OnDataReplaced = onDataReplaced;
|
this.OnDataReplaced = onDataReplaced;
|
||||||
|
|
|
@ -10,12 +10,12 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Construct an instance.</summary>
|
/// <summary>Construct an instance.</summary>
|
||||||
/// <param name="locale">The content's locale code, if the content is localised.</param>
|
/// <param name="locale">The content's locale code, if the content is localized.</param>
|
||||||
/// <param name="assetName">The normalised asset name being read.</param>
|
/// <param name="assetName">The normalized asset name being read.</param>
|
||||||
/// <param name="data">The content data being read.</param>
|
/// <param name="data">The content data being read.</param>
|
||||||
/// <param name="getNormalisedPath">Normalises an asset key to match the cache key.</param>
|
/// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param>
|
||||||
/// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param>
|
/// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param>
|
||||||
public AssetDataForDictionary(string locale, string assetName, IDictionary<TKey, TValue> data, Func<string, string> getNormalisedPath, Action<IDictionary<TKey, TValue>> onDataReplaced)
|
public AssetDataForDictionary(string locale, string assetName, IDictionary<TKey, TValue> data, Func<string, string> getNormalizedPath, Action<IDictionary<TKey, TValue>> onDataReplaced)
|
||||||
: base(locale, assetName, data, getNormalisedPath, onDataReplaced) { }
|
: base(locale, assetName, data, getNormalizedPath, onDataReplaced) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,13 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Construct an instance.</summary>
|
/// <summary>Construct an instance.</summary>
|
||||||
/// <param name="locale">The content's locale code, if the content is localised.</param>
|
/// <param name="locale">The content's locale code, if the content is localized.</param>
|
||||||
/// <param name="assetName">The normalised asset name being read.</param>
|
/// <param name="assetName">The normalized asset name being read.</param>
|
||||||
/// <param name="data">The content data being read.</param>
|
/// <param name="data">The content data being read.</param>
|
||||||
/// <param name="getNormalisedPath">Normalises an asset key to match the cache key.</param>
|
/// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param>
|
||||||
/// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param>
|
/// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param>
|
||||||
public AssetDataForImage(string locale, string assetName, Texture2D data, Func<string, string> getNormalisedPath, Action<Texture2D> onDataReplaced)
|
public AssetDataForImage(string locale, string assetName, Texture2D data, Func<string, string> getNormalizedPath, Action<Texture2D> onDataReplaced)
|
||||||
: base(locale, assetName, data, getNormalisedPath, onDataReplaced) { }
|
: base(locale, assetName, data, getNormalizedPath, onDataReplaced) { }
|
||||||
|
|
||||||
/// <summary>Overwrite part of the image.</summary>
|
/// <summary>Overwrite part of the image.</summary>
|
||||||
/// <param name="source">The image to patch into the content.</param>
|
/// <param name="source">The image to patch into the content.</param>
|
||||||
|
|
|
@ -11,19 +11,19 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Construct an instance.</summary>
|
/// <summary>Construct an instance.</summary>
|
||||||
/// <param name="locale">The content's locale code, if the content is localised.</param>
|
/// <param name="locale">The content's locale code, if the content is localized.</param>
|
||||||
/// <param name="assetName">The normalised asset name being read.</param>
|
/// <param name="assetName">The normalized asset name being read.</param>
|
||||||
/// <param name="data">The content data being read.</param>
|
/// <param name="data">The content data being read.</param>
|
||||||
/// <param name="getNormalisedPath">Normalises an asset key to match the cache key.</param>
|
/// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param>
|
||||||
public AssetDataForObject(string locale, string assetName, object data, Func<string, string> getNormalisedPath)
|
public AssetDataForObject(string locale, string assetName, object data, Func<string, string> getNormalizedPath)
|
||||||
: base(locale, assetName, data, getNormalisedPath, onDataReplaced: null) { }
|
: base(locale, assetName, data, getNormalizedPath, onDataReplaced: null) { }
|
||||||
|
|
||||||
/// <summary>Construct an instance.</summary>
|
/// <summary>Construct an instance.</summary>
|
||||||
/// <param name="info">The asset metadata.</param>
|
/// <param name="info">The asset metadata.</param>
|
||||||
/// <param name="data">The content data being read.</param>
|
/// <param name="data">The content data being read.</param>
|
||||||
/// <param name="getNormalisedPath">Normalises an asset key to match the cache key.</param>
|
/// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param>
|
||||||
public AssetDataForObject(IAssetInfo info, object data, Func<string, string> getNormalisedPath)
|
public AssetDataForObject(IAssetInfo info, object data, Func<string, string> getNormalizedPath)
|
||||||
: this(info.Locale, info.AssetName, data, getNormalisedPath) { }
|
: this(info.Locale, info.AssetName, data, getNormalizedPath) { }
|
||||||
|
|
||||||
/// <summary>Get a helper to manipulate the data as a dictionary.</summary>
|
/// <summary>Get a helper to manipulate the data as a dictionary.</summary>
|
||||||
/// <typeparam name="TKey">The expected dictionary key.</typeparam>
|
/// <typeparam name="TKey">The expected dictionary key.</typeparam>
|
||||||
|
@ -31,14 +31,14 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
/// <exception cref="InvalidOperationException">The content being read isn't a dictionary.</exception>
|
/// <exception cref="InvalidOperationException">The content being read isn't a dictionary.</exception>
|
||||||
public IAssetDataForDictionary<TKey, TValue> AsDictionary<TKey, TValue>()
|
public IAssetDataForDictionary<TKey, TValue> AsDictionary<TKey, TValue>()
|
||||||
{
|
{
|
||||||
return new AssetDataForDictionary<TKey, TValue>(this.Locale, this.AssetName, this.GetData<IDictionary<TKey, TValue>>(), this.GetNormalisedPath, this.ReplaceWith);
|
return new AssetDataForDictionary<TKey, TValue>(this.Locale, this.AssetName, this.GetData<IDictionary<TKey, TValue>>(), this.GetNormalizedPath, this.ReplaceWith);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a helper to manipulate the data as an image.</summary>
|
/// <summary>Get a helper to manipulate the data as an image.</summary>
|
||||||
/// <exception cref="InvalidOperationException">The content being read isn't an image.</exception>
|
/// <exception cref="InvalidOperationException">The content being read isn't an image.</exception>
|
||||||
public IAssetDataForImage AsImage()
|
public IAssetDataForImage AsImage()
|
||||||
{
|
{
|
||||||
return new AssetDataForImage(this.Locale, this.AssetName, this.GetData<Texture2D>(), this.GetNormalisedPath, this.ReplaceWith);
|
return new AssetDataForImage(this.Locale, this.AssetName, this.GetData<Texture2D>(), this.GetNormalizedPath, this.ReplaceWith);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get the data as a given type.</summary>
|
/// <summary>Get the data as a given type.</summary>
|
||||||
|
|
|
@ -9,17 +9,17 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
/*********
|
/*********
|
||||||
** Fields
|
** Fields
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Normalises an asset key to match the cache key.</summary>
|
/// <summary>Normalizes an asset key to match the cache key.</summary>
|
||||||
protected readonly Func<string, string> GetNormalisedPath;
|
protected readonly Func<string, string> GetNormalizedPath;
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Accessors
|
** Accessors
|
||||||
*********/
|
*********/
|
||||||
/// <summary>The content's locale code, if the content is localised.</summary>
|
/// <summary>The content's locale code, if the content is localized.</summary>
|
||||||
public string Locale { get; }
|
public string Locale { get; }
|
||||||
|
|
||||||
/// <summary>The normalised asset name being read. The format may change between platforms; see <see cref="AssetNameEquals"/> to compare with a known path.</summary>
|
/// <summary>The normalized asset name being read. The format may change between platforms; see <see cref="AssetNameEquals"/> to compare with a known path.</summary>
|
||||||
public string AssetName { get; }
|
public string AssetName { get; }
|
||||||
|
|
||||||
/// <summary>The content data type.</summary>
|
/// <summary>The content data type.</summary>
|
||||||
|
@ -30,23 +30,23 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Construct an instance.</summary>
|
/// <summary>Construct an instance.</summary>
|
||||||
/// <param name="locale">The content's locale code, if the content is localised.</param>
|
/// <param name="locale">The content's locale code, if the content is localized.</param>
|
||||||
/// <param name="assetName">The normalised asset name being read.</param>
|
/// <param name="assetName">The normalized asset name being read.</param>
|
||||||
/// <param name="type">The content type being read.</param>
|
/// <param name="type">The content type being read.</param>
|
||||||
/// <param name="getNormalisedPath">Normalises an asset key to match the cache key.</param>
|
/// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param>
|
||||||
public AssetInfo(string locale, string assetName, Type type, Func<string, string> getNormalisedPath)
|
public AssetInfo(string locale, string assetName, Type type, Func<string, string> getNormalizedPath)
|
||||||
{
|
{
|
||||||
this.Locale = locale;
|
this.Locale = locale;
|
||||||
this.AssetName = assetName;
|
this.AssetName = assetName;
|
||||||
this.DataType = type;
|
this.DataType = type;
|
||||||
this.GetNormalisedPath = getNormalisedPath;
|
this.GetNormalizedPath = getNormalizedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get whether the asset name being loaded matches a given name after normalisation.</summary>
|
/// <summary>Get whether the asset name being loaded matches a given name after normalization.</summary>
|
||||||
/// <param name="path">The expected asset path, relative to the game's content folder and without the .xnb extension or locale suffix (like 'Data\ObjectInformation').</param>
|
/// <param name="path">The expected asset path, relative to the game's content folder and without the .xnb extension or locale suffix (like 'Data\ObjectInformation').</param>
|
||||||
public bool AssetNameEquals(string path)
|
public bool AssetNameEquals(string path)
|
||||||
{
|
{
|
||||||
path = this.GetNormalisedPath(path);
|
path = this.GetNormalizedPath(path);
|
||||||
return this.AssetName.Equals(path, StringComparison.InvariantCultureIgnoreCase);
|
return this.AssetName.Equals(path, StringComparison.InvariantCultureIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ using StardewValley;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Framework.Content
|
namespace StardewModdingAPI.Framework.Content
|
||||||
{
|
{
|
||||||
/// <summary>A low-level wrapper around the content cache which handles reading, writing, and invalidating entries in the cache. This doesn't handle any higher-level logic like localisation, loading content, etc. It assumes all keys passed in are already normalised.</summary>
|
/// <summary>A low-level wrapper around the content cache which handles reading, writing, and invalidating entries in the cache. This doesn't handle any higher-level logic like localization, loading content, etc. It assumes all keys passed in are already normalized.</summary>
|
||||||
internal class ContentCache
|
internal class ContentCache
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
||||||
|
@ -19,8 +19,8 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
/// <summary>The underlying asset cache.</summary>
|
/// <summary>The underlying asset cache.</summary>
|
||||||
private readonly IDictionary<string, object> Cache;
|
private readonly IDictionary<string, object> Cache;
|
||||||
|
|
||||||
/// <summary>Applies platform-specific asset key normalisation so it's consistent with the underlying cache.</summary>
|
/// <summary>Applies platform-specific asset key normalization so it's consistent with the underlying cache.</summary>
|
||||||
private readonly Func<string, string> NormaliseAssetNameForPlatform;
|
private readonly Func<string, string> NormalizeAssetNameForPlatform;
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
|
@ -52,14 +52,14 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
// init
|
// init
|
||||||
this.Cache = reflection.GetField<Dictionary<string, object>>(contentManager, "loadedAssets").GetValue();
|
this.Cache = reflection.GetField<Dictionary<string, object>>(contentManager, "loadedAssets").GetValue();
|
||||||
|
|
||||||
// get key normalisation logic
|
// get key normalization logic
|
||||||
if (Constants.Platform == Platform.Windows)
|
if (Constants.Platform == Platform.Windows)
|
||||||
{
|
{
|
||||||
IReflectedMethod method = reflection.GetMethod(typeof(TitleContainer), "GetCleanPath");
|
IReflectedMethod method = reflection.GetMethod(typeof(TitleContainer), "GetCleanPath");
|
||||||
this.NormaliseAssetNameForPlatform = path => method.Invoke<string>(path);
|
this.NormalizeAssetNameForPlatform = path => method.Invoke<string>(path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this.NormaliseAssetNameForPlatform = key => key.Replace('\\', '/'); // based on MonoGame's ContentManager.Load<T> logic
|
this.NormalizeAssetNameForPlatform = key => key.Replace('\\', '/'); // based on MonoGame's ContentManager.Load<T> logic
|
||||||
}
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
|
@ -74,25 +74,25 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
|
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Normalise
|
** Normalize
|
||||||
****/
|
****/
|
||||||
/// <summary>Normalise path separators in a file path. For asset keys, see <see cref="NormaliseKey"/> instead.</summary>
|
/// <summary>Normalize path separators in a file path. For asset keys, see <see cref="NormalizeKey"/> instead.</summary>
|
||||||
/// <param name="path">The file path to normalise.</param>
|
/// <param name="path">The file path to normalize.</param>
|
||||||
[Pure]
|
[Pure]
|
||||||
public string NormalisePathSeparators(string path)
|
public string NormalizePathSeparators(string path)
|
||||||
{
|
{
|
||||||
return PathUtilities.NormalisePathSeparators(path);
|
return PathUtilities.NormalizePathSeparators(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Normalise a cache key so it's consistent with the underlying cache.</summary>
|
/// <summary>Normalize a cache key so it's consistent with the underlying cache.</summary>
|
||||||
/// <param name="key">The asset key.</param>
|
/// <param name="key">The asset key.</param>
|
||||||
[Pure]
|
[Pure]
|
||||||
public string NormaliseKey(string key)
|
public string NormalizeKey(string key)
|
||||||
{
|
{
|
||||||
key = this.NormalisePathSeparators(key);
|
key = this.NormalizePathSeparators(key);
|
||||||
return key.EndsWith(".xnb", StringComparison.InvariantCultureIgnoreCase)
|
return key.EndsWith(".xnb", StringComparison.InvariantCultureIgnoreCase)
|
||||||
? key.Substring(0, key.Length - 4)
|
? key.Substring(0, key.Length - 4)
|
||||||
: this.NormaliseAssetNameForPlatform(key);
|
: this.NormalizeAssetNameForPlatform(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
|
|
|
@ -9,7 +9,7 @@ using StardewModdingAPI.Framework.Content;
|
||||||
using StardewModdingAPI.Framework.ContentManagers;
|
using StardewModdingAPI.Framework.ContentManagers;
|
||||||
using StardewModdingAPI.Framework.Reflection;
|
using StardewModdingAPI.Framework.Reflection;
|
||||||
using StardewModdingAPI.Metadata;
|
using StardewModdingAPI.Metadata;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation;
|
using StardewModdingAPI.Toolkit.Serialization;
|
||||||
using StardewModdingAPI.Toolkit.Utilities;
|
using StardewModdingAPI.Toolkit.Utilities;
|
||||||
using StardewValley;
|
using StardewValley;
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <summary>Construct an instance.</summary>
|
/// <summary>Construct an instance.</summary>
|
||||||
/// <param name="serviceProvider">The service provider to use to locate services.</param>
|
/// <param name="serviceProvider">The service provider to use to locate services.</param>
|
||||||
/// <param name="rootDirectory">The root directory to search for content.</param>
|
/// <param name="rootDirectory">The root directory to search for content.</param>
|
||||||
/// <param name="currentCulture">The current culture for which to localise content.</param>
|
/// <param name="currentCulture">The current culture for which to localize content.</param>
|
||||||
/// <param name="monitor">Encapsulates monitoring and logging.</param>
|
/// <param name="monitor">Encapsulates monitoring and logging.</param>
|
||||||
/// <param name="reflection">Simplifies access to private code.</param>
|
/// <param name="reflection">Simplifies access to private code.</param>
|
||||||
/// <param name="jsonHelper">Encapsulates SMAPI's JSON file parsing.</param>
|
/// <param name="jsonHelper">Encapsulates SMAPI's JSON file parsing.</param>
|
||||||
|
@ -89,7 +89,7 @@ namespace StardewModdingAPI.Framework
|
||||||
this.ContentManagers.Add(
|
this.ContentManagers.Add(
|
||||||
this.MainContentManager = new GameContentManager("Game1.content", serviceProvider, rootDirectory, currentCulture, this, monitor, reflection, this.OnDisposing, onLoadingFirstAsset)
|
this.MainContentManager = new GameContentManager("Game1.content", serviceProvider, rootDirectory, currentCulture, this, monitor, reflection, this.OnDisposing, onLoadingFirstAsset)
|
||||||
);
|
);
|
||||||
this.CoreAssets = new CoreAssetPropagator(this.MainContentManager.AssertAndNormaliseAssetName, reflection, monitor);
|
this.CoreAssets = new CoreAssetPropagator(this.MainContentManager.AssertAndNormalizeAssetName, reflection, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a new content manager which handles reading files from the game content folder with support for interception.</summary>
|
/// <summary>Get a new content manager which handles reading files from the game content folder with support for interception.</summary>
|
||||||
|
@ -250,7 +250,7 @@ namespace StardewModdingAPI.Framework
|
||||||
string locale = this.GetLocale();
|
string locale = this.GetLocale();
|
||||||
return this.InvalidateCache((assetName, type) =>
|
return this.InvalidateCache((assetName, type) =>
|
||||||
{
|
{
|
||||||
IAssetInfo info = new AssetInfo(locale, assetName, type, this.MainContentManager.AssertAndNormaliseAssetName);
|
IAssetInfo info = new AssetInfo(locale, assetName, type, this.MainContentManager.AssertAndNormalizeAssetName);
|
||||||
return predicate(info);
|
return predicate(info);
|
||||||
}, dispose);
|
}, dispose);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <param name="name">A name for the mod manager. Not guaranteed to be unique.</param>
|
/// <param name="name">A name for the mod manager. Not guaranteed to be unique.</param>
|
||||||
/// <param name="serviceProvider">The service provider to use to locate services.</param>
|
/// <param name="serviceProvider">The service provider to use to locate services.</param>
|
||||||
/// <param name="rootDirectory">The root directory to search for content.</param>
|
/// <param name="rootDirectory">The root directory to search for content.</param>
|
||||||
/// <param name="currentCulture">The current culture for which to localise content.</param>
|
/// <param name="currentCulture">The current culture for which to localize content.</param>
|
||||||
/// <param name="coordinator">The central coordinator which manages content managers.</param>
|
/// <param name="coordinator">The central coordinator which manages content managers.</param>
|
||||||
/// <param name="monitor">Encapsulates monitoring and logging.</param>
|
/// <param name="monitor">Encapsulates monitoring and logging.</param>
|
||||||
/// <param name="reflection">Simplifies access to private code.</param>
|
/// <param name="reflection">Simplifies access to private code.</param>
|
||||||
|
@ -109,7 +109,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
|
/// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
|
||||||
public abstract T Load<T>(string assetName, LocalizedContentManager.LanguageCode language, bool useCache);
|
public abstract T Load<T>(string assetName, LocalizedContentManager.LanguageCode language, bool useCache);
|
||||||
|
|
||||||
/// <summary>Load the base asset without localisation.</summary>
|
/// <summary>Load the base asset without localization.</summary>
|
||||||
/// <typeparam name="T">The type of asset to load.</typeparam>
|
/// <typeparam name="T">The type of asset to load.</typeparam>
|
||||||
/// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
|
/// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
|
||||||
[Obsolete("This method is implemented for the base game and should not be used directly. To load an asset from the underlying content manager directly, use " + nameof(BaseContentManager.RawLoad) + " instead.")]
|
[Obsolete("This method is implemented for the base game and should not be used directly. To load an asset from the underlying content manager directly, use " + nameof(BaseContentManager.RawLoad) + " instead.")]
|
||||||
|
@ -121,19 +121,19 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <summary>Perform any cleanup needed when the locale changes.</summary>
|
/// <summary>Perform any cleanup needed when the locale changes.</summary>
|
||||||
public virtual void OnLocaleChanged() { }
|
public virtual void OnLocaleChanged() { }
|
||||||
|
|
||||||
/// <summary>Normalise path separators in a file path. For asset keys, see <see cref="AssertAndNormaliseAssetName"/> instead.</summary>
|
/// <summary>Normalize path separators in a file path. For asset keys, see <see cref="AssertAndNormalizeAssetName"/> instead.</summary>
|
||||||
/// <param name="path">The file path to normalise.</param>
|
/// <param name="path">The file path to normalize.</param>
|
||||||
[Pure]
|
[Pure]
|
||||||
public string NormalisePathSeparators(string path)
|
public string NormalizePathSeparators(string path)
|
||||||
{
|
{
|
||||||
return this.Cache.NormalisePathSeparators(path);
|
return this.Cache.NormalizePathSeparators(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Assert that the given key has a valid format and return a normalised form consistent with the underlying cache.</summary>
|
/// <summary>Assert that the given key has a valid format and return a normalized form consistent with the underlying cache.</summary>
|
||||||
/// <param name="assetName">The asset key to check.</param>
|
/// <param name="assetName">The asset key to check.</param>
|
||||||
/// <exception cref="SContentLoadException">The asset key is empty or contains invalid characters.</exception>
|
/// <exception cref="SContentLoadException">The asset key is empty or contains invalid characters.</exception>
|
||||||
[SuppressMessage("ReSharper", "ParameterOnlyUsedForPreconditionCheck.Local", Justification = "Parameter is only used for assertion checks by design.")]
|
[SuppressMessage("ReSharper", "ParameterOnlyUsedForPreconditionCheck.Local", Justification = "Parameter is only used for assertion checks by design.")]
|
||||||
public string AssertAndNormaliseAssetName(string assetName)
|
public string AssertAndNormalizeAssetName(string assetName)
|
||||||
{
|
{
|
||||||
// NOTE: the game checks for ContentLoadException to handle invalid keys, so avoid
|
// NOTE: the game checks for ContentLoadException to handle invalid keys, so avoid
|
||||||
// throwing other types like ArgumentException here.
|
// throwing other types like ArgumentException here.
|
||||||
|
@ -142,7 +142,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
if (assetName.Intersect(Path.GetInvalidPathChars()).Any())
|
if (assetName.Intersect(Path.GetInvalidPathChars()).Any())
|
||||||
throw new SContentLoadException("The asset key or local path contains invalid characters.");
|
throw new SContentLoadException("The asset key or local path contains invalid characters.");
|
||||||
|
|
||||||
return this.Cache.NormaliseKey(assetName);
|
return this.Cache.NormalizeKey(assetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
|
@ -165,8 +165,8 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
|
/// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
|
||||||
public bool IsLoaded(string assetName)
|
public bool IsLoaded(string assetName)
|
||||||
{
|
{
|
||||||
assetName = this.Cache.NormaliseKey(assetName);
|
assetName = this.Cache.NormalizeKey(assetName);
|
||||||
return this.IsNormalisedKeyLoaded(assetName);
|
return this.IsNormalizedKeyLoaded(assetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get the cached asset keys.</summary>
|
/// <summary>Get the cached asset keys.</summary>
|
||||||
|
@ -248,7 +248,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Load an asset file directly from the underlying content manager.</summary>
|
/// <summary>Load an asset file directly from the underlying content manager.</summary>
|
||||||
/// <typeparam name="T">The type of asset to load.</typeparam>
|
/// <typeparam name="T">The type of asset to load.</typeparam>
|
||||||
/// <param name="assetName">The normalised asset key.</param>
|
/// <param name="assetName">The normalized asset key.</param>
|
||||||
/// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
|
/// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
|
||||||
protected virtual T RawLoad<T>(string assetName, bool useCache)
|
protected virtual T RawLoad<T>(string assetName, bool useCache)
|
||||||
{
|
{
|
||||||
|
@ -264,17 +264,17 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <param name="language">The language code for which to inject the asset.</param>
|
/// <param name="language">The language code for which to inject the asset.</param>
|
||||||
protected virtual void Inject<T>(string assetName, T value, LanguageCode language)
|
protected virtual void Inject<T>(string assetName, T value, LanguageCode language)
|
||||||
{
|
{
|
||||||
assetName = this.AssertAndNormaliseAssetName(assetName);
|
assetName = this.AssertAndNormalizeAssetName(assetName);
|
||||||
this.Cache[assetName] = value;
|
this.Cache[assetName] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Parse a cache key into its component parts.</summary>
|
/// <summary>Parse a cache key into its component parts.</summary>
|
||||||
/// <param name="cacheKey">The input cache key.</param>
|
/// <param name="cacheKey">The input cache key.</param>
|
||||||
/// <param name="assetName">The original asset name.</param>
|
/// <param name="assetName">The original asset name.</param>
|
||||||
/// <param name="localeCode">The asset locale code (or <c>null</c> if not localised).</param>
|
/// <param name="localeCode">The asset locale code (or <c>null</c> if not localized).</param>
|
||||||
protected void ParseCacheKey(string cacheKey, out string assetName, out string localeCode)
|
protected void ParseCacheKey(string cacheKey, out string assetName, out string localeCode)
|
||||||
{
|
{
|
||||||
// handle localised key
|
// handle localized key
|
||||||
if (!string.IsNullOrWhiteSpace(cacheKey))
|
if (!string.IsNullOrWhiteSpace(cacheKey))
|
||||||
{
|
{
|
||||||
int lastSepIndex = cacheKey.LastIndexOf(".", StringComparison.InvariantCulture);
|
int lastSepIndex = cacheKey.LastIndexOf(".", StringComparison.InvariantCulture);
|
||||||
|
@ -296,8 +296,8 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get whether an asset has already been loaded.</summary>
|
/// <summary>Get whether an asset has already been loaded.</summary>
|
||||||
/// <param name="normalisedAssetName">The normalised asset name.</param>
|
/// <param name="normalizedAssetName">The normalized asset name.</param>
|
||||||
protected abstract bool IsNormalisedKeyLoaded(string normalisedAssetName);
|
protected abstract bool IsNormalizedKeyLoaded(string normalizedAssetName);
|
||||||
|
|
||||||
/// <summary>Get the locale codes (like <c>ja-JP</c>) used in asset keys.</summary>
|
/// <summary>Get the locale codes (like <c>ja-JP</c>) used in asset keys.</summary>
|
||||||
private IDictionary<LanguageCode, string> GetKeyLocales()
|
private IDictionary<LanguageCode, string> GetKeyLocales()
|
||||||
|
|
|
@ -26,8 +26,8 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <summary>Interceptors which edit matching assets after they're loaded.</summary>
|
/// <summary>Interceptors which edit matching assets after they're loaded.</summary>
|
||||||
private IDictionary<IModMetadata, IList<IAssetEditor>> Editors => this.Coordinator.Editors;
|
private IDictionary<IModMetadata, IList<IAssetEditor>> Editors => this.Coordinator.Editors;
|
||||||
|
|
||||||
/// <summary>A lookup which indicates whether the asset is localisable (i.e. the filename contains the locale), if previously loaded.</summary>
|
/// <summary>A lookup which indicates whether the asset is localizable (i.e. the filename contains the locale), if previously loaded.</summary>
|
||||||
private readonly IDictionary<string, bool> IsLocalisableLookup;
|
private readonly IDictionary<string, bool> IsLocalizableLookup;
|
||||||
|
|
||||||
/// <summary>Whether the next load is the first for any game content manager.</summary>
|
/// <summary>Whether the next load is the first for any game content manager.</summary>
|
||||||
private static bool IsFirstLoad = true;
|
private static bool IsFirstLoad = true;
|
||||||
|
@ -43,7 +43,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <param name="name">A name for the mod manager. Not guaranteed to be unique.</param>
|
/// <param name="name">A name for the mod manager. Not guaranteed to be unique.</param>
|
||||||
/// <param name="serviceProvider">The service provider to use to locate services.</param>
|
/// <param name="serviceProvider">The service provider to use to locate services.</param>
|
||||||
/// <param name="rootDirectory">The root directory to search for content.</param>
|
/// <param name="rootDirectory">The root directory to search for content.</param>
|
||||||
/// <param name="currentCulture">The current culture for which to localise content.</param>
|
/// <param name="currentCulture">The current culture for which to localize content.</param>
|
||||||
/// <param name="coordinator">The central coordinator which manages content managers.</param>
|
/// <param name="coordinator">The central coordinator which manages content managers.</param>
|
||||||
/// <param name="monitor">Encapsulates monitoring and logging.</param>
|
/// <param name="monitor">Encapsulates monitoring and logging.</param>
|
||||||
/// <param name="reflection">Simplifies access to private code.</param>
|
/// <param name="reflection">Simplifies access to private code.</param>
|
||||||
|
@ -52,7 +52,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
public GameContentManager(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action<BaseContentManager> onDisposing, Action onLoadingFirstAsset)
|
public GameContentManager(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action<BaseContentManager> onDisposing, Action onLoadingFirstAsset)
|
||||||
: base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isNamespaced: false)
|
: base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isNamespaced: false)
|
||||||
{
|
{
|
||||||
this.IsLocalisableLookup = reflection.GetField<IDictionary<string, bool>>(this, "_localizedAsset").GetValue();
|
this.IsLocalizableLookup = reflection.GetField<IDictionary<string, bool>>(this, "_localizedAsset").GetValue();
|
||||||
this.OnLoadingFirstAsset = onLoadingFirstAsset;
|
this.OnLoadingFirstAsset = onLoadingFirstAsset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +70,8 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
this.OnLoadingFirstAsset();
|
this.OnLoadingFirstAsset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalise asset name
|
// normalize asset name
|
||||||
assetName = this.AssertAndNormaliseAssetName(assetName);
|
assetName = this.AssertAndNormalizeAssetName(assetName);
|
||||||
if (this.TryParseExplicitLanguageAssetKey(assetName, out string newAssetName, out LanguageCode newLanguage))
|
if (this.TryParseExplicitLanguageAssetKey(assetName, out string newAssetName, out LanguageCode newLanguage))
|
||||||
return this.Load<T>(newAssetName, newLanguage, useCache);
|
return this.Load<T>(newAssetName, newLanguage, useCache);
|
||||||
|
|
||||||
|
@ -101,10 +101,10 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
data = this.AssetsBeingLoaded.Track(assetName, () =>
|
data = this.AssetsBeingLoaded.Track(assetName, () =>
|
||||||
{
|
{
|
||||||
string locale = this.GetLocale(language);
|
string locale = this.GetLocale(language);
|
||||||
IAssetInfo info = new AssetInfo(locale, assetName, typeof(T), this.AssertAndNormaliseAssetName);
|
IAssetInfo info = new AssetInfo(locale, assetName, typeof(T), this.AssertAndNormalizeAssetName);
|
||||||
IAssetData asset =
|
IAssetData asset =
|
||||||
this.ApplyLoader<T>(info)
|
this.ApplyLoader<T>(info)
|
||||||
?? new AssetDataForObject(info, this.RawLoad<T>(assetName, language, useCache), this.AssertAndNormaliseAssetName);
|
?? new AssetDataForObject(info, this.RawLoad<T>(assetName, language, useCache), this.AssertAndNormalizeAssetName);
|
||||||
asset = this.ApplyEditors<T>(info, asset);
|
asset = this.ApplyEditors<T>(info, asset);
|
||||||
return (T)asset.Data;
|
return (T)asset.Data;
|
||||||
});
|
});
|
||||||
|
@ -122,7 +122,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
|
|
||||||
// find assets for which a translatable version was loaded
|
// find assets for which a translatable version was loaded
|
||||||
HashSet<string> removeAssetNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> removeAssetNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
|
||||||
foreach (string key in this.IsLocalisableLookup.Where(p => p.Value).Select(p => p.Key))
|
foreach (string key in this.IsLocalizableLookup.Where(p => p.Value).Select(p => p.Key))
|
||||||
removeAssetNames.Add(this.TryParseExplicitLanguageAssetKey(key, out string assetName, out _) ? assetName : key);
|
removeAssetNames.Add(this.TryParseExplicitLanguageAssetKey(key, out string assetName, out _) ? assetName : key);
|
||||||
|
|
||||||
// invalidate translatable assets
|
// invalidate translatable assets
|
||||||
|
@ -149,20 +149,20 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
** Private methods
|
** Private methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Get whether an asset has already been loaded.</summary>
|
/// <summary>Get whether an asset has already been loaded.</summary>
|
||||||
/// <param name="normalisedAssetName">The normalised asset name.</param>
|
/// <param name="normalizedAssetName">The normalized asset name.</param>
|
||||||
protected override bool IsNormalisedKeyLoaded(string normalisedAssetName)
|
protected override bool IsNormalizedKeyLoaded(string normalizedAssetName)
|
||||||
{
|
{
|
||||||
// default English
|
// default English
|
||||||
if (this.Language == LocalizedContentManager.LanguageCode.en || this.Coordinator.IsManagedAssetKey(normalisedAssetName))
|
if (this.Language == LocalizedContentManager.LanguageCode.en || this.Coordinator.IsManagedAssetKey(normalizedAssetName))
|
||||||
return this.Cache.ContainsKey(normalisedAssetName);
|
return this.Cache.ContainsKey(normalizedAssetName);
|
||||||
|
|
||||||
// translated
|
// translated
|
||||||
string keyWithLocale = $"{normalisedAssetName}.{this.GetLocale(this.GetCurrentLanguage())}";
|
string keyWithLocale = $"{normalizedAssetName}.{this.GetLocale(this.GetCurrentLanguage())}";
|
||||||
if (this.IsLocalisableLookup.TryGetValue(keyWithLocale, out bool localisable))
|
if (this.IsLocalizableLookup.TryGetValue(keyWithLocale, out bool localizable))
|
||||||
{
|
{
|
||||||
return localisable
|
return localizable
|
||||||
? this.Cache.ContainsKey(keyWithLocale)
|
? this.Cache.ContainsKey(keyWithLocale)
|
||||||
: this.Cache.ContainsKey(normalisedAssetName);
|
: this.Cache.ContainsKey(normalizedAssetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// not loaded yet
|
// not loaded yet
|
||||||
|
@ -190,13 +190,13 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
string keyWithLocale = $"{assetName}.{this.GetLocale(language)}";
|
string keyWithLocale = $"{assetName}.{this.GetLocale(language)}";
|
||||||
if (this.Cache.ContainsKey(keyWithLocale))
|
if (this.Cache.ContainsKey(keyWithLocale))
|
||||||
{
|
{
|
||||||
this.IsLocalisableLookup[assetName] = true;
|
this.IsLocalizableLookup[assetName] = true;
|
||||||
this.IsLocalisableLookup[keyWithLocale] = true;
|
this.IsLocalizableLookup[keyWithLocale] = true;
|
||||||
}
|
}
|
||||||
else if (this.Cache.ContainsKey(assetName))
|
else if (this.Cache.ContainsKey(assetName))
|
||||||
{
|
{
|
||||||
this.IsLocalisableLookup[assetName] = false;
|
this.IsLocalizableLookup[assetName] = false;
|
||||||
this.IsLocalisableLookup[keyWithLocale] = false;
|
this.IsLocalizableLookup[keyWithLocale] = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this.Monitor.Log($"Asset '{assetName}' could not be found in the cache immediately after injection.", LogLevel.Error);
|
this.Monitor.Log($"Asset '{assetName}' could not be found in the cache immediately after injection.", LogLevel.Error);
|
||||||
|
@ -204,7 +204,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
|
|
||||||
/// <summary>Load an asset file directly from the underlying content manager.</summary>
|
/// <summary>Load an asset file directly from the underlying content manager.</summary>
|
||||||
/// <typeparam name="T">The type of asset to load.</typeparam>
|
/// <typeparam name="T">The type of asset to load.</typeparam>
|
||||||
/// <param name="assetName">The normalised asset key.</param>
|
/// <param name="assetName">The normalized asset key.</param>
|
||||||
/// <param name="language">The language code for which to load content.</param>
|
/// <param name="language">The language code for which to load content.</param>
|
||||||
/// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
|
/// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
|
||||||
/// <remarks>Derived from <see cref="LocalizedContentManager.Load{T}(string, LocalizedContentManager.LanguageCode)"/>.</remarks>
|
/// <remarks>Derived from <see cref="LocalizedContentManager.Load{T}(string, LocalizedContentManager.LanguageCode)"/>.</remarks>
|
||||||
|
@ -214,19 +214,19 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
if (language != LocalizedContentManager.LanguageCode.en)
|
if (language != LocalizedContentManager.LanguageCode.en)
|
||||||
{
|
{
|
||||||
string translatedKey = $"{assetName}.{this.GetLocale(language)}";
|
string translatedKey = $"{assetName}.{this.GetLocale(language)}";
|
||||||
if (!this.IsLocalisableLookup.TryGetValue(translatedKey, out bool isTranslatable) || isTranslatable)
|
if (!this.IsLocalizableLookup.TryGetValue(translatedKey, out bool isTranslatable) || isTranslatable)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
T obj = base.RawLoad<T>(translatedKey, useCache);
|
T obj = base.RawLoad<T>(translatedKey, useCache);
|
||||||
this.IsLocalisableLookup[assetName] = true;
|
this.IsLocalizableLookup[assetName] = true;
|
||||||
this.IsLocalisableLookup[translatedKey] = true;
|
this.IsLocalizableLookup[translatedKey] = true;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
catch (ContentLoadException)
|
catch (ContentLoadException)
|
||||||
{
|
{
|
||||||
this.IsLocalisableLookup[assetName] = false;
|
this.IsLocalizableLookup[assetName] = false;
|
||||||
this.IsLocalisableLookup[translatedKey] = false;
|
this.IsLocalizableLookup[translatedKey] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
}
|
}
|
||||||
|
|
||||||
// return matched asset
|
// return matched asset
|
||||||
return new AssetDataForObject(info, data, this.AssertAndNormaliseAssetName);
|
return new AssetDataForObject(info, data, this.AssertAndNormalizeAssetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Apply any <see cref="Editors"/> to a loaded asset.</summary>
|
/// <summary>Apply any <see cref="Editors"/> to a loaded asset.</summary>
|
||||||
|
@ -322,7 +322,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <param name="asset">The loaded asset.</param>
|
/// <param name="asset">The loaded asset.</param>
|
||||||
private IAssetData ApplyEditors<T>(IAssetInfo info, IAssetData asset)
|
private IAssetData ApplyEditors<T>(IAssetInfo info, IAssetData asset)
|
||||||
{
|
{
|
||||||
IAssetData GetNewData(object data) => new AssetDataForObject(info, data, this.AssertAndNormaliseAssetName);
|
IAssetData GetNewData(object data) => new AssetDataForObject(info, data, this.AssertAndNormalizeAssetName);
|
||||||
|
|
||||||
// edit asset
|
// edit asset
|
||||||
foreach (var entry in this.GetInterceptors(this.Editors))
|
foreach (var entry in this.GetInterceptors(this.Editors))
|
||||||
|
|
|
@ -39,15 +39,15 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <summary>Perform any cleanup needed when the locale changes.</summary>
|
/// <summary>Perform any cleanup needed when the locale changes.</summary>
|
||||||
void OnLocaleChanged();
|
void OnLocaleChanged();
|
||||||
|
|
||||||
/// <summary>Normalise path separators in a file path. For asset keys, see <see cref="AssertAndNormaliseAssetName"/> instead.</summary>
|
/// <summary>Normalize path separators in a file path. For asset keys, see <see cref="AssertAndNormalizeAssetName"/> instead.</summary>
|
||||||
/// <param name="path">The file path to normalise.</param>
|
/// <param name="path">The file path to normalize.</param>
|
||||||
[Pure]
|
[Pure]
|
||||||
string NormalisePathSeparators(string path);
|
string NormalizePathSeparators(string path);
|
||||||
|
|
||||||
/// <summary>Assert that the given key has a valid format and return a normalised form consistent with the underlying cache.</summary>
|
/// <summary>Assert that the given key has a valid format and return a normalized form consistent with the underlying cache.</summary>
|
||||||
/// <param name="assetName">The asset key to check.</param>
|
/// <param name="assetName">The asset key to check.</param>
|
||||||
/// <exception cref="SContentLoadException">The asset key is empty or contains invalid characters.</exception>
|
/// <exception cref="SContentLoadException">The asset key is empty or contains invalid characters.</exception>
|
||||||
string AssertAndNormaliseAssetName(string assetName);
|
string AssertAndNormalizeAssetName(string assetName);
|
||||||
|
|
||||||
/// <summary>Get the current content locale.</summary>
|
/// <summary>Get the current content locale.</summary>
|
||||||
string GetLocale();
|
string GetLocale();
|
||||||
|
|
|
@ -7,7 +7,7 @@ using Microsoft.Xna.Framework.Content;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using StardewModdingAPI.Framework.Exceptions;
|
using StardewModdingAPI.Framework.Exceptions;
|
||||||
using StardewModdingAPI.Framework.Reflection;
|
using StardewModdingAPI.Framework.Reflection;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation;
|
using StardewModdingAPI.Toolkit.Serialization;
|
||||||
using StardewModdingAPI.Toolkit.Utilities;
|
using StardewModdingAPI.Toolkit.Utilities;
|
||||||
using StardewValley;
|
using StardewValley;
|
||||||
using xTile;
|
using xTile;
|
||||||
|
@ -41,7 +41,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <param name="gameContentManager">The game content manager used for map tilesheets not provided by the mod.</param>
|
/// <param name="gameContentManager">The game content manager used for map tilesheets not provided by the mod.</param>
|
||||||
/// <param name="serviceProvider">The service provider to use to locate services.</param>
|
/// <param name="serviceProvider">The service provider to use to locate services.</param>
|
||||||
/// <param name="rootDirectory">The root directory to search for content.</param>
|
/// <param name="rootDirectory">The root directory to search for content.</param>
|
||||||
/// <param name="currentCulture">The current culture for which to localise content.</param>
|
/// <param name="currentCulture">The current culture for which to localize content.</param>
|
||||||
/// <param name="coordinator">The central coordinator which manages content managers.</param>
|
/// <param name="coordinator">The central coordinator which manages content managers.</param>
|
||||||
/// <param name="monitor">Encapsulates monitoring and logging.</param>
|
/// <param name="monitor">Encapsulates monitoring and logging.</param>
|
||||||
/// <param name="reflection">Simplifies access to private code.</param>
|
/// <param name="reflection">Simplifies access to private code.</param>
|
||||||
|
@ -78,7 +78,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
|
/// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
|
||||||
public override T Load<T>(string assetName, LanguageCode language, bool useCache)
|
public override T Load<T>(string assetName, LanguageCode language, bool useCache)
|
||||||
{
|
{
|
||||||
assetName = this.AssertAndNormaliseAssetName(assetName);
|
assetName = this.AssertAndNormalizeAssetName(assetName);
|
||||||
|
|
||||||
// disable caching
|
// disable caching
|
||||||
// This is necessary to avoid assets being shared between content managers, which can
|
// This is necessary to avoid assets being shared between content managers, which can
|
||||||
|
@ -91,7 +91,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
// disable language handling
|
// disable language handling
|
||||||
// Mod files don't support automatic translation logic, so this should never happen.
|
// Mod files don't support automatic translation logic, so this should never happen.
|
||||||
if (language != this.DefaultLanguage)
|
if (language != this.DefaultLanguage)
|
||||||
throw new InvalidOperationException("Localised assets aren't supported by the mod content manager.");
|
throw new InvalidOperationException("Localized assets aren't supported by the mod content manager.");
|
||||||
|
|
||||||
// resolve managed asset key
|
// resolve managed asset key
|
||||||
{
|
{
|
||||||
|
@ -121,7 +121,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
T data = this.RawLoad<T>(assetName, useCache: false);
|
T data = this.RawLoad<T>(assetName, useCache: false);
|
||||||
if (data is Map map)
|
if (data is Map map)
|
||||||
{
|
{
|
||||||
this.NormaliseTilesheetPaths(map);
|
this.NormalizeTilesheetPaths(map);
|
||||||
this.FixCustomTilesheetPaths(map, relativeMapPath: assetName);
|
this.FixCustomTilesheetPaths(map, relativeMapPath: assetName);
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
|
@ -161,7 +161,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
// fetch & cache
|
// fetch & cache
|
||||||
FormatManager formatManager = FormatManager.Instance;
|
FormatManager formatManager = FormatManager.Instance;
|
||||||
Map map = formatManager.LoadMap(file.FullName);
|
Map map = formatManager.LoadMap(file.FullName);
|
||||||
this.NormaliseTilesheetPaths(map);
|
this.NormalizeTilesheetPaths(map);
|
||||||
this.FixCustomTilesheetPaths(map, relativeMapPath: assetName);
|
this.FixCustomTilesheetPaths(map, relativeMapPath: assetName);
|
||||||
return (T)(object)map;
|
return (T)(object)map;
|
||||||
}
|
}
|
||||||
|
@ -199,10 +199,10 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
** Private methods
|
** Private methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Get whether an asset has already been loaded.</summary>
|
/// <summary>Get whether an asset has already been loaded.</summary>
|
||||||
/// <param name="normalisedAssetName">The normalised asset name.</param>
|
/// <param name="normalizedAssetName">The normalized asset name.</param>
|
||||||
protected override bool IsNormalisedKeyLoaded(string normalisedAssetName)
|
protected override bool IsNormalizedKeyLoaded(string normalizedAssetName)
|
||||||
{
|
{
|
||||||
return this.Cache.ContainsKey(normalisedAssetName);
|
return this.Cache.ContainsKey(normalizedAssetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get a file from the mod folder.</summary>
|
/// <summary>Get a file from the mod folder.</summary>
|
||||||
|
@ -245,12 +245,12 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Normalise map tilesheet paths for the current platform.</summary>
|
/// <summary>Normalize map tilesheet paths for the current platform.</summary>
|
||||||
/// <param name="map">The map whose tilesheets to fix.</param>
|
/// <param name="map">The map whose tilesheets to fix.</param>
|
||||||
private void NormaliseTilesheetPaths(Map map)
|
private void NormalizeTilesheetPaths(Map map)
|
||||||
{
|
{
|
||||||
foreach (TileSheet tilesheet in map.TileSheets)
|
foreach (TileSheet tilesheet in map.TileSheets)
|
||||||
tilesheet.ImageSource = this.NormalisePathSeparators(tilesheet.ImageSource);
|
tilesheet.ImageSource = this.NormalizePathSeparators(tilesheet.ImageSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Fix custom map tilesheet paths so they can be found by the content manager.</summary>
|
/// <summary>Fix custom map tilesheet paths so they can be found by the content manager.</summary>
|
||||||
|
@ -258,7 +258,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <param name="relativeMapPath">The relative map path within the mod folder.</param>
|
/// <param name="relativeMapPath">The relative map path within the mod folder.</param>
|
||||||
/// <exception cref="ContentLoadException">A map tilesheet couldn't be resolved.</exception>
|
/// <exception cref="ContentLoadException">A map tilesheet couldn't be resolved.</exception>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// The game's logic for tilesheets in <see cref="Game1.setGraphicsForSeason"/> is a bit specialised. It boils
|
/// The game's logic for tilesheets in <see cref="Game1.setGraphicsForSeason"/> is a bit specialized. It boils
|
||||||
/// down to this:
|
/// down to this:
|
||||||
/// * If the location is indoors or the desert, or the image source contains 'path' or 'object', it's loaded
|
/// * If the location is indoors or the desert, or the image source contains 'path' or 'object', it's loaded
|
||||||
/// as-is relative to the <c>Content</c> folder.
|
/// as-is relative to the <c>Content</c> folder.
|
||||||
|
@ -276,7 +276,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
// get map info
|
// get map info
|
||||||
if (!map.TileSheets.Any())
|
if (!map.TileSheets.Any())
|
||||||
return;
|
return;
|
||||||
relativeMapPath = this.AssertAndNormaliseAssetName(relativeMapPath); // Mono's Path.GetDirectoryName doesn't handle Windows dir separators
|
relativeMapPath = this.AssertAndNormalizeAssetName(relativeMapPath); // Mono's Path.GetDirectoryName doesn't handle Windows dir separators
|
||||||
string relativeMapFolder = Path.GetDirectoryName(relativeMapPath) ?? ""; // folder path containing the map, relative to the mod folder
|
string relativeMapFolder = Path.GetDirectoryName(relativeMapPath) ?? ""; // folder path containing the map, relative to the mod folder
|
||||||
bool isOutdoors = map.Properties.TryGetValue("Outdoors", out PropertyValue outdoorsProperty) && outdoorsProperty != null;
|
bool isOutdoors = map.Properties.TryGetValue("Outdoors", out PropertyValue outdoorsProperty) && outdoorsProperty != null;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Microsoft.Xna.Framework.Content;
|
using Microsoft.Xna.Framework.Content;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation;
|
using StardewModdingAPI.Toolkit.Serialization;
|
||||||
using StardewModdingAPI.Toolkit.Utilities;
|
using StardewModdingAPI.Toolkit.Utilities;
|
||||||
using xTile;
|
using xTile;
|
||||||
|
|
||||||
|
@ -63,14 +63,14 @@ namespace StardewModdingAPI.Framework
|
||||||
|
|
||||||
/// <summary>Read a JSON file from the content pack folder.</summary>
|
/// <summary>Read a JSON file from the content pack folder.</summary>
|
||||||
/// <typeparam name="TModel">The model type.</typeparam>
|
/// <typeparam name="TModel">The model type.</typeparam>
|
||||||
/// <param name="path">The file path relative to the contnet directory.</param>
|
/// <param name="path">The file path relative to the content directory.</param>
|
||||||
/// <returns>Returns the deserialised model, or <c>null</c> if the file doesn't exist or is empty.</returns>
|
/// <returns>Returns the deserialized model, or <c>null</c> if the file doesn't exist or is empty.</returns>
|
||||||
/// <exception cref="InvalidOperationException">The <paramref name="path"/> is not relative or contains directory climbing (../).</exception>
|
/// <exception cref="InvalidOperationException">The <paramref name="path"/> is not relative or contains directory climbing (../).</exception>
|
||||||
public TModel ReadJsonFile<TModel>(string path) where TModel : class
|
public TModel ReadJsonFile<TModel>(string path) where TModel : class
|
||||||
{
|
{
|
||||||
this.AssertRelativePath(path, nameof(this.ReadJsonFile));
|
this.AssertRelativePath(path, nameof(this.ReadJsonFile));
|
||||||
|
|
||||||
path = Path.Combine(this.DirectoryPath, PathUtilities.NormalisePathSeparators(path));
|
path = Path.Combine(this.DirectoryPath, PathUtilities.NormalizePathSeparators(path));
|
||||||
return this.JsonHelper.ReadJsonFileIfExists(path, out TModel model)
|
return this.JsonHelper.ReadJsonFileIfExists(path, out TModel model)
|
||||||
? model
|
? model
|
||||||
: null;
|
: null;
|
||||||
|
@ -85,7 +85,7 @@ namespace StardewModdingAPI.Framework
|
||||||
{
|
{
|
||||||
this.AssertRelativePath(path, nameof(this.WriteJsonFile));
|
this.AssertRelativePath(path, nameof(this.WriteJsonFile));
|
||||||
|
|
||||||
path = Path.Combine(this.DirectoryPath, PathUtilities.NormalisePathSeparators(path));
|
path = Path.Combine(this.DirectoryPath, PathUtilities.NormalizePathSeparators(path));
|
||||||
this.JsonHelper.WriteJsonFile(path, data);
|
this.JsonHelper.WriteJsonFile(path, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace StardewModdingAPI.Framework.Events
|
||||||
/// <summary>Raised after the game finishes writing data to the save file (except the initial save creation).</summary>
|
/// <summary>Raised after the game finishes writing data to the save file (except the initial save creation).</summary>
|
||||||
public readonly ManagedEvent<SavedEventArgs> Saved;
|
public readonly ManagedEvent<SavedEventArgs> Saved;
|
||||||
|
|
||||||
/// <summary>Raised after the player loads a save slot and the world is initialised.</summary>
|
/// <summary>Raised after the player loads a save slot and the world is initialized.</summary>
|
||||||
public readonly ManagedEvent<SaveLoadedEventArgs> SaveLoaded;
|
public readonly ManagedEvent<SaveLoadedEventArgs> SaveLoaded;
|
||||||
|
|
||||||
/// <summary>Raised after the game begins a new day, including when loading a save.</summary>
|
/// <summary>Raised after the game begins a new day, including when loading a save.</summary>
|
||||||
|
@ -152,15 +152,15 @@ namespace StardewModdingAPI.Framework.Events
|
||||||
public readonly ManagedEvent<TerrainFeatureListChangedEventArgs> TerrainFeatureListChanged;
|
public readonly ManagedEvent<TerrainFeatureListChangedEventArgs> TerrainFeatureListChanged;
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Specialised
|
** Specialized
|
||||||
****/
|
****/
|
||||||
/// <summary>Raised when the low-level stage in the game's loading process has changed. See notes on <see cref="ISpecialisedEvents.LoadStageChanged"/>.</summary>
|
/// <summary>Raised when the low-level stage in the game's loading process has changed. See notes on <see cref="ISpecializedEvents.LoadStageChanged"/>.</summary>
|
||||||
public readonly ManagedEvent<LoadStageChangedEventArgs> LoadStageChanged;
|
public readonly ManagedEvent<LoadStageChangedEventArgs> LoadStageChanged;
|
||||||
|
|
||||||
/// <summary>Raised before the game performs its overall update tick (≈60 times per second). See notes on <see cref="ISpecialisedEvents.UnvalidatedUpdateTicking"/>.</summary>
|
/// <summary>Raised before the game performs its overall update tick (≈60 times per second). See notes on <see cref="ISpecializedEvents.UnvalidatedUpdateTicking"/>.</summary>
|
||||||
public readonly ManagedEvent<UnvalidatedUpdateTickingEventArgs> UnvalidatedUpdateTicking;
|
public readonly ManagedEvent<UnvalidatedUpdateTickingEventArgs> UnvalidatedUpdateTicking;
|
||||||
|
|
||||||
/// <summary>Raised after the game performs its overall update tick (≈60 times per second). See notes on <see cref="ISpecialisedEvents.UnvalidatedUpdateTicked"/>.</summary>
|
/// <summary>Raised after the game performs its overall update tick (≈60 times per second). See notes on <see cref="ISpecializedEvents.UnvalidatedUpdateTicked"/>.</summary>
|
||||||
public readonly ManagedEvent<UnvalidatedUpdateTickedEventArgs> UnvalidatedUpdateTicked;
|
public readonly ManagedEvent<UnvalidatedUpdateTickedEventArgs> UnvalidatedUpdateTicked;
|
||||||
|
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ namespace StardewModdingAPI.Framework.Events
|
||||||
/// <param name="modRegistry">The mod registry with which to identify mods.</param>
|
/// <param name="modRegistry">The mod registry with which to identify mods.</param>
|
||||||
public EventManager(IMonitor monitor, ModRegistry modRegistry)
|
public EventManager(IMonitor monitor, ModRegistry modRegistry)
|
||||||
{
|
{
|
||||||
// create shortcut initialisers
|
// create shortcut initializers
|
||||||
ManagedEvent<TEventArgs> ManageEventOf<TEventArgs>(string typeName, string eventName) => new ManagedEvent<TEventArgs>($"{typeName}.{eventName}", monitor, modRegistry);
|
ManagedEvent<TEventArgs> ManageEventOf<TEventArgs>(string typeName, string eventName) => new ManagedEvent<TEventArgs>($"{typeName}.{eventName}", monitor, modRegistry);
|
||||||
|
|
||||||
// init events (new)
|
// init events (new)
|
||||||
|
@ -223,9 +223,9 @@ namespace StardewModdingAPI.Framework.Events
|
||||||
this.ObjectListChanged = ManageEventOf<ObjectListChangedEventArgs>(nameof(IModEvents.World), nameof(IWorldEvents.ObjectListChanged));
|
this.ObjectListChanged = ManageEventOf<ObjectListChangedEventArgs>(nameof(IModEvents.World), nameof(IWorldEvents.ObjectListChanged));
|
||||||
this.TerrainFeatureListChanged = ManageEventOf<TerrainFeatureListChangedEventArgs>(nameof(IModEvents.World), nameof(IWorldEvents.TerrainFeatureListChanged));
|
this.TerrainFeatureListChanged = ManageEventOf<TerrainFeatureListChangedEventArgs>(nameof(IModEvents.World), nameof(IWorldEvents.TerrainFeatureListChanged));
|
||||||
|
|
||||||
this.LoadStageChanged = ManageEventOf<LoadStageChangedEventArgs>(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.LoadStageChanged));
|
this.LoadStageChanged = ManageEventOf<LoadStageChangedEventArgs>(nameof(IModEvents.Specialized), nameof(ISpecializedEvents.LoadStageChanged));
|
||||||
this.UnvalidatedUpdateTicking = ManageEventOf<UnvalidatedUpdateTickingEventArgs>(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicking));
|
this.UnvalidatedUpdateTicking = ManageEventOf<UnvalidatedUpdateTickingEventArgs>(nameof(IModEvents.Specialized), nameof(ISpecializedEvents.UnvalidatedUpdateTicking));
|
||||||
this.UnvalidatedUpdateTicked = ManageEventOf<UnvalidatedUpdateTickedEventArgs>(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicked));
|
this.UnvalidatedUpdateTicked = ManageEventOf<UnvalidatedUpdateTickedEventArgs>(nameof(IModEvents.Specialized), nameof(ISpecializedEvents.UnvalidatedUpdateTicked));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ namespace StardewModdingAPI.Framework.Events
|
||||||
/// <summary>Events raised when something changes in the world.</summary>
|
/// <summary>Events raised when something changes in the world.</summary>
|
||||||
public IWorldEvents World { get; }
|
public IWorldEvents World { get; }
|
||||||
|
|
||||||
/// <summary>Events serving specialised edge cases that shouldn't be used by most mods.</summary>
|
/// <summary>Events serving specialized edge cases that shouldn't be used by most mods.</summary>
|
||||||
public ISpecialisedEvents Specialised { get; }
|
public ISpecializedEvents Specialized { get; }
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
|
@ -44,7 +44,7 @@ namespace StardewModdingAPI.Framework.Events
|
||||||
this.Multiplayer = new ModMultiplayerEvents(mod, eventManager);
|
this.Multiplayer = new ModMultiplayerEvents(mod, eventManager);
|
||||||
this.Player = new ModPlayerEvents(mod, eventManager);
|
this.Player = new ModPlayerEvents(mod, eventManager);
|
||||||
this.World = new ModWorldEvents(mod, eventManager);
|
this.World = new ModWorldEvents(mod, eventManager);
|
||||||
this.Specialised = new ModSpecialisedEvents(mod, eventManager);
|
this.Specialized = new ModSpecializedEvents(mod, eventManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ namespace StardewModdingAPI.Framework.Events
|
||||||
remove => this.EventManager.Saved.Remove(value);
|
remove => this.EventManager.Saved.Remove(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Raised after the player loads a save slot and the world is initialised.</summary>
|
/// <summary>Raised after the player loads a save slot and the world is initialized.</summary>
|
||||||
public event EventHandler<SaveLoadedEventArgs> SaveLoaded
|
public event EventHandler<SaveLoadedEventArgs> SaveLoaded
|
||||||
{
|
{
|
||||||
add => this.EventManager.SaveLoaded.Add(value);
|
add => this.EventManager.SaveLoaded.Add(value);
|
||||||
|
|
|
@ -3,8 +3,8 @@ using StardewModdingAPI.Events;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Framework.Events
|
namespace StardewModdingAPI.Framework.Events
|
||||||
{
|
{
|
||||||
/// <summary>Events serving specialised edge cases that shouldn't be used by most mods.</summary>
|
/// <summary>Events serving specialized edge cases that shouldn't be used by most mods.</summary>
|
||||||
internal class ModSpecialisedEvents : ModEventsBase, ISpecialisedEvents
|
internal class ModSpecializedEvents : ModEventsBase, ISpecializedEvents
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
||||||
** Accessors
|
** Accessors
|
||||||
|
@ -37,7 +37,7 @@ namespace StardewModdingAPI.Framework.Events
|
||||||
/// <summary>Construct an instance.</summary>
|
/// <summary>Construct an instance.</summary>
|
||||||
/// <param name="mod">The mod which uses this instance.</param>
|
/// <param name="mod">The mod which uses this instance.</param>
|
||||||
/// <param name="eventManager">The underlying event manager.</param>
|
/// <param name="eventManager">The underlying event manager.</param>
|
||||||
internal ModSpecialisedEvents(IModMetadata mod, EventManager eventManager)
|
internal ModSpecializedEvents(IModMetadata mod, EventManager eventManager)
|
||||||
: base(mod, eventManager) { }
|
: base(mod, eventManager) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace StardewModdingAPI.Framework
|
||||||
["1.04"] = "1.0.4",
|
["1.04"] = "1.0.4",
|
||||||
["1.05"] = "1.0.5",
|
["1.05"] = "1.0.5",
|
||||||
["1.051"] = "1.0.6-prerelease1", // not a very good mapping, but good enough for SMAPI's purposes.
|
["1.051"] = "1.0.6-prerelease1", // not a very good mapping, but good enough for SMAPI's purposes.
|
||||||
["1.051b"] = "1.0.6-prelease2",
|
["1.051b"] = "1.0.6-prerelease2",
|
||||||
["1.06"] = "1.0.6",
|
["1.06"] = "1.0.6",
|
||||||
["1.07"] = "1.0.7",
|
["1.07"] = "1.0.7",
|
||||||
["1.07a"] = "1.0.8-prerelease1",
|
["1.07a"] = "1.0.8-prerelease1",
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace StardewModdingAPI.Framework
|
||||||
** Exceptions
|
** Exceptions
|
||||||
****/
|
****/
|
||||||
/// <summary>Get a string representation of an exception suitable for writing to the error log.</summary>
|
/// <summary>Get a string representation of an exception suitable for writing to the error log.</summary>
|
||||||
/// <param name="exception">The error to summarise.</param>
|
/// <param name="exception">The error to summarize.</param>
|
||||||
public static string GetLogSummary(this Exception exception)
|
public static string GetLogSummary(this Exception exception)
|
||||||
{
|
{
|
||||||
switch (exception)
|
switch (exception)
|
||||||
|
|
|
@ -87,7 +87,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.AssertAndNormaliseAssetName(key);
|
this.AssertAndNormalizeAssetName(key);
|
||||||
switch (source)
|
switch (source)
|
||||||
{
|
{
|
||||||
case ContentSource.GameContent:
|
case ContentSource.GameContent:
|
||||||
|
@ -106,12 +106,12 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Normalise an asset name so it's consistent with those generated by the game. This is mainly useful for string comparisons like <see cref="string.StartsWith(string)"/> on generated asset names, and isn't necessary when passing asset names into other content helper methods.</summary>
|
/// <summary>Normalize an asset name so it's consistent with those generated by the game. This is mainly useful for string comparisons like <see cref="string.StartsWith(string)"/> on generated asset names, and isn't necessary when passing asset names into other content helper methods.</summary>
|
||||||
/// <param name="assetName">The asset key.</param>
|
/// <param name="assetName">The asset key.</param>
|
||||||
[Pure]
|
[Pure]
|
||||||
public string NormaliseAssetName(string assetName)
|
public string NormalizeAssetName(string assetName)
|
||||||
{
|
{
|
||||||
return this.ModContentManager.AssertAndNormaliseAssetName(assetName);
|
return this.ModContentManager.AssertAndNormalizeAssetName(assetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get the underlying key in the game's content cache for an asset. This can be used to load custom map tilesheets, but should be avoided when you can use the content API instead. This does not validate whether the asset exists.</summary>
|
/// <summary>Get the underlying key in the game's content cache for an asset. This can be used to load custom map tilesheets, but should be avoided when you can use the content API instead. This does not validate whether the asset exists.</summary>
|
||||||
|
@ -123,7 +123,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
switch (source)
|
switch (source)
|
||||||
{
|
{
|
||||||
case ContentSource.GameContent:
|
case ContentSource.GameContent:
|
||||||
return this.GameContentManager.AssertAndNormaliseAssetName(key);
|
return this.GameContentManager.AssertAndNormalizeAssetName(key);
|
||||||
|
|
||||||
case ContentSource.ModFolder:
|
case ContentSource.ModFolder:
|
||||||
return this.ModContentManager.GetInternalAssetKey(key);
|
return this.ModContentManager.GetInternalAssetKey(key);
|
||||||
|
@ -170,9 +170,9 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
/// <param name="key">The asset key to check.</param>
|
/// <param name="key">The asset key to check.</param>
|
||||||
/// <exception cref="ArgumentException">The asset key is empty or contains invalid characters.</exception>
|
/// <exception cref="ArgumentException">The asset key is empty or contains invalid characters.</exception>
|
||||||
[SuppressMessage("ReSharper", "ParameterOnlyUsedForPreconditionCheck.Local", Justification = "Parameter is only used for assertion checks by design.")]
|
[SuppressMessage("ReSharper", "ParameterOnlyUsedForPreconditionCheck.Local", Justification = "Parameter is only used for assertion checks by design.")]
|
||||||
private void AssertAndNormaliseAssetName(string key)
|
private void AssertAndNormalizeAssetName(string key)
|
||||||
{
|
{
|
||||||
this.ModContentManager.AssertAndNormaliseAssetName(key);
|
this.ModContentManager.AssertAndNormalizeAssetName(key);
|
||||||
if (Path.IsPathRooted(key))
|
if (Path.IsPathRooted(key))
|
||||||
throw new ArgumentException("The asset key must not be an absolute path.");
|
throw new ArgumentException("The asset key must not be an absolute path.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation.Models;
|
using StardewModdingAPI.Toolkit.Serialization.Models;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Framework.ModHelpers
|
namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
return this.ContentPacks.Value;
|
return this.ContentPacks.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Create a temporary content pack to read files from a directory, using randomised manifest fields. This will generate fake manifest data; any <c>manifest.json</c> in the directory will be ignored. Temporary content packs will not appear in the SMAPI log and update checks will not be performed.</summary>
|
/// <summary>Create a temporary content pack to read files from a directory, using randomized manifest fields. This will generate fake manifest data; any <c>manifest.json</c> in the directory will be ignored. Temporary content packs will not appear in the SMAPI log and update checks will not be performed.</summary>
|
||||||
/// <param name="directoryPath">The absolute directory path containing the content pack files.</param>
|
/// <param name="directoryPath">The absolute directory path containing the content pack files.</param>
|
||||||
public IContentPack CreateFake(string directoryPath)
|
public IContentPack CreateFake(string directoryPath)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation;
|
using StardewModdingAPI.Toolkit.Serialization;
|
||||||
using StardewModdingAPI.Toolkit.Utilities;
|
using StardewModdingAPI.Toolkit.Utilities;
|
||||||
using StardewValley;
|
using StardewValley;
|
||||||
|
|
||||||
|
@ -40,14 +40,14 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
/// <summary>Read data from a JSON file in the mod's folder.</summary>
|
/// <summary>Read data from a JSON file in the mod's folder.</summary>
|
||||||
/// <typeparam name="TModel">The model type. This should be a plain class that has public properties for the data you want. The properties can be complex types.</typeparam>
|
/// <typeparam name="TModel">The model type. This should be a plain class that has public properties for the data you want. The properties can be complex types.</typeparam>
|
||||||
/// <param name="path">The file path relative to the mod folder.</param>
|
/// <param name="path">The file path relative to the mod folder.</param>
|
||||||
/// <returns>Returns the deserialised model, or <c>null</c> if the file doesn't exist or is empty.</returns>
|
/// <returns>Returns the deserialized model, or <c>null</c> if the file doesn't exist or is empty.</returns>
|
||||||
/// <exception cref="InvalidOperationException">The <paramref name="path"/> is not relative or contains directory climbing (../).</exception>
|
/// <exception cref="InvalidOperationException">The <paramref name="path"/> is not relative or contains directory climbing (../).</exception>
|
||||||
public TModel ReadJsonFile<TModel>(string path) where TModel : class
|
public TModel ReadJsonFile<TModel>(string path) where TModel : class
|
||||||
{
|
{
|
||||||
if (!PathUtilities.IsSafeRelativePath(path))
|
if (!PathUtilities.IsSafeRelativePath(path))
|
||||||
throw new InvalidOperationException($"You must call {nameof(IModHelper.Data)}.{nameof(this.ReadJsonFile)} with a relative path.");
|
throw new InvalidOperationException($"You must call {nameof(IModHelper.Data)}.{nameof(this.ReadJsonFile)} with a relative path.");
|
||||||
|
|
||||||
path = Path.Combine(this.ModFolderPath, PathUtilities.NormalisePathSeparators(path));
|
path = Path.Combine(this.ModFolderPath, PathUtilities.NormalizePathSeparators(path));
|
||||||
return this.JsonHelper.ReadJsonFileIfExists(path, out TModel data)
|
return this.JsonHelper.ReadJsonFileIfExists(path, out TModel data)
|
||||||
? data
|
? data
|
||||||
: null;
|
: null;
|
||||||
|
@ -63,7 +63,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
if (!PathUtilities.IsSafeRelativePath(path))
|
if (!PathUtilities.IsSafeRelativePath(path))
|
||||||
throw new InvalidOperationException($"You must call {nameof(IMod.Helper)}.{nameof(IModHelper.Data)}.{nameof(this.WriteJsonFile)} with a relative path (without directory climbing).");
|
throw new InvalidOperationException($"You must call {nameof(IMod.Helper)}.{nameof(IModHelper.Data)}.{nameof(this.WriteJsonFile)} with a relative path (without directory climbing).");
|
||||||
|
|
||||||
path = Path.Combine(this.ModFolderPath, PathUtilities.NormalisePathSeparators(path));
|
path = Path.Combine(this.ModFolderPath, PathUtilities.NormalizePathSeparators(path));
|
||||||
this.JsonHelper.WriteJsonFile(path, data);
|
this.JsonHelper.WriteJsonFile(path, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
throw new InvalidOperationException($"Can't use {nameof(IMod.Helper)}.{nameof(IModHelper.Data)}.{nameof(this.ReadSaveData)} because this isn't the main player. (Save files are stored on the main player's computer.)");
|
throw new InvalidOperationException($"Can't use {nameof(IMod.Helper)}.{nameof(IModHelper.Data)}.{nameof(this.ReadSaveData)} because this isn't the main player. (Save files are stored on the main player's computer.)");
|
||||||
|
|
||||||
return Game1.CustomData.TryGetValue(this.GetSaveFileKey(key), out string value)
|
return Game1.CustomData.TryGetValue(this.GetSaveFileKey(key), out string value)
|
||||||
? this.JsonHelper.Deserialise<TModel>(value)
|
? this.JsonHelper.Deserialize<TModel>(value)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
|
|
||||||
string internalKey = this.GetSaveFileKey(key);
|
string internalKey = this.GetSaveFileKey(key);
|
||||||
if (data != null)
|
if (data != null)
|
||||||
Game1.CustomData[internalKey] = this.JsonHelper.Serialise(data, Formatting.None);
|
Game1.CustomData[internalKey] = this.JsonHelper.Serialize(data, Formatting.None);
|
||||||
else
|
else
|
||||||
Game1.CustomData.Remove(internalKey);
|
Game1.CustomData.Remove(internalKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using StardewModdingAPI.Events;
|
using StardewModdingAPI.Events;
|
||||||
using StardewModdingAPI.Framework.Input;
|
using StardewModdingAPI.Framework.Input;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation;
|
using StardewModdingAPI.Toolkit.Serialization;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Framework.ModHelpers
|
namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
{
|
{
|
||||||
|
@ -73,7 +73,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
if (!Directory.Exists(modDirectory))
|
if (!Directory.Exists(modDirectory))
|
||||||
throw new InvalidOperationException("The specified mod directory does not exist.");
|
throw new InvalidOperationException("The specified mod directory does not exist.");
|
||||||
|
|
||||||
// initialise
|
// initialize
|
||||||
this.DirectoryPath = modDirectory;
|
this.DirectoryPath = modDirectory;
|
||||||
this.Content = contentHelper ?? throw new ArgumentNullException(nameof(contentHelper));
|
this.Content = contentHelper ?? throw new ArgumentNullException(nameof(contentHelper));
|
||||||
this.ContentPacks = contentPackHelper ?? throw new ArgumentNullException(nameof(contentPackHelper));
|
this.ContentPacks = contentPackHelper ?? throw new ArgumentNullException(nameof(contentPackHelper));
|
||||||
|
|
|
@ -75,9 +75,9 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
public TInterface GetApi<TInterface>(string uniqueID) where TInterface : class
|
public TInterface GetApi<TInterface>(string uniqueID) where TInterface : class
|
||||||
{
|
{
|
||||||
// validate
|
// validate
|
||||||
if (!this.Registry.AreAllModsInitialised)
|
if (!this.Registry.AreAllModsInitialized)
|
||||||
{
|
{
|
||||||
this.Monitor.Log("Tried to access a mod-provided API before all mods were initialised.", LogLevel.Error);
|
this.Monitor.Log("Tried to access a mod-provided API before all mods were initialized.", LogLevel.Error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!typeof(TInterface).IsInterface)
|
if (!typeof(TInterface).IsInterface)
|
||||||
|
|
|
@ -5,7 +5,7 @@ using StardewModdingAPI.Framework.Reflection;
|
||||||
namespace StardewModdingAPI.Framework.ModHelpers
|
namespace StardewModdingAPI.Framework.ModHelpers
|
||||||
{
|
{
|
||||||
/// <summary>Provides helper methods for accessing private game code.</summary>
|
/// <summary>Provides helper methods for accessing private game code.</summary>
|
||||||
/// <remarks>This implementation searches up the type hierarchy, and caches the reflected fields and methods with a sliding expiry (to optimise performance without unnecessary memory usage).</remarks>
|
/// <remarks>This implementation searches up the type hierarchy, and caches the reflected fields and methods with a sliding expiry (to optimize performance without unnecessary memory usage).</remarks>
|
||||||
internal class ReflectionHelper : BaseHelper, IReflectionHelper
|
internal class ReflectionHelper : BaseHelper, IReflectionHelper
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
||||||
|
|
|
@ -317,7 +317,7 @@ namespace StardewModdingAPI.Framework.ModLoading
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Process the result from an instruction handler.</summary>
|
/// <summary>Process the result from an instruction handler.</summary>
|
||||||
/// <param name="mod">The mod being analysed.</param>
|
/// <param name="mod">The mod being analyzed.</param>
|
||||||
/// <param name="handler">The instruction handler.</param>
|
/// <param name="handler">The instruction handler.</param>
|
||||||
/// <param name="result">The result returned by the handler.</param>
|
/// <param name="result">The result returned by the handler.</param>
|
||||||
/// <param name="loggedMessages">The messages already logged for the current mod.</param>
|
/// <param name="loggedMessages">The messages already logged for the current mod.</param>
|
||||||
|
@ -341,9 +341,9 @@ namespace StardewModdingAPI.Framework.ModLoading
|
||||||
mod.SetWarning(ModWarning.PatchesGame);
|
mod.SetWarning(ModWarning.PatchesGame);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InstructionHandleResult.DetectedSaveSerialiser:
|
case InstructionHandleResult.DetectedSaveSerializer:
|
||||||
this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Detected possible save serialiser change ({handler.NounPhrase}) in assembly {filename}.");
|
this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Detected possible save serializer change ({handler.NounPhrase}) in assembly {filename}.");
|
||||||
mod.SetWarning(ModWarning.ChangesSaveSerialiser);
|
mod.SetWarning(ModWarning.ChangesSaveSerializer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InstructionHandleResult.DetectedUnvalidatedUpdateTick:
|
case InstructionHandleResult.DetectedUnvalidatedUpdateTick:
|
||||||
|
@ -370,7 +370,7 @@ namespace StardewModdingAPI.Framework.ModLoading
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new NotSupportedException($"Unrecognised instruction handler result '{result}'.");
|
throw new NotSupportedException($"Unrecognized instruction handler result '{result}'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
|
||||||
** Protected methods
|
** Protected methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Get whether a CIL instruction matches.</summary>
|
/// <summary>Get whether a CIL instruction matches.</summary>
|
||||||
/// <param name="method">The method deifnition.</param>
|
/// <param name="method">The method definition.</param>
|
||||||
protected bool IsMatch(MethodDefinition method)
|
protected bool IsMatch(MethodDefinition method)
|
||||||
{
|
{
|
||||||
if (this.IsMatch(method.ReturnType))
|
if (this.IsMatch(method.ReturnType))
|
||||||
|
|
|
@ -18,12 +18,12 @@ namespace StardewModdingAPI.Framework.ModLoading
|
||||||
DetectedGamePatch,
|
DetectedGamePatch,
|
||||||
|
|
||||||
/// <summary>The instruction is compatible, but affects the save serializer in a way that may make saves unloadable without the mod.</summary>
|
/// <summary>The instruction is compatible, but affects the save serializer in a way that may make saves unloadable without the mod.</summary>
|
||||||
DetectedSaveSerialiser,
|
DetectedSaveSerializer,
|
||||||
|
|
||||||
/// <summary>The instruction is compatible, but uses the <c>dynamic</c> keyword which won't work on Linux/Mac.</summary>
|
/// <summary>The instruction is compatible, but uses the <c>dynamic</c> keyword which won't work on Linux/Mac.</summary>
|
||||||
DetectedDynamic,
|
DetectedDynamic,
|
||||||
|
|
||||||
/// <summary>The instruction is compatible, but references <see cref="ISpecialisedEvents.UnvalidatedUpdateTicking"/> or <see cref="ISpecialisedEvents.UnvalidatedUpdateTicked"/> which may impact stability.</summary>
|
/// <summary>The instruction is compatible, but references <see cref="ISpecializedEvents.UnvalidatedUpdateTicking"/> or <see cref="ISpecializedEvents.UnvalidatedUpdateTicked"/> which may impact stability.</summary>
|
||||||
DetectedUnvalidatedUpdateTick,
|
DetectedUnvalidatedUpdateTick,
|
||||||
|
|
||||||
/// <summary>The instruction accesses the filesystem directly.</summary>
|
/// <summary>The instruction accesses the filesystem directly.</summary>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace StardewModdingAPI.Framework.ModLoading
|
namespace StardewModdingAPI.Framework.ModLoading
|
||||||
{
|
{
|
||||||
/// <summary>The status of a given mod in the dependency-sorting algorithm.</summary>
|
/// <summary>The status of a given mod in the dependency-sorting algorithm.</summary>
|
||||||
internal enum ModDependencyStatus
|
internal enum ModDependencyStatus
|
||||||
|
@ -6,7 +6,7 @@
|
||||||
/// <summary>The mod hasn't been visited yet.</summary>
|
/// <summary>The mod hasn't been visited yet.</summary>
|
||||||
Queued,
|
Queued,
|
||||||
|
|
||||||
/// <summary>The mod is currently being analysed as part of a dependency chain.</summary>
|
/// <summary>The mod is currently being analyzed as part of a dependency chain.</summary>
|
||||||
Checking,
|
Checking,
|
||||||
|
|
||||||
/// <summary>The mod has already been sorted.</summary>
|
/// <summary>The mod has already been sorted.</summary>
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.Linq;
|
||||||
using StardewModdingAPI.Toolkit;
|
using StardewModdingAPI.Toolkit;
|
||||||
using StardewModdingAPI.Toolkit.Framework.ModData;
|
using StardewModdingAPI.Toolkit.Framework.ModData;
|
||||||
using StardewModdingAPI.Toolkit.Framework.ModScanning;
|
using StardewModdingAPI.Toolkit.Framework.ModScanning;
|
||||||
using StardewModdingAPI.Toolkit.Serialisation.Models;
|
using StardewModdingAPI.Toolkit.Serialization.Models;
|
||||||
using StardewModdingAPI.Toolkit.Utilities;
|
using StardewModdingAPI.Toolkit.Utilities;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Framework.ModLoading
|
namespace StardewModdingAPI.Framework.ModLoading
|
||||||
|
@ -143,11 +143,11 @@ namespace StardewModdingAPI.Framework.ModLoading
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalid capitalisation
|
// invalid capitalization
|
||||||
string actualFilename = new DirectoryInfo(mod.DirectoryPath).GetFiles(mod.Manifest.EntryDll).FirstOrDefault()?.Name;
|
string actualFilename = new DirectoryInfo(mod.DirectoryPath).GetFiles(mod.Manifest.EntryDll).FirstOrDefault()?.Name;
|
||||||
if (actualFilename != mod.Manifest.EntryDll)
|
if (actualFilename != mod.Manifest.EntryDll)
|
||||||
{
|
{
|
||||||
mod.SetStatus(ModMetadataStatus.Failed, $"its {nameof(IManifest.EntryDll)} value '{mod.Manifest.EntryDll}' doesn't match the actual file capitalisation '{actualFilename}'. The capitalisation must match for crossplatform compatibility.");
|
mod.SetStatus(ModMetadataStatus.Failed, $"its {nameof(IManifest.EntryDll)} value '{mod.Manifest.EntryDll}' doesn't match the actual file capitalization '{actualFilename}'. The capitalization must match for crossplatform compatibility.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ namespace StardewModdingAPI.Framework.ModLoading
|
||||||
/// <param name="modDatabase">Handles access to SMAPI's internal mod metadata list.</param>
|
/// <param name="modDatabase">Handles access to SMAPI's internal mod metadata list.</param>
|
||||||
public IEnumerable<IModMetadata> ProcessDependencies(IEnumerable<IModMetadata> mods, ModDatabase modDatabase)
|
public IEnumerable<IModMetadata> ProcessDependencies(IEnumerable<IModMetadata> mods, ModDatabase modDatabase)
|
||||||
{
|
{
|
||||||
// initialise metadata
|
// initialize metadata
|
||||||
mods = mods.ToArray();
|
mods = mods.ToArray();
|
||||||
var sortedMods = new Stack<IModMetadata>();
|
var sortedMods = new Stack<IModMetadata>();
|
||||||
var states = mods.ToDictionary(mod => mod, mod => ModDependencyStatus.Queued);
|
var states = mods.ToDictionary(mod => mod, mod => ModDependencyStatus.Queued);
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace StardewModdingAPI.Framework.ModLoading
|
||||||
{
|
{
|
||||||
bool HeuristicallyEquals(string typeNameA, string typeNameB, IDictionary<string, string> tokenMap)
|
bool HeuristicallyEquals(string typeNameA, string typeNameB, IDictionary<string, string> tokenMap)
|
||||||
{
|
{
|
||||||
// analyse type names
|
// analyze type names
|
||||||
bool hasTokensA = typeNameA.Contains("!");
|
bool hasTokensA = typeNameA.Contains("!");
|
||||||
bool hasTokensB = typeNameB.Contains("!");
|
bool hasTokensB = typeNameB.Contains("!");
|
||||||
bool isTokenA = hasTokensA && typeNameA[0] == '!';
|
bool isTokenA = hasTokensA && typeNameA[0] == '!';
|
||||||
|
|
|
@ -21,8 +21,8 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <summary>Whether all mod assemblies have been loaded.</summary>
|
/// <summary>Whether all mod assemblies have been loaded.</summary>
|
||||||
public bool AreAllModsLoaded { get; set; }
|
public bool AreAllModsLoaded { get; set; }
|
||||||
|
|
||||||
/// <summary>Whether all mods have been initialised and their <see cref="IMod.Entry"/> method called.</summary>
|
/// <summary>Whether all mods have been initialized and their <see cref="IMod.Entry"/> method called.</summary>
|
||||||
public bool AreAllModsInitialised { get; set; }
|
public bool AreAllModsInitialized { get; set; }
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
|
@ -62,7 +62,7 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <returns>Returns the matching mod's metadata, or <c>null</c> if not found.</returns>
|
/// <returns>Returns the matching mod's metadata, or <c>null</c> if not found.</returns>
|
||||||
public IModMetadata Get(string uniqueID)
|
public IModMetadata Get(string uniqueID)
|
||||||
{
|
{
|
||||||
// normalise search ID
|
// normalize search ID
|
||||||
if (string.IsNullOrWhiteSpace(uniqueID))
|
if (string.IsNullOrWhiteSpace(uniqueID))
|
||||||
return null;
|
return null;
|
||||||
uniqueID = uniqueID.Trim();
|
uniqueID = uniqueID.Trim();
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace StardewModdingAPI.Framework
|
||||||
if (string.IsNullOrWhiteSpace(source))
|
if (string.IsNullOrWhiteSpace(source))
|
||||||
throw new ArgumentException("The log source cannot be empty.");
|
throw new ArgumentException("The log source cannot be empty.");
|
||||||
|
|
||||||
// initialise
|
// initialize
|
||||||
this.Source = source;
|
this.Source = source;
|
||||||
this.LogFile = logFile ?? throw new ArgumentNullException(nameof(logFile), "The log file manager cannot be null.");
|
this.LogFile = logFile ?? throw new ArgumentNullException(nameof(logFile), "The log file manager cannot be null.");
|
||||||
this.ConsoleWriter = new ColorfulConsoleWriter(Constants.Platform, colorScheme);
|
this.ConsoleWriter = new ColorfulConsoleWriter(Constants.Platform, colorScheme);
|
||||||
|
|
|
@ -2,7 +2,7 @@ using StardewValley;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Framework.Networking
|
namespace StardewModdingAPI.Framework.Networking
|
||||||
{
|
{
|
||||||
/// <summary>Network message types recognised by SMAPI and Stardew Valley.</summary>
|
/// <summary>Network message types recognized by SMAPI and Stardew Valley.</summary>
|
||||||
internal enum MessageType : byte
|
internal enum MessageType : byte
|
||||||
{
|
{
|
||||||
/*********
|
/*********
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue