refactor to handle itemview kill/create, fix sorting table, cleanup
This commit is contained in:
@@ -42,6 +42,11 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnDisable()
|
||||||
|
{
|
||||||
|
MultiSelect.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
if (!Settings.EnableMultiSelect.Value)
|
if (!Settings.EnableMultiSelect.Value)
|
||||||
@@ -84,7 +89,14 @@ namespace UIFixes
|
|||||||
selectEnd = Input.mousePosition;
|
selectEnd = Input.mousePosition;
|
||||||
|
|
||||||
Rect selectRect = new(selectOrigin, selectEnd - selectOrigin);
|
Rect selectRect = new(selectOrigin, selectEnd - selectOrigin);
|
||||||
foreach (GridItemView gridItemView in GetComponentsInChildren<GridItemView>().Concat(Singleton<PreloaderUI>.Instance.GetComponentsInChildren<GridItemView>()))
|
|
||||||
|
// If not secondary, then we can kick out any non-rendered items, plus they won't be covered by the foreach below
|
||||||
|
if (!secondary)
|
||||||
|
{
|
||||||
|
MultiSelect.Prune();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (GridItemView gridItemView in transform.root.GetComponentsInChildren<GridItemView>().Concat(Singleton<PreloaderUI>.Instance.GetComponentsInChildren<GridItemView>()))
|
||||||
{
|
{
|
||||||
RectTransform itemTransform = gridItemView.GetComponent<RectTransform>();
|
RectTransform itemTransform = gridItemView.GetComponent<RectTransform>();
|
||||||
Rect itemRect = new((Vector2)itemTransform.position + itemTransform.rect.position * itemTransform.lossyScale, itemTransform.rect.size * itemTransform.lossyScale);
|
Rect itemRect = new((Vector2)itemTransform.position + itemTransform.rect.position * itemTransform.lossyScale, itemTransform.rect.size * itemTransform.lossyScale);
|
||||||
@@ -94,48 +106,23 @@ namespace UIFixes
|
|||||||
// Otherwise, ensure it's not overlapped by window UI
|
// Otherwise, ensure it's not overlapped by window UI
|
||||||
PointerEventData eventData = new(EventSystem.current);
|
PointerEventData eventData = new(EventSystem.current);
|
||||||
|
|
||||||
// Non-absolute width/height
|
float widthMargin = 0.1f * (itemRect.xMax - itemRect.xMin);
|
||||||
float width = itemRect.xMax - itemRect.xMin;
|
float heightMargin = 0.1f * (itemRect.yMax - itemRect.yMin);
|
||||||
float height = itemRect.yMax - itemRect.yMin;
|
|
||||||
|
|
||||||
List<RaycastResult> raycastResults = [];
|
if (IsOnTop(itemRect, itemTransform, preloaderRaycaster)) // no preloaderUI on top of this?
|
||||||
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, secondary);
|
if (itemTransform.IsDescendantOf(Singleton<PreloaderUI>.Instance.transform))
|
||||||
continue;
|
{
|
||||||
}
|
MultiSelect.Select(gridItemView, secondary);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
raycastResults.Clear();
|
if (IsOnTop(itemRect, itemTransform, localRaycaster)) // no local UI on top of this?
|
||||||
eventData.position = new Vector2(itemRect.xMin + 0.1f * width, itemRect.yMax - 0.1f * height);
|
{
|
||||||
preloaderRaycaster.Raycast(eventData, raycastResults);
|
MultiSelect.Select(gridItemView, secondary);
|
||||||
if (raycastResults.Any() && !raycastResults[0].gameObject.transform.IsDescendantOf(itemTransform))
|
continue;
|
||||||
{
|
}
|
||||||
MultiSelect.Deselect(gridItemView, secondary);
|
|
||||||
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, secondary);
|
|
||||||
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, secondary);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiSelect.Select(gridItemView, secondary);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiSelect.Deselect(gridItemView, secondary);
|
MultiSelect.Deselect(gridItemView, secondary);
|
||||||
@@ -175,6 +162,54 @@ namespace UIFixes
|
|||||||
GUI.DrawTexture(lineArea, selectTexture);
|
GUI.DrawTexture(lineArea, selectTexture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsOnTop(Rect itemRect, Transform itemTransform, GraphicRaycaster raycaster)
|
||||||
|
{
|
||||||
|
// Otherwise, ensure it's not overlapped by window UI
|
||||||
|
PointerEventData eventData = new(EventSystem.current);
|
||||||
|
|
||||||
|
float widthMargin = 0.1f * (itemRect.xMax - itemRect.xMin);
|
||||||
|
float heightMargin = 0.1f * (itemRect.yMax - itemRect.yMin);
|
||||||
|
|
||||||
|
List<RaycastResult> raycastResults = [];
|
||||||
|
|
||||||
|
// Lower left
|
||||||
|
eventData.position = new Vector2(itemRect.xMin + widthMargin, itemRect.yMin + heightMargin);
|
||||||
|
raycaster.Raycast(eventData, raycastResults);
|
||||||
|
if (raycastResults.Any() && !raycastResults[0].gameObject.transform.IsDescendantOf(itemTransform))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upper left
|
||||||
|
raycastResults.Clear();
|
||||||
|
eventData.position = new Vector2(itemRect.xMin + widthMargin, itemRect.yMax - heightMargin);
|
||||||
|
raycaster.Raycast(eventData, raycastResults);
|
||||||
|
if (raycastResults.Any() && !raycastResults[0].gameObject.transform.IsDescendantOf(itemTransform))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upper right
|
||||||
|
raycastResults.Clear();
|
||||||
|
eventData.position = new Vector2(itemRect.xMax - widthMargin, itemRect.yMax - heightMargin);
|
||||||
|
raycaster.Raycast(eventData, raycastResults);
|
||||||
|
if (raycastResults.Any() && !raycastResults[0].gameObject.transform.IsDescendantOf(itemTransform))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lower right
|
||||||
|
raycastResults.Clear();
|
||||||
|
eventData.position = new Vector2(itemRect.xMax - widthMargin, itemRect.yMin + heightMargin);
|
||||||
|
raycaster.Raycast(eventData, raycastResults);
|
||||||
|
if (raycastResults.Any() && !raycastResults[0].gameObject.transform.IsDescendantOf(itemTransform))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransformExtensions
|
public static class TransformExtensions
|
||||||
|
|||||||
130
MultiSelect.cs
130
MultiSelect.cs
@@ -1,5 +1,7 @@
|
|||||||
using EFT.UI.DragAndDrop;
|
using EFT.UI;
|
||||||
|
using EFT.UI.DragAndDrop;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
@@ -12,11 +14,8 @@ namespace UIFixes
|
|||||||
private static GameObject SelectedMarkTemplate;
|
private static GameObject SelectedMarkTemplate;
|
||||||
private static GameObject SelectedBackgroundTemplate;
|
private static GameObject SelectedBackgroundTemplate;
|
||||||
|
|
||||||
private static readonly Dictionary<GridItemView, ItemContextClass> SelectedItemViews = [];
|
private static readonly Dictionary<ItemContextClass, GridItemView> SelectedItems = [];
|
||||||
private static readonly List<ItemContextClass> SortedItemContexts = [];
|
private static readonly Dictionary<ItemContextClass, GridItemView> SecondaryItems = [];
|
||||||
|
|
||||||
private static readonly Dictionary<GridItemView, ItemContextClass> SecondaryItemViews = [];
|
|
||||||
private static readonly List<ItemContextClass> SecondaryItemContexts = [];
|
|
||||||
|
|
||||||
public static void Initialize()
|
public static void Initialize()
|
||||||
{
|
{
|
||||||
@@ -34,10 +33,11 @@ namespace UIFixes
|
|||||||
|
|
||||||
public static void Toggle(GridItemView itemView, bool secondary = false)
|
public static void Toggle(GridItemView itemView, bool secondary = false)
|
||||||
{
|
{
|
||||||
var dictionary = secondary ? SecondaryItemViews : SelectedItemViews;
|
var dictionary = secondary ? SecondaryItems : SelectedItems;
|
||||||
if (dictionary.ContainsKey(itemView))
|
ItemContextClass itemContext = dictionary.FirstOrDefault(x => x.Value == itemView).Key;
|
||||||
|
if (itemContext != null)
|
||||||
{
|
{
|
||||||
Deselect(itemView, secondary);
|
Deselect(itemContext, secondary);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -48,92 +48,131 @@ namespace UIFixes
|
|||||||
public static void Clear()
|
public static void Clear()
|
||||||
{
|
{
|
||||||
// ToList() because modifying the collection
|
// ToList() because modifying the collection
|
||||||
foreach (GridItemView itemView in SelectedItemViews.Keys.ToList())
|
foreach (ItemContextClass itemContext in SelectedItems.Keys.ToList())
|
||||||
{
|
{
|
||||||
Deselect(itemView);
|
Deselect(itemContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Select(GridItemView itemView, bool secondary = false)
|
public static void Select(GridItemView itemView, bool secondary = false)
|
||||||
{
|
{
|
||||||
var dictionary = secondary ? SecondaryItemViews : SelectedItemViews;
|
var dictionary = secondary ? SecondaryItems : SelectedItems;
|
||||||
var list = secondary ? SecondaryItemContexts : SortedItemContexts;
|
|
||||||
|
|
||||||
if (itemView.IsSelectable() && !SelectedItemViews.ContainsKey(itemView) && !SecondaryItemViews.ContainsKey(itemView))
|
if (itemView.IsSelectable() && !SelectedItems.Any(x => x.Key.Item == itemView.Item) && !SecondaryItems.Any(x => x.Key.Item == itemView.Item))
|
||||||
{
|
{
|
||||||
ItemContextClass itemContext = new MultiSelectItemContext(itemView.ItemContext, itemView.ItemRotation);
|
ItemContextClass itemContext = new MultiSelectItemContext(itemView.ItemContext, itemView.ItemRotation);
|
||||||
itemContext.GClass2813_0.OnDisposed += RugPull;
|
|
||||||
itemContext.OnDisposed += RugPull;
|
|
||||||
|
|
||||||
// Remove event handlers that no one cares about and cause stack overflows
|
// Remove event handlers that no one cares about and cause stack overflows
|
||||||
itemContext.method_1();
|
itemContext.method_1();
|
||||||
|
|
||||||
dictionary.Add(itemView, itemContext);
|
// Subscribe to window closures to deselect
|
||||||
list.Add(itemContext);
|
GClass3085 windowContext = itemView.GetComponentInParent<GridWindow>()?.WindowContext ?? itemView.GetComponentInParent<InfoWindow>()?.WindowContext;
|
||||||
|
if (windowContext != null)
|
||||||
|
{
|
||||||
|
windowContext.OnClose += () => Deselect(itemContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
dictionary.Add(itemContext, itemView);
|
||||||
ShowSelection(itemView);
|
ShowSelection(itemView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Deselect(ItemContextClass itemContext, bool secondary = false)
|
||||||
|
{
|
||||||
|
var dictionary = secondary ? SecondaryItems : SelectedItems;
|
||||||
|
|
||||||
|
if (dictionary.TryGetValue(itemContext, out GridItemView itemView))
|
||||||
|
{
|
||||||
|
HideSelection(itemView);
|
||||||
|
}
|
||||||
|
|
||||||
|
dictionary.Remove(itemContext);
|
||||||
|
itemContext.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
public static void Deselect(GridItemView itemView, bool secondary = false)
|
public static void Deselect(GridItemView itemView, bool secondary = false)
|
||||||
{
|
{
|
||||||
var dictionary = secondary ? SecondaryItemViews : SelectedItemViews;
|
var dictionary = secondary ? SecondaryItems : SelectedItems;
|
||||||
var list = secondary ? SecondaryItemContexts : SortedItemContexts;
|
|
||||||
|
|
||||||
if (dictionary.TryGetValue(itemView, out ItemContextClass itemContext))
|
ItemContextClass itemContext = dictionary.FirstOrDefault(x => x.Value == itemView).Key;
|
||||||
|
if (itemContext != null)
|
||||||
{
|
{
|
||||||
itemContext.GClass2813_0.OnDisposed -= RugPull;
|
dictionary.Remove(itemContext);
|
||||||
itemContext.OnDisposed -= RugPull;
|
|
||||||
itemContext.Dispose();
|
itemContext.Dispose();
|
||||||
list.Remove(itemContext);
|
|
||||||
dictionary.Remove(itemView);
|
|
||||||
HideSelection(itemView);
|
HideSelection(itemView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void OnKillItemView(GridItemView itemView)
|
||||||
|
{
|
||||||
|
ItemContextClass itemContext = SelectedItems.FirstOrDefault(x => x.Value == itemView).Key;
|
||||||
|
if (itemContext != null)
|
||||||
|
{
|
||||||
|
SelectedItems[itemContext] = null;
|
||||||
|
HideSelection(itemView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnNewItemView(GridItemView itemView)
|
||||||
|
{
|
||||||
|
ItemContextClass itemContext = SelectedItems.FirstOrDefault(x => x.Key.Item == itemView.Item).Key;
|
||||||
|
if (itemContext != null)
|
||||||
|
{
|
||||||
|
// We need to refresh the context because if the item moved, it has a new address
|
||||||
|
Deselect(itemContext);
|
||||||
|
Select(itemView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsSelected(GridItemView itemView)
|
public static bool IsSelected(GridItemView itemView)
|
||||||
{
|
{
|
||||||
return SelectedItemViews.ContainsKey(itemView);
|
return SelectedItems.Any(x => x.Key.Item == itemView.Item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Prune()
|
||||||
|
{
|
||||||
|
foreach (var entry in SelectedItems.ToList())
|
||||||
|
{
|
||||||
|
if (entry.Value == null)
|
||||||
|
{
|
||||||
|
Deselect(entry.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CombineSecondary()
|
public static void CombineSecondary()
|
||||||
{
|
{
|
||||||
foreach (var entry in SecondaryItemViews)
|
foreach (var entry in SecondaryItems)
|
||||||
{
|
{
|
||||||
SelectedItemViews.Add(entry.Key, entry.Value);
|
SelectedItems.Add(entry.Key, entry.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ItemContextClass itemContext in SecondaryItemContexts)
|
SecondaryItems.Clear();
|
||||||
{
|
|
||||||
SortedItemContexts.Add(itemContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
SecondaryItemViews.Clear();
|
|
||||||
SecondaryItemContexts.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<ItemContextClass> ItemContexts
|
public static IEnumerable<ItemContextClass> ItemContexts
|
||||||
{
|
{
|
||||||
get { return SortedItemContexts; }
|
get { return SelectedItems.Keys; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<ItemContextClass> SecondaryContexts
|
public static IEnumerable<ItemContextClass> SecondaryContexts
|
||||||
{
|
{
|
||||||
get { return SecondaryItemContexts; }
|
get { return SecondaryItems.Keys; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int Count
|
public static int Count
|
||||||
{
|
{
|
||||||
get { return SelectedItemViews.Count; }
|
get { return SelectedItems.Count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int SecondaryCount
|
public static int SecondaryCount
|
||||||
{
|
{
|
||||||
get { return SecondaryItemViews.Count; }
|
get { return SecondaryItems.Count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Active
|
public static bool Active
|
||||||
{
|
{
|
||||||
get { return SelectedItemViews.Count > 0; }
|
get { return SelectedItems.Count > 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ShowDragCount(DraggedItemView draggedItemView)
|
public static void ShowDragCount(DraggedItemView draggedItemView)
|
||||||
@@ -157,11 +196,6 @@ 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;
|
||||||
@@ -186,6 +220,11 @@ namespace UIFixes
|
|||||||
|
|
||||||
private static void HideSelection(GridItemView itemView)
|
private static void HideSelection(GridItemView itemView)
|
||||||
{
|
{
|
||||||
|
if (itemView == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GameObject selectedMark = itemView.transform.Find("SelectedMark")?.gameObject;
|
GameObject selectedMark = itemView.transform.Find("SelectedMark")?.gameObject;
|
||||||
GameObject selectedBackground = itemView.transform.Find("SelectedBackground")?.gameObject;
|
GameObject selectedBackground = itemView.transform.Find("SelectedBackground")?.gameObject;
|
||||||
|
|
||||||
@@ -222,3 +261,4 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,18 +31,21 @@ namespace UIFixes
|
|||||||
// Prevents QuickFind from attempting a merge
|
// Prevents QuickFind from attempting a merge
|
||||||
private static bool DisableMerge = false;
|
private static bool DisableMerge = false;
|
||||||
|
|
||||||
|
// Specific type of TaskSerializer because Unity can't understand generics
|
||||||
|
public class ItemContextTaskSerializer : TaskSerializer<ItemContextClass> { }
|
||||||
|
|
||||||
public static void Enable()
|
public static void Enable()
|
||||||
{
|
{
|
||||||
new InitializeCommonUIPatch().Enable();
|
new InitializeCommonUIPatch().Enable();
|
||||||
new InitializeMenuUIPatch().Enable();
|
new InitializeMenuUIPatch().Enable();
|
||||||
new SelectOnMouseDownPatch().Enable();
|
new SelectOnMouseDownPatch().Enable();
|
||||||
new SelectMovedItemViewPatch().Enable();
|
|
||||||
new DeselectOnGridItemViewClickPatch().Enable();
|
new DeselectOnGridItemViewClickPatch().Enable();
|
||||||
new DeselectOnTradingItemViewClickPatch().Enable();
|
new DeselectOnTradingItemViewClickPatch().Enable();
|
||||||
new DeselectOnItemViewKillPatch().Enable();
|
new HandleItemViewInitPatch().Enable();
|
||||||
|
new HandleItemViewKillPatch().Enable();
|
||||||
new BeginDragPatch().Enable();
|
new BeginDragPatch().Enable();
|
||||||
new EndDragPatch().Enable();
|
new EndDragPatch().Enable();
|
||||||
new InspectWindowHack().Enable();
|
//new InspectWindowHack().Enable();
|
||||||
new DisableSplitPatch().Enable();
|
new DisableSplitPatch().Enable();
|
||||||
new DisableSplitTargetPatch().Enable();
|
new DisableSplitTargetPatch().Enable();
|
||||||
|
|
||||||
@@ -188,7 +191,27 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DeselectOnItemViewKillPatch : ModulePatch
|
public class HandleItemViewInitPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(GridItemView), nameof(GridItemView.Init));
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
public static void Postfix(GridItemView __instance)
|
||||||
|
{
|
||||||
|
if (!MultiSelect.Active)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the itemview isn't done being initialized
|
||||||
|
__instance.WaitForEndOfFrame(() => MultiSelect.OnNewItemView(__instance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HandleItemViewKillPatch : ModulePatch
|
||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
@@ -205,7 +228,7 @@ namespace UIFixes
|
|||||||
|
|
||||||
if (__instance is GridItemView gridItemView)
|
if (__instance is GridItemView gridItemView)
|
||||||
{
|
{
|
||||||
MultiSelect.Deselect(gridItemView);
|
MultiSelect.OnKillItemView(gridItemView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +274,7 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
public static bool Prefix(GridView __instance, ItemContextClass itemContext, ItemContextAbstractClass targetItemContext, ref GStruct413 operation, ref bool __result)
|
public static bool Prefix(GridView __instance, ItemContextClass itemContext, ItemContextAbstractClass targetItemContext, ref GStruct413 operation, ref bool __result, ItemUiContext ___itemUiContext_0)
|
||||||
{
|
{
|
||||||
if (InPatch || !MultiSelect.Active)
|
if (InPatch || !MultiSelect.Active)
|
||||||
{
|
{
|
||||||
@@ -306,9 +329,16 @@ namespace UIFixes
|
|||||||
FindOrigin = GetTargetGridAddress(itemContext, selectedItemContext, hoveredAddress);
|
FindOrigin = GetTargetGridAddress(itemContext, selectedItemContext, hoveredAddress);
|
||||||
FindVerticalFirst = selectedItemContext.ItemRotation == ItemRotation.Vertical;
|
FindVerticalFirst = selectedItemContext.ItemRotation == ItemRotation.Vertical;
|
||||||
|
|
||||||
operation = targetItem != null ?
|
if (targetItem is SortingTableClass)
|
||||||
wrappedInstance.TraderController.ExecutePossibleAction(selectedItemContext, targetItem, false /* splitting */, false /* simulate */) :
|
{
|
||||||
wrappedInstance.TraderController.ExecutePossibleAction(selectedItemContext, __instance.SourceContext, hoveredAddress, false /* splitting */, false /* simulate */);
|
operation = ___itemUiContext_0.QuickMoveToSortingTable(selectedItemContext.Item, false /* simulate */);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
operation = targetItem != null ?
|
||||||
|
wrappedInstance.TraderController.ExecutePossibleAction(selectedItemContext, targetItem, false /* splitting */, false /* simulate */) :
|
||||||
|
wrappedInstance.TraderController.ExecutePossibleAction(selectedItemContext, __instance.SourceContext, hoveredAddress, false /* splitting */, false /* simulate */);
|
||||||
|
}
|
||||||
|
|
||||||
FindOrigin = null;
|
FindOrigin = null;
|
||||||
FindVerticalFirst = false;
|
FindVerticalFirst = false;
|
||||||
@@ -377,8 +407,31 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
public static bool Prefix(GridView __instance, ItemContextClass itemContext, ItemContextAbstractClass targetItemContext, ref Task __result)
|
public static bool Prefix(GridView __instance, ItemContextClass itemContext, ItemContextAbstractClass targetItemContext, ref Task __result, ItemUiContext ___itemUiContext_0)
|
||||||
{
|
{
|
||||||
|
// Need to fully implement AcceptItem for the sorting table normally that just uses null targetItemContext
|
||||||
|
if (InPatch && targetItemContext?.Item is SortingTableClass)
|
||||||
|
{
|
||||||
|
__result = Task.CompletedTask;
|
||||||
|
var itemController = __instance.R().TraderController;
|
||||||
|
|
||||||
|
GStruct413 operation = ___itemUiContext_0.QuickMoveToSortingTable(itemContext.Item, true);
|
||||||
|
if (operation.Failed || !itemController.CanExecute(operation.Value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemController.RunNetworkTransaction(operation.Value, null);
|
||||||
|
|
||||||
|
if (___itemUiContext_0.Tooltip != null)
|
||||||
|
{
|
||||||
|
___itemUiContext_0.Tooltip.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Singleton<GUISounds>.Instance.PlayItemSound(itemContext.Item.ItemSound, EInventorySoundType.pickup, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (InPatch || !MultiSelect.Active)
|
if (InPatch || !MultiSelect.Active)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -390,7 +443,12 @@ namespace UIFixes
|
|||||||
LocationInGrid hoveredLocation = __instance.CalculateItemLocation(itemContext);
|
LocationInGrid hoveredLocation = __instance.CalculateItemLocation(itemContext);
|
||||||
GClass2769 hoveredAddress = new(__instance.Grid, hoveredLocation);
|
GClass2769 hoveredAddress = new(__instance.Grid, hoveredLocation);
|
||||||
|
|
||||||
var serializer = __instance.GetOrAddComponent<TaskSerializer>();
|
if (__instance.Grid.ParentItem is SortingTableClass)
|
||||||
|
{
|
||||||
|
targetItemContext = new GClass2817(__instance.Grid.ParentItem, EItemViewType.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
var serializer = __instance.GetOrAddComponent<ItemContextTaskSerializer>();
|
||||||
__result = serializer.Initialize(SortSelectedContexts(MultiSelect.ItemContexts, itemContext), ic =>
|
__result = serializer.Initialize(SortSelectedContexts(MultiSelect.ItemContexts, itemContext), ic =>
|
||||||
{
|
{
|
||||||
FindOrigin = GetTargetGridAddress(itemContext, ic, hoveredAddress);
|
FindOrigin = GetTargetGridAddress(itemContext, ic, hoveredAddress);
|
||||||
@@ -417,7 +475,7 @@ namespace UIFixes
|
|||||||
public class AdjustQuickFindFlagsPatch : ModulePatch
|
public class AdjustQuickFindFlagsPatch : ModulePatch
|
||||||
{
|
{
|
||||||
// For reasons (???), BSG doesn't even define the second bit of this flags enum
|
// For reasons (???), BSG doesn't even define the second bit of this flags enum
|
||||||
private static InteractionsHandlerClass.EMoveItemOrder PartialMerge = (InteractionsHandlerClass.EMoveItemOrder)2;
|
private static readonly InteractionsHandlerClass.EMoveItemOrder PartialMerge = (InteractionsHandlerClass.EMoveItemOrder)2;
|
||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
@@ -443,26 +501,6 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SelectMovedItemViewPatch : ModulePatch
|
|
||||||
{
|
|
||||||
protected override MethodBase GetTargetMethod()
|
|
||||||
{
|
|
||||||
return AccessTools.Method(typeof(GridItemView), nameof(GridItemView.Init));
|
|
||||||
}
|
|
||||||
|
|
||||||
[PatchPostfix]
|
|
||||||
public static void Postfix(GridItemView __instance)
|
|
||||||
{
|
|
||||||
if (!InPatch)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the itemview isn't done being initialized
|
|
||||||
__instance.WaitForEndOfFrame(() => MultiSelect.Select(__instance));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GridViewPickTargetPatch : ModulePatch
|
public class GridViewPickTargetPatch : ModulePatch
|
||||||
{
|
{
|
||||||
public static Item FallbackResult = null;
|
public static Item FallbackResult = null;
|
||||||
@@ -479,88 +517,6 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ShowPreview(GridView gridView, ItemContextClass itemContext, GStruct413 operation)
|
|
||||||
{
|
|
||||||
if (operation.Value is not GClass2786 moveOperation || moveOperation.To is not GClass2769 gridAddress)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gridAddress.Grid != gridView.Grid)
|
|
||||||
{
|
|
||||||
GridView otherGridView = gridView.transform.parent.GetComponentsInChildren<GridView>().FirstOrDefault(gv => gv.Grid == gridAddress.Grid);
|
|
||||||
if (otherGridView != null)
|
|
||||||
{
|
|
||||||
ShowPreview(otherGridView, itemContext, operation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Image preview = UnityEngine.Object.Instantiate(gridView.R().HighlightPanel, gridView.transform, false);
|
|
||||||
preview.gameObject.SetActive(true);
|
|
||||||
Previews.Add(preview);
|
|
||||||
|
|
||||||
var itemIcon = ItemViewFactory.LoadItemIcon(itemContext.Item);
|
|
||||||
preview.sprite = itemIcon.Sprite;
|
|
||||||
preview.SetNativeSize();
|
|
||||||
preview.color = gridView.R().TraderController.Examined(itemContext.Item) ? Color.white : new Color(0f, 0f, 0f, 0.85f);
|
|
||||||
|
|
||||||
Quaternion quaternion = (gridAddress.LocationInGrid.r == ItemRotation.Horizontal) ? ItemViewFactory.HorizontalRotation : ItemViewFactory.VerticalRotation;
|
|
||||||
preview.transform.rotation = quaternion;
|
|
||||||
|
|
||||||
GStruct24 itemSize = moveOperation.Item.CalculateRotatedSize(gridAddress.LocationInGrid.r);
|
|
||||||
LocationInGrid locationInGrid = gridAddress.LocationInGrid;
|
|
||||||
|
|
||||||
RectTransform rectTransform = preview.rectTransform;
|
|
||||||
rectTransform.localScale = Vector3.one;
|
|
||||||
rectTransform.pivot = new Vector2(0.5f, 0.5f);
|
|
||||||
rectTransform.anchorMin = new Vector2(0f, 1f);
|
|
||||||
rectTransform.anchorMax = new Vector2(0f, 1f);
|
|
||||||
rectTransform.anchoredPosition = new Vector2(locationInGrid.x * 63f, -locationInGrid.y * 63f) + new Vector2(itemSize.X * 63f / 2, -itemSize.Y * 63f / 2);
|
|
||||||
|
|
||||||
Image background = UnityEngine.Object.Instantiate(preview, gridView.transform, false);
|
|
||||||
background.sprite = null;
|
|
||||||
Color normalColor = gridView.GetHighlightColor(itemContext, operation, null);
|
|
||||||
background.color = new(normalColor.r, normalColor.g, normalColor.b, 0.3f);
|
|
||||||
background.gameObject.SetActive(true);
|
|
||||||
Previews.Add(background);
|
|
||||||
|
|
||||||
preview.transform.SetAsLastSibling();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void HidePreviews()
|
|
||||||
{
|
|
||||||
foreach (Image preview in Previews)
|
|
||||||
{
|
|
||||||
UnityEngine.Object.Destroy(preview.gameObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
Previews.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static GClass2769 GetTargetGridAddress(
|
|
||||||
ItemContextClass itemContext, ItemContextClass selectedItemContext, GClass2769 hoveredGridAddress)
|
|
||||||
{
|
|
||||||
if (itemContext != selectedItemContext &&
|
|
||||||
itemContext.ItemAddress is GClass2769 itemGridAddress &&
|
|
||||||
selectedItemContext.ItemAddress is GClass2769 selectedGridAddress &&
|
|
||||||
itemGridAddress.Grid == selectedGridAddress.Grid)
|
|
||||||
{
|
|
||||||
// Shared a grid with the dragged item - try to keep position
|
|
||||||
int xDelta = selectedGridAddress.LocationInGrid.x - itemGridAddress.LocationInGrid.x;
|
|
||||||
int yDelta = selectedGridAddress.LocationInGrid.y - itemGridAddress.LocationInGrid.y;
|
|
||||||
|
|
||||||
LocationInGrid newLocation = new(hoveredGridAddress.LocationInGrid.x + xDelta, hoveredGridAddress.LocationInGrid.y + yDelta, selectedGridAddress.LocationInGrid.r);
|
|
||||||
newLocation.x = Math.Max(0, Math.Min(hoveredGridAddress.Grid.GridWidth.Value, newLocation.x));
|
|
||||||
newLocation.y = Math.Max(0, Math.Min(hoveredGridAddress.Grid.GridHeight.Value, newLocation.y));
|
|
||||||
|
|
||||||
return new GClass2769(hoveredGridAddress.Grid, newLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hoveredGridAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort the items to prioritize the items that share a grid with the dragged item, prepend the dragContext as the first one
|
// Sort the items to prioritize the items that share a grid with the dragged item, prepend the dragContext as the first one
|
||||||
private static IEnumerable<ItemContextClass> SortSelectedContexts(
|
private static IEnumerable<ItemContextClass> SortSelectedContexts(
|
||||||
IEnumerable<ItemContextClass> selectedContexts, ItemContextClass itemContext, bool prepend = true)
|
IEnumerable<ItemContextClass> selectedContexts, ItemContextClass itemContext, bool prepend = true)
|
||||||
@@ -675,7 +631,7 @@ namespace UIFixes
|
|||||||
|
|
||||||
InPatch = true;
|
InPatch = true;
|
||||||
|
|
||||||
var serializer = __instance.GetOrAddComponent<TaskSerializer>();
|
var serializer = __instance.GetOrAddComponent<TaskSerializer<ItemContextClass>>();
|
||||||
__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; });
|
||||||
@@ -1030,44 +986,86 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TaskSerializer : MonoBehaviour
|
private static void ShowPreview(GridView gridView, ItemContextClass itemContext, GStruct413 operation)
|
||||||
{
|
{
|
||||||
private Func<ItemContextClass, Task> func;
|
if (operation.Value is not GClass2786 moveOperation || moveOperation.To is not GClass2769 gridAddress)
|
||||||
private Queue<ItemContextClass> itemContexts;
|
|
||||||
private Task currentTask;
|
|
||||||
private TaskCompletionSource totalTask;
|
|
||||||
|
|
||||||
public Task Initialize(IEnumerable<ItemContextClass> itemContexts, Func<ItemContextClass, Task> func)
|
|
||||||
{
|
{
|
||||||
// Create new contexts because the underlying ones will be disposed when drag ends
|
return;
|
||||||
this.itemContexts = new(itemContexts);
|
|
||||||
this.func = func;
|
|
||||||
|
|
||||||
currentTask = Task.CompletedTask;
|
|
||||||
Update();
|
|
||||||
|
|
||||||
totalTask = new TaskCompletionSource();
|
|
||||||
return totalTask.Task;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update()
|
if (gridAddress.Grid != gridView.Grid)
|
||||||
{
|
{
|
||||||
if (!currentTask.IsCompleted)
|
GridView otherGridView = gridView.transform.parent.GetComponentsInChildren<GridView>().FirstOrDefault(gv => gv.Grid == gridAddress.Grid);
|
||||||
|
if (otherGridView != null)
|
||||||
{
|
{
|
||||||
return;
|
ShowPreview(otherGridView, itemContext, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemContexts.Any())
|
return;
|
||||||
{
|
|
||||||
currentTask = func(itemContexts.Dequeue());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
totalTask.Complete();
|
|
||||||
func = null;
|
|
||||||
Destroy(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Image preview = UnityEngine.Object.Instantiate(gridView.R().HighlightPanel, gridView.transform, false);
|
||||||
|
preview.gameObject.SetActive(true);
|
||||||
|
Previews.Add(preview);
|
||||||
|
|
||||||
|
var itemIcon = ItemViewFactory.LoadItemIcon(itemContext.Item);
|
||||||
|
preview.sprite = itemIcon.Sprite;
|
||||||
|
preview.SetNativeSize();
|
||||||
|
preview.color = gridView.R().TraderController.Examined(itemContext.Item) ? Color.white : new Color(0f, 0f, 0f, 0.85f);
|
||||||
|
|
||||||
|
Quaternion quaternion = (gridAddress.LocationInGrid.r == ItemRotation.Horizontal) ? ItemViewFactory.HorizontalRotation : ItemViewFactory.VerticalRotation;
|
||||||
|
preview.transform.rotation = quaternion;
|
||||||
|
|
||||||
|
GStruct24 itemSize = moveOperation.Item.CalculateRotatedSize(gridAddress.LocationInGrid.r);
|
||||||
|
LocationInGrid locationInGrid = gridAddress.LocationInGrid;
|
||||||
|
|
||||||
|
RectTransform rectTransform = preview.rectTransform;
|
||||||
|
rectTransform.localScale = Vector3.one;
|
||||||
|
rectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||||
|
rectTransform.anchorMin = new Vector2(0f, 1f);
|
||||||
|
rectTransform.anchorMax = new Vector2(0f, 1f);
|
||||||
|
rectTransform.anchoredPosition = new Vector2(locationInGrid.x * 63f, -locationInGrid.y * 63f) + new Vector2(itemSize.X * 63f / 2, -itemSize.Y * 63f / 2);
|
||||||
|
|
||||||
|
Image background = UnityEngine.Object.Instantiate(preview, gridView.transform, false);
|
||||||
|
background.sprite = null;
|
||||||
|
Color normalColor = gridView.GetHighlightColor(itemContext, operation, null);
|
||||||
|
background.color = new(normalColor.r, normalColor.g, normalColor.b, 0.3f);
|
||||||
|
background.gameObject.SetActive(true);
|
||||||
|
Previews.Add(background);
|
||||||
|
|
||||||
|
preview.transform.SetAsLastSibling();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HidePreviews()
|
||||||
|
{
|
||||||
|
foreach (Image preview in Previews)
|
||||||
|
{
|
||||||
|
UnityEngine.Object.Destroy(preview.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
Previews.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GClass2769 GetTargetGridAddress(
|
||||||
|
ItemContextClass itemContext, ItemContextClass selectedItemContext, GClass2769 hoveredGridAddress)
|
||||||
|
{
|
||||||
|
if (itemContext != selectedItemContext &&
|
||||||
|
itemContext.ItemAddress is GClass2769 itemGridAddress &&
|
||||||
|
selectedItemContext.ItemAddress is GClass2769 selectedGridAddress &&
|
||||||
|
itemGridAddress.Grid == selectedGridAddress.Grid)
|
||||||
|
{
|
||||||
|
// Shared a grid with the dragged item - try to keep position
|
||||||
|
int xDelta = selectedGridAddress.LocationInGrid.x - itemGridAddress.LocationInGrid.x;
|
||||||
|
int yDelta = selectedGridAddress.LocationInGrid.y - itemGridAddress.LocationInGrid.y;
|
||||||
|
|
||||||
|
LocationInGrid newLocation = new(hoveredGridAddress.LocationInGrid.x + xDelta, hoveredGridAddress.LocationInGrid.y + yDelta, selectedGridAddress.LocationInGrid.r);
|
||||||
|
newLocation.x = Math.Max(0, Math.Min(hoveredGridAddress.Grid.GridWidth.Value, newLocation.x));
|
||||||
|
newLocation.y = Math.Max(0, Math.Min(hoveredGridAddress.Grid.GridHeight.Value, newLocation.y));
|
||||||
|
|
||||||
|
return new GClass2769(hoveredGridAddress.Grid, newLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hoveredGridAddress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
48
TaskSerializer.cs
Normal file
48
TaskSerializer.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace UIFixes
|
||||||
|
{
|
||||||
|
public class TaskSerializer<T> : MonoBehaviour
|
||||||
|
{
|
||||||
|
private Func<T, Task> func;
|
||||||
|
private Queue<T> items;
|
||||||
|
private Task currentTask;
|
||||||
|
private TaskCompletionSource totalTask;
|
||||||
|
|
||||||
|
public Task Initialize(IEnumerable<T> items, Func<T, Task> func)
|
||||||
|
{
|
||||||
|
this.items = new(items);
|
||||||
|
this.func = func;
|
||||||
|
|
||||||
|
currentTask = Task.CompletedTask;
|
||||||
|
totalTask = new TaskCompletionSource();
|
||||||
|
|
||||||
|
Update();
|
||||||
|
|
||||||
|
return totalTask.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
if (!currentTask.IsCompleted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items.Any())
|
||||||
|
{
|
||||||
|
currentTask = func(items.Dequeue());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
totalTask.Complete();
|
||||||
|
func = null;
|
||||||
|
Destroy(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user