From ec7a4076d51499f7e38d80eae00baea8564e2ffe Mon Sep 17 00:00:00 2001 From: Raymond Date: Tue, 10 Aug 2021 08:34:41 -0400 Subject: [PATCH 1/3] feat: Scan devPlugins from any location --- .../Internal/DalamudConfiguration.cs | 7 + .../Internal/DevPluginLocationSettings.cs | 24 +++ .../Internal/Windows/SettingsWindow.cs | 170 ++++++++++++++++-- Dalamud/Plugin/Internal/PluginManager.cs | 34 +++- 4 files changed, 214 insertions(+), 21 deletions(-) create mode 100644 Dalamud/Configuration/Internal/DevPluginLocationSettings.cs diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs index 4eb6e3b03..33933d98f 100644 --- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs +++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs @@ -92,6 +92,13 @@ namespace Dalamud.Configuration.Internal /// public Dictionary DevPluginSettings { get; set; } = new(); + /// + /// Gets or sets a list of additional locations that dev plugins should be loaded from. This can + /// be either a DLL or folder, but should be the absolute path, or a path relative to the currently + /// injected Dalamud instance. + /// + public List DevPluginLoadLocations { get; set; } = new(); + /// /// Gets or sets the global UI scale. /// diff --git a/Dalamud/Configuration/Internal/DevPluginLocationSettings.cs b/Dalamud/Configuration/Internal/DevPluginLocationSettings.cs new file mode 100644 index 000000000..995fb1a23 --- /dev/null +++ b/Dalamud/Configuration/Internal/DevPluginLocationSettings.cs @@ -0,0 +1,24 @@ +namespace Dalamud.Configuration +{ + /// + /// Additional locations to load dev plugins from. + /// + internal sealed class DevPluginLocationSettings + { + /// + /// Gets or sets the dev pluign path. + /// + public string Path { get; set; } + + /// + /// Gets or sets a value indicating whether the third party repo is enabled. + /// + public bool IsEnabled { get; set; } + + /// + /// Clone this object. + /// + /// A shallow copy of this object. + public DevPluginLocationSettings Clone() => this.MemberwiseClone() as DevPluginLocationSettings; + } +} diff --git a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/SettingsWindow.cs index f5c13dd0a..fde2ad0c7 100644 --- a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs +++ b/Dalamud/Interface/Internal/Windows/SettingsWindow.cs @@ -44,16 +44,21 @@ namespace Dalamud.Interface.Internal.Windows private bool doDocking; private bool doViewport; private bool doGamepad; + private List thirdRepoList; private bool thirdRepoListChanged; + private string thirdRepoTempUrl = string.Empty; + private string thirdRepoAddError = string.Empty; + + private List devPluginLocations; + private bool devPluginLocationsChanged; + private string devPluginTempLocation = string.Empty; + private string devPluginLocationAddError = string.Empty; private bool printPluginsWelcomeMsg; private bool autoUpdatePlugins; private bool doButtonsSystemMenu; - private string thirdRepoTempUrl = string.Empty; - private string thirdRepoAddError = string.Empty; - #region Experimental private bool doPluginTest; @@ -88,6 +93,7 @@ namespace Dalamud.Interface.Internal.Windows this.doPluginTest = this.dalamud.Configuration.DoPluginTest; this.thirdRepoList = this.dalamud.Configuration.ThirdRepoList.Select(x => x.Clone()).ToList(); + this.devPluginLocations = this.dalamud.Configuration.DevPluginLoadLocations.Select(x => x.Clone()).ToList(); this.printPluginsWelcomeMsg = this.dalamud.Configuration.PrintPluginsWelcomeMsg; this.autoUpdatePlugins = this.dalamud.Configuration.AutoUpdatePlugins; @@ -144,14 +150,15 @@ namespace Dalamud.Interface.Internal.Windows public override void OnOpen() { this.thirdRepoListChanged = false; + this.devPluginLocationsChanged = false; } /// public override void OnClose() { ImGui.GetIO().FontGlobalScale = this.dalamud.Configuration.GlobalUiScale; - this.thirdRepoList = this.dalamud.Configuration.ThirdRepoList.Select(x => x.Clone()).ToList(); + this.devPluginLocations = this.dalamud.Configuration.DevPluginLoadLocations.Select(x => x.Clone()).ToList(); } /// @@ -252,12 +259,18 @@ namespace Dalamud.Interface.Internal.Windows if (ImGui.BeginTabItem(Loc.Localize("DalamudSettingsExperimental", "Experimental"))) { + #region Plugin testing + ImGui.Checkbox(Loc.Localize("DalamudSettingsPluginTest", "Get plugin testing builds"), ref this.doPluginTest); ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingsPluginTestHint", "Receive testing prereleases for plugins.")); ImGui.TextColored(this.warnTextColor, Loc.Localize("DalamudSettingsPluginTestWarning", "Testing plugins may not have been vetted before being published. Please only enable this if you are aware of the risks.")); + #endregion + ImGuiHelpers.ScaledDummy(12); + #region Hidden plugins + if (ImGui.Button(Loc.Localize("DalamudSettingsClearHidden", "Clear hidden plugins"))) { this.dalamud.Configuration.HiddenPluginInternalName.Clear(); @@ -266,10 +279,12 @@ namespace Dalamud.Interface.Internal.Windows ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingsClearHiddenHint", "Restore plugins you have previously hidden from the plugin installer.")); - ImGuiHelpers.ScaledDummy(12); + #endregion ImGuiHelpers.ScaledDummy(12); + #region Custom repos + ImGui.Text(Loc.Localize("DalamudSettingsCustomRepo", "Custom Plugin Repositories")); ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingCustomRepoHint", "Add custom plugin repositories.")); ImGui.TextColored(this.warnTextColor, Loc.Localize("DalamudSettingCustomRepoWarning", "We cannot take any responsibility for third-party plugins and repositories.\nTake care when installing third-party plugins from untrusted sources.")); @@ -278,7 +293,7 @@ namespace Dalamud.Interface.Internal.Windows ImGui.Columns(4); ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale)); - ImGui.SetColumnWidth(1, ImGui.GetWindowWidth() - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionWidth() - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale)); ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale)); ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale)); @@ -303,7 +318,7 @@ namespace Dalamud.Interface.Internal.Windows ImGui.NextColumn(); ImGui.Separator(); - ThirdPartyRepoSettings toRemove = null; + ThirdPartyRepoSettings repoToRemove = null; var repoNumber = 1; foreach (var thirdRepoSetting in this.thirdRepoList) @@ -325,7 +340,7 @@ namespace Dalamud.Interface.Internal.Windows if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) { - toRemove = thirdRepoSetting; + repoToRemove = thirdRepoSetting; } ImGui.NextColumn(); @@ -336,9 +351,9 @@ namespace Dalamud.Interface.Internal.Windows repoNumber++; } - if (toRemove != null) + if (repoToRemove != null) { - this.thirdRepoList.Remove(toRemove); + this.thirdRepoList.Remove(repoToRemove); this.thirdRepoListChanged = true; } @@ -377,6 +392,115 @@ namespace Dalamud.Interface.Internal.Windows { ImGui.TextColored(new Vector4(1, 0, 0, 1), this.thirdRepoAddError); } + + #endregion + + ImGuiHelpers.ScaledDummy(12); + + #region Custom dev plugin load locations + + ImGui.Text(Loc.Localize("DalamudSettingsDevPluginLocation", "Dev Plugin Locations")); + ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingsDevPluginLocationsHint", "Add additional dev plugin load locations.\nThese can be either the directory or DLL path.")); + + ImGuiHelpers.ScaledDummy(5); + + ImGui.Columns(4); + ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionWidth() - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale)); + + ImGui.Separator(); + + ImGui.Text("#"); + ImGui.NextColumn(); + ImGui.Text("Path"); + ImGui.NextColumn(); + ImGui.Text("Enabled"); + ImGui.NextColumn(); + ImGui.Text(string.Empty); + ImGui.NextColumn(); + + ImGui.Separator(); + + DevPluginLocationSettings locationToRemove = null; + + var locNumber = 1; + foreach (var devPluginLocationSetting in this.devPluginLocations) + { + var isEnabled = devPluginLocationSetting.IsEnabled; + + ImGui.PushID($"devPluginLocation_{devPluginLocationSetting.Path}"); + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(repoNumber.ToString()).X / 2)); + ImGui.Text(locNumber.ToString()); + ImGui.NextColumn(); + + ImGui.TextWrapped(devPluginLocationSetting.Path); + ImGui.NextColumn(); + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 7 - (12 * ImGuiHelpers.GlobalScale)); + ImGui.Checkbox("##devPluginLocationCheck", ref isEnabled); + ImGui.NextColumn(); + + if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) + { + locationToRemove = devPluginLocationSetting; + } + + ImGui.NextColumn(); + ImGui.Separator(); + + devPluginLocationSetting.IsEnabled = isEnabled; + + locNumber++; + } + + if (locationToRemove != null) + { + this.devPluginLocations.Remove(locationToRemove); + this.devPluginLocationsChanged = true; + } + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(locNumber.ToString()).X / 2)); + ImGui.Text(locNumber.ToString()); + ImGui.NextColumn(); + ImGui.SetNextItemWidth(-1); + ImGui.InputText("##devPluginLocationInput", ref this.devPluginTempLocation, 300); + ImGui.NextColumn(); + // Enabled button + ImGui.NextColumn(); + if (!string.IsNullOrEmpty(this.devPluginTempLocation) && ImGuiComponents.IconButton(FontAwesomeIcon.Plus)) + { + if (this.devPluginLocations.Any(r => string.Equals(r.Path, this.devPluginTempLocation, StringComparison.InvariantCultureIgnoreCase))) + { + this.devPluginLocationAddError = Loc.Localize("DalamudDevPluginLocationExists", "Location already exists."); + Task.Delay(5000).ContinueWith(t => this.devPluginLocationAddError = string.Empty); + } + else + { + this.devPluginLocations.Add(new DevPluginLocationSettings + { + Path = this.devPluginTempLocation, + IsEnabled = true, + }); + this.devPluginLocationsChanged = true; + this.devPluginTempLocation = string.Empty; + } + } + + ImGui.Columns(1); + + ImGui.EndTabItem(); + + if (!string.IsNullOrEmpty(this.devPluginLocationAddError)) + { + ImGui.TextColored(new Vector4(1, 0, 0, 1), this.devPluginLocationAddError); + } + + #endregion + + ImGuiHelpers.ScaledDummy(12); } ImGui.EndTabBar(); @@ -384,20 +508,18 @@ namespace Dalamud.Interface.Internal.Windows ImGui.EndChild(); - if (ImGui.Button(Loc.Localize("Save", "Save"))) - { - this.Save(); + var buttonSave = false; + var buttonClose = false; - if (this.thirdRepoListChanged) - { - this.dalamud.PluginManager.SetPluginReposFromConfig(true); - this.thirdRepoListChanged = false; - } - } + if (ImGui.Button(Loc.Localize("Save", "Save"))) + buttonSave = true; ImGui.SameLine(); if (ImGui.Button(Loc.Localize("SaveAndClose", "Save and Close"))) + buttonSave = buttonClose = true; + + if (buttonSave) { this.Save(); @@ -407,6 +529,15 @@ namespace Dalamud.Interface.Internal.Windows this.thirdRepoListChanged = false; } + if (this.devPluginLocationsChanged) + { + this.dalamud.PluginManager.ScanDevPlugins(); + this.devPluginLocationsChanged = false; + } + } + + if (buttonClose) + { this.IsOpen = false; } } @@ -456,6 +587,7 @@ namespace Dalamud.Interface.Internal.Windows this.dalamud.Configuration.DoPluginTest = this.doPluginTest; this.dalamud.Configuration.ThirdRepoList = this.thirdRepoList.Select(x => x.Clone()).ToList(); + this.dalamud.Configuration.DevPluginLoadLocations = this.devPluginLocations.Select(x => x.Clone()).ToList(); this.dalamud.Configuration.PrintPluginsWelcomeMsg = this.printPluginsWelcomeMsg; this.dalamud.Configuration.AutoUpdatePlugins = this.autoUpdatePlugins; diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index c060bfcea..cec465f9e 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -186,7 +186,22 @@ namespace Dalamud.Plugin.Internal } // devPlugins are more freeform. Look for any dll and hope to get lucky. - var devDllFiles = this.devPluginDirectory.GetFiles("*.dll", SearchOption.AllDirectories); + var devDllFiles = this.devPluginDirectory.GetFiles("*.dll", SearchOption.AllDirectories).ToList(); + + foreach (var setting in this.dalamud.Configuration.DevPluginLoadLocations) + { + if (!setting.IsEnabled) + continue; + + if (Directory.Exists(setting.Path)) + { + devDllFiles.AddRange(new DirectoryInfo(setting.Path).GetFiles("*.dll", SearchOption.AllDirectories)); + } + else if (File.Exists(setting.Path)) + { + devDllFiles.Add(new FileInfo(setting.Path)); + } + } foreach (var dllFile in devDllFiles) { @@ -299,7 +314,22 @@ namespace Dalamud.Plugin.Internal this.devPluginDirectory.Create(); // devPlugins are more freeform. Look for any dll and hope to get lucky. - var devDllFiles = this.devPluginDirectory.GetFiles("*.dll", SearchOption.AllDirectories); + var devDllFiles = this.devPluginDirectory.GetFiles("*.dll", SearchOption.AllDirectories).ToList(); + + foreach (var setting in this.dalamud.Configuration.DevPluginLoadLocations) + { + if (!setting.IsEnabled) + continue; + + if (Directory.Exists(setting.Path)) + { + devDllFiles.AddRange(new DirectoryInfo(setting.Path).GetFiles("*.dll", SearchOption.AllDirectories)); + } + else if (File.Exists(setting.Path)) + { + devDllFiles.Add(new FileInfo(setting.Path)); + } + } var listChanged = false; From bc024b17e10fdbd3134575ba3dbc3543f5e661bf Mon Sep 17 00:00:00 2001 From: Raymond Date: Tue, 10 Aug 2021 08:35:21 -0400 Subject: [PATCH 2/3] Fix duplicate imgui ID on plugin control buttons --- .../Internal/Windows/PluginInstallerWindow.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs index b99c1beb9..902976feb 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs @@ -614,7 +614,9 @@ namespace Dalamud.Interface.Internal.Windows label += Locs.PluginTitleMod_TestingVersion; } - if (this.DrawPluginCollapsingHeader(label, manifest, false, false, index)) + ImGui.PushID($"available{index}{manifest.InternalName}"); + + if (ImGui.CollapsingHeader($"{label}###Header")) { ImGuiHelpers.ScaledDummy(5); @@ -709,6 +711,8 @@ namespace Dalamud.Interface.Internal.Windows ImGui.EndPopup(); } + + ImGui.PopID(); } private void DrawInstalledPlugin(LocalPlugin plugin, int index, bool showInstalled = false) @@ -782,7 +786,9 @@ namespace Dalamud.Interface.Internal.Windows trouble = true; } - if (this.DrawPluginCollapsingHeader(label, plugin.Manifest, trouble, availablePluginUpdate != default, index)) + ImGui.PushID($"installed{index}{plugin.Manifest.InternalName}"); + + if (ImGui.CollapsingHeader($"{label}###Header")) { var manifest = plugin.Manifest; @@ -880,6 +886,8 @@ namespace Dalamud.Interface.Internal.Windows ImGui.EndPopup(); } + + ImGui.PopID(); } private void DrawPluginControlButton(LocalPlugin plugin) From 090c4fcc116e35c719c6bf0c0556575b7d6a5b4a Mon Sep 17 00:00:00 2001 From: Raymond Date: Tue, 10 Aug 2021 08:36:51 -0400 Subject: [PATCH 3/3] feat: Show devPlugin file location in plugin window --- .../Internal/Windows/PluginInstallerWindow.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs index 902976feb..edd4e1791 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs @@ -798,7 +798,9 @@ namespace Dalamud.Interface.Internal.Windows ImGui.Text(manifest.Name); // Download count - var downloadText = manifest.DownloadCount > 0 + var downloadText = plugin.IsDev + ? Locs.PluginBody_AuthorWithoutDownloadCount(manifest.Author) + : manifest.DownloadCount > 0 ? Locs.PluginBody_AuthorWithDownloadCount(manifest.Author, manifest.DownloadCount) : Locs.PluginBody_AuthorWithDownloadCountUnavailable(manifest.Author); @@ -806,12 +808,15 @@ namespace Dalamud.Interface.Internal.Windows ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadText); // Installed from - if (!string.IsNullOrEmpty(manifest.InstalledFromUrl)) + if (plugin.IsDev) + { + var fileText = Locs.PluginBody_DevPluginPath(plugin.DllFile.FullName); + ImGui.TextColored(ImGuiColors.DalamudGrey3, fileText); + } + else if (!string.IsNullOrEmpty(manifest.InstalledFromUrl)) { var repoText = Locs.PluginBody_Plugin3rdPartyRepo(manifest.InstalledFromUrl); ImGui.TextColored(ImGuiColors.DalamudGrey3, repoText); - - ImGuiHelpers.ScaledDummy(2); } // Description @@ -1502,10 +1507,14 @@ namespace Dalamud.Interface.Internal.Windows #region Plugin body + public static string PluginBody_AuthorWithoutDownloadCount(string author) => Loc.Localize("InstallerAuthorWithoutDownloadCount", " by {0}").Format(author); + public static string PluginBody_AuthorWithDownloadCount(string author, long count) => Loc.Localize("InstallerAuthorWithDownloadCount", " by {0}, {1} downloads").Format(author, count); public static string PluginBody_AuthorWithDownloadCountUnavailable(string author) => Loc.Localize("InstallerAuthorWithDownloadCountUnavailable", " by {0}, download count unavailable").Format(author); + public static string PluginBody_DevPluginPath(string path) => Loc.Localize("InstallerDevPluginPath", "From {0}").Format(path); + public static string PluginBody_Plugin3rdPartyRepo(string url) => Loc.Localize("InstallerPlugin3rdPartyRepo", "From custom plugin repository {0}").Format(url); public static string PluginBody_AvailableDevPlugin => Loc.Localize("InstallerDevPlugin", " This plugin is available in one of your repos, please remove it from the devPlugins folder.");