refactor to handle itemview kill/create, fix sorting table, cleanup

This commit is contained in:
Tyfon
2024-06-19 00:47:48 -07:00
parent 3ea9726189
commit 8a2eb49baa
4 changed files with 349 additions and 228 deletions

View File

@@ -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

View File

@@ -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
}
}
}

View File

@@ -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
View 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);
}
}
}
}