remove recreated items from reordered list

This commit is contained in:
Tyfon
2024-07-10 12:01:15 -07:00
parent 2247b7bea6
commit 395108eda8
2 changed files with 135 additions and 110 deletions

View File

@@ -1,4 +1,5 @@
using EFT.UI.DragAndDrop; using EFT.InventoryLogic;
using EFT.UI.DragAndDrop;
using HarmonyLib; using HarmonyLib;
using SPT.Reflection.Patching; using SPT.Reflection.Patching;
using System; using System;
@@ -9,157 +10,181 @@ using UnityEngine;
namespace UIFixes namespace UIFixes
{ {
/* There are 3 cases to handle in TemplatedGridsView.Show public static class ReorderGridsPatches
* 1. An item is shown for the first time
* - It renders on its own, and the UI is correct
* - Use the UI to sort Grids, and update GridViews to match
* 2. An item is shown for the 2nd+ time in a new context
* - The GridViews will be recreated, so in the prefix we need to reorder them to match the Grids order
* 3. An existing TemplatedGridsView is reshown
* - Everything is already in place, no action needed
*/
public class ReorderGridsPatch : ModulePatch
{ {
private static readonly HashSet<string> ReorderedItems = []; private static readonly HashSet<string> ReorderedItems = [];
private static readonly Dictionary<string, int[]> GridMaps = [];
protected override MethodBase GetTargetMethod() public static void Enable()
{ {
return AccessTools.DeclaredMethod(typeof(TemplatedGridsView), nameof(TemplatedGridsView.Show)); new ReorderGridsPatch().Enable();
new ItemCreationPatch().Enable();
} }
[PatchPrefix] /* There are 3 cases to handle in TemplatedGridsView.Show
public static void Prefix(TemplatedGridsView __instance, LootItemClass compoundItem, ref GridView[] ____presetGridViews) * 1. An item is shown for the first time
* - It renders on its own, and the UI is correct
* - Use the UI to sort Grids, and update GridViews to match
* 2. An item is shown for the 2nd+ time in a new context
* - The GridViews will be recreated, so in the prefix we need to reorder them to match the Grids order
* 3. An existing TemplatedGridsView is reshown
* - Everything is already in place, no action needed
*/
public class ReorderGridsPatch : ModulePatch
{ {
if (!Settings.ReorderGrids.Value) private static readonly Dictionary<string, int[]> GridMaps = [];
protected override MethodBase GetTargetMethod()
{ {
// To properly support disabling this feature: return AccessTools.DeclaredMethod(typeof(TemplatedGridsView), nameof(TemplatedGridsView.Show));
// 1. Items that sorted their Grids need to return them to original order }
// 2. If this TemplatedGridsView was sorted, it needs to be unsorted to match
if (ReorderedItems.Contains(compoundItem.Id) && GridMaps.TryGetValue(compoundItem.TemplateId, out int[] unwantedMap)) [PatchPrefix]
public static void Prefix(TemplatedGridsView __instance, LootItemClass compoundItem, ref GridView[] ____presetGridViews)
{
if (!Settings.ReorderGrids.Value)
{ {
StashGridClass[] orderedGrids = new StashGridClass[compoundItem.Grids.Length]; // To properly support disabling this feature:
for (int i = 0; i < compoundItem.Grids.Length; i++) // 1. Items that sorted their Grids need to return them to original order
// 2. If this TemplatedGridsView was sorted, it needs to be unsorted to match
if (ReorderedItems.Contains(compoundItem.Id) && GridMaps.TryGetValue(compoundItem.TemplateId, out int[] unwantedMap))
{ {
orderedGrids[i] = compoundItem.Grids[unwantedMap[i]]; StashGridClass[] orderedGrids = new StashGridClass[compoundItem.Grids.Length];
for (int i = 0; i < compoundItem.Grids.Length; i++)
{
orderedGrids[i] = compoundItem.Grids[unwantedMap[i]];
}
compoundItem.Grids = orderedGrids;
ReorderedItems.Remove(compoundItem.Id);
if (IsSorted(__instance))
{
GridView[] orderedGridView = new GridView[____presetGridViews.Length];
for (int i = 0; i < ____presetGridViews.Length; i++)
{
orderedGridView[i] = ____presetGridViews[unwantedMap[i]];
}
____presetGridViews = orderedGridView;
MarkSorted(__instance, false);
}
} }
compoundItem.Grids = orderedGrids; return;
ReorderedItems.Remove(compoundItem.Id); }
if (IsSorted(__instance)) if (ReorderedItems.Contains(compoundItem.Id) && !IsSorted(__instance))
{
// This is a new context of a sorted Item, need to presort the GridViews
if (GridMaps.TryGetValue(compoundItem.TemplateId, out int[] map))
{ {
GridView[] orderedGridView = new GridView[____presetGridViews.Length]; GridView[] orderedGridView = new GridView[____presetGridViews.Length];
for (int i = 0; i < ____presetGridViews.Length; i++) for (int i = 0; i < ____presetGridViews.Length; i++)
{ {
orderedGridView[i] = ____presetGridViews[unwantedMap[i]]; orderedGridView[map[i]] = ____presetGridViews[i];
} }
____presetGridViews = orderedGridView; ____presetGridViews = orderedGridView;
MarkSorted(__instance, false); MarkSorted(__instance);
}
else
{
Logger.LogError($"Item {compoundItem.Id}, tpl: {compoundItem.TemplateId} has sorted Grids but no map to sort GridViews!");
} }
} }
return;
} }
if (ReorderedItems.Contains(compoundItem.Id) && !IsSorted(__instance)) [PatchPostfix]
public static void Postfix(TemplatedGridsView __instance, LootItemClass compoundItem, ref GridView[] ____presetGridViews)
{ {
// This is a new context of a sorted Item, need to presort the GridViews if (!Settings.ReorderGrids.Value || ReorderedItems.Contains(compoundItem.Id))
if (GridMaps.TryGetValue(compoundItem.TemplateId, out int[] map))
{ {
GridView[] orderedGridView = new GridView[____presetGridViews.Length]; return;
}
var pairs = compoundItem.Grids.Zip(____presetGridViews, (g, gv) => new KeyValuePair<StashGridClass, GridView>(g, gv));
RectTransform parentView = __instance.RectTransform();
Vector2 parentPosition = parentView.pivot.y == 1 ? parentView.position : new Vector2(parentView.position.x, parentView.position.y + parentView.sizeDelta.y);
Vector2 gridSize = new(64f * parentView.lossyScale.x, 64f * parentView.lossyScale.y);
var sorted = pairs.OrderBy(pair =>
{
var grid = pair.Key;
var gridView = pair.Value;
float xOffset = gridView.transform.position.x - parentPosition.x;
float yOffset = -(gridView.transform.position.y - parentPosition.y); // invert y since grid coords are upper-left origin
int x = (int)Math.Round(xOffset / gridSize.x, MidpointRounding.AwayFromZero);
int y = (int)Math.Round(yOffset / gridSize.y, MidpointRounding.AwayFromZero);
return y * 100 + x;
});
GridView[] orderedGridViews = sorted.Select(pair => pair.Value).ToArray();
// Populate the gridmap
if (!GridMaps.ContainsKey(compoundItem.TemplateId))
{
int[] map = new int[____presetGridViews.Length];
for (int i = 0; i < ____presetGridViews.Length; i++) for (int i = 0; i < ____presetGridViews.Length; i++)
{ {
orderedGridView[map[i]] = ____presetGridViews[i]; map[i] = orderedGridViews.IndexOf(____presetGridViews[i]);
} }
____presetGridViews = orderedGridView; GridMaps.Add(compoundItem.TemplateId, map);
MarkSorted(__instance); }
compoundItem.Grids = sorted.Select(pair => pair.Key).ToArray();
____presetGridViews = orderedGridViews;
ReorderedItems.Add(compoundItem.Id);
MarkSorted(__instance);
}
private static bool IsSorted(TemplatedGridsView view)
{
return view != null && view.GetComponent<SortedMarker>() != null;
}
private static void MarkSorted(TemplatedGridsView view, bool marked = true)
{
if (view == null)
{
return;
}
if (marked)
{
view.GetOrAddComponent<SortedMarker>();
} }
else else
{ {
Logger.LogError($"Item {compoundItem.Id}, tpl: {compoundItem.TemplateId} has sorted Grids but no map to sort GridViews!"); SortedMarker marker = view.GetComponent<SortedMarker>();
if (marker != null)
{
UnityEngine.Object.DestroyImmediate(marker);
}
} }
} }
public class SortedMarker : MonoBehaviour { }
} }
[PatchPostfix] public class ItemCreationPatch : ModulePatch
public static void Postfix(TemplatedGridsView __instance, LootItemClass compoundItem, ref GridView[] ____presetGridViews)
{ {
if (!Settings.ReorderGrids.Value || ReorderedItems.Contains(compoundItem.Id)) protected override MethodBase GetTargetMethod()
{ {
return; return AccessTools.Constructor(typeof(Item), [typeof(string), typeof(ItemTemplate)]);
} }
var pairs = compoundItem.Grids.Zip(____presetGridViews, (g, gv) => new KeyValuePair<StashGridClass, GridView>(g, gv)); [PatchPostfix]
public static void Postfix(string id)
RectTransform parentView = __instance.RectTransform();
Vector2 parentPosition = parentView.pivot.y == 1 ? parentView.position : new Vector2(parentView.position.x, parentView.position.y + parentView.sizeDelta.y);
Vector2 gridSize = new(64f * parentView.lossyScale.x, 64f * parentView.lossyScale.y);
var sorted = pairs.OrderBy(pair =>
{ {
var grid = pair.Key; ReorderedItems.Remove(id);
var gridView = pair.Value;
float xOffset = gridView.transform.position.x - parentPosition.x;
float yOffset = -(gridView.transform.position.y - parentPosition.y); // invert y since grid coords are upper-left origin
int x = (int)Math.Round(xOffset / gridSize.x, MidpointRounding.AwayFromZero);
int y = (int)Math.Round(yOffset / gridSize.y, MidpointRounding.AwayFromZero);
return y * 100 + x;
});
GridView[] orderedGridViews = sorted.Select(pair => pair.Value).ToArray();
// Populate the gridmap
if (!GridMaps.ContainsKey(compoundItem.TemplateId))
{
int[] map = new int[____presetGridViews.Length];
for (int i = 0; i < ____presetGridViews.Length; i++)
{
map[i] = orderedGridViews.IndexOf(____presetGridViews[i]);
}
GridMaps.Add(compoundItem.TemplateId, map);
}
compoundItem.Grids = sorted.Select(pair => pair.Key).ToArray();
____presetGridViews = orderedGridViews;
ReorderedItems.Add(compoundItem.Id);
MarkSorted(__instance);
}
private static bool IsSorted(TemplatedGridsView view)
{
return view != null && view.GetComponent<SortedMarker>() != null;
}
private static void MarkSorted(TemplatedGridsView view, bool marked = true)
{
if (view == null)
{
return;
}
if (marked)
{
view.GetOrAddComponent<SortedMarker>();
}
else
{
SortedMarker marker = view.GetComponent<SortedMarker>();
if (marker != null)
{
UnityEngine.Object.DestroyImmediate(marker);
}
} }
} }
public class SortedMarker : MonoBehaviour { }
} }
} }

View File

@@ -58,7 +58,7 @@ namespace UIFixes
new PutToolsBackPatch().Enable(); new PutToolsBackPatch().Enable();
new RebindGrenadesPatch().Enable(); new RebindGrenadesPatch().Enable();
AimToggleHoldPatches.Enable(); AimToggleHoldPatches.Enable();
new ReorderGridsPatch().Enable(); ReorderGridsPatches.Enable();
NoRandomGrenadesPatch.Init(); NoRandomGrenadesPatch.Init();
GPCoinPatches.Enable(); GPCoinPatches.Enable();
} }