From 44518e52d56c5e903f5c66d498fed7cf0a5af1d5 Mon Sep 17 00:00:00 2001 From: Tyfon <29051038+tyfon7@users.noreply.github.com> Date: Wed, 2 Oct 2024 13:35:48 -0700 Subject: [PATCH] Block GridView.MagnifyIfPossible to prevent multidrag issues with sorting table --- src/Patches/MultiSelectPatches.cs | 45 ++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/Patches/MultiSelectPatches.cs b/src/Patches/MultiSelectPatches.cs index 7be9306..081478c 100644 --- a/src/Patches/MultiSelectPatches.cs +++ b/src/Patches/MultiSelectPatches.cs @@ -35,6 +35,8 @@ public static class MultiSelectPatches private static bool DisableMerge = false; private static bool IgnoreItemParent = false; + private static bool DisableMagnify = false; // Causes issues during multi drag + private static readonly Color ValidMoveColor = new(0.06f, 0.38f, 0.06f, 0.57f); public static void Enable() @@ -55,6 +57,7 @@ public static class MultiSelectPatches new DisableSplitPatch().Enable(); new DisableSplitTargetPatch().Enable(); new FixSearchedContextPatch().Enable(); + new DisableMagnifyPatch().Enable(); // Actions new ItemViewClickPatch().Enable(); @@ -535,6 +538,24 @@ public static class MultiSelectPatches } } + // MagnifyIfPossible gets called when a dynamic grid (sorting table) resizes. It causes GridViews to be killed and recreated asynchronously (!) + // This causes all sorts of issues with multiselect move, as there are race conditions and items get dropped and views duplicated + // I'm not 100% sure what it does, it appears to be trying to unload items that may now be out of sight, an optimization I'm willing + // to sacrifice for this actually work properly. + public class DisableMagnifyPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + return AccessTools.Method(typeof(GridView), nameof(GridView.MagnifyIfPossible), []); + } + + [PatchPrefix] + public static bool Prefix() + { + return !DisableMagnify; + } + } + public class GridViewCanAcceptPatch : ModulePatch { protected override MethodBase GetTargetMethod() @@ -592,6 +613,7 @@ public static class MultiSelectPatches Item targetItem = __instance.method_8(targetItemContext); DisableMerge = targetItem == null; + DisableMagnify = true; bool isGridPlacement = targetItem == null; // If everything selected is the same type and is a stackable type, allow partial success @@ -719,6 +741,8 @@ public static class MultiSelectPatches operations.Pop().Value?.RollBack(); } + DisableMagnify = false; + // result and operation are set to the last one that completed - so success if they all passed, or the first failure return false; } @@ -1314,28 +1338,35 @@ public static class MultiSelectPatches int firstStart = FindOrigin != null ? invertDimensions ? FindOrigin.LocationInGrid.x : FindOrigin.LocationInGrid.y : 0; int secondStart = FindOrigin != null ? invertDimensions ? FindOrigin.LocationInGrid.y : FindOrigin.LocationInGrid.x : 0; - // Walks the first dimension until it finds a row/column with enough space, then walks down that row - // /column until it finds a column/row with enough space + // Walks the first dimension until it finds a row/column with enough space, + // then walks down that row/column until it finds a column/row with enough space // Starts at origin, wraps around for (int i = 0; i < firstDimensionSize; i++) { - int firstDim = (firstStart + i) % firstDimensionSize; - //for (int j = i == firstStart ? secondStart : 0; j + itemSecondSize <= secondDimensionSize; j++) + int firstDim = (firstStart + i) % firstDimensionSize; // loop around from start for (int j = 0; j < secondDimensionSize; j++) { + // second dimension starts at FindOrigin, but after first dimension increases, starts back at 0 + // e.g. there wasn't room on the first row, then on the second row we start with first column int secondDim = firstDim == firstStart ? (secondStart + j) % secondDimensionSize : j; if (secondDim + itemSecondSize > secondDimensionSize) { continue; } - int secondDimOpenSpaces = (invertDimensions ? secondDimensionSpaces[secondDim * firstDimensionSize + firstDim] : secondDimensionSpaces[firstDim * secondDimensionSize + secondDim]); - if (secondDimOpenSpaces >= itemSecondSize || secondDimOpenSpaces == -1) // no idea what -1 means + // Open spaces is a look-ahead number of open spaces in that dimension + // -1 means "infinite", the grid can stretch in that direction (and there's no item further in that direction) + int secondDimOpenSpaces = invertDimensions ? + secondDimensionSpaces[secondDim * firstDimensionSize + firstDim] : + secondDimensionSpaces[firstDim * secondDimensionSize + secondDim]; + if (secondDimOpenSpaces >= itemSecondSize || secondDimOpenSpaces == -1) { bool enoughSpace = true; for (int k = secondDim; enoughSpace && k < secondDim + itemSecondSize; k++) { - int firstDimOpenSpaces = (invertDimensions ? firstDimensionSpaces[k * firstDimensionSize + firstDim] : firstDimensionSpaces[firstDim * secondDimensionSize + k]); + int firstDimOpenSpaces = invertDimensions ? + firstDimensionSpaces[k * firstDimensionSize + firstDim] : + firstDimensionSpaces[firstDim * secondDimensionSize + k]; enoughSpace &= firstDimOpenSpaces >= itemMainSize || firstDimOpenSpaces == -1; }