using Comfort.Common; using EFT.InventoryLogic; using EFT.UI; using JetBrains.Annotations; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; using UnityEngine; using EmptyInteractionsAbstractClass = GClass3061; namespace IcyClawz.CustomInteractions; [EditorBrowsable(EditorBrowsableState.Never)] public interface ICustomInteractionsProvider { } // Do not implement this directly public interface IItemCustomInteractionsProvider : ICustomInteractionsProvider { IEnumerable GetCustomInteractions(ItemUiContext uiContext, EItemViewType viewType, Item item); } public static class CustomInteractionsManager { internal static readonly LinkedList Providers = []; public static void Register(ICustomInteractionsProvider provider) { if (!Providers.Contains(provider)) Providers.AddLast(provider); } } public class CustomInteraction() { internal readonly CustomInteractionImpl Impl = new(UnityEngine.Random.Range(0, int.MaxValue).ToString("x4")); public Func Caption { get => Impl.Caption; set => Impl.Caption = value; } public Func Icon { get => Impl.Icon; set => Impl.Icon = value; } public Action Action { get => Impl.Action; set => Impl.Action = value; } public Func SubMenu { get => Impl.SubMenu; set => Impl.SubMenu = value; } public Func Enabled { get => Impl.Enabled; set => Impl.Enabled = value; } public Func Error { get => Impl.Error; set => Impl.Error = value; } } internal sealed class CustomInteractionImpl(string id) : DynamicInteractionClass(id, id) { public Func Caption { get; set; } public new Func Icon { get; set; } public Action Action { get => action_0; set => action_0 = value; } public Func SubMenu { get; set; } public Func Enabled { get; set; } public Func Error { get; set; } public bool IsInteractive() => Enabled?.Invoke() ?? true; } public abstract class CustomSubInteractions(ItemUiContext uiContext) { internal readonly CustomSubInteractionsImpl Impl = new(uiContext); public bool ExaminationRequired { get => Impl.ExaminationRequiredInternal; set => Impl.ExaminationRequiredInternal = value; } public void Add(CustomInteraction interaction) => Impl.AddCustomInteraction(interaction); public void AddRange(IEnumerable interactions) => interactions.ExecuteForEach(Impl.AddCustomInteraction); public void Remove(CustomInteraction interaction) => Impl.RemoveCustomInteraction(interaction); public void RemoveRange(IEnumerable interactions) => interactions.ExecuteForEach(Impl.RemoveCustomInteraction); } internal sealed class CustomSubInteractionsImpl(ItemUiContext uiContext) : EmptyInteractionsAbstractClass(uiContext) { public IEnumerable CustomInteractions => DynamicInteractions.OfType(); public bool ExaminationRequiredInternal { get; set; } = true; public override bool ExaminationRequired => ExaminationRequiredInternal; public override bool HasIcons => CustomInteractions.Any(interaction => interaction.Icon is not null); } internal static class AbstractInteractionsExtensions { private static Dictionary GetDynamicInteractions(this ItemInfoInteractionsAbstractClass instance) where T : struct, Enum => typeof(ItemInfoInteractionsAbstractClass).GetField("dictionary_0", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(instance) as Dictionary; public static void AddCustomInteraction(this ItemInfoInteractionsAbstractClass instance, CustomInteraction interaction) where T : struct, Enum => instance.GetDynamicInteractions()[interaction.Impl.Key] = interaction.Impl; public static void RemoveCustomInteraction(this ItemInfoInteractionsAbstractClass instance, CustomInteraction interaction) where T : struct, Enum => instance.GetDynamicInteractions().Remove(interaction.Impl.Key); } internal static class InteractionButtonsContainerExtensions { private static readonly FieldInfo ButtonsContainerField = typeof(InteractionButtonsContainer).GetField("_buttonsContainer", BindingFlags.NonPublic | BindingFlags.Instance); private static RectTransform GetButtonsContainer(this InteractionButtonsContainer instance) => ButtonsContainerField.GetValue(instance) as RectTransform; private static readonly FieldInfo ButtonTemplateField = typeof(InteractionButtonsContainer).GetField("_buttonTemplate", BindingFlags.NonPublic | BindingFlags.Instance); private static SimpleContextMenuButton GetButtonTemplate(this InteractionButtonsContainer instance) => ButtonTemplateField.GetValue(instance) as SimpleContextMenuButton; private static readonly FieldInfo CurrentButtonField = typeof(InteractionButtonsContainer).GetField("simpleContextMenuButton_0", BindingFlags.NonPublic | BindingFlags.Instance); private static void SetCurrentButton(this InteractionButtonsContainer instance, SimpleContextMenuButton button) => CurrentButtonField.SetValue(instance, button); private static readonly MethodInfo CreateButtonMethod = typeof(InteractionButtonsContainer).GetMethod("method_1", BindingFlags.Public | BindingFlags.Instance); private static SimpleContextMenuButton CreateButton(this InteractionButtonsContainer instance, string key, string caption, SimpleContextMenuButton template, RectTransform container, [CanBeNull] Sprite sprite, [CanBeNull] Action onButtonClicked, [CanBeNull] Action onMouseHover, bool subMenu = false, bool autoClose = true) => (SimpleContextMenuButton)CreateButtonMethod.Invoke(instance, [ key, caption, template, container, sprite, onButtonClicked, onMouseHover, subMenu, autoClose ]); private static readonly MethodInfo CloseSubMenuMethod = typeof(InteractionButtonsContainer).GetMethod("method_4", BindingFlags.Public | BindingFlags.Instance); private static void CloseSubMenu(this InteractionButtonsContainer instance) => CloseSubMenuMethod.Invoke(instance, null); private static readonly MethodInfo AddButtonMethod = typeof(InteractionButtonsContainer).GetMethod("method_5", BindingFlags.Public | BindingFlags.Instance); private static void AddButton(this InteractionButtonsContainer instance, SimpleContextMenuButton button) => AddButtonMethod.Invoke(instance, [button]); public static void AddCustomButton(this InteractionButtonsContainer instance, CustomInteractionImpl impl) { bool isInteractive = impl.IsInteractive(); SimpleContextMenuButton button = null; button = instance.CreateButton( impl.Key, impl.Caption?.Invoke() ?? "", instance.GetButtonTemplate(), instance.GetButtonsContainer(), impl.Icon?.Invoke(), () => { if (isInteractive) impl.Execute(); }, () => { instance.SetCurrentButton(button); instance.CloseSubMenu(); if (isInteractive) { CustomSubInteractions subMenu = impl.SubMenu?.Invoke(); if (subMenu is not null) instance.SetSubInteractions(subMenu.Impl); } }, impl.SubMenu is not null, false ); button.SetButtonInteraction( isInteractive ? SuccessfulResult.New : new FailedResult(impl.Error?.Invoke() ?? "", 0) ); instance.AddButton(button); } }