mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-15 05:04:15 +01:00
merge
This commit is contained in:
commit
b446fcc191
10 changed files with 223 additions and 100 deletions
|
|
@ -2528,10 +2528,10 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
|
|
||||||
var applicableForProfiles = plugin.Manifest.SupportsProfiles && !plugin.IsDev;
|
var applicableForProfiles = plugin.Manifest.SupportsProfiles && !plugin.IsDev;
|
||||||
var profilesThatWantThisPlugin = profileManager.Profiles
|
var profilesThatWantThisPlugin = profileManager.Profiles
|
||||||
.Where(x => x.WantsPlugin(plugin.InternalName) != null)
|
.Where(x => x.WantsPlugin(plugin.Manifest.WorkingPluginId) != null)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
var isInSingleProfile = profilesThatWantThisPlugin.Length == 1;
|
var isInSingleProfile = profilesThatWantThisPlugin.Length == 1;
|
||||||
var isDefaultPlugin = profileManager.IsInDefaultProfile(plugin.Manifest.InternalName);
|
var isDefaultPlugin = profileManager.IsInDefaultProfile(plugin.Manifest.WorkingPluginId);
|
||||||
|
|
||||||
// Disable everything if the updater is running or another plugin is operating
|
// Disable everything if the updater is running or another plugin is operating
|
||||||
var disabled = this.updateStatus == OperationStatus.InProgress || this.installStatus == OperationStatus.InProgress;
|
var disabled = this.updateStatus == OperationStatus.InProgress || this.installStatus == OperationStatus.InProgress;
|
||||||
|
|
@ -2566,17 +2566,17 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
|
|
||||||
foreach (var profile in profileManager.Profiles.Where(x => !x.IsDefaultProfile))
|
foreach (var profile in profileManager.Profiles.Where(x => !x.IsDefaultProfile))
|
||||||
{
|
{
|
||||||
var inProfile = profile.WantsPlugin(plugin.Manifest.InternalName) != null;
|
var inProfile = profile.WantsPlugin(plugin.Manifest.WorkingPluginId) != null;
|
||||||
if (ImGui.Checkbox($"###profilePick{profile.Guid}{plugin.Manifest.InternalName}", ref inProfile))
|
if (ImGui.Checkbox($"###profilePick{profile.Guid}{plugin.Manifest.InternalName}", ref inProfile))
|
||||||
{
|
{
|
||||||
if (inProfile)
|
if (inProfile)
|
||||||
{
|
{
|
||||||
Task.Run(() => profile.AddOrUpdateAsync(plugin.Manifest.InternalName, true))
|
Task.Run(() => profile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, true))
|
||||||
.ContinueWith(this.DisplayErrorContinuation, Locs.Profiles_CouldNotAdd);
|
.ContinueWith(this.DisplayErrorContinuation, Locs.Profiles_CouldNotAdd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Task.Run(() => profile.RemoveAsync(plugin.Manifest.InternalName))
|
Task.Run(() => profile.RemoveAsync(plugin.Manifest.WorkingPluginId))
|
||||||
.ContinueWith(this.DisplayErrorContinuation, Locs.Profiles_CouldNotRemove);
|
.ContinueWith(this.DisplayErrorContinuation, Locs.Profiles_CouldNotRemove);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2596,11 +2596,11 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Times))
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.Times))
|
||||||
{
|
{
|
||||||
// TODO: Work this out
|
// TODO: Work this out
|
||||||
Task.Run(() => profileManager.DefaultProfile.AddOrUpdateAsync(plugin.Manifest.InternalName, plugin.IsLoaded, false))
|
Task.Run(() => profileManager.DefaultProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, plugin.IsLoaded, false))
|
||||||
.GetAwaiter().GetResult();
|
.GetAwaiter().GetResult();
|
||||||
foreach (var profile in profileManager.Profiles.Where(x => !x.IsDefaultProfile && x.Plugins.Any(y => y.InternalName == plugin.Manifest.InternalName)))
|
foreach (var profile in profileManager.Profiles.Where(x => !x.IsDefaultProfile && x.Plugins.Any(y => y.InternalName == plugin.Manifest.InternalName)))
|
||||||
{
|
{
|
||||||
Task.Run(() => profile.RemoveAsync(plugin.Manifest.InternalName, false))
|
Task.Run(() => profile.RemoveAsync(plugin.Manifest.WorkingPluginId, false))
|
||||||
.GetAwaiter().GetResult();
|
.GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2674,7 +2674,7 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
{
|
{
|
||||||
await plugin.UnloadAsync();
|
await plugin.UnloadAsync();
|
||||||
await applicableProfile.AddOrUpdateAsync(
|
await applicableProfile.AddOrUpdateAsync(
|
||||||
plugin.Manifest.InternalName, false, false);
|
plugin.Manifest.WorkingPluginId, false, false);
|
||||||
|
|
||||||
notifications.AddNotification(Locs.Notifications_PluginDisabled(plugin.Manifest.Name), Locs.Notifications_PluginDisabledTitle, NotificationType.Success);
|
notifications.AddNotification(Locs.Notifications_PluginDisabled(plugin.Manifest.Name), Locs.Notifications_PluginDisabledTitle, NotificationType.Success);
|
||||||
}).ContinueWith(t =>
|
}).ContinueWith(t =>
|
||||||
|
|
@ -2691,7 +2691,7 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
this.loadingIndicatorKind = LoadingIndicatorKind.EnablingSingle;
|
this.loadingIndicatorKind = LoadingIndicatorKind.EnablingSingle;
|
||||||
this.enableDisableWorkingPluginId = plugin.Manifest.WorkingPluginId;
|
this.enableDisableWorkingPluginId = plugin.Manifest.WorkingPluginId;
|
||||||
|
|
||||||
await applicableProfile.AddOrUpdateAsync(plugin.Manifest.InternalName, true, false);
|
await applicableProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, true, false);
|
||||||
await plugin.LoadAsync(PluginLoadReason.Installer);
|
await plugin.LoadAsync(PluginLoadReason.Installer);
|
||||||
|
|
||||||
notifications.AddNotification(Locs.Notifications_PluginEnabled(plugin.Manifest.Name), Locs.Notifications_PluginEnabledTitle, NotificationType.Success);
|
notifications.AddNotification(Locs.Notifications_PluginEnabled(plugin.Manifest.Name), Locs.Notifications_PluginEnabledTitle, NotificationType.Success);
|
||||||
|
|
@ -2712,7 +2712,7 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
if (shouldUpdate)
|
if (shouldUpdate)
|
||||||
{
|
{
|
||||||
// We need to update the profile right here, because PM will not enable the plugin otherwise
|
// We need to update the profile right here, because PM will not enable the plugin otherwise
|
||||||
await applicableProfile.AddOrUpdateAsync(plugin.InternalName, true, false);
|
await applicableProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, true, false);
|
||||||
await this.UpdateSinglePlugin(availableUpdate);
|
await this.UpdateSinglePlugin(availableUpdate);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -2893,7 +2893,7 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
if (localPlugin is LocalDevPlugin plugin)
|
if (localPlugin is LocalDevPlugin plugin)
|
||||||
{
|
{
|
||||||
var isInDefaultProfile =
|
var isInDefaultProfile =
|
||||||
Service<ProfileManager>.Get().IsInDefaultProfile(localPlugin.Manifest.InternalName);
|
Service<ProfileManager>.Get().IsInDefaultProfile(localPlugin.Manifest.WorkingPluginId);
|
||||||
|
|
||||||
// https://colorswall.com/palette/2868/
|
// https://colorswall.com/palette/2868/
|
||||||
var greenColor = new Vector4(0x5C, 0xB8, 0x5C, 0xFF) / 0xFF;
|
var greenColor = new Vector4(0x5C, 0xB8, 0x5C, 0xFF) / 0xFF;
|
||||||
|
|
@ -3237,7 +3237,7 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
this.pluginListAvailable.Sort((p1, p2) => p1.Name.CompareTo(p2.Name));
|
this.pluginListAvailable.Sort((p1, p2) => p1.Name.CompareTo(p2.Name));
|
||||||
|
|
||||||
var profman = Service<ProfileManager>.Get();
|
var profman = Service<ProfileManager>.Get();
|
||||||
this.pluginListInstalled.Sort((p1, p2) => profman.IsInDefaultProfile(p1.InternalName).CompareTo(profman.IsInDefaultProfile(p2.InternalName)));
|
this.pluginListInstalled.Sort((p1, p2) => profman.IsInDefaultProfile(p1.Manifest.WorkingPluginId).CompareTo(profman.IsInDefaultProfile(p2.Manifest.WorkingPluginId)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new InvalidEnumArgumentException("Unknown plugin sort type.");
|
throw new InvalidEnumArgumentException("Unknown plugin sort type.");
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@ internal class ProfileManagerWidget
|
||||||
|
|
||||||
if (ImGuiComponents.IconButton($"###exportButton{profile.Guid}", FontAwesomeIcon.FileExport))
|
if (ImGuiComponents.IconButton($"###exportButton{profile.Guid}", FontAwesomeIcon.FileExport))
|
||||||
{
|
{
|
||||||
ImGui.SetClipboardText(profile.Model.Serialize());
|
ImGui.SetClipboardText(profile.Model.SerializeForShare());
|
||||||
Service<NotificationManager>.Get().AddNotification(Locs.CopyToClipboardNotification, type: NotificationType.Success);
|
Service<NotificationManager>.Get().AddNotification(Locs.CopyToClipboardNotification, type: NotificationType.Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -323,7 +323,7 @@ internal class ProfileManagerWidget
|
||||||
|
|
||||||
if (ImGui.Selectable($"{plugin.Manifest.Name}###selector{plugin.Manifest.InternalName}"))
|
if (ImGui.Selectable($"{plugin.Manifest.Name}###selector{plugin.Manifest.InternalName}"))
|
||||||
{
|
{
|
||||||
Task.Run(() => profile.AddOrUpdateAsync(plugin.Manifest.InternalName, true, false))
|
Task.Run(() => profile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, true, false))
|
||||||
.ContinueWith(this.installer.DisplayErrorContinuation, Locs.ErrorCouldNotChangeState);
|
.ContinueWith(this.installer.DisplayErrorContinuation, Locs.ErrorCouldNotChangeState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -350,7 +350,7 @@ internal class ProfileManagerWidget
|
||||||
|
|
||||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.FileExport))
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.FileExport))
|
||||||
{
|
{
|
||||||
ImGui.SetClipboardText(profile.Model.Serialize());
|
ImGui.SetClipboardText(profile.Model.SerializeForShare());
|
||||||
Service<NotificationManager>.Get().AddNotification(Locs.CopyToClipboardNotification, type: NotificationType.Success);
|
Service<NotificationManager>.Get().AddNotification(Locs.CopyToClipboardNotification, type: NotificationType.Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -423,13 +423,13 @@ internal class ProfileManagerWidget
|
||||||
if (pluginListChild)
|
if (pluginListChild)
|
||||||
{
|
{
|
||||||
var pluginLineHeight = 32 * ImGuiHelpers.GlobalScale;
|
var pluginLineHeight = 32 * ImGuiHelpers.GlobalScale;
|
||||||
string? wantRemovePluginInternalName = null;
|
Guid? wantRemovePluginGuid = null;
|
||||||
|
|
||||||
using var syncScope = profile.GetSyncScope();
|
using var syncScope = profile.GetSyncScope();
|
||||||
foreach (var plugin in profile.Plugins.ToArray())
|
foreach (var plugin in profile.Plugins.ToArray())
|
||||||
{
|
{
|
||||||
didAny = true;
|
didAny = true;
|
||||||
var pmPlugin = pm.InstalledPlugins.FirstOrDefault(x => x.Manifest.InternalName == plugin.InternalName);
|
var pmPlugin = pm.InstalledPlugins.FirstOrDefault(x => x.Manifest.WorkingPluginId == plugin.WorkingPluginId);
|
||||||
var btnOffset = 2;
|
var btnOffset = 2;
|
||||||
|
|
||||||
if (pmPlugin != null)
|
if (pmPlugin != null)
|
||||||
|
|
@ -460,26 +460,33 @@ internal class ProfileManagerWidget
|
||||||
|
|
||||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (pluginLineHeight / 2) - (textHeight.Y / 2));
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (pluginLineHeight / 2) - (textHeight.Y / 2));
|
||||||
ImGui.TextUnformatted(text);
|
ImGui.TextUnformatted(text);
|
||||||
|
|
||||||
var available =
|
var firstAvailableInstalled = pm.InstalledPlugins.FirstOrDefault(x => x.InternalName == plugin.InternalName);
|
||||||
|
var installable =
|
||||||
pm.AvailablePlugins.FirstOrDefault(
|
pm.AvailablePlugins.FirstOrDefault(
|
||||||
x => x.InternalName == plugin.InternalName && !x.SourceRepo.IsThirdParty);
|
x => x.InternalName == plugin.InternalName && !x.SourceRepo.IsThirdParty);
|
||||||
if (available != null)
|
|
||||||
|
if (firstAvailableInstalled != null)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
ImGui.Text("GOAT WAS TOO LAZY TO IMPLEMENT THIS");
|
||||||
|
}
|
||||||
|
else if (installable != null)
|
||||||
{
|
{
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.SetCursorPosX(windowSize.X - (ImGuiHelpers.GlobalScale * 30 * 2) - 2);
|
ImGui.SetCursorPosX(windowSize.X - (ImGuiHelpers.GlobalScale * 30 * 2) - 2);
|
||||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (pluginLineHeight / 2) - (ImGui.GetFrameHeight() / 2));
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (pluginLineHeight / 2) - (ImGui.GetFrameHeight() / 2));
|
||||||
btnOffset = 3;
|
btnOffset = 3;
|
||||||
|
|
||||||
if (ImGuiComponents.IconButton($"###installMissingPlugin{available.InternalName}", FontAwesomeIcon.Download))
|
if (ImGuiComponents.IconButton($"###installMissingPlugin{installable.InternalName}", FontAwesomeIcon.Download))
|
||||||
{
|
{
|
||||||
this.installer.StartInstall(available, false);
|
this.installer.StartInstall(installable, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui.IsItemHovered())
|
if (ImGui.IsItemHovered())
|
||||||
ImGui.SetTooltip(Locs.InstallPlugin);
|
ImGui.SetTooltip(Locs.InstallPlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SetCursorPos(before);
|
ImGui.SetCursorPos(before);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -490,7 +497,7 @@ internal class ProfileManagerWidget
|
||||||
var enabled = plugin.IsEnabled;
|
var enabled = plugin.IsEnabled;
|
||||||
if (ImGui.Checkbox($"###{this.editingProfileGuid}-{plugin.InternalName}", ref enabled))
|
if (ImGui.Checkbox($"###{this.editingProfileGuid}-{plugin.InternalName}", ref enabled))
|
||||||
{
|
{
|
||||||
Task.Run(() => profile.AddOrUpdateAsync(plugin.InternalName, enabled))
|
Task.Run(() => profile.AddOrUpdateAsync(plugin.WorkingPluginId, enabled))
|
||||||
.ContinueWith(this.installer.DisplayErrorContinuation, Locs.ErrorCouldNotChangeState);
|
.ContinueWith(this.installer.DisplayErrorContinuation, Locs.ErrorCouldNotChangeState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -500,17 +507,17 @@ internal class ProfileManagerWidget
|
||||||
|
|
||||||
if (ImGuiComponents.IconButton($"###removePlugin{plugin.InternalName}", FontAwesomeIcon.Trash))
|
if (ImGuiComponents.IconButton($"###removePlugin{plugin.InternalName}", FontAwesomeIcon.Trash))
|
||||||
{
|
{
|
||||||
wantRemovePluginInternalName = plugin.InternalName;
|
wantRemovePluginGuid = plugin.WorkingPluginId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui.IsItemHovered())
|
if (ImGui.IsItemHovered())
|
||||||
ImGui.SetTooltip(Locs.RemovePlugin);
|
ImGui.SetTooltip(Locs.RemovePlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wantRemovePluginInternalName != null)
|
if (wantRemovePluginGuid != null)
|
||||||
{
|
{
|
||||||
// TODO: handle error
|
// TODO: handle error
|
||||||
Task.Run(() => profile.RemoveAsync(wantRemovePluginInternalName, false))
|
Task.Run(() => profile.RemoveAsync(wantRemovePluginGuid.Value, false))
|
||||||
.ContinueWith(this.installer.DisplayErrorContinuation, Locs.ErrorCouldNotRemove);
|
.ContinueWith(this.installer.DisplayErrorContinuation, Locs.ErrorCouldNotRemove);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Verbose(string messageTemplate, params object[] values)
|
public void Verbose(string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Verbose, messageTemplate, null, values);
|
=> this.WriteLog(LogEventLevel.Verbose, messageTemplate, null, values);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -43,7 +43,7 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Verbose(Exception exception, string messageTemplate, params object[] values)
|
public void Verbose(Exception exception, string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Verbose, messageTemplate, exception, values);
|
=> this.WriteLog(LogEventLevel.Verbose, messageTemplate, exception, values);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -52,7 +52,7 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Debug(string messageTemplate, params object[] values)
|
public void Debug(string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Debug, messageTemplate, null, values);
|
=> this.WriteLog(LogEventLevel.Debug, messageTemplate, null, values);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -62,7 +62,7 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Debug(Exception exception, string messageTemplate, params object[] values)
|
public void Debug(Exception exception, string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Debug, messageTemplate, exception, values);
|
=> this.WriteLog(LogEventLevel.Debug, messageTemplate, exception, values);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -71,7 +71,7 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Information(string messageTemplate, params object[] values)
|
public void Information(string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Information, messageTemplate, null, values);
|
=> this.WriteLog(LogEventLevel.Information, messageTemplate, null, values);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -81,7 +81,7 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Information(Exception exception, string messageTemplate, params object[] values)
|
public void Information(Exception exception, string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Information, messageTemplate, exception, values);
|
=> this.WriteLog(LogEventLevel.Information, messageTemplate, exception, values);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -90,7 +90,7 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Warning(string messageTemplate, params object[] values)
|
public void Warning(string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Warning, messageTemplate, null, values);
|
=> this.WriteLog(LogEventLevel.Warning, messageTemplate, null, values);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -100,7 +100,7 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Warning(Exception exception, string messageTemplate, params object[] values)
|
public void Warning(Exception exception, string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Warning, messageTemplate, exception, values);
|
=> this.WriteLog(LogEventLevel.Warning, messageTemplate, exception, values);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -109,7 +109,7 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Error(string messageTemplate, params object[] values)
|
public void Error(string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Error, messageTemplate, null, values);
|
=> this.WriteLog(LogEventLevel.Error, messageTemplate, null, values);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -119,7 +119,7 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Error(Exception? exception, string messageTemplate, params object[] values)
|
public void Error(Exception? exception, string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Error, messageTemplate, exception, values);
|
=> this.WriteLog(LogEventLevel.Error, messageTemplate, exception, values);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -128,7 +128,7 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Fatal(string messageTemplate, params object[] values)
|
public void Fatal(string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Fatal, messageTemplate, null, values);
|
=> this.WriteLog(LogEventLevel.Fatal, messageTemplate, null, values);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -138,12 +138,12 @@ public class ModuleLog
|
||||||
/// <param name="messageTemplate">The message template.</param>
|
/// <param name="messageTemplate">The message template.</param>
|
||||||
/// <param name="values">Values to log.</param>
|
/// <param name="values">Values to log.</param>
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
public void Fatal(Exception exception, string messageTemplate, params object[] values)
|
public void Fatal(Exception exception, string messageTemplate, params object?[] values)
|
||||||
=> this.WriteLog(LogEventLevel.Fatal, messageTemplate, exception, values);
|
=> this.WriteLog(LogEventLevel.Fatal, messageTemplate, exception, values);
|
||||||
|
|
||||||
[MessageTemplateFormatMethod("messageTemplate")]
|
[MessageTemplateFormatMethod("messageTemplate")]
|
||||||
private void WriteLog(
|
private void WriteLog(
|
||||||
LogEventLevel level, string messageTemplate, Exception? exception = null, params object[] values)
|
LogEventLevel level, string messageTemplate, Exception? exception = null, params object?[] values)
|
||||||
{
|
{
|
||||||
// FIXME: Eventually, the `pluginName` tag should be removed from here and moved over to the actual log
|
// FIXME: Eventually, the `pluginName` tag should be removed from here and moved over to the actual log
|
||||||
// formatter.
|
// formatter.
|
||||||
|
|
|
||||||
|
|
@ -1445,13 +1445,30 @@ internal partial class PluginManager : IDisposable, IServiceType
|
||||||
if (isDev)
|
if (isDev)
|
||||||
{
|
{
|
||||||
Log.Information($"Loading dev plugin {name}");
|
Log.Information($"Loading dev plugin {name}");
|
||||||
var devPlugin = new LocalDevPlugin(dllFile, manifest);
|
plugin = new LocalDevPlugin(dllFile, manifest);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Information($"Loading plugin {name}");
|
||||||
|
plugin = new LocalPlugin(dllFile, manifest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform a migration from InternalName to GUIDs. The plugin should definitely have a GUID here.
|
||||||
|
// This will also happen if you are installing a plugin with the installer, and that's intended!
|
||||||
|
// It means that, if you have a profile which has unsatisfied plugins, installing a matching plugin will
|
||||||
|
// enter it into the profiles it can match.
|
||||||
|
if (plugin.Manifest.WorkingPluginId == Guid.Empty)
|
||||||
|
throw new Exception("Plugin should have a WorkingPluginId at this point");
|
||||||
|
this.profileManager.MigrateProfilesToGuidsForPlugin(plugin.Manifest.InternalName, plugin.Manifest.WorkingPluginId);
|
||||||
|
|
||||||
|
// Now, if this is a devPlugin, figure out if we want to load it
|
||||||
|
if (isDev)
|
||||||
|
{
|
||||||
|
var devPlugin = (LocalDevPlugin)plugin;
|
||||||
loadPlugin &= !isBoot;
|
loadPlugin &= !isBoot;
|
||||||
|
|
||||||
var probablyInternalNameForThisPurpose = manifest?.InternalName ?? dllFile.Name;
|
|
||||||
|
|
||||||
var wantsInDefaultProfile =
|
var wantsInDefaultProfile =
|
||||||
this.profileManager.DefaultProfile.WantsPlugin(probablyInternalNameForThisPurpose);
|
this.profileManager.DefaultProfile.WantsPlugin(plugin.Manifest.WorkingPluginId);
|
||||||
if (wantsInDefaultProfile == null)
|
if (wantsInDefaultProfile == null)
|
||||||
{
|
{
|
||||||
// We don't know about this plugin, so we don't want to do anything here.
|
// We don't know about this plugin, so we don't want to do anything here.
|
||||||
|
|
@ -1460,46 +1477,41 @@ internal partial class PluginManager : IDisposable, IServiceType
|
||||||
else if (wantsInDefaultProfile == false && devPlugin.StartOnBoot)
|
else if (wantsInDefaultProfile == false && devPlugin.StartOnBoot)
|
||||||
{
|
{
|
||||||
// We didn't want this plugin, and StartOnBoot is on. That means we don't want it and it should stay off until manually enabled.
|
// We didn't want this plugin, and StartOnBoot is on. That means we don't want it and it should stay off until manually enabled.
|
||||||
Log.Verbose("DevPlugin {Name} disabled and StartOnBoot => disable", probablyInternalNameForThisPurpose);
|
Log.Verbose("DevPlugin {Name} disabled and StartOnBoot => disable", plugin.Manifest.InternalName);
|
||||||
await this.profileManager.DefaultProfile.AddOrUpdateAsync(probablyInternalNameForThisPurpose, false, false);
|
await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, false, false);
|
||||||
loadPlugin = false;
|
loadPlugin = false;
|
||||||
}
|
}
|
||||||
else if (wantsInDefaultProfile == true && devPlugin.StartOnBoot)
|
else if (wantsInDefaultProfile == true && devPlugin.StartOnBoot)
|
||||||
{
|
{
|
||||||
// We wanted this plugin, and StartOnBoot is on. That means we actually do want it.
|
// We wanted this plugin, and StartOnBoot is on. That means we actually do want it.
|
||||||
Log.Verbose("DevPlugin {Name} enabled and StartOnBoot => enable", probablyInternalNameForThisPurpose);
|
Log.Verbose("DevPlugin {Name} enabled and StartOnBoot => enable", plugin.Manifest.InternalName);
|
||||||
await this.profileManager.DefaultProfile.AddOrUpdateAsync(probablyInternalNameForThisPurpose, true, false);
|
await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, true, false);
|
||||||
loadPlugin = !doNotLoad;
|
loadPlugin = !doNotLoad;
|
||||||
}
|
}
|
||||||
else if (wantsInDefaultProfile == true && !devPlugin.StartOnBoot)
|
else if (wantsInDefaultProfile == true && !devPlugin.StartOnBoot)
|
||||||
{
|
{
|
||||||
// We wanted this plugin, but StartOnBoot is off. This means we don't want it anymore.
|
// We wanted this plugin, but StartOnBoot is off. This means we don't want it anymore.
|
||||||
Log.Verbose("DevPlugin {Name} enabled and !StartOnBoot => disable", probablyInternalNameForThisPurpose);
|
Log.Verbose("DevPlugin {Name} enabled and !StartOnBoot => disable", plugin.Manifest.InternalName);
|
||||||
await this.profileManager.DefaultProfile.AddOrUpdateAsync(probablyInternalNameForThisPurpose, false, false);
|
await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, false, false);
|
||||||
loadPlugin = false;
|
loadPlugin = false;
|
||||||
}
|
}
|
||||||
else if (wantsInDefaultProfile == false && !devPlugin.StartOnBoot)
|
else if (wantsInDefaultProfile == false && !devPlugin.StartOnBoot)
|
||||||
{
|
{
|
||||||
// We didn't want this plugin, and StartOnBoot is off. We don't want it.
|
// We didn't want this plugin, and StartOnBoot is off. We don't want it.
|
||||||
Log.Verbose("DevPlugin {Name} disabled and !StartOnBoot => disable", probablyInternalNameForThisPurpose);
|
Log.Verbose("DevPlugin {Name} disabled and !StartOnBoot => disable", plugin.Manifest.InternalName);
|
||||||
await this.profileManager.DefaultProfile.AddOrUpdateAsync(probablyInternalNameForThisPurpose, false, false);
|
await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, false, false);
|
||||||
loadPlugin = false;
|
loadPlugin = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin = devPlugin;
|
plugin = devPlugin;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.Information($"Loading plugin {name}");
|
|
||||||
plugin = new LocalPlugin(dllFile, manifest);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable CS0618
|
#pragma warning disable CS0618
|
||||||
var defaultState = manifest?.Disabled != true && loadPlugin;
|
var defaultState = manifest?.Disabled != true && loadPlugin;
|
||||||
#pragma warning restore CS0618
|
#pragma warning restore CS0618
|
||||||
|
|
||||||
// Need to do this here, so plugins that don't load are still added to the default profile
|
// Need to do this here, so plugins that don't load are still added to the default profile
|
||||||
var wantToLoad = await this.profileManager.GetWantStateAsync(plugin.Manifest.InternalName, defaultState);
|
var wantToLoad = await this.profileManager.GetWantStateAsync(plugin.Manifest.WorkingPluginId, defaultState);
|
||||||
|
|
||||||
if (loadPlugin)
|
if (loadPlugin)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ internal class Profile
|
||||||
/// Gets all plugins declared in this profile.
|
/// Gets all plugins declared in this profile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<ProfilePluginEntry> Plugins =>
|
public IEnumerable<ProfilePluginEntry> Plugins =>
|
||||||
this.modelV1.Plugins.Select(x => new ProfilePluginEntry(x.InternalName, x.IsEnabled));
|
this.modelV1.Plugins.Select(x => new ProfilePluginEntry(x.InternalName, x.WorkingPluginId, x.IsEnabled));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets this profile's underlying model.
|
/// Gets this profile's underlying model.
|
||||||
|
|
@ -142,13 +142,13 @@ internal class Profile
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if this profile contains a specific plugin, and if it is enabled.
|
/// Check if this profile contains a specific plugin, and if it is enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="internalName">The internal name of the plugin.</param>
|
/// <param name="workingPluginId">The ID of the plugin.</param>
|
||||||
/// <returns>Null if this profile does not declare the plugin, true if the profile declares the plugin and wants it enabled, false if the profile declares the plugin and does not want it enabled.</returns>
|
/// <returns>Null if this profile does not declare the plugin, true if the profile declares the plugin and wants it enabled, false if the profile declares the plugin and does not want it enabled.</returns>
|
||||||
public bool? WantsPlugin(string internalName)
|
public bool? WantsPlugin(Guid workingPluginId)
|
||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
var entry = this.modelV1.Plugins.FirstOrDefault(x => x.InternalName == internalName);
|
var entry = this.modelV1.Plugins.FirstOrDefault(x => x.WorkingPluginId == workingPluginId);
|
||||||
return entry?.IsEnabled;
|
return entry?.IsEnabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -157,17 +157,17 @@ internal class Profile
|
||||||
/// Add a plugin to this profile with the desired state, or change the state of a plugin in this profile.
|
/// Add a plugin to this profile with the desired state, or change the state of a plugin in this profile.
|
||||||
/// This will block until all states have been applied.
|
/// This will block until all states have been applied.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="internalName">The internal name of the plugin.</param>
|
/// <param name="workingPluginId">The ID of the plugin.</param>
|
||||||
/// <param name="state">Whether or not the plugin should be enabled.</param>
|
/// <param name="state">Whether or not the plugin should be enabled.</param>
|
||||||
/// <param name="apply">Whether or not the current state should immediately be applied.</param>
|
/// <param name="apply">Whether or not the current state should immediately be applied.</param>
|
||||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||||
public async Task AddOrUpdateAsync(string internalName, bool state, bool apply = true)
|
public async Task AddOrUpdateAsync(Guid workingPluginId, bool state, bool apply = true)
|
||||||
{
|
{
|
||||||
Debug.Assert(!internalName.IsNullOrEmpty(), "!internalName.IsNullOrEmpty()");
|
Debug.Assert(workingPluginId != Guid.Empty, "Trying to add plugin with empty guid");
|
||||||
|
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
var existing = this.modelV1.Plugins.FirstOrDefault(x => x.InternalName == internalName);
|
var existing = this.modelV1.Plugins.FirstOrDefault(x => x.WorkingPluginId == workingPluginId);
|
||||||
if (existing != null)
|
if (existing != null)
|
||||||
{
|
{
|
||||||
existing.IsEnabled = state;
|
existing.IsEnabled = state;
|
||||||
|
|
@ -176,16 +176,16 @@ internal class Profile
|
||||||
{
|
{
|
||||||
this.modelV1.Plugins.Add(new ProfileModelV1.ProfileModelV1Plugin
|
this.modelV1.Plugins.Add(new ProfileModelV1.ProfileModelV1Plugin
|
||||||
{
|
{
|
||||||
InternalName = internalName,
|
WorkingPluginId = workingPluginId,
|
||||||
IsEnabled = state,
|
IsEnabled = state,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to remove this plugin from the default profile, if it declares it.
|
// We need to remove this plugin from the default profile, if it declares it.
|
||||||
if (!this.IsDefaultProfile && this.manager.DefaultProfile.WantsPlugin(internalName) != null)
|
if (!this.IsDefaultProfile && this.manager.DefaultProfile.WantsPlugin(workingPluginId) != null)
|
||||||
{
|
{
|
||||||
await this.manager.DefaultProfile.RemoveAsync(internalName, false);
|
await this.manager.DefaultProfile.RemoveAsync(workingPluginId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Service<DalamudConfiguration>.Get().QueueSave();
|
Service<DalamudConfiguration>.Get().QueueSave();
|
||||||
|
|
@ -198,32 +198,32 @@ internal class Profile
|
||||||
/// Remove a plugin from this profile.
|
/// Remove a plugin from this profile.
|
||||||
/// This will block until all states have been applied.
|
/// This will block until all states have been applied.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="internalName">The internal name of the plugin.</param>
|
/// <param name="workingPluginId">The ID of the plugin.</param>
|
||||||
/// <param name="apply">Whether or not the current state should immediately be applied.</param>
|
/// <param name="apply">Whether or not the current state should immediately be applied.</param>
|
||||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||||
public async Task RemoveAsync(string internalName, bool apply = true)
|
public async Task RemoveAsync(Guid workingPluginId, bool apply = true)
|
||||||
{
|
{
|
||||||
ProfileModelV1.ProfileModelV1Plugin entry;
|
ProfileModelV1.ProfileModelV1Plugin entry;
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
entry = this.modelV1.Plugins.FirstOrDefault(x => x.InternalName == internalName);
|
entry = this.modelV1.Plugins.FirstOrDefault(x => x.WorkingPluginId == workingPluginId);
|
||||||
if (entry == null)
|
if (entry == null)
|
||||||
throw new PluginNotFoundException(internalName);
|
throw new PluginNotFoundException(workingPluginId.ToString());
|
||||||
|
|
||||||
if (!this.modelV1.Plugins.Remove(entry))
|
if (!this.modelV1.Plugins.Remove(entry))
|
||||||
throw new Exception("Couldn't remove plugin from model collection");
|
throw new Exception("Couldn't remove plugin from model collection");
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to add this plugin back to the default profile, if we were the last profile to have it.
|
// We need to add this plugin back to the default profile, if we were the last profile to have it.
|
||||||
if (!this.manager.IsInAnyProfile(internalName))
|
if (!this.manager.IsInAnyProfile(workingPluginId))
|
||||||
{
|
{
|
||||||
if (!this.IsDefaultProfile)
|
if (!this.IsDefaultProfile)
|
||||||
{
|
{
|
||||||
await this.manager.DefaultProfile.AddOrUpdateAsync(internalName, this.IsEnabled && entry.IsEnabled, false);
|
await this.manager.DefaultProfile.AddOrUpdateAsync(workingPluginId, this.IsEnabled && entry.IsEnabled, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PluginNotInDefaultProfileException(internalName);
|
throw new PluginNotInDefaultProfileException(workingPluginId.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,6 +233,34 @@ internal class Profile
|
||||||
await this.manager.ApplyAllWantStatesAsync();
|
await this.manager.ApplyAllWantStatesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This function tries to migrate all plugins with this internalName which do not have
|
||||||
|
/// a GUID to the specified GUID.
|
||||||
|
/// This is best-effort and will probably work well for anyone that only uses regular plugins.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="internalName">InternalName of the plugin to migrate.</param>
|
||||||
|
/// <param name="newGuid">Guid to use.</param>
|
||||||
|
public void MigrateProfilesToGuidsForPlugin(string internalName, Guid newGuid)
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
foreach (var plugin in this.modelV1.Plugins)
|
||||||
|
{
|
||||||
|
// TODO: What should happen if a profile has a GUID locked in, but the plugin
|
||||||
|
// is not installed anymore? That probably means that the user uninstalled the plugin
|
||||||
|
// and is now reinstalling it. We should still satisfy that and update the ID.
|
||||||
|
|
||||||
|
if (plugin.InternalName == internalName && plugin.WorkingPluginId == Guid.Empty)
|
||||||
|
{
|
||||||
|
plugin.WorkingPluginId = newGuid;
|
||||||
|
Log.Information("Migrated profile {Profile} plugin {Name} to guid {Guid}", this, internalName, newGuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Service<DalamudConfiguration>.Get().QueueSave();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string ToString() => $"{this.Guid} ({this.Name})";
|
public override string ToString() => $"{this.Guid} ({this.Name})";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,11 +69,11 @@ internal class ProfileManager : IServiceType
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if any enabled profile wants a specific plugin enabled.
|
/// Check if any enabled profile wants a specific plugin enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="internalName">The internal name of the plugin.</param>
|
/// <param name="workingPluginId">The ID of the plugin.</param>
|
||||||
/// <param name="defaultState">The state the plugin shall be in, if it needs to be added.</param>
|
/// <param name="defaultState">The state the plugin shall be in, if it needs to be added.</param>
|
||||||
/// <param name="addIfNotDeclared">Whether or not the plugin should be added to the default preset, if it's not present in any preset.</param>
|
/// <param name="addIfNotDeclared">Whether or not the plugin should be added to the default preset, if it's not present in any preset.</param>
|
||||||
/// <returns>Whether or not the plugin shall be enabled.</returns>
|
/// <returns>Whether or not the plugin shall be enabled.</returns>
|
||||||
public async Task<bool> GetWantStateAsync(string internalName, bool defaultState, bool addIfNotDeclared = true)
|
public async Task<bool> GetWantStateAsync(Guid workingPluginId, bool defaultState, bool addIfNotDeclared = true)
|
||||||
{
|
{
|
||||||
var want = false;
|
var want = false;
|
||||||
var wasInAnyProfile = false;
|
var wasInAnyProfile = false;
|
||||||
|
|
@ -82,7 +82,7 @@ internal class ProfileManager : IServiceType
|
||||||
{
|
{
|
||||||
foreach (var profile in this.profiles)
|
foreach (var profile in this.profiles)
|
||||||
{
|
{
|
||||||
var state = profile.WantsPlugin(internalName);
|
var state = profile.WantsPlugin(workingPluginId);
|
||||||
if (state.HasValue)
|
if (state.HasValue)
|
||||||
{
|
{
|
||||||
want = want || (profile.IsEnabled && state.Value);
|
want = want || (profile.IsEnabled && state.Value);
|
||||||
|
|
@ -93,8 +93,8 @@ internal class ProfileManager : IServiceType
|
||||||
|
|
||||||
if (!wasInAnyProfile && addIfNotDeclared)
|
if (!wasInAnyProfile && addIfNotDeclared)
|
||||||
{
|
{
|
||||||
Log.Warning("{Name} was not in any profile, adding to default with {Default}", internalName, defaultState);
|
Log.Warning("{Guid} was not in any profile, adding to default with {Default}", workingPluginId, defaultState);
|
||||||
await this.DefaultProfile.AddOrUpdateAsync(internalName, defaultState, false);
|
await this.DefaultProfile.AddOrUpdateAsync(workingPluginId, defaultState, false);
|
||||||
|
|
||||||
return defaultState;
|
return defaultState;
|
||||||
}
|
}
|
||||||
|
|
@ -105,22 +105,22 @@ internal class ProfileManager : IServiceType
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check whether a plugin is declared in any profile.
|
/// Check whether a plugin is declared in any profile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="internalName">The internal name of the plugin.</param>
|
/// <param name="workingPluginId">The ID of the plugin.</param>
|
||||||
/// <returns>Whether or not the plugin is in any profile.</returns>
|
/// <returns>Whether or not the plugin is in any profile.</returns>
|
||||||
public bool IsInAnyProfile(string internalName)
|
public bool IsInAnyProfile(Guid workingPluginId)
|
||||||
{
|
{
|
||||||
lock (this.profiles)
|
lock (this.profiles)
|
||||||
return this.profiles.Any(x => x.WantsPlugin(internalName) != null);
|
return this.profiles.Any(x => x.WantsPlugin(workingPluginId) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check whether a plugin is only in the default profile.
|
/// Check whether a plugin is only in the default profile.
|
||||||
/// A plugin can never be in the default profile if it is in any other profile.
|
/// A plugin can never be in the default profile if it is in any other profile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="internalName">The internal name of the plugin.</param>
|
/// <param name="workingPluginId">The ID of the plugin.</param>
|
||||||
/// <returns>Whether or not the plugin is in the default profile.</returns>
|
/// <returns>Whether or not the plugin is in the default profile.</returns>
|
||||||
public bool IsInDefaultProfile(string internalName)
|
public bool IsInDefaultProfile(Guid workingPluginId)
|
||||||
=> this.DefaultProfile.WantsPlugin(internalName) != null;
|
=> this.DefaultProfile.WantsPlugin(workingPluginId) != null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a new profile.
|
/// Add a new profile.
|
||||||
|
|
@ -151,7 +151,7 @@ internal class ProfileManager : IServiceType
|
||||||
/// <returns>The newly cloned profile.</returns>
|
/// <returns>The newly cloned profile.</returns>
|
||||||
public Profile CloneProfile(Profile toClone)
|
public Profile CloneProfile(Profile toClone)
|
||||||
{
|
{
|
||||||
var newProfile = this.ImportProfile(toClone.Model.Serialize());
|
var newProfile = this.ImportProfile(toClone.Model.SerializeForShare());
|
||||||
if (newProfile == null)
|
if (newProfile == null)
|
||||||
throw new Exception("New profile was null while cloning");
|
throw new Exception("New profile was null while cloning");
|
||||||
|
|
||||||
|
|
@ -172,7 +172,27 @@ internal class ProfileManager : IServiceType
|
||||||
newModel.Guid = Guid.NewGuid();
|
newModel.Guid = Guid.NewGuid();
|
||||||
newModel.Name = this.GenerateUniqueProfileName(newModel.Name.IsNullOrEmpty() ? "Unknown Collection" : newModel.Name);
|
newModel.Name = this.GenerateUniqueProfileName(newModel.Name.IsNullOrEmpty() ? "Unknown Collection" : newModel.Name);
|
||||||
if (newModel is ProfileModelV1 modelV1)
|
if (newModel is ProfileModelV1 modelV1)
|
||||||
|
{
|
||||||
|
// Disable it
|
||||||
modelV1.IsEnabled = false;
|
modelV1.IsEnabled = false;
|
||||||
|
|
||||||
|
// Try to find matching plugins for all plugins in the profile
|
||||||
|
var pm = Service<PluginManager>.Get();
|
||||||
|
foreach (var plugin in modelV1.Plugins)
|
||||||
|
{
|
||||||
|
var installedPlugin = pm.InstalledPlugins.FirstOrDefault(x => x.Manifest.InternalName == plugin.InternalName);
|
||||||
|
if (installedPlugin != null)
|
||||||
|
{
|
||||||
|
Log.Information("Satisfying plugin {InternalName} for profile {Name} with {Guid}", plugin.InternalName, newModel.Name, installedPlugin.Manifest.WorkingPluginId);
|
||||||
|
plugin.WorkingPluginId = installedPlugin.Manifest.WorkingPluginId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Warning("Couldn't find plugin {InternalName} for profile {Name}", plugin.InternalName, newModel.Name);
|
||||||
|
plugin.WorkingPluginId = Guid.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.config.SavedProfiles!.Add(newModel);
|
this.config.SavedProfiles!.Add(newModel);
|
||||||
this.config.QueueSave();
|
this.config.QueueSave();
|
||||||
|
|
@ -196,13 +216,13 @@ internal class ProfileManager : IServiceType
|
||||||
this.isBusy = true;
|
this.isBusy = true;
|
||||||
Log.Information("Getting want states...");
|
Log.Information("Getting want states...");
|
||||||
|
|
||||||
List<string> wantActive;
|
List<Guid> wantActive;
|
||||||
lock (this.profiles)
|
lock (this.profiles)
|
||||||
{
|
{
|
||||||
wantActive = this.profiles
|
wantActive = this.profiles
|
||||||
.Where(x => x.IsEnabled)
|
.Where(x => x.IsEnabled)
|
||||||
.SelectMany(profile => profile.Plugins.Where(plugin => plugin.IsEnabled)
|
.SelectMany(profile => profile.Plugins.Where(plugin => plugin.IsEnabled)
|
||||||
.Select(plugin => plugin.InternalName))
|
.Select(plugin => plugin.WorkingPluginId))
|
||||||
.Distinct().ToList();
|
.Distinct().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,7 +238,7 @@ internal class ProfileManager : IServiceType
|
||||||
var pm = Service<PluginManager>.Get();
|
var pm = Service<PluginManager>.Get();
|
||||||
foreach (var installedPlugin in pm.InstalledPlugins)
|
foreach (var installedPlugin in pm.InstalledPlugins)
|
||||||
{
|
{
|
||||||
var wantThis = wantActive.Contains(installedPlugin.Manifest.InternalName);
|
var wantThis = wantActive.Contains(installedPlugin.Manifest.WorkingPluginId);
|
||||||
switch (wantThis)
|
switch (wantThis)
|
||||||
{
|
{
|
||||||
case true when !installedPlugin.IsLoaded:
|
case true when !installedPlugin.IsLoaded:
|
||||||
|
|
@ -267,7 +287,7 @@ internal class ProfileManager : IServiceType
|
||||||
// We need to remove all plugins from the profile first, so that they are re-added to the default profile if needed
|
// We need to remove all plugins from the profile first, so that they are re-added to the default profile if needed
|
||||||
foreach (var plugin in profile.Plugins.ToArray())
|
foreach (var plugin in profile.Plugins.ToArray())
|
||||||
{
|
{
|
||||||
await profile.RemoveAsync(plugin.InternalName, false);
|
await profile.RemoveAsync(plugin.WorkingPluginId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.config.SavedProfiles!.Remove(profile.Model))
|
if (!this.config.SavedProfiles!.Remove(profile.Model))
|
||||||
|
|
@ -279,6 +299,22 @@ internal class ProfileManager : IServiceType
|
||||||
this.config.QueueSave();
|
this.config.QueueSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This function tries to migrate all plugins with this internalName which do not have
|
||||||
|
/// a GUID to the specified GUID.
|
||||||
|
/// This is best-effort and will probably work well for anyone that only uses regular plugins.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="internalName">InternalName of the plugin to migrate.</param>
|
||||||
|
/// <param name="newGuid">Guid to use.</param>
|
||||||
|
public void MigrateProfilesToGuidsForPlugin(string internalName, Guid newGuid)
|
||||||
|
{
|
||||||
|
lock (this.profiles)
|
||||||
|
{
|
||||||
|
foreach (var profile in this.profiles)
|
||||||
|
profile.MigrateProfilesToGuidsForPlugin(internalName, newGuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string GenerateUniqueProfileName(string startingWith)
|
private string GenerateUniqueProfileName(string startingWith)
|
||||||
{
|
{
|
||||||
if (this.profiles.All(x => x.Name != startingWith))
|
if (this.profiles.All(x => x.Name != startingWith))
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
|
||||||
namespace Dalamud.Plugin.Internal.Profiles;
|
namespace Dalamud.Plugin.Internal.Profiles;
|
||||||
|
|
||||||
|
|
@ -39,11 +41,11 @@ public abstract class ProfileModel
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize this model into a string usable for sharing.
|
/// Serialize this model into a string usable for sharing, without including GUIDs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The serialized representation of the model.</returns>
|
/// <returns>The serialized representation of the model.</returns>
|
||||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when an unsupported model is serialized.</exception>
|
/// <exception cref="ArgumentOutOfRangeException">Thrown when an unsupported model is serialized.</exception>
|
||||||
public string Serialize()
|
public string SerializeForShare()
|
||||||
{
|
{
|
||||||
string prefix;
|
string prefix;
|
||||||
switch (this)
|
switch (this)
|
||||||
|
|
@ -55,6 +57,32 @@ public abstract class ProfileModel
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefix + Convert.ToBase64String(Util.CompressString(JsonConvert.SerializeObject(this)));
|
// HACK: Just filter the ID for now, we should split the sharing + saving model
|
||||||
|
var serialized = JsonConvert.SerializeObject(this, new JsonSerializerSettings()
|
||||||
|
{ ContractResolver = new IgnorePropertiesResolver(new[] { "WorkingPluginId" }) });
|
||||||
|
|
||||||
|
return prefix + Convert.ToBase64String(Util.CompressString(serialized));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Short helper class to ignore some properties from serialization
|
||||||
|
private class IgnorePropertiesResolver : DefaultContractResolver
|
||||||
|
{
|
||||||
|
private readonly HashSet<string> ignoreProps;
|
||||||
|
|
||||||
|
public IgnorePropertiesResolver(IEnumerable<string> propNamesToIgnore)
|
||||||
|
{
|
||||||
|
this.ignoreProps = new HashSet<string>(propNamesToIgnore);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
|
||||||
|
{
|
||||||
|
var property = base.CreateProperty(member, memberSerialization);
|
||||||
|
if (this.ignoreProps.Contains(property.PropertyName))
|
||||||
|
{
|
||||||
|
property.ShouldSerialize = _ => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return property;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,11 @@ public class ProfileModelV1 : ProfileModel
|
||||||
/// Gets or sets the internal name of the plugin.
|
/// Gets or sets the internal name of the plugin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? InternalName { get; set; }
|
public string? InternalName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets an ID uniquely identifying this specific instance of a plugin.
|
||||||
|
/// </summary>
|
||||||
|
public Guid WorkingPluginId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether or not this entry is enabled.
|
/// Gets or sets a value indicating whether or not this entry is enabled.
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,12 @@ internal class ProfilePluginEntry
|
||||||
/// Initializes a new instance of the <see cref="ProfilePluginEntry"/> class.
|
/// Initializes a new instance of the <see cref="ProfilePluginEntry"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="internalName">The internal name of the plugin.</param>
|
/// <param name="internalName">The internal name of the plugin.</param>
|
||||||
|
/// <param name="workingPluginId">The ID of the plugin.</param>
|
||||||
/// <param name="state">A value indicating whether or not this entry is enabled.</param>
|
/// <param name="state">A value indicating whether or not this entry is enabled.</param>
|
||||||
public ProfilePluginEntry(string internalName, bool state)
|
public ProfilePluginEntry(string internalName, Guid workingPluginId, bool state)
|
||||||
{
|
{
|
||||||
this.InternalName = internalName;
|
this.InternalName = internalName;
|
||||||
|
this.WorkingPluginId = workingPluginId;
|
||||||
this.IsEnabled = state;
|
this.IsEnabled = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,6 +22,11 @@ internal class ProfilePluginEntry
|
||||||
/// Gets the internal name of the plugin.
|
/// Gets the internal name of the plugin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string InternalName { get; }
|
public string InternalName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets an ID uniquely identifying this specific instance of a plugin.
|
||||||
|
/// </summary>
|
||||||
|
public Guid WorkingPluginId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether or not this entry is enabled.
|
/// Gets a value indicating whether or not this entry is enabled.
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ internal class LocalPlugin : IDisposable
|
||||||
/// INCLUDES the default profile.
|
/// INCLUDES the default profile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsWantedByAnyProfile =>
|
public bool IsWantedByAnyProfile =>
|
||||||
Service<ProfileManager>.Get().GetWantStateAsync(this.manifest.InternalName, false, false).GetAwaiter().GetResult();
|
Service<ProfileManager>.Get().GetWantStateAsync(this.manifest.WorkingPluginId, false, false).GetAwaiter().GetResult();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this plugin's API level is out of date.
|
/// Gets a value indicating whether this plugin's API level is out of date.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue