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 ChestReach v0.1.0
ChestReach.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace ChestReach; [BepInPlugin("j1ga.chestreach", "ChestReach", "0.1.0")] public class ChestReachPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] private static class Player_HaveRequirements_Piece_Patch { private static void Postfix(Player __instance, Piece piece, RequirementMode mode, ref bool __result) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors) { return; } try { instance.AfterHavePieceRequirements(__instance, piece, mode, ref __result); } catch (Exception e) { instance.Fail("Player.HaveRequirements(Piece)", e); } } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] private static class Player_TryPlacePiece_Patch { private static bool Prefix(Player __instance, Piece piece, ref bool __result) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors) { return true; } try { if (instance.BeforeTryPlacePiece(__instance, piece)) { return true; } __result = false; return false; } catch (Exception e) { instance.Fail("Player.TryPlacePiece", e); instance._consume = null; __result = false; return false; } } private static void Postfix(bool __result) { ChestReachPlugin instance = Instance; if ((Object)(object)instance != (Object)null && !__result) { instance._consume = null; } } } [HarmonyPatch(typeof(Player), "UpdatePlacement")] private static class Player_UpdatePlacement_Patch { private static void Prefix() { ChestReachPlugin instance = Instance; if ((Object)(object)instance != (Object)null) { instance._consume = null; } } private static Exception Finalizer(Exception __exception) { ChestReachPlugin instance = Instance; if ((Object)(object)instance != (Object)null) { instance._consume = null; } return __exception; } } private sealed class ConsumeContext { public List<Box> Boxes; } [HarmonyPatch(typeof(Player), "HaveRequirementItems")] private static class Player_HaveRequirementItems_Patch { private static void Postfix(Player __instance, Recipe piece, bool discover, int qualityLevel, int amount, ref bool __result) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors) { return; } try { instance.AfterHaveRequirementItems(__instance, piece, discover, qualityLevel, amount, ref __result); } catch (Exception e) { instance.Fail("Player.HaveRequirementItems", e); } } } [HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")] private static class InventoryGui_OnCraftPressed_Patch { private static void Postfix(InventoryGui __instance) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors) { return; } try { instance.AfterCraftPressed(__instance); } catch (Exception e) { instance.Fail("InventoryGui.OnCraftPressed", e); } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] private static class InventoryGui_DoCrafting_Patch { private static bool Prefix(InventoryGui __instance, Player player) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors) { return true; } try { return instance.BeforeDoCrafting(__instance, player); } catch (Exception e) { instance.Fail("InventoryGui.DoCrafting", e); instance._consume = null; instance._craftHold = false; return false; } } private static Exception Finalizer(Exception __exception) { ChestReachPlugin instance = Instance; if ((Object)(object)instance != (Object)null) { instance._consume = null; } return __exception; } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] private static class InventoryGui_UpdateRecipe_Patch { private static void Postfix(InventoryGui __instance) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || !instance._craftHold) { return; } try { _craftTimer.SetValue(__instance, 1000f); } catch (Exception e) { instance.Fail("InventoryGui.UpdateRecipe", e); } } } [HarmonyPatch(typeof(InventoryGui), "Hide")] private static class InventoryGui_Hide_Patch { private static void Postfix() { ChestReachPlugin instance = Instance; if (!((Object)(object)instance == (Object)null)) { instance._craftHold = false; instance._craftHoldStart = -1f; } } } [HarmonyPatch(typeof(Player), "ConsumeResources")] private static class Player_ConsumeResources_Patch { private static void Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._consume == null) { return; } try { instance.BeforeConsume(__instance, requirements, qualityLevel, itemQuality, multiplier); } catch (Exception e) { instance.Fail("Player.ConsumeResources", e); } } } internal sealed class Box { public Container C; public Inventory Inv; public ZNetView View; public Piece Piece; public string Prefab; public bool Tomb; public bool Cart; public bool Ship; public bool World; public bool Dirty = true; public int WorldLevel = int.MinValue; public readonly Dictionary<string, int> Counts = new Dictionary<string, int>(); public bool Alive { get { if ((Object)(object)C != (Object)null && (Object)(object)View != (Object)null) { return View.IsValid(); } return false; } } public bool Owned { get { if (Alive) { return View.IsOwner(); } return false; } } public Vector3 Pos => ((Component)C).transform.position; public int Count(string name) { if (Dirty || WorldLevel != Game.m_worldLevel) { Recount(); } if (!Counts.TryGetValue(name, out var value)) { return 0; } return value; } public void Recount() { Counts.Clear(); Dirty = false; WorldLevel = Game.m_worldLevel; if (Inv == null) { return; } foreach (ItemData allItem in Inv.GetAllItems()) { if (allItem != null && allItem.m_shared != null && allItem.m_worldLevel >= Game.m_worldLevel) { Counts.TryGetValue(allItem.m_shared.m_name, out var value); Counts[allItem.m_shared.m_name] = value + allItem.m_stack; } } } } internal sealed class Stock { public Vector3 Center; public float Range; public int Version; public float Time; public readonly List<Box> Boxes = new List<Box>(); public readonly Dictionary<string, int> Total = new Dictionary<string, int>(); public int Count(string name) { if (!Total.TryGetValue(name, out var value)) { return 0; } return value; } } [HarmonyPatch(typeof(Container), "Awake")] private static class Container_Awake_Patch { private static void Postfix(Container __instance) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors) { return; } try { instance.Register(__instance); } catch (Exception e) { instance.Fail("Container.Awake", e); } } } internal enum Own { Ready, Pending, Failed } private sealed class Request { public Box B; public float Sent; public bool Granted; public bool Denied; public bool Manual; } [HarmonyPatch(typeof(Container), "RPC_OpenResponse")] private static class Container_RPC_OpenResponse_Patch { private static bool Prefix(Container __instance, bool granted) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null) { return true; } try { if (!instance._requests.TryGetValue(__instance, out var value)) { return true; } if (granted) { value.Granted = true; } else { value.Denied = true; } return value.Manual || instance.OpenedByHand(__instance); } catch (Exception e) { instance.Fail("Container.RPC_OpenResponse", e); return true; } } } [HarmonyPatch(typeof(Container), "Interact")] private static class Container_Interact_Patch { private static void Prefix(Container __instance, bool hold) { ChestReachPlugin instance = Instance; if (!((Object)(object)instance == (Object)null) && !hold) { instance._manualAt[__instance] = Time.time; if (instance._requests.TryGetValue(__instance, out var value)) { value.Manual = true; } } } } [HarmonyPatch(typeof(InventoryGui), "RepairOneItem")] private static class InventoryGui_RepairOneItem_Patch { private static bool Prefix(InventoryGui __instance) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors) { return true; } try { return instance.BeforeRepairOne(__instance); } catch (Exception e) { instance.Fail("InventoryGui.RepairOneItem", e); instance._repairingAll = false; return true; } } } private sealed class Fetched { public Box B; public string Name; public int After; } private sealed class StationRetry { public Box B; public Action Run; public float Until; } [HarmonyPatch(typeof(Fireplace), "Interact")] private static class Fireplace_Interact_Patch { private static bool Prefix(Fireplace __instance, Humanoid user, bool hold, bool alt, ref bool __result, out Fetched __state) { __state = null; ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || hold || !instance.StationsOn(instance._cfgRefuel)) { return true; } try { if (!__instance.m_canRefill || __instance.m_infiniteFuel || (Object)(object)__instance.m_fuelItem == (Object)null) { return true; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || component.GetZDO() == null) { return true; } float num = component.GetZDO().GetFloat(ZDOVars.s_fuel, 0f); if (__instance.m_canTurnOff && !alt && num > 0f) { return true; } if ((float)Mathf.CeilToInt(num) >= __instance.m_maxFuel) { return true; } Fireplace fp = __instance; Humanoid u = user; bool a = alt; if (instance.BeforeStation(user, (Component)(object)__instance, Names(__instance.m_fuelItem), delegate { fp.Interact(u, false, a); }, out __state)) { return true; } __result = false; return false; } catch (Exception e) { instance.Fail("Fireplace.Interact", e); return true; } } private static void Postfix(Humanoid user, Fetched __state) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || __state == null) { return; } try { instance.AfterStation(user, __state); } catch (Exception e) { instance.Fail("Fireplace.Interact", e); } } } [HarmonyPatch(typeof(Smelter), "OnAddFuel")] private static class Smelter_OnAddFuel_Patch { private static bool Prefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result, out Fetched __state) { __state = null; ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || item != null || !instance.StationsOn(instance._cfgRefuel)) { return true; } try { Smelter sm = __instance; Humanoid u = user; if (instance.BeforeStation(user, (Component)(object)__instance, Names(__instance.m_fuelItem), delegate { _smelterAddFuel.Invoke(sm, new object[3] { sw, u, null }); }, out __state)) { return true; } __result = false; return false; } catch (Exception e) { instance.Fail("Smelter.OnAddFuel", e); return true; } } private static void Postfix(Humanoid user, Fetched __state) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || __state == null) { return; } try { instance.AfterStation(user, __state); } catch (Exception e) { instance.Fail("Smelter.OnAddFuel", e); } } } [HarmonyPatch(typeof(Smelter), "OnAddOre")] private static class Smelter_OnAddOre_Patch { private static bool Prefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result, out Fetched __state) { __state = null; ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || item != null || !instance.StationsOn(instance._cfgLoad)) { return true; } try { List<string> list = new List<string>(); foreach (ItemConversion item2 in __instance.m_conversion) { if (item2 != null && (Object)(object)item2.m_from != (Object)null && !list.Contains(item2.m_from.m_itemData.m_shared.m_name)) { list.Add(item2.m_from.m_itemData.m_shared.m_name); } } Smelter sm = __instance; Switch s = sw; Humanoid u = user; if (instance.BeforeStation(user, (Component)(object)__instance, list, delegate { _smelterAddOre.Invoke(sm, new object[3] { s, u, null }); }, out __state)) { return true; } __result = false; return false; } catch (Exception e) { instance.Fail("Smelter.OnAddOre", e); return true; } } private static void Postfix(Humanoid user, Fetched __state) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || __state == null) { return; } try { instance.AfterStation(user, __state); } catch (Exception e) { instance.Fail("Smelter.OnAddOre", e); } } } [HarmonyPatch(typeof(CookingStation), "OnAddFuelSwitch")] private static class CookingStation_OnAddFuelSwitch_Patch { private static bool Prefix(CookingStation __instance, Switch sw, Humanoid user, ItemData item, ref bool __result, out Fetched __state) { __state = null; ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || item != null || !instance.StationsOn(instance._cfgRefuel) || !__instance.m_useFuel) { return true; } try { CookingStation cs = __instance; Humanoid u = user; if (instance.BeforeStation(user, (Component)(object)__instance, Names(__instance.m_fuelItem), delegate { _cookingAddFuel.Invoke(cs, new object[3] { sw, u, null }); }, out __state)) { return true; } __result = false; return false; } catch (Exception e) { instance.Fail("CookingStation.OnAddFuelSwitch", e); return true; } } private static void Postfix(Humanoid user, Fetched __state) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || __state == null) { return; } try { instance.AfterStation(user, __state); } catch (Exception e) { instance.Fail("CookingStation.OnAddFuelSwitch", e); } } } [HarmonyPatch(typeof(CookingStation), "OnInteract")] private static class CookingStation_OnInteract_Patch { private static bool Prefix(CookingStation __instance, Humanoid user, ref bool __result, out Fetched __state) { __state = null; ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || !instance.StationsOn(instance._cfgCook)) { return true; } try { if ((bool)_cookingHaveDone.Invoke(__instance, null)) { return true; } List<string> list = new List<string>(); foreach (ItemConversion item in __instance.m_conversion) { if (item != null && (Object)(object)item.m_from != (Object)null && !list.Contains(item.m_from.m_itemData.m_shared.m_name)) { list.Add(item.m_from.m_itemData.m_shared.m_name); } } CookingStation cs = __instance; Humanoid u = user; if (instance.BeforeStation(user, (Component)(object)__instance, list, delegate { _cookingInteract.Invoke(cs, new object[1] { u }); }, out __state)) { return true; } __result = false; return false; } catch (Exception e) { instance.Fail("CookingStation.OnInteract", e); return true; } } private static void Postfix(Humanoid user, Fetched __state) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || __state == null) { return; } try { instance.AfterStation(user, __state); } catch (Exception e) { instance.Fail("CookingStation.OnInteract", e); } } } [HarmonyPatch(typeof(Fermenter), "Interact")] private static class Fermenter_Interact_Patch { private static bool Prefix(Fermenter __instance, Humanoid user, bool hold, ref bool __result, out Fetched __state) { __state = null; ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || hold || !instance.StationsOn(instance._cfgCook)) { return true; } try { if (Convert.ToInt32(_fermenterStatus.Invoke(__instance, null)) != 0) { return true; } List<string> list = new List<string>(); foreach (ItemConversion item in __instance.m_conversion) { if (item != null && (Object)(object)item.m_from != (Object)null && !list.Contains(item.m_from.m_itemData.m_shared.m_name)) { list.Add(item.m_from.m_itemData.m_shared.m_name); } } Fermenter f = __instance; Humanoid u = user; if (instance.BeforeStation(user, (Component)(object)__instance, list, delegate { f.Interact(u, false, false); }, out __state)) { return true; } __result = false; return false; } catch (Exception e) { instance.Fail("Fermenter.Interact", e); return true; } } private static void Postfix(Humanoid user, Fetched __state) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || __state == null) { return; } try { instance.AfterStation(user, __state); } catch (Exception e) { instance.Fail("Fermenter.Interact", e); } } } [HarmonyPatch(typeof(ShieldGenerator), "OnAddFuel")] private static class ShieldGenerator_OnAddFuel_Patch { private static bool Prefix(ShieldGenerator __instance, Switch sw, Humanoid user, ItemData item, ref bool __result, out Fetched __state) { __state = null; ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || item != null || !instance.StationsOn(instance._cfgRefuel)) { return true; } try { ShieldGenerator sg = __instance; Humanoid u = user; if (instance.BeforeStation(user, (Component)(object)__instance, Names((IEnumerable<ItemDrop>)__instance.m_fuelItems), delegate { _shieldAddFuel.Invoke(sg, new object[3] { sw, u, null }); }, out __state)) { return true; } __result = false; return false; } catch (Exception e) { instance.Fail("ShieldGenerator.OnAddFuel", e); return true; } } private static void Postfix(Humanoid user, Fetched __state) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || __state == null) { return; } try { instance.AfterStation(user, __state); } catch (Exception e) { instance.Fail("ShieldGenerator.OnAddFuel", e); } } } [HarmonyPatch(typeof(Turret), "UseItem")] private static class Turret_UseItem_Patch { private static bool Prefix(Turret __instance, Humanoid user, ItemData item, ref bool __result, out Fetched __state) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) __state = null; ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || item != null || !instance.StationsOn(instance._cfgRefuel)) { return true; } try { List<string> list = new List<string>(); if (__instance.GetAmmo() > 0 && (Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab(__instance.GetAmmoType()); ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val != (Object)null) { list.Add(val.m_itemData.m_shared.m_name); } } else { foreach (AmmoType item2 in __instance.m_allowedAmmo) { if ((Object)(object)item2.m_ammo != (Object)null && !list.Contains(item2.m_ammo.m_itemData.m_shared.m_name)) { list.Add(item2.m_ammo.m_itemData.m_shared.m_name); } } } Turret t = __instance; Humanoid u = user; if (instance.BeforeStation(user, (Component)(object)__instance, list, delegate { t.UseItem(u, (ItemData)null); }, out __state)) { return true; } __result = false; return false; } catch (Exception e) { instance.Fail("Turret.UseItem", e); return true; } } private static void Postfix(Humanoid user, Fetched __state) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || __state == null) { return; } try { instance.AfterStation(user, __state); } catch (Exception e) { instance.Fail("Turret.UseItem", e); } } } [HarmonyPatch(typeof(ZNet), "Awake")] private static class ZNet_Awake_Patch { private static void Postfix() { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null) { return; } try { instance.RegisterRpc(); } catch (Exception e) { instance.Fail("ZNet.Awake", e); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private static class ZNet_RPC_PeerInfo_Patch { private static void Postfix(ZNet __instance, ZRpc rpc) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors) { return; } try { instance.OnPeerInfo(__instance, rpc); } catch (Exception e) { instance.Fail("ZNet.RPC_PeerInfo", e); } } } [HarmonyPatch(typeof(ZNet), "OnDestroy")] private static class ZNet_OnDestroy_Patch { private static void Postfix() { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null) { return; } try { ((MonoBehaviour)instance).StopAllCoroutines(); instance.ResetWorld(); } catch (Exception e) { instance.Fail("ZNet.OnDestroy", e); } } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] private static class InventoryGui_SetupRequirement_Patch { private static void Postfix(Transform elementRoot, Requirement req, Player player, int quality, int craftMultiplier, bool __result) { ChestReachPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors || !__result) { return; } try { instance.AfterSetupRequirement(elementRoot, req, player, quality, craftMultiplier); } catch (Exception e) { instance.Fail("InventoryGui.SetupRequirement", e); } } } [HarmonyPatch(typeof(Hud), "SetupPieceInfo")] private static class Hud_SetupPieceInfo_Patch { private static void Prefix() { ChestReachPlugin instance = Instance; if ((Object)(object)instance != (Object)null) { instance._rowsForBuild = true; } } private static Exception Finalizer(Exception __exception) { ChestReachPlugin instance = Instance; if ((Object)(object)instance != (Object)null) { instance._rowsForBuild = false; } return __exception; } } private const float PrefetchInterval = 0.5f; private const float PrefetchRepeat = 5f; private const float MaxRange = 50f; private const float CraftWait = 4f; public const string Guid = "j1ga.chestreach"; public const string Name = "ChestReach"; public const string Version = "0.1.0"; private const int MaxErrors = 25; private const float RequestTimeout = 3f; private const float RefusedPause = 5f; private const int RepairsPerFrame = 3; private const string RpcName = "j1ga.chestreach.config"; private const int PacketVersion = 1; private float _nextPrefetch; private readonly Dictionary<Box, float> _prefetched = new Dictionary<Box, float>(); private ConfigEntry<bool> _cfgEnabled; private ConfigEntry<bool> _cfgDebug; private ConfigEntry<bool> _cfgCraft; private ConfigEntry<float> _cfgCraftRange; private ConfigEntry<bool> _cfgBuild; private ConfigEntry<float> _cfgBuildRange; private ConfigEntry<bool> _cfgRefuel; private ConfigEntry<bool> _cfgLoad; private ConfigEntry<bool> _cfgCook; private ConfigEntry<float> _cfgStationRange; private ConfigEntry<bool> _cfgCarts; private ConfigEntry<bool> _cfgShips; private ConfigEntry<bool> _cfgDungeon; private ConfigEntry<bool> _cfgWardAll; private ConfigEntry<string> _cfgExcluded; private ConfigEntry<bool> _cfgRepairAll; private ConfigEntry<bool> _cfgAreaRepair; private ConfigEntry<KeyboardShortcut> _cfgAreaRepairKey; private ConfigEntry<float> _cfgAreaRepairRadius; private ConfigEntry<bool> _cfgShowTotal; private ConfigEntry<bool> _cfgShowTaken; private ConfigEntry<bool> _cfgTooltip; private ConfigEntry<Color> _cfgCoveredColor; private ConfigEntry<bool> _cfgSync; private readonly List<ConfigEntryBase> _synced = new List<ConfigEntryBase>(); private readonly HashSet<string> _excluded = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private readonly HashSet<string> _serverExcluded = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly Color CoveredDefault = new Color(0.3f, 0.72f, 1f, 1f); private static readonly Color CoveredDefaultV1 = new Color(0.62f, 0.83f, 1f, 1f); private ConsumeContext _consume; private bool _craftHold; private float _craftHoldStart = -1f; public static ChestReachPlugin Instance; private Harmony _harmony; private int _errorCount; private bool _disabledByErrors; private readonly HashSet<string> _loggedErrors = new HashSet<string>(); private string _lastMessage; private float _lastMessageTime; private static readonly Dictionary<string, string[]> Texts = new Dictionary<string, string[]> { { "fetching", new string[2] { "Taking materials from the chests nearby... press again", "Беру материалы из сундуков рядом... нажмите ещё раз" } }, { "waiting", new string[2] { "Waiting for the chests nearby...", "Жду сундуки рядом..." } }, { "busy", new string[2] { "A chest nearby is in use or did not answer", "Сундук рядом занят или не ответил" } }, { "short", new string[2] { "Not enough in the chests nearby: {0}", "Не хватает в сундуках рядом: {0}" } }, { "invfull", new string[2] { "No room in the inventory for {0}", "Нет места в инвентаре для {0}" } }, { "repaired", new string[2] { "Items repaired: {0}", "Починено предметов: {0}" } }, { "area", new string[2] { "Pieces repaired: {0}", "Починено построек: {0}" } }, { "area_none", new string[2] { "Nothing to repair nearby", "Рядом нечего чинить" } }, { "area_station", new string[2] { "; {0} need a crafting station that reaches you", "; {0} требуют станцию, достающую до вас" } }, { "taken", new string[2] { "From the chests: {0}", "Из сундуков: {0}" } }, { "tooltip", new string[2] { "In inventory: {0} · In chests nearby: {1}", "В инвентаре: {0} · В сундуках рядом: {1}" } } }; private readonly List<Box> _boxes = new List<Box>(); private readonly Dictionary<Container, Box> _byContainer = new Dictionary<Container, Box>(); private readonly List<Stock> _stocks = new List<Stock>(); private int _indexVersion; private static FieldInfo _containerView; private static MethodInfo _containerLoad; private static FieldInfo _craftRecipe; private static FieldInfo _craftUpgradeItem; private static FieldInfo _multiCrafting; private static FieldInfo _craftTimer; private static FieldInfo _knownStations; private static MethodInfo _haveRepairable; private static MethodInfo _repairOne; private static MethodInfo _smelterAddOre; private static MethodInfo _smelterAddFuel; private static MethodInfo _cookingInteract; private static MethodInfo _cookingAddFuel; private static MethodInfo _cookingHaveDone; private static MethodInfo _fermenterStatus; private static MethodInfo _shieldAddFuel; private readonly Dictionary<Container, Request> _requests = new Dictionary<Container, Request>(); private readonly Dictionary<Box, float> _refusedUntil = new Dictionary<Box, float>(); private readonly Dictionary<Container, float> _manualAt = new Dictionary<Container, float>(); private bool _repairingAll; private readonly Queue<WearNTear> _repairQueue = new Queue<WearNTear>(); private int _repairDone; private int _repairNoStation; private StationRetry _stationRetry; private bool _serverSynced; private readonly Dictionary<ConfigEntryBase, object> _serverValues = new Dictionary<ConfigEntryBase, object>(); private bool _syncDirty; private bool _rowsForBuild; private HashSet<string> Excluded { get { if (!_serverSynced || !_serverValues.ContainsKey((ConfigEntryBase)(object)_cfgExcluded)) { return _excluded; } return _serverExcluded; } } private float CraftRange => Mathf.Clamp(Eff<float>(_cfgCraftRange), 1f, 50f); private float BuildRange => Mathf.Clamp(Eff<float>(_cfgBuildRange), 1f, 50f); private float StationRange => Mathf.Clamp(Eff<float>(_cfgStationRange), 1f, 50f); private bool CraftOn { get { if (Ready) { return Eff<bool>(_cfgCraft); } return false; } } private bool BuildOn { get { if (Ready) { return Eff<bool>(_cfgBuild); } return false; } } private bool Ready { get { if (!_disabledByErrors) { return Eff<bool>(_cfgEnabled); } return false; } } private int PendingRequests => _requests.Count; private bool BuildFree(Player p, Piece piece) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (p.NoCostCheat()) { return true; } ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance != (Object)null) { return instance.GetGlobalKey(piece.FreeBuildKey()); } return false; } private void AfterHavePieceRequirements(Player player, Piece piece, RequirementMode mode, ref bool result) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Invalid comparison between Unknown and I4 if (result || (Object)(object)piece == (Object)null || (int)mode == 1 || !IsLocal((Humanoid)(object)player) || !BuildOn) { return; } if ((Object)(object)piece.m_craftingStation != (Object)null) { if ((int)mode == 2) { if (!(_knownStations.GetValue(player) is Dictionary<string, int> dictionary) || !dictionary.ContainsKey(piece.m_craftingStation.m_name)) { return; } } else if (!Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)player).transform.position)) && ((Object)(object)ZoneSystem.instance == (Object)null || !ZoneSystem.instance.GetGlobalKey((GlobalKeys)27))) { return; } } if (piece.m_dlc.Length > 0 && ((Object)(object)DLCMan.instance == (Object)null || !DLCMan.instance.IsDLCInstalled(piece.m_dlc))) { return; } Stock stock = GetStock(((Component)player).transform.position, BuildRange); if (stock.Boxes.Count == 0) { return; } Inventory inventory = ((Humanoid)player).GetInventory(); Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (val == null || (Object)(object)val.m_resItem == (Object)null || val.m_amount <= 0) { continue; } string name = val.m_resItem.m_itemData.m_shared.m_name; if ((int)mode == 2) { if (!inventory.HaveItem(name, true) && stock.Count(name) <= 0) { return; } } else if (inventory.CountItems(name, -1, true) + stock.Count(name) < val.m_amount) { return; } } result = true; } private bool BeforeTryPlacePiece(Player p, Piece piece) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) _consume = null; if (!IsLocal((Humanoid)(object)p) || !BuildOn || (Object)(object)piece == (Object)null || BuildFree(p, piece)) { return true; } Dictionary<string, int> dictionary = Deficits(p, PieceNeeds(piece)); if (dictionary.Count == 0) { return true; } Stock s = GetStock(((Component)p).transform.position, BuildRange); HashSet<Box> hashSet = new HashSet<Box>(); for (int i = 0; i < 3; i++) { List<Box> list = Plan(s, dictionary, hashSet); if (list == null) { Tell((hashSet.Count > 0) ? T("busy") : T("short", Shortfall(dictionary, s))); return false; } switch (AcquireAll(list, hashSet)) { case Own.Pending: Tell(T("fetching")); return false; case Own.Failed: continue; } if (!LiveCovers(list, dictionary)) { s = BuildStock(((Component)p).transform.position, BuildRange); continue; } ConsumeContext consumeContext = new ConsumeContext(); consumeContext.Boxes = list; _consume = consumeContext; return true; } Tell(T("busy")); return false; } private void UpdateBuildPrefetch() { //IL_008f: Unknown result type (might be due to invalid IL or missing references) if (Time.time < _nextPrefetch) { return; } _nextPrefetch = Time.time + 0.5f; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !BuildOn || !((Character)localPlayer).InPlaceMode() || localPlayer.InRepairMode()) { return; } Piece selectedPiece = localPlayer.GetSelectedPiece(); if ((Object)(object)selectedPiece == (Object)null || selectedPiece.m_repairPiece || selectedPiece.m_removePiece || BuildFree(localPlayer, selectedPiece)) { return; } Dictionary<string, int> dictionary = Deficits(localPlayer, PieceNeeds(selectedPiece)); if (dictionary.Count == 0) { return; } Stock stock = GetStock(((Component)localPlayer).transform.position, BuildRange); List<Box> list = Plan(stock, dictionary, null); if (list == null) { return; } if (_prefetched.Count > 64) { _prefetched.Clear(); } foreach (Box item in list) { if (!item.Owned && (!_prefetched.TryGetValue(item, out var value) || !(Time.time - value < 5f))) { _prefetched[item] = Time.time; Acquire(item); } } } private void RegisterCommands() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand("chestreach", "ChestReach. 'chestreach status' shows the settings in effect and the chests around you", (ConsoleEvent)delegate(ConsoleEventArgs args) { RunCommand(args); }, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static void Say(ConsoleEventArgs args, string text) { if (args != null && (Object)(object)args.Context != (Object)null) { args.Context.AddString(text); } } private void RunCommand(ConsoleEventArgs args) { try { string text = ((args.Args.Length > 1) ? args.Args[1].ToLowerInvariant() : ""); if (text == "status") { Say(args, StatusText()); } else { Say(args, "chestreach status"); } } catch (Exception ex) { Say(args, "chestreach: " + ex.Message); Fail("command", ex); } } private static string OnOff(bool v) { if (!v) { return "off"; } return "on"; } private string StatusValues() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("enabled ").Append(OnOff(Eff<bool>(_cfgEnabled))).Append("; crafting ") .Append(OnOff(Eff<bool>(_cfgCraft))) .Append(" ") .Append(F(CraftRange)) .Append(" m") .Append("; building ") .Append(OnOff(Eff<bool>(_cfgBuild))) .Append(" ") .Append(F(BuildRange)) .Append(" m") .Append("; stations ") .Append(F(StationRange)) .Append(" m: refuel ") .Append(OnOff(Eff<bool>(_cfgRefuel))) .Append(", ore ") .Append(OnOff(Eff<bool>(_cfgLoad))) .Append(", cook ") .Append(OnOff(Eff<bool>(_cfgCook))) .Append("; carts ") .Append(OnOff(Eff<bool>(_cfgCarts))) .Append(", ships ") .Append(OnOff(Eff<bool>(_cfgShips))) .Append(", world chests ") .Append(OnOff(Eff<bool>(_cfgDungeon))) .Append(", ward for all ") .Append(OnOff(Eff<bool>(_cfgWardAll))) .Append("; excluded ") .Append(Excluded.Count) .Append("; repair all ") .Append(OnOff(Eff<bool>(_cfgRepairAll))) .Append(", area repair ") .Append(OnOff(Eff<bool>(_cfgAreaRepair))) .Append(" ") .Append(F(Eff<float>(_cfgAreaRepairRadius))) .Append(" m."); return stringBuilder.ToString(); } private string StatusText() { //IL_0092: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("ChestReach").Append(" ").Append("0.1.0") .Append(_disabledByErrors ? " - DISABLED after errors, see the log" : "") .Append('\n'); stringBuilder.Append(_serverSynced ? "Settings from the server: " : "Local settings: ").Append(StatusValues()).Append('\n'); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { Prune(); Stock stock = BuildStock(((Component)localPlayer).transform.position, BuildRange); int num = 0; foreach (Box box in stock.Boxes) { if (box.Owned) { num++; } } stringBuilder.Append("Chests loaded: ").Append(_boxes.Count).Append("; within ") .Append(F(BuildRange)) .Append(" m of you and usable: ") .Append(stock.Boxes.Count) .Append(" (yours now: ") .Append(num) .Append("), ") .Append(stock.Total.Count) .Append(" kinds of items") .Append("; requests in flight: ") .Append(PendingRequests) .Append('.'); } return stringBuilder.ToString(); } private ConfigEntry<T> Synced<T>(ConfigEntry<T> e) { _synced.Add((ConfigEntryBase)(object)e); return e; } private ConfigEntry<float> Range(string section, string what) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown return Synced<float>(((BaseUnityPlugin)this).Config.Bind<float>(section, "RangeMeters", 20f, new ConfigDescription(what, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), new object[0]))); } private void BindConfig() { //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Expected O, but got Unknown //IL_0365: Unknown result type (might be due to invalid IL or missing references) _cfgEnabled = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("01 General", "Enabled", true, "Master switch. Off: crafting, building, stations and repair are vanilla.")); _cfgDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("01 General", "Debug", false, "Log every chest request and every take."); _cfgCraft = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("02 Crafting", "Enabled", true, "Craft and upgrade with materials from the chests around the crafting station (around you when crafting by hand). Your inventory is used first.")); _cfgCraftRange = Range("02 Crafting", "Chests up to this far from the crafting station count."); _cfgBuild = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("03 Building", "Enabled", true, "Build with materials from the chests around you: hammer, hoe, cultivator. Your inventory is used first.")); _cfgBuildRange = Range("03 Building", "Chests up to this far from you count."); _cfgRefuel = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("04 Stations", "Refuel", true, "With nothing to put in in your inventory, take one fuel item from a chest: fires, torches and lamps, smelter and oven fuel, the shield generator, ballista ammo.")); _cfgLoad = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("04 Stations", "LoadOre", true, "The same for what smelters process: ore into the smelter and furnace, wood into the charcoal kiln, flax and barley into the spinning wheel and windmill, sap into the eitr refinery.")); _cfgCook = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("04 Stations", "Cook", true, "The same for food: cooking stations, the oven, and mead bases into the fermenter.")); _cfgStationRange = Range("04 Stations", "Chests up to this far from the station count."); _cfgCarts = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("05 Chests", "IncludeCarts", true, "Take from carts.")); _cfgShips = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("05 Chests", "IncludeShips", true, "Take from the storage of ships.")); _cfgDungeon = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("05 Chests", "IncludeWorldChests", true, "Take from chests the world placed (dungeons, villages), not only from those built by players.")); _cfgWardAll = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("05 Chests", "RequireWardAccess", false, "Require access to the ward for every chest. The game asks it only of the chests that check wards; those are always respected.")); _cfgExcluded = Synced<string>(((BaseUnityPlugin)this).Config.Bind<string>("05 Chests", "ExcludedPrefabs", "", "Chest prefabs never taken from, comma separated. Example: piece_chest_private,piece_chest_blackmetal")); _cfgExcluded.SettingChanged += delegate { ReadExcluded(); }; ReadExcluded(); _cfgRepairAll = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("06 Repair", "RepairAll", true, "One press of the repair button at a station repairs every item it can, not one.")); _cfgAreaRepair = Synced<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("06 Repair", "AreaRepair", true, "The key below repairs the damaged buildings around you, as the hammer would one by one: wards and the crafting station a piece needs are respected, nothing is spent.")); _cfgAreaRepairKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("06 Repair", "AreaRepairKey", new KeyboardShortcut((KeyCode)59, (KeyCode[])(object)new KeyCode[0]), "Key for the area repair. Ignored while typing or in a menu."); _cfgAreaRepairRadius = Synced<float>(((BaseUnityPlugin)this).Config.Bind<float>("06 Repair", "AreaRepairRadius", 50f, new ConfigDescription("Radius of the area repair, meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), new object[0]))); _cfgShowTotal = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Display", "ShowAvailableAmount", true, "A material in a recipe or a piece reads 'available/needed': what you carry plus what is in the chests nearby, over what it takes. Off: only the amount needed, as in vanilla."); _cfgShowTaken = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Display", "ShowTakenMessage", true, "After a craft or a placement, a line in the top-left message log says what was taken from the chests."); _cfgTooltip = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Display", "ShowCountsInTooltip", true, "The tooltip of a material in a recipe or a piece tells how many you carry and how many are in the chests nearby."); _cfgCoveredColor = ((BaseUnityPlugin)this).Config.Bind<Color>("07 Display", "CoveredColor", CoveredDefault, "Colour of a material amount that your inventory alone does not cover but the chests nearby do."); _cfgSync = ((BaseUnityPlugin)this).Config.Bind<bool>("08 Sync", "SyncConfig", true, "The server sends its settings of sections 01-06 (except the key) to every connecting client with the mod and again when they change; the client uses them while connected. Players without the mod are never affected. Off on the server: every client uses its own file. Has no effect on a client."); MigrateConfig(); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { _syncDirty = true; }; } private void MigrateConfig() { //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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) Color value = _cfgCoveredColor.Value; if (Mathf.Abs(value.r - CoveredDefaultV1.r) < 0.01f && Mathf.Abs(value.g - CoveredDefaultV1.g) < 0.01f && Mathf.Abs(value.b - CoveredDefaultV1.b) < 0.01f) { _cfgCoveredColor.Value = CoveredDefault; } } private void ReadExcluded() { ReadList(_cfgExcluded.Value, _excluded); _indexVersion++; } private static void ReadList(string text, HashSet<string> into) { into.Clear(); if (string.IsNullOrEmpty(text)) { return; } string[] array = text.Split(',', ';'); foreach (string text2 in array) { string text3 = text2.Trim(); if (text3.Length > 0) { into.Add(text3); } } } private T Eff<T>(ConfigEntry<T> e) { if (_serverSynced && _serverValues.TryGetValue((ConfigEntryBase)(object)e, out var value) && value is T) { return (T)value; } return e.Value; } private static bool Counts(Requirement req, CraftingStation station) { if (req == null || (Object)(object)req.m_resItem == (Object)null) { return false; } if ((Object)(object)station != (Object)null && station.m_upgrader != req.m_upgraderResource) { return false; } if ((Object)(object)station == (Object)null && req.m_upgraderResource) { return false; } return true; } private static Dictionary<string, int> Needs(Player p, Requirement[] reqs, int quality, int multiplier) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); if (reqs == null) { return dictionary; } CraftingStation currentCraftingStation = p.GetCurrentCraftingStation(); foreach (Requirement val in reqs) { if (Counts(val, currentCraftingStation)) { int num = val.GetAmount(quality) * multiplier; if (num > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; dictionary.TryGetValue(name, out var value); dictionary[name] = value + num; } } } return dictionary; } private static Dictionary<string, int> PieceNeeds(Piece piece) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); if ((Object)(object)piece == (Object)null || piece.m_resources == null) { return dictionary; } Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (val != null && !((Object)(object)val.m_resItem == (Object)null) && val.m_amount > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; dictionary.TryGetValue(name, out var value); dictionary[name] = value + val.m_amount; } } return dictionary; } private static Dictionary<string, int> Deficits(Player p, Dictionary<string, int> need) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); Inventory inventory = ((Humanoid)p).GetInventory(); foreach (KeyValuePair<string, int> item in need) { int num = item.Value - inventory.CountItems(item.Key, -1, true); if (num > 0) { dictionary[item.Key] = num; } } return dictionary; } private static Vector3 CraftCenter(Player p) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) CraftingStation currentCraftingStation = p.GetCurrentCraftingStation(); if (!((Object)(object)currentCraftingStation != (Object)null)) { return ((Component)p).transform.position; } return ((Component)currentCraftingStation).transform.position; } private bool CraftFree(Player p) { if (!p.NoCostCheat()) { if ((Object)(object)ZoneSystem.instance != (Object)null) { return ZoneSystem.instance.GetGlobalKey((GlobalKeys)25); } return false; } return true; } private void CraftJob(InventoryGui gui, Player p, out Recipe recipe, out Dictionary<string, int> deficits) { object? value = _craftRecipe.GetValue(gui); recipe = (Recipe)((value is Recipe) ? value : null); deficits = null; if (!((Object)(object)recipe == (Object)null)) { object? value2 = _craftUpgradeItem.GetValue(gui); ItemData val = (ItemData)((value2 is ItemData) ? value2 : null); int quality = ((val == null) ? 1 : (val.m_quality + 1)); int multiplier = ((!(bool)_multiCrafting.GetValue(gui)) ? 1 : Math.Max(1, gui.m_multiCraftAmount)); if (!recipe.m_requireOnlyOneIngredient) { deficits = Deficits(p, Needs(p, recipe.m_resources, quality, multiplier)); } } } private void AfterHaveRequirementItems(Player player, Recipe recipe, bool discover, int quality, int amount, ref bool result) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (result || discover || (Object)(object)recipe == (Object)null || recipe.m_requireOnlyOneIngredient || !IsLocal((Humanoid)(object)player) || !CraftOn) { return; } Stock stock = GetStock(CraftCenter(player), CraftRange); if (stock.Boxes.Count == 0) { return; } Inventory inventory = ((Humanoid)player).GetInventory(); CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if (!Counts(val, currentCraftingStation)) { continue; } int num = val.GetAmount(quality) * amount; if (num > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; if (inventory.CountItems(name, -1, true) + stock.Count(name) < num) { return; } } } result = true; } private void AfterCraftPressed(InventoryGui gui) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !CraftOn || CraftFree(localPlayer)) { return; } CraftJob(gui, localPlayer, out var _, out var deficits); if (deficits != null && deficits.Count != 0) { Stock stock = GetStock(CraftCenter(localPlayer), CraftRange); List<Box> list = Plan(stock, deficits, null); if (list != null) { AcquireAll(list, null); } } } private bool BeforeDoCrafting(InventoryGui gui, Player p) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) _craftHold = false; _consume = null; if (!IsLocal((Humanoid)(object)p) || !CraftOn || CraftFree(p)) { return true; } CraftJob(gui, p, out var _, out var deficits); if (deficits == null || deficits.Count == 0) { _craftHoldStart = -1f; return true; } Stock s = GetStock(CraftCenter(p), CraftRange); HashSet<Box> hashSet = new HashSet<Box>(); for (int i = 0; i < 3; i++) { List<Box> list = Plan(s, deficits, hashSet); if (list == null) { _craftHoldStart = -1f; Tell((hashSet.Count > 0) ? T("busy") : T("short", Shortfall(deficits, s))); return hashSet.Count == 0; } switch (AcquireAll(list, hashSet)) { case Own.Pending: if (_craftHoldStart < 0f) { _craftHoldStart = Time.time; } if (Time.time - _craftHoldStart > 4f) { _craftHoldStart = -1f; Tell(T("busy")); return false; } _craftHold = true; return false; default: { if (!LiveCovers(list, deficits)) { s = BuildStock(CraftCenter(p), CraftRange); break; } _craftHoldStart = -1f; ConsumeContext consumeContext = new ConsumeContext(); consumeContext.Boxes = list; _consume = consumeContext; return true; } case Own.Failed: break; } } _craftHoldStart = -1f; Tell(T("busy")); return false; } private void BeforeConsume(Player p, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier) { ConsumeContext consume = _consume; if (consume == null || !IsLocal((Humanoid)(object)p) || requirements == null) { return; } _consume = null; Inventory inventory = ((Humanoid)p).GetInventory(); CraftingStation currentCraftingStation = p.GetCurrentCraftingStation(); List<string> list = new List<string>(); foreach (Requirement val in requirements) { if (!Counts(val, currentCraftingStation)) { continue; } int num = val.GetAmount(qualityLevel) * multiplier; if (num <= 0) { continue; } string name = val.m_resItem.m_itemData.m_shared.m_name; int num2 = num - inventory.CountItems(name, itemQuality, true); if (num2 > 0) { int num3 = Take(consume.Boxes, name, num2); if (num3 > 0) { list.Add(ItemName(name) + " x" + num3); } if (num3 < num2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Took " + num3 + " of " + num2 + " " + name + " from the chests; the rest was not there any more.")); } } } if (list.Count > 0 && _cfgShowTaken.Value) { ((Character)p).Message((MessageType)1, T("taken", string.Join(", ", list.ToArray())), 0, (Sprite)null, false); } } private void Awake() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown try { Instance = this; BindConfig(); FindReflection(); RegisterCommands(); _harmony = new Harmony("j1ga.chestreach"); _harmony.PatchAll(typeof(ChestReachPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"ChestReach 0.1.0 loaded."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Awake failed, mod is inert: " + ex)); _disabledByErrors = true; } } private void Update() { if (_disabledByErrors) { return; } try { if (_syncDirty) { FlushSync(); } if (!((Object)(object)Player.m_localPlayer == (Object)null)) { UpdateOwnership(); UpdateStationRetry(); UpdateBuildPrefetch(); UpdateAreaRepair(); } } catch (Exception e) { Fail("Update", e); } } private void OnDestroy() { try { ((MonoBehaviour)this).StopAllCoroutines(); if (_harmony != null) { _harmony.UnpatchSelf(); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("OnDestroy: " + ex.Message)); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void ResetWorld() { ClearIndex(); ClearOwnership(); ClearServerValues(); _consume = null; _craftHold = false; _stationRetry = null; _repairQueue.Clear(); } private static bool IsLocal(Humanoid h) { if ((Object)(object)h != (Object)null) { return (Object)(object)h == (Object)(object)Player.m_localPlayer; } return false; } private static long MyPlayerId() { Game instance = Game.instance; if (!((Object)(object)instance != (Object)null) || instance.GetPlayerProfile() == null) { return 0L; } return instance.GetPlayerProfile().GetPlayerID(); } private static string PrefabName(GameObject go) { if ((Object)(object)go == (Object)null) { return ""; } string name = ((Object)go).name; int num = name.IndexOf("(Clone)", StringComparison.Ordinal); if (num <= 0) { return name; } return name.Substring(0, num); } private static string F(float v) { return v.ToString("0.##", CultureInfo.InvariantCulture); } private void Debug(string text) { if (_cfgDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)text); } } private void Tell(string text) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !string.IsNullOrEmpty(text) && (!(text == _lastMessage) || !(Time.time - _lastMessageTime < 1f))) { _lastMessage = text; _lastMessageTime = Time.time; ((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } private void Fail(string where, Exception e) { string text = where + ": " + e.GetType().Name + ": " + e.Message; if (_loggedErrors.Add(text)) { ((BaseUnityPlugin)this).Logger.LogError((object)(text + "\n" + e.StackTrace)); } if (++_errorCount >= 25 && !_disabledByErrors) { _disabledByErrors = true; _consume = null; ((BaseUnityPlugin)this).Logger.LogError((object)"Too many errors, ChestReach is now inert until the game restarts."); } } private static bool Russian() { Localization instance = Localization.instance; if (instance != null) { return instance.GetSelectedLanguage() == "Russian"; } return false; } private static string T(string key, params object[] args) { if (!Texts.TryGetValue(key, out var value)) { return key; } string text = (Russian() ? value[1] : value[0]); if (args == null || args.Length <= 0) { return text; } return string.Format(text, args); } private static string ItemName(string sharedName) { Localization instance = Localization.instance; if (instance == null) { return sharedName; } return instance.Localize(sharedName); } private void FindReflection() { _containerView = AccessTools.Field(typeof(Container), "m_nview"); _containerLoad = AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null); _craftRecipe = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe"); _craftUpgradeItem = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem"); _multiCrafting = AccessTools.Field(typeof(InventoryGui), "m_multiCrafting"); _craftTimer = AccessTools.Field(typeof(InventoryGui), "m_craftTimer"); _knownStations = AccessTools.Field(typeof(Player), "m_knownStations"); _haveRepairable = AccessTools.Method(typeof(InventoryGui), "HaveRepairableItems", (Type[])null, (Type[])null); _repairOne = AccessTools.Method(typeof(InventoryGui), "RepairOneItem", (Type[])null, (Type[])null); _smelterAddOre = AccessTools.Method(typeof(Smelter), "OnAddOre", (Type[])null, (Type[])null); _smelterAddFuel = AccessTools.Method(typeof(Smelter), "OnAddFuel", (Type[])null, (Type[])null); _cookingInteract = AccessTools.Method(typeof(CookingStation), "OnInteract", (Type[])null, (Type[])null); _cookingAddFuel = AccessTools.Method(typeof(CookingStation), "OnAddFuelSwitch", (Type[])null, (Type[])null); _cookingHaveDone = AccessTools.Method(typeof(CookingStation), "HaveDoneItem", (Type[])null, (Type[])null); _fermenterStatus = AccessTools.Method(typeof(Fermenter), "GetStatus", (Type[])null, (Type[])null); _shieldAddFuel = AccessTools.Method(typeof(ShieldGenerator), "OnAddFuel", (Type[])null, (Type[])null); if (_containerView == null || _containerLoad == null) { throw new MissingMemberException("Container.m_nview / Container.Load not found: the game has changed, ChestReach cannot work."); } } private void Register(Container c) { if ((Object)(object)c == (Object)null || _byContainer.ContainsKey(c)) { return; } Inventory inventory = c.GetInventory(); object? value = _containerView.GetValue(c); ZNetView val = (ZNetView)((value is ZNetView) ? value : null); if (inventory != null && !((Object)(object)val == (Object)null) && val.GetZDO() != null) { Box b = new Box(); b.C = c; b.Inv = inventory; b.View = val; b.Piece = ((Component)c).GetComponent<Piece>(); b.Prefab = PrefabName(((Component)val).gameObject); b.Tomb = (Object)(object)((Component)c).GetComponent<TombStone>() != (Object)null; b.Cart = (Object)(object)c.m_wagon != (Object)null || (Object)(object)((Component)c).GetComponentInParent<Vagon>() != (Object)null; b.Ship = (Object)(object)((Component)c).GetComponentInParent<Ship>() != (Object)null; b.World = !b.Cart && !b.Ship && ((Object)(object)b.Piece == (Object)null || !b.Piece.IsPlacedByPlayer()); inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, (Action)delegate { b.Dirty = true; _indexVersion++; }); _boxes.Add(b); _byContainer[c] = b; _indexVersion++; } } private Box BoxOf(Container c) { if (!((Object)(object)c != (Object)null) || !_byContainer.TryGetValue(c, out var value)) { return null; } return value; } private void Prune() { for (int num = _boxes.Count - 1; num >= 0; num--) { Box box = _boxes[num]; if (!box.Alive) { _boxes.RemoveAt(num); if (!object.ReferenceEquals(box.C, null)) { _byContainer.Remove(box.C); } _indexVersion++; } } if (_byContainer.Count == _boxes.Count) { return; } _byContainer.Clear(); foreach (Box box2 in _boxes) { _byContainer[box2.C] = box2; } } private void ClearIndex() { _boxes.Clear(); _byContainer.Clear(); _stocks.Clear(); _indexVersion++; } private bool Eligible(Box b, long me) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Invalid comparison between Unknown and I4 //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (!b.Alive) { return false; } if (b.Tomb) { return false; } if (b.Cart && !Eff<bool>(_cfgCarts)) { return false; } if (b.Ship && !Eff<bool>(_cfgShips)) { return false; } if (b.World && !Eff<bool>(_cfgDungeon)) { return false; } if (Excluded.Contains(b.Prefab)) { return false; } Container c = b.C; if ((int)c.m_privacy == 0 && ((Object)(object)b.Piece == (Object)null || b.Piece.GetCreator() != me)) { return false; } if ((int)c.m_privacy == 1) { return false; } if ((c.m_checkGuardStone || Eff<bool>(_cfgWardAll)) && !PrivateArea.CheckAccess(b.Pos, 0f, false, false)) { return false; } if (!b.View.IsOwner()) { ZDO zDO = b.View.GetZDO(); if (zDO == null || zDO.GetInt(ZDOVars.s_inUse, 0) == 1) { return false; } if ((Object)(object)c.m_wagon != (Object)null && c.m_wagon.InUse()) { return false; } } return true; } private Stock GetStock(Vector3 center, float range) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_0049: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; for (int i = 0; i < _stocks.Count; i++) { Stock stock = _stocks[i]; if (stock.Version == _indexVersion && stock.Range == range && time - stock.Time < 1f) { Vector3 val = stock.Center - center; if (((Vector3)(ref val)).sqrMagnitude < 0.25f) { return stock; } } } Stock stock2 = BuildStock(center, range); if (_stocks.Count >= 8) { _stocks.RemoveAt(0); } _stocks.Add(stock2); return stock2; } private Stock BuildStock(Vector3 center, float range) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) Prune(); Stock stock = new Stock(); stock.Center = center; stock.Range = range; stock.Version = _indexVersion; stock.Time = Time.time; long me = MyPlayerId(); float num = range * range; List<KeyValuePair<float, Box>> list = new List<KeyValuePair<float, Box>>(); foreach (Box box in _boxes) { Vector3 val = box.Pos - center; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude > num) && Eligible(box, me)) { list.Add(new KeyValuePair<float, Box>(sqrMagnitude, box)); } } list.Sort((KeyValuePair<float, Box> a, KeyValuePair<float, Box> z) => a.Key.CompareTo(z.Key)); foreach (KeyValuePair<float, Box> item in list) { Box value = item.Value; stock.Boxes.Add(value); if (value.Dirty || value.WorldLevel != Game.m_worldLevel) { value.Recount(); } foreach (KeyValuePair<string, int> count in value.Counts) { stock.Total.TryGetValue(count.Key, out var value2); stock.Total[count.Key] = value2 + count.Value; } } return stock; } private static List<Box> Plan(Stock s, Dictionary<string, int> deficits, HashSet<Box> skip) { Dictionary<string, int> dictionary = new Dictionary<string, int>(deficits); List<string> list = new List<string>(deficits.Keys); List<Box> list2 = new List<Box>(); int num = 0; foreach (int value in dictionary.Values) { num += Math.Max(0, value); } if (num == 0) { return list2; } for (int i = 0; i < 2; i++) { foreach (Box box in s.Boxes) { if (!box.Alive || (skip != null && skip.Contains(box)) || i == 0 != box.Owned) { continue; } bool flag = false; foreach (string item in list) { int num2 = dictionary[item]; if (num2 > 0) { int num3 = box.Count(item); if (num3 > 0) { int num4 = Math.Min(num2, num3); dictionary[item] = num2 - num4; num -= num4; flag = true; } } } if (flag) { list2.Add(box); } if (num <= 0) { return list2; } } } return null; } private static bool LiveCovers(List<Box> plan, Dictionary<string, int> deficits) { foreach (KeyValuePair<string, int> deficit in deficits) { if (deficit.Value <= 0) { continue; } int num = 0; foreach (Box item in plan) { if (item.Owned) { num += item.Inv.CountItems(deficit.Key, -1, true); if (num >= deficit.Value) { break; } } } if (num < deficit.Value) { return false; } } return true; } private int Take(List<Box> boxes, string name, int amount) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (Box box in boxes) { if (amount - num <= 0) { break; } if (box.Owned) { int num2 = box.Inv.CountItems(name, -1, true); if (num2 > 0) { int num3 = Math.Min(num2, amount - num); box.Inv.RemoveItem(name, num3, -1, true); num += num3; Debug("took " + num3 + " " + name + " from " + box.Prefab + " at " + Pos(box.Pos)); } } } return num; } private static string Pos(Vector3 p) { return "(" + F(p.x) + ", " + F(p.y) + ", " + F(p.z) + ")"; } private static string Shortfall(Dictionary<string, int> deficits, Stock s) { List<string> list = new List<string>(); foreach (KeyValuePair<string, int> deficit in deficits) { int num = deficit.Value - s.Count(deficit.Key); if (num > 0) { list.Add(ItemName(deficit.Key) + " x" + num); } } return string.Join(", ", list.ToArray()); } private bool OpenedByHand(Container c) { if (_manualAt.TryGetValue(c, out var value)) { return Time.time - value < 2f; } return false; } private Own Acquire(Box b) { //IL_015e: Unknown result type (might be due to invalid IL or missing references) if (b == null || !b.Alive) { return Own.Failed; } _requests.TryGetValue(b.C, out var value); if (b.View.IsOwner()) { if (value != null) { _requests.Remove(b.C); Reload(b); } return Own.Ready; } if (value != null) { if (!value.Denied) { return Own.Pending; } return Own.Failed; } if (OpenedByHand(b.C)) { return Own.Pending; } if (_refusedUntil.TryGetValue(b, out var value2)) { if (Time.time < value2) { return Own.Failed; } _refusedUntil.Remove(b); } ZDO zDO = b.View.GetZDO(); if (zDO == null) { return Own.Failed; } if (zDO.GetOwner() == 0) { b.View.ClaimOwnership(); if (b.View.IsOwner()) { Reload(b); return Own.Ready; } } value = new Request(); value.B = b; value.Sent = Time.time; _requests[b.C] = value; b.View.InvokeRPC("RPC_RequestOpen", new object[1] { MyPlayerId() }); Debug("asked owner " + zDO.GetOwner() + " for " + b.Prefab + " at " + Pos(b.Pos)); return Own.Pending; } private void Reload(Box b) { try { _containerLoad.Invoke(b.C, null); } catch (Exception e) { Fail("Container.Load", e); } b.Dirty = true; _indexVersion++; } private void UpdateOwnership() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) if (_manualAt.Count > 32) { _manualAt.Clear(); } if (_requests.Count == 0) { return; } List<Container> list = null; foreach (KeyValuePair<Container, Request> request in _requests) { Request value = request.Value; Box b = value.B; bool flag = false; if (!b.Alive) { flag = true; } else if (b.View.IsOwner()) { Reload(b); Debug("got " + b.Prefab + " at " + Pos(b.Pos) + " after " + F(Time.time - value.Sent) + " s"); flag = true; } else if (value.Denied || Time.time - value.Sent > 3f) { _refusedUntil[b] = Time.time + 5f; Debug((value.Denied ? "refused: " : "no answer: ") + b.Prefab + " at " + Pos(b.Pos)); flag = true; } if (flag) { if (list == null) { list = new List<Container>(); } list.Add(request.Key); } } if (list == null) { return; } foreach (Container item in list) { _requests.Remove(item); } } private void ClearOwnership() { _requests.Clear(); _refusedUntil.Clear(); _manualAt.Clear(); } private Own AcquireAll(List<Box> plan, HashSet<Box> failed) { Own own = Own.Ready; foreach (Box item in plan) { switch (Acquire(item)) { case Own.Failed: failed?.Add(item); own = Own.Failed; break; case Own.Pending: if (own == Own.Ready) { own = Own.Pending; } break; } } return own; } private bool BeforeRepairOne(InventoryGui gui) { if (_repairingAll || !Ready || !Eff<bool>(_cfgRepairAll)) { return true; } int i = 0; _repairingAll = true; try { for (; i < 200; i++) { if (!(bool)_haveRepairable.Invoke(gui, null)) { break; } _repairOne.Invoke(gui, null); } } finally { _repairingAll = false; } if (i == 0) { return true; } if (i > 1) { Tell(T("repaired", i)); } return false; } private static bool Typing() { if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible() && !Minimap.InTextInput() && !StoreGui.IsVisible()) { if ((Object)(object)Hud.instance != (Object)null && (Object)(object)Hud.instance.m_buildUi != (Object)null) { return Hud.instance.m_buildUi.SearchFieldFocused; } return false; } return true; } private void UpdateAreaRepair() { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if (_repairQueue.Count > 0) { for (int i = 0; i < 3; i++) { if (_repairQueue.Count <= 0) { break; } WearNTear val = _repairQueue.Dequeue(); if (!((Object)(object)val == (Object)null) && val.Repair()) { _repairDone++; Piece component = ((Component)val).GetComponent<Piece>(); if ((Object)(object)component != (Object)null && component.m_placeEffect != null) { component.m_placeEffect.Create(((Component)val).transform.position, ((Component)val).transform.rotation, (Transform)null, 1f, -1, default(ZDOID)); } } } if (_repairQueue.Count == 0) { ReportAreaRepair(); } } else if (Ready && Eff<bool>(_cfgAreaRepair) && !Typing()) { KeyboardShortcut value = _cfgAreaRepairKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { StartAreaRepair(); } } } private void StartAreaRepair() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } float num = Mathf.Clamp(Eff<float>(_cfgAreaRepairRadius), 1f, 100f); float num2 = num * num; Vector3 position = ((Component)localPlayer).transform.position; bool flag = (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)27); _repairDone = 0; _repairNoStation = 0; List<KeyValuePair<float, WearNTear>> list = new List<KeyValuePair<float, WearNTear>>(); Dictionary<string, bool> dictionary = new Dictionary<string, bool>(); foreach (WearNTear allInstance in WearNTear.GetAllInstances()) { if ((Object)(object)allInstance == (Object)null) { continue; } Vector3 position2 = ((Component)allInstance).transform.position; Vector3 val = position2 - position; if (((Vector3)(ref val)).sqrMagnitude > num2) { continue; } Piece component = ((Component)allInstance).GetComponent<Piece>(); if ((Object)(object)component == (Object)null || !component.IsPlacedByPlayer()) { continue; } ZNetView component2 = ((Component)allInstance).GetComponent<ZNetView>(); if ((Object)(object)component2 == (Object)null || component2.GetZDO() == null || component2.GetZDO().GetFloat(ZDOVars.s_health, allInstance.m_health) >= allInstance.m_health || !PrivateArea.CheckAccess(position2, 0f, false, false)) { continue; } if ((Object)(object)component.m_craftingStation != (Object)null && !flag) { string name = component.m_craftingStation.m_name; if (!dictionary.TryGetValue(name, out var value)) { value = (dictionary[name] = (Object)(object)CraftingStation.HaveBuildStationInRange(name, position) != (Object)null); } if (!value) { _repairNoStation++; continue; } } Vector3 val2 = position2 - position; list.Add(new KeyValuePair<float, WearNTear>(((Vector3)(ref val2)).sqrMagnitude, allInstance)); } list.Sort((KeyValuePair<float, WearNTear> a, KeyValuePair<float, WearNTear> z) => a.Key.CompareTo(z.Key)); foreach (KeyValuePair<float, WearNTear> item in list) { _repairQueue.Enqueue(item.Value); } if (_repairQueue.Count == 0) { ReportAreaRepair(); } } private void ReportAreaRepair() { string text = ((_repairDone > 0) ? T("area", _repairDone) : T("area_none")); if (_repairNoStation > 0) { text += T("area_station", _repairNoStation); } Tell(text); } private bool StationsOn(ConfigEntry<bool> kind) { if (Ready) { return Eff<bool>(kind); } return false; } private bool BeforeStation(Humanoid user, Component station, List<string> wanted, Action retry, out Fetched fetched) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) fetched = null; if (!IsLocal(user) || (Object)(object)station == (Object)null || wanted == null || wanted.Count == 0) { return true; } Inventory inventory = user.GetInventory(); if (inventory == null) { return true; } foreach (string item in wanted) { if (inventory.HaveItem(item, true)) { return true; } } Stock stock = GetStock(station.transform.position, StationRange); if (stock.Boxes.Count == 0) { return true; } string text = null; foreach (string item2 in wanted) { if (stock.Count(item2) > 0) { text = item2; break; } } if (text == null) { return true; } Box box = null; for (int i = 0; i < 2; i++) { if (box != null) { break; } foreach (Box box2 in stock.Boxes) { if (i == 0 == box2.Owned && box2.Count(text) > 0) { box = box2; break; } } } if (box == null) { return true; } switch (Acquire(box)) { case Own.Pending: { StationRetry stationRetry = new StationRetry(); stationRetry.B = box; stationRetry.Run = retry; stationRetry.Until = Time.time + 3f + 0.5f; _stationRetry = stationRetry; return false; } case Own.Failed: Tell(T("busy")); return false; default: { ItemData val = FirstUsable(box.Inv, text); if (val == null) { return true; } ItemData val2 = val.Clone(); val2.m_stack = 1; if (!inventory.AddItem(val2)) { Tell(T("invfull", ItemName(text))); return false; } box.Inv.RemoveItem(val, 1); fetched = new Fetched(); fetched.B = box; fetched.Name = text; fetched.After = inventory.CountItems(text, -1, true); Debug("fetched 1 " + text + " from " + box.Prefab + " for " + PrefabName(station.gameObject)); return true; } } } private void AfterStation(Humanoid user, Fetched f) { if (f == null || (Object)(object)user == (Object)null) { return; } Inventory inventory = user.GetInventory(); if (inventory == null || inventory.CountItems(f.Name, -1, true) < f.After || !f.B.Owned) { return; } ItemData val = FirstUsable(inventory, f.Name); if (val != null) { ItemData val2 = val.Clone(); val2.m_stack = 1; if (f.B.Inv.AddItem(val2)) { inventory.RemoveItem(val, 1); Debug("returned 1 " + f.Name + " to " + f.B.Prefab); } } } private static ItemData FirstUsable(Inventory inv, string name) { foreach (ItemData allItem in inv.GetAllItems()) { if (allItem != null && allItem.m_shared.m_name == name && allItem.m_worldLevel >= Game.m_worldLevel && allItem.m_stack > 0) { return allItem; } } return null; } private void UpdateStationRetry() { StationRetry stationRetry = _stationRetry; if (stationRetry == null) { return; } Own own = Acquire(stationRetry.B); if (own == Own.Pending && Time.time < stationRetry.Until) { return; } _stationRetry = null; if (own == Own.Ready) { try { if (stationRetry.Run != null) { stationRetry.Run(); } return; } catch (Exception e) { Fail("station retry", e); return; } } Tell(T("busy")); } private static List<string> Names(ItemDrop single) { List<string> list = new List<string>(); if ((Object)(object)single != (Object)null) { list.Add(single.m_itemData.m_shared.m_name); } return list; } private static List<string> Names(IEnumerable<ItemDrop> items) { List<string> list = new List<string>(); if (items == null) { return list; } foreach (ItemDrop item in items) { if ((Object)(object)item != (Object)null && !list.Contains(item.m_itemData.m_shared.m_name)) { list.Add(item.m_itemData.m_shared.m_name); } } return list; } private void RegisterRpc() { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.Register<ZPackage>("j1ga.chestreach.config", (Action<long, ZPackage>)OnConfigPacket); } } private void FlushSync() { _syncDirty = false; _indexVersion++; ZNet instance = ZNet.instance; if (!((Object)(object)instance == (Object)null) && instance.IsServer() && _cfgSync.Value && ZRoutedRpc.instance != null && instance.GetPeers().Count != 0) { SendConfig(0L); Debug("settings sent to " + instance.GetPeers().Count + " peers"); } } private ZPackage BuildPacket() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(_synced.Count); foreach (ConfigEntryBase item in _synced) { val.Write(item.Definition.Section + "/" + item.Definition.Key); val.Write(item.GetSerializedValue()); } return val; } private void SendConfig(long target) { ZRoutedRpc.instance.InvokeRoutedRPC(target, "j1ga.chestreach.config", new object[1] { BuildPacket() }); } private void OnPeerInfo(ZNet znet, ZRpc rpc) { if (!znet.IsServer() || !_cfgSync.Value || rpc == null) { return; } foreach (ZNetPeer peer in znet.GetPeers()) { if (peer != null && peer.m_rpc == rpc) { if (peer.m_uid != 0) { ((MonoBehaviour)this).StartCoroutine(SendConfigLater(peer.m_uid)); } break; } } } private IEnumerator SendConfigLater(long uid) { yield return (object)new WaitForSeconds(1f); ZNet znet = ZNet.instance; if ((Object)(object)znet == (Object)null || !znet.IsServer() || ZRoutedRpc.instance == null || !_cfgSync.Value) { yield break; } ZNetPeer peer = znet.GetPeer(uid); if (peer != null) { try { SendConfig(uid); Debug("settings sent to " + peer.m_playerName); } catch (Exception e) { Fail("send config", e); } } } private void OnConfigPacket(long sender, ZPackage pkg) { try { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || instance.IsServer() || pkg == null) { return; } ZNetPeer serverPeer = instance.GetServerPeer(); if (serverPeer == null || sender != serverPeer.m_uid) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Settings packet from peer " + sender + ", which is not the server; ignored.")); return; } int num = pkg.ReadInt(); if (num != 1) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("The server runs a ChestReach with packet version " + num + ", this one understands " + 1 + "; using the local settings.")); return; } Dictionary<string, ConfigEntryBase> dictionary = new Dictionary<string, ConfigEntryBase>(); foreach (ConfigEntryBase item in _synced) { dictionary[item.Definition.Section + "/" + item.Definition.Key] = item; } int num2 = pkg.ReadInt(); if (num2 < 0 || num2 > 1000) { return; } Dictionary<ConfigEntryBase, object> dictionary2 = new Dictionary<ConfigEntryBase, object>(); for (int i = 0; i < num2; i++) { string text = pkg.ReadString(); string text2 = pkg.ReadString(); if (dictionary.TryGetValue(text, out var value)) { try { dictionary2[value] = TomlTypeConverter.ConvertToValue(text2, value.SettingType); } catch (Exception) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Server setting " + text + " = '" + text2 + "' could not be read; the local value applies.")); } } } _serverValues.Clear(); foreach (KeyValuePair<ConfigEntryBase, object> item2 in dictionary2) { _serverValues[item2.Key] = item2.Value; } ReadList(_serverValues.TryGetValue((ConfigEntryBase)(object)_cfgExcluded, out var value2) ? (value2 as string) : "", _serverExcluded); _serverSynced = true; _indexVersion++; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Settings from the server: " + StatusValues())); } catch (Exception e) { Fail("config packet", e); } } private void ClearServerValues() { _serverSynced = false; _serverValues.Clear(); _serverExcluded.Clear(); } private void AfterSetupRequirement(Transform root, Requirement req, Player player, int quality, int multiplier) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)root == (Object)null || req == null || (Object)(object)req.m_resItem == (Object)null || !IsLocal((Humanoid)(object)player)) { return; } bool rowsForBuild = _rowsForBuild; if (rowsForBuild ? (!BuildOn) : (!CraftOn)) { return; } int num = req.GetAmount(quality) * multiplier; if (num <= 0) { return; } string name = req.m_resItem.m_itemData.m_shared.m_name; int num2 = ((Humanoid)player).GetInventory().CountItems(name, -1, true); Stock stock = (rowsForBuild ? GetStock(((Component)player).transform.position, BuildRange) : GetStock(CraftCenter(player), CraftRange)); int num3 = stock.Count(name); Transform val = root.Find("res_amount"); TMP_Text val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<TMP_Text>() : null); if ((Object)(object)val2 != (Object)null) { if (_cfgShowTotal.Value) { FitOnOneLine(val2); val2.text = Short(num2 + num3) + "/" + num; } if (num2 < num && num2 + num3 >= num) { ((Graphic)val2).color = _cfgCoveredColor.Value; } } if (_cfgTooltip.Value && num3 > 0) { UITooltip component = ((Component)root).GetComponent<UITooltip>(); if ((Object)(object)component != (Object)null) { component.m_text = (component.m_text ?? "") + "\n" + T("tooltip", num2, num3); } } } private static void FitOnOneLine(TMP_Text text) { if (!text.enableAutoSizing) { float fontSize = text.fontSize; text.textWrappingMode = (TextWrappingModes)0; text.fontSizeMax = fontSize; text.fontSizeMin = Mathf.Max(6f, fontSize * 0.6f); text.enableAutoSizing = true; } } private static string Short(int n) { if (n < 10000) { return n.ToString(); } if (n < 1000000) { return n / 1000 + "k"; } return n / 1000000 + "M"; } }