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()
|
||||
{
|
||||
if (!Settings.EnableMultiSelect.Value)
|
||||
@@ -84,7 +89,14 @@ namespace UIFixes
|
||||
selectEnd = Input.mousePosition;
|
||||
|
||||
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>();
|
||||
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
|
||||
PointerEventData eventData = new(EventSystem.current);
|
||||
|
||||
// Non-absolute width/height
|
||||
float width = itemRect.xMax - itemRect.xMin;
|
||||
float height = itemRect.yMax - itemRect.yMin;
|
||||
float widthMargin = 0.1f * (itemRect.xMax - itemRect.xMin);
|
||||
float heightMargin = 0.1f * (itemRect.yMax - itemRect.yMin);
|
||||
|
||||
List<RaycastResult> raycastResults = [];
|
||||
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))
|
||||
if (IsOnTop(itemRect, itemTransform, preloaderRaycaster)) // no preloaderUI on top of this?
|
||||
{
|
||||
MultiSelect.Deselect(gridItemView, secondary);
|
||||
continue;
|
||||
}
|
||||
if (itemTransform.IsDescendantOf(Singleton<PreloaderUI>.Instance.transform))
|
||||
{
|
||||
MultiSelect.Select(gridItemView, secondary);
|
||||
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, secondary);
|
||||
continue;
|
||||
if (IsOnTop(itemRect, itemTransform, localRaycaster)) // no local UI on top of this?
|
||||
{
|
||||
MultiSelect.Select(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);
|
||||
@@ -175,6 +162,54 @@ namespace UIFixes
|
||||
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
|
||||
|
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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
@@ -12,11 +14,8 @@ namespace UIFixes
|
||||
private static GameObject SelectedMarkTemplate;
|
||||
private static GameObject SelectedBackgroundTemplate;
|
||||
|
||||
private static readonly Dictionary<GridItemView, ItemContextClass> SelectedItemViews = [];
|
||||
private static readonly List<ItemContextClass> SortedItemContexts = [];
|
||||
|
||||
private static readonly Dictionary<GridItemView, ItemContextClass> SecondaryItemViews = [];
|
||||
private static readonly List<ItemContextClass> SecondaryItemContexts = [];
|
||||
private static readonly Dictionary<ItemContextClass, GridItemView> SelectedItems = [];
|
||||
private static readonly Dictionary<ItemContextClass, GridItemView> SecondaryItems = [];
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
@@ -34,10 +33,11 @@ namespace UIFixes
|
||||
|
||||
public static void Toggle(GridItemView itemView, bool secondary = false)
|
||||
{
|
||||
var dictionary = secondary ? SecondaryItemViews : SelectedItemViews;
|
||||
if (dictionary.ContainsKey(itemView))
|
||||
var dictionary = secondary ? SecondaryItems : SelectedItems;
|
||||
ItemContextClass itemContext = dictionary.FirstOrDefault(x => x.Value == itemView).Key;
|
||||
if (itemContext != null)
|
||||
{
|
||||
Deselect(itemView, secondary);
|
||||
Deselect(itemContext, secondary);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -48,92 +48,131 @@ namespace UIFixes
|
||||
public static void Clear()
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
var dictionary = secondary ? SecondaryItemViews : SelectedItemViews;
|
||||
var list = secondary ? SecondaryItemContexts : SortedItemContexts;
|
||||
var dictionary = secondary ? SecondaryItems : SelectedItems;
|
||||
|
||||
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);
|
||||
itemContext.GClass2813_0.OnDisposed += RugPull;
|
||||
itemContext.OnDisposed += RugPull;
|
||||
|
||||
// Remove event handlers that no one cares about and cause stack overflows
|
||||
itemContext.method_1();
|
||||
|
||||
dictionary.Add(itemView, itemContext);
|
||||
list.Add(itemContext);
|
||||
// Subscribe to window closures to deselect
|
||||
GClass3085 windowContext = itemView.GetComponentInParent<GridWindow>()?.WindowContext ?? itemView.GetComponentInParent<InfoWindow>()?.WindowContext;
|
||||
if (windowContext != null)
|
||||
{
|
||||
windowContext.OnClose += () => Deselect(itemContext);
|
||||
}
|
||||
|
||||
dictionary.Add(itemContext, 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)
|
||||
{
|
||||
var dictionary = secondary ? SecondaryItemViews : SelectedItemViews;
|
||||
var list = secondary ? SecondaryItemContexts : SortedItemContexts;
|
||||
var dictionary = secondary ? SecondaryItems : SelectedItems;
|
||||
|
||||
if (dictionary.TryGetValue(itemView, out ItemContextClass itemContext))
|
||||
ItemContextClass itemContext = dictionary.FirstOrDefault(x => x.Value == itemView).Key;
|
||||
if (itemContext != null)
|
||||
{
|
||||
itemContext.GClass2813_0.OnDisposed -= RugPull;
|
||||
itemContext.OnDisposed -= RugPull;
|
||||
dictionary.Remove(itemContext);
|
||||
itemContext.Dispose();
|
||||
list.Remove(itemContext);
|
||||
dictionary.Remove(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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
SortedItemContexts.Add(itemContext);
|
||||
}
|
||||
|
||||
SecondaryItemViews.Clear();
|
||||
SecondaryItemContexts.Clear();
|
||||
SecondaryItems.Clear();
|
||||
}
|
||||
|
||||
public static IEnumerable<ItemContextClass> ItemContexts
|
||||
{
|
||||
get { return SortedItemContexts; }
|
||||
get { return SelectedItems.Keys; }
|
||||
}
|
||||
|
||||
public static IEnumerable<ItemContextClass> SecondaryContexts
|
||||
{
|
||||
get { return SecondaryItemContexts; }
|
||||
get { return SecondaryItems.Keys; }
|
||||
}
|
||||
|
||||
public static int Count
|
||||
{
|
||||
get { return SelectedItemViews.Count; }
|
||||
get { return SelectedItems.Count; }
|
||||
}
|
||||
|
||||
public static int SecondaryCount
|
||||
{
|
||||
get { return SecondaryItemViews.Count; }
|
||||
get { return SecondaryItems.Count; }
|
||||
}
|
||||
|
||||
public static bool Active
|
||||
{
|
||||
get { return SelectedItemViews.Count > 0; }
|
||||
get { return SelectedItems.Count > 0; }
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
GameObject selectedMark = itemView.transform.Find("SelectedMark")?.gameObject;
|
||||
@@ -186,6 +220,11 @@ namespace UIFixes
|
||||
|
||||
private static void HideSelection(GridItemView itemView)
|
||||
{
|
||||
if (itemView == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject selectedMark = itemView.transform.Find("SelectedMark")?.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
|
||||
private static bool DisableMerge = false;
|
||||
|
||||
// Specific type of TaskSerializer because Unity can't understand generics
|
||||
public class ItemContextTaskSerializer : TaskSerializer<ItemContextClass> { }
|
||||
|
||||
public static void Enable()
|
||||
{
|
||||
new InitializeCommonUIPatch().Enable();
|
||||
new InitializeMenuUIPatch().Enable();
|
||||
new SelectOnMouseDownPatch().Enable();
|
||||
new SelectMovedItemViewPatch().Enable();
|
||||
new DeselectOnGridItemViewClickPatch().Enable();
|
||||
new DeselectOnTradingItemViewClickPatch().Enable();
|
||||
new DeselectOnItemViewKillPatch().Enable();
|
||||
new HandleItemViewInitPatch().Enable();
|
||||
new HandleItemViewKillPatch().Enable();
|
||||
new BeginDragPatch().Enable();
|
||||
new EndDragPatch().Enable();
|
||||
new InspectWindowHack().Enable();
|
||||
//new InspectWindowHack().Enable();
|
||||
new DisableSplitPatch().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()
|
||||
{
|
||||
@@ -205,7 +228,7 @@ namespace UIFixes
|
||||
|
||||
if (__instance is GridItemView gridItemView)
|
||||
{
|
||||
MultiSelect.Deselect(gridItemView);
|
||||
MultiSelect.OnKillItemView(gridItemView);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,7 +274,7 @@ namespace UIFixes
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
@@ -306,9 +329,16 @@ namespace UIFixes
|
||||
FindOrigin = GetTargetGridAddress(itemContext, selectedItemContext, hoveredAddress);
|
||||
FindVerticalFirst = selectedItemContext.ItemRotation == ItemRotation.Vertical;
|
||||
|
||||
operation = targetItem != null ?
|
||||
wrappedInstance.TraderController.ExecutePossibleAction(selectedItemContext, targetItem, false /* splitting */, false /* simulate */) :
|
||||
wrappedInstance.TraderController.ExecutePossibleAction(selectedItemContext, __instance.SourceContext, hoveredAddress, false /* splitting */, false /* simulate */);
|
||||
if (targetItem is SortingTableClass)
|
||||
{
|
||||
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;
|
||||
FindVerticalFirst = false;
|
||||
@@ -377,8 +407,31 @@ namespace UIFixes
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
return true;
|
||||
@@ -390,7 +443,12 @@ namespace UIFixes
|
||||
LocationInGrid hoveredLocation = __instance.CalculateItemLocation(itemContext);
|
||||
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 =>
|
||||
{
|
||||
FindOrigin = GetTargetGridAddress(itemContext, ic, hoveredAddress);
|
||||
@@ -417,7 +475,7 @@ namespace UIFixes
|
||||
public class AdjustQuickFindFlagsPatch : ModulePatch
|
||||
{
|
||||
// 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()
|
||||
{
|
||||
@@ -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 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
|
||||
private static IEnumerable<ItemContextClass> SortSelectedContexts(
|
||||
IEnumerable<ItemContextClass> selectedContexts, ItemContextClass itemContext, bool prepend = true)
|
||||
@@ -675,7 +631,7 @@ namespace UIFixes
|
||||
|
||||
InPatch = true;
|
||||
|
||||
var serializer = __instance.GetOrAddComponent<TaskSerializer>();
|
||||
var serializer = __instance.GetOrAddComponent<TaskSerializer<ItemContextClass>>();
|
||||
__result = serializer.Initialize(MultiSelect.ItemContexts, itemContext => __instance.AcceptItem(itemContext, targetItemContext));
|
||||
|
||||
__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;
|
||||
private Queue<ItemContextClass> itemContexts;
|
||||
private Task currentTask;
|
||||
private TaskCompletionSource totalTask;
|
||||
|
||||
public Task Initialize(IEnumerable<ItemContextClass> itemContexts, Func<ItemContextClass, Task> func)
|
||||
if (operation.Value is not GClass2786 moveOperation || moveOperation.To is not GClass2769 gridAddress)
|
||||
{
|
||||
// Create new contexts because the underlying ones will be disposed when drag ends
|
||||
this.itemContexts = new(itemContexts);
|
||||
this.func = func;
|
||||
|
||||
currentTask = Task.CompletedTask;
|
||||
Update();
|
||||
|
||||
totalTask = new TaskCompletionSource();
|
||||
return totalTask.Task;
|
||||
return;
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
currentTask = func(itemContexts.Dequeue());
|
||||
}
|
||||
else
|
||||
{
|
||||
totalTask.Complete();
|
||||
func = null;
|
||||
Destroy(this);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
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