Code cleanup
This commit is contained in:
@@ -9,6 +9,9 @@ using System.Linq;
|
||||
|
||||
namespace PlayerTags.Features
|
||||
{
|
||||
/// <summary>
|
||||
/// A feature that adds options for the management of custom tags to context menus.
|
||||
/// </summary>
|
||||
public class CustomTagsContextMenuFeature : IDisposable
|
||||
{
|
||||
private string?[] SupportedAddonNames = new string?[]
|
||||
@@ -62,47 +65,6 @@ namespace PlayerTags.Features
|
||||
|
||||
private void ContextMenuHooks_ContextMenuOpened(ContextMenuOpenedArgs contextMenuOpenedArgs)
|
||||
{
|
||||
if (contextMenuOpenedArgs.GameObjectContext != null)
|
||||
{
|
||||
PluginLog.Debug($"ContextMenuHooks_ContextMenuOpened {contextMenuOpenedArgs.GameObjectContext?.Id} {contextMenuOpenedArgs.GameObjectContext?.ContentIdLower} '{contextMenuOpenedArgs.GameObjectContext?.Name}' {contextMenuOpenedArgs.GameObjectContext?.WorldId}");
|
||||
}
|
||||
|
||||
if (contextMenuOpenedArgs.ItemContext != null)
|
||||
{
|
||||
PluginLog.Debug($"ContextMenuHooks_ContextMenuOpened {contextMenuOpenedArgs.ItemContext?.Id} {contextMenuOpenedArgs.ItemContext?.Count} {contextMenuOpenedArgs.ItemContext?.IsHighQuality}");
|
||||
}
|
||||
|
||||
contextMenuOpenedArgs.ContextMenuItems.Add(new CustomContextMenuItem("Root1", (itemSelectedArgs =>
|
||||
{
|
||||
PluginLog.Debug("Executed Root1");
|
||||
})));
|
||||
|
||||
contextMenuOpenedArgs.ContextMenuItems.Add(new OpenSubContextMenuItem("Root2", (subContextMenuOpenedArgs =>
|
||||
{
|
||||
PluginLog.Debug("Executed Root2");
|
||||
|
||||
List<ContextMenuItem> newContextMenuItems = new List<ContextMenuItem>();
|
||||
newContextMenuItems.Add(new OpenSubContextMenuItem("Inner1", (subContextMenuOpenedArgs2 =>
|
||||
{
|
||||
PluginLog.Debug("Executed Inner1");
|
||||
|
||||
List<ContextMenuItem> newContextMenuItems = new List<ContextMenuItem>();
|
||||
newContextMenuItems.Add(new CustomContextMenuItem("Inner3", (itemSelectedArgs =>
|
||||
{
|
||||
PluginLog.Debug("Executed Inner3");
|
||||
})));
|
||||
|
||||
subContextMenuOpenedArgs2.ContextMenuItems.InsertRange(0, newContextMenuItems);
|
||||
})));
|
||||
|
||||
newContextMenuItems.Add(new CustomContextMenuItem("Inner2", (itemSelectedArgs =>
|
||||
{
|
||||
PluginLog.Debug("Executed Inner2");
|
||||
})));
|
||||
|
||||
subContextMenuOpenedArgs.ContextMenuItems.InsertRange(0, newContextMenuItems);
|
||||
})));
|
||||
|
||||
if (!m_PluginConfiguration.IsCustomTagsContextMenuEnabled || !SupportedAddonNames.Contains(contextMenuOpenedArgs.ParentAddonName))
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace PlayerTags.Features
|
||||
|
||||
private void Nameplate_PlayerNameplateUpdated(PlayerNameplateUpdatedArgs args)
|
||||
{
|
||||
var beforeTitleHashCode = args.Title.GetHashCode();
|
||||
var beforeTitleBytes = args.Title.Encode();
|
||||
AddTagsToNameplate(args.PlayerCharacter, args.Name, args.Title, args.FreeCompany/*, out isNameChanged, out isTitleChanged, out isFreeCompanyChanged*/);
|
||||
|
||||
if (m_PluginConfiguration.NameplateTitlePosition == NameplateTitlePosition.AlwaysAboveName)
|
||||
@@ -122,7 +122,7 @@ namespace PlayerTags.Features
|
||||
}
|
||||
else if (m_PluginConfiguration.NameplateTitleVisibility == NameplateTitleVisibility.WhenHasTags)
|
||||
{
|
||||
bool hasTitleChanged = beforeTitleHashCode != args.Title.GetHashCode();
|
||||
bool hasTitleChanged = !beforeTitleBytes.SequenceEqual(args.Title.Encode());
|
||||
args.IsTitleVisible = hasTitleChanged;
|
||||
}
|
||||
|
||||
@@ -132,7 +132,6 @@ namespace PlayerTags.Features
|
||||
else if (m_PluginConfiguration.NameplateFreeCompanyVisibility == NameplateFreeCompanyVisibility.Never)
|
||||
{
|
||||
args.FreeCompany.Payloads.Clear();
|
||||
//isFreeCompanyChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,20 +121,20 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
private delegate IntPtr GetAddonByIdDelegate_Unmanaged(IntPtr raptureAtkUnitManager, ushort id);
|
||||
private readonly GetAddonByIdDelegate_Unmanaged? m_GetAddonById;
|
||||
|
||||
private delegate byte OpenSubContextMenuDelegate_Unmanaged(IntPtr agent);
|
||||
private delegate bool OpenSubContextMenuDelegate_Unmanaged(IntPtr agent);
|
||||
private readonly OpenSubContextMenuDelegate_Unmanaged? m_OpenSubContextMenu;
|
||||
|
||||
private delegate IntPtr ContextMenuOpeningDelegate_Unmanaged(IntPtr a1, IntPtr a2, IntPtr a3, uint a4, IntPtr a5, IntPtr agent, IntPtr a7, ushort a8);
|
||||
private Hook<ContextMenuOpeningDelegate_Unmanaged>? m_ContextMenuOpeningHook;
|
||||
|
||||
private unsafe delegate byte ContextMenuOpenedDelegate_Unmanaged(IntPtr addon, int menuSize, AtkValue* atkValueArgs);
|
||||
private unsafe delegate bool ContextMenuOpenedDelegate_Unmanaged(IntPtr addon, int menuSize, AtkValue* atkValueArgs);
|
||||
private Hook<ContextMenuOpenedDelegate_Unmanaged>? m_ContextMenuOpenedHook;
|
||||
private Hook<ContextMenuOpenedDelegate_Unmanaged>? m_SubContextMenuOpenedHook;
|
||||
|
||||
private delegate byte ContextMenuItemSelectedDelegate_Unmanaged(IntPtr addon, int index, byte a3);
|
||||
private delegate bool ContextMenuItemSelectedDelegate_Unmanaged(IntPtr addon, int index, byte a3);
|
||||
private Hook<ContextMenuItemSelectedDelegate_Unmanaged>? m_ContextMenuItemSelectedHook;
|
||||
|
||||
private delegate byte SubContextMenuOpeningDelegate_Unmanaged(IntPtr agent);
|
||||
private delegate bool SubContextMenuOpeningDelegate_Unmanaged(IntPtr agent);
|
||||
private Hook<SubContextMenuOpeningDelegate_Unmanaged>? m_SubContextMenuOpeningHook;
|
||||
|
||||
private delegate IntPtr OpenInventoryContextMenuDelegate_Unmanaged(IntPtr agent, byte hasTitle, byte zero);
|
||||
@@ -150,8 +150,8 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
private IntPtr m_CurrentContextMenuAgent;
|
||||
private IntPtr m_CurrentSubContextMenuTitle;
|
||||
|
||||
private ContextMenuOpenedArgs? m_ContextMenuOpenedArgs;
|
||||
private OpenSubContextMenuItem? m_OpenSubContextMenuItem;
|
||||
private ContextMenuItem? m_CurrentSelectedItem;
|
||||
private ContextMenuOpenedArgs? m_CurrentContextMenuOpenedArgs;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a context menu is opened by the game.
|
||||
@@ -279,12 +279,12 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
return m_ContextMenuOpeningHook!.Original(a1, a2, a3, a4, a5, agent, a7, a8);
|
||||
}
|
||||
|
||||
private unsafe byte ContextMenuOpenedDetour(IntPtr addon, int atkValueCount, AtkValue* atkValues)
|
||||
private unsafe bool ContextMenuOpenedDetour(IntPtr addon, int atkValueCount, AtkValue* atkValues)
|
||||
{
|
||||
PluginLog.Debug($"ContextMenuOpenedDetour");
|
||||
if (m_ContextMenuOpenedHook == null)
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
var addonContext = (AddonContext*)addon;
|
||||
@@ -306,7 +306,7 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
|
||||
private unsafe void ContextMenuOpenedImplementation(IntPtr addon, ref int atkValueCount, ref AtkValue* atkValues)
|
||||
{
|
||||
PluginLog.Debug($"ContextMenuOpenedImplementation");
|
||||
PluginLog.Debug($"ContextMenuOpenedImplementation {m_CurrentSelectedItem}");
|
||||
|
||||
if (m_AtkValueChangeType == null
|
||||
|| m_AtkValueSetString == null
|
||||
@@ -316,19 +316,21 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
return;
|
||||
}
|
||||
|
||||
ContextMenuReaderWriter contextMenuReaderWriter = new ContextMenuReaderWriter(m_CurrentContextMenuAgent, atkValueCount, atkValues);
|
||||
|
||||
// Read the context menu items from the game, then allow subscribers to modify them
|
||||
if (m_ContextMenuOpenedArgs == null)
|
||||
ContextMenuOpenedDelegate contextMenuOpenedDelegate = ContextMenuOpened;
|
||||
if (m_CurrentSelectedItem is OpenSubContextMenuItem openSubContextMenuItem)
|
||||
{
|
||||
m_ContextMenuOpenedArgs = NotifyContextMenuOpened(addon, m_CurrentContextMenuAgent, ContextMenuOpened, contextMenuReaderWriter.Read());
|
||||
if (m_ContextMenuOpenedArgs == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
contextMenuOpenedDelegate = openSubContextMenuItem.OpenedAction;
|
||||
}
|
||||
|
||||
contextMenuReaderWriter.Write(null, m_ContextMenuOpenedArgs.ContextMenuItems, m_AtkValueChangeType, m_AtkValueSetString);
|
||||
// Read the context menu items from the game, then allow subscribers to modify them
|
||||
ContextMenuReaderWriter contextMenuReaderWriter = new ContextMenuReaderWriter(m_CurrentContextMenuAgent, atkValueCount, atkValues);
|
||||
m_CurrentContextMenuOpenedArgs = NotifyContextMenuOpened(addon, m_CurrentContextMenuAgent, m_CurrentSelectedItem, contextMenuOpenedDelegate, contextMenuReaderWriter.Read());
|
||||
if (m_CurrentContextMenuOpenedArgs == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
contextMenuReaderWriter.Write(m_CurrentContextMenuOpenedArgs, m_AtkValueChangeType, m_AtkValueSetString);
|
||||
|
||||
// Update the addon
|
||||
var addonContext = (AddonContext*)addon;
|
||||
@@ -336,17 +338,17 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
atkValues = *(&addonContext->AtkValues) = contextMenuReaderWriter.AtkValues;
|
||||
}
|
||||
|
||||
private byte SubContextMenuOpeningDetour(IntPtr agent)
|
||||
private bool SubContextMenuOpeningDetour(IntPtr agent)
|
||||
{
|
||||
PluginLog.Debug($"SubContextMenuOpeningDetour");
|
||||
if (m_SubContextMenuOpeningHook == null)
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SubContextMenuOpeningImplementation(agent))
|
||||
{
|
||||
return 0x0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_SubContextMenuOpeningHook.Original(agent);
|
||||
@@ -354,27 +356,16 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
|
||||
private unsafe bool SubContextMenuOpeningImplementation(IntPtr agent)
|
||||
{
|
||||
PluginLog.Debug($"SubContextMenuOpeningImplementation {m_OpenSubContextMenuItem}");
|
||||
PluginLog.Debug($"SubContextMenuOpeningImplementation {m_CurrentSelectedItem}");
|
||||
|
||||
if (m_OpenSubContextMenu == null
|
||||
|| m_OpenInventoryContextMenu == null
|
||||
|| m_AtkValueChangeType == null
|
||||
|| m_OpenSubContextMenuItem == null)
|
||||
|| !(m_CurrentSelectedItem is OpenSubContextMenuItem))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This isn't our own sub context menu -- don't go any further
|
||||
//if (m_OpenSubContextMenuItem == null)
|
||||
//{
|
||||
// return false;
|
||||
//}
|
||||
|
||||
//var a = (AgentContext*)agent;
|
||||
//var s = a->SelectedIndex;
|
||||
|
||||
//*(&a->SelectedIndex) = 0xff;
|
||||
|
||||
// The important things to make this work are:
|
||||
// 1. Temporary allocate a sub context menu title
|
||||
// 1. Temporarily increase the atk value count by 1 so the game knows to expect at least 1 context menu item
|
||||
@@ -398,8 +389,6 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
*(&agentContext->SubContextMenuTitle) = (byte*)m_CurrentSubContextMenuTitle;
|
||||
}
|
||||
|
||||
//*(&a->SelectedIndex) = s;
|
||||
|
||||
var atkValues = &agentContext->ItemData->AtkValues;
|
||||
|
||||
// Let the game know the context menu will have at least 1 item in it
|
||||
@@ -412,22 +401,17 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
return true;
|
||||
}
|
||||
|
||||
private unsafe byte SubContextMenuOpenedDetour(IntPtr addon, int atkValueCount, AtkValue* atkValues)
|
||||
private unsafe bool SubContextMenuOpenedDetour(IntPtr addon, int atkValueCount, AtkValue* atkValues)
|
||||
{
|
||||
PluginLog.Debug($"SubContextMenuOpenedDetour");
|
||||
if (m_SubContextMenuOpenedHook == null)
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
var addonContext = (AddonContext*)addon;
|
||||
PluginLog.Debug($"SubContextMenuOpenedDetour addonContext->IsInitialMenu={addonContext->IsInitialMenu}");
|
||||
|
||||
ContextMenuReaderWriter.Print(atkValueCount, atkValues);
|
||||
|
||||
try
|
||||
{
|
||||
SubContextMenuOpenedImplementation(addon, ref atkValueCount, ref atkValues);
|
||||
ContextMenuOpenedImplementation(addon, ref atkValueCount, ref atkValues);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -437,57 +421,16 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
return m_SubContextMenuOpenedHook.Original(addon, atkValueCount, atkValues);
|
||||
}
|
||||
|
||||
private unsafe void SubContextMenuOpenedImplementation(IntPtr addon, ref int atkValueCount, ref AtkValue* atkValues)
|
||||
{
|
||||
PluginLog.Debug($"SubContextMenuOpenedImplementation");
|
||||
|
||||
if (m_AtkValueSetString == null
|
||||
|| m_AtkValueChangeType == null
|
||||
|| ContextMenuOpened == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ContextMenuReaderWriter contextMenuReader = new ContextMenuReaderWriter(m_CurrentContextMenuAgent, atkValueCount, atkValues);
|
||||
|
||||
if (m_OpenSubContextMenuItem != null)
|
||||
{
|
||||
m_ContextMenuOpenedArgs = NotifyContextMenuOpened(addon, m_CurrentContextMenuAgent, m_OpenSubContextMenuItem.OpenedAction, contextMenuReader.Read());
|
||||
if (m_ContextMenuOpenedArgs == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ContextMenuOpenedArgs = NotifyContextMenuOpened(addon, m_CurrentContextMenuAgent, ContextMenuOpened, contextMenuReader.Read());
|
||||
if (m_ContextMenuOpenedArgs == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
contextMenuReader.Write(m_OpenSubContextMenuItem, m_ContextMenuOpenedArgs.ContextMenuItems, m_AtkValueChangeType, m_AtkValueSetString);
|
||||
|
||||
// Update the addon
|
||||
var addonContext = (AddonContext*)addon;
|
||||
atkValueCount = *(&addonContext->AtkValuesCount) = (ushort)contextMenuReader.AtkValueCount;
|
||||
atkValues = *(&addonContext->AtkValues) = contextMenuReader.AtkValues;
|
||||
}
|
||||
|
||||
private unsafe ContextMenuOpenedArgs? NotifyContextMenuOpened(IntPtr addon, IntPtr agent, ContextMenuOpenedDelegate contextMenuOpenedDelegate, IEnumerable<ContextMenuItem> initialContextMenuItems)
|
||||
private unsafe ContextMenuOpenedArgs? NotifyContextMenuOpened(IntPtr addon, IntPtr agent, ContextMenuItem? selectedContextMenuItem, ContextMenuOpenedDelegate contextMenuOpenedDelegate, IEnumerable<ContextMenuItem> initialContextMenuItems)
|
||||
{
|
||||
var parentAddonName = GetParentAddonName(addon);
|
||||
|
||||
ContextMenuOpenedArgs contextMenuOpenedArgs;
|
||||
ItemContext? itemContext = null;
|
||||
GameObjectContext? gameObjectContext = null;
|
||||
if (IsInventoryContext(agent))
|
||||
{
|
||||
var agentInventoryContext = (AgentInventoryContext*)agent;
|
||||
|
||||
contextMenuOpenedArgs = new ContextMenuOpenedArgs(addon, agent, parentAddonName, initialContextMenuItems)
|
||||
{
|
||||
ItemContext = new ItemContext(agentInventoryContext->ItemId, agentInventoryContext->ItemCount, agentInventoryContext->IsHighQuality)
|
||||
};
|
||||
itemContext = new ItemContext(agentInventoryContext->ItemId, agentInventoryContext->ItemCount, agentInventoryContext->IsHighQuality);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -499,12 +442,16 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
objectName = GameInterfaceHelper.ReadSeString((IntPtr)agentContext->ObjectName.StringPtr);
|
||||
}
|
||||
|
||||
contextMenuOpenedArgs = new ContextMenuOpenedArgs(addon, agent, parentAddonName, initialContextMenuItems)
|
||||
{
|
||||
GameObjectContext = new GameObjectContext(agentContext->ObjectId, agentContext->ObjectContentIdLower, objectName, agentContext->ObjectWorldId)
|
||||
};
|
||||
gameObjectContext = new GameObjectContext(agentContext->ObjectId, agentContext->ObjectContentIdLower, objectName, agentContext->ObjectWorldId);
|
||||
}
|
||||
|
||||
var contextMenuOpenedArgs = new ContextMenuOpenedArgs(addon, agent, parentAddonName, initialContextMenuItems)
|
||||
{
|
||||
SelectedItem = selectedContextMenuItem,
|
||||
ItemContext = itemContext,
|
||||
GameObjectContext = gameObjectContext
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
contextMenuOpenedDelegate.Invoke(contextMenuOpenedArgs);
|
||||
@@ -529,12 +476,12 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
return contextMenuOpenedArgs;
|
||||
}
|
||||
|
||||
private unsafe byte ContextMenuItemSelectedDetour(IntPtr addon, int index, byte a3)
|
||||
private unsafe bool ContextMenuItemSelectedDetour(IntPtr addon, int index, byte a3)
|
||||
{
|
||||
PluginLog.Debug($"ContextMenuItemSelectedDetour");
|
||||
PluginLog.Debug($"ContextMenuItemSelectedDetour index={index}");
|
||||
if (m_ContextMenuItemSelectedHook == null)
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
@@ -553,10 +500,10 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
{
|
||||
PluginLog.Debug($"ContextMenuItemSelectedImplementation index={index}");
|
||||
|
||||
if (m_ContextMenuOpenedArgs == null)
|
||||
if (m_CurrentContextMenuOpenedArgs == null)
|
||||
{
|
||||
m_ContextMenuOpenedArgs = null;
|
||||
m_OpenSubContextMenuItem = null;
|
||||
m_CurrentContextMenuOpenedArgs = null;
|
||||
m_CurrentSelectedItem = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -564,39 +511,31 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
var addonContext = (AddonContext*)addon;
|
||||
ContextMenuReaderWriter.Print(addonContext->AtkValuesCount, addonContext->AtkValues);
|
||||
|
||||
var contextMenuItem = m_ContextMenuOpenedArgs.ContextMenuItems.ElementAtOrDefault(index);
|
||||
var contextMenuItem = m_CurrentContextMenuOpenedArgs.ContextMenuItems.ElementAtOrDefault(index);
|
||||
if (contextMenuItem == null)
|
||||
{
|
||||
m_ContextMenuOpenedArgs = null;
|
||||
m_OpenSubContextMenuItem = null;
|
||||
m_CurrentContextMenuOpenedArgs = null;
|
||||
m_CurrentSelectedItem = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (contextMenuItem is OpenSubContextMenuItem openSubContextMenuItem)
|
||||
if (contextMenuItem is CustomContextMenuItem customContextMenuItem)
|
||||
{
|
||||
m_OpenSubContextMenuItem = openSubContextMenuItem;
|
||||
}
|
||||
else if (contextMenuItem is CustomContextMenuItem customContextMenuItem)
|
||||
{
|
||||
var args = new CustomContextMenuItemSelectedArgs(m_ContextMenuOpenedArgs, customContextMenuItem);
|
||||
|
||||
try
|
||||
{
|
||||
customContextMenuItem.CustomAction(args);
|
||||
var customContextMenuItemSelectedArgs = new CustomContextMenuItemSelectedArgs(m_CurrentContextMenuOpenedArgs, customContextMenuItem);
|
||||
customContextMenuItem.ItemSelected(customContextMenuItemSelectedArgs);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.LogError(ex, "ContextMenuItemSelectedImplementation");
|
||||
}
|
||||
}
|
||||
|
||||
m_ContextMenuOpenedArgs = null;
|
||||
m_OpenSubContextMenuItem = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ContextMenuOpenedArgs = null;
|
||||
m_OpenSubContextMenuItem = null;
|
||||
}
|
||||
m_CurrentSelectedItem = contextMenuItem;// is OpenSubContextMenuItem ? contextMenuItem : null;
|
||||
m_CurrentContextMenuOpenedArgs = null;
|
||||
|
||||
PluginLog.Debug($"ContextMenuItemSelectedImplementation index={index} dddddddddddddd");
|
||||
}
|
||||
|
||||
private void InventoryContextMenuEvent30Detour(IntPtr agent, IntPtr a2, int a3, int a4, short a5)
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
|
||||
public List<ContextMenuItem> ContextMenuItems { get; }
|
||||
|
||||
public ContextMenuItem? SelectedItem { get; init; }
|
||||
|
||||
public GameObjectContext? GameObjectContext { get; init; }
|
||||
|
||||
public ItemContext? ItemContext { get; init; }
|
||||
|
||||
@@ -278,11 +278,11 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
return gameContextMenuItems.ToArray();
|
||||
}
|
||||
|
||||
public unsafe void Write(OpenSubContextMenuItem? selectedOpenSubContextMenuItem, IEnumerable<ContextMenuItem> contextMenuItems, AtkValueChangeTypeDelegate_Unmanaged atkValueChangeType, AtkValueSetStringDelegate_Unmanaged atkValueSetString)
|
||||
public unsafe void Write(ContextMenuOpenedArgs contextMenuOpenedArgs, AtkValueChangeTypeDelegate_Unmanaged atkValueChangeType, AtkValueSetStringDelegate_Unmanaged atkValueSetString)
|
||||
{
|
||||
Print();
|
||||
|
||||
var newAtkValuesCount = FirstContextMenuItemIndex + (contextMenuItems.Count() * TotalDesiredAtkValuesPerContextMenuItem);
|
||||
var newAtkValuesCount = FirstContextMenuItemIndex + (contextMenuOpenedArgs.ContextMenuItems.Count() * TotalDesiredAtkValuesPerContextMenuItem);
|
||||
|
||||
// Allocate the new array. We have to do a little dance with the first 8 bytes which represents the array count
|
||||
const int arrayCountSize = 8;
|
||||
@@ -311,11 +311,11 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
m_AtkValueCount = newAtkValuesCount;
|
||||
m_AtkValues = newAtkValues;
|
||||
|
||||
// Set the title
|
||||
if (selectedOpenSubContextMenuItem != null)
|
||||
// Set the custom title if appropriate
|
||||
if (contextMenuOpenedArgs.SelectedItem is OpenSubContextMenuItem)
|
||||
{
|
||||
var titleAtkValue = &m_AtkValues[1];
|
||||
fixed (byte* TtlePtr = selectedOpenSubContextMenuItem.Name.Encode().NullTerminate())
|
||||
fixed (byte* TtlePtr = contextMenuOpenedArgs.SelectedItem.Name.Encode().NullTerminate())
|
||||
{
|
||||
atkValueSetString(titleAtkValue, TtlePtr);
|
||||
}
|
||||
@@ -324,7 +324,7 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
// Set the context menu item count
|
||||
const int contextMenuItemCountAtkValueIndex = 0;
|
||||
var contextMenuItemCountAtkValue = &m_AtkValues[contextMenuItemCountAtkValueIndex];
|
||||
contextMenuItemCountAtkValue->UInt = (uint)contextMenuItems.Count();
|
||||
contextMenuItemCountAtkValue->UInt = (uint)contextMenuOpenedArgs.ContextMenuItems.Count();
|
||||
|
||||
// Clear the previous arrow flags
|
||||
var hasPreviousArrowAtkValue = &m_AtkValues[HasPreviousArrowFlagsIndex];
|
||||
@@ -334,9 +334,9 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
var subContextMenusFlagsAtkValue = &m_AtkValues[HasNextArrowFlagsIndex];
|
||||
subContextMenusFlagsAtkValue->UInt = 0;
|
||||
|
||||
for (int contextMenuItemIndex = 0; contextMenuItemIndex < contextMenuItems.Count(); ++contextMenuItemIndex)
|
||||
for (int contextMenuItemIndex = 0; contextMenuItemIndex < contextMenuOpenedArgs.ContextMenuItems.Count(); ++contextMenuItemIndex)
|
||||
{
|
||||
var contextMenuItem = contextMenuItems.ElementAt(contextMenuItemIndex);
|
||||
var contextMenuItem = contextMenuOpenedArgs.ContextMenuItems.ElementAt(contextMenuItemIndex);
|
||||
|
||||
var contextMenuItemAtkValueBaseIndex = FirstContextMenuItemIndex + (contextMenuItemIndex * SequentialAtkValuesPerContextMenuItem);
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ namespace PlayerTags.GameInterface.ContextMenus
|
||||
{
|
||||
public class CustomContextMenuItem : ContextMenuItem
|
||||
{
|
||||
public CustomContextMenuItemSelectedDelegate CustomAction { get; }
|
||||
public CustomContextMenuItemSelectedDelegate ItemSelected { get; }
|
||||
|
||||
internal CustomContextMenuItem(SeString name, CustomContextMenuItemSelectedDelegate customAction)
|
||||
internal CustomContextMenuItem(SeString name, CustomContextMenuItemSelectedDelegate itemSelected)
|
||||
: base(name)
|
||||
{
|
||||
CustomAction = customAction;
|
||||
ItemSelected = itemSelected;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,18 @@
|
||||
namespace PlayerTags.GameInterface.ContextMenus
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides data for <see cref="CustomContextMenuItemSelectedDelegate"/> events.
|
||||
/// </summary>
|
||||
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; }
|
||||
|
||||
public CustomContextMenuItemSelectedArgs(ContextMenuOpenedArgs contextMenuOpenedArgs, CustomContextMenuItem selectedItem)
|
||||
|
||||
@@ -74,10 +74,8 @@ namespace PlayerTags.GameInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
public static IntPtr PluginAllocate(SeString seString)
|
||||
public static IntPtr PluginAllocate(byte[] bytes)
|
||||
{
|
||||
var bytes = seString.Encode();
|
||||
|
||||
IntPtr pointer = Marshal.AllocHGlobal(bytes.Length + 1);
|
||||
Marshal.Copy(bytes, 0, pointer, bytes.Length);
|
||||
Marshal.WriteByte(pointer, bytes.Length, 0);
|
||||
@@ -85,6 +83,11 @@ namespace PlayerTags.GameInterface
|
||||
return pointer;
|
||||
}
|
||||
|
||||
public static IntPtr PluginAllocate(SeString seString)
|
||||
{
|
||||
return PluginAllocate(seString.Encode());
|
||||
}
|
||||
|
||||
public static void PluginFree(ref IntPtr ptr)
|
||||
{
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
|
||||
@@ -7,6 +7,7 @@ using Dalamud.Logging;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Linq;
|
||||
|
||||
namespace PlayerTags.GameInterface.Nameplates
|
||||
{
|
||||
@@ -97,34 +98,38 @@ namespace PlayerTags.GameInterface.Nameplates
|
||||
isTitleAboveName,
|
||||
iconId);
|
||||
|
||||
var beforeNameHashCode = playerNameplateUpdatedArgs.Name.GetHashCode();
|
||||
var beforeTitleHashCode = playerNameplateUpdatedArgs.Title.GetHashCode();
|
||||
var beforeFreeCompanyHashCode = playerNameplateUpdatedArgs.FreeCompany.GetHashCode();
|
||||
byte[] beforeNameBytes = playerNameplateUpdatedArgs.Name.Encode();
|
||||
byte[] beforeTitleBytes = playerNameplateUpdatedArgs.Title.Encode();
|
||||
byte[] beforeFreeCompanyBytes = playerNameplateUpdatedArgs.FreeCompany.Encode();
|
||||
|
||||
PlayerNameplateUpdated?.Invoke(playerNameplateUpdatedArgs);
|
||||
|
||||
byte[] afterNameBytes = playerNameplateUpdatedArgs.Name.Encode();
|
||||
byte[] afterTitleBytes = playerNameplateUpdatedArgs.Title.Encode();
|
||||
byte[] afterFreeCompanyBytes = playerNameplateUpdatedArgs.FreeCompany.Encode();
|
||||
|
||||
IntPtr newNamePtr = namePtr;
|
||||
bool hasNameChanged = beforeNameHashCode != playerNameplateUpdatedArgs.Name.GetHashCode();
|
||||
bool hasNameChanged = !beforeNameBytes.SequenceEqual(afterNameBytes);
|
||||
if (hasNameChanged)
|
||||
{
|
||||
newNamePtr = GameInterfaceHelper.PluginAllocate(playerNameplateUpdatedArgs.Name);
|
||||
newNamePtr = GameInterfaceHelper.PluginAllocate(afterNameBytes);
|
||||
}
|
||||
|
||||
IntPtr newTitlePtr = titlePtr;
|
||||
bool hasTitleChanged = beforeTitleHashCode != playerNameplateUpdatedArgs.Title.GetHashCode();
|
||||
bool hasTitleChanged = !beforeTitleBytes.SequenceEqual(afterTitleBytes);
|
||||
if (hasTitleChanged)
|
||||
{
|
||||
newTitlePtr = GameInterfaceHelper.PluginAllocate(playerNameplateUpdatedArgs.Title);
|
||||
newTitlePtr = GameInterfaceHelper.PluginAllocate(afterTitleBytes);
|
||||
}
|
||||
|
||||
IntPtr newFreeCompanyPtr = freeCompanyPtr;
|
||||
bool hasFreeCompanyChanged = beforeFreeCompanyHashCode != playerNameplateUpdatedArgs.FreeCompany.GetHashCode();
|
||||
bool hasFreeCompanyChanged = !beforeFreeCompanyBytes.SequenceEqual(afterFreeCompanyBytes);
|
||||
if (hasFreeCompanyChanged)
|
||||
{
|
||||
newFreeCompanyPtr = GameInterfaceHelper.PluginAllocate(playerNameplateUpdatedArgs.FreeCompany);
|
||||
newFreeCompanyPtr = GameInterfaceHelper.PluginAllocate(afterFreeCompanyBytes);
|
||||
}
|
||||
|
||||
var result = m_SetPlayerNameplateHook.Original(playerNameplateObjectPtr, playerNameplateUpdatedArgs.IsTitleAboveName, playerNameplateUpdatedArgs.IsTitleVisible, newNamePtr, newTitlePtr, newFreeCompanyPtr, playerNameplateUpdatedArgs.IconId);
|
||||
var result = m_SetPlayerNameplateHook.Original(playerNameplateObjectPtr, playerNameplateUpdatedArgs.IsTitleAboveName, playerNameplateUpdatedArgs.IsTitleVisible, newTitlePtr, newNamePtr, newFreeCompanyPtr, playerNameplateUpdatedArgs.IconId);
|
||||
|
||||
if (hasNameChanged)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user