summaryrefslogtreecommitdiff
path: root/src/StardewModdingAPI/Framework
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <github@jplamondonw.com>2017-08-21 14:22:19 -0400
committerJesse Plamondon-Willard <github@jplamondonw.com>2017-08-21 14:22:19 -0400
commit80fe706f19d95ef2d00887344bcbc2a064a04541 (patch)
treee80dc30e52b2680391aaff9ee65c02ede2f5ee64 /src/StardewModdingAPI/Framework
parent723ddc255e1c2b399dfb734306fd00912a741e62 (diff)
downloadSMAPI-80fe706f19d95ef2d00887344bcbc2a064a04541.tar.gz
SMAPI-80fe706f19d95ef2d00887344bcbc2a064a04541.tar.bz2
SMAPI-80fe706f19d95ef2d00887344bcbc2a064a04541.zip
show friendlier error when players have two copies of a mod
Diffstat (limited to 'src/StardewModdingAPI/Framework')
-rw-r--r--src/StardewModdingAPI/Framework/Exceptions/SAssemblyLoadFailedException.cs16
-rw-r--r--src/StardewModdingAPI/Framework/ModLoading/AssemblyLoadStatus.cs15
-rw-r--r--src/StardewModdingAPI/Framework/ModLoading/AssemblyLoader.cs24
-rw-r--r--src/StardewModdingAPI/Framework/ModLoading/AssemblyParseResult.cs9
4 files changed, 56 insertions, 8 deletions
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
+{
+ /// <summary>An exception thrown when an assembly can't be loaded by SMAPI, with all the relevant details in the message.</summary>
+ internal class SAssemblyLoadFailedException : Exception
+ {
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="message">The error message.</param>
+ 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
+{
+ /// <summary>Indicates the result of an assembly load.</summary>
+ internal enum AssemblyLoadStatus
+ {
+ /// <summary>The assembly was loaded successfully.</summary>
+ Okay = 1,
+
+ /// <summary>The assembly could not be loaded.</summary>
+ Failed = 2,
+
+ /// <summary>The assembly is already loaded.</summary>
+ 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<string> visitedAssemblyNames = new HashSet<string>(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
/// <summary>The assembly definition.</summary>
public readonly AssemblyDefinition Definition;
+ /// <summary>The result of the assembly load.</summary>
+ public AssemblyLoadStatus Status;
+
/*********
** Public methods
@@ -22,10 +25,12 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <summary>Construct an instance.</summary>
/// <param name="file">The original assembly file.</param>
/// <param name="assembly">The assembly definition.</param>
- public AssemblyParseResult(FileInfo file, AssemblyDefinition assembly)
+ /// <param name="status">The result of the assembly load.</param>
+ public AssemblyParseResult(FileInfo file, AssemblyDefinition assembly, AssemblyLoadStatus status)
{
this.File = file;
this.Definition = assembly;
+ this.Status = status;
}
}
-} \ No newline at end of file
+}