diff --git a/Patches/NoRandomGrenadesPatch.cs b/Patches/NoRandomGrenadesPatch.cs new file mode 100644 index 0000000..3eb6695 --- /dev/null +++ b/Patches/NoRandomGrenadesPatch.cs @@ -0,0 +1,60 @@ +using HarmonyLib; +using SPT.Reflection.Patching; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; + +namespace UIFixes +{ + public class NoRandomGrenadesPatch : ModulePatch + { + private static NoRandomGrenadesPatch Patch; + + public static void Init() + { + Settings.DeterministicGrenades.Bind(enabled => + { + if (enabled) + { + Patch ??= new NoRandomGrenadesPatch(); + Patch.Enable(); + } + else + { + Patch?.Disable(); + } + }); + } + + // Make ctor private so I don't forget to call Init() instead + private NoRandomGrenadesPatch() { } + + protected override MethodBase GetTargetMethod() + { + return AccessTools.Method(typeof(Class1472), nameof(Class1472.vmethod_1)); + } + + [PatchTranspiler] + public static IEnumerable Transpile(IEnumerable instructions) + { + foreach (var instruction in instructions) + { + if (instruction.opcode == OpCodes.Ble_S || instruction.opcode == OpCodes.Ble) // DnSpy is lying about which one this is!? + { + // This is the line + // if (count > 0) + // which in IL does "if count is less than or equal to 1, jump over" + // So switch the IL to bge, so it jumps over if count is greater or equal to 1, thus skipping the randomizer + yield return new CodeInstruction(instruction) + { + opcode = instruction.opcode == OpCodes.Ble_S ? OpCodes.Bge_S : OpCodes.Bge, + }; + } + else + { + yield return instruction; + } + } + } + } +} diff --git a/Patches/ReorderGridsPatch.cs b/Patches/ReorderGridsPatch.cs new file mode 100644 index 0000000..5242b64 --- /dev/null +++ b/Patches/ReorderGridsPatch.cs @@ -0,0 +1,114 @@ +using EFT.UI.DragAndDrop; +using HarmonyLib; +using SPT.Reflection.Patching; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; + +namespace UIFixes +{ + public class ReorderGridsPatch : ModulePatch + { + private static readonly HashSet ReorderedItems = []; + private static readonly Dictionary GridMaps = []; + + protected override MethodBase GetTargetMethod() + { + return AccessTools.DeclaredMethod(typeof(TemplatedGridsView), nameof(TemplatedGridsView.Show)); + } + + [PatchPrefix] + public static void Prefix(LootItemClass compoundItem, ref GridView[] ____presetGridViews) + { + if (!Settings.ReorderGrids.Value) + { + if (ReorderedItems.Contains(compoundItem.Id) && GridMaps.TryGetValue(compoundItem.TemplateId, out int[] unwantedMap)) + { + // Put it back + 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); + } + + return; + } + + if (GridMaps.TryGetValue(compoundItem.TemplateId, out int[] map)) + { + GridView[] orderedGridView = new GridView[____presetGridViews.Length]; + for (int i = 0; i < ____presetGridViews.Length; i++) + { + orderedGridView[map[i]] = ____presetGridViews[i]; + } + + ____presetGridViews = orderedGridView; + + if (!ReorderedItems.Contains(compoundItem.Id)) + { + StashGridClass[] orderedGrids = new StashGridClass[compoundItem.Grids.Length]; + for (int i = 0; i < compoundItem.Grids.Length; i++) + { + orderedGrids[map[i]] = compoundItem.Grids[i]; + } + + compoundItem.Grids = orderedGrids; + ReorderedItems.Add(compoundItem.Id); + } + } + } + + [PatchPostfix] + public static void Postfix(TemplatedGridsView __instance, LootItemClass compoundItem, ref GridView[] ____presetGridViews) + { + if (!Settings.ReorderGrids.Value || ReorderedItems.Contains(compoundItem.Id)) + { + return; + } + + var pairs = compoundItem.Grids.Zip(____presetGridViews, (g, gv) => new KeyValuePair(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++) + { + 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); + } + } +} diff --git a/Plugin.cs b/Plugin.cs index 4380b8c..3e900d7 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -58,6 +58,8 @@ namespace UIFixes new PutToolsBackPatch().Enable(); new RebindGrenadesPatch().Enable(); AimToggleHoldPatches.Enable(); + new ReorderGridsPatch().Enable(); + NoRandomGrenadesPatch.Init(); } public static bool InRaid() diff --git a/Settings.cs b/Settings.cs index 7efbb35..113fdd8 100644 --- a/Settings.cs +++ b/Settings.cs @@ -76,6 +76,7 @@ namespace UIFixes public static ConfigEntry ShowMultiSelectDebug { get; set; } // Advanced public static ConfigEntry SwapItems { get; set; } public static ConfigEntry SwapImpossibleContainers { get; set; } + public static ConfigEntry ReorderGrids { get; set; } public static ConfigEntry SynchronizeStashScrolling { get; set; } public static ConfigEntry GreedyStackMove { get; set; } public static ConfigEntry MergeFIRMoney { get; set; } @@ -98,6 +99,7 @@ namespace UIFixes // In Raid public static ConfigEntry RemoveDisabledActions { get; set; } public static ConfigEntry EnableLoadAmmo { get; set; } + public static ConfigEntry DeterministicGrenades { get; set; } // Flea Market public static ConfigEntry EnableFleaHistory { get; set; } @@ -394,6 +396,15 @@ namespace UIFixes null, new ConfigurationManagerAttributes { }))); + configEntries.Add(ReorderGrids = config.Bind( + InventorySection, + "Standardize Grid Order", + true, + new ConfigDescription( + "Change internal ordering of grids in rigs/backpacks to be left to right, top to bottom", + null, + new ConfigurationManagerAttributes { }))); + configEntries.Add(SynchronizeStashScrolling = config.Bind( InventorySection, "Synchronize Stash Scroll Position", @@ -558,6 +569,15 @@ namespace UIFixes null, new ConfigurationManagerAttributes { }))); + configEntries.Add(DeterministicGrenades = config.Bind( + InRaidSection, + "Nonrandom Grenades", + false, + new ConfigDescription( + "By default, EFT picks a random grenade when you hit the Grenade key. This removes that behavior", + null, + new ConfigurationManagerAttributes { }))); + // Flea Market configEntries.Add(EnableFleaHistory = config.Bind( FleaMarketSection,