ctrl-click working
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using EFT.UI;
|
using EFT.InventoryLogic;
|
||||||
|
using EFT.UI;
|
||||||
using EFT.UI.DragAndDrop;
|
using EFT.UI.DragAndDrop;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -235,6 +236,18 @@ namespace UIFixes
|
|||||||
public class MultiSelectItemContext(ItemContextAbstractClass itemContext, ItemRotation rotation) : ItemContextClass(itemContext, rotation)
|
public class MultiSelectItemContext(ItemContextAbstractClass itemContext, ItemRotation rotation) : ItemContextClass(itemContext, rotation)
|
||||||
{
|
{
|
||||||
public override bool SplitAvailable => false;
|
public override bool SplitAvailable => false;
|
||||||
|
|
||||||
|
// used by ItemUiContext.QuickFindAppropriatePlace, the one that picks a container, i.e. ctrl-click
|
||||||
|
// ItemContextClass (drag) defaults to None, but we want what the underlying item allows
|
||||||
|
public override bool CanQuickMoveTo(ETargetContainer targetContainer)
|
||||||
|
{
|
||||||
|
if (this.GClass2813_0 != null)
|
||||||
|
{
|
||||||
|
return this.GClass2813_0.CanQuickMoveTo(targetContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.CanQuickMoveTo(targetContainer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MultiSelectExtensions
|
public static class MultiSelectExtensions
|
||||||
|
@@ -36,7 +36,7 @@ namespace UIFixes
|
|||||||
|
|
||||||
foreach (ItemContextClass itemContext in MultiSelect.ItemContexts)
|
foreach (ItemContextClass itemContext in MultiSelect.ItemContexts)
|
||||||
{
|
{
|
||||||
builder.Append(itemContext.Item.ToString());
|
builder.AppendFormat("x{0} {1}", itemContext.Item.StackObjectsCount, itemContext.Item.ToString());
|
||||||
builder.AppendLine();
|
builder.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -95,7 +95,10 @@ namespace UIFixes
|
|||||||
.Where(i => insurance.ItemTypeAvailableForInsurance(i) && !insurance.InsuredItems.Contains(i))
|
.Where(i => insurance.ItemTypeAvailableForInsurance(i) && !insurance.InsuredItems.Contains(i))
|
||||||
.Count();
|
.Count();
|
||||||
|
|
||||||
____text.text += " (x" + count + ")";
|
if (count > 0)
|
||||||
|
{
|
||||||
|
____text.text += " (x" + count + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using Aki.Reflection.Patching;
|
using Aki.Reflection.Patching;
|
||||||
using Comfort.Common;
|
using Comfort.Common;
|
||||||
|
using EFT.Communications;
|
||||||
using EFT.InventoryLogic;
|
using EFT.InventoryLogic;
|
||||||
using EFT.UI;
|
using EFT.UI;
|
||||||
using EFT.UI.DragAndDrop;
|
using EFT.UI.DragAndDrop;
|
||||||
@@ -30,6 +31,7 @@ namespace UIFixes
|
|||||||
|
|
||||||
// Prevents QuickFind from attempting a merge
|
// Prevents QuickFind from attempting a merge
|
||||||
private static bool DisableMerge = false;
|
private static bool DisableMerge = false;
|
||||||
|
private static bool IgnoreItemParent = false;
|
||||||
|
|
||||||
// Specific type of TaskSerializer because Unity can't understand generics
|
// Specific type of TaskSerializer because Unity can't understand generics
|
||||||
public class ItemContextTaskSerializer : TaskSerializer<ItemContextClass> { }
|
public class ItemContextTaskSerializer : TaskSerializer<ItemContextClass> { }
|
||||||
@@ -39,7 +41,7 @@ namespace UIFixes
|
|||||||
new InitializeCommonUIPatch().Enable();
|
new InitializeCommonUIPatch().Enable();
|
||||||
new InitializeMenuUIPatch().Enable();
|
new InitializeMenuUIPatch().Enable();
|
||||||
new SelectOnMouseDownPatch().Enable();
|
new SelectOnMouseDownPatch().Enable();
|
||||||
new DeselectOnGridItemViewClickPatch().Enable();
|
new ItemViewClickPatch().Enable();
|
||||||
new DeselectOnTradingItemViewClickPatch().Enable();
|
new DeselectOnTradingItemViewClickPatch().Enable();
|
||||||
new HandleItemViewInitPatch().Enable();
|
new HandleItemViewInitPatch().Enable();
|
||||||
new HandleItemViewKillPatch().Enable();
|
new HandleItemViewKillPatch().Enable();
|
||||||
@@ -144,26 +146,101 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DeselectOnGridItemViewClickPatch : ModulePatch
|
public class ItemViewClickPatch : ModulePatch
|
||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(typeof(GridItemView), nameof(GridItemView.OnClick));
|
return AccessTools.Method(typeof(GridItemView), nameof(GridItemView.OnClick));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPrefix]
|
||||||
public static void Postfix(PointerEventData.InputButton button)
|
public static bool Prefix(GridItemView __instance, PointerEventData.InputButton button, ItemUiContext ___ItemUiContext, TraderControllerClass ___ItemController)
|
||||||
{
|
{
|
||||||
if (!MultiSelect.Active)
|
if (!MultiSelect.Active || button != PointerEventData.InputButton.Left || ___ItemUiContext == null || !__instance.IsSearched)
|
||||||
{
|
{
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mousedown handles most things, just need to handle the non-shift click of a selected item
|
bool ctrlDown = Input.GetKey(KeyCode.LeftControl) && !Input.GetKey(KeyCode.RightControl);
|
||||||
if (button == PointerEventData.InputButton.Left && !Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift))
|
bool shiftDown = Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift);
|
||||||
|
bool altDown = Input.GetKey(KeyCode.LeftAlt) && !Input.GetKey(KeyCode.RightAlt);
|
||||||
|
|
||||||
|
if (ctrlDown && !shiftDown && !altDown)
|
||||||
{
|
{
|
||||||
MultiSelect.Clear();
|
bool succeeded = true;
|
||||||
|
DisableMerge = true;
|
||||||
|
IgnoreItemParent = true;
|
||||||
|
Stack<GStruct413> operations = new();
|
||||||
|
foreach (ItemContextClass selectedItemContext in SortSelectedContexts(MultiSelect.ItemContexts, null, false))
|
||||||
|
{
|
||||||
|
GStruct413 operation = ___ItemUiContext.QuickFindAppropriatePlace(selectedItemContext, ___ItemController, false /*forceStash*/, false /*showWarnings*/, false /*simulate*/);
|
||||||
|
if (operation.Succeeded && ___ItemController.CanExecute(operation.Value))
|
||||||
|
{
|
||||||
|
operations.Push(operation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
succeeded = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDestroyResult destroyResult;
|
||||||
|
if ((destroyResult = operation.Value as IDestroyResult) != null && destroyResult.ItemsDestroyRequired)
|
||||||
|
{
|
||||||
|
NotificationManagerClass.DisplayWarningNotification(new GClass3320(__instance.Item, destroyResult.ItemsToDestroy).GetLocalizedDescription(), ENotificationDurationType.Default);
|
||||||
|
succeeded = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DisableMerge = false;
|
||||||
|
IgnoreItemParent = true;
|
||||||
|
|
||||||
|
if (succeeded)
|
||||||
|
{
|
||||||
|
string itemSound = __instance.Item.ItemSound;
|
||||||
|
|
||||||
|
// We didn't simulate because we needed each result to depend on the last, but we have to undo before we actually do :S
|
||||||
|
Stack<GStruct413> networkOps = new();
|
||||||
|
while (operations.Any())
|
||||||
|
{
|
||||||
|
GStruct413 operation = operations.Pop();
|
||||||
|
operation.Value.RollBack();
|
||||||
|
networkOps.Push(operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (networkOps.Any())
|
||||||
|
{
|
||||||
|
___ItemController.RunNetworkTransaction(networkOps.Pop().Value, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (___ItemUiContext.Tooltip != null)
|
||||||
|
{
|
||||||
|
___ItemUiContext.Tooltip.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Singleton<GUISounds>.Instance.PlayItemSound(itemSound, EInventorySoundType.pickup, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (operations.Any())
|
||||||
|
{
|
||||||
|
operations.Pop().Value?.RollBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shiftDown)
|
||||||
|
{
|
||||||
|
// Nothing to do, mousedown handled it.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if neither ctrl or shift is down, this is a click to clear
|
||||||
|
MultiSelect.Clear();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,6 +377,13 @@ namespace UIFixes
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BSG BUG - if the targetItem is a magazine, and the multiselect is bullets, it will NOT be able to rollback correctly!!
|
||||||
|
// To prevent inventory corruption, reject magazines outright. Sorry, no multiple bullet stacks into one magazine
|
||||||
|
if (targetItemContext != null && targetItemContext.Item is MagazineClass)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Item item = itemContext.Item;
|
Item item = itemContext.Item;
|
||||||
ItemAddress itemAddress = itemContext.ItemAddress;
|
ItemAddress itemAddress = itemContext.ItemAddress;
|
||||||
if (itemAddress == null)
|
if (itemAddress == null)
|
||||||
@@ -421,23 +505,8 @@ namespace UIFixes
|
|||||||
// Need to fully implement AcceptItem for the sorting table - normally that just uses null targetItemContext
|
// Need to fully implement AcceptItem for the sorting table - normally that just uses null targetItemContext
|
||||||
if (InPatch && targetItemContext?.Item is SortingTableClass)
|
if (InPatch && targetItemContext?.Item is SortingTableClass)
|
||||||
{
|
{
|
||||||
|
MoveToSortingTable(__instance, itemContext, ___itemUiContext_0);
|
||||||
__result = Task.CompletedTask;
|
__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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,6 +549,26 @@ namespace UIFixes
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void MoveToSortingTable(GridView gridView, ItemContextClass itemContext, ItemUiContext itemUiContext)
|
||||||
|
{
|
||||||
|
var itemController = gridView.R().TraderController;
|
||||||
|
|
||||||
|
GStruct413 operation = itemUiContext.QuickMoveToSortingTable(itemContext.Item, true);
|
||||||
|
if (operation.Failed || !itemController.CanExecute(operation.Value))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemController.RunNetworkTransaction(operation.Value, null);
|
||||||
|
|
||||||
|
if (itemUiContext.Tooltip != null)
|
||||||
|
{
|
||||||
|
itemUiContext.Tooltip.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Singleton<GUISounds>.Instance.PlayItemSound(itemContext.Item.ItemSound, EInventorySoundType.pickup, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AdjustQuickFindFlagsPatch : ModulePatch
|
public class AdjustQuickFindFlagsPatch : ModulePatch
|
||||||
@@ -508,6 +597,11 @@ namespace UIFixes
|
|||||||
{
|
{
|
||||||
order &= ~InteractionsHandlerClass.EMoveItemOrder.TryMerge;
|
order &= ~InteractionsHandlerClass.EMoveItemOrder.TryMerge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IgnoreItemParent)
|
||||||
|
{
|
||||||
|
order |= InteractionsHandlerClass.EMoveItemOrder.IgnoreItemParent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,19 +642,20 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
// Can pass no itemContext, and it just sorts items by their grid order
|
||||||
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)
|
||||||
{
|
{
|
||||||
static int gridOrder(LocationInGrid loc, StashGridClass grid) => grid.GridWidth.Value * loc.y + loc.x;
|
static int gridOrder(LocationInGrid loc, StashGridClass grid) => grid.GridWidth.Value * loc.y + loc.x;
|
||||||
|
|
||||||
var result = selectedContexts
|
var result = selectedContexts
|
||||||
.Where(ic => ic.Item != itemContext.Item)
|
.Where(ic => itemContext == null || ic.Item != itemContext.Item)
|
||||||
.OrderByDescending(ic => ic.ItemAddress is GClass2769)
|
.OrderByDescending(ic => ic.ItemAddress is GClass2769)
|
||||||
.ThenByDescending(ic => itemContext.ItemAddress is GClass2769 originalDraggedAddress && ic.ItemAddress is GClass2769 selectedGridAddress && selectedGridAddress.Grid == originalDraggedAddress.Grid)
|
.ThenByDescending(ic => itemContext != null && itemContext.ItemAddress is GClass2769 originalDraggedAddress && ic.ItemAddress is GClass2769 selectedGridAddress && selectedGridAddress.Grid == originalDraggedAddress.Grid)
|
||||||
.ThenByDescending(ic => ic.ItemAddress is GClass2769 selectedGridAddress ? selectedGridAddress.Grid.Id : null)
|
.ThenByDescending(ic => ic.ItemAddress is GClass2769 selectedGridAddress ? selectedGridAddress.Grid.Id : null)
|
||||||
.ThenBy(ic => ic.ItemAddress is GClass2769 selectedGridAddress ? gridOrder(selectedGridAddress.LocationInGrid, selectedGridAddress.Grid) : 0);
|
.ThenBy(ic => ic.ItemAddress is GClass2769 selectedGridAddress ? gridOrder(selectedGridAddress.LocationInGrid, selectedGridAddress.Grid) : 0);
|
||||||
|
|
||||||
return prepend ? result.Prepend(itemContext) : result;
|
return itemContext != null && prepend ? result.Prepend(itemContext) : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GridViewDisableHighlightPatch : ModulePatch
|
public class GridViewDisableHighlightPatch : ModulePatch
|
||||||
@@ -620,7 +715,7 @@ namespace UIFixes
|
|||||||
}
|
}
|
||||||
|
|
||||||
Stack<GStruct413> operations = new();
|
Stack<GStruct413> operations = new();
|
||||||
foreach (ItemContextClass itemContext in MultiSelect.ItemContexts)
|
foreach (ItemContextClass itemContext in SortSelectedContexts(MultiSelect.ItemContexts, null, false))
|
||||||
{
|
{
|
||||||
__result = itemContext.CanAccept(__instance.Slot, __instance.ParentItemContext, ___InventoryController, out operation, false /* simulate */);
|
__result = itemContext.CanAccept(__instance.Slot, __instance.ParentItemContext, ___InventoryController, out operation, false /* simulate */);
|
||||||
if (operation.Succeeded)
|
if (operation.Succeeded)
|
||||||
@@ -667,7 +762,7 @@ namespace UIFixes
|
|||||||
InPatch = true;
|
InPatch = true;
|
||||||
|
|
||||||
var serializer = __instance.GetOrAddComponent<ItemContextTaskSerializer>();
|
var serializer = __instance.GetOrAddComponent<ItemContextTaskSerializer>();
|
||||||
__result = serializer.Initialize(MultiSelect.ItemContexts, itemContext => __instance.AcceptItem(itemContext, targetItemContext));
|
__result = serializer.Initialize(SortSelectedContexts(MultiSelect.ItemContexts, null, false), itemContext => __instance.AcceptItem(itemContext, targetItemContext));
|
||||||
|
|
||||||
__result.ContinueWith(_ => { InPatch = false; });
|
__result.ContinueWith(_ => { InPatch = false; });
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user