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 --- src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 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) -- 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 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 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; -- 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 --- src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (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(); } -- 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 --- .../Framework/ModLoading/AssemblyLoadStatus.cs | 15 ++++++++++++++ .../Framework/ModLoading/AssemblyLoader.cs | 24 ++++++++++++++++------ .../Framework/ModLoading/AssemblyParseResult.cs | 9 ++++++-- 3 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 src/StardewModdingAPI/Framework/ModLoading/AssemblyLoadStatus.cs (limited to 'src/StardewModdingAPI/Framework/ModLoading') 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 +} -- cgit