gridview containers can accept

This commit is contained in:
Tyfon
2024-06-15 13:14:22 -07:00
parent 0bf508df1f
commit 3c76f3c588
7 changed files with 269 additions and 79 deletions

View File

@@ -1,34 +1,68 @@
using EFT.UI; using Comfort.Common;
using EFT.UI;
using EFT.UI.DragAndDrop; using EFT.UI.DragAndDrop;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace UIFixes namespace UIFixes
{ {
public class DrawMultiSelect : MonoBehaviour public class DrawMultiSelect : MonoBehaviour
{ {
Texture2D selectTexture; private Texture2D selectTexture;
Vector3 selectOrigin; private Vector3 selectOrigin;
Vector3 selectEnd; private Vector3 selectEnd;
bool drawing; private GraphicRaycaster preloaderRaycaster;
private bool drawing;
public void Start() public void Start()
{ {
selectTexture = new Texture2D(1, 1); selectTexture = new Texture2D(1, 1);
selectTexture.SetPixel(0, 0, new Color(1f, 1f, 1f, 0.8f)); selectTexture.SetPixel(0, 0, new Color(1f, 1f, 1f, 0.6f));
selectTexture.Apply(); selectTexture.Apply();
preloaderRaycaster = Singleton<PreloaderUI>.Instance.transform.GetChild(0).GetComponent<GraphicRaycaster>();
if (preloaderRaycaster == null)
{
throw new InvalidOperationException("DrawMultiSelect couldn't find the PreloaderUI GraphicRayCaster");
}
} }
public void Update() public void Update()
{ {
if (!Settings.EnableMultiSelect.Value)
{
return;
}
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);
eventData.position = Input.mousePosition;
List<RaycastResult> results = new();
var preloaderRaycaster = Singleton<PreloaderUI>.Instance.transform.GetChild(0).GetComponent<GraphicRaycaster>();
preloaderRaycaster.Raycast(eventData, results);
foreach (GameObject gameObject in results.Select(r => r.gameObject))
{
var dragInterfaces = gameObject.GetComponents<MonoBehaviour>()
.Where(c => c is IDragHandler || c is IBeginDragHandler)
.Where(c => c is not ScrollRectNoDrag) // this disables scrolling, it doesn't add it
.Where(c => c.name != "Inner"); // there's a random DragTrigger sitting in ItemInfoWindows
if (dragInterfaces.Any())
{
return;
}
}
selectOrigin = Input.mousePosition; selectOrigin = Input.mousePosition;
drawing = true; drawing = true;
} }
@@ -37,20 +71,62 @@ namespace UIFixes
{ {
selectEnd = Input.mousePosition; selectEnd = Input.mousePosition;
Rect selectRect = new(selectOrigin.x, selectOrigin.y, selectEnd.x - selectOrigin.x, selectEnd.y - selectOrigin.y); Rect selectRect = new(selectOrigin, selectEnd - selectOrigin);
foreach (GridItemView gridItemView in GetComponentsInChildren<GridItemView>()) foreach (GridItemView gridItemView in GetComponentsInChildren<GridItemView>().Concat(Singleton<PreloaderUI>.Instance.GetComponentsInChildren<GridItemView>()))
{ {
RectTransform itemTransform = gridItemView.GetComponent<RectTransform>(); RectTransform itemTransform = gridItemView.GetComponent<RectTransform>();
Rect screenRect = new((Vector2)itemTransform.position + itemTransform.rect.position, itemTransform.rect.size); Rect itemRect = new((Vector2)itemTransform.position + itemTransform.rect.position * itemTransform.lossyScale, itemTransform.rect.size * itemTransform.lossyScale);
if (selectRect.Overlaps(screenRect, true)) if (selectRect.Overlaps(itemRect, true))
{ {
// Otherwise, ensure it's not overlapped by window UI
PointerEventData eventData = new(EventSystem.current);
// Non-absolute width/height
float width = itemRect.xMax - itemRect.xMin;
float height = itemRect.yMax - itemRect.yMin;
List<RaycastResult> raycastResults = new();
eventData.position = new Vector2(itemRect.xMin + 0.1f * width, itemRect.yMin + 0.1f * height);
preloaderRaycaster.Raycast(eventData, raycastResults);
if (raycastResults.Any() && !raycastResults[0].gameObject.transform.IsDescendantOf(itemTransform))
{
MultiSelect.Deselect(gridItemView);
continue;
}
raycastResults.Clear();
eventData.position = new Vector2(itemRect.xMin + 0.1f * width, itemRect.yMax - 0.1f * height);
preloaderRaycaster.Raycast(eventData, raycastResults);
if (raycastResults.Any() && !raycastResults[0].gameObject.transform.IsDescendantOf(itemTransform))
{
MultiSelect.Deselect(gridItemView);
continue;
}
raycastResults.Clear();
eventData.position = new Vector2(itemRect.xMax - 0.1f * width, itemRect.yMax - 0.1f * height);
preloaderRaycaster.Raycast(eventData, raycastResults);
if (raycastResults.Any() && !raycastResults[0].gameObject.transform.IsDescendantOf(itemTransform))
{
MultiSelect.Deselect(gridItemView);
continue;
}
raycastResults.Clear();
eventData.position = new Vector2(itemRect.xMax - 0.1f * width, itemRect.yMin + 0.1f * height);
preloaderRaycaster.Raycast(eventData, raycastResults);
if (raycastResults.Any() && !raycastResults[0].gameObject.transform.IsDescendantOf(itemTransform))
{
MultiSelect.Deselect(gridItemView);
continue;
}
MultiSelect.Select(gridItemView); MultiSelect.Select(gridItemView);
continue;
} }
else
{ MultiSelect.Deselect(gridItemView);
MultiSelect.Deselect(gridItemView);
}
} }
} }
@@ -82,6 +158,27 @@ namespace UIFixes
GUI.DrawTexture(lineArea, selectTexture); GUI.DrawTexture(lineArea, selectTexture);
} }
} }
}
public static class TransformExtensions
{
public static bool IsDescendantOf(this Transform transform, Transform target)
{
if (transform == target)
{
return true;
}
while (transform.parent != null)
{
transform = transform.parent;
if (transform == target)
{
return true;
}
}
return false;
}
} }
} }

View File

@@ -1,10 +1,6 @@
using EFT.InventoryLogic; 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 System.Text;
using System.Threading.Tasks;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
@@ -22,8 +18,13 @@ namespace UIFixes
{ {
// Grab the selection objects from ragfair as templates // Grab the selection objects from ragfair as templates
RagfairNewOfferItemView ragfairNewOfferItemView = ItemViewFactory.CreateFromPool<RagfairNewOfferItemView>("ragfair_layout"); RagfairNewOfferItemView ragfairNewOfferItemView = ItemViewFactory.CreateFromPool<RagfairNewOfferItemView>("ragfair_layout");
SelectedMarkTemplate = UnityEngine.Object.Instantiate(ragfairNewOfferItemView.R().SelectedMark, null, false); SelectedMarkTemplate = UnityEngine.Object.Instantiate(ragfairNewOfferItemView.R().SelectedMark, null, false);
UnityEngine.Object.DontDestroyOnLoad(SelectedMarkTemplate);
SelectedBackgroundTemplate = UnityEngine.Object.Instantiate(ragfairNewOfferItemView.R().SelectedBackground, null, false); SelectedBackgroundTemplate = UnityEngine.Object.Instantiate(ragfairNewOfferItemView.R().SelectedBackground, null, false);
UnityEngine.Object.DontDestroyOnLoad(SelectedBackgroundTemplate);
ragfairNewOfferItemView.ReturnToPool(); ragfairNewOfferItemView.ReturnToPool();
} }
@@ -91,7 +92,7 @@ namespace UIFixes
public static bool Active public static bool Active
{ {
get { return SelectedItemViews.Any(); } get { return SelectedItemViews.Count > 1; }
} }
public static bool IsSelected(GridItemView itemView) public static bool IsSelected(GridItemView itemView)

View File

@@ -1,5 +1,5 @@
using Aki.Reflection.Patching; using Aki.Reflection.Patching;
using Comfort.Common; using EFT.InventoryLogic;
using EFT.UI; using EFT.UI;
using EFT.UI.DragAndDrop; using EFT.UI.DragAndDrop;
using HarmonyLib; using HarmonyLib;
@@ -8,7 +8,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
@@ -29,6 +28,7 @@ namespace UIFixes
new EndDragPatch().Enable(); new EndDragPatch().Enable();
new GridViewCanAcceptPatch().Enable(); new GridViewCanAcceptPatch().Enable();
new GridViewAcceptItemPatch().Enable();
new SlotViewCanAcceptPatch().Enable(); new SlotViewCanAcceptPatch().Enable();
new SlotViewAcceptItemPatch().Enable(); new SlotViewAcceptItemPatch().Enable();
} }
@@ -43,11 +43,16 @@ namespace UIFixes
[PatchPostfix] [PatchPostfix]
public static void Postfix(CommonUI __instance) public static void Postfix(CommonUI __instance)
{ {
if (!Settings.EnableMultiSelect.Value)
{
return;
}
MultiSelect.Initialize(); MultiSelect.Initialize();
__instance.InventoryScreen.GetOrAddComponent<DrawMultiSelect>(); __instance.InventoryScreen.GetOrAddComponent<DrawMultiSelect>();
//__instance.TransferItemsInRaidScreen.GetOrAddComponent<DrawMultiSelect>(); __instance.TransferItemsInRaidScreen.GetOrAddComponent<DrawMultiSelect>();
//__instance.TransferItemsScreen.GetOrAddComponent<DrawMultiSelect>(); __instance.TransferItemsScreen.GetOrAddComponent<DrawMultiSelect>();
} }
} }
@@ -61,13 +66,18 @@ namespace UIFixes
[PatchPostfix] [PatchPostfix]
public static void Postfix(GridItemView __instance, PointerEventData.InputButton button) public static void Postfix(GridItemView __instance, PointerEventData.InputButton button)
{ {
if (button == PointerEventData.InputButton.Left && (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))) if (!Settings.EnableMultiSelect.Value)
{
return;
}
if (__instance.Item != null && button == PointerEventData.InputButton.Left && (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)))
{ {
MultiSelect.Toggle(__instance); MultiSelect.Toggle(__instance);
return; return;
} }
if (button == PointerEventData.InputButton.Left)// && !MultiSelect.IsSelected(__instance)) if (button == PointerEventData.InputButton.Left)
{ {
MultiSelect.Clear(); MultiSelect.Clear();
} }
@@ -84,6 +94,11 @@ namespace UIFixes
[PatchPostfix] [PatchPostfix]
public static void Postfix(ItemView __instance, PointerEventData eventData) public static void Postfix(ItemView __instance, PointerEventData eventData)
{ {
if (!Settings.EnableMultiSelect.Value)
{
return;
}
if (eventData.button == PointerEventData.InputButton.Left && (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))) if (eventData.button == PointerEventData.InputButton.Left && (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)))
{ {
// This will be shift-click, let it cook // This will be shift-click, let it cook
@@ -107,6 +122,11 @@ namespace UIFixes
[PatchPostfix] [PatchPostfix]
public static void Postfix(ItemView __instance) public static void Postfix(ItemView __instance)
{ {
if (!Settings.EnableMultiSelect.Value)
{
return;
}
if (__instance is GridItemView gridItemView) if (__instance is GridItemView gridItemView)
{ {
MultiSelect.Deselect(gridItemView); MultiSelect.Deselect(gridItemView);
@@ -124,12 +144,22 @@ namespace UIFixes
[PatchPrefix] [PatchPrefix]
public static void Prefix() public static void Prefix()
{ {
if (!Settings.EnableMultiSelect.Value)
{
return;
}
MultiSelect.BeginDrag(); MultiSelect.BeginDrag();
} }
[PatchPostfix] [PatchPostfix]
public static void Postfix(ItemView __instance) public static void Postfix(ItemView __instance)
{ {
if (!Settings.EnableMultiSelect.Value)
{
return;
}
MultiSelect.ShowDragCount(__instance.DraggedItemView); MultiSelect.ShowDragCount(__instance.DraggedItemView);
} }
} }
@@ -144,6 +174,11 @@ namespace UIFixes
[PatchPostfix] [PatchPostfix]
public static void Postfix() public static void Postfix()
{ {
if (!Settings.EnableMultiSelect.Value)
{
return;
}
MultiSelect.EndDrag(); MultiSelect.EndDrag();
} }
} }
@@ -158,27 +193,84 @@ namespace UIFixes
[PatchPrefix] [PatchPrefix]
public static bool Prefix(GridView __instance, ItemContextAbstractClass targetItemContext, ref GStruct413 operation, ref bool __result) public static bool Prefix(GridView __instance, ItemContextAbstractClass targetItemContext, ref GStruct413 operation, ref bool __result)
{ {
if (InPatch || !MultiSelect.Active) if (!Settings.EnableMultiSelect.Value || InPatch || !MultiSelect.Active)
{ {
return true; return true;
} }
// Reimplementing this in order to control the simulate param. Need to *not* simulate, then rollback myself in order to test
// multiple items going in
var wrappedInstance = __instance.R();
operation = default; operation = default;
__result = false; __result = false;
return false;
/* InPatch = true; if (__instance.Grid == null || wrappedInstance.NonInteractable)
{
return false;
}
if (targetItemContext != null && !targetItemContext.ModificationAvailable)
{
operation = new StashGridClass.GClass3291(__instance.Grid);
return false;
}
Item targetItem = __instance.method_8(targetItemContext);
// baby steps: bail if no targetItem for now
if (targetItem == null)
{
return false;
}
Stack<GStruct413> operations = new();
foreach (ItemContextClass itemContext in MultiSelect.ItemContexts) foreach (ItemContextClass itemContext in MultiSelect.ItemContexts)
{ {
__result = __instance.CanAccept(itemContext, targetItemContext, out operation); operation = wrappedInstance.TraderController.ExecutePossibleAction(itemContext, targetItem, false /* splitting */, false /* simulate */);
if (!__result) if (__result = operation.Succeeded)
{
operations.Push(operation);
}
else
{ {
break; break;
} }
} }
InPatch = false; // We didn't simulate so now we undo
return false;*/ while (operations.Any())
{
operations.Pop().Value?.RollBack();
}
// result and operation are set to the last one that completed - so success if they all passed, or the first failure
return false;
}
}
public class GridViewAcceptItemPatch : ModulePatch
{
protected override MethodBase GetTargetMethod()
{
return AccessTools.Method(typeof(GridView), nameof(GridView.AcceptItem));
}
[PatchPrefix]
public static bool Prefix(GridView __instance, ItemContextAbstractClass targetItemContext, ref Task __result)
{
if (!Settings.EnableMultiSelect.Value || InPatch || !MultiSelect.Active)
{
return true;
}
InPatch = true;
var serializer = __instance.GetOrAddComponent<TaskSerializer>();
__result = serializer.Initialize(MultiSelect.ItemContexts, itemContext => __instance.AcceptItem(itemContext, targetItemContext));
__result.ContinueWith(_ => { InPatch = false; });
return false;
} }
} }
@@ -190,27 +282,43 @@ namespace UIFixes
} }
[PatchPrefix] [PatchPrefix]
public static bool Prefix(SlotView __instance, ItemContextAbstractClass targetItemContext, ref GStruct413 operation, ref bool __result) public static bool Prefix(SlotView __instance, ItemContextAbstractClass targetItemContext, ref GStruct413 operation, ref bool __result, InventoryControllerClass ___InventoryController)
{ {
if (InPatch || !MultiSelect.Active) if (!Settings.EnableMultiSelect.Value || InPatch || !MultiSelect.Active)
{ {
return true; return true;
} }
operation = default; // Reimplementing this in order to control the simulate param. Need to *not* simulate, then rollback myself in order to test
__result = false; // multiple items going in
if (targetItemContext != null && !targetItemContext.ModificationAvailable ||
__instance.ParentItemContext != null && !__instance.ParentItemContext.ModificationAvailable)
{
operation = new StashGridClass.GClass3291(__instance.Slot);
return false;
}
InPatch = true; Stack<GStruct413> operations = new();
foreach (ItemContextClass itemContext in MultiSelect.ItemContexts) foreach (ItemContextClass itemContext in MultiSelect.ItemContexts)
{ {
__result = __instance.CanAccept(itemContext, targetItemContext, out operation); __result = itemContext.CanAccept(__instance.Slot, __instance.ParentItemContext, ___InventoryController, out operation, false /* simulate */);
if (!__result) if (operation.Succeeded)
{
operations.Push(operation);
}
else
{ {
break; break;
} }
} }
InPatch = false; // We didn't simulate so now we undo
while(operations.Any())
{
operations.Pop().Value?.RollBack();
}
// result and operation are set to the last one that completed - so success if they all passed, or the first failure
return false; return false;
} }
} }
@@ -225,22 +333,18 @@ namespace UIFixes
[PatchPrefix] [PatchPrefix]
public static bool Prefix(SlotView __instance, ItemContextAbstractClass targetItemContext, ref Task __result) public static bool Prefix(SlotView __instance, ItemContextAbstractClass targetItemContext, ref Task __result)
{ {
if (InPatch || !MultiSelect.Active) if (!Settings.EnableMultiSelect.Value || InPatch || !MultiSelect.Active)
{ {
return true; return true;
} }
InPatch = true; InPatch = true;
/* __result = Task.CompletedTask;
foreach (ItemContextClass itemContext in MultiSelect.ItemContexts.ToList())
{
__result = __result.ContinueWith(_ => __instance.AcceptItem(itemContext, targetItemContext));
}*/
var serializer = __instance.GetOrAddComponent<TaskSerializer>(); var serializer = __instance.GetOrAddComponent<TaskSerializer>();
__result = serializer.Initialize(MultiSelect.ItemContexts, itemContext => __instance.AcceptItem(itemContext, targetItemContext)); __result = serializer.Initialize(MultiSelect.ItemContexts, itemContext => __instance.AcceptItem(itemContext, targetItemContext));
__result.ContinueWith(_ => { InPatch = false; }); __result.ContinueWith(_ => { InPatch = false; });
return false; return false;
} }
} }
@@ -254,6 +358,7 @@ namespace UIFixes
public Task Initialize(IEnumerable<ItemContextClass> itemContexts, Func<ItemContextClass, Task> func) public Task Initialize(IEnumerable<ItemContextClass> itemContexts, Func<ItemContextClass, Task> func)
{ {
// Create new contexts because the underlying ones will be disposed when drag ends
this.itemContexts = new(itemContexts); this.itemContexts = new(itemContexts);
this.func = func; this.func = func;
@@ -283,31 +388,5 @@ namespace UIFixes
} }
} }
} }
/*public class GridViewAcceptItemPatch : ModulePatch
{
protected override MethodBase GetTargetMethod()
{
return AccessTools.Method(typeof(GridView), nameof(GridView.AcceptItem));
}
[PatchPrefix]
public static async bool Prefix(GridView __instance, ItemContextAbstractClass targetItemContext, ref Task __result)
{
if (InPatch || !MultiSelectContext.Instance.Any())
{
return true;
}
InPatch = true;
foreach (ItemContextClass itemContext in MultiSelectContext.Instance.SelectedDragContexts)
{
await __instance.AcceptItem(itemContext, targetItemContext);
}
InPatch = false;
return false;
}
}*/
} }
} }

View File

@@ -78,7 +78,7 @@ namespace UIFixes
return true; return true;
} }
if (!___bool_8 && ctrlPressed && tradingItemView.TraderAssortmentControler.QuickFindTradingAppropriatePlace(__instance.Item, null)) if (!___bool_8 && ctrlPressed && tradingItemView.TraderAssortmentController.QuickFindTradingAppropriatePlace(__instance.Item, null))
{ {
__instance.ItemContext.CloseDependentWindows(); __instance.ItemContext.CloseDependentWindows();
__instance.HideTooltip(); __instance.HideTooltip();
@@ -91,7 +91,7 @@ namespace UIFixes
if (___bool_8) if (___bool_8)
{ {
tradingItemView.TraderAssortmentControler.SelectItem(__instance.Item); tradingItemView.TraderAssortmentController.SelectItem(__instance.Item);
BuyTab.OnPointerClick(null); BuyTab.OnPointerClick(null);

4
R.cs
View File

@@ -295,7 +295,7 @@ namespace UIFixes
public static void InitTypes() public static void InitTypes()
{ {
Type = typeof(EFT.UI.DragAndDrop.GridView); Type = typeof(EFT.UI.DragAndDrop.GridView);
TraderControllerField = AccessTools.GetDeclaredFields(Type).Single(f => f.FieldType == typeof(TraderControllerClass)); TraderControllerField = AccessTools.GetDeclaredFields(Type).Single(f => f.FieldType == typeof(TraderControllerClass)); // field gclass2758_0
NonInteractableField = AccessTools.Field(Type, "_nonInteractable"); NonInteractableField = AccessTools.Field(Type, "_nonInteractable");
} }
@@ -562,7 +562,7 @@ namespace UIFixes
TraderAssortmentControllerField = AccessTools.GetDeclaredFields(Type).Single(t => t.FieldType == typeof(TraderAssortmentControllerClass)); TraderAssortmentControllerField = AccessTools.GetDeclaredFields(Type).Single(t => t.FieldType == typeof(TraderAssortmentControllerClass));
} }
public TraderAssortmentControllerClass TraderAssortmentControler { get { return (TraderAssortmentControllerClass)TraderAssortmentControllerField.GetValue(Value); } } public TraderAssortmentControllerClass TraderAssortmentController { get { return (TraderAssortmentControllerClass)TraderAssortmentControllerField.GetValue(Value); } }
} }
public class GridWindow(object value) : UIInputNode(value) public class GridWindow(object value) : UIInputNode(value)

View File

@@ -54,6 +54,7 @@ namespace UIFixes
public static ConfigEntry<int> MouseScrollMultiInRaid { get; set; } // Advanced public static ConfigEntry<int> MouseScrollMultiInRaid { get; set; } // Advanced
// Inventory // Inventory
public static ConfigEntry<bool> EnableMultiSelect { get; set; }
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; }
@@ -272,6 +273,15 @@ namespace UIFixes
new ConfigurationManagerAttributes { IsAdvanced = true }))); new ConfigurationManagerAttributes { IsAdvanced = true })));
// Inventory // Inventory
configEntries.Add(EnableMultiSelect = config.Bind(
InventorySection,
"Enable Multiselect",
true,
new ConfigDescription(
"Enable multiselect via Shift-click and drag-to-select",
null,
new ConfigurationManagerAttributes { })));
configEntries.Add(SwapItems = config.Bind( configEntries.Add(SwapItems = config.Bind(
InventorySection, InventorySection,
"Enable In-Place Item Swapping", "Enable In-Place Item Swapping",

View File

@@ -66,6 +66,9 @@
<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>
<Reference Include="UnityEngine.UIModule">
<HintPath>$(PathToSPT)\EscapeFromTarkov_Data\Managed\UnityEngine.UIModule.dll</HintPath>
</Reference>
<PackageReference Include="BepInEx.Analyzers" Version="1.*" PrivateAssets="all" /> <PackageReference Include="BepInEx.Analyzers" Version="1.*" PrivateAssets="all" />
<PackageReference Include="BepInEx.Core" Version="5.*" /> <PackageReference Include="BepInEx.Core" Version="5.*" />
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" /> <PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />