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 Quads Feed From Chests v1.8.4
plugins/FeedFromChests.dll
Decompiled 6 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using DHack.Shared; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI (Claude Code).")] [assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace FeedFromChests { internal class AutoSetting { public bool On; public readonly HashSet<string> Allowed = new HashSet<string>(); public int Reserve = 20; public int FuelReserve; public bool Output = true; public bool TakeOff = true; public int Target; public string Encode() { return (On ? "1" : "0") + ";" + string.Join(",", Allowed.ToArray()) + ";" + (Output ? "1" : "0") + ";" + Reserve + ";" + FuelReserve + ";" + (TakeOff ? "1" : "0") + ";" + Target; } public static AutoSetting Parse(string text) { AutoSetting autoSetting = new AutoSetting(); if (string.IsNullOrEmpty(text)) { return autoSetting; } string[] array = text.Split(new char[1] { ';' }); autoSetting.On = array[0] == "1"; if (array.Length > 1) { string[] array2 = array[1].Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string item in array2) { autoSetting.Allowed.Add(item); } } if (array.Length > 2) { autoSetting.Output = array[2] != "0"; } if (array.Length > 3 && int.TryParse(array[3], out var result)) { autoSetting.Reserve = Mathf.Max(0, result); } if (array.Length > 4 && int.TryParse(array[4], out var result2)) { autoSetting.FuelReserve = Mathf.Max(0, result2); } if (array.Length > 5) { autoSetting.TakeOff = array[5] != "0"; } if (array.Length > 6 && int.TryParse(array[6], out var result3)) { autoSetting.Target = Mathf.Max(0, result3); } return autoSetting; } public AutoSetting Copy() { AutoSetting autoSetting = new AutoSetting { On = On, Output = Output, Reserve = Reserve, FuelReserve = FuelReserve, TakeOff = TakeOff, Target = Target }; foreach (string item in Allowed) { autoSetting.Allowed.Add(item); } return autoSetting; } } internal static class AutoFeed { internal class Inside { public readonly List<KeyValuePair<string, int>> Queue = new List<KeyValuePair<string, int>>(); public int QueueSize; public int MaxOre; public int MaxFuel; public int Ready; public float Fuel; public string ReadyName = ""; } private static readonly int Key = StringExtensionMethods.GetStableHashCode("ffc_auto"); private static readonly List<Smelter> All = new List<Smelter>(); private static readonly Dictionary<Smelter, StationInfo> Infos = new Dictionary<Smelter, StationInfo>(); private static readonly MethodInfo QueueSize = AccessTools.Method(typeof(Smelter), "GetQueueSize", (Type[])null, (Type[])null); private static readonly MethodInfo FuelAmount = AccessTools.Method(typeof(Smelter), "GetFuel", (Type[])null, (Type[])null); private static float _next; public static bool Silent; private static readonly int RulesKey = StringExtensionMethods.GetStableHashCode("DHack_StackRules"); private static readonly MethodInfo ConversionOf = AccessTools.Method(typeof(Smelter), "GetItemConversion", (Type[])null, (Type[])null); private static float _explainedAt = -100f; private static float _hoverAt; private static Smelter _hoverFor; private static string _hoverText = ""; public static void Register(Smelter smelter) { if ((Object)(object)smelter != (Object)null && !All.Contains(smelter)) { All.Add(smelter); } } public static void Seed() { Smelter[] array = Object.FindObjectsOfType<Smelter>(); foreach (Smelter smelter in array) { Register(smelter); } } public static void Clear() { All.Clear(); Infos.Clear(); } public static bool Supported(StationInfo info) { if (info != null) { if (!(info.Component is Smelter) && !(info.Component is CookingStation)) { return info.Component is Fermenter; } return true; } return false; } public static AutoSetting Read(MonoBehaviour station) { ZNetView val = (((Object)(object)station != (Object)null) ? ((Component)station).GetComponent<ZNetView>() : null); return AutoSetting.Parse(((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO().GetString(Key, "") : ""); } public static void Write(MonoBehaviour station, AutoSetting setting) { ZNetView val = (((Object)(object)station != (Object)null) ? ((Component)station).GetComponent<ZNetView>() : null); if (!((Object)(object)val == (Object)null) && val.IsValid()) { Claims.Take(val); val.GetZDO().Set(Key, setting.Encode()); } } private static int Queue(Smelter s) { if (!(QueueSize != null)) { return 0; } return (int)QueueSize.Invoke(s, null); } private static float Fuel(Smelter s) { if (!(FuelAmount != null)) { return 0f; } return (float)FuelAmount.Invoke(s, null); } public static void Tick(Plugin plugin, Player player, float interval, float range) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_0082: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime < _next) { return; } _next = Time.unscaledTime + Mathf.Max(0.25f, interval); All.RemoveAll((Smelter s) => (Object)(object)s == (Object)null); float num = range * range; Smelter[] array = All.ToArray(); foreach (Smelter val in array) { Vector3 val2 = ((Component)val).transform.position - ((Component)player).transform.position; if (((Vector3)(ref val2)).sqrMagnitude > num) { continue; } ZNetView component = ((Component)val).GetComponent<ZNetView>(); if (!Claims.Settled(component)) { continue; } AutoSetting autoSetting = Read((MonoBehaviour)(object)val); if (!autoSetting.On || autoSetting.Allowed.Count == 0) { continue; } if (!Infos.TryGetValue(val, out var value) || !value.Alive) { if (!Stations.TryGet(((Component)val).gameObject, out value, out var _)) { continue; } Infos[val] = value; } plugin.AutoStep(player, val, value, autoSetting); } } private static int Wants(Container chest, string itemName, string category) { ZNetView val = Chests.ViewOf(chest); string text = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO().GetString(RulesKey, "") : ""); int result = 0; string[] array = text.Split(new char[1] { '|' }); foreach (string text2 in array) { if (text2.Length < 3) { continue; } bool flag = text2.StartsWith("I="); bool flag2 = text2.StartsWith("C="); if (!flag && !flag2) { continue; } string[] array2 = text2.Substring(2).Split(new char[1] { ',' }); foreach (string text3 in array2) { if (flag && text3 == itemName) { return 2; } if (flag2 && text3 == category) { result = 1; } } } return result; } private static string CategoryOf(SharedData s) { string text = (s.m_name ?? "").ToLowerInvariant(); if (text.StartsWith("$item_")) { text = text.Substring(6); } if ((text.EndsWith("ore") && !text.EndsWith("core")) || text.EndsWith("scrap")) { return "Ores"; } switch (text) { case "bronze": case "copper": case "silver": case "tin": case "iron": case "blackmetal": case "flametal": return "Metals"; default: return "Materials"; } } public static int SendOutput(Smelter smelter, string ore, int stack, float radius, Action<string> log) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null || stack <= 0 || ConversionOf == null) { return 0; } AutoSetting autoSetting = Read((MonoBehaviour)(object)smelter); if (!autoSetting.Output) { return 0; } object obj = ConversionOf.Invoke(smelter, new object[1] { ore }); ItemDrop val = ((obj == null) ? ((ItemDrop)null) : ((ItemDrop)AccessTools.Field(obj.GetType(), "m_to").GetValue(obj))); if ((Object)(object)val == (Object)null) { return 0; } string name = val.m_itemData.m_shared.m_name; string text = Localization.instance.Localize(name); string text2 = CategoryOf(val.m_itemData.m_shared); List<Container> list = Chests.Near(((Component)smelter).transform.position, radius); List<KeyValuePair<int, Container>> list2 = new List<KeyValuePair<int, Container>>(); foreach (Container item in list) { int num = Wants(item, name, text2); if (num > 0) { list2.Add(new KeyValuePair<int, Container>(num, item)); } } if (list2.Count == 0) { log($"{smelter.m_name} made {stack} {text}: none of the {list.Count} usable chest(s) within {radius:0} m is assigned to it or to {text2}, so it drops on the ground"); Explain(smelter, name, text2, radius, log); return 0; } int num2 = stack; foreach (KeyValuePair<int, Container> item2 in list2.OrderByDescending((KeyValuePair<int, Container> p) => p.Key)) { if (num2 <= 0) { break; } Container value = item2.Value; if ((Object)(object)value == (Object)null || Chests.InUse(value)) { continue; } Inventory inventory = value.GetInventory(); int maxStackSize = val.m_itemData.m_shared.m_maxStackSize; int num3 = Mathf.Min(num2, maxStackSize); if (!Chests.Ready(value)) { Chests.Request(value); log($"{smelter.m_name}: an assigned chest ({Vector3.Distance(((Component)smelter).transform.position, ((Component)value).transform.position):0} m away) is run by another player's game; it is claimed and takes output from a moment from now"); continue; } if (!inventory.CanAddItem(((Component)val).gameObject, num3)) { log($"{smelter.m_name}: an assigned chest ({Vector3.Distance(((Component)smelter).transform.position, ((Component)value).transform.position):0} m away) has no room for {num3} {text}"); continue; } int num4 = inventory.CountItems(name, -1, true); inventory.AddItem(((Component)val).gameObject, num3); int num5 = inventory.CountItems(name, -1, true) - num4; if (num5 <= 0) { log($"{smelter.m_name}: the chest did not take {num3} {text}, so it will drop on the ground"); continue; } if (num5 < num3) { log($"{smelter.m_name}: the chest only took {num5} of {num3} {text}"); } num2 -= num5; smelter.m_produceEffects.Create(((Component)smelter).transform.position, ((Component)smelter).transform.rotation, (Transform)null, 1f, -1, default(ZDOID)); log($"{smelter.m_name} made {num5} {text} and put it in a chest {Vector3.Distance(((Component)smelter).transform.position, ((Component)value).transform.position):0} m away"); } return stack - num2; } public static int SendItem(Vector3 from, ItemDrop product, int stack, float radius, string category, Action<string> log, string station) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)product == (Object)null || stack <= 0) { return 0; } string name = product.m_itemData.m_shared.m_name; List<KeyValuePair<int, Container>> list = new List<KeyValuePair<int, Container>>(); foreach (Container item in Chests.Near(from, radius)) { int num = Wants(item, name, category); if (num > 0) { list.Add(new KeyValuePair<int, Container>(num, item)); } } int num2 = stack; foreach (KeyValuePair<int, Container> item2 in list.OrderByDescending((KeyValuePair<int, Container> p) => p.Key)) { if (num2 <= 0) { break; } Container value = item2.Value; if ((Object)(object)value == (Object)null || Chests.InUse(value)) { continue; } if (!Chests.Ready(value)) { Chests.Request(value); continue; } Inventory inventory = value.GetInventory(); int num3 = Mathf.Min(num2, product.m_itemData.m_shared.m_maxStackSize); if (inventory.CanAddItem(((Component)product).gameObject, num3)) { int num4 = inventory.CountItems(name, -1, true); inventory.AddItem(((Component)product).gameObject, num3); int num5 = inventory.CountItems(name, -1, true) - num4; if (num5 > 0) { num2 -= num5; log($"{station} finished {num5} {Localization.instance.Localize(name)} and put it in a chest {Vector3.Distance(from, ((Component)value).transform.position):0} m away"); } } } return stack - num2; } private static void Explain(Smelter smelter, string name, string category, float radius, Action<string> log) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime - _explainedAt < 20f) { return; } _explainedAt = Time.unscaledTime; List<string> list = new List<string>(); int num = 0; foreach (Container item in ContainerRegistry.Alive()) { float num2 = Vector3.Distance(((Component)item).transform.position, ((Component)smelter).transform.position); if (!(num2 > radius + 15f)) { ZNetView val = Chests.ViewOf(item); string text = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO().GetString(RulesKey, "") : "(no data)"); if (text.Length > 0 && text != "(no data)" && text != "C=|I=") { num++; } if (text.Length > 0) { list.Add($"{num2:0} m: {text}"); } } } log($" looking for an assignment to '{name}' or '{category}'; chests with assignments within {radius + 15f:0} m: {num}" + ((list.Count > 0) ? (" -> " + string.Join(" ;; ", list.Take(8).ToArray())) : "")); } public static Inside Look(Smelter s) { //IL_01b9: Unknown result type (might be due to invalid IL or missing references) Inside inside = new Inside { MaxOre = s.m_maxOre, MaxFuel = s.m_maxFuel }; ZNetView val = (((Object)(object)s != (Object)null) ? ((Component)s).GetComponent<ZNetView>() : null); if ((Object)(object)val == (Object)null || !val.IsValid()) { return inside; } ZDO zDO = val.GetZDO(); inside.QueueSize = zDO.GetInt(ZDOVars.s_queued, 0); List<string> list = new List<string>(); Dictionary<string, int> dictionary = new Dictionary<string, int>(); for (int i = 0; i < inside.QueueSize; i++) { string text = zDO.GetString("item" + i, ""); if (text.Length != 0) { if (!dictionary.ContainsKey(text)) { dictionary[text] = 0; list.Add(text); } dictionary[text]++; } } foreach (string item in list) { inside.Queue.Add(new KeyValuePair<string, int>(item, dictionary[item])); } inside.Fuel = zDO.GetFloat(ZDOVars.s_fuel, 0f); inside.Ready = zDO.GetInt(ZDOVars.s_spawnAmount, 0); string text2 = zDO.GetString(ZDOVars.s_spawnOre, ""); if (inside.Ready > 0 && text2.Length > 0 && ConversionOf != null) { object obj = ConversionOf.Invoke(s, new object[1] { text2 }); ItemDrop val2 = ((obj == null) ? ((ItemDrop)null) : ((ItemDrop)AccessTools.Field(obj.GetType(), "m_to").GetValue(obj))); if ((Object)(object)val2 != (Object)null) { inside.ReadyName = Localization.instance.Localize(val2.m_itemData.m_shared.m_name); } } return inside; } private static ItemDrop DropOf(string prefabName) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefabName) : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.GetComponent<ItemDrop>(); } public static string NameOf(string prefabName) { ItemDrop val = DropOf(prefabName); if (!((Object)(object)val != (Object)null)) { return prefabName; } return Localization.instance.Localize(val.m_itemData.m_shared.m_name); } public static Sprite IconOf(string prefabName) { ItemDrop obj = DropOf(prefabName); if (obj == null) { return null; } return obj.m_itemData.GetIcon(); } public static string InsideLine(Inside i) { string text = ((i.Queue.Count > 0) ? string.Join(", ", i.Queue.Select((KeyValuePair<string, int> q) => Translations.T("feedfromchests_amount", q.Value, NameOf(q.Key))).ToArray()) : Translations.T("feedfromchests_nothing_loaded")); string text2 = Translations.T("feedfromchests_inside_line", text); if (i.MaxFuel > 0) { text2 = text2 + " " + Translations.T("feedfromchests_fuel_level", Mathf.Floor(i.Fuel).ToString("0"), i.MaxFuel); } if (i.Ready > 0) { text2 = text2 + " " + Translations.T("feedfromchests_ready", i.Ready, i.ReadyName); } return text2; } public static string HoverLine(Smelter smelter) { if ((Object)(object)smelter != (Object)(object)_hoverFor || Time.unscaledTime - _hoverAt > 0.5f) { _hoverFor = smelter; _hoverAt = Time.unscaledTime; _hoverText = "\n<size=14>" + InsideLine(Look(smelter)) + "</size>\n<size=14>" + Translations.T("feedfromchests_hover_auto", OnOff(Read((MonoBehaviour)(object)smelter).On)) + "</size>"; } return _hoverText; } public static string OnOff(bool on) { if (!on) { return Localization.instance.Localize("$hud_off").ToLowerInvariant(); } return "<color=#8fe388>" + Localization.instance.Localize("$hud_on").ToUpperInvariant() + "</color>"; } } [BepInPlugin("com.quad.feedfromchests", "FeedFromChests", "1.8.4")] public class Plugin : BaseUnityPlugin { private class Row { public ItemDrop Drop; public string Name; public string Display; public bool IsFuel; public int InInventory; public int InChests; public string Title; public string CountsText; } private class AutoItem { public string Name; public string Display; public ItemDrop Drop; public bool IsFuel; } private class LiveText { public TMP_Text Label; public Func<string> Text; public bool Fit; } private readonly Dictionary<Smelter, float> _whyAt = new Dictionary<Smelter, float>(); private readonly Dictionary<Fireplace, float> _refuelledAt = new Dictionary<Fireplace, float>(); internal static float MenuClosedAt = -1f; private string _stationTitle = ""; private string _subtitle = ""; private bool _supportsAuto; private AutoFeed.Inside _inside = new AutoFeed.Inside(); private List<string> _cookLines = new List<string>(); private LimitPlan _plan = new LimitPlan(); private readonly List<KeyValuePair<string, bool>> _limitLines = new List<KeyValuePair<string, bool>>(); private string _fermentLine = ""; private readonly Dictionary<string, int> _autoStock = new Dictionary<string, int>(); private AutoSetting _auto = new AutoSetting(); private List<AutoItem> _autoItems = new List<AutoItem>(); private StationInfo _station; private List<Row> _rows = new List<Row>(); private float _nextRefresh; private string _status = ""; private bool _autoEverSet; private const string WindowName = "FeedFromChestsMenu"; private const float Pad = 30f; private const float ColW = 480f; private const float ColGap = 20f; private const float Below = 90f; private RectTransform _window; private RectTransform _addList; private RectTransform _autoList; private float _openedAt; private float _nextCheck; private string _shown = ""; private readonly List<LiveText> _live = new List<LiveText>(); public const string Guid = "com.quad.feedfromchests"; public const string OldGuid = "com.dhack.feedfromchests"; public const string Name = "FeedFromChests"; public const string Version = "1.8.4"; internal static Plugin Instance; internal static ServerSettings Synced; private ConfigEntry<bool> _enabled; private ConfigEntry<bool> _autoFeed; private ConfigEntry<bool> _alwaysOpenMenu; private ConfigEntry<bool> _stationAuto; private ConfigEntry<bool> _takeOffCooked; private ConfigEntry<bool> _refuelLights; private ConfigEntry<bool> _refuelFires; private ConfigEntry<bool> _collectHoney; private ConfigEntry<int> _keepFuel; private ConfigEntry<bool> _fuelShields; private ConfigEntry<bool> _reloadBallistas; private ConfigEntry<bool> _collectSap; private ConfigEntry<float> _radius; private ConfigEntry<float> _autoInterval; private ConfigEntry<float> _autoRange; private ConfigEntry<float> _outputRadius; private ConfigEntry<float> _autoRadius; private ConfigEntry<int> _fillLimit; private Harmony _harmony; private string _lastAction = ""; private float _lastActionAt = -100f; private int _lastGc; private Action _pending; private bool _filling; private float _lastHintAt = -100f; internal static bool MenuOpen { get { if ((Object)(object)Instance != (Object)null) { return (Object)(object)Instance._window != (Object)null; } return false; } } private bool IsCooking { get { if (_station != null) { return _station.Component is CookingStation; } return false; } } private bool IsFermenter { get { if (_station != null) { return _station.Component is Fermenter; } return false; } } private bool FuelSwitchedOff { get { if (_supportsAuto && _auto.On && _station != null && (Object)(object)_station.Fuel != (Object)null) { return !_auto.Allowed.Contains(_station.Fuel.m_itemData.m_shared.m_name); } return false; } } internal int KeepFuel => Mathf.Max(0, _keepFuel.Value); internal bool AutoEnabled { get { if (_stationAuto != null) { return _stationAuto.Value; } return false; } } internal float ChestRadius => _radius.Value; internal float OutputRadius => _outputRadius.Value; internal float FeedRadius => _autoRadius.Value; internal bool CollectsHoney { get { if (_enabled.Value) { return _collectHoney.Value; } return false; } } internal bool HiveInfo => _enabled.Value; internal void AutoStep(Player player, Smelter smelter, StationInfo info, AutoSetting setting) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) List<Container> list = Chests.Near(info.Position, _autoRadius.Value); if (list.Count == 0) { Why(smelter, $"no usable chest within {_autoRadius.Value:0} m of it, so nothing to feed from"); return; } LimitPlan plan = Limits.For(info); AutoFeed.Silent = true; try { if ((Object)(object)info.Fuel != (Object)null && smelter.m_maxFuel > 0 && AutoFeedFuel(smelter) < (float)(smelter.m_maxFuel - 1)) { string name = info.Fuel.m_itemData.m_shared.m_name; if (setting.Allowed.Contains(name)) { if (Limits.MayFeed(info, setting, plan, info.Fuel, isFuel: true, Chests.Stock(list, name), _outputRadius.Value, out var line)) { AddOne(player, info, info.Fuel, isFuel: true, list, chestsOnly: true); } else { Why(smelter, line); } } } if (smelter.m_maxOre <= 0 || AutoFeedQueue(smelter) >= smelter.m_maxOre) { return; } string text = null; foreach (ItemDrop item in info.Inputs.OrderBy((ItemDrop d) => Tiers.Rank(d.m_itemData.m_shared))) { string name2 = item.m_itemData.m_shared.m_name; if (setting.Allowed.Contains(name2)) { if (!Limits.MayFeed(info, setting, plan, item, isFuel: false, Chests.Stock(list, name2), _outputRadius.Value, out var line2)) { text = text ?? line2; } else if (AddOne(player, info, item, isFuel: false, list, chestsOnly: true)) { text = null; break; } } } if (text != null) { Why(smelter, text); } } finally { AutoFeed.Silent = false; } } private void Why(Smelter smelter, string reason) { if (!_whyAt.TryGetValue(smelter, out var value) || !(Time.unscaledTime - value < 20f)) { _whyAt[smelter] = Time.unscaledTime; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Auto-feed, " + smelter.m_name + ": " + reason)); } } private static float AutoFeedFuel(Smelter s) { return (float)AccessTools.Method(typeof(Smelter), "GetFuel", (Type[])null, (Type[])null).Invoke(s, null); } private static int AutoFeedQueue(Smelter s) { return (int)AccessTools.Method(typeof(Smelter), "GetQueueSize", (Type[])null, (Type[])null).Invoke(s, null); } internal void CookAutoStep(Player player, CookingStation station, AutoSetting setting) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!Stations.TryGet(((Component)station).gameObject, out var info, out var _)) { return; } List<Container> list = Chests.Near(info.Position, _autoRadius.Value); if (list.Count == 0) { return; } LimitPlan plan = Limits.For(info); AutoFeed.Silent = true; try { string line; if ((Object)(object)info.Fuel != (Object)null && station.m_useFuel && Cooking.Fuel(station) < (float)(station.m_maxFuel - 1)) { string name = info.Fuel.m_itemData.m_shared.m_name; if (setting.Allowed.Contains(name) && Limits.MayFeed(info, setting, plan, info.Fuel, isFuel: true, Chests.Stock(list, name), _outputRadius.Value, out line)) { AddOne(player, info, info.Fuel, isFuel: true, list, chestsOnly: true); } } if (!Cooking.HasFreeSlot(station)) { return; } foreach (ItemDrop item in info.Inputs.OrderBy((ItemDrop d) => Tiers.Rank(d.m_itemData.m_shared))) { string name2 = item.m_itemData.m_shared.m_name; if (setting.Allowed.Contains(name2) && Limits.MayFeed(info, setting, plan, item, isFuel: false, Chests.Stock(list, name2), _outputRadius.Value, out line) && AddOne(player, info, item, isFuel: false, list, chestsOnly: true)) { break; } } } finally { AutoFeed.Silent = false; } } internal void FermentAutoStep(Player player, Fermenter fermenter, AutoSetting setting) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) if (!Stations.TryGet(((Component)fermenter).gameObject, out var info, out var _)) { return; } List<Container> list = Chests.Near(info.Position, _autoRadius.Value); if (list.Count == 0) { return; } LimitPlan plan = Limits.For(info); AutoFeed.Silent = true; try { foreach (ItemDrop input in info.Inputs) { string name = input.m_itemData.m_shared.m_name; if (setting.Allowed.Contains(name) && Limits.MayFeed(info, setting, plan, input, isFuel: false, Chests.Stock(list, name), _outputRadius.Value, out var _) && AddOne(player, info, input, isFuel: false, list, chestsOnly: true)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"{Localization.instance.Localize(fermenter.m_name)} at {((Component)fermenter).transform.position:F0} took {Localization.instance.Localize(name)} from a chest"); break; } } } finally { AutoFeed.Silent = false; } } internal void RefuelFromChests(Player player, Fireplace fire) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) if (!Stations.TryGet(((Component)fire).gameObject, out var info, out var _) || (Object)(object)info.Fuel == (Object)null) { return; } List<Container> list = Chests.Near(info.Position, _autoRadius.Value); if (list.Count != 0 && Chests.Stock(list, info.Fuel.m_itemData.m_shared.m_name) > KeepFuel) { AutoFeed.Silent = true; bool flag; try { flag = AddOne(player, info, info.Fuel, isFuel: true, list, chestsOnly: true); } finally { AutoFeed.Silent = false; } if (flag && (!_refuelledAt.TryGetValue(fire, out var value) || Time.unscaledTime - value > 60f)) { _refuelledAt[fire] = Time.unscaledTime; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Refuelled {Localization.instance.Localize(fire.m_name)} at {((Component)fire).transform.position:F0} with {Localization.instance.Localize(info.Fuel.m_itemData.m_shared.m_name)} from a chest (now {Lights.FuelOf(fire):0.#}/{fire.m_maxFuel})"); } } } internal void Log(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); } private void OpenMenu(Player player, StationInfo info) { _station = info; _status = ""; Mark("opened the menu"); _stationTitle = ((info.Component is CookingStation) ? Localization.instance.Localize(info.Title) : Translations.T("feedfromchests_add_to", Localization.instance.Localize(info.Title))); _subtitle = Translations.T("feedfromchests_subtitle", _radius.Value.ToString("0")); _supportsAuto = _stationAuto.Value && AutoFeed.Supported(info); _autoItems = BuildAutoItems(info); _auto = (_supportsAuto ? AutoFeed.Read(info.Component) : new AutoSetting()); _plan = Limits.For(info); _autoEverSet = _supportsAuto && (_auto.On || _auto.Allowed.Count > 0); RefreshRows(player); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("Menu for '{0}': {1} item(s) available, {2} input(s), fuel={3}, auto-feed={4}", info.Title, _rows.Count, _station.Inputs.Count, ((Object)(object)_station.Fuel != (Object)null) ? "yes" : "no", (!_supportsAuto) ? "n/a" : (_auto.On ? "on" : "off"))); if (_rows.Count == 0 && !_supportsAuto) { ((Character)player).Message((MessageType)2, Translations.T("feedfromchests_nothing_to_add"), 0, (Sprite)null, false); _station = null; return; } if (!GameUi.Ready()) { _station = null; return; } GameUi.IsOpen = () => MenuOpen; GameUi_EscapeCloses.Close = CloseFromEscape; if (InventoryGui.IsVisible()) { InventoryGui.instance.Hide(); } _openedAt = Time.unscaledTime; BuildWindow(fresh: true); } internal static void CloseFromEscape() { Instance?.CloseMenu(); } private void CloseMenu() { bool flag = _station != null || (Object)(object)_window != (Object)null; if ((Object)(object)_window != (Object)null) { Object.Destroy((Object)(object)((Component)_window).gameObject); } _window = null; _addList = null; _autoList = null; _shown = ""; _live.Clear(); _station = null; if (flag) { MenuClosedAt = Time.unscaledTime; UITooltip.HideTooltip(); } } private void UpdateMenu(Player player) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) bool flag = Time.unscaledTime > _openedAt + 0.2f && ZInput.GetButtonDown("Use"); if (!((Object)(object)_window == (Object)null || (Object)(object)player == (Object)null || ((Character)player).IsDead() || _station == null || !_station.Alive || Menu.IsVisible() || flag)) { Vector3 val = _station.Position - ((Component)player).transform.position; if (!(((Vector3)(ref val)).sqrMagnitude > 144f)) { if (Time.unscaledTime >= _nextRefresh) { RefreshRows(player); } if (Time.unscaledTime >= _nextCheck) { _nextCheck = Time.unscaledTime + 0.2f; if (Signature() != _shown) { BuildWindow(fresh: false); } else { UpdateLive(); } } return; } } CloseMenu(); } private void RefreshRows(Player player) { Stopwatch stopwatch = Stopwatch.StartNew(); RefreshRowsCore(player); if (stopwatch.ElapsedMilliseconds >= 12) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Slow menu refresh: {stopwatch.ElapsedMilliseconds} ms"); } } private static List<AutoItem> BuildAutoItems(StationInfo info) { HashSet<string> hashSet = new HashSet<string>(); List<AutoItem> list = new List<AutoItem>(); foreach (ItemDrop item in info.Inputs.Concat((IEnumerable<ItemDrop>)(object)((!((Object)(object)info.Fuel != (Object)null)) ? new ItemDrop[0] : new ItemDrop[1] { info.Fuel }))) { string name = item.m_itemData.m_shared.m_name; if (hashSet.Add(name)) { list.Add(new AutoItem { Name = name, Display = Localization.instance.Localize(name), Drop = item, IsFuel = ((Object)(object)info.Fuel != (Object)null && (Object)(object)item == (Object)(object)info.Fuel) }); } } return (from i in list orderby i.IsFuel, Tiers.Rank(i.Drop.m_itemData.m_shared) select i).ToList(); } private void ToggleAuto() { if (_station == null || !_station.Alive || !_supportsAuto) { return; } AutoSetting autoSetting = AutoFeed.Read(_station.Component); autoSetting.On = !autoSetting.On; if (autoSetting.On && autoSetting.Allowed.Count == 0) { bool flag = _autoItems.Count > 0 && _autoItems.All((AutoItem i) => i.IsFuel || Tiers.IsWood(i.Drop.m_itemData.m_shared)); foreach (AutoItem autoItem in _autoItems) { if (!flag || autoItem.IsFuel || autoItem == _autoItems.First((AutoItem i) => !i.IsFuel)) { autoSetting.Allowed.Add(autoItem.Name); } } } if (autoSetting.On && !_autoEverSet) { autoSetting.Output = true; autoSetting.Target = _plan.DefaultTarget; autoSetting.Reserve = _plan.DefaultReserve; autoSetting.FuelReserve = _plan.DefaultFuelReserve; } AutoFeed.Write(_station.Component, autoSetting); _auto = autoSetting; _status = (autoSetting.On ? Translations.T("feedfromchests_auto_is_on") : Translations.T("feedfromchests_auto_is_off")); } private void AdjustReserve(int delta) { if (_station != null && _station.Alive && _supportsAuto) { AutoSetting autoSetting = AutoFeed.Read(_station.Component); autoSetting.Reserve = Mathf.Clamp(autoSetting.Reserve + delta, 0, 9999); AutoFeed.Write(_station.Component, autoSetting); _auto = autoSetting; } } private void AdjustTarget(int delta) { if (_station != null && _station.Alive && _supportsAuto) { AutoSetting autoSetting = AutoFeed.Read(_station.Component); autoSetting.Target = Mathf.Clamp(autoSetting.Target + delta, 0, 99999); AutoFeed.Write(_station.Component, autoSetting); _auto = autoSetting; } } private void AdjustFuelReserve(int delta) { if (_station != null && _station.Alive && _supportsAuto) { AutoSetting autoSetting = AutoFeed.Read(_station.Component); autoSetting.FuelReserve = Mathf.Clamp(autoSetting.FuelReserve + delta, 0, 9999); AutoFeed.Write(_station.Component, autoSetting); _auto = autoSetting; } } private void ToggleOutput() { if (_station != null && _station.Alive && _supportsAuto) { AutoSetting autoSetting = AutoFeed.Read(_station.Component); autoSetting.Output = !autoSetting.Output; AutoFeed.Write(_station.Component, autoSetting); _auto = autoSetting; _status = (autoSetting.Output ? Translations.T("feedfromchests_output_chests") : Translations.T("feedfromchests_output_ground")); } } private void ToggleTakeOff() { if (_station != null && _station.Alive && _supportsAuto) { AutoSetting autoSetting = AutoFeed.Read(_station.Component); autoSetting.TakeOff = !autoSetting.TakeOff; AutoFeed.Write(_station.Component, autoSetting); _auto = autoSetting; _status = (autoSetting.TakeOff ? Translations.T("feedfromchests_takeoff_on") : Translations.T("feedfromchests_takeoff_off")); } } private void ToggleAutoItem(string name) { if (_station != null && _station.Alive && _supportsAuto) { AutoSetting autoSetting = AutoFeed.Read(_station.Component); if (!autoSetting.Allowed.Remove(name)) { autoSetting.Allowed.Add(name); } AutoFeed.Write(_station.Component, autoSetting); _auto = autoSetting; } } private void RefreshRowsCore(Player player) { //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) _nextRefresh = Time.unscaledTime + 0.5f; if (_station == null || (Object)(object)player == (Object)null) { return; } if (_supportsAuto && _station != null && _station.Alive) { _auto = AutoFeed.Read(_station.Component); MonoBehaviour component = _station.Component; Smelter val = (Smelter)(object)((component is Smelter) ? component : null); if (val != null) { _inside = AutoFeed.Look(val); } else { MonoBehaviour component2 = _station.Component; CookingStation val2 = (CookingStation)(object)((component2 is CookingStation) ? component2 : null); if (val2 != null) { _cookLines = Cooking.Lines(val2); } else { MonoBehaviour component3 = _station.Component; Fermenter val3 = (Fermenter)(object)((component3 is Fermenter) ? component3 : null); if (val3 != null) { _fermentLine = Ferment.Line(val3); } } } _autoStock.Clear(); List<Container> chests = Chests.Near(_station.Position, _autoRadius.Value); foreach (AutoItem autoItem in _autoItems) { _autoStock[autoItem.Name] = Chests.Stock(chests, autoItem.Name); } _limitLines.Clear(); if (_auto.On) { foreach (AutoItem autoItem2 in _autoItems) { if (_auto.Allowed.Contains(autoItem2.Name)) { string line; bool value = Limits.MayFeed(_station, _auto, _plan, autoItem2.Drop, autoItem2.IsFuel, _autoStock[autoItem2.Name], _outputRadius.Value, out line); _limitLines.Add(new KeyValuePair<string, bool>(line, value)); } } } } List<Container> chests2 = Chests.Near(_station.Position, _radius.Value); Inventory inventory = ((Humanoid)player).GetInventory(); List<Row> list = new List<Row>(); HashSet<string> hashSet = new HashSet<string>(); foreach (ItemDrop item in _station.Inputs.Concat((IEnumerable<ItemDrop>)(object)((!((Object)(object)_station.Fuel != (Object)null)) ? new ItemDrop[0] : new ItemDrop[1] { _station.Fuel }))) { string name = item.m_itemData.m_shared.m_name; if (hashSet.Add(name)) { Row row = new Row { Drop = item, Name = name, Display = Localization.instance.Localize(name), IsFuel = ((Object)(object)_station.Fuel != (Object)null && (Object)(object)item == (Object)(object)_station.Fuel), InInventory = inventory.CountItems(name, -1, true), InChests = Chests.Count(chests2, name) }; row.Title = row.Display + (row.IsFuel ? (" <size=80%><color=#bdb7a9>" + Translations.T("feedfromchests_fuel_tag") + "</color></size>") : ""); row.CountsText = Translations.T("feedfromchests_in_inventory", row.InInventory) + "\n" + Translations.T("feedfromchests_in_chests", row.InChests); if (row.InInventory + row.InChests > 0) { list.Add(row); } } } _rows = (from r in list orderby r.IsFuel, Tiers.Rank(r.Drop.m_itemData.m_shared) select r).ThenBy<Row, string>((Row r) => r.Display, StringComparer.OrdinalIgnoreCase).ToList(); } private void AddOneFromMenu(Player player, Row row) { if (_station != null && _station.Alive && !_filling) { Mark("Add 1 " + row.Display); bool flag = AddOne(player, _station, row.Drop, row.IsFuel); _status = (flag ? Translations.T("feedfromchests_added_one", row.Display) : Translations.T("feedfromchests_couldnt_add", row.Display)); RefreshRows(player); if (_rows.Count == 0) { CloseMenu(); } } } private void FillFromMenu(Player player, Row row) { if (_station != null && _station.Alive && !_filling) { Mark("Fill " + row.Display); ((MonoBehaviour)this).StartCoroutine(FillRoutine(player, _station, new List<Row> { row })); } } private void FillStation(Player player) { if (_station != null && _station.Alive && !_filling) { Mark("Fill station"); ((MonoBehaviour)this).StartCoroutine(FillRoutine(player, _station, _rows.OrderByDescending((Row r) => r.IsFuel).ToList())); } } private TMP_Text Live(TMP_Text label, Func<string> text, bool fit = false) { _live.Add(new LiveText { Label = label, Text = text, Fit = fit }); return label; } private void UpdateLive() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) foreach (LiveText item in _live) { if ((Object)(object)item.Label == (Object)null) { continue; } string text = item.Text() ?? ""; if (item.Label.text == text) { continue; } item.Label.text = text; if (item.Fit) { RectTransform val = (RectTransform)item.Label.transform; if (Mathf.Abs(Mathf.Ceil(item.Label.GetPreferredValues(text, val.sizeDelta.x, 0f).y) - val.sizeDelta.y) > 1f) { _shown = ""; } } } } private static Button Squeeze(Button b) { TMP_Text val = GameUi.Label(b); if ((Object)(object)val != (Object)null) { val.fontSizeMax = val.fontSize; val.fontSizeMin = 11f; val.enableAutoSizing = true; } return b; } private static float Fit(TMP_Text t, float width) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Ceil(t.GetPreferredValues(t.text, width, 0f).y); ((RectTransform)t.transform).sizeDelta = new Vector2(width, num); return num; } private Row RowNamed(string name) { return _rows.FirstOrDefault((Row r) => r.Name == name); } private static int Total(Row row) { if (row == null) { return 0; } return row.InInventory + row.InChests; } private static string Shown(int value, bool offWhenZero) { if (!(value == 0 && offWhenZero)) { return value.ToString(); } return Localization.instance.Localize("$hud_off"); } private void Later(Action<Player> act) { _pending = delegate { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { act(localPlayer); } }; } private string Signature() { if (_station == null) { return ""; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(((Object)(object)_station.Component != (Object)null) ? ((Object)_station.Component).GetInstanceID() : 0).Append('|').Append(_supportsAuto) .Append(_filling) .Append(_takeOffCooked.Value) .Append('|') .Append(_autoRadius.Value) .Append('|') .Append(_subtitle); foreach (Row row in _rows) { stringBuilder.Append("|r").Append(row.Name); } if (_supportsAuto) { stringBuilder.Append("|a").Append(_auto.On).Append(_auto.Output) .Append(_auto.TakeOff) .Append(FuelSwitchedOff) .Append(':') .Append(string.Join(",", _auto.Allowed.OrderBy((string n) => n).ToArray())); foreach (KeyValuePair<string, int> item in _inside.Queue) { stringBuilder.Append("|q").Append(item.Key); } stringBuilder.Append("|c").Append(_cookLines.Count); foreach (KeyValuePair<string, bool> limitLine in _limitLines) { stringBuilder.Append("|l").Append(limitLine.Value); } } return stringBuilder.ToString(); } private void BuildWindow(bool fresh) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) if (!GameUi.Ready() || _station == null) { CloseMenu(); return; } float num = ((!fresh && (Object)(object)_addList != (Object)null) ? _addList.anchoredPosition.y : 0f); float num2 = ((!fresh && (Object)(object)_autoList != (Object)null) ? _autoList.anchoredPosition.y : 0f); if ((Object)(object)_window != (Object)null) { Object.Destroy((Object)(object)((Component)_window).gameObject); } _addList = (_autoList = null); UITooltip.HideTooltip(); _live.Clear(); _shown = Signature(); float num3 = (_supportsAuto ? 1040f : 540f); float num4 = (_supportsAuto ? 740f : 600f); _window = GameUi.Window("FeedFromChestsMenu", new Vector2(num3, num4)); Transform window = (Transform)(object)_window; TMP_Text val = GameUi.Label(window, _stationTitle, new Vector2(30f, -20f), new Vector2(num3 - 60f - 130f, 60f), 34f, GameUi.Warm, GameUi.Norse, (TextAlignmentOptions)257); val.enableWordWrapping = false; val.overflowMode = (TextOverflowModes)1; GameUi.Button(window, Localization.instance.Localize("$menu_close"), new Vector2(num3 - 30f - 110f, -24f), new Vector2(110f, 40f), delegate { _pending = CloseMenu; }); GameUi.Braid(window, new Vector2(0f, -76f), num3 - 60f); DrawAddColumn(window, 30f, num4); if (_supportsAuto) { DrawAutoColumn(window, 530f, num4); } if ((Object)(object)_addList != (Object)null) { _addList.anchoredPosition = new Vector2(0f, Mathf.Clamp(num, 0f, Mathf.Max(0f, _addList.sizeDelta.y))); } if ((Object)(object)_autoList != (Object)null) { _autoList.anchoredPosition = new Vector2(0f, Mathf.Clamp(num2, 0f, Mathf.Max(0f, _autoList.sizeDelta.y))); } } private void DrawAddColumn(Transform win, float x, float h) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_03f8: Unknown result type (might be due to invalid IL or missing references) //IL_0402: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_04a2: Unknown result type (might be due to invalid IL or missing references) float num = 90f; num += Fit(GameUi.Label(win, _subtitle, new Vector2(x, 0f - num), new Vector2(480f, 40f), 16f, GameUi.Dim, null, (TextAlignmentOptions)257), 480f) + 8f; RectTransform box = GameUi.Box(win, new Vector2(x - 6f, 0f - num), new Vector2(492f, h - 30f - 62f - num)); _addList = GameUi.Scroll(box, 8f); float x2 = _addList.sizeDelta.x; if (_rows.Count == 0) { TMP_Text t = GameUi.Label((Transform)(object)_addList, Translations.T("feedfromchests_nothing_by_hand"), new Vector2(8f, -8f), new Vector2(x2 - 16f, 40f), 17f, GameUi.Dim, null, (TextAlignmentOptions)257); _addList.sizeDelta = new Vector2(x2, Fit(t, x2 - 16f) + 16f); } else { float cellSpace = GameUi.CellSpace; float num2 = 84f; float num3 = 4f; float num4 = 80f; float num5 = x2 - num4 - num2 * 2f - 14f; foreach (Row row in _rows) { Row r = row; string name = row.Name; InventoryElement val = GameUi.Cell((Transform)(object)_addList, new Vector2(4f, 0f - num3), row.Drop.m_itemData, Total(row).ToString(), selected: false, null); Live(val.m_amount, () => Total(RowNamed(name)).ToString()); TMP_Text val2 = GameUi.Label((Transform)(object)_addList, row.Title, new Vector2(num4, 0f - num3 - 4f), new Vector2(num5, 34f), 19f, GameUi.Text, null, (TextAlignmentOptions)257); val2.enableWordWrapping = false; val2.overflowMode = (TextOverflowModes)1; Live(GameUi.Label((Transform)(object)_addList, row.CountsText, new Vector2(num4, 0f - num3 - 28f), new Vector2(num5, 38f), 14f, GameUi.Dim, null, (TextAlignmentOptions)257), () => RowNamed(name)?.CountsText ?? ""); Squeeze(GameUi.Button((Transform)(object)_addList, Translations.T("feedfromchests_add_one"), new Vector2(x2 - num2 * 2f - 6f, 0f - num3 - 12f), new Vector2(num2, 40f), delegate { Later(delegate(Player p) { AddOneFromMenu(p, r); }); }, !_filling, 17f)); Button b = Squeeze(GameUi.Button((Transform)(object)_addList, Translations.T("feedfromchests_fill"), new Vector2(x2 - num2, 0f - num3 - 12f), new Vector2(num2, 40f), delegate { Later(delegate(Player p) { FillFromMenu(p, r); }); }, !_filling, 17f)); if (!_filling) { ((Graphic)GameUi.Label(b)).color = GameUi.Gold; } num3 += cellSpace; } _addList.sizeDelta = new Vector2(x2, num3 - cellSpace + 64f + 4f); } float num6 = h - 30f - 50f; Live(GameUi.Label(win, _status, new Vector2(x, 0f - num6), new Vector2(284f, 50f), 15f, GameUi.Dim, null, (TextAlignmentOptions)4097), () => _status); bool flag = !_filling && _rows.Count > 0; Button b2 = GameUi.Button(win, Translations.T("feedfromchests_fill_station"), new Vector2(x + 480f - 184f, 0f - num6), new Vector2(184f, 48f), delegate { Later(FillStation); }, flag, 19f); if (flag) { ((Graphic)GameUi.Label(b2)).color = GameUi.Gold; } } private void DrawAutoColumn(Transform win, float x, float h) { //IL_001a: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Expected O, but got Unknown //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_05c5: Unknown result type (might be due to invalid IL or missing references) //IL_063d: Unknown result type (might be due to invalid IL or missing references) //IL_06f3: Unknown result type (might be due to invalid IL or missing references) //IL_0719: Unknown result type (might be due to invalid IL or missing references) //IL_08b4: Unknown result type (might be due to invalid IL or missing references) //IL_07f5: Unknown result type (might be due to invalid IL or missing references) //IL_0800: Unknown result type (might be due to invalid IL or missing references) //IL_096f: Unknown result type (might be due to invalid IL or missing references) //IL_0985: Unknown result type (might be due to invalid IL or missing references) //IL_0927: Unknown result type (might be due to invalid IL or missing references) //IL_0920: Unknown result type (might be due to invalid IL or missing references) RectTransform box = GameUi.Box(win, new Vector2(x - 6f, -90f), new Vector2(492f, h - 90f - 30f)); _autoList = GameUi.Scroll(box, 8f); RectTransform c = _autoList; float cw = c.sizeDelta.x - 8f; float y = 6f; if (IsFermenter) { Heading(Translations.T("feedfromchests_in_barrel")); Live(Line(_fermentLine, 16f, GameUi.Text, 10f), () => _fermentLine, fit: true); } else if (IsCooking) { Heading(Translations.T("feedfromchests_on_station")); for (int num = 0; num < _cookLines.Count; num++) { int k = num; Live(Line(_cookLines[num], 16f, GameUi.Text, 2f), () => (k >= _cookLines.Count) ? "" : _cookLines[k], fit: true); } y += 8f; } else { Heading(Translations.T("feedfromchests_inside")); if (_inside.Queue.Count == 0) { Line(Translations.T("feedfromchests_nothing_loaded_menu"), 16f, GameUi.Dim, 4f); } else { float num2 = 4f; foreach (KeyValuePair<string, int> item in _inside.Queue) { string key = item.Key; string text = QueueText(key); TMP_Text val = GameUi.Label((Transform)(object)c, text, Vector2.zero, new Vector2(cw, 28f), 16f, GameUi.Text, null, (TextAlignmentOptions)257); val.enableWordWrapping = false; Live(val, () => QueueText(key)); float num3 = val.GetPreferredValues(text, cw, 0f).x + 20f; if (num2 > 4f && num2 + 32f + num3 > cw) { num2 = 4f; y += 34f; } GameUi.Icon((Transform)(object)c, new Vector2(num2, 0f - y), new Vector2(28f, 28f), AutoFeed.IconOf(key)); RectTransform val2 = (RectTransform)val.transform; val2.anchoredPosition = new Vector2(num2 + 32f, 0f - y - 3f); val2.sizeDelta = new Vector2(num3, 28f); num2 += 32f + num3 + 6f; } y += 34f; } Live(Line(InsideStatus(), 15f, GameUi.Dim, 6f), InsideStatus, fit: true); } GameUi.Braid((Transform)(object)c, new Vector2(0f, 0f - y - 8f), cw - 40f); y += 20f; OnOff(Translations.T("feedfromchests_auto_toggle"), _auto.On, ToggleAuto); Line(_auto.On ? Translations.T("feedfromchests_auto_on_help", _autoRadius.Value.ToString("0")) : Translations.T("feedfromchests_auto_off_help"), 15f, GameUi.Dim, 12f); if (_plan.Target) { Number(_plan.TargetLabel, () => _auto.Target, offWhenZero: true, _plan.TargetHelp, AdjustTarget); } if (_plan.Reserve) { Number(_plan.ReserveLabel, () => _auto.Reserve, offWhenZero: false, _plan.ReserveHelp, AdjustReserve); } if (_plan.FuelReserve) { Number(_plan.FuelLabel, () => _auto.FuelReserve, offWhenZero: false, _plan.FuelHelp, AdjustFuelReserve); } if (IsFermenter) { OnOff(Translations.T("feedfromchests_taps_toggle"), _auto.TakeOff, ToggleTakeOff); Line(Translations.T("feedfromchests_taps_help"), 15f, GameUi.Dim, 12f); } if (IsCooking) { OnOff(Translations.T("feedfromchests_takeoff_on"), _auto.TakeOff, ToggleTakeOff); Line(_takeOffCooked.Value ? Translations.T("feedfromchests_takeoff_help") : Translations.T("feedfromchests_takeoff_config_off"), 15f, GameUi.Dim, 12f); } OnOff(IsCooking ? Translations.T("feedfromchests_output_food") : (IsFermenter ? Translations.T("feedfromchests_output_mead") : Translations.T("feedfromchests_output_chests")), _auto.Output, ToggleOutput); Line(IsFermenter ? Translations.T("feedfromchests_output_mead_help") : (IsCooking ? Translations.T("feedfromchests_output_food_help") : Translations.T("feedfromchests_output_help")), 15f, GameUi.Dim, 12f); Line(Translations.T("feedfromchests_items_may_use"), 17f, GameUi.Text, 6f); float num4 = (cw - 6f) / 2f; for (int num5 = 0; num5 < _autoItems.Count; num5++) { AutoItem autoItem = _autoItems[num5]; string name = autoItem.Name; GameUi.Toggle((Transform)(object)c, autoItem.Display + (autoItem.IsFuel ? (" " + Translations.T("feedfromchests_fuel_tag")) : ""), _auto.Allowed.Contains(name), new Vector2(4f + (float)(num5 % 2) * (num4 + 6f), 0f - y - (float)(num5 / 2) * 44f), new Vector2(num4, 40f), delegate { _pending = delegate { ToggleAutoItem(name); }; }, 15f, autoItem.Drop.m_itemData.GetIcon()); } y += (float)((_autoItems.Count + 1) / 2) * 44f + 6f; if (FuelSwitchedOff) { Line(Translations.T("feedfromchests_fuel_off_warn", Localization.instance.Localize(_station.Fuel.m_itemData.m_shared.m_name)), 15f, GameUi.Warn, 4f); } for (int num6 = 0; num6 < _limitLines.Count; num6++) { int k2 = num6; Live(Line(_limitLines[num6].Key, 15f, _limitLines[num6].Value ? GameUi.Good : GameUi.Gold, 4f), () => (k2 >= _limitLines.Count) ? "" : _limitLines[k2].Key, fit: true); } c.sizeDelta = new Vector2(c.sizeDelta.x, y + 2f); void Heading(string text2) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) Line(text2, 20f, GameUi.Warm, 6f, GameUi.Serif); } TMP_Text Line(string text2, float size, Color color, float gap, TMP_FontAsset font = null) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) TMP_Text val3 = GameUi.Label((Transform)(object)c, text2, new Vector2(4f, 0f - y), new Vector2(cw, 30f), size, color, font, (TextAlignmentOptions)257); y += Fit(val3, cw) + gap; return val3; } void Number(string label, Func<int> value, bool offWhenZero, string help, Action<int> adjust) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) Line(label, 17f, GameUi.Text, 6f); TMP_Text label2 = GameUi.Stepper((Transform)(object)c, new Vector2(4f, 0f - y), 34f, Shown(value(), offWhenZero), new int[2] { 10, 1 }, delegate(int d) { _pending = delegate { adjust(d); }; }); Live(label2, () => Shown(value(), offWhenZero)); y += 40f; if (!string.IsNullOrEmpty(help)) { Line(help, 15f, GameUi.Dim, 12f); } else { y += 8f; } } void OnOff(string text2, bool on, Action act) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) GameUi.Toggle((Transform)(object)c, text2, on, new Vector2(4f, 0f - y), new Vector2(cw, 40f), delegate { _pending = act; }); y += 46f; } } private string QueueText(string prefab) { foreach (KeyValuePair<string, int> item in _inside.Queue) { if (item.Key == prefab) { return Translations.T("feedfromchests_amount", item.Value, AutoFeed.NameOf(item.Key)); } } return ""; } private string InsideStatus() { AutoFeed.Inside inside = _inside; string text = Translations.T("feedfromchests_loaded", inside.QueueSize, inside.MaxOre); if (inside.MaxFuel > 0) { text = text + " · " + Translations.T("feedfromchests_fuel_level", Mathf.Floor(inside.Fuel).ToString("0"), inside.MaxFuel); } if (inside.Ready > 0) { text = text + " · " + Translations.T("feedfromchests_ready_collect", inside.Ready, inside.ReadyName); } return text; } internal bool RefuelsItself(Fireplace f) { if (_enabled.Value) { return Lights.Refuels(f, _refuelLights.Value, _refuelFires.Value); } return false; } internal void Info(string message) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); } private void Awake() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Expected O, but got Unknown //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Expected O, but got Unknown Migration.FromOldGuid((BaseUnityPlugin)(object)this, "com.dhack.feedfromchests"); Translations.Load((BaseUnityPlugin)(object)this); Instance = this; Synced = new ServerSettings("com.quad.feedfromchests", ((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turn the mod on or off."); _radius = Synced.Add<float>(((BaseUnityPlugin)this).Config.Bind<float>("General", "Radius", 15f, new ConfigDescription("How far (in metres) from the station a chest can be and still be used. In multiplayer the server's value applies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 50f), Array.Empty<object>()))); _autoFeed = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoFeedOnUse", true, "Pressing E at a station when you carry nothing it takes, but a nearby chest has some: add it for you (or open the menu if there's a choice)."); _alwaysOpenMenu = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AlwaysOpenMenu", false, "Pressing E at a station when you rely on chests: off = add one automatically if there's only one kind to add (menu only for a choice); on = always open the menu (so Fill is always at hand)."); _fillLimit = ((BaseUnityPlugin)this).Config.Bind<int>("General", "FillLimit", 100, "Safety limit: the most of one item the menu's Fill button will put in at once. (Fill stops sooner when the station is full or you run out.)"); _stationAuto = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoFeed", "Enabled", true, "Allow smelters, kilns and furnaces to be set to keep themselves stocked from nearby chests (set up in the station's menu)."); _autoRadius = Synced.Add<float>(((BaseUnityPlugin)this).Config.Bind<float>("AutoFeed", "FeedRadius", 30f, new ConfigDescription("How far (in metres) from a smelter or kiln a chest can be and still be used to keep it stocked automatically. In multiplayer the server's value applies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>()))); _outputRadius = Synced.Add<float>(((BaseUnityPlugin)this).Config.Bind<float>("AutoFeed", "OutputRadius", 30f, new ConfigDescription("How far (in metres) from a smelter or kiln a chest can be and still receive what it makes (only chests assigned to it, with the chest assign menu, K). In multiplayer the server's value applies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>()))); _autoInterval = ((BaseUnityPlugin)this).Config.Bind<float>("AutoFeed", "Interval", 1f, "Seconds between automatic top-ups of each station."); _autoRange = Synced.Add<float>(((BaseUnityPlugin)this).Config.Bind<float>("AutoFeed", "PlayerRange", 40f, new ConfigDescription("Automatic feeding only runs while you are within this many metres of the station (the game only loads chests near players). In multiplayer the server's value applies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), Array.Empty<object>()))); _takeOffCooked = ((BaseUnityPlugin)this).Config.Bind<bool>("Cooking", "TakeOffCooked", true, "Food on a cooking station comes off by itself the moment it is done, so it never burns: into a chest assigned to it or to Food (the chest assign menu, K), else it slides off the side of the spit. Each station can also be switched off in its menu (E)."); _refuelLights = ((BaseUnityPlugin)this).Config.Bind<bool>("Fires", "RefuelTorches", true, "Every torch, sconce and brazier keeps itself lit: when it has room for more fuel (resin, coal...), one is taken from a chest within FeedRadius of it. For all of them at once, no setup per torch. Runs while you are within PlayerRange; never uses your inventory."); _collectHoney = ((BaseUnityPlugin)this).Config.Bind<bool>("Beehives", "CollectHoney", true, "Beehives near you put their honey into a chest (one assigned to honey or to Food with K, else one that already has honey), so they never sit full: a full hive stops making honey. With no such chest within OutputRadius the honey stays in the hive."); _refuelFires = ((BaseUnityPlugin)this).Config.Bind<bool>("Fires", "RefuelCampfires", false, "The same for fires that burn wood (campfires, hearths, bonfires): keep them topped up with wood from nearby chests."); _fuelShields = ((BaseUnityPlugin)this).Config.Bind<bool>("Defenses", "FuelShieldGenerators", true, "Shield generators near you take their fuel (bones and the like) from chests within FeedRadius as they have room, so the shield never runs dry. All of them at once."); _reloadBallistas = ((BaseUnityPlugin)this).Config.Bind<bool>("Defenses", "ReloadBallistas", true, "Ballistas near you are reloaded from chests within FeedRadius: with the ammo they hold, or when empty the first ammo they take that the chests have."); _collectSap = ((BaseUnityPlugin)this).Config.Bind<bool>("Defenses", "CollectSap", true, "Sap extractors near you empty themselves into a chest assigned to sap or Materials (K), else one that already holds sap, so they never sit full."); _keepFuel = ((BaseUnityPlugin)this).Config.Bind<int>("Fires", "KeepFuel", 10, "Torches and fires never take the last of a fuel: this many of it (resin, coal, wood...) always stay in the chests, for crafting."); _harmony = new Harmony("com.quad.feedfromchests"); _harmony.PatchAll(); ContainerRegistry.Seed(); AutoFeed.Seed(); Cooking.Seed(); Lights.Seed(); Hives.Seed(); Ferment.Seed(); Defenses.Seed(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"FeedFromChests 1.8.4 loaded"); ((MonoBehaviour)this).StartCoroutine(Warmup()); if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)Chat.instance != (Object)null) { ((Terminal)Chat.instance).AddString("[Mod]", "FeedFromChests v1.8.4 reloaded", (Type)1, false); } } private void OnDestroy() { CloseMenu(); GameUi.Destroy(); AutoFeed.Clear(); Cooking.Clear(); Lights.Clear(); Hives.Clear(); Ferment.Clear(); Defenses.Clear(); Feed.Prepaid = null; ContainerRegistry.Clear(); if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } Translations.Unload(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } Synced?.Dispose(); } private void Mark(string action) { _lastAction = action; _lastActionAt = Time.unscaledTime; } private void WatchForSpikes() { int num = GC.CollectionCount(0); float unscaledDeltaTime = Time.unscaledDeltaTime; if (unscaledDeltaTime > 0.1f && Time.unscaledTime - _lastActionAt < 3f) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Slow frame: {unscaledDeltaTime * 1000f:0} ms, {num - _lastGc} memory cleanup(s), shortly after: {_lastAction}"); } _lastGc = num; } private IEnumerator Warmup() { yield return (object)new WaitForSeconds(3f); List<MethodBase> list = new List<MethodBase>(); Type[] types = typeof(Plugin).Assembly.GetTypes(); foreach (Type type in types) { if (!type.IsGenericTypeDefinition) { MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodBase item in methods) { list.Add(item); } } } int done = 0; foreach (MethodBase item2 in list) { if (!item2.IsAbstract && !item2.ContainsGenericParameters) { try { RuntimeHelpers.PrepareMethod(item2.MethodHandle); } catch (Exception) { } int num = done + 1; done = num; if (num % 4 == 0) { yield return null; } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Warmed up {done} methods"); } private void Update() { Synced?.Update(); WatchForSpikes(); if (_pending != null) { Action pending = _pending; _pending = null; pending(); } Player localPlayer = Player.m_localPlayer; if (_station != null) { UpdateMenu(localPlayer); } if (_enabled.Value && !((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsDead()) { if (_stationAuto.Value && !_filling) { AutoFeed.Tick(this, localPlayer, _autoInterval.Value, _autoRange.Value); } if (_stationAuto.Value && !_filling) { Cooking.Tick(this, localPlayer, _autoRange.Value, _takeOffCooked.Value); } if (!_filling) { Lights.Tick(this, localPlayer, _autoRange.Value, _refuelLights.Value, _refuelFires.Value); } if (!_filling && _collectHoney.Value) { Hives.Tick(this, localPlayer, _autoRange.Value, _outputRadius.Value); } if (!_filling) { Defenses.Tick(this, localPlayer, _autoRange.Value, _autoRadius.Value, _outputRadius.Value, _fuelShields.Value, _reloadBallistas.Value, _collectSap.Value); } if (_stationAuto.Value && !_filling) { Ferment.Tick(this, localPlayer, _autoRange.Value); } } } private static bool TypingOrMenuOpen() { if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Minimap.InTextInput() && !Menu.IsVisible()) { return InventoryGui.IsVisible(); } return true; } internal bool AddOne(Player player, StationInfo info, ItemDrop drop, bool isFuel, List<Container> chests = null, bool chestsOnly = false) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) if (info == null || !info.Alive) { return false; } Stopwatch stopwatch = Stopwatch.StartNew(); Feed.Chests = chests ?? Chests.Near(info.Position, _radius.Value); string name = drop.m_itemData.m_shared.m_name; long elapsedMilliseconds = stopwatch.ElapsedMilliseconds; Inventory inventory = ((Humanoid)player).GetInventory(); bool flag = !chestsOnly && Chests.OwnCount(inventory, name) > 0; Container from = null; ItemData val = (flag ? null : Chests.TakeOne(Feed.Chests, name, out from)); if (!flag && val == null) { return false; } long elapsedMilliseconds2 = stopwatch.ElapsedMilliseconds; Feed.Prepaid = ((val != null) ? name : null); Feed.Active = true; Feed.ChestsOnly = chestsOnly; Outcome outcome; try { outcome = (isFuel ? info.AddFuel : info.AddInput)(player, Stations.StandIn(drop)); } finally { Feed.Active = false; Feed.ChestsOnly = false; } bool flag2 = Feed.Prepaid != null; Feed.Prepaid = null; long elapsedMilliseconds3 = stopwatch.ElapsedMilliseconds; switch (outcome) { case Outcome.AddedTakeOne: if (val != null) { flag2 = false; } else { inventory.RemoveItem(name, 1, -1, true); } break; case Outcome.Failed: if (val != null) { flag2 = true; } break; } if (flag2 && val != null) { Chests.PutBack(val, from, player, info.Position); } long elapsedMilliseconds4 = stopwatch.ElapsedMilliseconds; if (elapsedMilliseconds4 >= 12) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Slow add of {name}: {elapsedMilliseconds4} ms total (chest lookup {elapsedMilliseconds}, taking from a chest {elapsedMilliseconds2 - elapsedMilliseconds}, the station's own add {elapsedMilliseconds3 - elapsedMilliseconds2}, settling {elapsedMilliseconds4 - elapsedMilliseconds3})"); } return outcome != Outcome.Failed; } private IEnumerator FillRoutine(Player player, StationInfo info, List<Row> rows) { _filling = true; List<Container> chests = Chests.Near(info.Position, _radius.Value); List<string> parts = new List<string>(); try { ZNetView view = (((Object)(object)info.Component != (Object)null) ? ((Component)info.Component).GetComponent<ZNetView>() : null); if ((Object)(object)view != (Object)null && view.IsValid() && !Claims.Settled(view)) { Claims.Take(view); float giveUp = Time.unscaledTime + 3f; while (info.Alive && view.IsValid() && !Claims.Settled(view) && Time.unscaledTime < giveUp) { yield return null; } } foreach (Row row in rows) { int added = 0; for (int i = 0; i < _fillLimit.Value; i++) { if (!info.Alive) { break; } if ((Object)(object)player == (Object)null) { break; } if ((Object)(object)view != (Object)null && !Claims.Settled(view)) { break; } if (!AddOne(player, info, row.Drop, row.IsFuel, chests)) { break; } added++; if (added % 2 == 0) { yield return null; } } if (added > 0) { parts.Add(Translations.T("feedfromchests_amount", added, row.Display)); } } } finally { _filling = false; } _status = ((parts.Count > 0) ? Translations.T("feedfromchests_filled", string.Join(", ", parts.ToArray())) : Translations.T("feedfromchests_nothing_fits")); if (_station == info && (Object)(object)player != (Object)null) { RefreshRows(player); if (_rows.Count == 0) { CloseMenu(); } } } internal bool TryAutoFeed(Player player, GameObject go, bool alt = false) { //IL_01b8: Unknown result type (might be due to invalid IL or missing references) if (!_enabled.Value) { return false; } CookingStation val = (((Object)(object)go != (Object)null) ? go.GetComponentInParent<CookingStation>() : null); Purpose? purpose; if ((Object)(object)val != (Object)null && !alt) { if (Cooking.HasDone(val)) { int num = Cooking.TakeAllInto(player, val); Mark($"took {num} off a cooking station"); return num > 0; } if (_stationAuto.Value && Stations.TryGet(go, out var info, out purpose)) { Mark("pressed E at a cooking station"); OpenMenu(player, info); return true; } } if ((Object)(object)val != (Object)null && alt) { return false; } Fermenter val2 = (((Object)(object)go != (Object)null) ? go.GetComponentInParent<Fermenter>() : null); if ((Object)(object)val2 != (Object)null) { if (alt || !_stationAuto.Value || Ferment.StateOf(val2, out var _) != Ferment.State.Empty) { return false; } if (Stations.TryGet(go, out var info2, out purpose)) { Mark("pressed E at a fermenter"); OpenMenu(player, info2); return true; } } if (!Stations.TryGet(go, out var info3, out var purpose2) || !purpose2.HasValue) { return false; } if (_stationAuto.Value && AutoFeed.Supported(info3)) { Mark("pressed E at a smelter"); OpenMenu(player, info3); return true; } if (!_autoFeed.Value) { return false; } bool flag = purpose2 == Purpose.Fuel; List<ItemDrop> list = ((!flag) ? info3.Inputs : (((Object)(object)info3.Fuel != (Object)null) ? new List<ItemDrop> { info3.Fuel } : new List<ItemDrop>())); if (list.Count == 0) { return false; } Inventory inventory = ((Humanoid)player).GetInventory(); if (list.Any((ItemDrop d) => inventory.CountItems(d.m_itemData.m_shared.m_name, -1, true) > 0)) { return false; } List<Container> chests = Chests.Near(info3.Position, _radius.Value); List<ItemDrop> list2 = list.Where((ItemDrop d) => Chests.Count(chests, d.m_itemData.m_shared.m_name) > 0).ToList(); if (list2.Count == 0) { return false; } Mark("pressed E at a station"); if (list2.Count == 1 && !_alwaysOpenMenu.Value) { AddOne(player, info3, list2[0], flag); if (Time.unscaledTime - _lastHintAt > 30f) { _lastHintAt = Time.unscaledTime; ((Character)player).Message((MessageType)1, Translations.T("feedfromchests_tip_menu"), 0, (Sprite)null, false); } } else { OpenMenu(player, info3); } return true; } } [HarmonyPatch(typeof(Smelter), "Awake")] internal static class Smelter_Awake { private static void Postfix(Smelter __instance) { AutoFeed.Register(__instance); } } [HarmonyPatch(typeof(Smelter), "Spawn")] internal static class Smelter_Spawn { [HarmonyPriority(0)] private static bool Prefix(Smelter __instance, string ore, ref int stack, bool __runOriginal) { if (!__runOriginal) { return false; } Plugin instance = Plugin.Instance; if ((Object)(object)instance == (Object)null || !instance.AutoEnabled) { return true; } try { int num = AutoFeed.SendOutput(__instance, ore, stack, instance.OutputRadius, instance.Info); if (num >= stack) { return false; } stack -= num; return true; } catch (Exception ex) { instance.Log("Could not send output to a chest, dropping it instead: " + ex.Message); return true; } } } [HarmonyPatch(typeof(Player), "Message")] internal static class Player_Message { private static bool Prefix() { return !AutoFeed.Silent; } } [HarmonyPatch(typeof(Switch), "GetHoverText")] internal static class Switch_GetHoverText { private static void Postfix(Switch __instance, ref string __result) { Plugin instance = Plugin.Instance; if (!((Object)(object)instance == (Object)null) && !string.IsNullOrEmpty(__result) && instance.AutoEnabled) { Smelter componentInParent = ((Component)__instance).GetComponentInParent<Smelter>(); if ((Object)(object)componentInParent != (Object)null) { __result += AutoFeed.HoverLine(componentInParent); } } } } internal static class Chests { private static readonly Func<Container, long, bool> CheckAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null), (object)null, true); private static readonly FieldInfo NView = AccessTools.Field(typeof(Container), "m_nview"); private static readonly MethodInfo Load = AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null); private static List<Container> _cached; private static Vector3 _cachedOrigin; private static float _cachedRadius; private static float _cachedAt = -10f; internal static ZNetView ViewOf(Container c) { object? value = NView.GetValue(c); return (ZNetView)((value is ZNetView) ? value : null); } internal static bool InUse(Container c) { if (c.IsInUse()) { return true; } ZNetView val = ViewOf(c); if ((Object)(object)val != (Object)null && val.IsValid() && !val.IsOwner()) { return val.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 1; } return false; } internal static bool Ready(Container c) { if ((Object)(object)c == (Object)null || !Claims.Settled(ViewOf(c))) { return false; } Load?.Invoke(c, null); return true; } internal static void Request(Container c) { if ((Object)(object)c != (Object)null && !InUse(c)) { Claims.Request(ViewOf(c)); } } private static bool IsStorage(Container c) { if ((Object)(object)((Component)c).GetComponentInParent<Piece>() == (Object)null || (Object)(object)((Component)c).GetComponent<TombStone>() != (Object)null) { return false; } if ((Object)(object)((Component)c).GetComponentInParent<Character>() != (Object)null || (Object)(object)((Component)c).GetComponentInParent<Vagon>() != (Object)null || (Object)(object)((Component)c).GetComponentInParent<Ship>() != (Object)null) { return false; } if (SpecialContainers.NotStorage(c)) { return false; } ZNetView val = ViewOf(c); if ((Object)(object)val != (Object)null && val.IsValid()) { return val.GetZDO().GetLong("dhc_home", 0L) == 0; } return false; } private static bool Usable(Container c) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)c == (Object)null || c.GetInventory() == null || !IsStorage(c) || InUse(c)) { return false; } if (c.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)c).transform.position, 0f, false, false)) { return false; } long playerID = Game.instance.GetPlayerProfile().GetPlayerID(); return CheckAccess(c, playerID); } public static List<Container> Near(Vector3 origin, float radius) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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) if (_cached != null && Time.unscaledTime - _cachedAt < 0.5f && radius == _cachedRadius) { Vector3 val = origin - _cachedOrigin; if (((Vector3)(ref val)).sqrMagnitude < 0.01f && _cached.All((Container c) => (Object)(object)c != (Object)null)) { return _cached; } } float max = radius * radius; _cached = ContainerRegistry.Alive().Where(delegate(Container c) { //IL_000f: 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_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) if ((Object)(object)c != (Object)null) { Vector3 val2 = ((Component)c).transform.position - origin; if (((Vector3)(ref val2)).sqrMagnitude <= max) { return Usable(c); } } return false; }).OrderBy(delegate(Container c) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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) Vector3 val2 = ((Component)c).transform.position - origin; return ((Vector3)(ref val2)).sqrMagnitude; }) .ToList(); _cachedOrigin = origin; _cachedRadius = radius; _cachedAt = Time.unscaledTime; return _cached; } public static void ForgetCache() { _cached = null; } public static int Count(IEnumerable<Container> chests, string itemName) { int num = 0; foreach (Container chest in chests) { if ((Object)(object)chest == (Object)null || InUse(chest)) { continue; } int num2 = chest.GetInventory().CountItems(itemName, -1, true); if (num2 > 0) { if (Claims.Settled(ViewOf(chest))) { num += num2; } else { Request(chest); } } } return num; } public static int Stock(IEnumerable<Container> chests, string itemName) { int num = 0; foreach (Container chest in chests) { if ((Object)(object)chest != (Object)null && !InUse(chest)) { num += chest.GetInventory().CountItems(itemName, -1, true); } } return num; } public static int Take(IEnumerable<Container> chests, string itemName, int amount) { int num = 0; foreach (Container chest in chests) { if (num >= amount) { break; } if ((Object)(object)chest == (Object)null || InUse(chest)) { continue; } Inventory inventory = chest.GetInventory(); if (inventory.CountItems(itemName, -1, true) <= 0) { continue; } if (!Ready(chest)) { Request(chest); continue; } int num2 = Math.Min(inventory.CountItems(itemName, -1, true), amount - num); if (num2 > 0) { inventory.RemoveItem(itemName, num2, -1, true); num += num2; } } return num; } public static ItemData TakeOne(IEnumerable<Container> chests, string itemName, out Container from) { from = null; foreach (Container chest in chests) { if ((Object)(object)chest == (Object)null || InUse(chest) || chest.GetInventory().CountItems(itemName, -1, true) <= 0) { continue; } if (!Ready(chest)) { Request(chest); continue; } Inventory inventory = chest.GetInventory(); ItemData val = ((IEnumerable<ItemData>)inventory.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => i.m_shared.m_name == itemName && i.m_worldLevel >= Game.m_worldLevel)); if (val != null) { ItemData val2 = val.Clone(); val2.m_stack = 1; if (inventory.RemoveItem(val, 1)) { from = chest; return val2; } } } return null; } public static void PutBack(ItemData item, Container from, Player player, Vector3 at) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) if (item != null && (!((Object)(object)from != (Object)null) || InUse(from) || !Ready(from) || !from.GetInventory().AddItem(item)) && (!((Object)(object)player != (Object)null) || !((Humanoid)player).GetInventory().AddItem(item))) { ItemDrop.DropItem(item, 1, at + Vector3.up, Quaternion.identity); } } public static int OwnCount(Inventory inventory, string itemName) { int num = 0; foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_shared.m_name == itemName && allItem.m_worldLevel >= Game.m_worldLevel) { num += allItem.m_stack; } } return num; } public static int AddToChestHolding(Vector3 origin, ItemDrop item, int count, float radius) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) string name = item.m_itemData.m_shared.m_name; foreach (Container item2 in Near(origin, radius)) { if ((Object)(object)item2 == (Object)null || InUse(item2) || item2.GetInventory().CountItems(name, -1, true) <= 0) { continue; } if (!Ready(item2)) { Request(item2); continue; } Inventory inventory = item2.GetInventory(); if (!inventory.CanAddItem(((Component)item).gameObject, count)) { continue; } int num = inventory.CountItems(name, -1, true); inventory.AddItem(((Component)item).gameObject, count); return inventory.CountItems(name, -1, true) - num; } return 0; } } internal static class Claims { private class Claim { public float At; public float RetryAt = -1f; } private const float Settle = 1f; private const float Retry = 5f; private const float Forget = 10f; private static readonly Dictionary<(long, uint), Claim> Recent = new Dictionary<(long, uint), Claim>(); private static float _prunedAt; private static (long, uint) Id(ZDOID uid) { return (((ZDOID)(ref uid)).UserID, ((ZDOID)(ref uid)).ID); } private static Claim Find((long, uint) id, float now) { if (!Recent.TryGetValue(id, out var value)) { return null; } if ((value.RetryAt >= 0f) ? (now < value.RetryAt) : (now - value.At < 10f)) { return value; } Recent.Remove(id); return null; } public static bool Settled(ZNetView view) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)view == (Object)null || !view.IsValid()) { return false; } float unscaledTime = Time.unscaledTime; Claim claim = Find(Id(view.GetZDO().m_uid), unscaledTime); if (!view.IsOwner()) { if (claim != null && claim.RetryAt < 0f) { claim.RetryAt = unscaledTime + 5f; } return false; } if (claim != null) { return unscaledTime - claim.At >= 1f; } return true; } public static void Request(ZNetView view) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)view == (Object)null || !view.IsValid() || view.IsOwner()) { return; } float unscaledTime = Time.unscaledTime; if (unscaledTime - _prunedAt > 30f) { _prunedAt = unscaledTime; foreach (var item in new List<(long, uint)>(Recent.Keys)) { Find(item, unscaledTime); } } Claim claim = Find(Id(view.GetZDO().m_uid), unscaledTime); if (claim != null) { if (claim.RetryAt < 0f) { claim.RetryAt = unscaledTime + 5f; } } else { Take(view); } } public static void Take(ZNetView view) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)view == (Object)null) && view.IsValid() && !view.IsOwner()) { view.ClaimOwnership(); Recent[Id(view.GetZDO().m_uid)] = new Claim { At = Time.unscaledTime }; } } public static void Clear() { Recent.Clear(); } } internal static class ContainerRegistry { private static readonly List<Container> All = new List<Container>(); public static void Register(Container c) { if ((Object)(object)c != (Object)null && !((Object)c).name.StartsWith("piece_recycler") && !All.Contains(c)) { All.Add(c); } } public static void Seed() { Container[] array = Object.FindObjectsOfType<Container>(); foreach (Container c in array) { Register(c); } } public static List<Container> Alive() { All.RemoveAll((Container c) => (Object)(object)c == (Object)null); return All; } public static void Clear() { All.Clear(); } } [HarmonyPatch(typeof(Container), "Awake")] internal static class Container_Awake { private static void Postfix(Container __instance) { ContainerRegistry.Register(__instance); } } internal static class Cooking { private static readonly List<CookingStation> All = new List<CookingStation>(); private static readonly MethodInfo GetSlotM = AccessTools.Method(typeof(CookingStation), "GetSlot", (Type[])null, (Type[])null); private static readonly MethodInfo IsItemDoneM = AccessTools.Method(typeof(CookingStation), "IsItemDone", (Type[])null, (Type[])null); private static readonly MethodInfo HaveDoneItemM = AccessTools.Method(typeof(CookingStation), "HaveDoneItem", (Type[])null, (Type[])null); private static readonly MethodInfo OnInteractM = AccessTools.Method(typeof(CookingStation), "OnInteract", (Type[])null, (Type[])null); private static readonly MethodInfo GetFreeSlotM = AccessTools.Method(typeof(CookingStation), "GetFreeSlot", (Type[])null, (Type[])null); private static readonly MethodInfo GetFuelM = AccessTools.Method(typeof(CookingStation), "GetFuel", (Type[])null, (Type[])null); private static readonly MethodInfo ConversionM = AccessTools.Method(typeof(CookingStation), "GetItemConversion", (Type[])null, (Type[])null); private static float _next; internal static Player DeliverTo; internal static CookingStation AutoFrom; internal static Vector3 AutoToward; private static float _hoverAt; private static CookingStation _hoverFor; private static string _hoverText = ""; public static void Register(CookingStation s) { if ((Object)(object)s != (Object)null && !All.Contains(s)) { All.Add(s); } } public static void Seed() { CookingStation[] array = Object.FindObjectsOfType<CookingStation>(); foreach (CookingStation s in array) { Register(s); } } public static void Clear() { All.Clear(); DeliverTo = null; AutoFrom = null; } public static bool HasDone(CookingStation s) { if (HaveDoneItemM != null && (Object)(object)s != (Object)null) { return (bool)HaveDoneItemM.Invoke(s, null); } return false; } public static bool HasFreeSlot(CookingStation s) { if (GetFreeSlotM != null) { return (int)GetFreeSlotM.Invoke(s, null) >= 0; } return false; } public static float Fuel(CookingStation s) { if (!(GetFuelM != null)) { return 0f; } return (float)GetFuelM.Invoke(s, null); } public static void Slot(CookingStation s, int i, out string item, out float cooked, out int status) { object[] array = new object[5] { i, null, null, null, null }; GetSlotM.Invoke(s, array); item = (string)array[1]; cooked = (float)array[2]; status = (int)array[3]; } public static float CookTime(CookingStation s, string item) { object obj = ((ConversionM != null) ? ConversionM.Invoke(s, new object[1] { item }) : null); if (obj == null) { return 0f; } return (float)AccessTools.Field(obj.GetType(), "m_cookTime").GetValue(obj); } public static int TakeAllInto(Player player, CookingStation s) { ZNetView component = ((Component)s).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || OnInteractM == null) { return 0; } if (!component.HasOwner()) { component.ClaimOwnership(); } if (!Claims.Settled(component)) { return 0; } int num = 0; DeliverTo = player; try { for (int i = 0; i < s.m_slots.Length; i++) { if (!HasDone(s)) { break; } OnInteractM.Invoke(s, new object[1] { player }); num++; } } finally { DeliverTo = null; } return num; } public static void Tick(Plugin plugin, Player player, float range, bool takeOffDefault) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime < _next) { return; } _next = Time.unscaledTime + 0.5f; All.RemoveAll((CookingStation s) => (Object)(object)s == (Object)null); float num = range * range; CookingStation[] array = All.ToArray(); foreach (CookingStation val in array) { Vector3 val2 = ((Component)val).transform.position - ((Component)player).transform.position; if (((Vector3)(ref val2)).sqrMagnitude > num) { continue; } ZNetView component = ((Component)val).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { continue; } if (!component.IsOwner()) { if (component.HasOwner()) { continue; } component.ClaimOwnership(); } if (Claims.Settled(component)) { AutoSetting autoSetting = AutoFeed.Read((MonoBehaviour)(object)val); if (autoSetting.TakeOff && takeOffDefault) { TakeOffDone(val, ((Component)player).transform.position); } if (autoSetting.On && autoSetting.Allowed.Count > 0) { plugin.CookAutoStep(player, val, autoSetting); } } } } private static void TakeOffDone(CookingStation s, Vector3 toward) { //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_0025: Unknown result type (might be due to invalid IL or missing references) ZNetView component = ((Component)s).GetComponent<ZNetView>(); AutoFrom = s; AutoToward = toward; try { for (int i = 0; i < s.m_slots.Length; i++) { if (!HasDone(s)) { break; } component.InvokeRPC("RPC_RemoveDoneItem", new object[2] { toward, 1 }); } } finally { AutoFrom = null; } } public static string CategoryOf(SharedData s) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: