Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MySix NearbyChests v1.0.2
MySix.NearbyChests.dll
Decompiled 4 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using HarmonyLib; using MySix.Core; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.0.0.0")] namespace MySix { internal static class SuiteVersion { public const string Value = "1.0.2"; } } namespace MySix.NearbyChests { internal static class ConnectionEffect { public static Setting<bool> Show; private const float Seconds = 3f; private static GameObject _prefab; private static ZNetScene _scanned; public static void Play(CraftingStation station, Container container) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) if (Show != null && !Show.Value) { return; } GameObject val = Prefab(); if (!((Object)(object)val == (Object)null)) { Vector3 val2 = ((Component)container).transform.position + Vector3.up * container.GetHoverOffset(); Vector3 val3 = station.GetConnectionEffectPoint() - val2; if (!(((Vector3)(ref val3)).sqrMagnitude <= 0f)) { GameObject obj = Object.Instantiate<GameObject>(val, val2, Quaternion.LookRotation(((Vector3)(ref val3)).normalized)); obj.transform.localScale = new Vector3(1f, 1f, ((Vector3)(ref val3)).magnitude); Object.Destroy((Object)(object)obj, 3f); } } } private static GameObject Prefab() { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { return null; } if ((Object)(object)instance == (Object)(object)_scanned) { return _prefab; } _scanned = instance; _prefab = null; foreach (GameObject prefab in instance.m_prefabs) { StationExtension component = prefab.GetComponent<StationExtension>(); if ((Object)(object)component != (Object)null && (Object)(object)component.m_connectionPrefab != (Object)null) { _prefab = component.m_connectionPrefab; return _prefab; } } CorePlugin.Log.LogWarning((object)"NearbyChests found no station connection effect to borrow; materials are still taken from nearby containers, just without the beam."); return null; } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] public static class DoCraftingPatch { private enum Outcome { Nothing, Fetch, Short } private struct Withdrawal { public string Name; public int Quality; public int Amount; public int Carried; public int Fetched; } private struct Taking { public Container Container; public int Withdrawal; public int Amount; } private static readonly FieldRef<InventoryGui, Recipe> CraftRecipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe"); private static readonly FieldRef<InventoryGui, ItemData> CraftUpgradeItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem"); private static readonly FieldRef<InventoryGui, bool> MultiCrafting = AccessTools.FieldRefAccess<InventoryGui, bool>("m_multiCrafting"); private static readonly List<Withdrawal> Plan = new List<Withdrawal>(); private static readonly List<Taking> Taken = new List<Taking>(); private static readonly List<Container> From = new List<Container>(); private static readonly List<ItemData> Stacks = new List<ItemData>(); private static CraftingStation _station; private static bool Prefix(InventoryGui __instance, Player player) { Reset(); Recipe val = CraftRecipe.Invoke(__instance); CraftingStation val2 = NearbyContainers.Station(); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return true; } if (player.NoCostCheat() || ZoneSystem.instance.GetGlobalKey((GlobalKeys)25)) { return true; } ItemData val3 = CraftUpgradeItem.Invoke(__instance); int qualityLevel = ((val3 == null) ? 1 : (val3.m_quality + 1)); int multiplier = ((!MultiCrafting.Invoke(__instance)) ? 1 : __instance.m_multiCraftAmount); switch (Decide(player, val, val2, qualityLevel, multiplier)) { case Outcome.Nothing: Reset(); return true; case Outcome.Short: Reset(); ((Character)player).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false); return false; default: _station = val2; return Fetch(player); } } private static void Finalizer(Player player) { if (Taken.Count != 0 && !((Object)(object)player == (Object)null)) { int num = RollBack(player); if (num > 0) { CorePlugin.Log.LogInfo((object)($"NearbyChests: the craft did not go through, so {num} fetched " + "material(s) went back into the containers they came from")); } else { ShowConnections(); } Reset(); } } private static void Reset() { Plan.Clear(); Taken.Clear(); From.Clear(); _station = null; } private static Outcome Decide(Player player, Recipe recipe, CraftingStation station, int qualityLevel, int multiplier) { Inventory inventory = ((Humanoid)player).GetInventory(); bool requireOnlyOneIngredient = recipe.m_requireOnlyOneIngredient; bool flag = false; Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if ((Object)(object)val.m_resItem == (Object)null || station.m_upgrader != val.m_upgraderResource) { continue; } int num = val.GetAmount(qualityLevel) * multiplier; if (num <= 0) { continue; } flag = true; ItemData itemData = val.m_resItem.m_itemData; string name = itemData.m_shared.m_name; bool num2 = !requireOnlyOneIngredient; bool flag2 = false; int quality = -1; int num3 = -1; int num4 = 0; for (int j = (num2 ? 1 : 0); j <= itemData.m_shared.m_maxQuality; j++) { int num5 = inventory.CountItems(name, j, true); if (num5 >= num) { flag2 = true; break; } int num6 = num5 + NearbyContainers.CountIn(name, j, matchWorldLevel: true); if (num6 > num3) { num3 = num6; quality = j; num4 = num5; } if (requireOnlyOneIngredient && num6 >= num) { break; } } if (flag2) { if (requireOnlyOneIngredient) { return Outcome.Nothing; } continue; } if (num3 < num) { if (!requireOnlyOneIngredient) { return Outcome.Short; } continue; } Plan.Add(new Withdrawal { Name = name, Quality = quality, Amount = num - num4 }); if (requireOnlyOneIngredient) { return Outcome.Fetch; } } if (requireOnlyOneIngredient && flag) { return Outcome.Short; } if (Plan.Count <= 0) { return Outcome.Nothing; } return Outcome.Fetch; } private static bool Fetch(Player player) { Inventory inventory = ((Humanoid)player).GetInventory(); From.AddRange(NearbyContainers.Current()); for (int i = 0; i < Plan.Count; i++) { Withdrawal value = Plan[i]; value.Carried = inventory.CountItems(value.Name, -1, true); Plan[i] = value; } bool flag = true; for (int j = 0; j < Plan.Count; j++) { Withdrawal value2 = Plan[j]; int num = value2.Amount; for (int k = 0; k < From.Count; k++) { if (num <= 0) { break; } num -= TakeFrom(From[k], inventory, j, value2.Name, value2.Quality, num); } value2.Fetched = value2.Amount - num; Plan[j] = value2; if (num > 0) { flag = false; } } if (flag) { return true; } RollBack(player); Reset(); ((Character)player).Message((MessageType)2, "Not enough room in your inventory for the materials", 0, (Sprite)null, false); CorePlugin.Log.LogInfo((object)"NearbyChests: the materials would not fit in the player's inventory, so they went back into the containers and the craft was cancelled"); return false; } private static int TakeFrom(Container container, Inventory inventory, int withdrawal, string name, int quality, int wanted) { Inventory inventory2 = container.GetInventory(); Stacks.Clear(); inventory2.GetAllItems(name, Stacks); int num = 0; foreach (ItemData stack in Stacks) { if (num >= wanted) { break; } if (quality < 0 || stack.m_quality == quality) { if (!NearbyContainers.Claim(container)) { break; } num += Move(inventory2, inventory, stack, wanted - num); } } if (num > 0) { Taken.Add(new Taking { Container = container, Withdrawal = withdrawal, Amount = num }); } return num; } private static int RollBack(Player player) { Inventory inventory = ((Humanoid)player).GetInventory(); int num = 0; for (int i = 0; i < Plan.Count; i++) { Withdrawal withdrawal = Plan[i]; int num2 = Mathf.Min(withdrawal.Fetched, inventory.CountItems(withdrawal.Name, -1, true) - withdrawal.Carried); for (int j = 0; j < Taken.Count; j++) { if (num2 <= 0) { break; } if (Taken[j].Withdrawal == i) { int num3 = PutBack(inventory, Taken[j].Container, withdrawal.Name, withdrawal.Quality, Mathf.Min(num2, Taken[j].Amount)); num2 -= num3; num += num3; } } } return num; } private static int PutBack(Inventory inventory, Container container, string name, int quality, int amount) { if ((Object)(object)container == (Object)null || !NearbyContainers.Claim(container)) { return 0; } Inventory inventory2 = container.GetInventory(); Stacks.Clear(); inventory.GetAllItems(name, Stacks); int num = 0; foreach (ItemData stack in Stacks) { if (num >= amount) { break; } if (quality < 0 || stack.m_quality == quality) { num += Move(inventory, inventory2, stack, amount - num); } } return num; } private static void ShowConnections() { if ((Object)(object)_station == (Object)null) { return; } for (int i = 0; i < Taken.Count; i++) { if ((Object)(object)Taken[i].Container == (Object)null) { continue; } bool flag = false; for (int j = 0; j < i; j++) { if (flag) { break; } flag = (Object)(object)Taken[j].Container == (Object)(object)Taken[i].Container; } if (!flag) { ConnectionEffect.Play(_station, Taken[i].Container); } } } private static int Move(Inventory from, Inventory to, ItemData stack, int wanted) { int num = Mathf.Min(wanted, stack.m_stack); if (num <= 0) { return 0; } ItemData val = stack.Clone(); val.m_stack = num; int num2 = (to.AddItem(val) ? num : (num - val.m_stack)); if (num2 > 0) { from.RemoveItem(stack, num2); } return num2; } } [BepInPlugin("com.mysix.nearbychests", "MySix Nearby Chests", "1.0.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class NearbyChestsPlugin : BaseUnityPlugin { public const string PluginGuid = "com.mysix.nearbychests"; public const string PluginName = "MySix Nearby Chests"; public const string PluginVersion = "1.0.2"; private const int RequiredCoreApi = 1; private Harmony _harmony; private void Awake() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown if (CorePlugin.RequireApi("MySix Nearby Chests", 1)) { NearbyContainers.Enabled = Settings.Register<bool>("MySix Nearby Chests", ((BaseUnityPlugin)this).Config.Bind<bool>("NearbyChests", "Enabled", true, "Crafting and upgrading at a crafting station also uses materials from containers standing near it. Building with the hammer is unaffected and always takes materials from your own inventory."), (Scope)0, (string)null); NearbyContainers.Range = Settings.Register<float>("MySix Nearby Chests", ((BaseUnityPlugin)this).Config.Bind<float>("NearbyChests", "Range", 10f, "How far a container may stand from the crafting station, in metres. Large values cost a little performance, because every container in range is counted while the crafting menu is open."), (Scope)0, (string)null); ConnectionEffect.Show = Settings.Register<bool>("MySix Nearby Chests", ((BaseUnityPlugin)this).Config.Bind<bool>("NearbyChests", "ShowConnection", true, "Draw the station's own connection beam to each container it took materials from."), (Scope)1, (string)null); _harmony = new Harmony("com.mysix.nearbychests"); _harmony.PatchAll(typeof(NearbyChestsPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"MySix Nearby Chests 1.0.2 loaded"); } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class NearbyContainers { public static Setting<bool> Enabled; public static Setting<float> Range; private const float CacheSeconds = 0.25f; private static readonly List<Container> Usable = new List<Container>(); private static readonly List<Piece> Nearby = new List<Piece>(); private static readonly Comparison<Container> ByDistance = CompareByDistance; private static CraftingStation _station; private static float _range; private static float _at = float.NegativeInfinity; private static Vector3 _centre; private static readonly Func<Container, long, bool> CheckAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null), (object)null, true); private static readonly FieldRef<Container, ZNetView> NView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview"); public static CraftingStation Station() { if (Enabled == null || !Enabled.Value) { return null; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { return localPlayer.GetCurrentCraftingStation(); } return null; } public static List<Container> Current() { CraftingStation val = Station(); if ((Object)(object)val == (Object)null) { Usable.Clear(); _station = null; return Usable; } float num = Mathf.Max(0f, (Range != null) ? Range.Value : 10f); if ((Object)(object)val == (Object)(object)_station && num == _range && Time.unscaledTime - _at < 0.25f) { return Usable; } _station = val; _range = num; _at = Time.unscaledTime; Refresh(val, num); return Usable; } public static int CountIn(string sharedName, int quality, bool matchWorldLevel) { List<Container> list = Current(); int num = 0; for (int i = 0; i < list.Count; i++) { num += list[i].GetInventory().CountItems(sharedName, quality, matchWorldLevel); } return num; } public static bool Claim(Container container) { ZNetView val = NView.Invoke(container); if (!val.IsOwner()) { val.ClaimOwnership(); } return val.IsOwner(); } private static void Refresh(CraftingStation station, float range) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) Usable.Clear(); Nearby.Clear(); _centre = ((Component)station).transform.position; Piece.GetAllPiecesInRadius(_centre, range, Nearby); long playerID = Game.instance.GetPlayerProfile().GetPlayerID(); for (int i = 0; i < Nearby.Count; i++) { Container component = ((Component)Nearby[i]).GetComponent<Container>(); if ((Object)(object)component != (Object)null && MayTakeFrom(component, playerID)) { Usable.Add(component); } } Usable.Sort(ByDistance); } private static bool MayTakeFrom(Container container, long playerId) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) ZNetView val = NView.Invoke(container); if ((Object)(object)val == (Object)null || !val.IsValid()) { return false; } if (container.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false)) { return false; } if (!CheckAccess(container, playerId)) { return false; } return val.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 0; } private static int CompareByDistance(Container a, Container b) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)a).transform.position - _centre; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; val = ((Component)b).transform.position - _centre; return sqrMagnitude.CompareTo(((Vector3)(ref val)).sqrMagnitude); } } public static class RequirementCounting { private static readonly MethodInfo CountItems = AccessTools.Method(typeof(Inventory), "CountItems", new Type[3] { typeof(string), typeof(int), typeof(bool) }, (Type[])null); public static int CountForCrafting(Inventory inventory, string sharedName, int quality, bool matchWorldLevel) { int num = inventory.CountItems(sharedName, quality, matchWorldLevel); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || inventory != ((Humanoid)localPlayer).GetInventory()) { return num; } return num + NearbyContainers.CountIn(sharedName, quality, matchWorldLevel); } public static int CountForRequirementRow(Inventory inventory, string sharedName, int quality, bool matchWorldLevel) { if (!SetupRequirementListPatch.Drawing) { return inventory.CountItems(sharedName, quality, matchWorldLevel); } return CountForCrafting(inventory, sharedName, quality, matchWorldLevel); } public static IEnumerable<CodeInstruction> Redirect(IEnumerable<CodeInstruction> instructions, MethodInfo replacement, string where) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], CountItems)) { list[i] = new CodeInstruction(OpCodes.Call, (object)replacement) { labels = list[i].labels, blocks = list[i].blocks }; num++; } } if (num == 1) { return list; } CorePlugin.Log.LogError((object)($"NearbyChests could not patch {where} (found {num} item counts, expected 1). " + "Crafting will only see your own inventory.")); return instructions; } } [HarmonyPatch(typeof(Player), "HaveRequirementItems")] public static class HaveRequirementItemsPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { return RequirementCounting.Redirect(instructions, AccessTools.Method(typeof(RequirementCounting), "CountForCrafting", (Type[])null, (Type[])null), "Player.HaveRequirementItems"); } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] public static class SetupRequirementPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { return RequirementCounting.Redirect(instructions, AccessTools.Method(typeof(RequirementCounting), "CountForRequirementRow", (Type[])null, (Type[])null), "InventoryGui.SetupRequirement"); } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirementList")] public static class SetupRequirementListPatch { public static bool Drawing { get; private set; } private static void Prefix() { Drawing = true; } private static void Finalizer() { Drawing = false; } } }