Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Penumbra.Api
2 changes: 1 addition & 1 deletion Penumbra/Api/Api/PenumbraApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class PenumbraApi(
UiApi ui) : IDisposable, IApiService, IPenumbraApi
{
public const int BreakingVersion = 5;
public const int FeatureVersion = 12;
public const int FeatureVersion = 13;

public void Dispose()
{
Expand Down
26 changes: 19 additions & 7 deletions Penumbra/Api/Api/UiApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@
using Penumbra.Mods.Manager;
using Penumbra.Services;
using Penumbra.UI;
using Penumbra.UI.Integration;
using Penumbra.UI.Tabs;

namespace Penumbra.Api.Api;

public class UiApi : IPenumbraApiUi, IApiService, IDisposable
{
private readonly CommunicatorService _communicator;
private readonly ConfigWindow _configWindow;
private readonly ModManager _modManager;
private readonly CommunicatorService _communicator;
private readonly ConfigWindow _configWindow;
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;
_configWindow = configWindow;
_modManager = modManager;
_communicator = communicator;
_configWindow = configWindow;
_modManager = modManager;
_integrationSettings = integrationSettings;
_communicator.ChangedItemHover.Subscribe(OnChangedItemHover, ChangedItemHover.Priority.Default);
_communicator.ChangedItemClick.Subscribe(OnChangedItemClick, ChangedItemClick.Priority.Default);
}
Expand Down Expand Up @@ -98,4 +102,12 @@ private void OnChangedItemHover(IIdentifiedObjectData data)
var (type, id) = data.ToApiObject();
ChangedItemTooltip.Invoke(type, id);
}

public PenumbraApiEc RegisterSettingsSection(Action draw)
=> _integrationSettings.RegisterSection(draw);

public PenumbraApiEc UnregisterSettingsSection(Action draw)
=> _integrationSettings.UnregisterSection(draw)
? PenumbraApiEc.Success
: PenumbraApiEc.NothingChanged;
}
2 changes: 2 additions & 0 deletions Penumbra/Api/IpcProviders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ public IpcProviders(IDalamudPluginInterface pi, IPenumbraApi api, CharacterUtili
IpcSubscribers.PostSettingsDraw.Provider(pi, api.Ui),
IpcSubscribers.OpenMainWindow.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)
_initializedProvider.Invoke();
Expand Down
115 changes: 115 additions & 0 deletions Penumbra/UI/Integration/IntegrationSettingsRegistry.cs
Original file line number Diff line number Diff line change
@@ -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);
}
8 changes: 6 additions & 2 deletions Penumbra/UI/Tabs/SettingsTab.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Penumbra.Mods.Manager;
using Penumbra.Services;
using Penumbra.UI.Classes;
using Penumbra.UI.Integration;
using Penumbra.UI.ModsTab;

namespace Penumbra.UI.Tabs;
Expand Down Expand Up @@ -55,6 +56,7 @@ public ReadOnlySpan<byte> Label
private readonly CleanupService _cleanupService;
private readonly AttributeHook _attributeHook;
private readonly PcpService _pcpService;
private readonly IntegrationSettingsRegistry _integrationSettings;

private int _minimumX = int.MaxValue;
private int _minimumY = int.MaxValue;
Expand All @@ -71,7 +73,7 @@ public SettingsTab(IDalamudPluginInterface pluginInterface, Configuration config
DalamudSubstitutionProvider dalamudSubstitutionProvider, FileCompactor compactor, DalamudConfigService dalamudConfig,
IDataManager gameData, PredefinedTagManager predefinedTagConfig, CrashHandlerService crashService,
MigrationSectionDrawer migrationDrawer, CollectionAutoSelector autoSelector, CleanupService cleanupService,
AttributeHook attributeHook, PcpService pcpService)
AttributeHook attributeHook, PcpService pcpService, IntegrationSettingsRegistry integrationSettings)
{
_pluginInterface = pluginInterface;
_config = config;
Expand Down Expand Up @@ -99,6 +101,7 @@ public SettingsTab(IDalamudPluginInterface pluginInterface, Configuration config
_cleanupService = cleanupService;
_attributeHook = attributeHook;
_pcpService = pcpService;
_integrationSettings = integrationSettings;
}

public void DrawHeader()
Expand Down Expand Up @@ -129,6 +132,7 @@ public void DrawContent()
DrawColorSettings();
DrawPredefinedTagsSection();
DrawAdvancedSettings();
_integrationSettings.Draw();
DrawSupportButtons();
}

Expand Down Expand Up @@ -1133,7 +1137,7 @@ private void DrawWaitForPluginsReflection()
}

#endregion

/// <summary> Draw the support button group on the right-hand side of the window. </summary>
private void DrawSupportButtons()
{
Expand Down
Loading