From d9c001a39f4562038fb608468169ea22cf074111 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 9 May 2021 12:06:18 -0400 Subject: fix version zero validation --- src/SMAPI/Framework/ModLoading/ModResolver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index c70820e4..7761a567 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -173,7 +173,7 @@ namespace StardewModdingAPI.Framework.ModLoading if (string.IsNullOrWhiteSpace(mod.Manifest.Name)) missingFields.Add(nameof(IManifest.Name)); - if (mod.Manifest.Version == null || mod.Manifest.Version.ToString() == "0.0") + if (mod.Manifest.Version == null || mod.Manifest.Version.ToString() == "0.0.0") missingFields.Add(nameof(IManifest.Version)); if (string.IsNullOrWhiteSpace(mod.Manifest.UniqueID)) missingFields.Add(nameof(IManifest.UniqueID)); -- cgit From 4b391d631ccde301969ae0c04f407a01ba4055b1 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 9 May 2021 12:12:03 -0400 Subject: normalize manifest array fields --- src/SMAPI.Toolkit/Framework/ModData/ModDataField.cs | 2 +- src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs | 2 +- src/SMAPI.Toolkit/Serialization/Models/Manifest.cs | 10 ++++++++++ src/SMAPI/Framework/ModLoading/ModMetadata.cs | 19 +++++++++++-------- src/SMAPI/Framework/ModLoading/ModResolver.cs | 2 +- src/SMAPI/Framework/SCore.cs | 19 ++++++++----------- 6 files changed, 32 insertions(+), 22 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataField.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataField.cs index 6658d219..b02be3e4 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModDataField.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataField.cs @@ -66,7 +66,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData { // update key case ModDataFieldKey.UpdateKey: - return manifest.UpdateKeys != null && manifest.UpdateKeys.Any(p => !string.IsNullOrWhiteSpace(p)); + return manifest.UpdateKeys.Any(p => !string.IsNullOrWhiteSpace(p)); // non-manifest fields case ModDataFieldKey.StatusReasonPhrase: diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs index d0df09a1..825b98e5 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs @@ -69,7 +69,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning public IEnumerable GetUpdateKeys(Manifest manifest) { return - (manifest.UpdateKeys ?? new string[0]) + manifest.UpdateKeys .Where(p => !string.IsNullOrWhiteSpace(p)) .ToArray(); } diff --git a/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs b/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs index 99e85cbd..46b654a5 100644 --- a/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs +++ b/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Runtime.Serialization; using Newtonsoft.Json; using StardewModdingAPI.Toolkit.Serialization.Converters; @@ -70,5 +71,14 @@ namespace StardewModdingAPI.Toolkit.Serialization.Models this.UpdateKeys = new string[0]; this.ContentPackFor = new ManifestContentPackFor { UniqueID = contentPackFor }; } + + /// Normalize the model after it's deserialized. + /// The deserialization context. + [OnDeserialized] + public void OnDeserialized(StreamingContext context) + { + this.Dependencies ??= new IManifestDependency[0]; + this.UpdateKeys ??= new string[0]; + } } } diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs index 17e6d59a..b703f74c 100644 --- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs +++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs @@ -195,7 +195,10 @@ namespace StardewModdingAPI.Framework.ModLoading /// public IEnumerable GetUpdateKeys(bool validOnly = false) { - foreach (string rawKey in this.Manifest?.UpdateKeys ?? new string[0]) + if (this.Manifest == null) + yield break; + + foreach (string rawKey in this.Manifest.UpdateKeys) { UpdateKey updateKey = UpdateKey.Parse(rawKey); if (updateKey.LooksValid || !validOnly) @@ -251,16 +254,16 @@ namespace StardewModdingAPI.Framework.ModLoading { var ids = new Dictionary(StringComparer.OrdinalIgnoreCase); - // yield dependencies - if (this.Manifest?.Dependencies != null) + if (this.Manifest != null) { - foreach (var entry in this.Manifest?.Dependencies) + // yield dependencies + foreach (IManifestDependency entry in this.Manifest.Dependencies) ids[entry.UniqueID] = entry.IsRequired; - } - // yield content pack parent - if (this.Manifest?.ContentPackFor?.UniqueID != null) - ids[this.Manifest.ContentPackFor.UniqueID] = true; + // yield content pack parent + if (this.Manifest.ContentPackFor?.UniqueID != null) + ids[this.Manifest.ContentPackFor.UniqueID] = true; + } return ids; } diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index 7761a567..3bf2b0a1 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -82,7 +82,7 @@ namespace StardewModdingAPI.Framework.ModLoading // get update URLs List updateUrls = new List(); - foreach (string key in mod.Manifest.UpdateKeys ?? new string[0]) + foreach (string key in mod.Manifest.UpdateKeys) { string url = getUpdateUrl(key); if (url != null) diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 5862b112..8b2c7544 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -1593,19 +1593,16 @@ namespace StardewModdingAPI.Framework // validate dependencies // Although dependencies are validated before mods are loaded, a dependency may have failed to load. - if (mod.Manifest.Dependencies?.Any() == true) + foreach (IManifestDependency dependency in mod.Manifest.Dependencies.Where(p => p.IsRequired)) { - foreach (IManifestDependency dependency in mod.Manifest.Dependencies.Where(p => p.IsRequired)) + if (this.ModRegistry.Get(dependency.UniqueID) == null) { - if (this.ModRegistry.Get(dependency.UniqueID) == null) - { - string dependencyName = mods - .FirstOrDefault(otherMod => otherMod.HasID(dependency.UniqueID)) - ?.DisplayName ?? dependency.UniqueID; - errorReasonPhrase = $"it needs the '{dependencyName}' mod, which couldn't be loaded."; - failReason = ModFailReason.MissingDependencies; - return false; - } + string dependencyName = mods + .FirstOrDefault(otherMod => otherMod.HasID(dependency.UniqueID)) + ?.DisplayName ?? dependency.UniqueID; + errorReasonPhrase = $"it needs the '{dependencyName}' mod, which couldn't be loaded."; + failReason = ModFailReason.MissingDependencies; + return false; } } -- cgit From 7c76c5cad2c6edac75d6387dbaa5999295be46d8 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 9 May 2021 12:13:39 -0400 Subject: add validation for the manifest 'Dependencies' field --- docs/release-notes.md | 1 + src/SMAPI/Framework/ModLoading/ModResolver.cs | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'src/SMAPI/Framework') diff --git a/docs/release-notes.md b/docs/release-notes.md index 859bf155..f3440d43 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -9,6 +9,7 @@ ## Upcoming release * For mod authors: + * Added validation for the manifest `Dependencies` field. * Fixed validation for mods with version `0.0.0`. ## 3.10.1 diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index 3bf2b0a1..2f506571 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -188,6 +188,28 @@ namespace StardewModdingAPI.Framework.ModLoading // validate ID format if (!PathUtilities.IsSlug(mod.Manifest.UniqueID)) mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, "its manifest specifies an invalid ID (IDs must only contain letters, numbers, underscores, periods, or hyphens)."); + + // validate dependencies + foreach (var dependency in mod.Manifest.Dependencies) + { + // null dependency + if (dependency == null) + { + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its manifest has a null entry under {nameof(IManifest.Dependencies)}."); + continue; + } + + // missing ID + if (string.IsNullOrWhiteSpace(dependency.UniqueID)) + { + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its manifest has a {nameof(IManifest.Dependencies)} entry with no {nameof(IManifestDependency.UniqueID)} field."); + continue; + } + + // invalid ID + if (!PathUtilities.IsSlug(dependency.UniqueID)) + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its manifest has a {nameof(IManifest.Dependencies)} entry with an invalid {nameof(IManifestDependency.UniqueID)} field (IDs must only contain letters, numbers, underscores, periods, or hyphens)."); + } } // validate IDs are unique -- cgit From 4ac04ee3aca00f7c1e105ddabd1ed16995b17086 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 9 May 2021 12:19:30 -0400 Subject: fix error if a mod has a 'Dependencies' entry with no ID --- src/SMAPI/Framework/ModLoading/ModMetadata.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs index b703f74c..0ace084f 100644 --- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs +++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs @@ -195,7 +195,7 @@ namespace StardewModdingAPI.Framework.ModLoading /// public IEnumerable GetUpdateKeys(bool validOnly = false) { - if (this.Manifest == null) + if (!this.HasManifest()) yield break; foreach (string rawKey in this.Manifest.UpdateKeys) @@ -254,14 +254,17 @@ namespace StardewModdingAPI.Framework.ModLoading { var ids = new Dictionary(StringComparer.OrdinalIgnoreCase); - if (this.Manifest != null) + if (this.HasManifest()) { // yield dependencies foreach (IManifestDependency entry in this.Manifest.Dependencies) - ids[entry.UniqueID] = entry.IsRequired; + { + if (!string.IsNullOrWhiteSpace(entry.UniqueID)) + ids[entry.UniqueID] = entry.IsRequired; + } // yield content pack parent - if (this.Manifest.ContentPackFor?.UniqueID != null) + if (!string.IsNullOrWhiteSpace(this.Manifest.ContentPackFor?.UniqueID)) ids[this.Manifest.ContentPackFor.UniqueID] = true; } -- cgit From c310875f902f82ef3b9486e2ff3705106b2ad40c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 19 May 2021 23:38:10 -0400 Subject: fix 'loaded with custom settings' message shown with default settings --- docs/release-notes.md | 1 + src/SMAPI/Framework/Models/SConfig.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src/SMAPI/Framework') diff --git a/docs/release-notes.md b/docs/release-notes.md index 666dc8e4..a0b64bdc 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -15,6 +15,7 @@ * For mod authors: * Added validation for the manifest `Dependencies` field. * Fixed validation for mods with version `0.0.0`. + * Fixed _loaded with custom settings_ trace log when using default settings. ## 3.10.1 Released 03 May 2021 for Stardew Valley 1.5.4 or later. diff --git a/src/SMAPI/Framework/Models/SConfig.cs b/src/SMAPI/Framework/Models/SConfig.cs index a71bafd9..10bf9f94 100644 --- a/src/SMAPI/Framework/Models/SConfig.cs +++ b/src/SMAPI/Framework/Models/SConfig.cs @@ -22,7 +22,7 @@ namespace StardewModdingAPI.Framework.Models [nameof(VerboseLogging)] = false, [nameof(LogNetworkTraffic)] = false, [nameof(RewriteMods)] = true, - [nameof(AggressiveMemoryOptimizations)] = true + [nameof(AggressiveMemoryOptimizations)] = false }; /// The default values for , to log changes if different. -- cgit From b149e11338ba2dbaf030a70783d28b6be21ccf1e Mon Sep 17 00:00:00 2001 From: DiscipleOfEris Date: Wed, 26 May 2021 11:50:49 -0700 Subject: Add `World.FurnitureListChanged` event Create a new event available to SMAPI mods to track furniture changes. To facilitate the event, a `FurnitureListChangedEventArgs` class is added as well. Fixes #778 --- src/SMAPI/Events/FurnitureListChangedEventArgs.cs | 44 ++++++++++++++++++++++ src/SMAPI/Events/IWorldEvents.cs | 3 ++ src/SMAPI/Framework/Events/EventManager.cs | 4 ++ src/SMAPI/Framework/Events/ModWorldEvents.cs | 7 ++++ src/SMAPI/Framework/SCore.cs | 4 ++ .../Framework/StateTracking/LocationTracker.cs | 7 +++- .../StateTracking/Snapshots/LocationSnapshot.cs | 4 ++ 7 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/SMAPI/Events/FurnitureListChangedEventArgs.cs (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Events/FurnitureListChangedEventArgs.cs b/src/SMAPI/Events/FurnitureListChangedEventArgs.cs new file mode 100644 index 00000000..04fcf9ff --- /dev/null +++ b/src/SMAPI/Events/FurnitureListChangedEventArgs.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using StardewValley; +using StardewValley.Objects; + +namespace StardewModdingAPI.Events +{ + /// Event arguments for a event. + public class FurnitureListChangedEventArgs : EventArgs + { + /********* + ** Accessors + *********/ + /// The location which changed. + public GameLocation Location { get; } + + /// The furniture added to the location. + public IEnumerable Added { get; } + + /// The furniture removed from the location. + public IEnumerable Removed { get; } + + /// Whether this is the location containing the local player. + public bool IsCurrentLocation => object.ReferenceEquals(this.Location, Game1.player?.currentLocation); + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The location which changed. + /// The furniture added to the location. + /// The furniture removed from the location. + internal FurnitureListChangedEventArgs(GameLocation location, IEnumerable added, IEnumerable removed) + { + this.Location = location; + this.Added = added.ToArray(); + this.Removed = removed.ToArray(); + } + } +} diff --git a/src/SMAPI/Events/IWorldEvents.cs b/src/SMAPI/Events/IWorldEvents.cs index 9569a57b..c023e1f0 100644 --- a/src/SMAPI/Events/IWorldEvents.cs +++ b/src/SMAPI/Events/IWorldEvents.cs @@ -28,5 +28,8 @@ namespace StardewModdingAPI.Events /// Raised after terrain features (like floors and trees) are added or removed in a location. event EventHandler TerrainFeatureListChanged; + + /// Raised after furniture are added or removed in a location. + event EventHandler FurnitureListChanged; } } diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index f4abfffe..dfc289ed 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -162,6 +162,9 @@ namespace StardewModdingAPI.Framework.Events /// Raised after terrain features (like floors and trees) are added or removed in a location. public readonly ManagedEvent TerrainFeatureListChanged; + /// Raised after furniture are added or removed in a location. + public readonly ManagedEvent FurnitureListChanged; + /**** ** Specialized ****/ @@ -238,6 +241,7 @@ namespace StardewModdingAPI.Framework.Events this.ObjectListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.ObjectListChanged)); this.ChestInventoryChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.ChestInventoryChanged)); this.TerrainFeatureListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.TerrainFeatureListChanged)); + this.FurnitureListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.FurnitureListChanged)); this.LoadStageChanged = ManageEventOf(nameof(IModEvents.Specialized), nameof(ISpecializedEvents.LoadStageChanged)); this.UnvalidatedUpdateTicking = ManageEventOf(nameof(IModEvents.Specialized), nameof(ISpecializedEvents.UnvalidatedUpdateTicking), isPerformanceCritical: true); diff --git a/src/SMAPI/Framework/Events/ModWorldEvents.cs b/src/SMAPI/Framework/Events/ModWorldEvents.cs index 21b1b664..f4c40abc 100644 --- a/src/SMAPI/Framework/Events/ModWorldEvents.cs +++ b/src/SMAPI/Framework/Events/ModWorldEvents.cs @@ -65,6 +65,13 @@ namespace StardewModdingAPI.Framework.Events remove => this.EventManager.TerrainFeatureListChanged.Remove(value); } + /// Raised after furniture are added or removed in a location. + public event EventHandler FurnitureListChanged + { + add => this.EventManager.FurnitureListChanged.Add(value, this.Mod); + remove => this.EventManager.FurnitureListChanged.Remove(value); + } + /********* ** Public methods diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 8b2c7544..bf88798b 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -914,6 +914,10 @@ namespace StardewModdingAPI.Framework // terrain features changed if (locState.TerrainFeatures.IsChanged) events.TerrainFeatureListChanged.Raise(new TerrainFeatureListChangedEventArgs(location, locState.TerrainFeatures.Added, locState.TerrainFeatures.Removed)); + + // furniture changed + if (locState.Furniture.IsChanged) + events.FurnitureListChanged.Raise(new FurnitureListChangedEventArgs(location, locState.Furniture.Added, locState.Furniture.Removed)); } } diff --git a/src/SMAPI/Framework/StateTracking/LocationTracker.cs b/src/SMAPI/Framework/StateTracking/LocationTracker.cs index 519fe8f4..6d3a62bb 100644 --- a/src/SMAPI/Framework/StateTracking/LocationTracker.cs +++ b/src/SMAPI/Framework/StateTracking/LocationTracker.cs @@ -48,6 +48,9 @@ namespace StardewModdingAPI.Framework.StateTracking /// Tracks added or removed terrain features. public IDictionaryWatcher TerrainFeaturesWatcher { get; } + /// Tracks added or removed furniture. + public ICollectionWatcher FurnitureWatcher { get; } + /// Tracks items added or removed to chests. public IDictionary ChestWatchers { get; } = new Dictionary(); @@ -68,6 +71,7 @@ namespace StardewModdingAPI.Framework.StateTracking this.NpcsWatcher = WatcherFactory.ForNetCollection(location.characters); this.ObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects); this.TerrainFeaturesWatcher = WatcherFactory.ForNetDictionary(location.terrainFeatures); + this.FurnitureWatcher = WatcherFactory.ForNetCollection(location.furniture); this.Watchers.AddRange(new IWatcher[] { @@ -76,7 +80,8 @@ namespace StardewModdingAPI.Framework.StateTracking this.LargeTerrainFeaturesWatcher, this.NpcsWatcher, this.ObjectsWatcher, - this.TerrainFeaturesWatcher + this.TerrainFeaturesWatcher, + this.FurnitureWatcher }); this.UpdateChestWatcherList(added: location.Objects.Pairs, removed: new KeyValuePair[0]); diff --git a/src/SMAPI/Framework/StateTracking/Snapshots/LocationSnapshot.cs b/src/SMAPI/Framework/StateTracking/Snapshots/LocationSnapshot.cs index 6ae52fd0..6c9cc4f5 100644 --- a/src/SMAPI/Framework/StateTracking/Snapshots/LocationSnapshot.cs +++ b/src/SMAPI/Framework/StateTracking/Snapshots/LocationSnapshot.cs @@ -34,6 +34,9 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots /// Tracks added or removed terrain features. public SnapshotListDiff> TerrainFeatures { get; } = new SnapshotListDiff>(); + /// Tracks added or removed furniture. + public SnapshotListDiff Furniture { get; } = new SnapshotListDiff(); + /// Tracks changed chest inventories. public IDictionary ChestItems { get; } = new Dictionary(); @@ -59,6 +62,7 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots this.Npcs.Update(watcher.NpcsWatcher); this.Objects.Update(watcher.ObjectsWatcher); this.TerrainFeatures.Update(watcher.TerrainFeaturesWatcher); + this.Furniture.Update(watcher.FurnitureWatcher); // chest inventories this.ChestItems.Clear(); -- cgit From 66f8920c29567de615dbcb0a06e78f774d128f6b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 24 Jun 2021 20:17:34 -0400 Subject: log trace message if conflicting software is detected --- docs/release-notes.md | 1 + src/SMAPI/Framework/SCore.cs | 55 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) (limited to 'src/SMAPI/Framework') diff --git a/docs/release-notes.md b/docs/release-notes.md index 0879a072..f3f66430 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -17,6 +17,7 @@ * Added `World.FurnitureListChanged` event (thanks to DiscipleOfEris!). * Added asset propagation for building/house paint masks. * Added validation for the manifest `Dependencies` field. + * Added `TRACE` message if software known to cause issues is installed (currently MSI Afterburner and RivaTuner), to simplify troubleshooting. * Fixed [JSON schema](technical/web.md#using-a-schema-file-directly) in Visual Studio Code warning about comments or trailing commas. * Fixed JSON schema for `i18n` files requiring the wrong value for the `$schema` field. * Fixed validation for mods with version `0.0.0`. diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index bf88798b..2de2b21a 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -11,6 +11,9 @@ using System.Security; using System.Text; using System.Threading; using System.Threading.Tasks; +#if SMAPI_FOR_WINDOWS +using Microsoft.Win32; +#endif using Microsoft.Xna.Framework; #if SMAPI_FOR_XNA using System.Windows.Forms; @@ -376,6 +379,9 @@ namespace StardewModdingAPI.Framework mods = resolver.ProcessDependencies(mods, modDatabase).ToArray(); this.LoadMods(mods, this.Toolkit.JsonHelper, this.ContentCore, modDatabase); + // check for software likely to cause issues + this.CheckForSoftwareConflicts(); + // check for updates this.CheckForUpdatesAsync(mods); } @@ -1251,6 +1257,55 @@ namespace StardewModdingAPI.Framework this.LogManager.SetConsoleTitle(consoleTitle); } + /// Log a warning if software known to cause issues is installed. + private void CheckForSoftwareConflicts() + { +#if SMAPI_FOR_WINDOWS + this.Monitor.Log("Checking for known software conflicts..."); + + try + { + string[] registryKeys = { @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall", @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" }; + + string[] installedNames = registryKeys + .SelectMany(registryKey => + { + using RegistryKey key = Registry.LocalMachine.OpenSubKey(registryKey); + if (key == null) + return new string[0]; + + return key + .GetSubKeyNames() + .Select(subkeyName => + { + using RegistryKey subkey = key.OpenSubKey(subkeyName); + string displayName = (string)subkey?.GetValue("DisplayName"); + string displayVersion = (string)subkey?.GetValue("DisplayVersion"); + + if (displayName != null && displayVersion != null && displayName.EndsWith($" {displayVersion}")) + displayName = displayName.Substring(0, displayName.Length - displayVersion.Length - 1); + + return displayName; + }) + .ToArray(); + }) + .Where(name => name != null && (name.Contains("MSI Afterburner") || name.Contains("RivaTuner"))) + .Distinct() + .OrderBy(name => name) + .ToArray(); + + if (installedNames.Any()) + this.Monitor.Log($" Found {string.Join(" and ", installedNames)} installed, which can conflict with SMAPI. If you experience errors or crashes, try disabling that software or adding an exception for SMAPI / Stardew Valley."); + else + this.Monitor.Log(" None found!"); + } + catch (Exception ex) + { + this.Monitor.Log($"Failed when checking for conflicting software. Technical details:\n{ex}"); + } +#endif + } + /// Asynchronously check for a new version of SMAPI and any installed mods, and print alerts to the console if an update is available. /// The mods to include in the update check (if eligible). private void CheckForUpdatesAsync(IModMetadata[] mods) -- cgit From 5e3a1abbd421196ee63442c82cb6606b6630a6ca Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 26 Jun 2021 11:16:12 -0400 Subject: improve error if SMAPI fails to dispose on exit --- docs/release-notes.md | 7 ++++--- src/SMAPI/Framework/SCore.cs | 9 ++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/docs/release-notes.md b/docs/release-notes.md index f3f66430..76539ff6 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -9,6 +9,7 @@ ## Upcoming release * For players: + * Improved error if SMAPI fails to dispose on game exit. * Fixed error when running the Windows installer as administrator (thanks to LostLogic!). * Fixed `player_add` and `list_items` console commands not including some shirts _(in Console Commands)_. * Fixed installer error on some older Windows systems (thanks to eddyballs!). @@ -18,14 +19,14 @@ * Added asset propagation for building/house paint masks. * Added validation for the manifest `Dependencies` field. * Added `TRACE` message if software known to cause issues is installed (currently MSI Afterburner and RivaTuner), to simplify troubleshooting. - * Fixed [JSON schema](technical/web.md#using-a-schema-file-directly) in Visual Studio Code warning about comments or trailing commas. - * Fixed JSON schema for `i18n` files requiring the wrong value for the `$schema` field. * Fixed validation for mods with version `0.0.0`. * Fixed _loaded with custom settings_ trace log when using default settings. * Fixed `Constants.SaveFolderName` and `Constants.CurrentSavePath` not set correctly in rare cases. -* For the web UI: +* For the web UI and JSON validator: * Updated the JSON validator/schema for Content Patcher 1.23. + * Fixed [JSON schema](technical/web.md#using-a-schema-file-directly) in Visual Studio Code warning about comments or trailing commas. + * Fixed JSON schema for `i18n` files requiring the wrong value for the `$schema` field. ## 3.10.1 Released 03 May 2021 for Stardew Valley 1.5.4 or later. diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 2de2b21a..c3285979 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -297,7 +297,14 @@ namespace StardewModdingAPI.Framework } finally { - this.Dispose(); + try + { + this.Dispose(); + } + catch (Exception ex) + { + this.Monitor.Log($"The game ended, but SMAPI wasn't able to dispose correctly. Technical details: {ex}", LogLevel.Error); + } } } -- cgit