diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs index a570bc33b..df6a4d0c6 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs @@ -1171,9 +1171,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller ImGui.TextWrapped(Locs.PluginBody_Outdated); ImGui.PopStyleColor(); } - - // Banned warning - if (plugin is { IsBanned: true }) + else if (plugin is { IsBanned: true }) // Banned warning { ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); ImGuiHelpers.SafeTextWrapped(plugin.BanReason.IsNullOrEmpty() @@ -1182,6 +1180,14 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller ImGui.PopStyleColor(); } + else if (plugin is { State: PluginState.LoadError or PluginState.DependencyResolutionFailed }) // Load failed warning + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); + ImGui.TextWrapped(Locs.PluginBody_LoadFailed); + ImGui.PopStyleColor(); + } + + ImGui.SetCursorPosX(cursor.X); // Description if (plugin is null or { IsOutdated: false, IsBanned: false }) @@ -1458,7 +1464,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller } // Load error - if (plugin.State == PluginState.LoadError) + if (plugin.State is PluginState.LoadError or PluginState.DependencyResolutionFailed) { label += Locs.PluginTitleMod_LoadError; trouble = true; @@ -1685,11 +1691,14 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller // Disable everything if the plugin is outdated disabled = disabled || (plugin.IsOutdated && !configuration.LoadAllApiLevels) || plugin.IsBanned; + // Disable everything if the plugin failed to load + disabled = disabled || plugin.State == PluginState.LoadError || plugin.State == PluginState.DependencyResolutionFailed; + if (plugin.State == PluginState.Loading || plugin.State == PluginState.Unloading) { ImGuiComponents.DisabledButton(Locs.PluginButton_Working); } - else if (plugin.State == PluginState.Loaded || plugin.State == PluginState.LoadError) + else if (plugin.State == PluginState.Loaded || plugin.State == PluginState.LoadError || plugin.State == PluginState.DependencyResolutionFailed) { if (disabled) { @@ -2278,7 +2287,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller public static string PluginBody_AuthorWithDownloadCount(string author, long count) => Loc.Localize("InstallerAuthorWithDownloadCount", " by {0} ({1} downloads)").Format(author, count.ToString("N0")); - public static string PluginBody_AuthorWithDownloadCountUnavailable(string author) => Loc.Localize("InstallerAuthorWithDownloadCountUnavailable", " by {0}, download count unavailable").Format(author); + public static string PluginBody_AuthorWithDownloadCountUnavailable(string author) => Loc.Localize("InstallerAuthorWithDownloadCountUnavailable", " by {0}").Format(author); public static string PluginBody_DevPluginPath(string path) => Loc.Localize("InstallerDevPluginPath", "From {0}").Format(path); @@ -2290,6 +2299,8 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller public static string PluginBody_Outdated => Loc.Localize("InstallerOutdatedPluginBody ", "This plugin is outdated and incompatible at the moment. Please wait for it to be updated by its author."); + public static string PluginBody_LoadFailed => Loc.Localize("InstallerLoadFailedPluginBody ", "This plugin failed to load. Please contact the author for more information."); + public static string PluginBody_Banned => Loc.Localize("InstallerBannedPluginBody ", "This plugin was automatically disabled due to incompatibilities and is not available at the moment. Please wait for it to be updated by its author."); public static string PluginBody_BannedReason(string message) => diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index b0c206dd1..8879ce4f2 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -734,13 +734,23 @@ internal partial class PluginManager : IDisposable, IServiceType { // Dev plugins always get added to the list so they can be fiddled with in the UI Log.Information(ex, $"Dev plugin failed to load, adding anyways: {dllFile.Name}"); - plugin.Disable(); // Disable here, otherwise you can't enable+load later + + // NOTE(goat): This can't work - plugins don't "unload" if they fail to load. + // plugin.Disable(); // Disable here, otherwise you can't enable+load later } else if (plugin.IsOutdated) { // Out of date plugins get added so they can be updated. Log.Information(ex, $"Plugin was outdated, adding anyways: {dllFile.Name}"); } + else if (isBoot) + { + // During boot load, plugins always get added to the list so they can be fiddled with in the UI + Log.Information(ex, $"Regular plugin failed to load, adding anyways: {dllFile.Name}"); + + // NOTE(goat): This can't work - plugins don't "unload" if they fail to load. + // plugin.Disable(); // Disable here, otherwise you can't enable+load later + } else { PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty, out _); @@ -919,7 +929,7 @@ internal partial class PluginManager : IDisposable, IServiceType if (!dryRun) { // Unload if loaded - if (plugin.State == PluginState.Loaded || plugin.State == PluginState.LoadError) + if (plugin.State is PluginState.Loaded or PluginState.LoadError or PluginState.DependencyResolutionFailed) { try { diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs index ec90d9c3f..f9fe09b68 100644 --- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs +++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs @@ -55,7 +55,16 @@ internal class LocalPlugin : IDisposable this.DllFile = dllFile; this.State = PluginState.Unloaded; - this.loader = PluginLoader.CreateFromAssemblyFile(this.DllFile.FullName, SetupLoaderConfig); + try + { + this.loader = PluginLoader.CreateFromAssemblyFile(this.DllFile.FullName, SetupLoaderConfig); + } + catch (InvalidOperationException ex) + { + Log.Error(ex, "Loader.CreateFromAssemblyFile() failed"); + this.State = PluginState.DependencyResolutionFailed; + throw; + } try { @@ -522,6 +531,8 @@ internal class LocalPlugin : IDisposable break; case PluginState.UnloadError: break; + case PluginState.DependencyResolutionFailed: + throw new InvalidPluginOperationException($"Unable to enable {this.Name}, dependency resolution failed"); default: throw new ArgumentOutOfRangeException(this.State.ToString()); } @@ -550,6 +561,8 @@ internal class LocalPlugin : IDisposable break; case PluginState.UnloadError: break; + case PluginState.DependencyResolutionFailed: + return; // This is a no-op. default: throw new ArgumentOutOfRangeException(this.State.ToString()); } diff --git a/Dalamud/Plugin/Internal/Types/PluginState.cs b/Dalamud/Plugin/Internal/Types/PluginState.cs index 7a8074801..691b8d474 100644 --- a/Dalamud/Plugin/Internal/Types/PluginState.cs +++ b/Dalamud/Plugin/Internal/Types/PluginState.cs @@ -34,4 +34,9 @@ internal enum PluginState /// Currently loading. /// Loading, + + /// + /// This plugin couldn't load one of its dependencies. + /// + DependencyResolutionFailed, }