Skip to content

Commit

Permalink
Add GameConfigPluginScoped (#1383)
Browse files Browse the repository at this point in the history
* Add GameConfigPluginScoped

* Proposed Resolution to sub-object events

* Nullify delegates to prevent memory leaks
  • Loading branch information
MidoriKami authored Sep 22, 2023
1 parent b742abe commit 43abb12
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 8 deletions.
224 changes: 218 additions & 6 deletions Dalamud/Game/Config/GameConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ namespace Dalamud.Game.Config;
/// This class represents the game's configuration.
/// </summary>
[InterfaceVersion("1.0")]
[PluginInterface]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IGameConfig>]
#pragma warning restore SA1015
internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
{
private readonly GameConfigAddressResolver address = new();
Expand All @@ -36,15 +32,30 @@ private unsafe GameConfig(Framework framework, SigScanner sigScanner)
this.address.Setup(sigScanner);
this.configChangeHook = Hook<ConfigChangeDelegate>.FromAddress(this.address.ConfigChangeAddress, this.OnConfigChanged);
this.configChangeHook?.Enable();
this.configChangeHook.Enable();
});
}

private unsafe delegate nint ConfigChangeDelegate(ConfigBase* configBase, ConfigEntry* configEntry);

/// <inheritdoc/>
public event EventHandler<ConfigChangeEvent> Changed;
public event EventHandler<ConfigChangeEvent>? Changed;

/// <summary>
/// Unused internally, used as a proxy for System.Changed via GameConfigPluginScoped
/// </summary>
public event EventHandler<ConfigChangeEvent>? SystemChanged;

/// <summary>
/// Unused internally, used as a proxy for UiConfig.Changed via GameConfigPluginScoped
/// </summary>
public event EventHandler<ConfigChangeEvent>? UiConfigChanged;

/// <summary>
/// Unused internally, used as a proxy for UiControl.Changed via GameConfigPluginScoped
/// </summary>
public event EventHandler<ConfigChangeEvent>? UiControlChanged;

/// <inheritdoc/>
public GameConfigSection System { get; private set; }

Expand Down Expand Up @@ -192,3 +203,204 @@ private unsafe nint OnConfigChanged(ConfigBase* configBase, ConfigEntry* configE
return returnValue;
}
}

/// <summary>
/// Plugin-scoped version of a GameConfig service.
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.ScopedService]
#pragma warning disable SA1015
[ResolveVia<IGameConfig>]
#pragma warning restore SA1015
internal class GameConfigPluginScoped : IDisposable, IServiceType, IGameConfig
{
[ServiceManager.ServiceDependency]
private readonly GameConfig gameConfigService = Service<GameConfig>.Get();

/// <summary>
/// Initializes a new instance of the <see cref="GameConfigPluginScoped"/> class.
/// </summary>
internal GameConfigPluginScoped()
{
this.gameConfigService.Changed += this.ConfigChangedForward;
this.gameConfigService.System.Changed += this.SystemConfigChangedForward;
this.gameConfigService.UiConfig.Changed += this.UiConfigConfigChangedForward;
this.gameConfigService.UiControl.Changed += this.UiControlConfigChangedForward;
}

/// <inheritdoc/>
public event EventHandler<ConfigChangeEvent>? Changed;

/// <inheritdoc/>
public event EventHandler<ConfigChangeEvent>? SystemChanged;

/// <inheritdoc/>
public event EventHandler<ConfigChangeEvent>? UiConfigChanged;

/// <inheritdoc/>
public event EventHandler<ConfigChangeEvent>? UiControlChanged;

/// <inheritdoc/>
public GameConfigSection System => this.gameConfigService.System;

/// <inheritdoc/>
public GameConfigSection UiConfig => this.gameConfigService.UiConfig;

/// <inheritdoc/>
public GameConfigSection UiControl => this.gameConfigService.UiControl;

/// <inheritdoc/>
public void Dispose()
{
this.gameConfigService.Changed -= this.ConfigChangedForward;
this.gameConfigService.System.Changed -= this.SystemConfigChangedForward;
this.gameConfigService.UiConfig.Changed -= this.UiConfigConfigChangedForward;
this.gameConfigService.UiControl.Changed -= this.UiControlConfigChangedForward;

this.Changed = null;
this.SystemChanged = null;
this.UiConfigChanged = null;
this.UiControlChanged = null;
}

/// <inheritdoc/>
public bool TryGet(SystemConfigOption option, out bool value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(SystemConfigOption option, out uint value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(SystemConfigOption option, out float value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(SystemConfigOption option, out string value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(SystemConfigOption option, out UIntConfigProperties? properties)
=> this.gameConfigService.TryGet(option, out properties);

/// <inheritdoc/>
public bool TryGet(SystemConfigOption option, out FloatConfigProperties? properties)
=> this.gameConfigService.TryGet(option, out properties);

/// <inheritdoc/>
public bool TryGet(SystemConfigOption option, out StringConfigProperties? properties)
=> this.gameConfigService.TryGet(option, out properties);

/// <inheritdoc/>
public bool TryGet(UiConfigOption option, out bool value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(UiConfigOption option, out uint value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(UiConfigOption option, out float value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(UiConfigOption option, out string value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(UiConfigOption option, out UIntConfigProperties? properties)
=> this.gameConfigService.TryGet(option, out properties);

/// <inheritdoc/>
public bool TryGet(UiConfigOption option, out FloatConfigProperties? properties)
=> this.gameConfigService.TryGet(option, out properties);

/// <inheritdoc/>
public bool TryGet(UiConfigOption option, out StringConfigProperties? properties)
=> this.gameConfigService.TryGet(option, out properties);

/// <inheritdoc/>
public bool TryGet(UiControlOption option, out bool value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(UiControlOption option, out uint value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(UiControlOption option, out float value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(UiControlOption option, out string value)
=> this.gameConfigService.TryGet(option, out value);

/// <inheritdoc/>
public bool TryGet(UiControlOption option, out UIntConfigProperties? properties)
=> this.gameConfigService.TryGet(option, out properties);

/// <inheritdoc/>
public bool TryGet(UiControlOption option, out FloatConfigProperties? properties)
=> this.gameConfigService.TryGet(option, out properties);

/// <inheritdoc/>
public bool TryGet(UiControlOption option, out StringConfigProperties? properties)
=> this.gameConfigService.TryGet(option, out properties);

/// <inheritdoc/>
public void Set(SystemConfigOption option, bool value)
=> this.gameConfigService.Set(option, value);

/// <inheritdoc/>
public void Set(SystemConfigOption option, uint value)
=> this.gameConfigService.Set(option, value);

/// <inheritdoc/>
public void Set(SystemConfigOption option, float value)
=> this.gameConfigService.Set(option, value);

/// <inheritdoc/>
public void Set(SystemConfigOption option, string value)
=> this.gameConfigService.Set(option, value);

/// <inheritdoc/>
public void Set(UiConfigOption option, bool value)
=> this.gameConfigService.Set(option, value);

/// <inheritdoc/>
public void Set(UiConfigOption option, uint value)
=> this.gameConfigService.Set(option, value);

/// <inheritdoc/>
public void Set(UiConfigOption option, float value)
=> this.gameConfigService.Set(option, value);

/// <inheritdoc/>
public void Set(UiConfigOption option, string value)
=> this.gameConfigService.Set(option, value);

/// <inheritdoc/>
public void Set(UiControlOption option, bool value)
=> this.gameConfigService.Set(option, value);

/// <inheritdoc/>
public void Set(UiControlOption option, uint value)
=> this.gameConfigService.Set(option, value);

/// <inheritdoc/>
public void Set(UiControlOption option, float value)
=> this.gameConfigService.Set(option, value);

/// <inheritdoc/>
public void Set(UiControlOption option, string value)
=> this.gameConfigService.Set(option, value);

private void ConfigChangedForward(object sender, ConfigChangeEvent data) => this.Changed?.Invoke(sender, data);

private void SystemConfigChangedForward(object sender, ConfigChangeEvent data) => this.SystemChanged?.Invoke(sender, data);

private void UiConfigConfigChangedForward(object sender, ConfigChangeEvent data) => this.UiConfigChanged?.Invoke(sender, data);

private void UiControlConfigChangedForward(object sender, ConfigChangeEvent data) => this.UiControlChanged?.Invoke(sender, data);
}
2 changes: 1 addition & 1 deletion Dalamud/Game/Config/GameConfigSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ internal GameConfigSection(string sectionName, Framework framework, GetConfigBas
/// <summary>
/// Event which is fired when a game config option is changed within the section.
/// </summary>
public event EventHandler<ConfigChangeEvent>? Changed;
internal event EventHandler<ConfigChangeEvent>? Changed;

/// <summary>
/// Gets the number of config entries contained within the section.
Expand Down
17 changes: 16 additions & 1 deletion Dalamud/Plugin/Services/IGameConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,25 @@ namespace Dalamud.Plugin.Services;
public interface IGameConfig
{
/// <summary>
/// Event which is fired when a game config option is changed.
/// Event which is fired when any game config option is changed.
/// </summary>
public event EventHandler<ConfigChangeEvent> Changed;

/// <summary>
/// Event which is fired when a system config option is changed.
/// </summary>
public event EventHandler<ConfigChangeEvent> SystemChanged;

/// <summary>
/// Event which is fired when a UiConfig option is changed.
/// </summary>
public event EventHandler<ConfigChangeEvent> UiConfigChanged;

/// <summary>
/// Event which is fired when a UiControl config option is changed.
/// </summary>
public event EventHandler<ConfigChangeEvent> UiControlChanged;

/// <summary>
/// Gets the collection of config options that persist between characters.
/// </summary>
Expand Down

0 comments on commit 43abb12

Please sign in to comment.