refactor: ContextMenus cleanup, docs

This commit is contained in:
goaaats 2022-01-28 23:50:06 +01:00
parent 4aebbfa2cb
commit 7a242c962a
No known key found for this signature in database
GPG key ID: 49E2AA8C6A76498B
14 changed files with 179 additions and 135 deletions

View file

@ -12,7 +12,7 @@ using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using Serilog; using Serilog;
using SignatureHelper = Dalamud.Utility.Signatures.SignatureHelper;
using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
namespace Dalamud.Game.Gui.ContextMenus namespace Dalamud.Game.Gui.ContextMenus
@ -48,7 +48,6 @@ namespace Dalamud.Game.Gui.ContextMenus
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ContextMenu"/> class. /// Initializes a new instance of the <see cref="ContextMenu"/> class.
/// </summary> /// </summary>
/// <param name="address">Address resolver for context menu hooks.</param>
public ContextMenu() public ContextMenu()
{ {
this.Address = new ContextMenuAddressResolver(); this.Address = new ContextMenuAddressResolver();
@ -66,7 +65,6 @@ namespace Dalamud.Game.Gui.ContextMenus
} }
} }
#region Delegates #region Delegates
private unsafe delegate bool OpenSubContextMenuDelegate(AgentContext* agentContext); private unsafe delegate bool OpenSubContextMenuDelegate(AgentContext* agentContext);

View file

@ -2,9 +2,11 @@
namespace Dalamud.Game.Gui.ContextMenus namespace Dalamud.Game.Gui.ContextMenus
{ {
/// <summary>
/// Address resolver for context menu functions.
/// </summary>
public class ContextMenuAddressResolver : BaseAddressResolver public class ContextMenuAddressResolver : BaseAddressResolver
{ {
private const string SigOpenSubContextMenu = "E8 ?? ?? ?? ?? 44 39 A3 ?? ?? ?? ?? 0F 86"; private const string SigOpenSubContextMenu = "E8 ?? ?? ?? ?? 44 39 A3 ?? ?? ?? ?? 0F 86";
private const string SigContextMenuOpening = "E8 ?? ?? ?? ?? 0F B7 C0 48 83 C4 60"; private const string SigContextMenuOpening = "E8 ?? ?? ?? ?? 0F B7 C0 48 83 C4 60";
private const string SigContextMenuOpened = "48 8B C4 57 41 56 41 57 48 81 EC"; private const string SigContextMenuOpened = "48 8B C4 57 41 56 41 57 48 81 EC";
@ -12,18 +14,37 @@ namespace Dalamud.Game.Gui.ContextMenus
private const string SigSubContextMenuOpening = "E8 ?? ?? ?? ?? 44 39 A3 ?? ?? ?? ?? 0F 84"; private const string SigSubContextMenuOpening = "E8 ?? ?? ?? ?? 44 39 A3 ?? ?? ?? ?? 0F 84";
private const string SigSubContextMenuOpened = "48 8B C4 57 41 55 41 56 48 81 EC"; private const string SigSubContextMenuOpened = "48 8B C4 57 41 55 41 56 48 81 EC";
/// <summary>
/// Gets the OpenSubContextMenu function address.
/// </summary>
public IntPtr OpenSubContextMenuPtr { get; private set; } public IntPtr OpenSubContextMenuPtr { get; private set; }
/// <summary>
/// Gets the ContextMenuOpening function address.
/// </summary>
public IntPtr ContextMenuOpeningPtr { get; private set; } public IntPtr ContextMenuOpeningPtr { get; private set; }
/// <summary>
/// Gets the ContextMenuOpened function address.
/// </summary>
public IntPtr ContextMenuOpenedPtr { get; private set; } public IntPtr ContextMenuOpenedPtr { get; private set; }
/// <summary>
/// Gets the ContextMenuItemSelected function address.
/// </summary>
public IntPtr ContextMenuItemSelectedPtr { get; private set; } public IntPtr ContextMenuItemSelectedPtr { get; private set; }
/// <summary>
/// Gets the SubContextMenuOpening function address.
/// </summary>
public IntPtr SubContextMenuOpeningPtr { get; private set; } public IntPtr SubContextMenuOpeningPtr { get; private set; }
/// <summary>
/// Gets the SubContextMenuOpened function address.
/// </summary>
public IntPtr SubContextMenuOpenedPtr { get; private set; } public IntPtr SubContextMenuOpenedPtr { get; private set; }
/// <inheritdoc/>
protected override void Setup64Bit(SigScanner scanner) protected override void Setup64Bit(SigScanner scanner)
{ {
this.OpenSubContextMenuPtr = scanner.ScanText(SigOpenSubContextMenu); this.OpenSubContextMenuPtr = scanner.ScanText(SigOpenSubContextMenu);

View file

@ -1,7 +1,6 @@
using System.Numerics; using System.Numerics;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
namespace Dalamud.Game.Gui.ContextMenus namespace Dalamud.Game.Gui.ContextMenus
{ {

View file

@ -9,13 +9,15 @@
/// The item has no indicator. /// The item has no indicator.
/// </summary> /// </summary>
None, None,
/// <summary> /// <summary>
/// The item has a previous indicator. /// The item has a previous indicator.
/// </summary> /// </summary>
Previous, Previous,
/// <summary> /// <summary>
/// The item has a next indicator. /// The item has a next indicator.
/// </summary> /// </summary>
Next Next,
} }
} }

View file

@ -1,8 +1,7 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using FFXIVClientStructs.FFXIV.Component.GUI;
namespace Dalamud.Game.Gui.ContextMenus namespace Dalamud.Game.Gui.ContextMenus
{ {

View file

@ -14,6 +14,9 @@ using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
namespace Dalamud.Game.Gui.ContextMenus namespace Dalamud.Game.Gui.ContextMenus
{ {
/// <summary>
/// Class responsible for reading and writing to context menu data.
/// </summary>
internal unsafe class ContextMenuReaderWriter internal unsafe class ContextMenuReaderWriter
{ {
private readonly AgentContextInterface* agentContextInterface; private readonly AgentContextInterface* agentContextInterface;
@ -42,12 +45,24 @@ namespace Dalamud.Game.Gui.ContextMenus
Alternate, Alternate,
} }
/// <summary>
/// Gets the number of AtkValues for this context menu.
/// </summary>
public int AtkValueCount => this.atkValueCount; public int AtkValueCount => this.atkValueCount;
/// <summary>
/// Gets the AtkValues for this context menu.
/// </summary>
public AtkValue* AtkValues => this.atkValues; public AtkValue* AtkValues => this.atkValues;
/// <summary>
/// Gets the amount of items in the context menu.
/// </summary>
public int ContextMenuItemCount => this.atkValues[0].Int; public int ContextMenuItemCount => this.atkValues[0].Int;
/// <summary>
/// Gets a value indicating whether the context menu has a title.
/// </summary>
public bool HasTitle public bool HasTitle
{ {
get get
@ -61,6 +76,9 @@ namespace Dalamud.Game.Gui.ContextMenus
} }
} }
/// <summary>
/// Gets the title of the context menu.
/// </summary>
public SeString? Title public SeString? Title
{ {
get get
@ -75,32 +93,9 @@ namespace Dalamud.Game.Gui.ContextMenus
} }
} }
public int HasPreviousIndicatorFlagsIndex /// <summary>
{ /// Gets the index of the first context menu item.
get /// </summary>
{
if (this.HasTitle)
{
return 6;
}
return 2;
}
}
public int HasNextIndicatorFlagsIndex
{
get
{
if (this.HasTitle)
{
return 5;
}
return 3;
}
}
public int FirstContextMenuItemIndex public int FirstContextMenuItemIndex
{ {
get get
@ -114,7 +109,46 @@ namespace Dalamud.Game.Gui.ContextMenus
} }
} }
public int NameIndexOffset /// <summary>
/// Gets the position of the context menu.
/// </summary>
public Vector2? Position
{
get
{
if (this.HasTitle) return new Vector2(this.atkValues[2].Int, this.atkValues[3].Int);
return null;
}
}
private int HasPreviousIndicatorFlagsIndex
{
get
{
if (this.HasTitle)
{
return 6;
}
return 2;
}
}
private int HasNextIndicatorFlagsIndex
{
get
{
if (this.HasTitle)
{
return 5;
}
return 3;
}
}
private int NameIndexOffset
{ {
get get
{ {
@ -127,7 +161,7 @@ namespace Dalamud.Game.Gui.ContextMenus
} }
} }
public int IsDisabledIndexOffset private int IsDisabledIndexOffset
{ {
get get
{ {
@ -140,6 +174,7 @@ namespace Dalamud.Game.Gui.ContextMenus
} }
} }
/*
/// <summary> /// <summary>
/// 0x14000000 | action /// 0x14000000 | action
/// </summary> /// </summary>
@ -152,8 +187,9 @@ namespace Dalamud.Game.Gui.ContextMenus
return null; return null;
} }
} }
*/
public int SequentialAtkValuesPerContextMenuItem private int SequentialAtkValuesPerContextMenuItem
{ {
get get
{ {
@ -163,7 +199,7 @@ namespace Dalamud.Game.Gui.ContextMenus
} }
} }
public int TotalDesiredAtkValuesPerContextMenuItem private int TotalDesiredAtkValuesPerContextMenuItem
{ {
get get
{ {
@ -173,17 +209,7 @@ namespace Dalamud.Game.Gui.ContextMenus
} }
} }
public Vector2? Position private bool IsInventoryContext
{
get
{
if (this.HasTitle) return new Vector2(this.atkValues[2].Int, this.atkValues[3].Int);
return null;
}
}
public unsafe bool IsInventoryContext
{ {
get get
{ {
@ -200,58 +226,48 @@ namespace Dalamud.Game.Gui.ContextMenus
{ {
get get
{ {
if (HasTitle) if (this.HasTitle)
{ {
if (this.atkValues[7].Int == 8) if (this.atkValues[7].Int == 8)
{
return SubContextMenuStructLayout.Alternate; return SubContextMenuStructLayout.Alternate;
}
else if (this.atkValues[7].Int == 1) if (this.atkValues[7].Int == 1) return SubContextMenuStructLayout.Main;
{
return SubContextMenuStructLayout.Main;
}
} }
return null; return null;
} }
} }
public byte NoopAction private byte NoopAction
{ {
get get
{ {
if (IsInventoryContext) if (this.IsInventoryContext)
{
return 0xff; return 0xff;
} return 0x67;
else
{
return 0x67;
}
} }
} }
public byte OpenSubContextMenuAction private byte OpenSubContextMenuAction
{ {
get get
{ {
if (IsInventoryContext) if (this.IsInventoryContext)
{ {
// This is actually the action to open the Second Tier context menu and we just hack around it // This is actually the action to open the Second Tier context menu and we just hack around it
return 0x31; return 0x31;
} }
else
{ return 0x66;
return 0x66;
}
} }
} }
public byte? FirstUnhandledAction private byte? FirstUnhandledAction
{ {
get get
{ {
if (this.StructLayout is SubContextMenuStructLayout.Alternate) return 0x68; if (this.StructLayout is SubContextMenuStructLayout.Alternate)
return 0x68;
return null; return null;
} }
@ -334,6 +350,11 @@ namespace Dalamud.Game.Gui.ContextMenus
return gameContextMenuItems.ToArray(); return gameContextMenuItems.ToArray();
} }
/// <summary>
/// Write items to the context menu.
/// </summary>
/// <param name="contextMenuItems">The items to write.</param>
/// <param name="allowReallocate">Whether or not reallocation is allowed.</param>
public void Write(IEnumerable<ContextMenuItem> contextMenuItems, bool allowReallocate = true) public void Write(IEnumerable<ContextMenuItem> contextMenuItems, bool allowReallocate = true)
{ {
if (allowReallocate) if (allowReallocate)
@ -353,7 +374,7 @@ namespace Dalamud.Game.Gui.ContextMenus
// Zero the memory, then copy the atk values up to the first context menu item atk value // Zero the memory, then copy the atk values up to the first context menu item atk value
Marshal.Copy(new byte[newAtkValuesArraySize], 0, newAtkValuesArray, newAtkValuesArraySize); Marshal.Copy(new byte[newAtkValuesArraySize], 0, newAtkValuesArray, newAtkValuesArraySize);
Buffer.MemoryCopy(this.atkValues, newAtkValues, newAtkValuesArraySize - arrayCountSize, (long)sizeof(AtkValue) * FirstContextMenuItemIndex); Buffer.MemoryCopy(this.atkValues, newAtkValues, newAtkValuesArraySize - arrayCountSize, (long)sizeof(AtkValue) * this.FirstContextMenuItemIndex);
// Free the old array // Free the old array
var oldArray = (IntPtr)this.atkValues - arrayCountSize; var oldArray = (IntPtr)this.atkValues - arrayCountSize;
@ -467,12 +488,13 @@ namespace Dalamud.Game.Gui.ContextMenus
} }
} }
public void Log() /*
private void Log()
{ {
Log(this.atkValueCount, this.atkValues); Log(this.atkValueCount, this.atkValues);
} }
public static void Log(int atkValueCount, AtkValue* atkValues) private static void Log(int atkValueCount, AtkValue* atkValues)
{ {
PluginLog.Debug($"ContextMenuReader.Log"); PluginLog.Debug($"ContextMenuReader.Log");
@ -515,5 +537,6 @@ namespace Dalamud.Game.Gui.ContextMenus
PluginLog.Debug($"atkValues[{atkValueIndex}]={(IntPtr)atkValue:X} {atkValue->Type}={value}"); PluginLog.Debug($"atkValues[{atkValueIndex}]={(IntPtr)atkValue:X} {atkValue->Type}={value}");
} }
} }
*/
} }
} }

View file

@ -9,11 +9,6 @@ namespace Dalamud.Game.Gui.ContextMenus
/// </summary> /// </summary>
public class CustomContextMenuItem : ContextMenuItem public class CustomContextMenuItem : ContextMenuItem
{ {
/// <summary>
/// The action that will be called when the item is selected.
/// </summary>
public CustomContextMenuItemSelectedDelegate ItemSelected { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CustomContextMenuItem"/> class. /// Initializes a new instance of the <see cref="CustomContextMenuItem"/> class.
/// </summary> /// </summary>
@ -22,15 +17,21 @@ namespace Dalamud.Game.Gui.ContextMenus
internal CustomContextMenuItem(SeString name, CustomContextMenuItemSelectedDelegate itemSelected) internal CustomContextMenuItem(SeString name, CustomContextMenuItemSelectedDelegate itemSelected)
: base(new SeString().Append(new UIForegroundPayload(539)).Append($"{SeIconChar.BoxedLetterD.ToIconString()} ").Append(new UIForegroundPayload(0)).Append(name)) : base(new SeString().Append(new UIForegroundPayload(539)).Append($"{SeIconChar.BoxedLetterD.ToIconString()} ").Append(new UIForegroundPayload(0)).Append(name))
{ {
ItemSelected = itemSelected; this.ItemSelected = itemSelected;
} }
/// <summary>
/// Gets the action that will be called when the item is selected.
/// </summary>
public CustomContextMenuItemSelectedDelegate ItemSelected { get; }
/// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ {
unchecked unchecked
{ {
int hash = base.GetHashCode(); var hash = base.GetHashCode();
hash = hash * 23 + ItemSelected.GetHashCode(); hash = (hash * 23) + this.ItemSelected.GetHashCode();
return hash; return hash;
} }
} }

View file

@ -5,16 +5,6 @@
/// </summary> /// </summary>
public class CustomContextMenuItemSelectedArgs public class CustomContextMenuItemSelectedArgs
{ {
/// <summary>
/// The currently opened context menu.
/// </summary>
public ContextMenuOpenedArgs ContextMenuOpenedArgs { get; init; }
/// <summary>
/// The selected item within the currently opened context menu.
/// </summary>
public CustomContextMenuItem SelectedItem { get; init; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CustomContextMenuItemSelectedArgs"/> class. /// Initializes a new instance of the <see cref="CustomContextMenuItemSelectedArgs"/> class.
/// </summary> /// </summary>
@ -22,8 +12,18 @@
/// <param name="selectedItem">The selected item within the currently opened context menu.</param> /// <param name="selectedItem">The selected item within the currently opened context menu.</param>
public CustomContextMenuItemSelectedArgs(ContextMenuOpenedArgs contextMenuOpenedArgs, CustomContextMenuItem selectedItem) public CustomContextMenuItemSelectedArgs(ContextMenuOpenedArgs contextMenuOpenedArgs, CustomContextMenuItem selectedItem)
{ {
ContextMenuOpenedArgs = contextMenuOpenedArgs; this.ContextMenuOpenedArgs = contextMenuOpenedArgs;
SelectedItem = selectedItem; this.SelectedItem = selectedItem;
} }
/// <summary>
/// Gets the currently opened context menu.
/// </summary>
public ContextMenuOpenedArgs ContextMenuOpenedArgs { get; init; }
/// <summary>
/// Gets the selected item within the currently opened context menu.
/// </summary>
public CustomContextMenuItem SelectedItem { get; init; }
} }
} }

View file

@ -7,11 +7,6 @@ namespace Dalamud.Game.Gui.ContextMenus
/// </summary> /// </summary>
public class GameContextMenuItem : ContextMenuItem public class GameContextMenuItem : ContextMenuItem
{ {
/// <summary>
/// The game action that will be handled when the item is selected.
/// </summary>
public byte SelectedAction { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GameContextMenuItem"/> class. /// Initializes a new instance of the <see cref="GameContextMenuItem"/> class.
/// </summary> /// </summary>
@ -20,15 +15,21 @@ namespace Dalamud.Game.Gui.ContextMenus
public GameContextMenuItem(SeString name, byte selectedAction) public GameContextMenuItem(SeString name, byte selectedAction)
: base(name) : base(name)
{ {
SelectedAction = selectedAction; this.SelectedAction = selectedAction;
} }
/// <summary>
/// Gets the game action that will be handled when the item is selected.
/// </summary>
public byte SelectedAction { get; }
/// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ {
unchecked unchecked
{ {
int hash = base.GetHashCode(); var hash = base.GetHashCode();
hash = hash * 23 + SelectedAction; hash = (hash * 23) + this.SelectedAction;
return hash; return hash;
} }
} }

View file

@ -5,21 +5,6 @@
/// </summary> /// </summary>
public class InventoryItemContext public class InventoryItemContext
{ {
/// <summary>
/// The id of the item.
/// </summary>
public uint Id { get; }
/// <summary>
/// The count of the item in the stack.
/// </summary>
public uint Count { get; }
/// <summary>
/// Whether the item is high quality.
/// </summary>
public bool IsHighQuality { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="InventoryItemContext"/> class. /// Initializes a new instance of the <see cref="InventoryItemContext"/> class.
/// </summary> /// </summary>
@ -28,9 +13,24 @@
/// <param name="isHighQuality">Whether the item is high quality.</param> /// <param name="isHighQuality">Whether the item is high quality.</param>
public InventoryItemContext(uint id, uint count, bool isHighQuality) public InventoryItemContext(uint id, uint count, bool isHighQuality)
{ {
Id = id; this.Id = id;
Count = count; this.Count = count;
IsHighQuality = isHighQuality; this.IsHighQuality = isHighQuality;
} }
/// <summary>
/// Gets the id of the item.
/// </summary>
public uint Id { get; }
/// <summary>
/// Gets the count of the item in the stack.
/// </summary>
public uint Count { get; }
/// <summary>
/// Gets a value indicating whether the item is high quality.
/// </summary>
public bool IsHighQuality { get; }
} }
} }

View file

@ -7,11 +7,6 @@ namespace Dalamud.Game.Gui.ContextMenus
/// </summary> /// </summary>
public class OpenSubContextMenuItem : ContextMenuItem public class OpenSubContextMenuItem : ContextMenuItem
{ {
/// <summary>
/// The action that will be called when the item is selected.
/// </summary>
public ContextMenuOpenedDelegate Opened { get; set; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="OpenSubContextMenuItem"/> class. /// Initializes a new instance of the <see cref="OpenSubContextMenuItem"/> class.
/// </summary> /// </summary>
@ -20,16 +15,22 @@ namespace Dalamud.Game.Gui.ContextMenus
internal OpenSubContextMenuItem(SeString name, ContextMenuOpenedDelegate opened) internal OpenSubContextMenuItem(SeString name, ContextMenuOpenedDelegate opened)
: base(name) : base(name)
{ {
Opened = opened; this.Opened = opened;
Indicator = ContextMenuItemIndicator.Next; this.Indicator = ContextMenuItemIndicator.Next;
} }
/// <summary>
/// Gets the action that will be called when the item is selected.
/// </summary>
public ContextMenuOpenedDelegate Opened { get; }
/// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ {
unchecked unchecked
{ {
int hash = base.GetHashCode(); int hash = base.GetHashCode();
hash = hash * 23 + Opened.GetHashCode(); hash = (hash * 23) + this.Opened.GetHashCode();
return hash; return hash;
} }
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Game.Gui.ContextMenus; using Dalamud.Game.Gui.ContextMenus;
using Dalamud.Game.Gui.FlyText; using Dalamud.Game.Gui.FlyText;
using Dalamud.Game.Gui.PartyFinder; using Dalamud.Game.Gui.PartyFinder;

View file

@ -1,7 +1,7 @@
namespace Dalamud.Game.Text namespace Dalamud.Game.Text
{ {
/// <summary> /// <summary>
/// Extension methods for <see cref="SeIconChar"/> /// Extension methods for <see cref="SeIconChar"/>.
/// </summary> /// </summary>
public static class SeIconCharExtensions public static class SeIconCharExtensions
{ {

View file

@ -1,13 +1,11 @@
using System; using System;
using System.Runtime.CompilerServices;
using Dalamud.Data; using Dalamud.Data;
using Dalamud.Game.Gui.ContextMenus; using Dalamud.Game.Gui.ContextMenus;
using Dalamud.Utility; using Dalamud.Utility;
using ImGuiNET; using ImGuiNET;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using Lumina.Text;
using Serilog; using Serilog;
using SeString = Dalamud.Game.Text.SeStringHandling.SeString;
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
{ {