Major reflection refactor into R helper class
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
using Aki.Reflection.Patching;
|
||||
using EFT.UI;
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -9,19 +7,16 @@ namespace UIFixes
|
||||
{
|
||||
public class ConfirmationDialogKeysPatch : ModulePatch
|
||||
{
|
||||
private static MethodInfo AcceptMethod;
|
||||
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
Type dialogWindowType = typeof(MessageWindow).BaseType;
|
||||
AcceptMethod = AccessTools.Method(dialogWindowType, "Accept");
|
||||
|
||||
return AccessTools.Method(dialogWindowType, "Update");
|
||||
return AccessTools.Method(R.DialogWindow.Type, "Update");
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
public static void Postfix(object __instance, bool ___bool_0)
|
||||
{
|
||||
var instance = new R.DialogWindow(__instance);
|
||||
|
||||
if (!___bool_0)
|
||||
{
|
||||
return;
|
||||
@@ -29,7 +24,7 @@ namespace UIFixes
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter) || Input.GetKeyDown(KeyCode.Space))
|
||||
{
|
||||
AcceptMethod.Invoke(__instance, []);
|
||||
instance.Accept();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Aki.Reflection.Patching;
|
||||
using EFT.UI.Chat;
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace UIFixes
|
||||
|
||||
@@ -1,39 +1,32 @@
|
||||
using Aki.Reflection.Patching;
|
||||
using Aki.Reflection.Utils;
|
||||
using EFT.InputSystem;
|
||||
using EFT.InventoryLogic;
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace UIFixes
|
||||
{
|
||||
public class FixWeaponBindsDisplayPatch : ModulePatch
|
||||
{
|
||||
private static Type ControlSettingsClass;
|
||||
private static MethodInfo GetKeyNameMethod;
|
||||
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
ControlSettingsClass = PatchConstants.EftTypes.Single(x => x.GetMethod("GetBoundItemNames") != null); // GClass960
|
||||
GetKeyNameMethod = AccessTools.Method(ControlSettingsClass, "GetKeyName");
|
||||
return AccessTools.Method(ControlSettingsClass, "GetBoundItemNames");
|
||||
return AccessTools.Method(R.ControlSettings.Type, "GetBoundItemNames");
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
public static void Postfix(object __instance, EBoundItem boundItem, ref string __result)
|
||||
{
|
||||
var instance = new R.ControlSettings(__instance);
|
||||
switch(boundItem)
|
||||
{
|
||||
case EBoundItem.Item1:
|
||||
__result = GetKeyNameMethod.Invoke(__instance, [EGameKey.SecondaryWeapon]) as string;
|
||||
__result = instance.GetKeyName(EGameKey.SecondaryWeapon);
|
||||
break;
|
||||
case EBoundItem.Item2:
|
||||
__result = GetKeyNameMethod.Invoke(__instance, [EGameKey.PrimaryWeaponFirst]) as string;
|
||||
__result = instance.GetKeyName(EGameKey.PrimaryWeaponFirst);
|
||||
break;
|
||||
case EBoundItem.Item3:
|
||||
__result = GetKeyNameMethod.Invoke(__instance, [EGameKey.PrimaryWeaponSecond]) as string;
|
||||
__result = instance.GetKeyName(EGameKey.PrimaryWeaponSecond);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,16 +12,10 @@ namespace UIFixes
|
||||
{
|
||||
public class HideoutSearchPatches
|
||||
{
|
||||
private static FieldInfo ProductionPanelSearch;
|
||||
private static FieldInfo SubstrateContentLayoutField;
|
||||
|
||||
private static readonly Dictionary<string, string> LastSearches = [];
|
||||
|
||||
public static void Enable()
|
||||
{
|
||||
ProductionPanelSearch = AccessTools.Field(typeof(ProductionPanel), "_searchInputField");
|
||||
SubstrateContentLayoutField = AccessTools.Field(typeof(AreaScreenSubstrate), "_contentLayout");
|
||||
|
||||
new FixHideoutSearchPatch().Enable();
|
||||
new RestoreHideoutSearchPatch().Enable();
|
||||
new SaveHideoutSearchPatch().Enable();
|
||||
@@ -35,20 +29,17 @@ namespace UIFixes
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
Type type = typeof(ProductionPanel).GetNestedTypes().First(t =>
|
||||
{
|
||||
MethodInfo method = t.GetMethod("method_6");
|
||||
return method != null && method.GetParameters().Length == 2 && method.GetParameters()[1].ParameterType == typeof(ProduceView);
|
||||
});
|
||||
|
||||
return AccessTools.Method(type, "method_6");
|
||||
return AccessTools.Method(R.ProductionPanelShowSubclass.Type, "method_6");
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
public static void Postfix(ProductionPanel.Class1631 __instance, GClass1923 scheme, ProduceView view)
|
||||
public static void Postfix(object __instance, GClass1923 scheme, ProduceView view)
|
||||
{
|
||||
var searchField = ProductionPanelSearch.GetValue(__instance.productionPanel_0) as ValidationInputField;
|
||||
if (searchField.text.Length > 0 && scheme.endProduct.LocalizedName().IndexOf(searchField.text, StringComparison.InvariantCultureIgnoreCase) < 0)
|
||||
var instance = new R.ProductionPanelShowSubclass(__instance);
|
||||
var productScheme = new R.Scheme(scheme);
|
||||
|
||||
ValidationInputField searchField = new R.ProductionPanel(instance.ProductionPanel).SeachInputField;
|
||||
if (searchField.text.Length > 0 && productScheme.EndProduct.LocalizedName().IndexOf(searchField.text, StringComparison.InvariantCultureIgnoreCase) < 0)
|
||||
{
|
||||
view.GameObject.SetActive(false);
|
||||
}
|
||||
@@ -58,7 +49,6 @@ namespace UIFixes
|
||||
// Populate the search box, and force the window to render
|
||||
public class RestoreHideoutSearchPatch : ModulePatch
|
||||
{
|
||||
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return AccessTools.Method(typeof(ProductionPanel), nameof(ProductionPanel.ShowContents));
|
||||
@@ -80,7 +70,7 @@ namespace UIFixes
|
||||
if (__instance.method_4().Count() > 2)
|
||||
{
|
||||
AreaScreenSubstrate areaScreenSubstrate = __instance.GetComponentInParent<AreaScreenSubstrate>();
|
||||
LayoutElement layoutElement = SubstrateContentLayoutField.GetValue(areaScreenSubstrate) as LayoutElement;
|
||||
LayoutElement layoutElement = new R.AreaScreenSubstrate(areaScreenSubstrate).ContentLayout;
|
||||
layoutElement.minHeight = 750f; // aka areaScreenSubstrate._maxHeight
|
||||
areaScreenSubstrate.method_8();
|
||||
}
|
||||
@@ -98,8 +88,7 @@ namespace UIFixes
|
||||
return AccessTools.Method(typeof(ProductionPanel), nameof(ProductionPanel.method_4));
|
||||
}
|
||||
|
||||
// Working with GClasses directly here, because this would be a nightmare with reflection
|
||||
// Copied directly from method_4
|
||||
// Copied directly from method_4. Working with GClasses directly here, because this would be a nightmare with reflection
|
||||
[PatchPrefix]
|
||||
public static bool Prefix(ref IEnumerable<GClass1923> __result, ProductionPanel __instance, GClass1922[] ___gclass1922_0, ValidationInputField ____searchInputField)
|
||||
{
|
||||
@@ -143,7 +132,7 @@ namespace UIFixes
|
||||
|
||||
// Reset the default behavior
|
||||
AreaScreenSubstrate areaScreenSubstrate = __instance.GetComponentInParent<AreaScreenSubstrate>();
|
||||
LayoutElement layoutElement = SubstrateContentLayoutField.GetValue(areaScreenSubstrate) as LayoutElement;
|
||||
LayoutElement layoutElement = new R.AreaScreenSubstrate(areaScreenSubstrate).ContentLayout;
|
||||
layoutElement.minHeight = -1f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,20 +16,8 @@ namespace UIFixes
|
||||
{
|
||||
public class InspectWindowStatsPatches
|
||||
{
|
||||
private static FieldInfo AttributeCompactPanelDictionaryField;
|
||||
private static FieldInfo AttributeCompactDropdownDictionaryField;
|
||||
|
||||
private static FieldInfo CompactCharacteristicPanelItemAttributeField;
|
||||
private static FieldInfo CompactCharacteristicPanelCompareItemAttributeField;
|
||||
|
||||
public static void Enable()
|
||||
{
|
||||
AttributeCompactPanelDictionaryField = AccessTools.GetDeclaredFields(typeof(ItemSpecificationPanel)).First(f => typeof(IEnumerable<KeyValuePair<ItemAttributeClass, CompactCharacteristicPanel>>).IsAssignableFrom(f.FieldType));
|
||||
AttributeCompactDropdownDictionaryField = AccessTools.GetDeclaredFields(typeof(ItemSpecificationPanel)).First(f => typeof(IEnumerable<KeyValuePair<ItemAttributeClass, CompactCharacteristicDropdownPanel>>).IsAssignableFrom(f.FieldType));
|
||||
|
||||
CompactCharacteristicPanelItemAttributeField = AccessTools.Field(typeof(CompactCharacteristicPanel), "ItemAttribute");
|
||||
CompactCharacteristicPanelCompareItemAttributeField = AccessTools.Field(typeof(CompactCharacteristicPanel), "CompareItemAttribute");
|
||||
|
||||
new AddShowHideModStatsButtonPatch().Enable();
|
||||
new CalculateModStatsPatch().Enable();
|
||||
new CompareModStatsPatch().Enable();
|
||||
@@ -52,6 +40,8 @@ namespace UIFixes
|
||||
Transform ____compactPanel,
|
||||
SimpleTooltip ___simpleTooltip_0)
|
||||
{
|
||||
var instance = new R.ItemSpecificationPanel(__instance);
|
||||
|
||||
if (!Settings.ShowModStats.Value || ___item_0 is not Mod)
|
||||
{
|
||||
return;
|
||||
@@ -64,28 +54,25 @@ namespace UIFixes
|
||||
}
|
||||
|
||||
// Clean up existing one
|
||||
if (AttributeCompactPanelDictionaryField.GetValue(__instance) is IDisposable compactPanels)
|
||||
if (instance.CompactCharacteristicPanels is IDisposable compactPanels)
|
||||
{
|
||||
compactPanels.Dispose();
|
||||
}
|
||||
|
||||
var newCompactPanels = Activator.CreateInstance(AttributeCompactPanelDictionaryField.FieldType,
|
||||
[
|
||||
var newCompactPanels = R.ItemSpecificationPanel.CreateCompactCharacteristicPanels(
|
||||
deepAttributes,
|
||||
____compactCharTemplate,
|
||||
____compactPanel,
|
||||
(ItemAttributeClass attribute, CompactCharacteristicPanel viewer) => viewer.Show(attribute, ___simpleTooltip_0, __instance.Boolean_0, 100)
|
||||
]) as IEnumerable<KeyValuePair<ItemAttributeClass, CompactCharacteristicPanel>>;
|
||||
(attribute, viewer) => viewer.Show(attribute, ___simpleTooltip_0, __instance.Boolean_0, 100));
|
||||
|
||||
AttributeCompactPanelDictionaryField.SetValue(__instance, newCompactPanels);
|
||||
instance.CompactCharacteristicPanels = newCompactPanels;
|
||||
|
||||
if (newCompactPanels.Any())
|
||||
{
|
||||
newCompactPanels.Last().Value.OnTextWidthCalculated += __instance.method_3;
|
||||
int siblingIndex = newCompactPanels.Last().Value.Transform.GetSiblingIndex();
|
||||
|
||||
var compactDropdownPanels = AttributeCompactDropdownDictionaryField.GetValue(__instance) as IEnumerable<KeyValuePair<ItemAttributeClass, CompactCharacteristicDropdownPanel>>;
|
||||
foreach (var item in compactDropdownPanels)
|
||||
foreach (var item in instance.CompactCharacteristicDropdowns)
|
||||
{
|
||||
item.Value.Transform.SetSiblingIndex(++siblingIndex);
|
||||
}
|
||||
@@ -104,12 +91,8 @@ namespace UIFixes
|
||||
// So I have to forcably call the refresh values method
|
||||
private class CompareModStatsPatch : ModulePatch
|
||||
{
|
||||
private static MethodInfo RefreshStaticMethod;
|
||||
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
RefreshStaticMethod = AccessTools.Method(typeof(ItemSpecificationPanel), nameof(ItemSpecificationPanel.smethod_1), null, [typeof(CompactCharacteristicPanel)]);
|
||||
|
||||
return AccessTools.Method(typeof(ItemSpecificationPanel), nameof(ItemSpecificationPanel.method_6));
|
||||
}
|
||||
|
||||
@@ -153,31 +136,15 @@ namespace UIFixes
|
||||
return;
|
||||
}
|
||||
|
||||
var compactPanels = AttributeCompactPanelDictionaryField.GetValue(__instance);
|
||||
RefreshStaticMethod.Invoke(null, [compactPanels, deepAttributes]);
|
||||
var compactPanels = new R.ItemSpecificationPanel(__instance).CompactCharacteristicPanels;
|
||||
R.ItemSpecificationPanel.Refresh(compactPanels, deepAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
private class AddShowHideModStatsButtonPatch : ModulePatch
|
||||
{
|
||||
private static FieldInfo InteractionsButtonsContainerButtonTemplateField;
|
||||
private static FieldInfo InteractionsButtonsContainerContainerField;
|
||||
|
||||
private static FieldInfo InteractionsButtonContainerUIField;
|
||||
private static MethodInfo InteractionsButtonContainerUIAddDisposableMethod;
|
||||
|
||||
private static FieldInfo SimpleContextMenuButtonTextField;
|
||||
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
InteractionsButtonsContainerButtonTemplateField = AccessTools.Field(typeof(InteractionButtonsContainer), "_buttonTemplate");
|
||||
InteractionsButtonsContainerContainerField = AccessTools.Field(typeof(InteractionButtonsContainer), "_buttonsContainer");
|
||||
|
||||
InteractionsButtonContainerUIField = AccessTools.Field(typeof(InteractionButtonsContainer), "UI");
|
||||
InteractionsButtonContainerUIAddDisposableMethod = AccessTools.Method(InteractionsButtonContainerUIField.FieldType, "AddDisposable", [typeof(Action)]);
|
||||
|
||||
SimpleContextMenuButtonTextField = AccessTools.Field(typeof(ContextMenuButton), "_text");
|
||||
|
||||
return AccessTools.Method(typeof(ItemSpecificationPanel), nameof(ItemSpecificationPanel.method_4));
|
||||
}
|
||||
|
||||
@@ -194,15 +161,14 @@ namespace UIFixes
|
||||
return;
|
||||
}
|
||||
|
||||
SimpleContextMenuButton template = InteractionsButtonsContainerButtonTemplateField.GetValue(____interactionButtonsContainer) as SimpleContextMenuButton;
|
||||
Transform transform = InteractionsButtonsContainerContainerField.GetValue(____interactionButtonsContainer) as Transform;
|
||||
var buttonsContainer = new R.InteractionButtonsContainer(____interactionButtonsContainer);
|
||||
|
||||
SimpleContextMenuButton toggleButton = null;
|
||||
|
||||
// Listen to the setting and the work there to handle multiple windows open at once
|
||||
void onSettingChanged(object sender, EventArgs args)
|
||||
{
|
||||
var text = SimpleContextMenuButtonTextField.GetValue(toggleButton) as TextMeshProUGUI;
|
||||
var text = new R.ContextMenuButton(toggleButton).Text;
|
||||
text.text = GetLabel();
|
||||
|
||||
__instance.method_5(); // rebuild stat panels
|
||||
@@ -217,7 +183,7 @@ namespace UIFixes
|
||||
void createButton()
|
||||
{
|
||||
Sprite sprite = CacheResourcesPopAbstractClass.Pop<Sprite>("Characteristics/Icons/Modding");
|
||||
toggleButton = UnityEngine.Object.Instantiate(template, transform, false);
|
||||
toggleButton = UnityEngine.Object.Instantiate(buttonsContainer.ButtonTemplate, buttonsContainer.Container, false);
|
||||
toggleButton.Show(GetLabel(), null, sprite, onClick, null);
|
||||
____interactionButtonsContainer.method_5(toggleButton); // add to disposable list
|
||||
}
|
||||
@@ -226,11 +192,11 @@ namespace UIFixes
|
||||
contextInteractions.OnRedrawRequired += createButton;
|
||||
|
||||
// And unsubscribe when the window goes away
|
||||
InteractionsButtonContainerUIAddDisposableMethod.Invoke(InteractionsButtonContainerUIField.GetValue(____interactionButtonsContainer), [() =>
|
||||
buttonsContainer.AddDisposable(() =>
|
||||
{
|
||||
contextInteractions.OnRedrawRequired -= createButton;
|
||||
Settings.ShowModStats.SettingChanged -= onSettingChanged;
|
||||
}]);
|
||||
});
|
||||
|
||||
createButton();
|
||||
}
|
||||
@@ -346,14 +312,16 @@ namespace UIFixes
|
||||
const string DecreasingColorHex = "#C40000";
|
||||
|
||||
string text = textMesh.text;
|
||||
ItemAttributeClass attribute = CompactCharacteristicPanelItemAttributeField.GetValue(panel) as ItemAttributeClass;
|
||||
var wrappedPanel = new R.CompactCharacteristicPanel(panel);
|
||||
ItemAttributeClass attribute = wrappedPanel.ItemAttribute;
|
||||
|
||||
// Holy shit did they mess up MOA. Half of the calculation is done in the StringValue() method, so calculating delta from Base() loses all that
|
||||
// Plus, they round the difference to the nearest integer (!?)
|
||||
// Completely redo it
|
||||
if ((EItemAttributeId)attribute.Id == EItemAttributeId.CenterOfImpact)
|
||||
{
|
||||
if (CompactCharacteristicPanelCompareItemAttributeField.GetValue(panel) is ItemAttributeClass compareAttribute)
|
||||
var compareAttribute = wrappedPanel.CompareItemAttribute;
|
||||
if (compareAttribute != null)
|
||||
{
|
||||
string currentStringValue = attribute.StringValue();
|
||||
var moaMatch = Regex.Match(currentStringValue, @"^(\S+)");
|
||||
|
||||
@@ -27,7 +27,6 @@ namespace UIFixes
|
||||
{
|
||||
for (int i = __result.Actions.Count - 1; i >= 0; i--)
|
||||
{
|
||||
// if (__result.Actions[i].Disabled)
|
||||
if (UnimplementedActions.Contains(__result.Actions[i].Name))
|
||||
{
|
||||
__result.Actions.RemoveAt(i);
|
||||
|
||||
@@ -17,24 +17,8 @@ namespace UIFixes
|
||||
{
|
||||
public class SwapPatches
|
||||
{
|
||||
// Types needed
|
||||
private static Type GridItemAddressType; // GClass2769
|
||||
private static FieldInfo GridItemAddressLocationInGridField;
|
||||
private static PropertyInfo GridItemAddressGridProperty;
|
||||
|
||||
private static Type SlotItemAddressType; // GClass2767
|
||||
private static FieldInfo SlotItemAddressSlotField;
|
||||
|
||||
private static Type CanAcceptOperationType; // GStruct413
|
||||
private static PropertyInfo CanAcceptOperationSucceededProperty;
|
||||
private static PropertyInfo CanAcceptOperationErrorProperty;
|
||||
|
||||
private static Type SwapOperationType; // GStruct414<GClass2797>
|
||||
private static MethodInfo SwapOperationToCanAcceptOperationOperator;
|
||||
|
||||
// Source container for the drag - we have to grab this early to check it
|
||||
private static IContainer SourceContainer;
|
||||
private static FieldInfo GridViewNonInteractableField;
|
||||
|
||||
// Whether we're being called from the "check every slot" loop
|
||||
private static bool InHighlight = false;
|
||||
@@ -50,22 +34,6 @@ namespace UIFixes
|
||||
|
||||
public static void Enable()
|
||||
{
|
||||
GridItemAddressType = PatchConstants.EftTypes.First(t => typeof(ItemAddress).IsAssignableFrom(t) && t.GetProperty("Grid") != null); // GClass2769
|
||||
GridItemAddressLocationInGridField = AccessTools.Field(GridItemAddressType, "LocationInGrid");
|
||||
GridItemAddressGridProperty = AccessTools.Property(GridItemAddressType, "Grid");
|
||||
|
||||
SlotItemAddressType = PatchConstants.EftTypes.First(t => typeof(ItemAddress).IsAssignableFrom(t) && t.GetField("Slot") != null); // GClass2767
|
||||
SlotItemAddressSlotField = AccessTools.Field(SlotItemAddressType, "Slot");
|
||||
|
||||
CanAcceptOperationType = AccessTools.Method(typeof(GridView), "CanAccept").GetParameters()[2].ParameterType.GetElementType(); // GStruct413, parameter is a ref type, get underlying type
|
||||
CanAcceptOperationSucceededProperty = AccessTools.Property(CanAcceptOperationType, "Succeeded");
|
||||
CanAcceptOperationErrorProperty = AccessTools.Property(CanAcceptOperationType, "Error");
|
||||
|
||||
SwapOperationType = AccessTools.Method(typeof(InteractionsHandlerClass), nameof(InteractionsHandlerClass.Swap)).ReturnType; // GStruct414<GClass2797>
|
||||
SwapOperationToCanAcceptOperationOperator = SwapOperationType.GetMethods().First(m => m.Name == "op_Implicit" && m.ReturnType == CanAcceptOperationType);
|
||||
|
||||
GridViewNonInteractableField = AccessTools.Field(typeof(GridView), "_nonInteractable");
|
||||
|
||||
new DetectSwapSourceContainerPatch().Enable();
|
||||
new GridViewCanAcceptSwapPatch().Enable();
|
||||
new DetectGridHighlightPrecheckPatch().Enable();
|
||||
@@ -89,7 +57,9 @@ namespace UIFixes
|
||||
return false;
|
||||
}
|
||||
|
||||
if (InHighlight || itemContext == null || targetItemContext == null || (bool)CanAcceptOperationSucceededProperty.GetValue(operation) == true)
|
||||
var wrappedOperation = new R.GridViewCanAcceptOperation(operation);
|
||||
|
||||
if (InHighlight || itemContext == null || targetItemContext == null || wrappedOperation.Succeeded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -114,12 +84,12 @@ namespace UIFixes
|
||||
}
|
||||
|
||||
// Check if the source container is a non-interactable GridView. Specifically for StashSearch, but may exist in other scenarios?
|
||||
if (SourceContainer != null && SourceContainer is GridView && (bool)GridViewNonInteractableField.GetValue(SourceContainer))
|
||||
if (SourceContainer != null && SourceContainer is GridView && new R.GridView(SourceContainer).NonInteractable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string error = CanAcceptOperationErrorProperty.GetValue(operation).ToString();
|
||||
string error = wrappedOperation.Error.ToString();
|
||||
if (Settings.SwapImpossibleContainers.Value && !InRaid() && error.StartsWith("No free room"))
|
||||
{
|
||||
// Check if it isn't allowed in that container, if so try to swap
|
||||
@@ -182,11 +152,8 @@ namespace UIFixes
|
||||
|
||||
public class GridViewCanAcceptSwapPatch : ModulePatch
|
||||
{
|
||||
private static FieldInfo GridViewTraderControllerClassField;
|
||||
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
GridViewTraderControllerClassField = AccessTools.GetDeclaredFields(typeof(GridView)).First(f => f.FieldType == typeof(TraderControllerClass));
|
||||
return AccessTools.Method(typeof(GridView), nameof(GridView.CanAccept));
|
||||
}
|
||||
|
||||
@@ -199,11 +166,14 @@ namespace UIFixes
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GridItemAddressType.IsInstanceOfType(itemAddressA) && GridItemAddressType.IsInstanceOfType(itemAddressB))
|
||||
if (R.GridItemAddress.Type.IsInstanceOfType(itemAddressA) && R.GridItemAddress.Type.IsInstanceOfType(itemAddressB))
|
||||
{
|
||||
LocationInGrid locationA = GridItemAddressLocationInGridField.GetValue(itemAddressA) as LocationInGrid;
|
||||
LocationInGrid locationB = GridItemAddressLocationInGridField.GetValue(itemAddressB) as LocationInGrid;
|
||||
StashGridClass grid = GridItemAddressGridProperty.GetValue(itemAddressA) as StashGridClass;
|
||||
var gridItemAddressA = new R.GridItemAddress(itemAddressA);
|
||||
var gridItemAddressB = new R.GridItemAddress(itemAddressB);
|
||||
|
||||
LocationInGrid locationA = gridItemAddressA.Location;
|
||||
LocationInGrid locationB = gridItemAddressB.Location;
|
||||
StashGridClass grid = gridItemAddressA.Grid;
|
||||
|
||||
var itemASize = itemA.CalculateRotatedSize(locationA.r);
|
||||
var itemASlots = new List<int>();
|
||||
@@ -243,9 +213,9 @@ namespace UIFixes
|
||||
Item item = itemContext.Item;
|
||||
Item targetItem = targetItemContext.Item;
|
||||
ItemAddress itemAddress = item.Parent;
|
||||
ItemAddress targetAddress = targetItem.Parent;
|
||||
ItemAddress targetItemAddress = targetItem.Parent;
|
||||
|
||||
if (targetAddress == null)
|
||||
if (targetItemAddress == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -259,24 +229,26 @@ namespace UIFixes
|
||||
}
|
||||
}
|
||||
|
||||
// This is the location you're dragging it over, including rotation
|
||||
// This is the location you're dragging it, including rotation
|
||||
LocationInGrid itemToLocation = __instance.CalculateItemLocation(itemContext);
|
||||
|
||||
// This is a grid because we're in the GridView patch, i.e. you're dragging it over a grid
|
||||
ItemAddress itemToAddress = Activator.CreateInstance(GridItemAddressType, [GridItemAddressGridProperty.GetValue(targetAddress), itemToLocation]) as ItemAddress;
|
||||
// Target is a grid because we're in the GridView patch, i.e. you're dragging it over a grid
|
||||
var targetGridItemAddress = new R.GridItemAddress(targetItemAddress);
|
||||
ItemAddress itemToAddress = R.GridItemAddress.Create(targetGridItemAddress.Grid, itemToLocation);
|
||||
|
||||
ItemAddress targetToAddress;
|
||||
if (GridItemAddressType.IsInstanceOfType(itemAddress))
|
||||
if (R.GridItemAddress.Type.IsInstanceOfType(itemAddress))
|
||||
{
|
||||
LocationInGrid targetToLocation = (GridItemAddressLocationInGridField.GetValue(itemAddress) as LocationInGrid).Clone();
|
||||
targetToLocation.r = (GridItemAddressLocationInGridField.GetValue(targetAddress) as LocationInGrid).r;
|
||||
var gridItemAddress = new R.GridItemAddress(itemAddress);
|
||||
|
||||
StashGridClass grid = GridItemAddressGridProperty.GetValue(itemAddress) as StashGridClass;
|
||||
targetToAddress = Activator.CreateInstance(GridItemAddressType, [grid, targetToLocation]) as ItemAddress;
|
||||
LocationInGrid targetToLocation = gridItemAddress.Location.Clone();
|
||||
targetToLocation.r = targetGridItemAddress.Location.r;
|
||||
|
||||
targetToAddress = R.GridItemAddress.Create(gridItemAddress.Grid, targetToLocation);
|
||||
}
|
||||
else if (SlotItemAddressType.IsInstanceOfType(itemAddress))
|
||||
else if (R.SlotItemAddress.Type.IsInstanceOfType(itemAddress))
|
||||
{
|
||||
targetToAddress = Activator.CreateInstance(SlotItemAddressType, [SlotItemAddressSlotField.GetValue(itemAddress)]) as ItemAddress;
|
||||
targetToAddress = R.SlotItemAddress.Create(new R.SlotItemAddress(itemAddress).Slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -284,14 +256,14 @@ namespace UIFixes
|
||||
}
|
||||
|
||||
// Get the TraderControllerClass
|
||||
TraderControllerClass traderControllerClass = GridViewTraderControllerClassField.GetValue(__instance) as TraderControllerClass;
|
||||
TraderControllerClass traderControllerClass = new R.GridView(__instance).TraderController;
|
||||
|
||||
// Check that the destinations won't overlap (Swap won't check this)
|
||||
if (!ItemsOverlap(item, itemToAddress, targetItem, targetToAddress))
|
||||
{
|
||||
// Try original rotations
|
||||
var result = InteractionsHandlerClass.Swap(item, itemToAddress, targetItem, targetToAddress, traderControllerClass, true);
|
||||
operation = SwapOperationToCanAcceptOperationOperator.Invoke(null, [result]);
|
||||
operation = new R.SwapOperation(result).ToGridViewCanAcceptOperation();
|
||||
__result = result.Succeeded;
|
||||
if (result.Succeeded)
|
||||
{
|
||||
@@ -300,9 +272,10 @@ namespace UIFixes
|
||||
}
|
||||
|
||||
// If we're coming from a grid, try rotating the target object
|
||||
if (GridItemAddressType.IsInstanceOfType(itemAddress))
|
||||
if (R.GridItemAddress.Type.IsInstanceOfType(itemAddress))
|
||||
{
|
||||
var targetToLocation = GridItemAddressLocationInGridField.GetValue(targetToAddress) as LocationInGrid;
|
||||
var gridItemAddress = new R.GridItemAddress(itemAddress);
|
||||
var targetToLocation = gridItemAddress.Location;
|
||||
targetToLocation.r = targetToLocation.r == ItemRotation.Horizontal ? ItemRotation.Vertical : ItemRotation.Horizontal;
|
||||
if (!ItemsOverlap(item, itemToAddress, targetItem, targetToAddress))
|
||||
{
|
||||
@@ -310,7 +283,7 @@ namespace UIFixes
|
||||
if (result.Succeeded)
|
||||
{
|
||||
// Only save this operation result if it succeeded, otherwise we return the non-rotated result from above
|
||||
operation = SwapOperationToCanAcceptOperationOperator.Invoke(null, [result]);
|
||||
operation = new R.SwapOperation(result).ToGridViewCanAcceptOperation();
|
||||
__result = true;
|
||||
return;
|
||||
}
|
||||
@@ -326,7 +299,7 @@ namespace UIFixes
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return AccessTools.Method(SwapOperationType.GenericTypeArguments[0], "RaiseEvents"); // GClass2787
|
||||
return AccessTools.Method(R.SwapOperation.Type.GenericTypeArguments[0], "RaiseEvents"); // GClass2797
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
@@ -404,7 +377,7 @@ namespace UIFixes
|
||||
|
||||
var item = __instance.Item;
|
||||
var targetItem = slot.ContainedItem;
|
||||
var itemToAddress = Activator.CreateInstance(SlotItemAddressType, [slot]) as ItemAddress;
|
||||
var itemToAddress = R.SlotItemAddress.Create(slot);
|
||||
var targetToAddress = item.Parent;
|
||||
|
||||
// Repair kits again
|
||||
@@ -415,7 +388,7 @@ namespace UIFixes
|
||||
}
|
||||
|
||||
var result = InteractionsHandlerClass.Swap(item, itemToAddress, targetItem, targetToAddress, itemController, simulate);
|
||||
operation = SwapOperationToCanAcceptOperationOperator.Invoke(null, [result]);
|
||||
operation = new R.SwapOperation(result).ToGridViewCanAcceptOperation();
|
||||
__result = result.Succeeded;
|
||||
}
|
||||
}
|
||||
@@ -500,7 +473,7 @@ namespace UIFixes
|
||||
ItemSpecificationPanel panel = sourceComponent.GetComponentInParent<ItemSpecificationPanel>();
|
||||
if (panel != null)
|
||||
{
|
||||
Slot slot = SlotItemAddressSlotField.GetValue(__instance.ItemAddress) as Slot;
|
||||
Slot slot = new R.SlotItemAddress(__instance.ItemAddress).Slot;
|
||||
ItemContextClass itemUnderCursorContext = itemUnderCursor != null ? new ItemContextClass(itemUnderCursor, ItemRotation.Horizontal) : null;
|
||||
panel.method_15(slot, itemUnderCursorContext);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using EFT.InventoryLogic;
|
||||
using EFT.UI;
|
||||
using EFT.UI.WeaponModding;
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace UIFixes
|
||||
{
|
||||
Settings.Init(Config);
|
||||
|
||||
R.Init();
|
||||
|
||||
new ConfirmationDialogKeysPatch().Enable();
|
||||
new FixMailRecieveAllPatch().Enable();
|
||||
new FixTooltipPatch().Enable();
|
||||
|
||||
311
R.cs
Normal file
311
R.cs
Normal file
@@ -0,0 +1,311 @@
|
||||
using Aki.Reflection.Utils;
|
||||
using Diz.LanguageExtensions;
|
||||
using EFT.InputSystem;
|
||||
using EFT.InventoryLogic;
|
||||
using EFT.UI;
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UIFixes
|
||||
{
|
||||
public static class R
|
||||
{
|
||||
public static void Init()
|
||||
{
|
||||
// Order is significant, as some reference each other
|
||||
DialogWindow.InitTypes();
|
||||
ControlSettings.InitTypes();
|
||||
ProductionPanel.InitTypes();
|
||||
ProductionPanelShowSubclass.InitTypes();
|
||||
Scheme.InitTypes();
|
||||
AreaScreenSubstrate.InitTypes();
|
||||
ItemSpecificationPanel.InitTypes();
|
||||
CompactCharacteristicPanel.InitTypes();
|
||||
GridItemAddress.InitTypes();
|
||||
SlotItemAddress.InitTypes();
|
||||
GridView.InitTypes();
|
||||
GridViewCanAcceptOperation.InitTypes();
|
||||
SwapOperation.InitTypes();
|
||||
InteractionButtonsContainer.InitTypes();
|
||||
ContextMenuButton.InitTypes();
|
||||
}
|
||||
|
||||
public abstract class Wrapper(object value)
|
||||
{
|
||||
public object Value { get; protected set; } = value;
|
||||
}
|
||||
|
||||
public class DialogWindow(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static MethodInfo AcceptMethod;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = typeof(MessageWindow).BaseType;
|
||||
AcceptMethod = AccessTools.Method(Type, "Accept");
|
||||
}
|
||||
|
||||
public void Accept() => AcceptMethod.Invoke(Value, []);
|
||||
}
|
||||
|
||||
public class ControlSettings(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static MethodInfo GetKeyNameMethod;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = PatchConstants.EftTypes.Single(x => x.GetMethod("GetBoundItemNames") != null); // GClass960
|
||||
GetKeyNameMethod = AccessTools.Method(Type, "GetKeyName");
|
||||
}
|
||||
|
||||
public string GetKeyName(EGameKey key) => (string)GetKeyNameMethod.Invoke(Value, [key]);
|
||||
}
|
||||
|
||||
public class ProductionPanel(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static FieldInfo SearchInputFieldField;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = typeof(EFT.Hideout.ProductionPanel);
|
||||
SearchInputFieldField = AccessTools.Field(Type, "_searchInputField");
|
||||
}
|
||||
|
||||
public ValidationInputField SeachInputField { get { return (ValidationInputField)SearchInputFieldField.GetValue(Value); } }
|
||||
}
|
||||
|
||||
public class ProductionPanelShowSubclass(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static FieldInfo ProductionPanelField;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = typeof(EFT.Hideout.ProductionPanel).GetNestedTypes().First(t => t.GetField("availableSearch") != null); // ProductionPanel.Class1631
|
||||
ProductionPanelField = AccessTools.Field(Type, "productionPanel_0");
|
||||
}
|
||||
|
||||
public EFT.Hideout.ProductionPanel ProductionPanel { get { return (EFT.Hideout.ProductionPanel)ProductionPanelField.GetValue(Value); } }
|
||||
}
|
||||
|
||||
public class Scheme(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static FieldInfo EndProductField;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = PatchConstants.EftTypes.First(t => t.GetField("endProduct") != null); // GClass1923
|
||||
EndProductField = AccessTools.Field(Type, "endProduct");
|
||||
}
|
||||
|
||||
public string EndProduct { get { return (string)EndProductField.GetValue(Value); } }
|
||||
}
|
||||
|
||||
public class AreaScreenSubstrate(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static FieldInfo ContentLayoutField;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = typeof(EFT.Hideout.AreaScreenSubstrate);
|
||||
ContentLayoutField = AccessTools.Field(Type, "_contentLayout");
|
||||
}
|
||||
|
||||
public LayoutElement ContentLayout { get { return (LayoutElement)ContentLayoutField.GetValue(Value); } }
|
||||
}
|
||||
|
||||
public class ItemSpecificationPanel(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static FieldInfo CompactCharacteristicPanelsField;
|
||||
private static FieldInfo CompactCharacteristicDropdownsField;
|
||||
private static MethodInfo RefreshMethod;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = typeof(EFT.UI.ItemSpecificationPanel);
|
||||
CompactCharacteristicPanelsField = AccessTools.GetDeclaredFields(Type).First(f => typeof(IEnumerable<KeyValuePair<ItemAttributeClass, EFT.UI.CompactCharacteristicPanel>>).IsAssignableFrom(f.FieldType));
|
||||
CompactCharacteristicDropdownsField = AccessTools.GetDeclaredFields(Type).First(f => typeof(IEnumerable<KeyValuePair<ItemAttributeClass, EFT.UI.CompactCharacteristicDropdownPanel>>).IsAssignableFrom(f.FieldType));
|
||||
|
||||
RefreshMethod = AccessTools.Method(Type, nameof(EFT.UI.ItemSpecificationPanel.smethod_1), null, [typeof(EFT.UI.CompactCharacteristicPanel)]);
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<ItemAttributeClass, EFT.UI.CompactCharacteristicPanel>> CompactCharacteristicPanels
|
||||
{
|
||||
get { return (IEnumerable<KeyValuePair<ItemAttributeClass, EFT.UI.CompactCharacteristicPanel>>)CompactCharacteristicPanelsField.GetValue(Value); }
|
||||
set { CompactCharacteristicPanelsField.SetValue(Value, value); }
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<ItemAttributeClass, EFT.UI.CompactCharacteristicDropdownPanel>> CompactCharacteristicDropdowns
|
||||
{
|
||||
get { return (IEnumerable<KeyValuePair<ItemAttributeClass, EFT.UI.CompactCharacteristicDropdownPanel>>)CompactCharacteristicDropdownsField.GetValue(Value); }
|
||||
set { CompactCharacteristicDropdownsField.SetValue(Value, value); }
|
||||
}
|
||||
|
||||
public static IEnumerable<KeyValuePair<ItemAttributeClass, EFT.UI.CompactCharacteristicPanel>> CreateCompactCharacteristicPanels(
|
||||
IEnumerable<ItemAttributeClass> items,
|
||||
EFT.UI.CompactCharacteristicPanel template,
|
||||
Transform transform,
|
||||
Action<ItemAttributeClass, EFT.UI.CompactCharacteristicPanel> showAction)
|
||||
{
|
||||
return (IEnumerable<KeyValuePair<ItemAttributeClass, EFT.UI.CompactCharacteristicPanel>>)Activator.CreateInstance(CompactCharacteristicPanelsField.FieldType, [items, template, transform, showAction]);
|
||||
}
|
||||
|
||||
public static void Refresh(IEnumerable<KeyValuePair<ItemAttributeClass, EFT.UI.CompactCharacteristicPanel>> viewList, IReadOnlyCollection<ItemAttributeClass> changedList) => RefreshMethod.Invoke(null, [viewList, changedList]);
|
||||
}
|
||||
|
||||
public class CompactCharacteristicPanel(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static FieldInfo ItemAttributeField;
|
||||
private static FieldInfo CompareItemAttributeField;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = typeof(EFT.UI.CompactCharacteristicPanel);
|
||||
ItemAttributeField = AccessTools.Field(Type, "ItemAttribute");
|
||||
CompareItemAttributeField = AccessTools.Field(Type, "CompareItemAttribute");
|
||||
}
|
||||
|
||||
public ItemAttributeClass ItemAttribute { get { return (ItemAttributeClass)ItemAttributeField.GetValue(Value); } }
|
||||
public ItemAttributeClass CompareItemAttribute { get { return (ItemAttributeClass)CompareItemAttributeField.GetValue(Value); } }
|
||||
}
|
||||
|
||||
public class GridItemAddress(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static FieldInfo LocationInGridField;
|
||||
private static PropertyInfo GridProperty;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = PatchConstants.EftTypes.First(t => typeof(ItemAddress).IsAssignableFrom(t) && t.GetProperty("Grid") != null); // GClass2769
|
||||
LocationInGridField = AccessTools.Field(Type, "LocationInGrid");
|
||||
GridProperty = AccessTools.Property(Type, "Grid");
|
||||
}
|
||||
|
||||
public static ItemAddress Create(StashGridClass grid, LocationInGrid location)
|
||||
{
|
||||
return (ItemAddress)Activator.CreateInstance(Type, [grid, location]);
|
||||
}
|
||||
|
||||
public LocationInGrid Location { get { return (LocationInGrid)LocationInGridField.GetValue(Value); } }
|
||||
public StashGridClass Grid { get { return (StashGridClass)GridProperty.GetValue(Value); } }
|
||||
}
|
||||
|
||||
public class SlotItemAddress(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static FieldInfo SlotField;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = PatchConstants.EftTypes.First(t => typeof(ItemAddress).IsAssignableFrom(t) && t.GetField("Slot") != null); // GClass2767
|
||||
SlotField = AccessTools.Field(Type, "Slot");
|
||||
}
|
||||
|
||||
public static ItemAddress Create(Slot slot)
|
||||
{
|
||||
return (ItemAddress)Activator.CreateInstance(Type, [slot]);
|
||||
}
|
||||
|
||||
public Slot Slot { get { return (Slot)SlotField.GetValue(Value); } }
|
||||
}
|
||||
|
||||
public class GridView(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static FieldInfo TraderControllerField;
|
||||
private static FieldInfo NonInteractableField;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = typeof(EFT.UI.DragAndDrop.GridView);
|
||||
TraderControllerField = AccessTools.GetDeclaredFields(Type).First(f => f.FieldType == typeof(TraderControllerClass));
|
||||
NonInteractableField = AccessTools.Field(Type, "_nonInteractable");
|
||||
}
|
||||
|
||||
public TraderControllerClass TraderController { get { return (TraderControllerClass)TraderControllerField.GetValue(Value); } }
|
||||
public bool NonInteractable { get { return (bool)NonInteractableField.GetValue(Value); } }
|
||||
}
|
||||
|
||||
public class GridViewCanAcceptOperation(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static PropertyInfo SucceededProperty;
|
||||
private static PropertyInfo ErrorProperty;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = AccessTools.Method(typeof(EFT.UI.DragAndDrop.GridView), "CanAccept").GetParameters()[2].ParameterType.GetElementType(); // GStruct413, parameter is a ref type, get underlying type
|
||||
SucceededProperty = AccessTools.Property(Type, "Succeeded");
|
||||
ErrorProperty = AccessTools.Property(Type, "Error");
|
||||
}
|
||||
|
||||
public bool Succeeded { get { return (bool)SucceededProperty.GetValue(Value); } }
|
||||
public Error Error { get { return (Error)ErrorProperty.GetValue(Value); } }
|
||||
}
|
||||
|
||||
public class SwapOperation(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static MethodInfo ImplicitCastToGridViewCanAcceptOperationMethod;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = AccessTools.Method(typeof(InteractionsHandlerClass), nameof(InteractionsHandlerClass.Swap)).ReturnType; // GStruct414<GClass2797>
|
||||
ImplicitCastToGridViewCanAcceptOperationMethod = Type.GetMethods().First(m => m.Name == "op_Implicit" && m.ReturnType == GridViewCanAcceptOperation.Type);
|
||||
}
|
||||
|
||||
public object ToGridViewCanAcceptOperation() => ImplicitCastToGridViewCanAcceptOperationMethod.Invoke(null, [Value]);
|
||||
}
|
||||
|
||||
public class InteractionButtonsContainer(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set; }
|
||||
private static FieldInfo ButtonTemplateField;
|
||||
private static FieldInfo ContainerField;
|
||||
private static FieldInfo UIField;
|
||||
private static MethodInfo UIAddDisposableMethod;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = typeof(EFT.UI.InteractionButtonsContainer);
|
||||
ButtonTemplateField = AccessTools.Field(Type, "_buttonTemplate");
|
||||
ContainerField = AccessTools.Field(Type, "_buttonsContainer");
|
||||
UIField = AccessTools.Field(Type, "UI"); // GClass767
|
||||
UIAddDisposableMethod = AccessTools.Method(UIField.FieldType, "AddDisposable", [typeof(Action)]);
|
||||
}
|
||||
|
||||
public SimpleContextMenuButton ButtonTemplate { get { return (SimpleContextMenuButton)ButtonTemplateField.GetValue(Value); } }
|
||||
public Transform Container { get { return (Transform)ContainerField.GetValue(Value); } }
|
||||
public object UI { get { return UIField.GetValue(Value); } }
|
||||
public void AddDisposable(Action action) => UIAddDisposableMethod.Invoke(UI, [action]);
|
||||
}
|
||||
|
||||
public class ContextMenuButton(object value) : Wrapper(value)
|
||||
{
|
||||
public static Type Type { get; private set;}
|
||||
private static FieldInfo TextField;
|
||||
|
||||
public static void InitTypes()
|
||||
{
|
||||
Type = typeof(EFT.UI.ContextMenuButton);
|
||||
TextField = AccessTools.Field(Type, "_text");
|
||||
}
|
||||
|
||||
public TextMeshProUGUI Text { get { return (TextMeshProUGUI)TextField.GetValue(Value); } }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user