Major reflection refactor into R helper class
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
using Aki.Reflection.Patching;
|
using Aki.Reflection.Patching;
|
||||||
using EFT.UI;
|
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@@ -9,19 +7,16 @@ namespace UIFixes
|
|||||||
{
|
{
|
||||||
public class ConfirmationDialogKeysPatch : ModulePatch
|
public class ConfirmationDialogKeysPatch : ModulePatch
|
||||||
{
|
{
|
||||||
private static MethodInfo AcceptMethod;
|
|
||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
Type dialogWindowType = typeof(MessageWindow).BaseType;
|
return AccessTools.Method(R.DialogWindow.Type, "Update");
|
||||||
AcceptMethod = AccessTools.Method(dialogWindowType, "Accept");
|
|
||||||
|
|
||||||
return AccessTools.Method(dialogWindowType, "Update");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
public static void Postfix(object __instance, bool ___bool_0)
|
public static void Postfix(object __instance, bool ___bool_0)
|
||||||
{
|
{
|
||||||
|
var instance = new R.DialogWindow(__instance);
|
||||||
|
|
||||||
if (!___bool_0)
|
if (!___bool_0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -29,7 +24,7 @@ namespace UIFixes
|
|||||||
|
|
||||||
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter) || Input.GetKeyDown(KeyCode.Space))
|
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter) || Input.GetKeyDown(KeyCode.Space))
|
||||||
{
|
{
|
||||||
AcceptMethod.Invoke(__instance, []);
|
instance.Accept();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Aki.Reflection.Patching;
|
using Aki.Reflection.Patching;
|
||||||
using EFT.UI.Chat;
|
using EFT.UI.Chat;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace UIFixes
|
namespace UIFixes
|
||||||
|
|||||||
@@ -1,39 +1,32 @@
|
|||||||
using Aki.Reflection.Patching;
|
using Aki.Reflection.Patching;
|
||||||
using Aki.Reflection.Utils;
|
|
||||||
using EFT.InputSystem;
|
using EFT.InputSystem;
|
||||||
using EFT.InventoryLogic;
|
using EFT.InventoryLogic;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace UIFixes
|
namespace UIFixes
|
||||||
{
|
{
|
||||||
public class FixWeaponBindsDisplayPatch : ModulePatch
|
public class FixWeaponBindsDisplayPatch : ModulePatch
|
||||||
{
|
{
|
||||||
private static Type ControlSettingsClass;
|
|
||||||
private static MethodInfo GetKeyNameMethod;
|
|
||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
ControlSettingsClass = PatchConstants.EftTypes.Single(x => x.GetMethod("GetBoundItemNames") != null); // GClass960
|
return AccessTools.Method(R.ControlSettings.Type, "GetBoundItemNames");
|
||||||
GetKeyNameMethod = AccessTools.Method(ControlSettingsClass, "GetKeyName");
|
|
||||||
return AccessTools.Method(ControlSettingsClass, "GetBoundItemNames");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
public static void Postfix(object __instance, EBoundItem boundItem, ref string __result)
|
public static void Postfix(object __instance, EBoundItem boundItem, ref string __result)
|
||||||
{
|
{
|
||||||
|
var instance = new R.ControlSettings(__instance);
|
||||||
switch(boundItem)
|
switch(boundItem)
|
||||||
{
|
{
|
||||||
case EBoundItem.Item1:
|
case EBoundItem.Item1:
|
||||||
__result = GetKeyNameMethod.Invoke(__instance, [EGameKey.SecondaryWeapon]) as string;
|
__result = instance.GetKeyName(EGameKey.SecondaryWeapon);
|
||||||
break;
|
break;
|
||||||
case EBoundItem.Item2:
|
case EBoundItem.Item2:
|
||||||
__result = GetKeyNameMethod.Invoke(__instance, [EGameKey.PrimaryWeaponFirst]) as string;
|
__result = instance.GetKeyName(EGameKey.PrimaryWeaponFirst);
|
||||||
break;
|
break;
|
||||||
case EBoundItem.Item3:
|
case EBoundItem.Item3:
|
||||||
__result = GetKeyNameMethod.Invoke(__instance, [EGameKey.PrimaryWeaponSecond]) as string;
|
__result = instance.GetKeyName(EGameKey.PrimaryWeaponSecond);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,16 +12,10 @@ namespace UIFixes
|
|||||||
{
|
{
|
||||||
public class HideoutSearchPatches
|
public class HideoutSearchPatches
|
||||||
{
|
{
|
||||||
private static FieldInfo ProductionPanelSearch;
|
|
||||||
private static FieldInfo SubstrateContentLayoutField;
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, string> LastSearches = [];
|
private static readonly Dictionary<string, string> LastSearches = [];
|
||||||
|
|
||||||
public static void Enable()
|
public static void Enable()
|
||||||
{
|
{
|
||||||
ProductionPanelSearch = AccessTools.Field(typeof(ProductionPanel), "_searchInputField");
|
|
||||||
SubstrateContentLayoutField = AccessTools.Field(typeof(AreaScreenSubstrate), "_contentLayout");
|
|
||||||
|
|
||||||
new FixHideoutSearchPatch().Enable();
|
new FixHideoutSearchPatch().Enable();
|
||||||
new RestoreHideoutSearchPatch().Enable();
|
new RestoreHideoutSearchPatch().Enable();
|
||||||
new SaveHideoutSearchPatch().Enable();
|
new SaveHideoutSearchPatch().Enable();
|
||||||
@@ -35,20 +29,17 @@ namespace UIFixes
|
|||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
Type type = typeof(ProductionPanel).GetNestedTypes().First(t =>
|
return AccessTools.Method(R.ProductionPanelShowSubclass.Type, "method_6");
|
||||||
{
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPostfix]
|
[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;
|
var instance = new R.ProductionPanelShowSubclass(__instance);
|
||||||
if (searchField.text.Length > 0 && scheme.endProduct.LocalizedName().IndexOf(searchField.text, StringComparison.InvariantCultureIgnoreCase) < 0)
|
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);
|
view.GameObject.SetActive(false);
|
||||||
}
|
}
|
||||||
@@ -58,7 +49,6 @@ namespace UIFixes
|
|||||||
// Populate the search box, and force the window to render
|
// Populate the search box, and force the window to render
|
||||||
public class RestoreHideoutSearchPatch : ModulePatch
|
public class RestoreHideoutSearchPatch : ModulePatch
|
||||||
{
|
{
|
||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(typeof(ProductionPanel), nameof(ProductionPanel.ShowContents));
|
return AccessTools.Method(typeof(ProductionPanel), nameof(ProductionPanel.ShowContents));
|
||||||
@@ -80,7 +70,7 @@ namespace UIFixes
|
|||||||
if (__instance.method_4().Count() > 2)
|
if (__instance.method_4().Count() > 2)
|
||||||
{
|
{
|
||||||
AreaScreenSubstrate areaScreenSubstrate = __instance.GetComponentInParent<AreaScreenSubstrate>();
|
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
|
layoutElement.minHeight = 750f; // aka areaScreenSubstrate._maxHeight
|
||||||
areaScreenSubstrate.method_8();
|
areaScreenSubstrate.method_8();
|
||||||
}
|
}
|
||||||
@@ -98,8 +88,7 @@ namespace UIFixes
|
|||||||
return AccessTools.Method(typeof(ProductionPanel), nameof(ProductionPanel.method_4));
|
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. Working with GClasses directly here, because this would be a nightmare with reflection
|
||||||
// Copied directly from method_4
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
public static bool Prefix(ref IEnumerable<GClass1923> __result, ProductionPanel __instance, GClass1922[] ___gclass1922_0, ValidationInputField ____searchInputField)
|
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
|
// Reset the default behavior
|
||||||
AreaScreenSubstrate areaScreenSubstrate = __instance.GetComponentInParent<AreaScreenSubstrate>();
|
AreaScreenSubstrate areaScreenSubstrate = __instance.GetComponentInParent<AreaScreenSubstrate>();
|
||||||
LayoutElement layoutElement = SubstrateContentLayoutField.GetValue(areaScreenSubstrate) as LayoutElement;
|
LayoutElement layoutElement = new R.AreaScreenSubstrate(areaScreenSubstrate).ContentLayout;
|
||||||
layoutElement.minHeight = -1f;
|
layoutElement.minHeight = -1f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,20 +16,8 @@ namespace UIFixes
|
|||||||
{
|
{
|
||||||
public class InspectWindowStatsPatches
|
public class InspectWindowStatsPatches
|
||||||
{
|
{
|
||||||
private static FieldInfo AttributeCompactPanelDictionaryField;
|
|
||||||
private static FieldInfo AttributeCompactDropdownDictionaryField;
|
|
||||||
|
|
||||||
private static FieldInfo CompactCharacteristicPanelItemAttributeField;
|
|
||||||
private static FieldInfo CompactCharacteristicPanelCompareItemAttributeField;
|
|
||||||
|
|
||||||
public static void Enable()
|
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 AddShowHideModStatsButtonPatch().Enable();
|
||||||
new CalculateModStatsPatch().Enable();
|
new CalculateModStatsPatch().Enable();
|
||||||
new CompareModStatsPatch().Enable();
|
new CompareModStatsPatch().Enable();
|
||||||
@@ -52,6 +40,8 @@ namespace UIFixes
|
|||||||
Transform ____compactPanel,
|
Transform ____compactPanel,
|
||||||
SimpleTooltip ___simpleTooltip_0)
|
SimpleTooltip ___simpleTooltip_0)
|
||||||
{
|
{
|
||||||
|
var instance = new R.ItemSpecificationPanel(__instance);
|
||||||
|
|
||||||
if (!Settings.ShowModStats.Value || ___item_0 is not Mod)
|
if (!Settings.ShowModStats.Value || ___item_0 is not Mod)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -64,28 +54,25 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clean up existing one
|
// Clean up existing one
|
||||||
if (AttributeCompactPanelDictionaryField.GetValue(__instance) is IDisposable compactPanels)
|
if (instance.CompactCharacteristicPanels is IDisposable compactPanels)
|
||||||
{
|
{
|
||||||
compactPanels.Dispose();
|
compactPanels.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
var newCompactPanels = Activator.CreateInstance(AttributeCompactPanelDictionaryField.FieldType,
|
var newCompactPanels = R.ItemSpecificationPanel.CreateCompactCharacteristicPanels(
|
||||||
[
|
|
||||||
deepAttributes,
|
deepAttributes,
|
||||||
____compactCharTemplate,
|
____compactCharTemplate,
|
||||||
____compactPanel,
|
____compactPanel,
|
||||||
(ItemAttributeClass attribute, CompactCharacteristicPanel viewer) => viewer.Show(attribute, ___simpleTooltip_0, __instance.Boolean_0, 100)
|
(attribute, viewer) => viewer.Show(attribute, ___simpleTooltip_0, __instance.Boolean_0, 100));
|
||||||
]) as IEnumerable<KeyValuePair<ItemAttributeClass, CompactCharacteristicPanel>>;
|
|
||||||
|
|
||||||
AttributeCompactPanelDictionaryField.SetValue(__instance, newCompactPanels);
|
instance.CompactCharacteristicPanels = newCompactPanels;
|
||||||
|
|
||||||
if (newCompactPanels.Any())
|
if (newCompactPanels.Any())
|
||||||
{
|
{
|
||||||
newCompactPanels.Last().Value.OnTextWidthCalculated += __instance.method_3;
|
newCompactPanels.Last().Value.OnTextWidthCalculated += __instance.method_3;
|
||||||
int siblingIndex = newCompactPanels.Last().Value.Transform.GetSiblingIndex();
|
int siblingIndex = newCompactPanels.Last().Value.Transform.GetSiblingIndex();
|
||||||
|
|
||||||
var compactDropdownPanels = AttributeCompactDropdownDictionaryField.GetValue(__instance) as IEnumerable<KeyValuePair<ItemAttributeClass, CompactCharacteristicDropdownPanel>>;
|
foreach (var item in instance.CompactCharacteristicDropdowns)
|
||||||
foreach (var item in compactDropdownPanels)
|
|
||||||
{
|
{
|
||||||
item.Value.Transform.SetSiblingIndex(++siblingIndex);
|
item.Value.Transform.SetSiblingIndex(++siblingIndex);
|
||||||
}
|
}
|
||||||
@@ -104,12 +91,8 @@ namespace UIFixes
|
|||||||
// So I have to forcably call the refresh values method
|
// So I have to forcably call the refresh values method
|
||||||
private class CompareModStatsPatch : ModulePatch
|
private class CompareModStatsPatch : ModulePatch
|
||||||
{
|
{
|
||||||
private static MethodInfo RefreshStaticMethod;
|
|
||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
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));
|
return AccessTools.Method(typeof(ItemSpecificationPanel), nameof(ItemSpecificationPanel.method_6));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,31 +136,15 @@ namespace UIFixes
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var compactPanels = AttributeCompactPanelDictionaryField.GetValue(__instance);
|
var compactPanels = new R.ItemSpecificationPanel(__instance).CompactCharacteristicPanels;
|
||||||
RefreshStaticMethod.Invoke(null, [compactPanels, deepAttributes]);
|
R.ItemSpecificationPanel.Refresh(compactPanels, deepAttributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AddShowHideModStatsButtonPatch : ModulePatch
|
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()
|
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));
|
return AccessTools.Method(typeof(ItemSpecificationPanel), nameof(ItemSpecificationPanel.method_4));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,15 +161,14 @@ namespace UIFixes
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleContextMenuButton template = InteractionsButtonsContainerButtonTemplateField.GetValue(____interactionButtonsContainer) as SimpleContextMenuButton;
|
var buttonsContainer = new R.InteractionButtonsContainer(____interactionButtonsContainer);
|
||||||
Transform transform = InteractionsButtonsContainerContainerField.GetValue(____interactionButtonsContainer) as Transform;
|
|
||||||
|
|
||||||
SimpleContextMenuButton toggleButton = null;
|
SimpleContextMenuButton toggleButton = null;
|
||||||
|
|
||||||
// Listen to the setting and the work there to handle multiple windows open at once
|
// Listen to the setting and the work there to handle multiple windows open at once
|
||||||
void onSettingChanged(object sender, EventArgs args)
|
void onSettingChanged(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
var text = SimpleContextMenuButtonTextField.GetValue(toggleButton) as TextMeshProUGUI;
|
var text = new R.ContextMenuButton(toggleButton).Text;
|
||||||
text.text = GetLabel();
|
text.text = GetLabel();
|
||||||
|
|
||||||
__instance.method_5(); // rebuild stat panels
|
__instance.method_5(); // rebuild stat panels
|
||||||
@@ -217,7 +183,7 @@ namespace UIFixes
|
|||||||
void createButton()
|
void createButton()
|
||||||
{
|
{
|
||||||
Sprite sprite = CacheResourcesPopAbstractClass.Pop<Sprite>("Characteristics/Icons/Modding");
|
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);
|
toggleButton.Show(GetLabel(), null, sprite, onClick, null);
|
||||||
____interactionButtonsContainer.method_5(toggleButton); // add to disposable list
|
____interactionButtonsContainer.method_5(toggleButton); // add to disposable list
|
||||||
}
|
}
|
||||||
@@ -226,11 +192,11 @@ namespace UIFixes
|
|||||||
contextInteractions.OnRedrawRequired += createButton;
|
contextInteractions.OnRedrawRequired += createButton;
|
||||||
|
|
||||||
// And unsubscribe when the window goes away
|
// And unsubscribe when the window goes away
|
||||||
InteractionsButtonContainerUIAddDisposableMethod.Invoke(InteractionsButtonContainerUIField.GetValue(____interactionButtonsContainer), [() =>
|
buttonsContainer.AddDisposable(() =>
|
||||||
{
|
{
|
||||||
contextInteractions.OnRedrawRequired -= createButton;
|
contextInteractions.OnRedrawRequired -= createButton;
|
||||||
Settings.ShowModStats.SettingChanged -= onSettingChanged;
|
Settings.ShowModStats.SettingChanged -= onSettingChanged;
|
||||||
}]);
|
});
|
||||||
|
|
||||||
createButton();
|
createButton();
|
||||||
}
|
}
|
||||||
@@ -346,14 +312,16 @@ namespace UIFixes
|
|||||||
const string DecreasingColorHex = "#C40000";
|
const string DecreasingColorHex = "#C40000";
|
||||||
|
|
||||||
string text = textMesh.text;
|
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
|
// 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 (!?)
|
// Plus, they round the difference to the nearest integer (!?)
|
||||||
// Completely redo it
|
// Completely redo it
|
||||||
if ((EItemAttributeId)attribute.Id == EItemAttributeId.CenterOfImpact)
|
if ((EItemAttributeId)attribute.Id == EItemAttributeId.CenterOfImpact)
|
||||||
{
|
{
|
||||||
if (CompactCharacteristicPanelCompareItemAttributeField.GetValue(panel) is ItemAttributeClass compareAttribute)
|
var compareAttribute = wrappedPanel.CompareItemAttribute;
|
||||||
|
if (compareAttribute != null)
|
||||||
{
|
{
|
||||||
string currentStringValue = attribute.StringValue();
|
string currentStringValue = attribute.StringValue();
|
||||||
var moaMatch = Regex.Match(currentStringValue, @"^(\S+)");
|
var moaMatch = Regex.Match(currentStringValue, @"^(\S+)");
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ namespace UIFixes
|
|||||||
{
|
{
|
||||||
for (int i = __result.Actions.Count - 1; i >= 0; i--)
|
for (int i = __result.Actions.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
// if (__result.Actions[i].Disabled)
|
|
||||||
if (UnimplementedActions.Contains(__result.Actions[i].Name))
|
if (UnimplementedActions.Contains(__result.Actions[i].Name))
|
||||||
{
|
{
|
||||||
__result.Actions.RemoveAt(i);
|
__result.Actions.RemoveAt(i);
|
||||||
|
|||||||
@@ -17,24 +17,8 @@ namespace UIFixes
|
|||||||
{
|
{
|
||||||
public class SwapPatches
|
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
|
// Source container for the drag - we have to grab this early to check it
|
||||||
private static IContainer SourceContainer;
|
private static IContainer SourceContainer;
|
||||||
private static FieldInfo GridViewNonInteractableField;
|
|
||||||
|
|
||||||
// Whether we're being called from the "check every slot" loop
|
// Whether we're being called from the "check every slot" loop
|
||||||
private static bool InHighlight = false;
|
private static bool InHighlight = false;
|
||||||
@@ -50,22 +34,6 @@ namespace UIFixes
|
|||||||
|
|
||||||
public static void Enable()
|
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 DetectSwapSourceContainerPatch().Enable();
|
||||||
new GridViewCanAcceptSwapPatch().Enable();
|
new GridViewCanAcceptSwapPatch().Enable();
|
||||||
new DetectGridHighlightPrecheckPatch().Enable();
|
new DetectGridHighlightPrecheckPatch().Enable();
|
||||||
@@ -89,7 +57,9 @@ namespace UIFixes
|
|||||||
return false;
|
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;
|
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?
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string error = CanAcceptOperationErrorProperty.GetValue(operation).ToString();
|
string error = wrappedOperation.Error.ToString();
|
||||||
if (Settings.SwapImpossibleContainers.Value && !InRaid() && error.StartsWith("No free room"))
|
if (Settings.SwapImpossibleContainers.Value && !InRaid() && error.StartsWith("No free room"))
|
||||||
{
|
{
|
||||||
// Check if it isn't allowed in that container, if so try to swap
|
// Check if it isn't allowed in that container, if so try to swap
|
||||||
@@ -182,11 +152,8 @@ namespace UIFixes
|
|||||||
|
|
||||||
public class GridViewCanAcceptSwapPatch : ModulePatch
|
public class GridViewCanAcceptSwapPatch : ModulePatch
|
||||||
{
|
{
|
||||||
private static FieldInfo GridViewTraderControllerClassField;
|
|
||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
GridViewTraderControllerClassField = AccessTools.GetDeclaredFields(typeof(GridView)).First(f => f.FieldType == typeof(TraderControllerClass));
|
|
||||||
return AccessTools.Method(typeof(GridView), nameof(GridView.CanAccept));
|
return AccessTools.Method(typeof(GridView), nameof(GridView.CanAccept));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,11 +166,14 @@ namespace UIFixes
|
|||||||
return false;
|
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;
|
var gridItemAddressA = new R.GridItemAddress(itemAddressA);
|
||||||
LocationInGrid locationB = GridItemAddressLocationInGridField.GetValue(itemAddressB) as LocationInGrid;
|
var gridItemAddressB = new R.GridItemAddress(itemAddressB);
|
||||||
StashGridClass grid = GridItemAddressGridProperty.GetValue(itemAddressA) as StashGridClass;
|
|
||||||
|
LocationInGrid locationA = gridItemAddressA.Location;
|
||||||
|
LocationInGrid locationB = gridItemAddressB.Location;
|
||||||
|
StashGridClass grid = gridItemAddressA.Grid;
|
||||||
|
|
||||||
var itemASize = itemA.CalculateRotatedSize(locationA.r);
|
var itemASize = itemA.CalculateRotatedSize(locationA.r);
|
||||||
var itemASlots = new List<int>();
|
var itemASlots = new List<int>();
|
||||||
@@ -243,9 +213,9 @@ namespace UIFixes
|
|||||||
Item item = itemContext.Item;
|
Item item = itemContext.Item;
|
||||||
Item targetItem = targetItemContext.Item;
|
Item targetItem = targetItemContext.Item;
|
||||||
ItemAddress itemAddress = item.Parent;
|
ItemAddress itemAddress = item.Parent;
|
||||||
ItemAddress targetAddress = targetItem.Parent;
|
ItemAddress targetItemAddress = targetItem.Parent;
|
||||||
|
|
||||||
if (targetAddress == null)
|
if (targetItemAddress == null)
|
||||||
{
|
{
|
||||||
return;
|
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);
|
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
|
// Target 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;
|
var targetGridItemAddress = new R.GridItemAddress(targetItemAddress);
|
||||||
|
ItemAddress itemToAddress = R.GridItemAddress.Create(targetGridItemAddress.Grid, itemToLocation);
|
||||||
|
|
||||||
ItemAddress targetToAddress;
|
ItemAddress targetToAddress;
|
||||||
if (GridItemAddressType.IsInstanceOfType(itemAddress))
|
if (R.GridItemAddress.Type.IsInstanceOfType(itemAddress))
|
||||||
{
|
{
|
||||||
LocationInGrid targetToLocation = (GridItemAddressLocationInGridField.GetValue(itemAddress) as LocationInGrid).Clone();
|
var gridItemAddress = new R.GridItemAddress(itemAddress);
|
||||||
targetToLocation.r = (GridItemAddressLocationInGridField.GetValue(targetAddress) as LocationInGrid).r;
|
|
||||||
|
|
||||||
StashGridClass grid = GridItemAddressGridProperty.GetValue(itemAddress) as StashGridClass;
|
LocationInGrid targetToLocation = gridItemAddress.Location.Clone();
|
||||||
targetToAddress = Activator.CreateInstance(GridItemAddressType, [grid, targetToLocation]) as ItemAddress;
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -284,14 +256,14 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the TraderControllerClass
|
// 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)
|
// Check that the destinations won't overlap (Swap won't check this)
|
||||||
if (!ItemsOverlap(item, itemToAddress, targetItem, targetToAddress))
|
if (!ItemsOverlap(item, itemToAddress, targetItem, targetToAddress))
|
||||||
{
|
{
|
||||||
// Try original rotations
|
// Try original rotations
|
||||||
var result = InteractionsHandlerClass.Swap(item, itemToAddress, targetItem, targetToAddress, traderControllerClass, true);
|
var result = InteractionsHandlerClass.Swap(item, itemToAddress, targetItem, targetToAddress, traderControllerClass, true);
|
||||||
operation = SwapOperationToCanAcceptOperationOperator.Invoke(null, [result]);
|
operation = new R.SwapOperation(result).ToGridViewCanAcceptOperation();
|
||||||
__result = result.Succeeded;
|
__result = result.Succeeded;
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
@@ -300,9 +272,10 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we're coming from a grid, try rotating the target object
|
// 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;
|
targetToLocation.r = targetToLocation.r == ItemRotation.Horizontal ? ItemRotation.Vertical : ItemRotation.Horizontal;
|
||||||
if (!ItemsOverlap(item, itemToAddress, targetItem, targetToAddress))
|
if (!ItemsOverlap(item, itemToAddress, targetItem, targetToAddress))
|
||||||
{
|
{
|
||||||
@@ -310,7 +283,7 @@ namespace UIFixes
|
|||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
// Only save this operation result if it succeeded, otherwise we return the non-rotated result from above
|
// 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;
|
__result = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -326,7 +299,7 @@ namespace UIFixes
|
|||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(SwapOperationType.GenericTypeArguments[0], "RaiseEvents"); // GClass2787
|
return AccessTools.Method(R.SwapOperation.Type.GenericTypeArguments[0], "RaiseEvents"); // GClass2797
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
@@ -404,7 +377,7 @@ namespace UIFixes
|
|||||||
|
|
||||||
var item = __instance.Item;
|
var item = __instance.Item;
|
||||||
var targetItem = slot.ContainedItem;
|
var targetItem = slot.ContainedItem;
|
||||||
var itemToAddress = Activator.CreateInstance(SlotItemAddressType, [slot]) as ItemAddress;
|
var itemToAddress = R.SlotItemAddress.Create(slot);
|
||||||
var targetToAddress = item.Parent;
|
var targetToAddress = item.Parent;
|
||||||
|
|
||||||
// Repair kits again
|
// Repair kits again
|
||||||
@@ -415,7 +388,7 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
|
|
||||||
var result = InteractionsHandlerClass.Swap(item, itemToAddress, targetItem, targetToAddress, itemController, simulate);
|
var result = InteractionsHandlerClass.Swap(item, itemToAddress, targetItem, targetToAddress, itemController, simulate);
|
||||||
operation = SwapOperationToCanAcceptOperationOperator.Invoke(null, [result]);
|
operation = new R.SwapOperation(result).ToGridViewCanAcceptOperation();
|
||||||
__result = result.Succeeded;
|
__result = result.Succeeded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -500,7 +473,7 @@ namespace UIFixes
|
|||||||
ItemSpecificationPanel panel = sourceComponent.GetComponentInParent<ItemSpecificationPanel>();
|
ItemSpecificationPanel panel = sourceComponent.GetComponentInParent<ItemSpecificationPanel>();
|
||||||
if (panel != null)
|
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;
|
ItemContextClass itemUnderCursorContext = itemUnderCursor != null ? new ItemContextClass(itemUnderCursor, ItemRotation.Horizontal) : null;
|
||||||
panel.method_15(slot, itemUnderCursorContext);
|
panel.method_15(slot, itemUnderCursorContext);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using EFT.InventoryLogic;
|
|||||||
using EFT.UI;
|
using EFT.UI;
|
||||||
using EFT.UI.WeaponModding;
|
using EFT.UI.WeaponModding;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ namespace UIFixes
|
|||||||
{
|
{
|
||||||
Settings.Init(Config);
|
Settings.Init(Config);
|
||||||
|
|
||||||
|
R.Init();
|
||||||
|
|
||||||
new ConfirmationDialogKeysPatch().Enable();
|
new ConfirmationDialogKeysPatch().Enable();
|
||||||
new FixMailRecieveAllPatch().Enable();
|
new FixMailRecieveAllPatch().Enable();
|
||||||
new FixTooltipPatch().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