mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-08 00:44:36 +01:00
Misc Fixes (#2584)
* Disable default logging, remove log message * Add IDtrBarEntry.MinimumWidth * Fix Addon/Agent Lifecycle Register/Unregister * Rename Agent.ReceiveEvent2 * Add to IReadOnlyDtrBarEntry * Fix autoformat being terrible * More style fixes * Add focused changed lifecycle event * Fix for obsolete renames
This commit is contained in:
parent
e598013e30
commit
5c7a5295d1
10 changed files with 245 additions and 91 deletions
|
|
@ -0,0 +1,22 @@
|
|||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for OnFocusChanged events.
|
||||
/// </summary>
|
||||
public class AddonFocusChangedArgs : AddonArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AddonFocusChangedArgs"/> class.
|
||||
/// </summary>
|
||||
internal AddonFocusChangedArgs()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override AddonArgsType Type => AddonArgsType.FocusChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the window is being focused or unfocused.
|
||||
/// </summary>
|
||||
public bool ShouldFocus { get; set; }
|
||||
}
|
||||
|
|
@ -44,4 +44,9 @@ public enum AddonArgsType
|
|||
/// Contains argument data for Close.
|
||||
/// </summary>
|
||||
Close,
|
||||
|
||||
/// <summary>
|
||||
/// Contains argument data for OnFocusChanged.
|
||||
/// </summary>
|
||||
FocusChanged,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,4 +203,14 @@ public enum AddonEvent
|
|||
/// Be aware this is only called for certain popup windows, it is not triggered when clicking on windows.
|
||||
/// </remarks>
|
||||
PostFocus,
|
||||
|
||||
/// <summary>
|
||||
/// An event that is fired before an addon processes its FocusChanged method.
|
||||
/// </summary>
|
||||
PreFocusChanged,
|
||||
|
||||
/// <summary>
|
||||
/// An event that is fired after a addon processes its FocusChanged method.
|
||||
/// </summary>
|
||||
PostFocusChanged,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
private readonly Framework framework = Service<Framework>.Get();
|
||||
|
||||
private Hook<AtkUnitBase.Delegates.Initialize>? onInitializeAddonHook;
|
||||
private bool isInvokingListeners = false;
|
||||
private bool isInvokingListeners;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private AddonLifecycle()
|
||||
|
|
@ -56,29 +56,36 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
AllocatedTables.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a virtual table address to the original virtual table address.
|
||||
/// </summary>
|
||||
/// <param name="tableAddress">The modified address to resolve.</param>
|
||||
/// <returns>The original address.</returns>
|
||||
internal static AtkUnitBase.AtkUnitBaseVirtualTable* GetOriginalVirtualTable(AtkUnitBase.AtkUnitBaseVirtualTable* tableAddress)
|
||||
{
|
||||
var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress);
|
||||
if (matchedTable == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return matchedTable.OriginalVirtualTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a listener for the target event and addon.
|
||||
/// </summary>
|
||||
/// <param name="listener">The listener to register.</param>
|
||||
internal void RegisterListener(AddonLifecycleEventListener listener)
|
||||
{
|
||||
this.framework.RunOnTick(() =>
|
||||
if (this.isInvokingListeners)
|
||||
{
|
||||
if (!this.EventListeners.ContainsKey(listener.EventType))
|
||||
{
|
||||
if (!this.EventListeners.TryAdd(listener.EventType, []))
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: string.Empty is a valid addon name, as that will trigger on any addon for this event type
|
||||
if (!this.EventListeners[listener.EventType].ContainsKey(listener.AddonName))
|
||||
{
|
||||
if (!this.EventListeners[listener.EventType].TryAdd(listener.AddonName, []))
|
||||
return;
|
||||
}
|
||||
|
||||
this.EventListeners[listener.EventType][listener.AddonName].Add(listener);
|
||||
}, delayTicks: this.isInvokingListeners ? 1 : 0);
|
||||
this.framework.RunOnTick(() => this.RegisterListenerMethod(listener));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.framework.RunOnFrameworkThread(() => this.RegisterListenerMethod(listener));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -87,16 +94,14 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
/// <param name="listener">The listener to unregister.</param>
|
||||
internal void UnregisterListener(AddonLifecycleEventListener listener)
|
||||
{
|
||||
this.framework.RunOnTick(() =>
|
||||
if (this.isInvokingListeners)
|
||||
{
|
||||
if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners))
|
||||
{
|
||||
if (addonListeners.TryGetValue(listener.AddonName, out var addonListener))
|
||||
{
|
||||
addonListener.Remove(listener);
|
||||
}
|
||||
}
|
||||
}, delayTicks: this.isInvokingListeners ? 1 : 0);
|
||||
this.framework.RunOnTick(() => this.UnregisterListenerMethod(listener));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.framework.RunOnFrameworkThread(() => this.UnregisterListenerMethod(listener));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -147,17 +152,37 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
this.isInvokingListeners = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a virtual table address to the original virtual table address.
|
||||
/// </summary>
|
||||
/// <param name="tableAddress">The modified address to resolve.</param>
|
||||
/// <returns>The original address.</returns>
|
||||
internal AtkUnitBase.AtkUnitBaseVirtualTable* GetOriginalVirtualTable(AtkUnitBase.AtkUnitBaseVirtualTable* tableAddress)
|
||||
private void RegisterListenerMethod(AddonLifecycleEventListener listener)
|
||||
{
|
||||
var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress);
|
||||
if (matchedTable == null) return null;
|
||||
if (!this.EventListeners.ContainsKey(listener.EventType))
|
||||
{
|
||||
if (!this.EventListeners.TryAdd(listener.EventType, []))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return matchedTable.OriginalVirtualTable;
|
||||
// Note: string.Empty is a valid addon name, as that will trigger on any addon for this event type
|
||||
if (!this.EventListeners[listener.EventType].ContainsKey(listener.AddonName))
|
||||
{
|
||||
if (!this.EventListeners[listener.EventType].TryAdd(listener.AddonName, []))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.EventListeners[listener.EventType][listener.AddonName].Add(listener);
|
||||
}
|
||||
|
||||
private void UnregisterListenerMethod(AddonLifecycleEventListener listener)
|
||||
{
|
||||
if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners))
|
||||
{
|
||||
if (addonListeners.TryGetValue(listener.AddonName, out var addonListener))
|
||||
{
|
||||
addonListener.Remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAddonInitialize(AtkUnitBase* addon)
|
||||
|
|
@ -277,5 +302,5 @@ internal class AddonLifecyclePluginScoped : IInternalDisposableService, IAddonLi
|
|||
|
||||
/// <inheritdoc/>
|
||||
public unsafe nint GetOriginalVirtualTable(nint virtualTableAddress)
|
||||
=> (nint)this.addonLifecycleService.GetOriginalVirtualTable((AtkUnitBase.AtkUnitBaseVirtualTable*)virtualTableAddress);
|
||||
=> (nint)AddonLifecycle.GetOriginalVirtualTable((AtkUnitBase.AtkUnitBaseVirtualTable*)virtualTableAddress);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ internal unsafe class AddonVirtualTable : IDisposable
|
|||
private readonly AddonArgs onMouseOverArgs = new();
|
||||
private readonly AddonArgs onMouseOutArgs = new();
|
||||
private readonly AddonArgs focusArgs = new();
|
||||
private readonly AddonFocusChangedArgs focusChangedArgs = new();
|
||||
|
||||
private readonly AtkUnitBase* atkUnitBase;
|
||||
|
||||
|
|
@ -63,6 +64,7 @@ internal unsafe class AddonVirtualTable : IDisposable
|
|||
private readonly AtkUnitBase.Delegates.OnMouseOver onMouseOverFunction;
|
||||
private readonly AtkUnitBase.Delegates.OnMouseOut onMouseOutFunction;
|
||||
private readonly AtkUnitBase.Delegates.Focus focusFunction;
|
||||
private readonly AtkUnitBase.Delegates.OnFocusChange onFocusChangeFunction;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AddonVirtualTable"/> class.
|
||||
|
|
@ -103,6 +105,7 @@ internal unsafe class AddonVirtualTable : IDisposable
|
|||
this.onMouseOverFunction = this.OnAddonMouseOver;
|
||||
this.onMouseOutFunction = this.OnAddonMouseOut;
|
||||
this.focusFunction = this.OnAddonFocus;
|
||||
this.onFocusChangeFunction = this.OnAddonFocusChange;
|
||||
|
||||
// Overwrite specific virtual table entries
|
||||
this.ModifiedVirtualTable->Dtor = (delegate* unmanaged<AtkUnitBase*, byte, AtkEventListener*>)Marshal.GetFunctionPointerForDelegate(this.destructorFunction);
|
||||
|
|
@ -121,6 +124,7 @@ internal unsafe class AddonVirtualTable : IDisposable
|
|||
this.ModifiedVirtualTable->OnMouseOver = (delegate* unmanaged<AtkUnitBase*, void>)Marshal.GetFunctionPointerForDelegate(this.onMouseOverFunction);
|
||||
this.ModifiedVirtualTable->OnMouseOut = (delegate* unmanaged<AtkUnitBase*, void>)Marshal.GetFunctionPointerForDelegate(this.onMouseOutFunction);
|
||||
this.ModifiedVirtualTable->Focus = (delegate* unmanaged<AtkUnitBase*, void>)Marshal.GetFunctionPointerForDelegate(this.focusFunction);
|
||||
this.ModifiedVirtualTable->OnFocusChange = (delegate* unmanaged<AtkUnitBase*, bool, void>)Marshal.GetFunctionPointerForDelegate(this.onFocusChangeFunction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -630,6 +634,36 @@ internal unsafe class AddonVirtualTable : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private void OnAddonFocusChange(AtkUnitBase* thisPtr, bool isFocused)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.LogEvent(EnableLogging);
|
||||
|
||||
this.focusChangedArgs.Addon = thisPtr;
|
||||
this.focusChangedArgs.ShouldFocus = isFocused;
|
||||
|
||||
this.lifecycleService.InvokeListenersSafely(AddonEvent.PreFocusChanged, this.focusChangedArgs);
|
||||
|
||||
isFocused = this.focusChangedArgs.ShouldFocus;
|
||||
|
||||
try
|
||||
{
|
||||
this.OriginalVirtualTable->OnFocusChange(thisPtr, isFocused);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Caught exception when calling original Addon OnFocusChanged. This may be a bug in the game or another plugin hooking this method.");
|
||||
}
|
||||
|
||||
this.lifecycleService.InvokeListenersSafely(AddonEvent.PostFocusChanged, this.focusChangedArgs);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Caught exception from Dalamud when attempting to process OnAddonFocusChange.");
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void LogEvent(bool loggingEnabled, [CallerMemberName] string caller = "")
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ public enum AgentEvent
|
|||
/// <summary>
|
||||
/// An event that is fired before the agent processes its Filtered Receive Event Function.
|
||||
/// </summary>
|
||||
PreReceiveFilteredEvent,
|
||||
PreReceiveEventWithResult,
|
||||
|
||||
/// <summary>
|
||||
/// An event that is fired after the agent has processed its Filtered Receive Event Function.
|
||||
/// </summary>
|
||||
PostReceiveFilteredEvent,
|
||||
PostReceiveEventWithResult,
|
||||
|
||||
/// <summary>
|
||||
/// An event that is fired before the agent processes its Show Function.
|
||||
|
|
|
|||
|
|
@ -69,30 +69,36 @@ internal unsafe class AgentLifecycle : IInternalDisposableService
|
|||
AllocatedTables.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a virtual table address to the original virtual table address.
|
||||
/// </summary>
|
||||
/// <param name="tableAddress">The modified address to resolve.</param>
|
||||
/// <returns>The original address.</returns>
|
||||
internal static AgentInterface.AgentInterfaceVirtualTable* GetOriginalVirtualTable(AgentInterface.AgentInterfaceVirtualTable* tableAddress)
|
||||
{
|
||||
var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress);
|
||||
if (matchedTable == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return matchedTable.OriginalVirtualTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a listener for the target event and agent.
|
||||
/// </summary>
|
||||
/// <param name="listener">The listener to register.</param>
|
||||
internal void RegisterListener(AgentLifecycleEventListener listener)
|
||||
{
|
||||
this.framework.RunOnTick(() =>
|
||||
if (this.isInvokingListeners)
|
||||
{
|
||||
if (!this.EventListeners.ContainsKey(listener.EventType))
|
||||
{
|
||||
if (!this.EventListeners.TryAdd(listener.EventType, []))
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: uint.MaxValue is a valid agent id, as that will trigger on any agent for this event type
|
||||
if (!this.EventListeners[listener.EventType].ContainsKey(listener.AgentId))
|
||||
{
|
||||
if (!this.EventListeners[listener.EventType].TryAdd(listener.AgentId, []))
|
||||
return;
|
||||
}
|
||||
|
||||
this.EventListeners[listener.EventType][listener.AgentId].Add(listener);
|
||||
},
|
||||
delayTicks: this.isInvokingListeners ? 1 : 0);
|
||||
this.framework.RunOnTick(() => this.RegisterListenerMethod(listener));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.framework.RunOnFrameworkThread(() => this.RegisterListenerMethod(listener));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -101,17 +107,14 @@ internal unsafe class AgentLifecycle : IInternalDisposableService
|
|||
/// <param name="listener">The listener to unregister.</param>
|
||||
internal void UnregisterListener(AgentLifecycleEventListener listener)
|
||||
{
|
||||
this.framework.RunOnTick(() =>
|
||||
if (this.isInvokingListeners)
|
||||
{
|
||||
if (this.EventListeners.TryGetValue(listener.EventType, out var agentListeners))
|
||||
{
|
||||
if (agentListeners.TryGetValue(listener.AgentId, out var agentListener))
|
||||
{
|
||||
agentListener.Remove(listener);
|
||||
}
|
||||
}
|
||||
},
|
||||
delayTicks: this.isInvokingListeners ? 1 : 0);
|
||||
this.framework.RunOnTick(() => this.UnregisterListenerMethod(listener));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.framework.RunOnFrameworkThread(() => this.UnregisterListenerMethod(listener));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -162,19 +165,6 @@ internal unsafe class AgentLifecycle : IInternalDisposableService
|
|||
this.isInvokingListeners = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a virtual table address to the original virtual table address.
|
||||
/// </summary>
|
||||
/// <param name="tableAddress">The modified address to resolve.</param>
|
||||
/// <returns>The original address.</returns>
|
||||
internal AgentInterface.AgentInterfaceVirtualTable* GetOriginalVirtualTable(AgentInterface.AgentInterfaceVirtualTable* tableAddress)
|
||||
{
|
||||
var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress);
|
||||
if (matchedTable == null) return null;
|
||||
|
||||
return matchedTable.OriginalVirtualTable;
|
||||
}
|
||||
|
||||
private void OnAgentModuleInitialize(AgentModule* thisPtr, UIModule* uiModule)
|
||||
{
|
||||
this.onInitializeAgentsHook!.Original(thisPtr, uiModule);
|
||||
|
|
@ -193,6 +183,39 @@ internal unsafe class AgentLifecycle : IInternalDisposableService
|
|||
}
|
||||
}
|
||||
|
||||
private void RegisterListenerMethod(AgentLifecycleEventListener listener)
|
||||
{
|
||||
if (!this.EventListeners.ContainsKey(listener.EventType))
|
||||
{
|
||||
if (!this.EventListeners.TryAdd(listener.EventType, []))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: uint.MaxValue is a valid agent id, as that will trigger on any agent for this event type
|
||||
if (!this.EventListeners[listener.EventType].ContainsKey(listener.AgentId))
|
||||
{
|
||||
if (!this.EventListeners[listener.EventType].TryAdd(listener.AgentId, []))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.EventListeners[listener.EventType][listener.AgentId].Add(listener);
|
||||
}
|
||||
|
||||
private void UnregisterListenerMethod(AgentLifecycleEventListener listener)
|
||||
{
|
||||
if (this.EventListeners.TryGetValue(listener.EventType, out var agentListeners))
|
||||
{
|
||||
if (agentListeners.TryGetValue(listener.AgentId, out var agentListener))
|
||||
{
|
||||
agentListener.Remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReplaceVirtualTables(AgentModule* agentModule)
|
||||
{
|
||||
foreach (uint index in Enumerable.Range(0, agentModule->Agents.Length))
|
||||
|
|
@ -311,5 +334,5 @@ internal class AgentLifecyclePluginScoped : IInternalDisposableService, IAgentLi
|
|||
|
||||
/// <inheritdoc/>
|
||||
public unsafe nint GetOriginalVirtualTable(nint virtualTableAddress)
|
||||
=> (nint)this.agentLifecycleService.GetOriginalVirtualTable((AgentInterface.AgentInterfaceVirtualTable*)virtualTableAddress);
|
||||
=> (nint)AgentLifecycle.GetOriginalVirtualTable((AgentInterface.AgentInterfaceVirtualTable*)virtualTableAddress);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ internal unsafe class AgentVirtualTable : IDisposable
|
|||
// Copying extra entries is not problematic, and is considered safe.
|
||||
private const int VirtualTableEntryCount = 60;
|
||||
|
||||
private const bool EnableLogging = true;
|
||||
private const bool EnableLogging = false;
|
||||
|
||||
private static readonly ModuleLog Log = new("AgentVT");
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ internal unsafe class AgentVirtualTable : IDisposable
|
|||
// Pinned Function Delegates, as these functions get assigned to an unmanaged virtual table,
|
||||
// the CLR needs to know they are in use, or it will invalidate them causing random crashing.
|
||||
private readonly AgentInterface.Delegates.ReceiveEvent receiveEventFunction;
|
||||
private readonly AgentInterface.Delegates.ReceiveEvent2 filteredReceiveEventFunction;
|
||||
private readonly AgentInterface.Delegates.ReceiveEventWithResult receiveEventWithResultFunction;
|
||||
private readonly AgentInterface.Delegates.Show showFunction;
|
||||
private readonly AgentInterface.Delegates.Hide hideFunction;
|
||||
private readonly AgentInterface.Delegates.Update updateFunction;
|
||||
|
|
@ -60,8 +60,6 @@ internal unsafe class AgentVirtualTable : IDisposable
|
|||
/// <param name="lifecycleService">Reference to AgentLifecycle service to callback and invoke listeners.</param>
|
||||
internal AgentVirtualTable(AgentInterface* agent, AgentId agentId, AgentLifecycle lifecycleService)
|
||||
{
|
||||
Log.Debug($"Initializing AgentVirtualTable for {agentId}, Address: {(nint)agent:X}");
|
||||
|
||||
this.agentInterface = agent;
|
||||
this.agentId = agentId;
|
||||
this.lifecycleService = lifecycleService;
|
||||
|
|
@ -80,7 +78,7 @@ internal unsafe class AgentVirtualTable : IDisposable
|
|||
|
||||
// Pin each of our listener functions
|
||||
this.receiveEventFunction = this.OnAgentReceiveEvent;
|
||||
this.filteredReceiveEventFunction = this.OnAgentFilteredReceiveEvent;
|
||||
this.receiveEventWithResultFunction = this.OnAgentReceiveEventWithResult;
|
||||
this.showFunction = this.OnAgentShow;
|
||||
this.hideFunction = this.OnAgentHide;
|
||||
this.updateFunction = this.OnAgentUpdate;
|
||||
|
|
@ -90,7 +88,7 @@ internal unsafe class AgentVirtualTable : IDisposable
|
|||
|
||||
// Overwrite specific virtual table entries
|
||||
this.ModifiedVirtualTable->ReceiveEvent = (delegate* unmanaged<AgentInterface*, AtkValue*, AtkValue*, uint, ulong, AtkValue*>)Marshal.GetFunctionPointerForDelegate(this.receiveEventFunction);
|
||||
this.ModifiedVirtualTable->ReceiveEvent2 = (delegate* unmanaged<AgentInterface*, AtkValue*, AtkValue*, uint, ulong, AtkValue*>)Marshal.GetFunctionPointerForDelegate(this.filteredReceiveEventFunction);
|
||||
this.ModifiedVirtualTable->ReceiveEventWithResult = (delegate* unmanaged<AgentInterface*, AtkValue*, AtkValue*, uint, ulong, AtkValue*>)Marshal.GetFunctionPointerForDelegate(this.receiveEventWithResultFunction);
|
||||
this.ModifiedVirtualTable->Show = (delegate* unmanaged<AgentInterface*, void>)Marshal.GetFunctionPointerForDelegate(this.showFunction);
|
||||
this.ModifiedVirtualTable->Hide = (delegate* unmanaged<AgentInterface*, void>)Marshal.GetFunctionPointerForDelegate(this.hideFunction);
|
||||
this.ModifiedVirtualTable->Update = (delegate* unmanaged<AgentInterface*, uint, void>)Marshal.GetFunctionPointerForDelegate(this.updateFunction);
|
||||
|
|
@ -158,7 +156,7 @@ internal unsafe class AgentVirtualTable : IDisposable
|
|||
return result;
|
||||
}
|
||||
|
||||
private AtkValue* OnAgentFilteredReceiveEvent(AgentInterface* thisPtr, AtkValue* returnValue, AtkValue* values, uint valueCount, ulong eventKind)
|
||||
private AtkValue* OnAgentReceiveEventWithResult(AgentInterface* thisPtr, AtkValue* returnValue, AtkValue* values, uint valueCount, ulong eventKind)
|
||||
{
|
||||
AtkValue* result = null;
|
||||
|
||||
|
|
@ -173,7 +171,7 @@ internal unsafe class AgentVirtualTable : IDisposable
|
|||
this.filteredReceiveEventArgs.ValueCount = valueCount;
|
||||
this.filteredReceiveEventArgs.EventKind = eventKind;
|
||||
|
||||
this.lifecycleService.InvokeListenersSafely(AgentEvent.PreReceiveFilteredEvent, this.filteredReceiveEventArgs);
|
||||
this.lifecycleService.InvokeListenersSafely(AgentEvent.PreReceiveEventWithResult, this.filteredReceiveEventArgs);
|
||||
|
||||
returnValue = (AtkValue*)this.filteredReceiveEventArgs.ReturnValue;
|
||||
values = (AtkValue*)this.filteredReceiveEventArgs.AtkValues;
|
||||
|
|
@ -182,18 +180,18 @@ internal unsafe class AgentVirtualTable : IDisposable
|
|||
|
||||
try
|
||||
{
|
||||
result = this.OriginalVirtualTable->ReceiveEvent2(thisPtr, returnValue, values, valueCount, eventKind);
|
||||
result = this.OriginalVirtualTable->ReceiveEventWithResult(thisPtr, returnValue, values, valueCount, eventKind);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Caught exception when calling original Agent FilteredReceiveEvent. This may be a bug in the game or another plugin hooking this method.");
|
||||
}
|
||||
|
||||
this.lifecycleService.InvokeListenersSafely(AgentEvent.PostReceiveFilteredEvent, this.filteredReceiveEventArgs);
|
||||
this.lifecycleService.InvokeListenersSafely(AgentEvent.PostReceiveEventWithResult, this.filteredReceiveEventArgs);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Caught exception from Dalamud when attempting to process OnAgentFilteredReceiveEvent.");
|
||||
Log.Error(e, "Caught exception from Dalamud when attempting to process OnAgentReceiveEventWithResult.");
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -397,7 +397,15 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
|
||||
ushort w = 0, h = 0;
|
||||
node->GetTextDrawSize(&w, &h, node->NodeText.StringPtr);
|
||||
node->SetWidth(w);
|
||||
|
||||
if (data.MinimumWidth > 0)
|
||||
{
|
||||
node->SetWidth(Math.Max(data.MinimumWidth, w));
|
||||
}
|
||||
else
|
||||
{
|
||||
node->SetWidth(w);
|
||||
}
|
||||
}
|
||||
|
||||
var elementWidth = data.TextNode->Width + this.configuration.DtrSpacing;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ public interface IReadOnlyDtrBarEntry
|
|||
/// </summary>
|
||||
public bool Shown { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating this entry's minimum width.
|
||||
/// </summary>
|
||||
public ushort MinimumWidth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the user has hidden this entry from view through the Dalamud settings.
|
||||
/// </summary>
|
||||
|
|
@ -76,6 +81,11 @@ public interface IDtrBarEntry : IReadOnlyDtrBarEntry
|
|||
/// </summary>
|
||||
public new bool Shown { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value specifying the requested minimum width to make this entry.
|
||||
/// </summary>
|
||||
public new ushort MinimumWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an action to be invoked when the user clicks on the dtr entry.
|
||||
/// </summary>
|
||||
|
|
@ -128,6 +138,25 @@ internal sealed unsafe class DtrBarEntry : IDisposable, IDtrBarEntry
|
|||
/// <inheritdoc cref="IDtrBarEntry.Tooltip" />
|
||||
public SeString? Tooltip { get; set; }
|
||||
|
||||
/// <inheritdoc cref="MinimumWidth" />
|
||||
public ushort MinimumWidth
|
||||
{
|
||||
get;
|
||||
set
|
||||
{
|
||||
field = value;
|
||||
if (this.TextNode is not null)
|
||||
{
|
||||
if (this.TextNode->GetWidth() < value)
|
||||
{
|
||||
this.TextNode->SetWidth(value);
|
||||
}
|
||||
}
|
||||
|
||||
this.Dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Action<DtrInteractionEvent>? OnClick { get; set; }
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue