diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs
index 5d250a533..7af530ee9 100644
--- a/Dalamud/Plugin/Internal/PluginManager.cs
+++ b/Dalamud/Plugin/Internal/PluginManager.cs
@@ -664,6 +664,15 @@ internal partial class PluginManager : IDisposable, IServiceType
this.PluginsReady = true;
this.NotifyinstalledPluginsListChanged();
sigScanner.Save();
+
+ try
+ {
+ this.ParanoiaValidatePluginsAndProfiles();
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, "Plugin and profile validation failed!");
+ }
},
tokenSource.Token);
}
@@ -1256,6 +1265,30 @@ internal partial class PluginManager : IDisposable, IServiceType
}
}
+ ///
+ /// Check if there are any inconsistencies with our plugins, their IDs, and our profiles.
+ ///
+ private void ParanoiaValidatePluginsAndProfiles()
+ {
+ var seenIds = new List();
+
+ foreach (var installedPlugin in this.InstalledPlugins)
+ {
+ if (installedPlugin.Manifest.WorkingPluginId == Guid.Empty)
+ throw new Exception($"{(installedPlugin is LocalDevPlugin ? "DevPlugin" : "Plugin")} '{installedPlugin.Manifest.InternalName}' has an empty WorkingPluginId.");
+
+ if (seenIds.Contains(installedPlugin.Manifest.WorkingPluginId))
+ {
+ throw new Exception(
+ $"{(installedPlugin is LocalDevPlugin ? "DevPlugin" : "Plugin")} '{installedPlugin.Manifest.InternalName}' has a duplicate WorkingPluginId '{installedPlugin.Manifest.WorkingPluginId}'");
+ }
+
+ seenIds.Add(installedPlugin.Manifest.WorkingPluginId);
+ }
+
+ this.profileManager.ParanoiaValidateProfiles();
+ }
+
private async Task DownloadPluginAsync(RemotePluginManifest repoManifest, bool useTesting)
{
var downloadUrl = useTesting ? repoManifest.DownloadLinkTesting : repoManifest.DownloadLinkInstall;
diff --git a/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs b/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs
index 6b51f7535..768583bea 100644
--- a/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs
+++ b/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs
@@ -216,19 +216,18 @@ internal class ProfileManager : IServiceType
this.isBusy = true;
Log.Information("Getting want states...");
- List wantActive;
+ List wantActive;
lock (this.profiles)
{
wantActive = this.profiles
.Where(x => x.IsEnabled)
- .SelectMany(profile => profile.Plugins.Where(plugin => plugin.IsEnabled)
- .Select(plugin => plugin.WorkingPluginId))
+ .SelectMany(profile => profile.Plugins.Where(plugin => plugin.IsEnabled))
.Distinct().ToList();
}
- foreach (var internalName in wantActive)
+ foreach (var profilePluginEntry in wantActive)
{
- Log.Information("\t=> Want {Name}", internalName);
+ Log.Information("\t=> Want {Name}({WorkingPluginId})", profilePluginEntry.InternalName, profilePluginEntry.WorkingPluginId);
}
Log.Information("Applying want states...");
@@ -238,7 +237,7 @@ internal class ProfileManager : IServiceType
var pm = Service.Get();
foreach (var installedPlugin in pm.InstalledPlugins)
{
- var wantThis = wantActive.Contains(installedPlugin.Manifest.WorkingPluginId);
+ var wantThis = wantActive.Any(x => x.WorkingPluginId == installedPlugin.Manifest.WorkingPluginId);
switch (wantThis)
{
case true when !installedPlugin.IsLoaded:
@@ -314,6 +313,26 @@ internal class ProfileManager : IServiceType
profile.MigrateProfilesToGuidsForPlugin(internalName, newGuid);
}
}
+
+ ///
+ /// Validate profiles for errors.
+ ///
+ /// Thrown when a profile is not sane.
+ public void ParanoiaValidateProfiles()
+ {
+ foreach (var profile in this.profiles)
+ {
+ var seenIds = new List();
+
+ foreach (var pluginEntry in profile.Plugins)
+ {
+ if (seenIds.Contains(pluginEntry.WorkingPluginId))
+ throw new Exception($"Plugin '{pluginEntry.WorkingPluginId}'('{pluginEntry.InternalName}') is twice in profile '{profile.Guid}'('{profile.Name}')");
+
+ seenIds.Add(pluginEntry.WorkingPluginId);
+ }
+ }
+ }
private string GenerateUniqueProfileName(string startingWith)
{