Add integration settings sections

This commit is contained in:
Exter-N 2025-11-13 19:53:50 +01:00
parent ce54aa5d25
commit 5be021b0eb
6 changed files with 139 additions and 11 deletions

@ -1 +1 @@
Subproject commit 874a3773bc4f637de1ef1fa8756b4debe3d8f68b Subproject commit b97784bd7cd911bd0a323cd8e717714de1875469

View file

@ -17,7 +17,7 @@ public class PenumbraApi(
UiApi ui) : IDisposable, IApiService, IPenumbraApi UiApi ui) : IDisposable, IApiService, IPenumbraApi
{ {
public const int BreakingVersion = 5; public const int BreakingVersion = 5;
public const int FeatureVersion = 12; public const int FeatureVersion = 13;
public void Dispose() public void Dispose()
{ {

View file

@ -5,6 +5,8 @@ using Penumbra.GameData.Data;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.UI; using Penumbra.UI;
using Penumbra.UI.Integration;
using Penumbra.UI.Tabs;
namespace Penumbra.Api.Api; namespace Penumbra.Api.Api;
@ -13,12 +15,14 @@ public class UiApi : IPenumbraApiUi, IApiService, IDisposable
private readonly CommunicatorService _communicator; private readonly CommunicatorService _communicator;
private readonly ConfigWindow _configWindow; private readonly ConfigWindow _configWindow;
private readonly ModManager _modManager; private readonly ModManager _modManager;
private readonly IntegrationSettingsRegistry _integrationSettings;
public UiApi(CommunicatorService communicator, ConfigWindow configWindow, ModManager modManager) public UiApi(CommunicatorService communicator, ConfigWindow configWindow, ModManager modManager, IntegrationSettingsRegistry integrationSettings)
{ {
_communicator = communicator; _communicator = communicator;
_configWindow = configWindow; _configWindow = configWindow;
_modManager = modManager; _modManager = modManager;
_integrationSettings = integrationSettings;
_communicator.ChangedItemHover.Subscribe(OnChangedItemHover, ChangedItemHover.Priority.Default); _communicator.ChangedItemHover.Subscribe(OnChangedItemHover, ChangedItemHover.Priority.Default);
_communicator.ChangedItemClick.Subscribe(OnChangedItemClick, ChangedItemClick.Priority.Default); _communicator.ChangedItemClick.Subscribe(OnChangedItemClick, ChangedItemClick.Priority.Default);
} }
@ -98,4 +102,12 @@ public class UiApi : IPenumbraApiUi, IApiService, IDisposable
var (type, id) = data.ToApiObject(); var (type, id) = data.ToApiObject();
ChangedItemTooltip.Invoke(type, id); ChangedItemTooltip.Invoke(type, id);
} }
public PenumbraApiEc RegisterSettingsSection(Action draw)
=> _integrationSettings.RegisterSection(draw);
public PenumbraApiEc UnregisterSettingsSection(Action draw)
=> _integrationSettings.UnregisterSection(draw)
? PenumbraApiEc.Success
: PenumbraApiEc.NothingChanged;
} }

View file

@ -130,6 +130,8 @@ public sealed class IpcProviders : IDisposable, IApiService
IpcSubscribers.PostSettingsDraw.Provider(pi, api.Ui), IpcSubscribers.PostSettingsDraw.Provider(pi, api.Ui),
IpcSubscribers.OpenMainWindow.Provider(pi, api.Ui), IpcSubscribers.OpenMainWindow.Provider(pi, api.Ui),
IpcSubscribers.CloseMainWindow.Provider(pi, api.Ui), IpcSubscribers.CloseMainWindow.Provider(pi, api.Ui),
IpcSubscribers.RegisterSettingsSection.Provider(pi, api.Ui),
IpcSubscribers.UnregisterSettingsSection.Provider(pi, api.Ui),
]; ];
if (_characterUtility.Ready) if (_characterUtility.Ready)
_initializedProvider.Invoke(); _initializedProvider.Invoke();

View file

@ -0,0 +1,110 @@
using Dalamud.Plugin;
using OtterGui.Services;
using OtterGui.Text;
using Penumbra.Api.Enums;
namespace Penumbra.UI.Integration;
public sealed class IntegrationSettingsRegistry : IService, IDisposable
{
private readonly IDalamudPluginInterface _pluginInterface;
private readonly List<(string InternalName, string Name, Action Draw)> _sections = [];
private bool _disposed = false;
public IntegrationSettingsRegistry(IDalamudPluginInterface pluginInterface)
{
_pluginInterface = pluginInterface;
_pluginInterface.ActivePluginsChanged += OnActivePluginsChanged;
}
public void Dispose()
{
_disposed = true;
_pluginInterface.ActivePluginsChanged -= OnActivePluginsChanged;
_sections.Clear();
}
public void Draw()
{
foreach (var (internalName, name, draw) in _sections)
{
if (!ImUtf8.CollapsingHeader($"Integration with {name}###IntegrationSettingsHeader.{internalName}"))
continue;
using var id = ImUtf8.PushId($"IntegrationSettings.{internalName}");
try
{
draw();
}
catch (Exception e)
{
Penumbra.Log.Error($"Error while drawing {internalName} integration settings: {e}");
}
}
}
public PenumbraApiEc RegisterSection(Action draw)
{
if (_disposed)
return PenumbraApiEc.SystemDisposed;
var plugin = GetPlugin(draw);
if (plugin is null)
return PenumbraApiEc.InvalidArgument;
var section = (plugin.InternalName, plugin.Name, draw);
var index = FindSectionIndex(plugin.InternalName);
if (index >= 0)
{
if (_sections[index] == section)
return PenumbraApiEc.NothingChanged;
_sections[index] = section;
}
else
_sections.Add(section);
_sections.Sort((lhs, rhs) => string.Compare(lhs.Name, rhs.Name, StringComparison.CurrentCultureIgnoreCase));
return PenumbraApiEc.Success;
}
public bool UnregisterSection(Action draw)
{
var index = FindSectionIndex(draw);
if (index < 0)
return false;
_sections.RemoveAt(index);
return true;
}
private void OnActivePluginsChanged(IActivePluginsChangedEventArgs args)
{
if (args.Kind is PluginListInvalidationKind.Loaded)
return;
foreach (var internalName in args.AffectedInternalNames)
{
var index = FindSectionIndex(internalName);
if (index >= 0 && GetPlugin(_sections[index].Draw) is null)
{
_sections.RemoveAt(index);
Penumbra.Log.Warning($"Removed stale integration setting section of {internalName} (reason: {args.Kind})");
}
}
}
private IExposedPlugin? GetPlugin(Delegate @delegate)
=> null; // TODO Use IDalamudPluginInterface.GetPlugin(Assembly) when it's in Dalamud stable.
private int FindSectionIndex(string internalName)
=> _sections.FindIndex(section => section.InternalName.Equals(internalName, StringComparison.Ordinal));
private int FindSectionIndex(Action draw)
=> _sections.FindIndex(section => section.Draw == draw);
}

View file

@ -20,6 +20,7 @@ using Penumbra.Interop.Services;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
using Penumbra.UI.Integration;
using Penumbra.UI.ModsTab; using Penumbra.UI.ModsTab;
namespace Penumbra.UI.Tabs; namespace Penumbra.UI.Tabs;
@ -55,6 +56,7 @@ public class SettingsTab : ITab, IUiService
private readonly CleanupService _cleanupService; private readonly CleanupService _cleanupService;
private readonly AttributeHook _attributeHook; private readonly AttributeHook _attributeHook;
private readonly PcpService _pcpService; private readonly PcpService _pcpService;
private readonly IntegrationSettingsRegistry _integrationSettings;
private int _minimumX = int.MaxValue; private int _minimumX = int.MaxValue;
private int _minimumY = int.MaxValue; private int _minimumY = int.MaxValue;
@ -71,7 +73,7 @@ public class SettingsTab : ITab, IUiService
DalamudSubstitutionProvider dalamudSubstitutionProvider, FileCompactor compactor, DalamudConfigService dalamudConfig, DalamudSubstitutionProvider dalamudSubstitutionProvider, FileCompactor compactor, DalamudConfigService dalamudConfig,
IDataManager gameData, PredefinedTagManager predefinedTagConfig, CrashHandlerService crashService, IDataManager gameData, PredefinedTagManager predefinedTagConfig, CrashHandlerService crashService,
MigrationSectionDrawer migrationDrawer, CollectionAutoSelector autoSelector, CleanupService cleanupService, MigrationSectionDrawer migrationDrawer, CollectionAutoSelector autoSelector, CleanupService cleanupService,
AttributeHook attributeHook, PcpService pcpService) AttributeHook attributeHook, PcpService pcpService, IntegrationSettingsRegistry integrationSettings)
{ {
_pluginInterface = pluginInterface; _pluginInterface = pluginInterface;
_config = config; _config = config;
@ -99,6 +101,7 @@ public class SettingsTab : ITab, IUiService
_cleanupService = cleanupService; _cleanupService = cleanupService;
_attributeHook = attributeHook; _attributeHook = attributeHook;
_pcpService = pcpService; _pcpService = pcpService;
_integrationSettings = integrationSettings;
} }
public void DrawHeader() public void DrawHeader()
@ -129,6 +132,7 @@ public class SettingsTab : ITab, IUiService
DrawColorSettings(); DrawColorSettings();
DrawPredefinedTagsSection(); DrawPredefinedTagsSection();
DrawAdvancedSettings(); DrawAdvancedSettings();
_integrationSettings.Draw();
DrawSupportButtons(); DrawSupportButtons();
} }