public void UpdatePlugins() { try { var pluginsDirectory = new DirectoryInfo(this.pluginDirectory); this.installStatus = PluginInstallStatus.Success; foreach (var installed in pluginsDirectory.GetDirectories()) { var versions = installed.GetDirectories(); if (versions.Length == 0) { Log.Information("Has no versions: {0}", installed.FullName); continue; } var sortedVersions = versions.OrderBy(x => x.CreationTime); var latest = sortedVersions.Last(); var localInfoFile = new FileInfo(Path.Combine(latest.FullName, $"{installed.Name}.json")); if (!localInfoFile.Exists) { Log.Information("Has no definition: {0}", localInfoFile.FullName); continue; } var info = JsonConvert.DeserializeObject <PluginDefinition>(File.ReadAllText(localInfoFile.FullName)); var remoteInfo = this.pluginMaster.FirstOrDefault(x => x.Name == info.Name); if (remoteInfo == null) { Log.Information("Is not in pluginmaster: {0}", info.Name); continue; } if (remoteInfo.AssemblyVersion != info.AssemblyVersion) { this.manager.DisablePlugin(info); InstallPlugin(remoteInfo); } } } catch (Exception e) { Log.Error(e, "Plugin update failed hard."); this.installStatus = PluginInstallStatus.Fail; } }
private void InstallPlugin(PluginDefinition definition) { try { var outputDir = new DirectoryInfo(Path.Combine(this.pluginDirectory, definition.InternalName, definition.AssemblyVersion)); var dllFile = new FileInfo(Path.Combine(outputDir.FullName, $"{definition.InternalName}.dll")); var disabledFile = new FileInfo(Path.Combine(outputDir.FullName, ".disabled")); if (dllFile.Exists) { if (disabledFile.Exists) { disabledFile.Delete(); } this.installStatus = this.manager.LoadPluginFromAssembly(dllFile, false) ? PluginInstallStatus.Success : PluginInstallStatus.Fail; return; } if (outputDir.Exists) { outputDir.Delete(true); } outputDir.Create(); var path = Path.GetTempFileName(); Log.Information("Downloading plugin to {0}", path); using var client = new WebClient(); client.DownloadFile(PluginRepoBaseUrl + $"/plugins/{definition.InternalName}/latest.zip", path); Log.Information("Extracting to {0}", outputDir); ZipFile.ExtractToDirectory(path, outputDir.FullName); this.installStatus = this.manager.LoadPluginFromAssembly(dllFile, false) ? PluginInstallStatus.Success : PluginInstallStatus.Fail; } catch (Exception e) { Log.Error(e, "Plugin download failed hard."); this.installStatus = PluginInstallStatus.Fail; } }
/// <summary> /// Draw the plugin installer view ImGui. /// </summary> public override void Draw() { ImGui.SetCursorPosY(ImGui.GetCursorPosY() - (5 * ImGui.GetIO().FontGlobalScale)); var descriptionText = Loc.Localize("InstallerHint", "This window allows you to install and remove in-game plugins.\nThey are made by third-party developers."); ImGui.Text(descriptionText); var sortingTextSize = ImGui.CalcTextSize(Loc.Localize("SortDownloadCounts", "Download Count")) + ImGui.CalcTextSize(Loc.Localize("PluginSort", "Sort By")); ImGui.SameLine(ImGui.GetWindowWidth() - sortingTextSize.X - ((250 + 20) * ImGui.GetIO().FontGlobalScale)); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (ImGui.CalcTextSize(descriptionText).Y / 4) - 2); ImGui.SetCursorPosX(ImGui.GetWindowWidth() - sortingTextSize.X - ((250 + 20) * ImGui.GetIO().FontGlobalScale)); ImGui.SetNextItemWidth(240 * ImGui.GetIO().FontGlobalScale); ImGui.InputTextWithHint("###XPlPluginInstaller_Search", Loc.Localize("InstallerSearch", "Search"), ref this.searchText, 100); ImGui.SameLine(); ImGui.SetNextItemWidth((10 * ImGui.GetIO().FontGlobalScale) + ImGui.CalcTextSize(Loc.Localize("SortDownloadCounts", "Download Count")).X); if (ImGui.BeginCombo(Loc.Localize("PluginSort", "Sort By"), this.filterText, ImGuiComboFlags.NoArrowButton)) { if (ImGui.Selectable(Loc.Localize("SortAlphabetical", "Alphabetical"))) { this.sortKind = PluginSortKind.Alphabetical; this.filterText = Loc.Localize("SortAlphabetical", "Alphabetical"); this.ResortPlugins(); } if (ImGui.Selectable(Loc.Localize("SortDownloadCounts", "Download Count"))) { this.sortKind = PluginSortKind.DownloadCount; this.filterText = Loc.Localize("SortDownloadCounts", "Download Count"); this.ResortPlugins(); } if (ImGui.Selectable(Loc.Localize("SortLastUpdate", "Last Update"))) { this.sortKind = PluginSortKind.LastUpdate; this.filterText = Loc.Localize("SortLastUpdate", "Last Update"); this.ResortPlugins(); } ImGui.EndCombo(); } ImGui.SetCursorPosY(ImGui.GetCursorPosY() - (5 * ImGui.GetIO().FontGlobalScale)); string initializationStatusText = null; if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.InProgress) { initializationStatusText = Loc.Localize("InstallerLoading", "Loading plugins..."); this.pluginListAvailable = null; } else if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.Fail) { initializationStatusText = Loc.Localize("InstallerDownloadFailed", "Download failed."); this.pluginListAvailable = null; } else if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.FailThirdRepo) { initializationStatusText = Loc.Localize("InstallerDownloadFailedThird", "One of your third party repos is unreachable or there is no internet connection."); this.pluginListAvailable = null; } else { if (this.pluginListAvailable == null) { this.RefetchPlugins(); } } ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 3) * ImGui.GetIO().FontGlobalScale); if (ImGui.BeginTabBar("PluginsTabBar", ImGuiTabBarFlags.NoTooltip)) { this.DrawTab(false, initializationStatusText); this.DrawTab(true, initializationStatusText); ImGui.EndTabBar(); ImGui.Separator(); } ImGui.PopStyleVar(); ImGui.Dummy(new Vector2(3f, 3f) * ImGui.GetIO().FontGlobalScale); if (this.installStatus == PluginInstallStatus.InProgress) { ImGui.Button(Loc.Localize("InstallerUpdating", "Updating...")); } else { if (this.updateComplete) { ImGui.Button(this.updatePluginCount == 0 ? Loc.Localize("InstallerNoUpdates", "No updates found!") : string.Format(Loc.Localize("InstallerUpdateComplete", "{0} plugins updated!"), this.updatePluginCount)); } else { if (ImGui.Button(Loc.Localize("InstallerUpdatePlugins", "Update plugins")) && this.dalamud.PluginRepository.State == PluginRepository.InitializationState.Success) { this.installStatus = PluginInstallStatus.InProgress; Task.Run(() => this.dalamud.PluginRepository.UpdatePlugins()).ContinueWith(t => { this.installStatus = t.Result.Success ? PluginInstallStatus.Success : PluginInstallStatus.Fail; this.installStatus = t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus; if (this.installStatus == PluginInstallStatus.Success) { this.updateComplete = true; } if (t.Result.UpdatedPlugins != null) { this.updatePluginCount = t.Result.UpdatedPlugins.Count; this.updatedPlugins = t.Result.UpdatedPlugins; } this.errorModalDrawing = this.installStatus == PluginInstallStatus.Fail; this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail; this.dalamud.PluginRepository.PrintUpdatedPlugins( this.updatedPlugins, Loc.Localize("DalamudPluginUpdates", "Updates:")); this.RefetchPlugins(); }); } } } ImGui.SameLine(); if (ImGui.Button(Loc.Localize("SettingsInstaller", "Settings"))) { this.dalamud.DalamudUi.OpenSettings(); } var closeText = Loc.Localize("Close", "Close"); ImGui.SameLine(ImGui.GetWindowWidth() - ImGui.CalcTextSize(closeText).X - (16 * ImGui.GetIO().FontGlobalScale)); if (ImGui.Button(closeText)) { this.IsOpen = false; this.dalamud.Configuration.Save(); } if (ImGui.BeginPopupModal(Loc.Localize("InstallerError", "Installer failed"), ref this.errorModalDrawing, ImGuiWindowFlags.AlwaysAutoResize)) { var message = Loc.Localize( "InstallerErrorHint", "The plugin installer ran into an issue or the plugin is incompatible.\nPlease restart the game and report this error on our discord."); if (this.updatedPlugins != null) { if (this.updatedPlugins.Any(x => x.WasUpdated == false)) { var extraInfoMessage = Loc.Localize( "InstallerErrorPluginInfo", "\n\nThe following plugins caused these issues:\n\n{0}\nYou may try removing these plugins manually and reinstalling them."); var insert = this.updatedPlugins.Where(x => x.WasUpdated == false) .Aggregate( string.Empty, (current, pluginUpdateStatus) => current + $"* {pluginUpdateStatus.InternalName}\n"); extraInfoMessage = string.Format(extraInfoMessage, insert); message += extraInfoMessage; } } ImGui.Text(message); ImGui.Spacing(); if (ImGui.Button(Loc.Localize("OK", "OK"), new Vector2(120, 40))) { ImGui.CloseCurrentPopup(); } ImGui.EndPopup(); } if (this.errorModalOnNextFrame) { ImGui.OpenPopup(Loc.Localize("InstallerError", "Installer failed")); this.errorModalOnNextFrame = false; } }
private void DrawPluginList(List <PluginDefinition> pluginDefinitions, bool installed) { var didAny = false; var didAnyWithSearch = false; var hasSearchString = !string.IsNullOrWhiteSpace(this.searchText); for (var index = 0; index < pluginDefinitions.Count; index++) { var pluginDefinition = pluginDefinitions[index]; if (pluginDefinition.ApplicableVersion != this.gameVersion && pluginDefinition.ApplicableVersion != "any") { continue; } if (pluginDefinition.IsHide) { continue; } if (pluginDefinition.DalamudApiLevel < PluginManager.DalamudApiLevel) { continue; } if (this.dalamud.Configuration.HiddenPluginInternalName.Contains(pluginDefinition.InternalName)) { 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 (!installed && !this.dalamud.Configuration.DoPluginTest && pluginDefinition.IsTestingExclusive) { continue; } var label = string.Empty; if (isInstalled && !installed) { label += Loc.Localize("InstallerInstalled", " (installed)"); } else if (!isInstalled && installed) { label += Loc.Localize("InstallerDisabled", " (disabled)"); } 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)"); } if (isTestingAvailable) { label += Loc.Localize("InstallerTestingVersion", " (testing version)"); } ImGui.PushID(pluginDefinition.InternalName + pluginDefinition.AssemblyVersion + installed + index); if (ImGui.CollapsingHeader(pluginDefinition.Name + label + "###Header" + pluginDefinition.InternalName)) { ImGui.Indent(); ImGui.Text(pluginDefinition.Name); ImGui.SameLine(); var info = $" by {pluginDefinition.Author}"; info += pluginDefinition.DownloadCount != 0 ? $", {pluginDefinition.DownloadCount} downloads" : ", download count unavailable"; if (pluginDefinition.RepoNumber != 0) { info += $", from custom plugin repository #{pluginDefinition.RepoNumber}"; } ImGui.TextColored(ImGuiColors.DalamudGrey3, info); if (!string.IsNullOrWhiteSpace(pluginDefinition.Description)) { ImGui.TextWrapped(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(10f, 10f) * ImGui.GetIO().FontGlobalScale); foreach (var command in commands) { ImGui.TextWrapped($"{command.Key} → {command.Value.HelpMessage}"); } } ImGui.NewLine(); if (!installedPlugin.IsRaw) { ImGui.SameLine(); 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.HasConfigUi) { ImGui.SameLine(); if (ImGui.Button(Loc.Localize("InstallerOpenConfig", "Open Configuration"))) { installedPlugin.PluginInterface.UiBuilder.OpenConfigUi(); } } 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(ImGuiColors.DalamudGrey3, $" v{installedPlugin.Definition.AssemblyVersion}"); if (installedPlugin.IsRaw) { ImGui.SameLine(); ImGui.TextColored( ImGuiColors.DalamudRed, this.dalamud.PluginRepository.PluginMaster.Any(x => x.InternalName == installedPlugin.Definition.InternalName) ? " This plugin is available in one of your repos, please remove it from the devPlugins folder." : " To disable this plugin, please remove it from the devPlugins folder."); } } ImGui.Unindent(); } if (ImGui.BeginPopupContextItem("item context menu")) { if (ImGui.Selectable("Hide from installer")) { this.dalamud.Configuration.HiddenPluginInternalName.Add(pluginDefinition.InternalName); } ImGui.EndPopup(); } ImGui.PopID(); } if (!didAny) { if (installed) { ImGui.TextColored( ImGuiColors.DalamudGrey, Loc.Localize( "InstallerNoInstalled", "No plugins are currently installed. You can install them from the Available Plugins tab.")); } else { ImGui.TextColored( ImGuiColors.DalamudGrey, Loc.Localize( "InstallerNoCompatible", "No compatible plugins were found :( Please restart your game and try again.")); } } else if (!didAnyWithSearch) { ImGui.TextColored( ImGuiColors.DalamudGrey2, Loc.Localize("InstallNoMatching", "No plugins were found matching your search.")); } }
public bool Draw() { var windowOpen = true; ImGui.SetNextWindowSize(new Vector2(750, 520)); ImGui.Begin(Loc.Localize("InstallerHeader", "Plugin Installer"), ref windowOpen, ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollbar); ImGui.Text(Loc.Localize("InstallerHint", "This window allows you install and remove in-game plugins.\nThey are made by third-party developers.")); ImGui.Separator(); ImGui.BeginChild("scrolling", new Vector2(0, 400), true, ImGuiWindowFlags.HorizontalScrollbar); ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 3)); if (this.repository.State == PluginRepository.InitializationState.InProgress) { ImGui.Text(Loc.Localize("InstallerLoading", "Loading plugins...")); } else if (this.repository.State == PluginRepository.InitializationState.Fail) { ImGui.Text(Loc.Localize("InstallerDownloadFailed", "Download failed.")); } else { foreach (var pluginDefinition in this.repository.PluginMaster) { if (pluginDefinition.ApplicableVersion != this.gameVersion && pluginDefinition.ApplicableVersion != "any") { continue; } if (pluginDefinition.IsHide) { continue; } ImGui.PushID(pluginDefinition.InternalName + pluginDefinition.AssemblyVersion); var isInstalled = this.manager.Plugins.Where(x => x.Definition != null).Any( x => x.Definition.InternalName == pluginDefinition.InternalName); if (ImGui.CollapsingHeader(pluginDefinition.Name + (isInstalled ? Loc.Localize("InstallerInstalled", " (installed)") : string.Empty))) { ImGui.Indent(); ImGui.Text(pluginDefinition.Name); ImGui.SameLine(); ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" by {pluginDefinition.Author}"); ImGui.Text(pluginDefinition.Description); if (!isInstalled) { if (this.installStatus == PluginInstallStatus.InProgress) { ImGui.Button(Loc.Localize("InstallerInProgress", "Install in progress...")); } else { if (ImGui.Button($"Install v{pluginDefinition.AssemblyVersion}")) { this.installStatus = PluginInstallStatus.InProgress; Task.Run(() => this.repository.InstallPlugin(pluginDefinition)).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; }); } } } else { var installedPlugin = this.manager.Plugins.Where(x => x.Definition != null).First( x => x.Definition.InternalName == pluginDefinition.InternalName); if (ImGui.Button(Loc.Localize("InstallerDisable", "Disable"))) { try { this.manager.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); } } ImGui.SameLine(); ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" v{pluginDefinition.AssemblyVersion}"); } ImGui.Unindent(); } ImGui.PopID(); } } ImGui.PopStyleVar(); ImGui.EndChild(); ImGui.Separator(); if (this.installStatus == PluginInstallStatus.InProgress) { ImGui.Button(Loc.Localize("InstallerUpdating", "Updating...")); } else { if (this.updateComplete) { ImGui.Button(this.updatePluginCount == 0 ? Loc.Localize("InstallerNoUpdates", "No updates found!") : string.Format(Loc.Localize("InstallerUpdateComplete", "{0} plugins updated!"), this.updatePluginCount)); } else { if (ImGui.Button(Loc.Localize("InstallerUpdatePlugins", "Update plugins"))) { this.installStatus = PluginInstallStatus.InProgress; Task.Run(() => this.repository.UpdatePlugins()).ContinueWith(t => { this.installStatus = t.Result.Success ? PluginInstallStatus.Success : PluginInstallStatus.Fail; this.installStatus = t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus; if (this.installStatus == PluginInstallStatus.Success) { this.updateComplete = true; this.updatePluginCount = t.Result.UpdatedCount; } this.errorModalDrawing = this.installStatus == PluginInstallStatus.Fail; this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail; }); } } } ImGui.SameLine(); if (ImGui.Button(Loc.Localize("Close", "Close"))) { windowOpen = false; } ImGui.Spacing(); if (ImGui.BeginPopupModal(Loc.Localize("InstallerError", "Installer failed"), ref this.errorModalDrawing, ImGuiWindowFlags.AlwaysAutoResize)) { ImGui.Text(Loc.Localize("InstallerErrorHint", "The plugin installer ran into an issue or the plugin is incompatible.\nPlease restart the game and report this error on our discord.")); ImGui.Spacing(); if (ImGui.Button(Loc.Localize("OK", "OK"), new Vector2(120, 40))) { ImGui.CloseCurrentPopup(); } ImGui.EndPopup(); } if (this.errorModalOnNextFrame) { ImGui.OpenPopup(Loc.Localize("InstallerError", "Installer failed")); this.errorModalOnNextFrame = false; } ImGui.End(); return(windowOpen); }
public bool Draw() { var windowOpen = true; ImGui.SetNextWindowSize(new Vector2(750, 520)); ImGui.Begin(Loc.Localize("InstallerHeader", "Plugin Installer") + (this.dalamud.Configuration.DoPluginTest ? " (TESTING)" : string.Empty) + "###XlPluginInstaller", ref windowOpen, ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollbar); ImGui.Text(Loc.Localize("InstallerHint", "This window allows you install and remove in-game plugins.\nThey are made by third-party developers.")); ImGui.SameLine(); ImGui.InputTextWithHint("###XPlPluginInstaller_Search", Loc.Localize("InstallerSearch", "Search"), this.searchText, 100); ImGui.Separator(); ImGui.BeginChild("scrolling", new Vector2(0, 400), true, ImGuiWindowFlags.HorizontalScrollbar); ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 3)); if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.InProgress) { ImGui.Text(Loc.Localize("InstallerLoading", "Loading plugins...")); } else if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.Fail) { ImGui.Text(Loc.Localize("InstallerDownloadFailed", "Download failed.")); } else { var didAny = false; var didAnyWithSearch = false; var hasSearchString = !string.IsNullOrWhiteSpace(this.searchText); 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; ImGui.PushID(pluginDefinition.InternalName + pluginDefinition.AssemblyVersion); var isInstalled = this.dalamud.PluginManager.Plugins.Where(x => x.Definition != null).Any( x => x.Definition.InternalName == pluginDefinition.InternalName); var label = isInstalled ? Loc.Localize("InstallerInstalled", " (installed)") : string.Empty; label = this.updatedPlugins != null && this.updatedPlugins.Any(x => x.InternalName == pluginDefinition.InternalName && x.WasUpdated) ? Loc.Localize("InstallerUpdated", " (updated)") : label; label = this.updatedPlugins != null && this.updatedPlugins.Any(x => x.InternalName == pluginDefinition.InternalName && x.WasUpdated == false) ? Loc.Localize("InstallerUpdateFailed", " (update failed)") : label; 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 { if (ImGui.Button($"Install v{pluginDefinition.AssemblyVersion}")) { this.installStatus = PluginInstallStatus.InProgress; Task.Run(() => this.dalamud.PluginRepository.InstallPlugin(pluginDefinition)).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); 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(); } 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.PopStyleVar(); ImGui.EndChild(); ImGui.Separator(); if (this.installStatus == PluginInstallStatus.InProgress) { ImGui.Button(Loc.Localize("InstallerUpdating", "Updating...")); } else { if (this.updateComplete) { ImGui.Button(this.updatePluginCount == 0 ? Loc.Localize("InstallerNoUpdates", "No updates found!") : string.Format(Loc.Localize("InstallerUpdateComplete", "{0} plugins updated!"), this.updatePluginCount)); } else { if (ImGui.Button(Loc.Localize("InstallerUpdatePlugins", "Update plugins"))) { this.installStatus = PluginInstallStatus.InProgress; Task.Run(() => this.dalamud.PluginRepository.UpdatePlugins()).ContinueWith(t => { this.installStatus = t.Result.Success ? PluginInstallStatus.Success : PluginInstallStatus.Fail; this.installStatus = t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus; if (this.installStatus == PluginInstallStatus.Success) { this.updateComplete = true; } if (t.Result.UpdatedPlugins != null) { this.updatePluginCount = t.Result.UpdatedPlugins.Count; this.updatedPlugins = t.Result.UpdatedPlugins; } this.errorModalDrawing = this.installStatus == PluginInstallStatus.Fail; this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail; }); } } } ImGui.SameLine(); if (ImGui.Button(Loc.Localize("Close", "Close"))) { windowOpen = false; } ImGui.Spacing(); if (ImGui.BeginPopupModal(Loc.Localize("InstallerError", "Installer failed"), ref this.errorModalDrawing, ImGuiWindowFlags.AlwaysAutoResize)) { var message = Loc.Localize("InstallerErrorHint", "The plugin installer ran into an issue or the plugin is incompatible.\nPlease restart the game and report this error on our discord."); if (this.updatedPlugins != null) { if (this.updatedPlugins.Any(x => x.WasUpdated == false)) { var extraInfoMessage = Loc.Localize("InstallerErrorPluginInfo", "\n\nThe following plugins caused these issues:\n\n{0}\nYou may try removing these plugins manually and reinstalling them."); var insert = this.updatedPlugins.Where(x => x.WasUpdated == false) .Aggregate(string.Empty, (current, pluginUpdateStatus) => current + $"* {pluginUpdateStatus.InternalName}\n"); extraInfoMessage = string.Format(extraInfoMessage, insert); message += extraInfoMessage; } } ImGui.Text(message); ImGui.Spacing(); if (ImGui.Button(Loc.Localize("OK", "OK"), new Vector2(120, 40))) { ImGui.CloseCurrentPopup(); } ImGui.EndPopup(); } if (this.errorModalOnNextFrame) { ImGui.OpenPopup(Loc.Localize("InstallerError", "Installer failed")); this.errorModalOnNextFrame = false; } ImGui.End(); return(windowOpen); }
public bool Draw() { var windowOpen = true; ImGui.SetNextWindowSize(new Vector2(810, 520) * ImGui.GetIO().FontGlobalScale); ImGui.Begin(Loc.Localize("InstallerHeader", "Plugin Installer") + (this.dalamud.Configuration.DoPluginTest ? " (TESTING)" : string.Empty) + "###XlPluginInstaller", ref windowOpen, ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollbar); ImGui.Text(Loc.Localize("InstallerHint", "This window allows you install and remove in-game plugins.\nThey are made by third-party developers.")); ImGui.SameLine(ImGui.GetWindowWidth() - ((250 + 20 + ImGui.CalcTextSize(Loc.Localize("SortDownloadCounts", "Download Count")).X + ImGui.CalcTextSize(Loc.Localize("PluginSort", "Sort By")).X) * ImGui.GetIO().FontGlobalScale)); ImGui.SetNextItemWidth(240 * ImGui.GetIO().FontGlobalScale); ImGui.InputTextWithHint("###XPlPluginInstaller_Search", Loc.Localize("InstallerSearch", "Search"), ref this.searchText, 100); ImGui.SameLine(); ImGui.SetNextItemWidth(10 + (ImGui.CalcTextSize(Loc.Localize("SortDownloadCounts", "Download Count")).X) * ImGui.GetIO().FontGlobalScale); if (ImGui.BeginCombo(Loc.Localize("PluginSort", "Sort By"), this.filterText, ImGuiComboFlags.NoArrowButton)) { if (ImGui.Selectable(Loc.Localize("SortAlphabetical", "Alphabetical"))) { this.sortKind = PluginSortKind.Alphabetical; this.filterText = Loc.Localize("SortAlphabetical", "Alphabetical"); ResortAvailable(); } if (ImGui.Selectable(Loc.Localize("SortDownloadCounts", "Download Count"))) { this.sortKind = PluginSortKind.DownloadCount; this.filterText = Loc.Localize("SortDownloadCounts", "Download Count"); ResortAvailable(); } if (ImGui.Selectable(Loc.Localize("SortLastUpdate", "Last Update"))) { this.sortKind = PluginSortKind.LastUpdate; this.filterText = Loc.Localize("SortLastUpdate", "Last Update"); ResortAvailable(); } ImGui.EndCombo(); } ImGui.BeginChild("scrolling", new Vector2(0, 400 * ImGui.GetIO().FontGlobalScale), true, ImGuiWindowFlags.HorizontalScrollbar); ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 3) * ImGui.GetIO().FontGlobalScale); if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.InProgress) { ImGui.Text(Loc.Localize("InstallerLoading", "Loading plugins...")); } else if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.Fail) { ImGui.Text(Loc.Localize("InstallerDownloadFailed", "Download failed.")); } else if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.FailThirdRepo) { ImGui.Text(Loc.Localize("InstallerDownloadFailedThird", "One of your third party repos is unreachable or there is no internet connection.")); } else { 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); this.pluginListInstalled.Sort((x, y) => x.Name.CompareTo(y.Name)); ResortAvailable(); } 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(); ImGui.EndChild(); ImGui.Separator(); if (this.installStatus == PluginInstallStatus.InProgress) { ImGui.Button(Loc.Localize("InstallerUpdating", "Updating...")); } else { if (this.updateComplete) { ImGui.Button(this.updatePluginCount == 0 ? Loc.Localize("InstallerNoUpdates", "No updates found!") : string.Format(Loc.Localize("InstallerUpdateComplete", "{0} plugins updated!"), this.updatePluginCount)); } else { if (ImGui.Button(Loc.Localize("InstallerUpdatePlugins", "Update plugins"))) { this.installStatus = PluginInstallStatus.InProgress; Task.Run(() => this.dalamud.PluginRepository.UpdatePlugins()).ContinueWith(t => { this.installStatus = t.Result.Success ? PluginInstallStatus.Success : PluginInstallStatus.Fail; this.installStatus = t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus; if (this.installStatus == PluginInstallStatus.Success) { this.updateComplete = true; } if (t.Result.UpdatedPlugins != null) { this.updatePluginCount = t.Result.UpdatedPlugins.Count; this.updatedPlugins = t.Result.UpdatedPlugins; } this.errorModalDrawing = this.installStatus == PluginInstallStatus.Fail; this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail; this.dalamud.PluginRepository.PrintUpdatedPlugins(updatedPlugins, Loc.Localize("DalamudPluginUpdates", "Updates:")); }); } } } ImGui.SameLine(); if (ImGui.Button(Loc.Localize("Close", "Close"))) { windowOpen = false; } ImGui.Spacing(); if (ImGui.BeginPopupModal(Loc.Localize("InstallerError", "Installer failed"), ref this.errorModalDrawing, ImGuiWindowFlags.AlwaysAutoResize)) { var message = Loc.Localize("InstallerErrorHint", "The plugin installer ran into an issue or the plugin is incompatible.\nPlease restart the game and report this error on our discord."); if (this.updatedPlugins != null) { if (this.updatedPlugins.Any(x => x.WasUpdated == false)) { var extraInfoMessage = Loc.Localize("InstallerErrorPluginInfo", "\n\nThe following plugins caused these issues:\n\n{0}\nYou may try removing these plugins manually and reinstalling them."); var insert = this.updatedPlugins.Where(x => x.WasUpdated == false) .Aggregate(string.Empty, (current, pluginUpdateStatus) => current + $"* {pluginUpdateStatus.InternalName}\n"); extraInfoMessage = string.Format(extraInfoMessage, insert); message += extraInfoMessage; } } ImGui.Text(message); ImGui.Spacing(); if (ImGui.Button(Loc.Localize("OK", "OK"), new Vector2(120, 40))) { ImGui.CloseCurrentPopup(); } ImGui.EndPopup(); } if (this.errorModalOnNextFrame) { ImGui.OpenPopup(Loc.Localize("InstallerError", "Installer failed")); this.errorModalOnNextFrame = false; } ImGui.End(); return(windowOpen); }
public bool Draw() { var windowOpen = true; ImGui.SetNextWindowSize(new Vector2(750, 518)); ImGui.Begin("Plugin Installer", ref windowOpen, ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollbar); ImGui.Text("This window allows you install and remove in-game plugins."); ImGui.Text("They are made by third-party developers."); ImGui.Separator(); ImGui.BeginChild("scrolling", new Vector2(0, 400), true, ImGuiWindowFlags.HorizontalScrollbar); ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 3)); if (this.pluginMaster == null) { ImGui.Text("Loading plugins..."); } else if (this.masterDownloadFailed) { ImGui.Text("Download failed."); } else { foreach (var pluginDefinition in this.pluginMaster) { if (pluginDefinition.ApplicableVersion != this.gameVersion && pluginDefinition.ApplicableVersion != "any") { continue; } if (pluginDefinition.IsHide) { continue; } if (ImGui.CollapsingHeader(pluginDefinition.Name)) { ImGui.Indent(); ImGui.Text(pluginDefinition.Name); ImGui.SameLine(); ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" by {pluginDefinition.Author}"); ImGui.Text(pluginDefinition.Description); var isInstalled = this.manager.Plugins.Where(x => x.Definition != null).Any( x => x.Definition.InternalName == pluginDefinition.InternalName); if (!isInstalled) { if (this.installStatus == PluginInstallStatus.InProgress) { ImGui.Button("Install in progress..."); } else { if (ImGui.Button($"Install v{pluginDefinition.AssemblyVersion}")) { this.installStatus = PluginInstallStatus.InProgress; Task.Run(() => InstallPlugin(pluginDefinition)).ContinueWith(t => { this.installStatus = t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus; this.errorModalDrawing = this.installStatus == PluginInstallStatus.Fail; this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail; }); } } } else { var installedPlugin = this.manager.Plugins.Where(x => x.Definition != null).First( x => x.Definition.InternalName == pluginDefinition.InternalName); if (ImGui.Button("Disable")) { try { this.manager.DisablePlugin(installedPlugin.Definition); } catch (Exception exception) { Log.Error(exception, "Could not disable plugin."); this.errorModalDrawing = true; this.errorModalOnNextFrame = true; } } if (installedPlugin.Plugin is IHasConfigUi v2Plugin && v2Plugin.OpenConfigUi != null) { ImGui.SameLine(); if (ImGui.Button("Open Configuration")) { v2Plugin.OpenConfigUi?.Invoke(null, null); } } ImGui.SameLine(); ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" v{pluginDefinition.AssemblyVersion}"); } ImGui.Unindent(); } } } ImGui.PopStyleVar(); ImGui.EndChild(); ImGui.Separator(); if (this.installStatus == PluginInstallStatus.InProgress) { ImGui.Button("In progress..."); } else { if (ImGui.Button("Update plugins")) { this.installStatus = PluginInstallStatus.InProgress; Task.Run(() => UpdatePlugins()).ContinueWith(t => { this.installStatus = t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus; this.errorModalDrawing = this.installStatus == PluginInstallStatus.Fail; this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail; }); } } ImGui.SameLine(); if (ImGui.Button("Close")) { windowOpen = false; } ImGui.Spacing(); if (ImGui.BeginPopupModal("Installer failed", ref this.errorModalDrawing, ImGuiWindowFlags.AlwaysAutoResize)) { ImGui.Text("The plugin installer ran into an issue or the plugin is incompatible."); ImGui.Text("Please restart the game and report this error on our discord."); ImGui.Spacing(); if (ImGui.Button("OK", new Vector2(120, 40))) { ImGui.CloseCurrentPopup(); } ImGui.EndPopup(); } if (this.errorModalOnNextFrame) { ImGui.OpenPopup("Installer failed"); this.errorModalOnNextFrame = false; } ImGui.End(); return(windowOpen); }