Add GameConfigPluginScoped (#1383)

* Add GameConfigPluginScoped

* Proposed Resolution to sub-object events

* Nullify delegates to prevent memory leaks
This commit is contained in:
MidoriKami 2023-09-21 21:55:56 -07:00 committed by GitHub
parent b742abe77f
commit 43abb12710
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 235 additions and 8 deletions

View file

@ -12,11 +12,7 @@ namespace Dalamud.Game.Config;
/// This class represents the game's configuration. /// This class represents the game's configuration.
/// </summary> /// </summary>
[InterfaceVersion("1.0")] [InterfaceVersion("1.0")]
[PluginInterface]
[ServiceManager.EarlyLoadedService] [ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IGameConfig>]
#pragma warning restore SA1015
internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
{ {
private readonly GameConfigAddressResolver address = new(); private readonly GameConfigAddressResolver address = new();
@ -36,15 +32,30 @@ internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
this.address.Setup(sigScanner); this.address.Setup(sigScanner);
this.configChangeHook = Hook<ConfigChangeDelegate>.FromAddress(this.address.ConfigChangeAddress, this.OnConfigChanged); 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); private unsafe delegate nint ConfigChangeDelegate(ConfigBase* configBase, ConfigEntry* configEntry);
/// <inheritdoc/> /// <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/> /// <inheritdoc/>
public GameConfigSection System { get; private set; } public GameConfigSection System { get; private set; }
@ -192,3 +203,204 @@ internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
return returnValue; 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);
}

View file

@ -51,7 +51,7 @@ public class GameConfigSection
/// <summary> /// <summary>
/// Event which is fired when a game config option is changed within the section. /// Event which is fired when a game config option is changed within the section.
/// </summary> /// </summary>
public event EventHandler<ConfigChangeEvent>? Changed; internal event EventHandler<ConfigChangeEvent>? Changed;
/// <summary> /// <summary>
/// Gets the number of config entries contained within the section. /// Gets the number of config entries contained within the section.

View file

@ -12,10 +12,25 @@ namespace Dalamud.Plugin.Services;
public interface IGameConfig public interface IGameConfig
{ {
/// <summary> /// <summary>
/// Event which is fired when a game config option is changed. /// Event which is fired when any game config option is changed.
/// </summary> /// </summary>
public event EventHandler<ConfigChangeEvent> Changed; 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> /// <summary>
/// Gets the collection of config options that persist between characters. /// Gets the collection of config options that persist between characters.
/// </summary> /// </summary>