This commit is contained in:
N. Lo. 2025-11-30 22:29:25 +01:00 committed by GitHub
commit b9651456fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 144 additions and 11 deletions

@ -1 +1 @@
Subproject commit 874a3773bc4f637de1ef1fa8756b4debe3d8f68b Subproject commit 704d62f64f791b8cfd42363beaa464ad6f98ae48

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,20 +5,24 @@ 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;
public class UiApi : IPenumbraApiUi, IApiService, IDisposable 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,115 @@
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)
=> @delegate.Method.DeclaringType
switch
{
null => null,
var type => _pluginInterface.GetPlugin(type.Assembly),
};
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();
} }