mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Config change event (#1301)
* Add events for config changes * Update ConfigChangeEvent.cs * change event names --------- Co-authored-by: goat <16760685+goaaats@users.noreply.github.com>
This commit is contained in:
parent
e52f7696ba
commit
7109f21387
5 changed files with 131 additions and 5 deletions
7
Dalamud/Game/Config/ConfigChangeEvent.cs
Normal file
7
Dalamud/Game/Config/ConfigChangeEvent.cs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.Config;
|
||||
|
||||
public abstract record ConfigChangeEvent(Enum Option);
|
||||
|
||||
public record ConfigChangeEvent<T>(T ConfigOption) : ConfigChangeEvent(ConfigOption) where T : Enum;
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
using Dalamud.IoC;
|
||||
using System;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Common.Configuration;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.Config;
|
||||
|
|
@ -14,10 +18,13 @@ namespace Dalamud.Game.Config;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGameConfig>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed class GameConfig : IServiceType, IGameConfig
|
||||
public sealed class GameConfig : IServiceType, IGameConfig, IDisposable
|
||||
{
|
||||
private readonly GameConfigAddressResolver address = new();
|
||||
private Hook<ConfigChangeDelegate>? configChangeHook;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private unsafe GameConfig(Framework framework)
|
||||
private unsafe GameConfig(Framework framework, SigScanner sigScanner)
|
||||
{
|
||||
framework.RunOnTick(() =>
|
||||
{
|
||||
|
|
@ -27,9 +34,18 @@ public sealed class GameConfig : IServiceType, IGameConfig
|
|||
this.System = new GameConfigSection("System", framework, &commonConfig->ConfigBase);
|
||||
this.UiConfig = new GameConfigSection("UiConfig", framework, &commonConfig->UiConfig);
|
||||
this.UiControl = new GameConfigSection("UiControl", framework, () => this.UiConfig.TryGetBool("PadMode", out var padMode) && padMode ? &commonConfig->UiControlGamepadConfig : &commonConfig->UiControlConfig);
|
||||
|
||||
this.address.Setup(sigScanner);
|
||||
this.configChangeHook = Hook<ConfigChangeDelegate>.FromAddress(this.address.ConfigChangeAddress, this.OnConfigChanged);
|
||||
this.configChangeHook?.Enable();
|
||||
});
|
||||
}
|
||||
|
||||
private unsafe delegate nint ConfigChangeDelegate(ConfigBase* configBase, ConfigEntry* configEntry);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ConfigChangeEvent> Changed;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GameConfigSection System { get; private set; }
|
||||
|
||||
|
|
@ -110,4 +126,43 @@ public sealed class GameConfig : IServiceType, IGameConfig
|
|||
|
||||
/// <inheritdoc/>
|
||||
public void Set(UiControlOption option, string value) => this.UiControl.Set(option.GetName(), value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
this.configChangeHook?.Disable();
|
||||
this.configChangeHook?.Dispose();
|
||||
}
|
||||
|
||||
private unsafe nint OnConfigChanged(ConfigBase* configBase, ConfigEntry* configEntry)
|
||||
{
|
||||
var returnValue = this.configChangeHook!.Original(configBase, configEntry);
|
||||
try
|
||||
{
|
||||
ConfigChangeEvent? eventArgs = null;
|
||||
|
||||
if (configBase == this.System.GetConfigBase())
|
||||
{
|
||||
eventArgs = this.System.InvokeChange<SystemConfigOption>(configEntry);
|
||||
}
|
||||
else if (configBase == this.UiConfig.GetConfigBase())
|
||||
{
|
||||
eventArgs = this.UiConfig.InvokeChange<UiConfigOption>(configEntry);
|
||||
}
|
||||
else if (configBase == this.UiControl.GetConfigBase())
|
||||
{
|
||||
eventArgs = this.UiControl.InvokeChange<UiControlOption>(configEntry);
|
||||
}
|
||||
|
||||
if (eventArgs == null) return returnValue;
|
||||
|
||||
this.Changed?.InvokeSafely(this, eventArgs);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Exception thrown handing {nameof(this.OnConfigChanged)} events.");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
18
Dalamud/Game/Config/GameConfigAddressResolver.cs
Normal file
18
Dalamud/Game/Config/GameConfigAddressResolver.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
namespace Dalamud.Game.Config;
|
||||
|
||||
/// <summary>
|
||||
/// Game config system address resolver.
|
||||
/// </summary>
|
||||
public sealed class GameConfigAddressResolver : BaseAddressResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of the method called when any config option is changed.
|
||||
/// </summary>
|
||||
public nint ConfigChangeAddress { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Setup64Bit(SigScanner scanner)
|
||||
{
|
||||
this.ConfigChangeAddress = scanner.ScanText("E8 ?? ?? ?? ?? 48 8B 3F 49 3B 3E");
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Common.Configuration;
|
||||
using Serilog;
|
||||
|
||||
|
|
@ -16,6 +17,12 @@ public class GameConfigSection
|
|||
private readonly Framework framework;
|
||||
private readonly Dictionary<string, uint> indexMap = new();
|
||||
private readonly Dictionary<uint, string> nameMap = new();
|
||||
private readonly Dictionary<uint, object> enumMap = new();
|
||||
|
||||
/// <summary>
|
||||
/// Event which is fired when a game config option is changed within the section.
|
||||
/// </summary>
|
||||
public event EventHandler<ConfigChangeEvent> Changed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameConfigSection"/> class.
|
||||
|
|
@ -59,7 +66,10 @@ public class GameConfigSection
|
|||
/// </summary>
|
||||
public string SectionName { get; }
|
||||
|
||||
private GetConfigBaseDelegate GetConfigBase { get; }
|
||||
/// <summary>
|
||||
/// Gets the pointer to the config section container.
|
||||
/// </summary>
|
||||
internal GetConfigBaseDelegate GetConfigBase { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to get a boolean config option.
|
||||
|
|
@ -380,6 +390,35 @@ public class GameConfigSection
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes a change event within the config section.
|
||||
/// </summary>
|
||||
/// <param name="entry">The config entry that was changed.</param>
|
||||
/// <typeparam name="TEnum">SystemConfigOption, UiConfigOption, or UiControlOption.</typeparam>
|
||||
/// <returns>The ConfigChangeEvent record.</returns>
|
||||
internal unsafe ConfigChangeEvent? InvokeChange<TEnum>(ConfigEntry* entry) where TEnum : Enum
|
||||
{
|
||||
if (!this.enumMap.TryGetValue(entry->Index, out var enumObject))
|
||||
{
|
||||
if (entry->Name == null) return null;
|
||||
var name = MemoryHelper.ReadStringNullTerminated(new IntPtr(entry->Name));
|
||||
if (Enum.TryParse(typeof(TEnum), name, out enumObject))
|
||||
{
|
||||
this.enumMap.Add(entry->Index, enumObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
enumObject = null;
|
||||
this.enumMap.Add(entry->Index, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (enumObject == null) return null;
|
||||
var eventArgs = new ConfigChangeEvent<TEnum>((TEnum)enumObject);
|
||||
this.Changed?.InvokeSafely(this, eventArgs);
|
||||
return eventArgs;
|
||||
}
|
||||
|
||||
private unsafe bool TryGetIndex(string name, out uint index)
|
||||
{
|
||||
if (this.indexMap.TryGetValue(name, out index))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
using Dalamud.Game.Config;
|
||||
using FFXIVClientStructs.FFXIV.Common.Configuration;
|
||||
|
||||
namespace Dalamud.Plugin.Services;
|
||||
|
||||
|
|
@ -9,6 +11,11 @@ namespace Dalamud.Plugin.Services;
|
|||
/// </summary>
|
||||
public interface IGameConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Event which is fired when a game config option is changed.
|
||||
/// </summary>
|
||||
public event EventHandler<ConfigChangeEvent> Changed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of config options that persist between characters.
|
||||
/// </summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue