multiselect debug, things seem good?

This commit is contained in:
Tyfon
2024-06-15 17:10:58 -07:00
parent 3c76f3c588
commit b562a8665d
6 changed files with 173 additions and 84 deletions

View File

@@ -17,6 +17,7 @@ namespace UIFixes
private Vector3 selectOrigin; private Vector3 selectOrigin;
private Vector3 selectEnd; private Vector3 selectEnd;
private GraphicRaycaster localRaycaster;
private GraphicRaycaster preloaderRaycaster; private GraphicRaycaster preloaderRaycaster;
private bool drawing; private bool drawing;
@@ -27,6 +28,12 @@ namespace UIFixes
selectTexture.SetPixel(0, 0, new Color(1f, 1f, 1f, 0.6f)); selectTexture.SetPixel(0, 0, new Color(1f, 1f, 1f, 0.6f));
selectTexture.Apply(); selectTexture.Apply();
localRaycaster = GetComponentInParent<GraphicRaycaster>();
if (localRaycaster == null)
{
throw new InvalidOperationException("DrawMultiSelect couldn't find GraphicRayCaster in parents");
}
preloaderRaycaster = Singleton<PreloaderUI>.Instance.transform.GetChild(0).GetComponent<GraphicRaycaster>(); preloaderRaycaster = Singleton<PreloaderUI>.Instance.transform.GetChild(0).GetComponent<GraphicRaycaster>();
if (preloaderRaycaster == null) if (preloaderRaycaster == null)
{ {
@@ -41,13 +48,16 @@ namespace UIFixes
return; return;
} }
// checking ItemUiContext is a quick and easy way to know the mouse is over an item
if (Input.GetKeyDown(KeyCode.Mouse0) && ItemUiContext.Instance.R().ItemContext == null) if (Input.GetKeyDown(KeyCode.Mouse0) && ItemUiContext.Instance.R().ItemContext == null)
{ {
PointerEventData eventData = new(EventSystem.current); PointerEventData eventData = new(EventSystem.current)
eventData.position = Input.mousePosition; {
position = Input.mousePosition
};
List<RaycastResult> results = new(); List<RaycastResult> results = [];
var preloaderRaycaster = Singleton<PreloaderUI>.Instance.transform.GetChild(0).GetComponent<GraphicRaycaster>(); localRaycaster.Raycast(eventData, results);
preloaderRaycaster.Raycast(eventData, results); preloaderRaycaster.Raycast(eventData, results);
foreach (GameObject gameObject in results.Select(r => r.gameObject)) foreach (GameObject gameObject in results.Select(r => r.gameObject))
@@ -86,7 +96,7 @@ namespace UIFixes
float width = itemRect.xMax - itemRect.xMin; float width = itemRect.xMax - itemRect.xMin;
float height = itemRect.yMax - itemRect.yMin; float height = itemRect.yMax - itemRect.yMin;
List<RaycastResult> raycastResults = new(); List<RaycastResult> raycastResults = [];
eventData.position = new Vector2(itemRect.xMin + 0.1f * width, itemRect.yMin + 0.1f * height); eventData.position = new Vector2(itemRect.xMin + 0.1f * width, itemRect.yMin + 0.1f * height);
preloaderRaycaster.Raycast(eventData, raycastResults); preloaderRaycaster.Raycast(eventData, raycastResults);
if (raycastResults.Any() && !raycastResults[0].gameObject.transform.IsDescendantOf(itemTransform)) if (raycastResults.Any() && !raycastResults[0].gameObject.transform.IsDescendantOf(itemTransform))

View File

@@ -1,4 +1,5 @@
using EFT.UI.DragAndDrop; using EFT.UI.DragAndDrop;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using TMPro; using TMPro;
@@ -11,8 +12,8 @@ namespace UIFixes
private static GameObject SelectedMarkTemplate; private static GameObject SelectedMarkTemplate;
private static GameObject SelectedBackgroundTemplate; private static GameObject SelectedBackgroundTemplate;
private static readonly HashSet<GridItemView> SelectedItemViews = []; private static readonly Dictionary<GridItemView, ItemContextClass> SelectedItemViews = [];
private static readonly List<ItemContextClass> SelectedItemContexts = []; private static readonly List<ItemContextClass> SortedItemContexts = [];
public static void Initialize() public static void Initialize()
{ {
@@ -35,7 +36,7 @@ namespace UIFixes
return; return;
} }
if (SelectedItemViews.Contains(itemView)) if (SelectedItemViews.ContainsKey(itemView))
{ {
Deselect(itemView); Deselect(itemView);
} }
@@ -48,7 +49,7 @@ namespace UIFixes
public static void Clear() public static void Clear()
{ {
// ToList() because we'll be modifying the collection // ToList() because we'll be modifying the collection
foreach (GridItemView itemView in SelectedItemViews.ToList()) foreach (GridItemView itemView in SelectedItemViews.Keys.ToList())
{ {
Deselect(itemView); Deselect(itemView);
} }
@@ -56,28 +57,39 @@ namespace UIFixes
public static void Select(GridItemView itemView) public static void Select(GridItemView itemView)
{ {
if (itemView.IsInteractable && SelectedItemViews.Add(itemView)) if (itemView.IsInteractable && !SelectedItemViews.ContainsKey(itemView))
{ {
ItemContextClass itemContext = new ItemContextClass(itemView.ItemContext, itemView.ItemRotation);
itemContext.GClass2813_0.OnDisposed += RugPull;
itemContext.OnDisposed += RugPull;
SelectedItemViews.Add(itemView, itemContext);
SortedItemContexts.Add(itemContext);
ShowSelection(itemView); ShowSelection(itemView);
} }
} }
public static void Deselect(GridItemView itemView) public static void Deselect(GridItemView itemView)
{ {
if (SelectedItemViews.Remove(itemView)) if (SelectedItemViews.TryGetValue(itemView, out ItemContextClass itemContext))
{ {
itemContext.GClass2813_0.OnDisposed -= RugPull;
itemContext.OnDisposed -= RugPull;
itemContext.Dispose();
SortedItemContexts.Remove(itemContext);
SelectedItemViews.Remove(itemView);
HideSelection(itemView); HideSelection(itemView);
} }
} }
public static IEnumerable<ItemView> ItemViews public static bool IsSelected(GridItemView itemView)
{ {
get { return SelectedItemViews; } return SelectedItemViews.ContainsKey(itemView);
} }
public static IEnumerable<ItemContextClass> ItemContexts public static IEnumerable<ItemContextClass> ItemContexts
{ {
get { return SelectedItemContexts; } get { return SortedItemContexts; }
} }
public static int Count public static int Count
@@ -85,39 +97,11 @@ namespace UIFixes
get { return SelectedItemViews.Count; } get { return SelectedItemViews.Count; }
} }
public static bool Contains(GridItemView itemView)
{
return SelectedItemViews.Contains(itemView);
}
public static bool Active public static bool Active
{ {
get { return SelectedItemViews.Count > 1; } get { return SelectedItemViews.Count > 1; }
} }
public static bool IsSelected(GridItemView itemView)
{
return SelectedItemViews.Contains(itemView);
}
public static void BeginDrag()
{
foreach (ItemView itemView in SelectedItemViews)
{
SelectedItemContexts.Add(new ItemContextClass(itemView.ItemContext, itemView.ItemRotation));
}
}
public static void EndDrag()
{
foreach(ItemContextClass itemContext in SelectedItemContexts)
{
itemContext.Dispose();
}
SelectedItemContexts.Clear();
}
public static void ShowDragCount(DraggedItemView draggedItemView) public static void ShowDragCount(DraggedItemView draggedItemView)
{ {
if (Count > 1) if (Count > 1)
@@ -139,6 +123,11 @@ namespace UIFixes
} }
} }
private static void RugPull()
{
throw new InvalidOperationException("ItemContext disposed before MultiSelect was done with it!");
}
private static void ShowSelection(GridItemView itemView) private static void ShowSelection(GridItemView itemView)
{ {
GameObject selectedMark = itemView.transform.Find("SelectedMark")?.gameObject; GameObject selectedMark = itemView.transform.Find("SelectedMark")?.gameObject;

50
MultiSelectDebug.cs Normal file
View File

@@ -0,0 +1,50 @@
using System.Text;
using UnityEngine;
namespace UIFixes
{
public class MultiSelectDebug : MonoBehaviour
{
private GUIStyle guiStyle;
private Rect guiRect = new(20, 20, 0, 0);
GUIContent guiContent;
public void OnGUI()
{
if (!Settings.EnableMultiSelect.Value || !Settings.ShowMultiSelectDebug.Value)
{
return;
}
guiStyle ??= new GUIStyle(GUI.skin.box)
{
alignment = TextAnchor.MiddleLeft,
fontSize = 14,
margin = new RectOffset(3, 3, 3, 3),
richText = true
};
guiContent ??= new GUIContent();
StringBuilder builder = new();
builder.Append("<b>MultiSelect</b>\n");
builder.AppendFormat("Active: <color={0}>{1}</color>\n", MultiSelect.Active ? "green" : "red", MultiSelect.Active);
builder.AppendFormat("Count: <color=yellow>{0}</color>\n", MultiSelect.Count);
builder.Append("Items:\n");
foreach (ItemContextClass itemContext in MultiSelect.ItemContexts)
{
builder.Append(itemContext.Item.ToString());
builder.AppendLine();
}
guiContent.text = builder.ToString();
guiRect.size = guiStyle.CalcSize(guiContent);
GUI.Box(guiRect, guiContent, guiStyle);
}
}
}

View File

@@ -1,4 +1,5 @@
using Aki.Reflection.Patching; using Aki.Reflection.Patching;
using Comfort.Common;
using EFT.InventoryLogic; using EFT.InventoryLogic;
using EFT.UI; using EFT.UI;
using EFT.UI.DragAndDrop; using EFT.UI.DragAndDrop;
@@ -23,14 +24,15 @@ namespace UIFixes
new InitializePatch().Enable(); new InitializePatch().Enable();
new SelectPatch().Enable(); new SelectPatch().Enable();
new DeselectOnOtherMouseDown().Enable(); new DeselectOnOtherMouseDown().Enable();
new DeselectOnMovePatch().Enable(); new DeselectOnItemViewKillPatch().Enable();
new BeginDragPatch().Enable(); new BeginDragPatch().Enable();
new EndDragPatch().Enable();
new GridViewCanAcceptPatch().Enable(); new GridViewCanAcceptPatch().Enable();
new GridViewAcceptItemPatch().Enable(); new GridViewAcceptItemPatch().Enable();
new SlotViewCanAcceptPatch().Enable(); new SlotViewCanAcceptPatch().Enable();
new SlotViewAcceptItemPatch().Enable(); new SlotViewAcceptItemPatch().Enable();
new InspectWindowHack().Enable();
} }
public class InitializePatch : ModulePatch public class InitializePatch : ModulePatch
@@ -50,9 +52,14 @@ namespace UIFixes
MultiSelect.Initialize(); MultiSelect.Initialize();
__instance.InventoryScreen.GetOrAddComponent<DrawMultiSelect>(); __instance.InventoryScreen.transform.Find("Items Panel").gameObject.GetOrAddComponent<DrawMultiSelect>();
__instance.TransferItemsInRaidScreen.GetOrAddComponent<DrawMultiSelect>(); __instance.TransferItemsInRaidScreen.GetOrAddComponent<DrawMultiSelect>();
__instance.TransferItemsScreen.GetOrAddComponent<DrawMultiSelect>(); __instance.TransferItemsScreen.GetOrAddComponent<DrawMultiSelect>();
if (Settings.ShowMultiSelectDebug.Value)
{
Singleton<PreloaderUI>.Instance.GetOrAddComponent<MultiSelectDebug>();
}
} }
} }
@@ -112,15 +119,15 @@ namespace UIFixes
} }
} }
public class DeselectOnMovePatch : ModulePatch public class DeselectOnItemViewKillPatch : ModulePatch
{ {
protected override MethodBase GetTargetMethod() protected override MethodBase GetTargetMethod()
{ {
return AccessTools.Method(typeof(ItemView), nameof(ItemView.Kill)); return AccessTools.Method(typeof(ItemView), nameof(ItemView.Kill));
} }
[PatchPostfix] [PatchPrefix]
public static void Postfix(ItemView __instance) public static void Prefix(ItemView __instance)
{ {
if (!Settings.EnableMultiSelect.Value) if (!Settings.EnableMultiSelect.Value)
{ {
@@ -141,17 +148,6 @@ namespace UIFixes
return AccessTools.Method(typeof(ItemView), nameof(ItemView.OnBeginDrag)); return AccessTools.Method(typeof(ItemView), nameof(ItemView.OnBeginDrag));
} }
[PatchPrefix]
public static void Prefix()
{
if (!Settings.EnableMultiSelect.Value)
{
return;
}
MultiSelect.BeginDrag();
}
[PatchPostfix] [PatchPostfix]
public static void Postfix(ItemView __instance) public static void Postfix(ItemView __instance)
{ {
@@ -164,25 +160,6 @@ namespace UIFixes
} }
} }
public class EndDragPatch : ModulePatch
{
protected override MethodBase GetTargetMethod()
{
return AccessTools.Method(typeof(ItemView), nameof(ItemView.OnEndDrag));
}
[PatchPostfix]
public static void Postfix()
{
if (!Settings.EnableMultiSelect.Value)
{
return;
}
MultiSelect.EndDrag();
}
}
public class GridViewCanAcceptPatch : ModulePatch public class GridViewCanAcceptPatch : ModulePatch
{ {
protected override MethodBase GetTargetMethod() protected override MethodBase GetTargetMethod()
@@ -291,7 +268,7 @@ namespace UIFixes
// Reimplementing this in order to control the simulate param. Need to *not* simulate, then rollback myself in order to test // Reimplementing this in order to control the simulate param. Need to *not* simulate, then rollback myself in order to test
// multiple items going in // multiple items going in
if (targetItemContext != null && !targetItemContext.ModificationAvailable || if (targetItemContext != null && !targetItemContext.ModificationAvailable ||
__instance.ParentItemContext != null && !__instance.ParentItemContext.ModificationAvailable) __instance.ParentItemContext != null && !__instance.ParentItemContext.ModificationAvailable)
{ {
operation = new StashGridClass.GClass3291(__instance.Slot); operation = new StashGridClass.GClass3291(__instance.Slot);
@@ -313,7 +290,7 @@ namespace UIFixes
} }
// We didn't simulate so now we undo // We didn't simulate so now we undo
while(operations.Any()) while (operations.Any())
{ {
operations.Pop().Value?.RollBack(); operations.Pop().Value?.RollBack();
} }
@@ -349,6 +326,29 @@ namespace UIFixes
} }
} }
// The inspect window likes to recreate itself entirely when a slot is removed, which destroys all of the gridviews and
// borks the multiselect. This patch just stops it from responding until the last one (since by then the selection is down to 1, which
// is considered inactive multiselect)
public class InspectWindowHack : ModulePatch
{
protected override MethodBase GetTargetMethod()
{
return AccessTools.Method(typeof(ItemSpecificationPanel), nameof(ItemSpecificationPanel.OnRemoveFromSlotEvent));
}
[PatchPrefix]
public static bool Prefix()
{
if (!Settings.EnableMultiSelect.Value || !MultiSelect.Active)
{
return true;
}
// Just skip it when multiselect is active
return false;
}
}
public class TaskSerializer : MonoBehaviour public class TaskSerializer : MonoBehaviour
{ {
private Func<ItemContextClass, Task> func; private Func<ItemContextClass, Task> func;
@@ -375,7 +375,7 @@ namespace UIFixes
{ {
return; return;
} }
if (itemContexts.Any()) if (itemContexts.Any())
{ {
currentTask = func(itemContexts.Dequeue()); currentTask = func(itemContexts.Dequeue());

View File

@@ -55,6 +55,7 @@ namespace UIFixes
// Inventory // Inventory
public static ConfigEntry<bool> EnableMultiSelect { get; set; } public static ConfigEntry<bool> EnableMultiSelect { get; set; }
public static ConfigEntry<bool> ShowMultiSelectDebug { get; set; } // Advanced
public static ConfigEntry<bool> SwapItems { get; set; } public static ConfigEntry<bool> SwapItems { get; set; }
public static ConfigEntry<bool> SwapImpossibleContainers { get; set; } public static ConfigEntry<bool> SwapImpossibleContainers { get; set; }
public static ConfigEntry<bool> SynchronizeStashScrolling { get; set; } public static ConfigEntry<bool> SynchronizeStashScrolling { get; set; }
@@ -278,10 +279,19 @@ namespace UIFixes
"Enable Multiselect", "Enable Multiselect",
true, true,
new ConfigDescription( new ConfigDescription(
"Enable multiselect via Shift-click and drag-to-select", "Enable multiselect via Shift-click and drag-to-select. This cannot be used together with Auto-open Sorting Table",
null, null,
new ConfigurationManagerAttributes { }))); new ConfigurationManagerAttributes { })));
configEntries.Add(ShowMultiSelectDebug = config.Bind(
InventorySection,
"Show Multiselect Debug",
false,
new ConfigDescription(
"Enable multi-select debugging display",
null,
new ConfigurationManagerAttributes { IsAdvanced = true })));
configEntries.Add(SwapItems = config.Bind( configEntries.Add(SwapItems = config.Bind(
InventorySection, InventorySection,
"Enable In-Place Item Swapping", "Enable In-Place Item Swapping",
@@ -339,9 +349,9 @@ namespace UIFixes
configEntries.Add(AutoOpenSortingTable = config.Bind( configEntries.Add(AutoOpenSortingTable = config.Bind(
InventorySection, InventorySection,
"Auto-open Sorting Table", "Auto-open Sorting Table",
true, false,
new ConfigDescription( new ConfigDescription(
"Automatically open the sorting table if it's closed when you shift-click an item", "Automatically open the sorting table if it's closed when you shift-click an item. This and Enable Multiselect cannot be used together.",
null, null,
new ConfigurationManagerAttributes { }))); new ConfigurationManagerAttributes { })));
@@ -502,7 +512,10 @@ namespace UIFixes
new ConfigurationManagerAttributes { IsAdvanced = true }))); new ConfigurationManagerAttributes { IsAdvanced = true })));
RecalcOrder(configEntries); RecalcOrder(configEntries);
ToggleExclusives();
} }
private static void RecalcOrder(List<ConfigEntryBase> configEntries) private static void RecalcOrder(List<ConfigEntryBase> configEntries)
{ {
// Set the Order field for all settings, to avoid unnecessary changes when adding new settings // Set the Order field for all settings, to avoid unnecessary changes when adding new settings
@@ -517,5 +530,29 @@ namespace UIFixes
settingOrder--; settingOrder--;
} }
} }
private static void ToggleExclusives()
{
if (Settings.EnableMultiSelect.Value)
{
Settings.AutoOpenSortingTable.Value = false;
}
Settings.EnableMultiSelect.SettingChanged += (_, _) =>
{
if (Settings.EnableMultiSelect.Value)
{
Settings.AutoOpenSortingTable.Value = false;
}
};
Settings.AutoOpenSortingTable.SettingChanged += (_, _) =>
{
if (Settings.AutoOpenSortingTable.Value)
{
Settings.EnableMultiSelect.Value = false;
}
};
}
} }
} }

View File

@@ -63,6 +63,9 @@
<Reference Include="UnityEngine.InputLegacyModule"> <Reference Include="UnityEngine.InputLegacyModule">
<HintPath>$(PathToSPT)\EscapeFromTarkov_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath> <HintPath>$(PathToSPT)\EscapeFromTarkov_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
</Reference> </Reference>
<Reference Include="UnityEngine.TextRenderingModule">
<HintPath>..\..\..\..\SPT\3.8.3-debug\EscapeFromTarkov_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UI"> <Reference Include="UnityEngine.UI">
<HintPath>$(PathToSPT)\EscapeFromTarkov_Data\Managed\UnityEngine.UI.dll</HintPath> <HintPath>$(PathToSPT)\EscapeFromTarkov_Data\Managed\UnityEngine.UI.dll</HintPath>
</Reference> </Reference>