diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index 2cb49ed6f..3446ad3fa 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -354,6 +354,7 @@ namespace Dalamud { this.pluginWindow = new PluginInstallerWindow(this, this.StartInfo.GameVersion); this.isImguiDrawPluginWindow = true; } + ImGui.Separator(); if (ImGui.MenuItem("Open Plugin Stats")) { if (!this.isImguiDrawPluginStatWindow) { this.pluginStatWindow = new DalamudPluginStatWindow(this.PluginManager); @@ -436,6 +437,9 @@ namespace Dalamud { if (this.isImguiDrawPluginWindow) { this.isImguiDrawPluginWindow = this.pluginWindow != null && this.pluginWindow.Draw(); + + if (!this.isImguiDrawPluginWindow) + this.pluginWindow = null; } if (this.isImguiDrawCreditsWindow) diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs index 73346299c..1892a16f0 100644 --- a/Dalamud/Plugin/DalamudPluginInterface.cs +++ b/Dalamud/Plugin/DalamudPluginInterface.cs @@ -199,7 +199,7 @@ namespace Dalamud.Plugin /// True if the corresponding plugin was present and received the message. public bool SendMessage(string pluginName, ExpandoObject message) { - var (_, _, pluginInterface) = this.dalamud.PluginManager.Plugins.FirstOrDefault(x => x.Definition.InternalName == this.pluginName); + var (_, _, pluginInterface, _) = this.dalamud.PluginManager.Plugins.FirstOrDefault(x => x.Definition.InternalName == this.pluginName); if (pluginInterface?.anyPluginIpcAction == null) return false; diff --git a/Dalamud/Plugin/PluginInstallerWindow.cs b/Dalamud/Plugin/PluginInstallerWindow.cs index aa7203c54..2ecb4b441 100644 --- a/Dalamud/Plugin/PluginInstallerWindow.cs +++ b/Dalamud/Plugin/PluginInstallerWindow.cs @@ -29,8 +29,13 @@ namespace Dalamud.Plugin private int updatePluginCount = 0; private List updatedPlugins; + private List pluginListAvailable; + private List pluginListInstalled; + private string searchText = ""; + private readonly Vector4 colorGrey = new Vector4(0.70f, 0.70f, 0.70f, 1.00f); + private enum PluginInstallStatus { None, InProgress, @@ -105,8 +110,6 @@ namespace Dalamud.Plugin ImGui.EndCombo(); } - ImGui.Separator(); - ImGui.BeginChild("scrolling", new Vector2(0, 400 * ImGui.GetIO().FontGlobalScale), true, ImGuiWindowFlags.HorizontalScrollbar); ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 3) * ImGui.GetIO().FontGlobalScale); @@ -117,166 +120,35 @@ namespace Dalamud.Plugin ImGui.Text(Loc.Localize("InstallerDownloadFailed", "Download failed.")); } else { - var didAny = false; - var didAnyWithSearch = false; - var hasSearchString = !string.IsNullOrWhiteSpace(this.searchText); + if (this.pluginListAvailable == null) { + var hiddenPlugins = this.dalamud.PluginManager.Plugins.Where( + x => this.dalamud.PluginRepository.PluginMaster.All( + y => y.InternalName != x.Definition.InternalName || y.InternalName == x.Definition.InternalName && y.IsHide)).Select(x => x.Definition).ToList(); + this.pluginListInstalled = this.dalamud.PluginRepository.PluginMaster + .Where(def => { + return this.dalamud.PluginManager.Plugins.Where(x => x.Definition != null).Any( + x => x.Definition.InternalName == def.InternalName); + }) + .ToList(); + this.pluginListInstalled.AddRange(hiddenPlugins); - foreach (var pluginDefinition in this.dalamud.PluginRepository.PluginMaster) { - if (pluginDefinition.ApplicableVersion != this.gameVersion && - pluginDefinition.ApplicableVersion != "any") - continue; - - if (pluginDefinition.IsHide) - continue; - - if (pluginDefinition.DalamudApiLevel < PluginManager.DALAMUD_API_LEVEL) - continue; - - didAny = true; - - if (hasSearchString && - !(pluginDefinition.Name.ToLowerInvariant().Contains(this.searchText.ToLowerInvariant()) || - string.Equals(pluginDefinition.Author, this.searchText, StringComparison.InvariantCultureIgnoreCase) || - pluginDefinition.Tags != null && - pluginDefinition.Tags.Contains(this.searchText.ToLowerInvariant(), StringComparer.InvariantCultureIgnoreCase) - )) { - continue; - } - - didAnyWithSearch = true; - - var isInstalled = this.dalamud.PluginManager.Plugins.Where(x => x.Definition != null).Any( - x => x.Definition.InternalName == pluginDefinition.InternalName); - - var isTestingAvailable = false; - if (Version.TryParse(pluginDefinition.AssemblyVersion, out var assemblyVersion) && Version.TryParse(pluginDefinition.TestingAssemblyVersion, out var testingAssemblyVersion)) - isTestingAvailable = this.dalamud.Configuration.DoPluginTest && testingAssemblyVersion > assemblyVersion; - - if (this.dalamud.Configuration.DoPluginTest && pluginDefinition.IsTestingExclusive) { - isTestingAvailable = true; - } else if (!this.dalamud.Configuration.DoPluginTest && pluginDefinition.IsTestingExclusive) { - continue; - } - - var label = string.Empty; - if (isInstalled) { - label += Loc.Localize("InstallerInstalled", " (installed)"); - if (this.filter == PluginFilter.NotInstalled) { - continue; - } - } else if (this.filter == PluginFilter.Installed) { - continue; - } - - if (this.updatedPlugins != null && this.updatedPlugins.Any(x => x.InternalName == pluginDefinition.InternalName && x.WasUpdated == true)) { - label += Loc.Localize("InstallerUpdated", " (updated)"); - } else if (this.updatedPlugins != null && this.updatedPlugins.Any(x => x.InternalName == pluginDefinition.InternalName && x.WasUpdated == false)) { - label += Loc.Localize("InstallerUpdateFailed", " (update failed)"); - } else if (this.filter == PluginFilter.Updated) { - continue; - } - - if (isTestingAvailable) { - label += " (testing version)"; - } else if (this.filter == PluginFilter.Testing) { - continue; - } - - ImGui.PushID(pluginDefinition.InternalName + pluginDefinition.AssemblyVersion); - - if (ImGui.CollapsingHeader(pluginDefinition.Name + label + "###Header" + pluginDefinition.InternalName)) { - ImGui.Indent(); - - ImGui.Text(pluginDefinition.Name); - ImGui.SameLine(); - ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" by {pluginDefinition.Author}, {pluginDefinition.DownloadCount} downloads"); - - ImGui.Text(pluginDefinition.Description); - - if (!isInstalled) { - if (this.installStatus == PluginInstallStatus.InProgress) { - ImGui.Button(Loc.Localize("InstallerInProgress", "Install in progress...")); - } else { - var versionString = isTestingAvailable ? (pluginDefinition.TestingAssemblyVersion + " (testing version)") : pluginDefinition.AssemblyVersion; - - if (ImGui.Button($"Install v{versionString}")) { - this.installStatus = PluginInstallStatus.InProgress; - - Task.Run(() => this.dalamud.PluginRepository.InstallPlugin(pluginDefinition, true, false, isTestingAvailable)).ContinueWith(t => { - this.installStatus = - t.Result ? PluginInstallStatus.Success : PluginInstallStatus.Fail; - this.installStatus = - t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus; - - this.errorModalDrawing = this.installStatus == PluginInstallStatus.Fail; - this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail; - }); - } - } - if (!string.IsNullOrEmpty(pluginDefinition.RepoUrl)) - { - ImGui.PushFont(InterfaceManager.IconFont); - - ImGui.SameLine(); - if (ImGui.Button(FontAwesomeIcon.Globe.ToIconString()) && - pluginDefinition.RepoUrl.StartsWith("https://")) - Process.Start(pluginDefinition.RepoUrl); - - ImGui.PopFont(); - } - } else { - var installedPlugin = this.dalamud.PluginManager.Plugins.Where(x => x.Definition != null).First( - x => x.Definition.InternalName == - pluginDefinition.InternalName); - - var commands = this.dalamud.CommandManager.Commands.Where(x => x.Value.LoaderAssemblyName == installedPlugin.Definition?.InternalName && x.Value.ShowInHelp); - if (commands.Any()) { - ImGui.Dummy(new Vector2(10, 10) * ImGui.GetIO().FontGlobalScale); - foreach (var command in commands) { - ImGui.Text($"{command.Key} → {command.Value.HelpMessage}"); - } - } - - if (ImGui.Button(Loc.Localize("InstallerDisable", "Disable"))) - try { - this.dalamud.PluginManager.DisablePlugin(installedPlugin.Definition); - } catch (Exception exception) { - Log.Error(exception, "Could not disable plugin."); - this.errorModalDrawing = true; - this.errorModalOnNextFrame = true; - } - - if (installedPlugin.PluginInterface.UiBuilder.OnOpenConfigUi != null) { - ImGui.SameLine(); - - if (ImGui.Button(Loc.Localize("InstallerOpenConfig", "Open Configuration"))) installedPlugin.PluginInterface.UiBuilder.OnOpenConfigUi?.Invoke(null, null); - } - - if (!string.IsNullOrEmpty(installedPlugin.Definition.RepoUrl)) { - ImGui.PushFont(InterfaceManager.IconFont); - - ImGui.SameLine(); - if (ImGui.Button(FontAwesomeIcon.Globe.ToIconString()) && - installedPlugin.Definition.RepoUrl.StartsWith("https://")) - Process.Start(installedPlugin.Definition.RepoUrl); - - ImGui.PopFont(); - } - - ImGui.SameLine(); - ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" v{pluginDefinition.AssemblyVersion}"); - } - - ImGui.Unindent(); - } - - ImGui.PopID(); + this.pluginListAvailable = this.dalamud.PluginRepository.PluginMaster.Where( + x => this.pluginListInstalled.All(y => x.InternalName != y.InternalName)).ToList(); } - if (!didAny) - ImGui.TextColored(new Vector4(0.70f, 0.70f, 0.70f, 1.00f), Loc.Localize("InstallerNoCompatible", "No compatible plugins were found :( Please restart your game and try again.")); - else if (!didAnyWithSearch) - ImGui.TextColored(new Vector4(0.7f, 0.7f, 0.7f, 1.0f), Loc.Localize("InstallNoMatching", "No plugins were found matching your search.")); + ImGui.TextColored(this.colorGrey, + Loc.Localize("InstallerAvailablePluginList", + "Available Plugins:")); + DrawPluginList(this.pluginListAvailable, false); + + ImGui.Dummy(new Vector2(5, 5)); + ImGui.Separator(); + ImGui.Dummy(new Vector2(5, 5)); + + ImGui.TextColored(this.colorGrey, + Loc.Localize("InstallerInstalledPluginList", + "Installed Plugins:")); + DrawPluginList(this.pluginListInstalled, true); } ImGui.PopStyleVar(); @@ -367,5 +239,188 @@ namespace Dalamud.Plugin return windowOpen; } + + private void DrawPluginList(List pluginDefinitions, bool installed) { + var didAny = false; + var didAnyWithSearch = false; + var hasSearchString = !string.IsNullOrWhiteSpace(this.searchText); + + foreach (var pluginDefinition in pluginDefinitions) { + if (pluginDefinition.ApplicableVersion != this.gameVersion && + pluginDefinition.ApplicableVersion != "any") + continue; + + if (pluginDefinition.IsHide) + continue; + + if (pluginDefinition.DalamudApiLevel < PluginManager.DALAMUD_API_LEVEL) + continue; + + didAny = true; + + if (hasSearchString && !installed && + !(pluginDefinition.Name.ToLowerInvariant().Contains(this.searchText.ToLowerInvariant()) || + string.Equals(pluginDefinition.Author, this.searchText, + StringComparison.InvariantCultureIgnoreCase) || + pluginDefinition.Tags != null && + pluginDefinition.Tags.Contains(this.searchText.ToLowerInvariant(), + StringComparer.InvariantCultureIgnoreCase) + )) + continue; + + didAnyWithSearch = true; + + var isInstalled = this.dalamud.PluginManager.Plugins.Where(x => x.Definition != null).Any( + x => x.Definition.InternalName == pluginDefinition.InternalName); + + var isTestingAvailable = false; + if (Version.TryParse(pluginDefinition.AssemblyVersion, out var assemblyVersion) && + Version.TryParse(pluginDefinition.TestingAssemblyVersion, out var testingAssemblyVersion)) + isTestingAvailable = this.dalamud.Configuration.DoPluginTest && + testingAssemblyVersion > assemblyVersion; + + if (this.dalamud.Configuration.DoPluginTest && pluginDefinition.IsTestingExclusive) + isTestingAvailable = true; + else if (!this.dalamud.Configuration.DoPluginTest && pluginDefinition.IsTestingExclusive) continue; + + var label = string.Empty; + if (isInstalled) { + label += Loc.Localize("InstallerInstalled", " (installed)"); + if (this.filter == PluginFilter.NotInstalled) continue; + } else if (this.filter == PluginFilter.Installed) { + continue; + } + + if (this.updatedPlugins != null && + this.updatedPlugins.Any(x => x.InternalName == pluginDefinition.InternalName && x.WasUpdated)) + label += Loc.Localize("InstallerUpdated", " (updated)"); + else if (this.updatedPlugins != null && + this.updatedPlugins.Any(x => x.InternalName == pluginDefinition.InternalName && + x.WasUpdated == false)) + label += Loc.Localize("InstallerUpdateFailed", " (update failed)"); + else if (this.filter == PluginFilter.Updated) continue; + + if (isTestingAvailable) + label += " (testing version)"; + else if (this.filter == PluginFilter.Testing) continue; + + ImGui.PushID(pluginDefinition.InternalName + pluginDefinition.AssemblyVersion); + + if (ImGui.CollapsingHeader(pluginDefinition.Name + label + "###Header" + pluginDefinition.InternalName) + ) { + ImGui.Indent(); + + ImGui.Text(pluginDefinition.Name); + ImGui.SameLine(); + ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), + $" by {pluginDefinition.Author}, {pluginDefinition.DownloadCount} downloads"); + + ImGui.Text(pluginDefinition.Description); + + if (!isInstalled) { + if (this.installStatus == PluginInstallStatus.InProgress) { + ImGui.Button(Loc.Localize("InstallerInProgress", "Install in progress...")); + } else { + var versionString = isTestingAvailable + ? pluginDefinition.TestingAssemblyVersion + " (testing version)" + : pluginDefinition.AssemblyVersion; + + if (ImGui.Button($"Install v{versionString}")) { + this.installStatus = PluginInstallStatus.InProgress; + + Task.Run(() => this.dalamud.PluginRepository.InstallPlugin( + pluginDefinition, true, false, isTestingAvailable)).ContinueWith(t => { + this.installStatus = + t.Result ? PluginInstallStatus.Success : PluginInstallStatus.Fail; + this.installStatus = + t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus; + + this.errorModalDrawing = this.installStatus == PluginInstallStatus.Fail; + this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail; + }); + } + } + + if (!string.IsNullOrEmpty(pluginDefinition.RepoUrl)) { + ImGui.PushFont(InterfaceManager.IconFont); + + ImGui.SameLine(); + if (ImGui.Button(FontAwesomeIcon.Globe.ToIconString()) && + pluginDefinition.RepoUrl.StartsWith("https://")) + Process.Start(pluginDefinition.RepoUrl); + + ImGui.PopFont(); + } + } else { + var installedPlugin = this.dalamud.PluginManager.Plugins.Where(x => x.Definition != null).First( + x => x.Definition.InternalName == + pluginDefinition.InternalName); + + var commands = this.dalamud.CommandManager.Commands.Where( + x => x.Value.LoaderAssemblyName == installedPlugin.Definition?.InternalName && + x.Value.ShowInHelp); + if (commands.Any()) { + ImGui.Dummy(new Vector2(10, 10) * ImGui.GetIO().FontGlobalScale); + foreach (var command in commands) + ImGui.Text($"{command.Key} → {command.Value.HelpMessage}"); + } + + if (!installedPlugin.IsRaw && ImGui.Button(Loc.Localize("InstallerDisable", "Disable"))) { + try { + this.dalamud.PluginManager.DisablePlugin(installedPlugin.Definition); + } catch (Exception exception) { + Log.Error(exception, "Could not disable plugin."); + this.errorModalDrawing = true; + this.errorModalOnNextFrame = true; + } + } + + if (installedPlugin.PluginInterface.UiBuilder.OnOpenConfigUi != null) { + ImGui.SameLine(); + + if (ImGui.Button(Loc.Localize("InstallerOpenConfig", "Open Configuration"))) + installedPlugin.PluginInterface.UiBuilder.OnOpenConfigUi?.Invoke(null, null); + } + + if (!string.IsNullOrEmpty(installedPlugin.Definition.RepoUrl)) { + ImGui.PushFont(InterfaceManager.IconFont); + + ImGui.SameLine(); + if (ImGui.Button(FontAwesomeIcon.Globe.ToIconString()) && + installedPlugin.Definition.RepoUrl.StartsWith("https://")) + Process.Start(installedPlugin.Definition.RepoUrl); + + ImGui.PopFont(); + } + + ImGui.SameLine(); + ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" v{pluginDefinition.AssemblyVersion}"); + + if(installedPlugin.IsRaw) { + ImGui.TextColored(new Vector4(1.0f, 0.0f, 0.0f, 1.0f), "To update or disable this plugin, please remove it from the devPlugins folder."); + } + } + + ImGui.Unindent(); + } + + ImGui.PopID(); + } + + if (!didAny) { + if (installed) { + ImGui.TextColored(this.colorGrey, + Loc.Localize("InstallerNoInstalled", + "No plugins are currently installed. You can install them from above.")); + } else { + ImGui.TextColored(this.colorGrey, + Loc.Localize("InstallerNoCompatible", + "No compatible plugins were found :( Please restart your game and try again.")); + } + } + else if (!didAnyWithSearch && !installed) + ImGui.TextColored(new Vector4(0.7f, 0.7f, 0.7f, 1.0f), + Loc.Localize("InstallNoMatching", "No plugins were found matching your search.")); + } } } diff --git a/Dalamud/Plugin/PluginManager.cs b/Dalamud/Plugin/PluginManager.cs index 6f9077e2d..472aaa621 100644 --- a/Dalamud/Plugin/PluginManager.cs +++ b/Dalamud/Plugin/PluginManager.cs @@ -22,7 +22,7 @@ namespace Dalamud.Plugin private readonly Type interfaceType = typeof(IDalamudPlugin); - public readonly List<(IDalamudPlugin Plugin, PluginDefinition Definition, DalamudPluginInterface PluginInterface)> Plugins = new List<(IDalamudPlugin plugin, PluginDefinition def, DalamudPluginInterface PluginInterface)>(); + public readonly List<(IDalamudPlugin Plugin, PluginDefinition Definition, DalamudPluginInterface PluginInterface, bool IsRaw)> Plugins = new List<(IDalamudPlugin plugin, PluginDefinition def, DalamudPluginInterface PluginInterface, bool IsRaw)>(); public List<(string SourcePluginName, string SubPluginName, Action SubAction)> IpcSubscriptions = new List<(string SourcePluginName, string SubPluginName, Action SubAction)>(); @@ -181,7 +181,7 @@ namespace Dalamud.Plugin plugin.Initialize(dalamudInterface); Log.Information("Loaded plugin: {0}", plugin.Name); - this.Plugins.Add((plugin, pluginDef, dalamudInterface)); + this.Plugins.Add((plugin, pluginDef, dalamudInterface, raw)); return true; }