diff --git a/XivCommon/Functions/ContextMenu.cs b/XivCommon/Functions/ContextMenu.cs
index cc2efbe..714354c 100755
--- a/XivCommon/Functions/ContextMenu.cs
+++ b/XivCommon/Functions/ContextMenu.cs
@@ -37,8 +37,16 @@ namespace XivCommon.Functions {
///
private const int MenuActionsOffset = 0x428;
+ private const int ActorIdOffset = 0xEF0;
+ private const int ContentIdLowerOffset = 0xEE0;
+
private const int NoopContextId = 0x67;
+ ///
+ /// The delegate that is run when a context menu item is selected.
+ ///
+ public delegate void ContextMenuItemSelectedDelegate(IntPtr addon, IntPtr agent, ContextMenuItemSelectedArgs args);
+
private unsafe delegate byte ContextMenuOpenDelegate(IntPtr addon, int menuSize, AtkValue* atkValueArgs);
private delegate IntPtr GetAddonByInternalIdDelegate(IntPtr raptureAtkUnitManager, short id);
@@ -47,9 +55,9 @@ namespace XivCommon.Functions {
private Hook? ContextMenuOpenHook { get; }
- private delegate byte ContextMenuItemSelectedDelegate(IntPtr addon, int index, byte a3);
+ private delegate byte ContextMenuItemSelectedInternalDelegate(IntPtr addon, int index, byte a3);
- private Hook? ContextMenuItemSelectedHook { get; }
+ private Hook? ContextMenuItemSelectedHook { get; }
private unsafe delegate void AtkValueChangeTypeDelegate(AtkValue* thisPtr, ValueType type);
@@ -97,7 +105,7 @@ namespace XivCommon.Functions {
}
if (scanner.TryScanText(Signatures.ContextMenuSelected, out var selectedPtr, "Context Menu selected")) {
- this.ContextMenuItemSelectedHook = new Hook(selectedPtr, new ContextMenuItemSelectedDelegate(this.ItemSelectedDetour));
+ this.ContextMenuItemSelectedHook = new Hook(selectedPtr, new ContextMenuItemSelectedInternalDelegate(this.ItemSelectedDetour));
this.ContextMenuItemSelectedHook.Enable();
}
}
@@ -166,7 +174,7 @@ namespace XivCommon.Functions {
return this.ContextMenuOpenHook!.Original(addon, menuSize, atkValueArgs);
}
- private byte ItemSelectedDetour(IntPtr addon, int index, byte a3) {
+ private unsafe byte ItemSelectedDetour(IntPtr addon, int index, byte a3) {
var addonName = this.GetParentAddonName(addon);
if (addonName == null) {
goto Original;
@@ -183,9 +191,13 @@ namespace XivCommon.Functions {
goto Original;
}
+ var agent = this.GetContextMenuAgent();
+ var actorId = *(uint*) (agent + ActorIdOffset);
+ var contentIdLower = *(uint*) (agent + ContentIdLowerOffset);
+
var item = registered[idx];
try {
- item.Action();
+ item.Action(addon, agent, new ContextMenuItemSelectedArgs(actorId, contentIdLower));
} catch (Exception ex) {
PluginLog.LogError(ex, "Exception in custom context menu item");
}
@@ -264,14 +276,14 @@ namespace XivCommon.Functions {
///
/// The action to perform when this item is clicked.
///
- public Action Action { get; }
+ public ContextMenu.ContextMenuItemSelectedDelegate Action { get; }
///
/// Create a new context menu item.
///
/// the English name of the item, copied to other languages
/// the action to perform on click
- public ContextMenuItem(string name, Action action) {
+ public ContextMenuItem(string name, ContextMenu.ContextMenuItemSelectedDelegate action) {
this.NameEnglish = name;
this.NameJapanese = name;
this.NameFrench = name;
@@ -280,4 +292,24 @@ namespace XivCommon.Functions {
this.Action = action;
}
}
+
+ ///
+ /// Arguments for the context menu item selected delegate.
+ ///
+ public class ContextMenuItemSelectedArgs {
+ ///
+ /// The actor ID for this context menu. May be invalid (0xE0000000).
+ ///
+ public uint ActorId { get; }
+
+ ///
+ /// The lower half of the content ID of the actor for this context menu. May be zero.
+ ///
+ public uint ContentIdLower { get; }
+
+ internal ContextMenuItemSelectedArgs(uint actorId, uint contentIdLower) {
+ this.ContentIdLower = contentIdLower;
+ this.ActorId = actorId;
+ }
+ }
}