diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
index 05376a770..f21925b5a 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
@@ -2186,6 +2186,14 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGuiHelpers.SafeTextWrapped(manifest.Description);
}
+ // Working Plugin ID
+ if (this.hasDevPlugins)
+ {
+ ImGuiHelpers.ScaledDummy(3);
+ ImGui.TextColored(ImGuiColors.DalamudGrey, $"WorkingPluginId: {manifest.WorkingPluginId}");
+ ImGuiHelpers.ScaledDummy(3);
+ }
+
// Available commands (if loaded)
if (plugin.IsLoaded)
{
diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs
index c98a6bbfc..58e122c3e 100644
--- a/Dalamud/Plugin/Internal/PluginManager.cs
+++ b/Dalamud/Plugin/Internal/PluginManager.cs
@@ -763,8 +763,9 @@ internal partial class PluginManager : IDisposable, IServiceType
/// The plugin definition.
/// If the testing version should be used.
/// The reason this plugin was loaded.
+ /// WorkingPluginId this plugin should inherit.
/// A representing the asynchronous operation.
- public async Task InstallPluginAsync(RemotePluginManifest repoManifest, bool useTesting, PluginLoadReason reason)
+ public async Task InstallPluginAsync(RemotePluginManifest repoManifest, bool useTesting, PluginLoadReason reason, Guid? inheritedWorkingPluginId = null)
{
Log.Debug($"Installing plugin {repoManifest.Name} (testing={useTesting})");
@@ -851,6 +852,9 @@ internal partial class PluginManager : IDisposable, IServiceType
// Reload as a local manifest, add some attributes, and save again.
var manifest = LocalPluginManifest.Load(manifestFile);
+ if (manifest == null)
+ throw new Exception("Plugin had no valid manifest");
+
if (manifest.InternalName != repoManifest.InternalName)
{
Directory.Delete(outputDir.FullName, true);
@@ -858,6 +862,11 @@ internal partial class PluginManager : IDisposable, IServiceType
$"Distributed internal name does not match repo internal name: {manifest.InternalName} - {repoManifest.InternalName}");
}
+ if (manifest.WorkingPluginId != Guid.Empty)
+ throw new Exception("Plugin shall not specify a WorkingPluginId");
+
+ manifest.WorkingPluginId = inheritedWorkingPluginId ?? Guid.NewGuid();
+
if (useTesting)
{
manifest.Testing = true;
@@ -1040,6 +1049,10 @@ internal partial class PluginManager : IDisposable, IServiceType
{
var plugin = metadata.InstalledPlugin;
+ var workingPluginId = metadata.InstalledPlugin.Manifest.WorkingPluginId;
+ if (workingPluginId == Guid.Empty)
+ throw new Exception("Existing plugin had no WorkingPluginId");
+
var updateStatus = new PluginUpdateStatus
{
InternalName = plugin.Manifest.InternalName,
@@ -1099,7 +1112,7 @@ internal partial class PluginManager : IDisposable, IServiceType
try
{
- await this.InstallPluginAsync(metadata.UpdateManifest, metadata.UseTesting, PluginLoadReason.Update);
+ await this.InstallPluginAsync(metadata.UpdateManifest, metadata.UseTesting, PluginLoadReason.Update, workingPluginId);
}
catch (Exception ex)
{
diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
index 5ad09ebc3..115ab0f8d 100644
--- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
+++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
@@ -158,6 +158,14 @@ internal class LocalPlugin : IDisposable
needsSaveDueToLegacyFiles = true;
}
+ // Create an installation instance ID for this plugin, if it doesn't have one yet
+ if (this.manifest.WorkingPluginId == Guid.Empty)
+ {
+ this.manifest.WorkingPluginId = Guid.NewGuid();
+
+ needsSaveDueToLegacyFiles = true;
+ }
+
var pluginManager = Service.Get();
this.IsBanned = pluginManager.IsManifestBanned(this.manifest) && !this.IsDev;
this.BanReason = pluginManager.GetBanReason(this.manifest);
diff --git a/Dalamud/Plugin/Internal/Types/Manifest/ILocalPluginManifest.cs b/Dalamud/Plugin/Internal/Types/Manifest/ILocalPluginManifest.cs
index 97365d1e5..5b147dde1 100644
--- a/Dalamud/Plugin/Internal/Types/Manifest/ILocalPluginManifest.cs
+++ b/Dalamud/Plugin/Internal/Types/Manifest/ILocalPluginManifest.cs
@@ -1,4 +1,6 @@
-namespace Dalamud.Plugin.Internal.Types.Manifest;
+using System;
+
+namespace Dalamud.Plugin.Internal.Types.Manifest;
///
/// Public interface for the local plugin manifest.
@@ -16,4 +18,9 @@ public interface ILocalPluginManifest : IPluginManifest
/// Gets a value indicating whether the plugin should be deleted during the next cleanup.
///
public bool ScheduledForDeletion { get; }
+
+ ///
+ /// Gets an ID uniquely identifying this specific installation of a plugin.
+ ///
+ public Guid WorkingPluginId { get; }
}
diff --git a/Dalamud/Plugin/Internal/Types/Manifest/LocalPluginManifest.cs b/Dalamud/Plugin/Internal/Types/Manifest/LocalPluginManifest.cs
index 4b4bf5d6e..8afbe1aea 100644
--- a/Dalamud/Plugin/Internal/Types/Manifest/LocalPluginManifest.cs
+++ b/Dalamud/Plugin/Internal/Types/Manifest/LocalPluginManifest.cs
@@ -44,6 +44,9 @@ internal record LocalPluginManifest : PluginManifest, ILocalPluginManifest
///
public string InstalledFromUrl { get; set; } = string.Empty;
+ ///
+ public Guid WorkingPluginId { get; set; } = Guid.Empty;
+
///
/// Gets a value indicating whether this manifest is associated with a plugin that was installed from a third party
/// repo. Unless the manifest has been manually modified, this is determined by the InstalledFromUrl being null.