private unsafe void ContextMenuItemSelectedImplementation(AddonContextMenu *addonContextMenu, int selectedIndex) { if (this.currentContextMenuOpenedArgs == null || selectedIndex == -1) { this.currentContextMenuOpenedArgs = null; this.selectedOpenSubContextMenuItem = null; return; } // Read the selected item directly from the game ContextMenuReaderWriter contextMenuReaderWriter = new ContextMenuReaderWriter(this.currentAgentContextInterface, addonContextMenu->AtkValuesCount, addonContextMenu->AtkValues); var gameContextMenuItems = contextMenuReaderWriter.Read(); var gameSelectedItem = gameContextMenuItems.ElementAtOrDefault(selectedIndex); // This should be impossible if (gameSelectedItem == null) { this.currentContextMenuOpenedArgs = null; this.selectedOpenSubContextMenuItem = null; return; } // Match it with the items we already know about based on its name. // We can get into a state where we have a game item we don't recognize when another plugin has added one. var selectedItem = this.currentContextMenuOpenedArgs.Items.FirstOrDefault(item => item.Name.Encode().SequenceEqual(gameSelectedItem.Name.Encode())); this.selectedOpenSubContextMenuItem = null; if (selectedItem is CustomContextMenuItem customContextMenuItem) { try { var customContextMenuItemSelectedArgs = new CustomContextMenuItemSelectedArgs(this.currentContextMenuOpenedArgs, customContextMenuItem); customContextMenuItem.ItemSelected(customContextMenuItemSelectedArgs); } catch (Exception ex) { PluginLog.LogError(ex, "ContextMenuItemSelectedImplementation"); } } else if (selectedItem is OpenSubContextMenuItem openSubContextMenuItem) { this.selectedOpenSubContextMenuItem = openSubContextMenuItem; } this.currentContextMenuOpenedArgs = null; }
private unsafe void ContextMenuOpenedImplementation(AddonContextMenu *addonContextMenu, ref int atkValueCount, ref AtkValue *atkValues) { if (this.ContextMenuOpened == null || this.currentAgentContextInterface == null) { return; } var contextMenuReaderWriter = new ContextMenuReaderWriter(this.currentAgentContextInterface, atkValueCount, atkValues); // Check for a title. string?title = null; if (this.selectedOpenSubContextMenuItem != null) { title = this.selectedOpenSubContextMenuItem.Name.TextValue; // Write the custom title var titleAtkValue = &atkValues[1]; fixed(byte *titlePtr = this.selectedOpenSubContextMenuItem.Name.Encode().NullTerminate()) { titleAtkValue->SetString(titlePtr); } } else if (contextMenuReaderWriter.Title != null) { title = contextMenuReaderWriter.Title.TextValue; } // Determine which event to raise. var contextMenuOpenedDelegate = this.ContextMenuOpened; // this.selectedOpenSubContextMenuItem is OpenSubContextMenuItem openSubContextMenuItem if (this.selectedOpenSubContextMenuItem != null) { contextMenuOpenedDelegate = this.selectedOpenSubContextMenuItem.Opened; } // Get the existing items from the game. // TODO: For inventory sub context menus, we take only the last item -- the return item. // This is because we're doing a hack to spawn a Second Tier sub context menu and then appropriating it. var contextMenuItems = contextMenuReaderWriter.Read(); if (IsInventoryContext(this.currentAgentContextInterface) && this.selectedOpenSubContextMenuItem != null) { contextMenuItems = contextMenuItems.TakeLast(1).ToArray(); } var beforeHashCode = GetContextMenuItemsHashCode(contextMenuItems); // Raise the event and get the context menu changes. this.currentContextMenuOpenedArgs = this.NotifyContextMenuOpened(addonContextMenu, this.currentAgentContextInterface, title, contextMenuOpenedDelegate, contextMenuItems); if (this.currentContextMenuOpenedArgs == null) { return; } var afterHashCode = GetContextMenuItemsHashCode(this.currentContextMenuOpenedArgs.Items); PluginLog.Warning($"{beforeHashCode}={afterHashCode}"); // Only write to memory if the items were actually changed. if (beforeHashCode != afterHashCode) { // Write the new changes. contextMenuReaderWriter.Write(this.currentContextMenuOpenedArgs.Items); // Update the addon. atkValueCount = *(&addonContextMenu->AtkValuesCount) = (ushort)contextMenuReaderWriter.AtkValueCount; atkValues = *(&addonContextMenu->AtkValues) = contextMenuReaderWriter.AtkValues; } }