From ae01396d9db77789937ff26cfc1cdf90feea68b2 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 13 Jul 2017 17:26:36 -0400 Subject: fix crash in unique-ID check when mod has no manifest (#323) --- src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/StardewModdingAPI/Framework/ModLoading') diff --git a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs index b75453b7..16c397be 100644 --- a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs +++ b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs @@ -161,7 +161,7 @@ namespace StardewModdingAPI.Framework.ModLoading #if !SMAPI_1_x { var duplicatesByID = mods - .GroupBy(mod => mod.Manifest.UniqueID?.Trim(), mod => mod, StringComparer.InvariantCultureIgnoreCase) + .GroupBy(mod => mod.Manifest?.UniqueID?.Trim(), mod => mod, StringComparer.InvariantCultureIgnoreCase) .Where(p => p.Count() > 1); foreach (var group in duplicatesByID) { -- cgit From 6ddcef61e94a81711ad25a378f0fa03d7799f2dc Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 20 Jul 2017 00:05:39 -0400 Subject: simplify mod compatibility model parsing --- .../Framework/ModLoading/ModResolver.cs | 6 ++-- .../Framework/Models/ModCompatibility.cs | 35 ++++------------------ 2 files changed, 9 insertions(+), 32 deletions(-) (limited to 'src/StardewModdingAPI/Framework/ModLoading') diff --git a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs index 16c397be..cf43eb45 100644 --- a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs +++ b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs @@ -72,8 +72,8 @@ namespace StardewModdingAPI.Framework.ModLoading from mod in compatibilityRecords where mod.ID.Contains(key, StringComparer.InvariantCultureIgnoreCase) - && (mod.LowerSemanticVersion == null || !manifest.Version.IsOlderThan(mod.LowerSemanticVersion)) - && !manifest.Version.IsNewerThan(mod.UpperSemanticVersion) + && (mod.LowerVersion == null || !manifest.Version.IsOlderThan(mod.LowerVersion)) + && !manifest.Version.IsNewerThan(mod.UpperVersion) select mod ).FirstOrDefault(); } @@ -113,7 +113,7 @@ namespace StardewModdingAPI.Framework.ModLoading bool hasUnofficialUrl = !string.IsNullOrWhiteSpace(mod.Compatibility.UnofficialUpdateUrl); string reasonPhrase = compatibility.ReasonPhrase ?? "it's not compatible with the latest version of the game or SMAPI"; - string error = $"{reasonPhrase}. Please check for a version newer than {compatibility.UpperVersionLabel ?? compatibility.UpperVersion} here:"; + string error = $"{reasonPhrase}. Please check for a version newer than {compatibility.UpperVersionLabel ?? compatibility.UpperVersion.ToString()} here:"; if (hasOfficialUrl) error += !hasUnofficialUrl ? $" {compatibility.UpdateUrl}" : $"{Environment.NewLine}- official mod: {compatibility.UpdateUrl}"; if (hasUnofficialUrl) diff --git a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs index 90cbd237..eb312eff 100644 --- a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs +++ b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs @@ -1,5 +1,5 @@ -using System.Runtime.Serialization; -using Newtonsoft.Json; +using Newtonsoft.Json; +using StardewModdingAPI.Framework.Serialisation; namespace StardewModdingAPI.Framework.Models { @@ -19,10 +19,12 @@ namespace StardewModdingAPI.Framework.Models public string Name { get; set; } /// The oldest incompatible mod version, or null for all past versions. - public string LowerVersion { get; set; } + [JsonConverter(typeof(SFieldConverter))] + public ISemanticVersion LowerVersion { get; set; } /// The most recent incompatible mod version. - public string UpperVersion { get; set; } + [JsonConverter(typeof(SFieldConverter))] + public ISemanticVersion UpperVersion { get; set; } /// A label to show to the user instead of , when the manifest version differs from the user-facing version. public string UpperVersionLabel { get; set; } @@ -39,30 +41,5 @@ namespace StardewModdingAPI.Framework.Models /// Indicates how SMAPI should consider the mod. public ModCompatibilityType Compatibility { get; set; } - - - /**** - ** Injected - ****/ - /// The semantic version corresponding to . - [JsonIgnore] - public ISemanticVersion LowerSemanticVersion { get; set; } - - /// The semantic version corresponding to . - [JsonIgnore] - public ISemanticVersion UpperSemanticVersion { get; set; } - - - /********* - ** Private methods - *********/ - /// The method called when the model finishes deserialising. - /// The deserialisation context. - [OnDeserialized] - private void OnDeserialized(StreamingContext context) - { - this.LowerSemanticVersion = this.LowerVersion != null ? new SemanticVersion(this.LowerVersion) : null; - this.UpperSemanticVersion = this.UpperVersion != null ? new SemanticVersion(this.UpperVersion) : null; - } } } -- cgit From 7d73b0bf0c545b281d9d84bc73ad40932764b483 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 20 Jul 2017 00:37:58 -0400 Subject: simplify compatibility skip message in 2.0 & combine update URL fields --- .../Framework/ModLoading/ModResolver.cs | 18 +++- .../Framework/Models/ModCompatibility.cs | 7 +- .../StardewModdingAPI.config.json | 104 +++++++++------------ 3 files changed, 62 insertions(+), 67 deletions(-) (limited to 'src/StardewModdingAPI/Framework/ModLoading') diff --git a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs index cf43eb45..fdcbdaa7 100644 --- a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs +++ b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs @@ -109,15 +109,25 @@ namespace StardewModdingAPI.Framework.ModLoading ModCompatibility compatibility = mod.Compatibility; if (compatibility?.Compatibility == ModCompatibilityType.AssumeBroken) { - bool hasOfficialUrl = !string.IsNullOrWhiteSpace(mod.Compatibility.UpdateUrl); - bool hasUnofficialUrl = !string.IsNullOrWhiteSpace(mod.Compatibility.UnofficialUpdateUrl); +#if SMAPI_1_x + bool hasOfficialUrl = mod.Compatibility.UpdateUrls.Length > 0; + bool hasUnofficialUrl = mod.Compatibility.UpdateUrls.Length > 1; string reasonPhrase = compatibility.ReasonPhrase ?? "it's not compatible with the latest version of the game or SMAPI"; string error = $"{reasonPhrase}. Please check for a version newer than {compatibility.UpperVersionLabel ?? compatibility.UpperVersion.ToString()} here:"; if (hasOfficialUrl) - error += !hasUnofficialUrl ? $" {compatibility.UpdateUrl}" : $"{Environment.NewLine}- official mod: {compatibility.UpdateUrl}"; + error += !hasUnofficialUrl ? $" {compatibility.UpdateUrls[0]}" : $"{Environment.NewLine}- official mod: {compatibility.UpdateUrls[0]}"; if (hasUnofficialUrl) - error += $"{Environment.NewLine}- unofficial update: {compatibility.UnofficialUpdateUrl}"; + error += $"{Environment.NewLine}- unofficial update: {compatibility.UpdateUrls[1]}"; +#else + string reasonPhrase = compatibility.ReasonPhrase ?? "it's no longer compatible"; + string error = $"{reasonPhrase}. Please check for a "; + if (mod.Manifest.Version.Equals(compatibility.UpperVersion) && compatibility.UpperVersionLabel == null) + error += "newer version"; + else + error += $"version newer than {compatibility.UpperVersionLabel ?? compatibility.UpperVersion.ToString()}"; + error += " at " + string.Join(" or ", compatibility.UpdateUrls); +#endif mod.SetStatus(ModMetadataStatus.Failed, error); continue; diff --git a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs index eb312eff..72b6f2af 100644 --- a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs +++ b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs @@ -29,11 +29,8 @@ namespace StardewModdingAPI.Framework.Models /// A label to show to the user instead of , when the manifest version differs from the user-facing version. public string UpperVersionLabel { get; set; } - /// The URL the user can check for an official updated version. - public string UpdateUrl { get; set; } - - /// The URL the user can check for an unofficial updated version. - public string UnofficialUpdateUrl { get; set; } + /// The URLs the user can check for a newer version. + public string[] UpdateUrls { get; set; } /// The reason phrase to show in the warning, or null to use the default value. /// "this version is incompatible with the latest version of the game" diff --git a/src/StardewModdingAPI/StardewModdingAPI.config.json b/src/StardewModdingAPI/StardewModdingAPI.config.json index 4e871636..90bf29c9 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.config.json +++ b/src/StardewModdingAPI/StardewModdingAPI.config.json @@ -54,8 +54,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "AccessChestAnywhere" ], "UpperVersion": "1.1", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/257", - "UnofficialUpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/257", "http://www.nexusmods.com/stardewvalley/mods/518" ], "Notes": "Needs update for SDV 1.1." }, { @@ -63,7 +62,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "AlmightyTool.dll" ], "UpperVersion": "1.1.1", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/439", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/439" ], "Notes": "Needs update for SDV 1.2." }, { @@ -71,8 +70,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "SPDSprinklersMod", /*since 2.3*/ "Speeder.BetterSprinklers" ], "UpperVersion": "2.3.1-pathoschild-update", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/41", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/41", "http://community.playstarbound.com/threads/132096" ], "Notes": "Needs update for SDV 1.2 and to migrate broken TimeEvents.AfterDayOfMonthChanged." }, { @@ -80,8 +78,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "005e02dc-d900-425c-9c68-1ff55c5a295d" ], "UpperVersion": "1.2.2", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/276", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/276", "http://community.playstarbound.com/threads/132096" ], "Notes": "Needs update for SDV 1.2." }, { @@ -89,8 +86,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "SPDChestLabel" ], "UpperVersion": "1.6", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/242", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/242", "http://community.playstarbound.com/threads/132096" ], "Notes": "Needs update for SDV 1.1." }, { @@ -98,7 +94,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "ChestPooling.dll" ], "UpperVersion": "1.2", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/threads/111988", + "UpdateUrls": [ "http://community.playstarbound.com/threads/111988" ], "Notes": "Needs update for SDV 1.2." }, { @@ -106,7 +102,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "ChestsAnywhere", /*since 1.9*/ "Pathoschild.ChestsAnywhere" ], "UpperVersion": "1.9-beta", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/518" ], "Notes": "Needs update for SDV 1.2." }, { @@ -114,22 +110,21 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "CJBAutomation" ], "UpperVersion": "1.4", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/211", - "UnofficialUpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/1063", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/211", "http://www.nexusmods.com/stardewvalley/mods/1063" ], "Notes": "Needs update for SDV 1.2." }, { "Name": "CJB Cheats Menu", "ID": [ "CJBCheatsMenu" ], "UpperVersion": "1.12", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/4", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/4" ], "Notes": "Needs update for SDV 1.1." }, { "Name": "CJB Item Spawner", "ID": [ "CJBItemSpawner" ], "UpperVersion": "1.5", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/93", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/93" ], "Notes": "Needs update for SDV 1.1." }, { @@ -137,7 +132,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "CJBShowItemSellPrice" ], "UpperVersion": "1.6", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/93", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/93" ], "Notes": "Needs update for SDV 1.2." }, { @@ -145,7 +140,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "CookingSkill" ], "UpperVersion": "1.0.3", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/522", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/522" ], "Notes": "Needs update for SDV 1.2." }, { @@ -153,8 +148,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "20d6b8a3-b6e7-460b-a6e4-07c2b0cb6c63" ], "UpperVersion": "1.0.4", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/569", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/569", "http://community.playstarbound.com/threads/132096" ], "Notes": "Needs update for SDV 1.2." }, { @@ -162,8 +156,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "SPDHealthBar" ], "UpperVersion": "1.7", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/193", - "UnofficialUrl": "http://community.playstarbound.com/threads/132096", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/193", "http://community.playstarbound.com/threads/132096" ], "Notes": "Needs update for SDV 1.2." }, { @@ -171,7 +164,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "eacdb74b-4080-4452-b16b-93773cda5cf9", /*since ???*/ "Entoarox.EntoaroxFramework" ], "UpperVersion": "1.7.5", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/resources/4228", + "UpdateUrls": [ "http://community.playstarbound.com/resources/4228" ], "Notes": "Needs update for SDV 1.2." }, { @@ -180,7 +173,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpperVersion": "1.0", "UpperVersionLabel": "0.94", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/485", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/485" ], "Notes": "Needs update for SDV 1.2. Actual upper version is 0.94, but mod incorrectly sets it to 1.0 in the manifest." }, { @@ -188,7 +181,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "FarmAutomation.ItemCollector.dll", /*since 0.4*/ "Maddy99.FarmAutomation.ItemCollector" ], "UpperVersion": "0.4", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/threads/125172", + "UpdateUrls": [ "http://community.playstarbound.com/threads/125172" ], "Notes": "Needs update for SDV 1.2." }, { @@ -196,8 +189,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "InstantGeode" ], "UpperVersion": "1.12", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/threads/109038", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "UpdateUrls": [ "http://community.playstarbound.com/threads/109038", "http://community.playstarbound.com/threads/132096" ], "Notes": "Needs update for SDV 1.2." }, { @@ -205,7 +197,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "GateOpener.dll", /*since 1.1*/ "mralbobo.GateOpener" ], "UpperVersion": "1.0.1", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/threads/111988", + "UpdateUrls": [ "http://community.playstarbound.com/threads/111988" ], "Notes": "Needs update for SDV 1.2." }, { @@ -213,7 +205,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "GetDressed.dll", /*since 3.3*/ "Advize.GetDressed" ], "UpperVersion": "3.3", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/331", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/331" ], "Notes": "Needs update for SDV 1.2." }, { @@ -221,7 +213,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "8008db57-fa67-4730-978e-34b37ef191d6" ], "UpperVersion": "2.3.1", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/229", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/229" ], "Notes": "Needs update for SDV 1.2." }, { @@ -229,7 +221,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "LookupAnything", /*since 1.10.1*/ "Pathoschild.LookupAnything" ], "UpperVersion": "1.10.1", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/541" ], "Notes": "Needs update for SDV 1.2." }, { @@ -237,7 +229,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "StardewValleyMP", /*since 0.3*/ "spacechase0.StardewValleyMP" ], "Compatibility": "AssumeBroken", "UpperVersion": "0.3.3", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/501", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/501" ], "Notes": "Needs update for SDV 1.2." }, { @@ -245,8 +237,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "289dee03-5f38-4d8e-8ffc-e440198e8610" ], "UpperVersion": "0.5", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/237", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/237", "http://community.playstarbound.com/threads/132096" ], "Notes": "Needs update for SDV 1.2, and uses Assembly.GetExecutingAssembly().Location." }, { @@ -255,7 +246,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "LowerVersion": "1.42", "UpperVersion": "1.43", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/239", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/239" ], "ReasonPhrase": "These versions have an update check error which crash the game." }, { @@ -263,7 +254,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "SB_PotC" ], "UpperVersion": "1.0.8", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/923", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/923" ], "ReasonPhrase": "Needs update for SDV 1.2." }, { @@ -271,7 +262,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "PointAndPlant.dll" ], "UpperVersion": "1.0.2", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/572", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/572" ], "Notes": "Needs update for SDV 1.2." }, { @@ -279,8 +270,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "PrairieKingMadeEasy.dll" ], "UpperVersion": "1.0.0", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/resources/3594", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "UpdateUrls": [ "http://community.playstarbound.com/resources/3594", "http://community.playstarbound.com/threads/132096" ], "Notes": "Needs update for SDV 1.2." }, { @@ -288,7 +278,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "RushOrders", /*since 1.1*/ "spacechase0.RushOrders" ], "UpperVersion": "1.1", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/605", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/605" ], "Notes": "Needs update for SDV 1.2." }, { @@ -296,7 +286,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "SaveAnywhere" ], "UpperVersion": "2.3", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/444", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/444" ], "Notes": "Needs update for SDV 1.2." }, { @@ -304,7 +294,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "SimpleSprinkler.dll" ], "UpperVersion": "1.4", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/76", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/76" ], "Notes": "Needs update for SDV 1.2." }, { @@ -312,8 +302,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "SPDSprintAndDash" ], "UpperVersion": "1.0", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/resources/3531", - "UnofficialUpdateUrl": "http://community.playstarbound.com/resources/4201", + "UpdateUrls": [ "http://community.playstarbound.com/resources/3531", "http://community.playstarbound.com/resources/4201" ], "Notes": "Needs update for SDV 1.2." }, { @@ -321,7 +310,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "SPDSprintAndDash" ], "UpperVersion": "1.2", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/resources/4201", + "UpdateUrls": [ "http://community.playstarbound.com/resources/4201" ], "Notes": "Needs update for SDV 1.2." }, { @@ -329,7 +318,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "StackSplitX.dll" ], "UpperVersion": "1.2", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/798", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/798" ], "Notes": "Needs update for SDV 1.2." }, { @@ -337,7 +326,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "Teleporter" ], "UpperVersion": "1.0.2", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/resources/4374", + "UpdateUrls": [ "http://community.playstarbound.com/resources/4374" ], "Notes": "Needs update for SDV 1.2." }, { @@ -345,7 +334,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "TimeSpeed.dll", /* since 2.0.3 */ "4108e859-333c-4fec-a1a7-d2e18c1019fe", /*since 2.1*/ "community.TimeSpeed" ], "UpperVersion": "2.2", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/169", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/169" ], "Notes": "Needs update for SDV 1.2 and to migrate broken TimeEvents.AfterDayOfMonthChanged." }, { @@ -354,7 +343,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpperVersion": "0.5", "UpperVersionLabel": "1.0", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/1023", + "UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/1023" ], "Notes": "Needs update for SDV 1.2. Actual upper version is 1.0, but mod incorrectly sets it to 0.5 in the manifest." }, { @@ -362,8 +351,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "WeatherController.dll" ], "UpperVersion": "1.0.2", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/threads/111526", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "UpdateUrls": [ "http://community.playstarbound.com/threads/111526", "http://community.playstarbound.com/threads/132096" ], "Notes": "Needs update for SDV 1.2." }, { @@ -371,7 +359,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "zdailyincrease" ], "UpperVersion": "1.2", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/resources/4247", + "UpdateUrls": [ "http://community.playstarbound.com/resources/4247" ], "Notes": "Needs update for SDV 1.2." }, { @@ -379,7 +367,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "ZoomMod" ], "UpperVersion": "0.1", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/threads/115028", + "UpdateUrls": [ "http://community.playstarbound.com/threads/115028" ], "Notes": "Needs update for SDV 1.2." }, { @@ -387,7 +375,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "76b6d1e1-f7ba-4d72-8c32-5a1e6d2716f6", /*since 1.6*/ "Zoryn.BetterRNG" ], "UpperVersion": "1.6", "Compatibility": "AssumeBroken", - "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "UpdateUrls": [ "https://github.com/Zoryn4163/SMAPI-Mods/releases" ], "Notes": "Needs update for SDV 1.2." }, { @@ -395,7 +383,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "a41c01cd-0437-43eb-944f-78cb5a53002a", /*since 1.6*/ "Zoryn.CalendarAnywhere" ], "UpperVersion": "1.6", "Compatibility": "AssumeBroken", - "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "UpdateUrls": [ "https://github.com/Zoryn4163/SMAPI-Mods/releases" ], "Notes": "Needs update for SDV 1.2." }, { @@ -403,7 +391,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "HealthBars.dll", /*since 1.6*/ "Zoryn.HealthBars" ], "UpperVersion": "1.6", "Compatibility": "AssumeBroken", - "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "UpdateUrls": [ "https://github.com/Zoryn4163/SMAPI-Mods/releases" ], "Notes": "Needs update for SDV 1.2." }, { @@ -411,7 +399,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "f93a4fe8-cade-4146-9335-b5f82fbbf7bc", /*since 1.6*/ "Zoryn.JunimoDepositAnywhere" ], "UpperVersion": "1.7", "Compatibility": "AssumeBroken", - "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "UpdateUrls": [ "https://github.com/Zoryn4163/SMAPI-Mods/releases" ], "Notes": "Needs update for SDV 1.2." }, { @@ -419,7 +407,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "8a632929-8335-484f-87dd-c29d2ba3215d", /*since 1.6*/ "Zoryn.MovementModifier" ], "UpperVersion": "1.6", "Compatibility": "AssumeBroken", - "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "UpdateUrls": [ "https://github.com/Zoryn4163/SMAPI-Mods/releases" ], "Notes": "Needs update for SDV 1.2." }, { @@ -427,7 +415,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": [ "dfac4383-1b6b-4f33-ae4e-37fc23e5252e", /*since 1.6*/ "Zoryn.RegenMod" ], "UpperVersion": "1.6", "Compatibility": "AssumeBroken", - "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "UpdateUrls": [ "https://github.com/Zoryn4163/SMAPI-Mods/releases" ], "Notes": "Needs update for SDV 1.2." } ] -- cgit From c20b21bcaa799a9961799316b7f4b7d8f929ca3f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 21 Jul 2017 01:51:05 -0400 Subject: add support for disambiguating IDs in mod compatibility list --- .../Framework/ModLoading/ModResolver.cs | 6 +-- .../Framework/Models/ModCompatibility.cs | 6 +-- .../Framework/Models/ModCompatibilityID.cs | 57 ++++++++++++++++++++++ .../Framework/Serialisation/SFieldConverter.cs | 19 +++++++- src/StardewModdingAPI/StardewModdingAPI.csproj | 1 + 5 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 src/StardewModdingAPI/Framework/Models/ModCompatibilityID.cs (limited to 'src/StardewModdingAPI/Framework/ModLoading') diff --git a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs index fdcbdaa7..6b19db5c 100644 --- a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs +++ b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs @@ -71,9 +71,9 @@ namespace StardewModdingAPI.Framework.ModLoading compatibility = ( from mod in compatibilityRecords where - mod.ID.Contains(key, StringComparer.InvariantCultureIgnoreCase) - && (mod.LowerVersion == null || !manifest.Version.IsOlderThan(mod.LowerVersion)) - && !manifest.Version.IsNewerThan(mod.UpperVersion) + mod.ID.Any(p => p.Matches(key, manifest)) + && (mod.LowerVersion == null || !manifest.Version.IsOlderThan(mod.LowerVersion)) + && !manifest.Version.IsNewerThan(mod.UpperVersion) select mod ).FirstOrDefault(); } diff --git a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs index 91be1d38..d3a9c533 100644 --- a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs +++ b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs @@ -9,11 +9,9 @@ namespace StardewModdingAPI.Framework.Models /********* ** Accessors *********/ - /**** - ** From config - ****/ /// The unique mod IDs. - public string[] ID { get; set; } + [JsonConverter(typeof(SFieldConverter))] + public ModCompatibilityID[] ID { get; set; } /// The mod name. public string Name { get; set; } diff --git a/src/StardewModdingAPI/Framework/Models/ModCompatibilityID.cs b/src/StardewModdingAPI/Framework/Models/ModCompatibilityID.cs new file mode 100644 index 00000000..98e70116 --- /dev/null +++ b/src/StardewModdingAPI/Framework/Models/ModCompatibilityID.cs @@ -0,0 +1,57 @@ +using System; +using Newtonsoft.Json; + +namespace StardewModdingAPI.Framework.Models +{ + /// Uniquely identifies a mod for compatibility checks. + internal class ModCompatibilityID + { + /********* + ** Accessors + *********/ + /// The unique mod ID. + public string ID { get; set; } + + /// The mod name to disambiguate non-unique IDs, or null to ignore the mod name. + public string Name { get; set; } + + /// The author name to disambiguate non-unique IDs, or null to ignore the author. + public string Author { get; set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + public ModCompatibilityID() { } + + /// Construct an instance. + /// The mod ID or a JSON string matching the fields. + public ModCompatibilityID(string data) + { + // JSON can be stuffed into the ID string as a convenience hack to keep JSON mod lists + // formatted readably. The tradeoff is that the format is a bit more magical, but that's + // probably acceptable since players aren't meant to edit it. It's also fairly clear what + // the JSON strings do, if not necessarily how. + if (data.StartsWith("{")) + JsonConvert.PopulateObject(data, this); + else + this.ID = data; + } + + /// Get whether this ID matches a given mod manifest. + /// The mod's unique ID, or a substitute ID if it isn't set in the manifest. + /// The manifest to check. + public bool Matches(string id, IManifest manifest) + { + return + this.ID.Equals(id, StringComparison.InvariantCultureIgnoreCase) + && ( + this.Author == null + || this.Author.Equals(manifest.Author, StringComparison.InvariantCultureIgnoreCase) + || (manifest.ExtraFields.ContainsKey("Authour") && this.Author.Equals(manifest.ExtraFields["Authour"].ToString(), StringComparison.InvariantCultureIgnoreCase)) + ) + && (this.Name == null || this.Name.Equals(manifest.Name, StringComparison.InvariantCultureIgnoreCase)); + } + } +} diff --git a/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs b/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs index 9dc62b6a..11ffdccb 100644 --- a/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs +++ b/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs @@ -24,7 +24,10 @@ namespace StardewModdingAPI.Framework.Serialisation /// The object type. public override bool CanConvert(Type objectType) { - return objectType == typeof(ISemanticVersion) || objectType == typeof(IManifestDependency[]); + return + objectType == typeof(ISemanticVersion) + || objectType == typeof(IManifestDependency[]) + || objectType == typeof(ModCompatibilityID[]); } /// Reads the JSON representation of the object. @@ -83,6 +86,20 @@ namespace StardewModdingAPI.Framework.Serialisation return result.ToArray(); } + // mod compatibility ID + if (objectType == typeof(ModCompatibilityID[])) + { + List result = new List(); + foreach (JToken child in JArray.Load(reader).Children()) + { + result.Add(child is JValue value + ? new ModCompatibilityID(value.Value()) + : child.ToObject() + ); + } + return result.ToArray(); + } + // unknown throw new NotSupportedException($"Unknown type '{objectType?.FullName}'."); } diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index 9047aea4..f7992122 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -128,6 +128,7 @@ + -- cgit From 80fe706f19d95ef2d00887344bcbc2a064a04541 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 21 Aug 2017 14:22:19 -0400 Subject: show friendlier error when players have two copies of a mod --- release-notes.md | 1 + .../Exceptions/SAssemblyLoadFailedException.cs | 16 +++++++++++++++ .../Framework/ModLoading/AssemblyLoadStatus.cs | 15 ++++++++++++++ .../Framework/ModLoading/AssemblyLoader.cs | 24 ++++++++++++++++------ .../Framework/ModLoading/AssemblyParseResult.cs | 9 ++++++-- src/StardewModdingAPI/Program.cs | 6 ++++++ src/StardewModdingAPI/StardewModdingAPI.csproj | 2 ++ 7 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 src/StardewModdingAPI/Framework/Exceptions/SAssemblyLoadFailedException.cs create mode 100644 src/StardewModdingAPI/Framework/ModLoading/AssemblyLoadStatus.cs (limited to 'src/StardewModdingAPI/Framework/ModLoading') diff --git a/release-notes.md b/release-notes.md index 803f7354..7b7e250c 100644 --- a/release-notes.md +++ b/release-notes.md @@ -6,6 +6,7 @@ For players: * The SMAPI console is now much simpler and easier to read. * The SMAPI console now adjusts its colors when you have a light terminal background. * Updated compatibility list. +* Improved errors when a mod DLL can't be loaded. For mod developers: * Added new APIs to edit, inject, and reload XNB assets loaded by the game at any time. diff --git a/src/StardewModdingAPI/Framework/Exceptions/SAssemblyLoadFailedException.cs b/src/StardewModdingAPI/Framework/Exceptions/SAssemblyLoadFailedException.cs new file mode 100644 index 00000000..ec9279f1 --- /dev/null +++ b/src/StardewModdingAPI/Framework/Exceptions/SAssemblyLoadFailedException.cs @@ -0,0 +1,16 @@ +using System; + +namespace StardewModdingAPI.Framework.Exceptions +{ + /// An exception thrown when an assembly can't be loaded by SMAPI, with all the relevant details in the message. + internal class SAssemblyLoadFailedException : Exception + { + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The error message. + public SAssemblyLoadFailedException(string message) + : base(message) { } + } +} diff --git a/src/StardewModdingAPI/Framework/ModLoading/AssemblyLoadStatus.cs b/src/StardewModdingAPI/Framework/ModLoading/AssemblyLoadStatus.cs new file mode 100644 index 00000000..11be19fc --- /dev/null +++ b/src/StardewModdingAPI/Framework/ModLoading/AssemblyLoadStatus.cs @@ -0,0 +1,15 @@ +namespace StardewModdingAPI.Framework.ModLoading +{ + /// Indicates the result of an assembly load. + internal enum AssemblyLoadStatus + { + /// The assembly was loaded successfully. + Okay = 1, + + /// The assembly could not be loaded. + Failed = 2, + + /// The assembly is already loaded. + AlreadyLoaded = 3 + } +} diff --git a/src/StardewModdingAPI/Framework/ModLoading/AssemblyLoader.cs b/src/StardewModdingAPI/Framework/ModLoading/AssemblyLoader.cs index 406d49e1..b14ae56f 100644 --- a/src/StardewModdingAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/ModLoading/AssemblyLoader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -6,6 +6,7 @@ using System.Reflection; using Mono.Cecil; using Mono.Cecil.Cil; using StardewModdingAPI.AssemblyRewriters; +using StardewModdingAPI.Framework.Exceptions; namespace StardewModdingAPI.Framework.ModLoading { @@ -65,16 +66,27 @@ namespace StardewModdingAPI.Framework.ModLoading AssemblyDefinitionResolver resolver = new AssemblyDefinitionResolver(); HashSet visitedAssemblyNames = new HashSet(AppDomain.CurrentDomain.GetAssemblies().Select(p => p.GetName().Name)); // don't try loading assemblies that are already loaded assemblies = this.GetReferencedLocalAssemblies(new FileInfo(assemblyPath), visitedAssemblyNames, resolver).ToArray(); - if (!assemblies.Any()) - throw new InvalidOperationException($"Could not load '{assemblyPath}' because it doesn't exist."); - resolver.Add(assemblies.Select(p => p.Definition).ToArray()); } + // validate load + if (!assemblies.Any() || assemblies[0].Status == AssemblyLoadStatus.Failed) + { + throw new SAssemblyLoadFailedException(!File.Exists(assemblyPath) + ? $"Could not load '{assemblyPath}' because it doesn't exist." + : $"Could not load '{assemblyPath}'." + ); + } + if (assemblies[0].Status == AssemblyLoadStatus.AlreadyLoaded) + throw new SAssemblyLoadFailedException($"Could not load '{assemblyPath}' because it was already loaded. Do you have two copies of this mod?"); + // rewrite & load assemblies in leaf-to-root order bool oneAssembly = assemblies.Length == 1; Assembly lastAssembly = null; foreach (AssemblyParseResult assembly in assemblies) { + if (assembly.Status == AssemblyLoadStatus.AlreadyLoaded) + continue; + bool changed = this.RewriteAssembly(assembly.Definition, assumeCompatible, logPrefix: " "); if (changed) { @@ -143,7 +155,7 @@ namespace StardewModdingAPI.Framework.ModLoading // skip if already visited if (visitedAssemblyNames.Contains(assembly.Name.Name)) - yield break; + yield return new AssemblyParseResult(file, null, AssemblyLoadStatus.AlreadyLoaded); visitedAssemblyNames.Add(assembly.Name.Name); // yield referenced assemblies @@ -155,7 +167,7 @@ namespace StardewModdingAPI.Framework.ModLoading } // yield assembly - yield return new AssemblyParseResult(file, assembly); + yield return new AssemblyParseResult(file, assembly, AssemblyLoadStatus.Okay); } /**** diff --git a/src/StardewModdingAPI/Framework/ModLoading/AssemblyParseResult.cs b/src/StardewModdingAPI/Framework/ModLoading/AssemblyParseResult.cs index 69c99afe..b56a776c 100644 --- a/src/StardewModdingAPI/Framework/ModLoading/AssemblyParseResult.cs +++ b/src/StardewModdingAPI/Framework/ModLoading/AssemblyParseResult.cs @@ -15,6 +15,9 @@ namespace StardewModdingAPI.Framework.ModLoading /// The assembly definition. public readonly AssemblyDefinition Definition; + /// The result of the assembly load. + public AssemblyLoadStatus Status; + /********* ** Public methods @@ -22,10 +25,12 @@ namespace StardewModdingAPI.Framework.ModLoading /// Construct an instance. /// The original assembly file. /// The assembly definition. - public AssemblyParseResult(FileInfo file, AssemblyDefinition assembly) + /// The result of the assembly load. + public AssemblyParseResult(FileInfo file, AssemblyDefinition assembly, AssemblyLoadStatus status) { this.File = file; this.Definition = assembly; + this.Status = status; } } -} \ No newline at end of file +} diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 57ff011f..108e9273 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -15,6 +15,7 @@ using Newtonsoft.Json; using StardewModdingAPI.AssemblyRewriters; using StardewModdingAPI.Events; using StardewModdingAPI.Framework; +using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Logging; using StardewModdingAPI.Framework.Models; using StardewModdingAPI.Framework.ModHelpers; @@ -655,6 +656,11 @@ namespace StardewModdingAPI #endif continue; } + catch (SAssemblyLoadFailedException ex) + { + TrackSkip(metadata, $"its DLL '{manifest.EntryDll}' couldn't be loaded: {ex.Message}"); + continue; + } catch (Exception ex) { TrackSkip(metadata, $"its DLL '{manifest.EntryDll}' couldn't be loaded:\n{ex.GetLogSummary()}"); diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index 73112983..8c7279a1 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -91,6 +91,8 @@ Properties\GlobalAssemblyInfo.cs + + -- cgit