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 SorosQualityOfLife v1.0.21
SorosQualityOfLife.dll
Decompiled 11 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("SorosQualityOfLife")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.21.0")] [assembly: AssemblyInformationalVersion("1.0.21")] [assembly: AssemblyProduct("SorosQualityOfLife")] [assembly: AssemblyTitle("SorosQualityOfLife")] [assembly: AssemblyVersion("1.0.21.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 SorosQualityOfLife { internal static class Acc { public delegate void GetSlotD(CookingStation c, int slot, out string item, out float time, out Status status, out bool cheated); public delegate void SetSlotD(CookingStation c, int slot, string item, float time, Status status, bool cheated); public static FieldRef<BaseAI, ZSyncAnimation> BaseAI_animator; public static FieldRef<Beehive, ZNetView> Beehive_nview; public static FieldRef<Container, ZNetView> Container_nview; public static FieldRef<CookingStation, ZNetView> Cooking_nview; public static FieldRef<Fermenter, ZNetView> Fermenter_nview; public static FieldRef<Fireplace, ZNetView> Fireplace_nview; public static FieldRef<SapCollector, ZNetView> Sap_nview; public static FieldRef<Smelter, ZNetView> Smelter_nview; public static FieldRef<Tameable, ZNetView> Tameable_nview; public static FieldRef<Tameable, MonsterAI> Tameable_monsterAI; public static FieldRef<InventoryGui, InventoryGrid> Gui_containerGrid; public static FieldRef<InventoryGui, Recipe> Gui_craftRecipe; public static FieldRef<InventoryGui, ItemData> Gui_craftUpgradeItem; public static FieldRef<InventoryGui, Container> Gui_currentContainer; public static FieldRef<InventoryGui, int> Gui_dragAmount; public static FieldRef<InventoryGui, Inventory> Gui_dragInventory; public static FieldRef<InventoryGui, ItemData> Gui_dragItem; public static FieldRef<InventoryGui, bool> Gui_multiCrafting; public static FieldRef<Player, List<Food>> Player_foods; public static FieldRef<ZNetScene, Dictionary<int, GameObject>> Scene_namedPrefabs; private static FieldInfo _reqUpgrader; public static Func<Beehive, int> Beehive_GetHoneyLevel; public static Func<SapCollector, int> Sap_GetLevel; public static Func<Container, long, bool> Container_CheckAccess; public static Action<Container> Container_CheckForChanges; public static Func<CookingStation, float> Cooking_GetFuel; public static Func<CookingStation, bool> Cooking_IsFireLit; public static Func<CookingStation, ItemData, bool> Cooking_IsItemAllowed; public static Func<CookingStation, string, bool> Cooking_IsItemDone; public static GetSlotD Cooking_GetSlot; public static SetSlotD Cooking_SetSlot; public static Func<Fermenter, string> Fermenter_GetContentName; public static Func<Fermenter, int, ItemConversion> Fermenter_GetConversion; public static Func<Fermenter, Status> Fermenter_GetStatus; public static Func<Fermenter, ItemData, bool> Fermenter_IsItemAllowed; public static Action<InventoryGui, ItemData, Inventory, int> Gui_SetupDragItem; public static Action<InventoryGui, bool> Gui_UpdateCraftingPanel; public static Func<Smelter, float> Smelter_GetFuel; public static Func<Smelter, string, ItemConversion> Smelter_GetConversion; public static Func<Smelter, int> Smelter_GetQueueSize; public static Func<Smelter, ItemData, bool> Smelter_IsItemAllowed; public static Action<Smelter> Smelter_SpawnProcessed; public static Action<Tameable, ItemDrop> Tameable_OnConsumedItem; public static readonly List<string> Failed = new List<string>(); private static FieldInfo _stUpgrader; private static bool _stUpgraderInit; private static MethodInfo _effCreate; private static MethodInfo _msg; private static FieldRef<T, F> F<T, F>(string name) { try { return AccessTools.FieldRefAccess<T, F>(name); } catch (Exception ex) { Failed.Add(typeof(T).Name + "." + name + " (" + ex.Message + ")"); return null; } } private static D M<D>(Type t, string name, Type[] args = null) where D : Delegate { try { MethodInfo methodInfo = AccessTools.Method(t, name, args, (Type[])null); if (methodInfo == null) { Failed.Add(t.Name + "." + name + "()"); return null; } return AccessTools.MethodDelegate<D>(methodInfo, (object)null, true); } catch (Exception ex) { Failed.Add(t.Name + "." + name + "() (" + ex.Message + ")"); return null; } } public static void Init() { BaseAI_animator = F<BaseAI, ZSyncAnimation>("m_animator"); Beehive_nview = F<Beehive, ZNetView>("m_nview"); Container_nview = F<Container, ZNetView>("m_nview"); Cooking_nview = F<CookingStation, ZNetView>("m_nview"); Fermenter_nview = F<Fermenter, ZNetView>("m_nview"); Fireplace_nview = F<Fireplace, ZNetView>("m_nview"); Sap_nview = F<SapCollector, ZNetView>("m_nview"); Smelter_nview = F<Smelter, ZNetView>("m_nview"); Tameable_nview = F<Tameable, ZNetView>("m_nview"); Tameable_monsterAI = F<Tameable, MonsterAI>("m_monsterAI"); Gui_containerGrid = F<InventoryGui, InventoryGrid>("m_containerGrid"); Gui_craftRecipe = F<InventoryGui, Recipe>("m_craftRecipe"); Gui_craftUpgradeItem = F<InventoryGui, ItemData>("m_craftUpgradeItem"); Gui_currentContainer = F<InventoryGui, Container>("m_currentContainer"); Gui_dragAmount = F<InventoryGui, int>("m_dragAmount"); Gui_dragInventory = F<InventoryGui, Inventory>("m_dragInventory"); Gui_dragItem = F<InventoryGui, ItemData>("m_dragItem"); Gui_multiCrafting = F<InventoryGui, bool>("m_multiCrafting"); Player_foods = F<Player, List<Food>>("m_foods"); Scene_namedPrefabs = F<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs"); _reqUpgrader = AccessTools.Field(typeof(Requirement), "m_upgraderResource"); Beehive_GetHoneyLevel = M<Func<Beehive, int>>(typeof(Beehive), "GetHoneyLevel"); Sap_GetLevel = M<Func<SapCollector, int>>(typeof(SapCollector), "GetLevel"); Container_CheckAccess = M<Func<Container, long, bool>>(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }); Container_CheckForChanges = M<Action<Container>>(typeof(Container), "CheckForChanges"); Cooking_GetFuel = M<Func<CookingStation, float>>(typeof(CookingStation), "GetFuel"); Cooking_IsFireLit = M<Func<CookingStation, bool>>(typeof(CookingStation), "IsFireLit"); Cooking_IsItemAllowed = M<Func<CookingStation, ItemData, bool>>(typeof(CookingStation), "IsItemAllowed", new Type[1] { typeof(ItemData) }); Cooking_IsItemDone = M<Func<CookingStation, string, bool>>(typeof(CookingStation), "IsItemDone", new Type[1] { typeof(string) }); Cooking_GetSlot = M<GetSlotD>(typeof(CookingStation), "GetSlot"); Cooking_SetSlot = M<SetSlotD>(typeof(CookingStation), "SetSlot"); Fermenter_GetContentName = M<Func<Fermenter, string>>(typeof(Fermenter), "GetContentName"); Fermenter_GetConversion = M<Func<Fermenter, int, ItemConversion>>(typeof(Fermenter), "GetItemConversion", new Type[1] { typeof(int) }); Fermenter_GetStatus = M<Func<Fermenter, Status>>(typeof(Fermenter), "GetStatus"); Fermenter_IsItemAllowed = M<Func<Fermenter, ItemData, bool>>(typeof(Fermenter), "IsItemAllowed", new Type[1] { typeof(ItemData) }); Gui_SetupDragItem = M<Action<InventoryGui, ItemData, Inventory, int>>(typeof(InventoryGui), "SetupDragItem"); Gui_UpdateCraftingPanel = M<Action<InventoryGui, bool>>(typeof(InventoryGui), "UpdateCraftingPanel"); Smelter_GetFuel = M<Func<Smelter, float>>(typeof(Smelter), "GetFuel"); Smelter_GetConversion = M<Func<Smelter, string, ItemConversion>>(typeof(Smelter), "GetItemConversion", new Type[1] { typeof(string) }); Smelter_GetQueueSize = M<Func<Smelter, int>>(typeof(Smelter), "GetQueueSize"); Smelter_IsItemAllowed = M<Func<Smelter, ItemData, bool>>(typeof(Smelter), "IsItemAllowed", new Type[1] { typeof(ItemData) }); Smelter_SpawnProcessed = M<Action<Smelter>>(typeof(Smelter), "SpawnProcessed"); Tameable_OnConsumedItem = M<Action<Tameable, ItemDrop>>(typeof(Tameable), "OnConsumedItem", new Type[1] { typeof(ItemDrop) }); } public static ZNetView NView(Container c) { if (!((Object)(object)c == (Object)null)) { return Container_nview.Invoke(c); } return null; } public static ZNetView NView(Smelter c) { if (!((Object)(object)c == (Object)null)) { return Smelter_nview.Invoke(c); } return null; } public static ZNetView NView(CookingStation c) { if (!((Object)(object)c == (Object)null)) { return Cooking_nview.Invoke(c); } return null; } public static ZNetView NView(Fermenter c) { if (!((Object)(object)c == (Object)null)) { return Fermenter_nview.Invoke(c); } return null; } public static ZNetView NView(Fireplace c) { if (!((Object)(object)c == (Object)null)) { return Fireplace_nview.Invoke(c); } return null; } public static ZNetView NView(Beehive c) { if (!((Object)(object)c == (Object)null)) { return Beehive_nview.Invoke(c); } return null; } public static ZNetView NView(SapCollector c) { if (!((Object)(object)c == (Object)null)) { return Sap_nview.Invoke(c); } return null; } public static ZNetView NView(Tameable c) { if (!((Object)(object)c == (Object)null)) { return Tameable_nview.Invoke(c); } return null; } public static Container CurrentContainer(InventoryGui g) { if (!((Object)(object)g == (Object)null) && Gui_currentContainer != null) { return Gui_currentContainer.Invoke(g); } return null; } public static bool StationIsUpgrader(CraftingStation st) { if (!_stUpgraderInit) { _stUpgraderInit = true; _stUpgrader = AccessTools.Field(typeof(CraftingStation), "m_upgrader"); } try { return (Object)(object)st != (Object)null && _stUpgrader != null && (bool)_stUpgrader.GetValue(st); } catch { return false; } } public static bool IsUpgraderResource(Requirement r) { if (_reqUpgrader != null) { return (bool)_reqUpgrader.GetValue(r); } return false; } public static bool Probe(out string why) { why = null; try { Init(); } catch (Exception ex) { why = ex.ToString(); return false; } if (Gui_currentContainer == null || Container_nview == null || Player_foods == null) { why = "missing core members: " + string.Join(", ", Failed); return false; } return true; } internal static void Effects(EffectList e, Vector3 pos, Quaternion rot) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) try { if (e == null) { return; } if (_effCreate == null) { _effCreate = AccessTools.Method(typeof(EffectList), "Create", (Type[])null, (Type[])null); } if (!(_effCreate == null)) { ParameterInfo[] parameters = _effCreate.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { array[i] = (parameters[i].HasDefaultValue ? parameters[i].DefaultValue : (parameters[i].ParameterType.IsValueType ? Activator.CreateInstance(parameters[i].ParameterType) : null)); } array[0] = pos; if (parameters.Length > 1) { array[1] = rot; } _effCreate.Invoke(e, array); } } catch { } } internal static void Msg(string text) { try { if ((Object)(object)MessageHud.instance == (Object)null) { return; } if (_msg == null) { _msg = AccessTools.Method(typeof(MessageHud), "ShowMessage", (Type[])null, (Type[])null); } if (!(_msg == null)) { ParameterInfo[] parameters = _msg.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { array[i] = (parameters[i].HasDefaultValue ? parameters[i].DefaultValue : (parameters[i].ParameterType.IsValueType ? Activator.CreateInstance(parameters[i].ParameterType) : null)); } array[0] = (object)(MessageType)2; array[1] = text; _msg.Invoke(MessageHud.instance, array); } } catch { } } } internal static class AnimalFeeder { [HarmonyPatch(typeof(Tameable), "Awake")] private static class TameableAwake { private static void Postfix(Tameable __instance) { Safe.Run("Reg.Tameable", delegate { ZNetView nv = Acc.NView(__instance); if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null) { nv.Register<string>("SoroQoL_Feed", (Action<long, string>)delegate(long sender, string prefab) { Safe.Run("Feed", delegate { if (nv.IsOwner()) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab); ItemDrop val = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null); MonsterAI val2 = Acc.Tameable_monsterAI.Invoke(__instance); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null)) { if (val2.m_onConsumedItem != null) { val2.m_onConsumedItem(val); } else { Acc.Tameable_OnConsumedItem(__instance, val); } ZSyncAnimation obj = Acc.BaseAI_animator.Invoke((BaseAI)(object)val2); if (obj != null) { obj.SetTrigger("consume"); } } } }); }); } }); } } internal const string RpcFeed = "SoroQoL_Feed"; private static readonly Dictionary<ZDOID, float> _cooldown = new Dictionary<ZDOID, float>(); public static void Tick(SpecialChest chest, Inventory inv) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)chest).transform.position; float range = chest.Range; foreach (Character allCharacter in Character.GetAllCharacters()) { if ((Object)(object)allCharacter == (Object)null || allCharacter.IsPlayer() || allCharacter.IsDead() || Vector3.Distance(((Component)allCharacter).transform.position, position) > range) { continue; } Tameable component = ((Component)allCharacter).GetComponent<Tameable>(); MonsterAI component2 = ((Component)allCharacter).GetComponent<MonsterAI>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || component2.m_consumeItems == null || component2.m_consumeItems.Count == 0) { continue; } ZNetView val = Acc.NView(component); if ((Object)(object)val == (Object)null || !val.IsValid()) { continue; } bool flag = allCharacter.IsTamed(); if ((flag && !Cfg.FeedTamed) || (!flag && (!Cfg.FeedWild || component.m_tamingTime <= 0f)) || !component.IsHungry()) { continue; } ZDOID uid = val.GetZDO().m_uid; if (_cooldown.TryGetValue(uid, out var value) && Time.time < value) { continue; } ItemData val2 = null; ItemDrop val3 = null; foreach (ItemData it in inv.GetAllItems()) { val3 = ((IEnumerable<ItemDrop>)component2.m_consumeItems).FirstOrDefault((Func<ItemDrop, bool>)((ItemDrop c) => Object.op_Implicit((Object)(object)c) && c.m_itemData.m_shared.m_name == it.m_shared.m_name)); if (Object.op_Implicit((Object)(object)val3)) { val2 = it; break; } } if (val2 != null && val.IsOwner() && inv.RemoveItem(val2, 1)) { _cooldown[uid] = Time.time + Cfg.AnimalCooldown; val.InvokeRPC("SoroQoL_Feed", new object[1] { ((Object)((Component)val3).gameObject).name }); } } } } public enum ChestMode { All, Smelter, BlastFurnace, Kiln, EitrRefinery, Fermenter, Beehive, SapCollector, CookingStation, Oven, Fuel, WindmillSpinningWheel, AnimalFeeding, Windmill, SpinningWheel } public enum StationKind { Other, Smelter, BlastFurnace, Kiln, EitrRefinery, Fermenter, Beehive, SapCollector, CookingStation, Oven, Fire, Windmill, HotTub, SpinningWheel } internal static class Kinds { public static readonly ChestMode[] PickerOrder = new ChestMode[15] { ChestMode.All, ChestMode.Smelter, ChestMode.BlastFurnace, ChestMode.Kiln, ChestMode.EitrRefinery, ChestMode.Fermenter, ChestMode.Beehive, ChestMode.SapCollector, ChestMode.CookingStation, ChestMode.Oven, ChestMode.Windmill, ChestMode.SpinningWheel, ChestMode.WindmillSpinningWheel, ChestMode.Fuel, ChestMode.AnimalFeeding }; public static readonly string[] ModeLabels = new string[15] { "All", "Smelter", "Blast Furnace", "Kiln", "Eitr Refinery", "Fermenter", "Beehive", "Sap Collector", "Cooking Station", "Oven", "Fuel", "Windmill + Spinning Wheel (old)", "Animal Feeding", "Windmill", "Spinning Wheel" }; public static string Label(ChestMode m) { if (m < ChestMode.All || (int)m >= ModeLabels.Length) { return "All"; } return ModeLabels[(int)m]; } public static StationKind Of(Smelter s) { return s.m_name switch { "$piece_smelter" => StationKind.Smelter, "$piece_blastfurnace" => StationKind.BlastFurnace, "$piece_charcoalkiln" => StationKind.Kiln, "$piece_eitrrefinery" => StationKind.EitrRefinery, "$piece_windmill" => StationKind.Windmill, "$piece_spinningwheel" => StationKind.SpinningWheel, "$piece_bathtub" => StationKind.HotTub, _ => StationKind.Other, }; } public static StationKind Of(CookingStation c) { if (!(c.m_name == "$piece_oven")) { return StationKind.CookingStation; } return StationKind.Oven; } public static bool Matches(ChestMode m, StationKind k) { switch (m) { case ChestMode.All: return true; case ChestMode.Smelter: return k == StationKind.Smelter; case ChestMode.BlastFurnace: return k == StationKind.BlastFurnace; case ChestMode.Kiln: return k == StationKind.Kiln; case ChestMode.EitrRefinery: return k == StationKind.EitrRefinery; case ChestMode.Fermenter: return k == StationKind.Fermenter; case ChestMode.Beehive: return k == StationKind.Beehive; case ChestMode.SapCollector: return k == StationKind.SapCollector; case ChestMode.CookingStation: return k == StationKind.CookingStation; case ChestMode.Oven: return k == StationKind.Oven; case ChestMode.Fuel: return true; case ChestMode.WindmillSpinningWheel: if (k != StationKind.Windmill) { return k == StationKind.SpinningWheel; } return true; case ChestMode.Windmill: return k == StationKind.Windmill; case ChestMode.SpinningWheel: return k == StationKind.SpinningWheel; default: return false; } } } internal static class ChestPickerGui { private static Rect _rect = new Rect(20f, 120f, 260f, 0f); private static SpecialChest _dragChest; private static SpecialChest _nameChest; private static string _nameBuf = ""; internal static bool Typing; private const string NameCtl = "SoroQoL_Name"; private const string TargetCtl = "SoroQoL_Target"; private static string _targetBuf = ""; private static float _dragValue; private static void TextRow(string label, string ctl, ref string buf, string current, Action<string> save, ref bool typing) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Invalid comparison between Unknown and I4 //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Invalid comparison between Unknown and I4 GUILayout.Label(label, Array.Empty<GUILayoutOption>()); Event current2 = Event.current; bool num = GUI.GetNameOfFocusedControl() == ctl; bool flag = num && (int)current2.type == 4 && ((int)current2.keyCode == 13 || (int)current2.keyCode == 271); bool flag2 = num && (int)current2.type == 4 && (int)current2.keyCode == 27; GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUI.SetNextControlName(ctl); buf = GUILayout.TextField(buf ?? "", 30, Array.Empty<GUILayoutOption>()); bool num2 = GUILayout.Button("Save", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }); GUILayout.EndHorizontal(); if (num2 || flag) { save(buf); buf = SpecialChest.Sanitize(buf); GUI.FocusControl((string)null); if (flag) { current2.Use(); } } else if (flag2) { GUI.FocusControl((string)null); buf = current; current2.Use(); } if (GUI.GetNameOfFocusedControl() == ctl) { typing = true; } } private static void List(ChestMode cur, bool push, Action<ChestMode> set) { ChestMode[] pickerOrder = Kinds.PickerOrder; foreach (ChestMode chestMode in pickerOrder) { if ((push || !SpecialChest.InputOnly(chestMode)) && (chestMode != ChestMode.WindmillSpinningWheel || cur == chestMode) && GUILayout.Toggle(cur == chestMode, Kinds.Label(chestMode), Array.Empty<GUILayoutOption>()) && cur != chestMode) { set(chestMode); } } } public static void Draw() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) if (!Cfg.StationChests) { Typing = false; return; } InventoryGui instance = InventoryGui.instance; Container val = Acc.CurrentContainer(instance); if ((Object)(object)instance == (Object)null || !InventoryGui.IsVisible() || (Object)(object)val == (Object)null) { Typing = false; _nameChest = null; return; } SpecialChest sc = ((Component)val).GetComponent<SpecialChest>(); if ((Object)(object)sc == (Object)null || !SettingsButton.Open) { Typing = false; _nameChest = null; return; } _rect = GUILayout.Window(20640, _rect, (WindowFunction)delegate { if ((Object)(object)_nameChest != (Object)(object)sc) { _nameChest = sc; _nameBuf = sc.CustomName; _targetBuf = sc.TargetName; } bool typing = false; TextRow("Name (empty = default):", "SoroQoL_Name", ref _nameBuf, sc.CustomName, sc.RequestName, ref typing); if (sc.IsTransfer) { TextRow("Target chest name:", "SoroQoL_Target", ref _targetBuf, sc.TargetName, sc.RequestTarget, ref typing); } Typing = typing; int role = sc.Role; bool isFeeder = sc.IsFeeder; if (isFeeder && sc.Paused) { GUILayout.Label("Feeding is PAUSED (converted old chest). Items stay in the chest.", Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Resume feeding", Array.Empty<GUILayoutOption>())) { sc.RequestPaused(paused: false); } } if (!sc.IsTransfer) { GUILayout.Label("Role:", Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); for (int i = 0; i <= 1; i++) { if (GUILayout.Toggle(role == i, SpecialChest.RoleLabel(i), Array.Empty<GUILayoutOption>()) && role != i) { sc.RequestRole(i); } } GUILayout.EndHorizontal(); } GUILayout.Label(isFeeder ? "Push into:" : "Collect from:", Array.Empty<GUILayoutOption>()); List(sc.Mode, isFeeder, sc.RequestMode); float num = (((Object)(object)_dragChest == (Object)(object)sc && _dragValue > 0f) ? _dragValue : sc.Range); GUILayout.Label($"Range: {num:0} m", Array.Empty<GUILayoutOption>()); float num2 = Mathf.Round(GUILayout.HorizontalSlider(num, 5f, Mathf.Floor(sc.MaxRange), Array.Empty<GUILayoutOption>())); if (Mathf.Abs(num2 - num) >= 1f) { _dragChest = sc; _dragValue = num2; sc.RequestRange(num2); } else if ((Object)(object)_dragChest == (Object)(object)sc && Mathf.Abs(sc.Range - _dragValue) < 0.5f) { _dragValue = 0f; } GUI.DragWindow(); }, "Soro's QoL", Array.Empty<GUILayoutOption>()); } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class SpecialChestHover { private static void Postfix(Container __instance, ref string __result) { try { PostfixImpl(__instance, ref __result); } catch (Exception e) { Safe.Report("ChestPickerGui.cs:Postfix", e); } } private static void PostfixImpl(Container __instance, ref string __result) { try { SpecialChest component = ((Component)__instance).GetComponent<SpecialChest>(); if (!((Object)(object)component == (Object)null)) { string customName = component.CustomName; if (customName.Length > 0) { string text = __instance.m_name ?? ""; int num = ((text.Length > 0) ? __result.IndexOf(text, StringComparison.Ordinal) : (-1)); __result = ((num >= 0) ? (__result.Substring(0, num) + "\"" + customName + "\" (" + text + ")" + __result.Substring(num + text.Length)) : ("\"" + customName + "\"\n" + __result)); } if (component.IsTransfer) { __result = __result + "\nMode: " + Kinds.Label(component.Mode); string targetName = component.TargetName; __result += ((targetName.Length == 0) ? "\n→ (no target set)" : ("\n→ \"" + targetName + "\" (" + component.TransferStatus() + ")")); } else { __result = __result + "\nRole: " + SpecialChest.RoleLabel(component.Role) + ((component.IsFeeder && component.Paused) ? " (paused)" : "") + "\nMode: " + Kinds.Label(component.Mode); } } } catch (Exception e) { Safe.Report("Hover", e); } } } [HarmonyPatch(typeof(InventoryGui), "Update")] internal static class SettingsButton { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__5_0; internal void <Create>b__5_0() { Open = !Open; } } internal static bool Open; private static Button _btn; private static Container _last; private static void Postfix(InventoryGui __instance) { try { PostfixImpl(__instance); } catch (Exception e) { Safe.Report("SettingsButton", e); } } private static void PostfixImpl(InventoryGui gui) { Container val = (InventoryGui.IsVisible() ? Acc.CurrentContainer(gui) : null); if ((Object)(object)val != (Object)(object)_last) { Open = false; _last = val; } bool flag = Plugin.Enabled && Cfg.StationChests && (Object)(object)val != (Object)null && (Object)(object)((Component)val).GetComponent<SpecialChest>() != (Object)null; if (flag && (Object)(object)_btn == (Object)null) { Create(gui); } if ((Object)(object)_btn != (Object)null && ((Component)_btn).gameObject.activeSelf != flag) { ((Component)_btn).gameObject.SetActive(flag); } } private static void Create(InventoryGui gui) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown Button stackAllButton = gui.m_stackAllButton; if ((Object)(object)stackAllButton == (Object)null) { return; } GameObject val = Object.Instantiate<GameObject>(((Component)stackAllButton).gameObject, ((Component)stackAllButton).transform.parent); ((Object)val).name = "SoroQoL_Settings"; MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren) { string name = ((object)val2).GetType().Name; if (name == "UIGamePad" || name == "Localize") { Object.DestroyImmediate((Object)(object)val2); } } foreach (Transform item in val.transform) { Transform val3 = item; if (((Object)val3).name.ToLowerInvariant().Contains("gamepad") || ((Object)val3).name.ToLowerInvariant().Contains("hint")) { ((Component)val3).gameObject.SetActive(false); } } RectTransform val4 = (RectTransform)val.transform; RectTransform val5 = (RectTransform)((Component)stackAllButton).transform; Vector2 anchoredPosition = val5.anchoredPosition; Rect rect = val5.rect; val4.anchoredPosition = anchoredPosition + new Vector2(((Rect)(ref rect)).width + 10f, 0f); TMP_Text componentInChildren = val.GetComponentInChildren<TMP_Text>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = "Settings"; } _btn = val.GetComponent<Button>(); _btn.onClick = new ButtonClickedEvent(); ButtonClickedEvent onClick = _btn.onClick; object obj = <>c.<>9__5_0; if (obj == null) { UnityAction val6 = delegate { Open = !Open; }; <>c.<>9__5_0 = val6; obj = (object)val6; } ((UnityEvent)onClick).AddListener((UnityAction)obj); ((Selectable)_btn).interactable = true; } } [HarmonyPatch(typeof(Container), "GetHoverName")] internal static class SpecialChestName { private static void Postfix(Container __instance, ref string __result) { try { SpecialChest specialChest = (Object.op_Implicit((Object)(object)__instance) ? ((Component)__instance).GetComponent<SpecialChest>() : null); string text = (((Object)(object)specialChest != (Object)null) ? specialChest.CustomName : ""); if (text.Length > 0) { __result = text; } } catch (Exception e) { Safe.Report("SpecialChestName", e); } } } [HarmonyPatch(typeof(Chat), "HasFocus")] internal static class BlockInput { private static void Postfix(ref bool __result) { try { if (ChestPickerGui.Typing && Plugin.Enabled) { __result = true; } } catch (Exception e) { Safe.Report("BlockInput", e); } } } internal static class CollectorLogic { [HarmonyPatch(typeof(Smelter), "Awake")] private static class SmelterAwake { private static void Postfix(Smelter __instance) { Safe.Run("Reg.Smelter", delegate { ZNetView nv = Acc.NView(__instance); if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null) { nv.Register<ZDOID>("SoroQoL_Collect", (Action<long, ZDOID>)delegate { Safe.Run("Collect.Smelter", delegate { if (nv.IsOwner()) { Acc.Smelter_SpawnProcessed(__instance); } }); }); } }); } } [HarmonyPatch(typeof(Smelter), "Spawn")] private static class SmelterSpawn { private static bool Prefix(Smelter __instance, string ore, int stack) { try { return PrefixImpl(__instance, ore, stack); } catch (Exception e) { Safe.Report("CollectorLogic.cs:Prefix", e); return true; } } private static bool PrefixImpl(Smelter __instance, string ore, int stack) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) try { if (!Cfg.StationChests || (Object)(object)Acc.NView(__instance) == (Object)null || !Acc.NView(__instance).IsOwner() || stack <= 0) { return true; } ItemConversion val = Acc.Smelter_GetConversion(__instance, ore); if ((Object)(object)val?.m_to == (Object)null) { return true; } StationKind kind = Kinds.Of(__instance); SpecialChest specialChest = SpecialChest.FindCollectors(((Component)__instance).transform.position, kind).FirstOrDefault(); if ((Object)(object)specialChest == (Object)null) { return true; } Send(specialChest, ((Object)((Component)val.m_to).gameObject).name, stack, Object.op_Implicit((Object)(object)__instance.m_outputPoint) ? __instance.m_outputPoint.position : ((Component)__instance).transform.position, kind); Acc.Effects(__instance.m_produceEffects, ((Component)__instance).transform.position, ((Component)__instance).transform.rotation); return false; } catch (Exception e) { Safe.Report("Smelter.Spawn", e); return true; } } } [HarmonyPatch(typeof(Beehive), "Awake")] private static class BeehiveAwake { private static void Postfix(Beehive __instance) { Safe.Run("Reg.Beehive", delegate { ZNetView nv = Acc.NView(__instance); if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null) { nv.Register<ZDOID>("SoroQoL_Collect", (Action<long, ZDOID>)delegate(long sender, ZDOID id) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) Safe.Run("Collect.Beehive", delegate { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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) if (nv.IsOwner()) { SpecialChest specialChest = Resolve(id); int num = Acc.Beehive_GetHoneyLevel(__instance); if (!((Object)(object)specialChest == (Object)null) && num > 0 && !((Object)(object)__instance.m_honeyItem == (Object)null)) { nv.GetZDO().Set(ZDOVars.s_level, 0, false); Acc.Effects(__instance.m_spawnEffect, __instance.m_spawnPoint.position, Quaternion.identity); Send(specialChest, ((Object)((Component)__instance.m_honeyItem).gameObject).name, num, __instance.m_spawnPoint.position, StationKind.Beehive); } } }); }); } }); } } [HarmonyPatch(typeof(SapCollector), "Awake")] private static class SapAwake { private static void Postfix(SapCollector __instance) { Safe.Run("Reg.Sap", delegate { ZNetView nv = Acc.NView(__instance); if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null) { nv.Register<ZDOID>("SoroQoL_Collect", (Action<long, ZDOID>)delegate(long sender, ZDOID id) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) Safe.Run("Collect.Sap", delegate { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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) if (nv.IsOwner()) { SpecialChest specialChest = Resolve(id); int num = Acc.Sap_GetLevel(__instance); if (!((Object)(object)specialChest == (Object)null) && num > 0 && !((Object)(object)__instance.m_spawnItem == (Object)null)) { nv.GetZDO().Set(ZDOVars.s_level, 0, false); Acc.Effects(__instance.m_spawnEffect, __instance.m_spawnPoint.position, Quaternion.identity); Send(specialChest, ((Object)((Component)__instance.m_spawnItem).gameObject).name, num, __instance.m_spawnPoint.position, StationKind.SapCollector); } } }); }); } }); } } [HarmonyPatch(typeof(Fermenter), "Awake")] private static class FermenterAwake { private static void Postfix(Fermenter __instance) { Safe.Run("Reg.Fermenter", delegate { ZNetView nv = Acc.NView(__instance); if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null) { nv.Register<ZDOID>("SoroQoL_Collect", (Action<long, ZDOID>)delegate(long sender, ZDOID id) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) Safe.Run("Collect.Fermenter", delegate { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) if (nv.IsOwner() && (int)Acc.Fermenter_GetStatus(__instance) == 3) { SpecialChest specialChest = Resolve(id); if (!((Object)(object)specialChest == (Object)null)) { string text = Acc.Fermenter_GetContentName(__instance); ItemConversion val = Acc.Fermenter_GetConversion(__instance, StringExtensionMethods.GetStableHashCode(text)); if (!((Object)(object)val?.m_to == (Object)null)) { ZDO zDO = nv.GetZDO(); zDO.Set(ZDOVars.s_content, ""); zDO.Set(ZDOVars.s_startTime, 0L); Acc.Effects(__instance.m_tapEffects, ((Component)__instance).transform.position, ((Component)__instance).transform.rotation); Send(specialChest, ((Object)((Component)val.m_to).gameObject).name, val.m_producedItems, ((Component)__instance).transform.position, StationKind.Fermenter); } } } }); }); } }); } } [HarmonyPatch(typeof(CookingStation), "Awake")] private static class CookingAwake { private static void Postfix(CookingStation __instance) { Safe.Run("Reg.Cooking", delegate { ZNetView nv = Acc.NView(__instance); if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null) { nv.Register<ZDOID>("SoroQoL_Collect", (Action<long, ZDOID>)delegate(long sender, ZDOID id) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) Safe.Run("Collect.Cooking", delegate { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) if (nv.IsOwner()) { SpecialChest specialChest = Resolve(id); if (!((Object)(object)specialChest == (Object)null)) { StationKind kind = Kinds.Of(__instance); for (int i = 0; i < __instance.m_slots.Length; i++) { Acc.Cooking_GetSlot(__instance, i, out var item, out var _, out var _, out var _); if (!string.IsNullOrEmpty(item) && Acc.Cooking_IsItemDone(__instance, item)) { Acc.Cooking_SetSlot(__instance, i, "", 0f, (Status)0, cheated: false); Send(specialChest, item, 1, __instance.m_slots[i].position, kind); } } } } }); }); } }); } } internal const string RpcCollect = "SoroQoL_Collect"; public static void Tick(SpecialChest chest) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Invalid comparison between Unknown and I4 //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) ChestMode mode = chest.Mode; if (mode == ChestMode.AnimalFeeding || mode == ChestMode.Fuel) { return; } Vector3 position = ((Component)chest).transform.position; float range = chest.Range; ZDOID uid = chest.m_nview.GetZDO().m_uid; foreach (Smelter item in SpecialChest.Near<Smelter>(position, range)) { if (Kinds.Matches(mode, Kinds.Of(item)) && Acc.NView(item).GetZDO().GetInt(ZDOVars.s_spawnAmount, 0) > 0) { Ask(Acc.NView(item), uid); } } foreach (Beehive item2 in SpecialChest.Near<Beehive>(position, range)) { if (Kinds.Matches(mode, StationKind.Beehive) && Acc.Beehive_GetHoneyLevel(item2) > 0) { Ask(Acc.NView(item2), uid); } } foreach (SapCollector item3 in SpecialChest.Near<SapCollector>(position, range)) { if (Kinds.Matches(mode, StationKind.SapCollector) && Acc.Sap_GetLevel(item3) > 0) { Ask(Acc.NView(item3), uid); } } foreach (Fermenter item4 in SpecialChest.Near<Fermenter>(position, range)) { if (Kinds.Matches(mode, StationKind.Fermenter) && (int)Acc.Fermenter_GetStatus(item4) == 3) { Ask(Acc.NView(item4), uid); } } foreach (CookingStation item5 in SpecialChest.Near<CookingStation>(position, range)) { if (Kinds.Matches(mode, Kinds.Of(item5)) && HasDone(item5)) { Ask(Acc.NView(item5), uid); } } } private static bool HasDone(CookingStation c) { for (int i = 0; i < c.m_slots.Length; i++) { Acc.Cooking_GetSlot(c, i, out var item, out var _, out var _, out var _); if (!string.IsNullOrEmpty(item) && Acc.Cooking_IsItemDone(c, item)) { return true; } } return false; } private static void Ask(ZNetView nv, ZDOID chest) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (SpecialChest.StationReady(nv)) { SpecialChest.MarkStation(nv); nv.InvokeRPC("SoroQoL_Collect", new object[1] { chest }); } } internal static SpecialChest Resolve(ZDOID id) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null); if (!Object.op_Implicit((Object)(object)val)) { return null; } return val.GetComponent<SpecialChest>(); } internal static void Send(SpecialChest chest, string prefab, int amount, Vector3 origin, StationKind kind) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) ItemData val = ItemNet.FromPrefab(prefab, amount); if (val != null && amount > 0) { chest.m_nview.InvokeRPC("SoroQoL_Store", new object[1] { SpecialChest.StorePkg(val, origin, kind, 0) }); } } } internal static class ConfigSync { [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class RegisterPatch { private static void Postfix(ZNetPeer peer) { try { PostfixImpl(peer); } catch (Exception e) { Safe.Report("ConfigSync.cs:Postfix", e); } } private static void PostfixImpl(ZNetPeer peer) { Safe.Run("ConfigRegister", delegate { peer.m_rpc.Register<ZPackage>("SoroQoL_Config", (Action<ZRpc, ZPackage>)Receive); }); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private static class SendPatch { private static void Postfix(ZNet __instance, ZRpc rpc) { try { PostfixImpl(__instance, rpc); } catch (Exception e) { Safe.Report("ConfigSync.cs:Postfix", e); } } private static void PostfixImpl(ZNet __instance, ZRpc rpc) { Safe.Run("ConfigSend", delegate { if (__instance.IsServer()) { rpc.Invoke("SoroQoL_Config", new object[1] { Build() }); } }); } } [HarmonyPatch(typeof(ZNet), "OnDestroy")] private static class ResetPatch { private static void Postfix() { _remote.Clear(); HostVersion = null; } } private const string Rpc = "SoroQoL_Config"; private static readonly List<ConfigEntryBase> _entries = new List<ConfigEntryBase>(); private static readonly Dictionary<ConfigEntryBase, object> _remote = new Dictionary<ConfigEntryBase, object>(); internal static string HostVersion; internal static bool HasHostConfig => _remote.Count > 0; internal static void Init(ConfigFile cfg) { cfg.SettingChanged += delegate { Safe.Run("ConfigBroadcast", Broadcast); }; } internal static void Track(ConfigEntryBase e) { _entries.Add(e); } internal static T Get<T>(ConfigEntry<T> e) { if (_remote.TryGetValue((ConfigEntryBase)(object)e, out var value) && value is T) { return (T)value; } return e.Value; } private static string Key(ConfigEntryBase e) { return e.Definition.Section + "|" + e.Definition.Key; } private static ZPackage Build() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write("1.0.21"); val.Write(_entries.Count); foreach (ConfigEntryBase entry in _entries) { val.Write(Key(entry)); val.Write(entry.GetSerializedValue()); } return val; } private static void Broadcast() { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer?.m_rpc != null) { peer.m_rpc.Invoke("SoroQoL_Config", new object[1] { Build() }); } } } private static void Receive(ZRpc rpc, ZPackage p) { if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { return; } HostVersion = p.ReadString(); int num = p.ReadInt(); Dictionary<string, string> dictionary = new Dictionary<string, string>(); for (int i = 0; i < num; i++) { dictionary[p.ReadString()] = p.ReadString(); } _remote.Clear(); foreach (ConfigEntryBase entry in _entries) { if (dictionary.TryGetValue(Key(entry), out var value)) { try { _remote[entry] = TomlTypeConverter.ConvertToValue(value, entry.SettingType); } catch (Exception e) { Safe.Report("ConfigParse " + Key(entry), e); } } } if (HostVersion != "1.0.21") { Plugin.Log.LogWarning((object)("Host runs Soro's Quality of life mod " + HostVersion + ", you run 1.0.21. Please use the same version.")); } Plugin.Log.LogInfo((object)$"Received {_remote.Count} config values from host."); } } internal static class Cfg { public const float MinRange = 5f; public const float MaxRangeLimit = 30f; public static bool StationChests => ConfigSync.Get<bool>(Plugin.EnableStationChests); public static float MaxRange => Mathf.Clamp(ConfigSync.Get<float>(Plugin.ChestMaxRange), 5f, 30f); public static float Range => Mathf.Clamp(ConfigSync.Get<float>(Plugin.ChestRange), 5f, MaxRange); public static float Tick => ConfigSync.Get<float>(Plugin.ChestTickSeconds); public static float StationCooldown => ConfigSync.Get<float>(Plugin.StationCooldownSeconds); public static int ItemsPerTick => ConfigSync.Get<int>(Plugin.ItemsPerStationPerTick); public static bool KilnAllWood => ConfigSync.Get<bool>(Plugin.KilnUseFineAndCoreWood); public static bool CookRequireFire => ConfigSync.Get<bool>(Plugin.CookingRequireFire); public static bool AnimalFeeding => ConfigSync.Get<bool>(Plugin.EnableAnimalFeeding); public static bool FeedTamed => ConfigSync.Get<bool>(Plugin.FeedTamed); public static bool FeedWild => ConfigSync.Get<bool>(Plugin.FeedWild); public static float AnimalCooldown => ConfigSync.Get<float>(Plugin.AnimalFeedCooldown); public static bool FullFood => ConfigSync.Get<bool>(Plugin.EnableFullFood); public static bool Recycle => ConfigSync.Get<bool>(Plugin.EnableRecycle); public static float RecycleReturn => ConfigSync.Get<float>(Plugin.RecycleReturn); public static bool RecycleRequireStation => ConfigSync.Get<bool>(Plugin.RecycleRequireStation); public static bool MultiUser => ConfigSync.Get<bool>(Plugin.EnableMultiUser); public static int MaxViewers => ConfigSync.Get<int>(Plugin.MaxViewers); public static bool Totem => ConfigSync.Get<bool>(Plugin.EnableTotem); public static float TotemRadius => ConfigSync.Get<float>(Plugin.TotemRadius); public static bool EternalLights => ConfigSync.Get<bool>(Plugin.EnableEternalLights); } public class CraftingTotem : MonoBehaviour { [HarmonyPatch(typeof(Container), "Awake")] private static class ContainerAwake { private static void Postfix(Container __instance) { Safe.Run("Totem.RegContainer", delegate { ZNetView nv = Acc.NView(__instance); if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null) { Containers.Add(__instance); nv.Register<string, int>("SoroQoL_Take", (Action<long, string, int>)delegate(long sender, string name, int amount) { Safe.Run("Totem.Take", delegate { if (nv.IsOwner()) { TakeFrom(__instance.GetInventory(), name, amount, out var _); } }); }); nv.Register<string, int>("SoroQoL_Pull", (Action<long, string, int>)delegate(long sender, string name, int amount) { Safe.Run("Totem.Pull", delegate { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown if (nv.IsOwner()) { ItemData proto; int num = TakeFrom(__instance.GetInventory(), name, amount, out proto); if (num > 0) { ItemData val = proto.Clone(); val.m_stack = num; if (sender == ZNet.GetUID()) { ItemNet.GiveLocalPlayer(val); } else { ZPackage val2 = new ZPackage(); ItemNet.Write(val2, val); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "SoroQoL_MucGive", new object[1] { val2 }); } } } }); }); } }); } } [HarmonyPatch(typeof(Player), "HaveRequirementItems")] private static class HaveReqItems { private static void Postfix(Player __instance, ref bool __result, Recipe piece, bool discover, int qualityLevel, int amount) { try { PostfixImpl(__instance, ref __result, piece, discover, qualityLevel, amount); } catch (Exception e) { Safe.Report("CraftingTotem.cs:Postfix", e); } } private static void PostfixImpl(Player __instance, ref bool __result, Recipe piece, bool discover, int qualityLevel, int amount) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) try { if (__result || discover || (Object)(object)piece == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)Covering(((Component)__instance).transform.position) == (Object)null) { return; } CraftingStation currentCraftingStation = __instance.GetCurrentCraftingStation(); bool requireOnlyOneIngredient = piece.m_requireOnlyOneIngredient; bool flag = false; Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (!Applies(val, currentCraftingStation)) { continue; } int num = val.GetAmount(qualityLevel) * amount; if (num <= 0) { continue; } string name = val.m_resItem.m_itemData.m_shared.m_name; bool flag2 = ((Humanoid)__instance).GetInventory().CountItems(name, -1, true) + CountInSources(__instance, name) >= num; if (requireOnlyOneIngredient) { if (flag2) { flag = true; break; } } else if (!flag2) { Diag(piece, name, num, __instance); return; } } if (!requireOnlyOneIngredient || flag) { __result = true; } } catch (Exception e) { Safe.Report("Totem.HaveReqItems", e); } } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] private static class HaveReqPiece { private static void Postfix(Player __instance, ref bool __result, Piece piece, RequirementMode mode) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) try { PostfixImpl(__instance, ref __result, piece, mode); } catch (Exception e) { Safe.Report("CraftingTotem.cs:Postfix", e); } } private static void PostfixImpl(Player __instance, ref bool __result, Piece piece, RequirementMode mode) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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) try { if (__result || (int)mode != 0 || (Object)(object)piece == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)Covering(((Component)__instance).transform.position) == (Object)null || (Object.op_Implicit((Object)(object)piece.m_craftingStation) && !Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)__instance).transform.position)))) { return; } Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (!((Object)(object)val?.m_resItem == (Object)null) && val.m_amount > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; if (((Humanoid)__instance).GetInventory().CountItems(name, -1, true) + CountInSources(__instance, name) < val.m_amount) { return; } } } __result = true; } catch (Exception e) { Safe.Report("Totem.HaveReqPiece", e); } } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] private static class ShowCounts { private static void Postfix(Transform elementRoot, Requirement req, Player player, int quality, int craftMultiplier) { try { PostfixImpl(elementRoot, req, player, quality, craftMultiplier); } catch (Exception e) { Safe.Report("CraftingTotem.cs:Postfix", e); } } private static void PostfixImpl(Transform elementRoot, Requirement req, Player player, int quality, int craftMultiplier) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)req?.m_resItem == (Object)null || (Object)(object)player == (Object)null || (Object)(object)Covering(((Component)player).transform.position) == (Object)null) { return; } Transform obj = elementRoot.Find("res_amount"); TMP_Text val = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null); if (!((Object)(object)val == (Object)null)) { string name = req.m_resItem.m_itemData.m_shared.m_name; int num = req.GetAmount(quality) * craftMultiplier; int num2 = ((Humanoid)player).GetInventory().CountItems(name, -1, true) + CountInSources(player, name); if (num > 0) { val.text = $"{num2}/{num}"; } if (num2 >= num) { ((Graphic)val).color = Color.white; } } } catch (Exception e) { Safe.Report("Totem.ShowCounts", e); } } } [HarmonyPatch(typeof(Player), "ConsumeResources")] private static class Consume { private static void Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int multiplier) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) try { if (requirements == null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || __instance.NoCostCheat() || (Object)(object)Covering(((Component)__instance).transform.position) == (Object)null) { return; } Inventory inventory = ((Humanoid)__instance).GetInventory(); CraftingStation currentCraftingStation = __instance.GetCurrentCraftingStation(); foreach (Requirement val in requirements) { if (Applies(val, currentCraftingStation)) { int num = val.GetAmount(qualityLevel) * Mathf.Max(1, multiplier); string name = val.m_resItem.m_itemData.m_shared.m_name; int num2 = num - inventory.CountItems(name, -1, true); if (num2 > 0) { TakeFromChests(__instance, name, num2); } } } } catch (Exception e) { Safe.Report("Totem.Consume", e); } } } internal static readonly List<CraftingTotem> All = new List<CraftingTotem>(); internal static readonly List<Container> Containers = new List<Container>(); private const string RpcPull = "SoroQoL_Pull"; private static readonly HashSet<string> _diag = new HashSet<string>(); private const string RpcTake = "SoroQoL_Take"; private void Awake() { ZNetView component = ((Component)this).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.GetZDO() != null) { All.Add(this); } } private void OnDestroy() { All.Remove(this); } internal static CraftingTotem Covering(Vector3 pos) { //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) if (!Cfg.Totem) { return null; } float r = Cfg.TotemRadius; return All.FirstOrDefault((CraftingTotem t) => Object.op_Implicit((Object)(object)t) && Vector3.Distance(((Component)t).transform.position, pos) <= r); } internal static List<Container> Sources(Player pl) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) List<Container> list = new List<Container>(); if ((Object)(object)pl == (Object)null) { return list; } CraftingTotem craftingTotem = Covering(((Component)pl).transform.position); if ((Object)(object)craftingTotem == (Object)null) { return list; } float totemRadius = Cfg.TotemRadius; long playerID = pl.GetPlayerID(); Containers.RemoveAll((Container c) => (Object)(object)c == (Object)null); foreach (Container container in Containers) { ZNetView val = Acc.NView(container); if (!((Object)(object)val == (Object)null) && val.IsValid() && container.GetInventory() != null && !(Vector3.Distance(((Component)container).transform.position, ((Component)craftingTotem).transform.position) > totemRadius) && !((Object)(object)container.m_wagon != (Object)null) && !((Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null)) { Piece componentInParent = ((Component)container).GetComponentInParent<Piece>(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsPlacedByPlayer() && Acc.Container_CheckAccess(container, playerID) && PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false)) { list.Add(container); } } } return list.OrderBy((Container c) => Vector3.Distance(((Component)c).transform.position, ((Component)pl).transform.position)).ToList(); } internal static int CountInSources(Player pl, string name) { return Sources(pl).Sum((Container c) => c.GetInventory().CountItems(name, -1, true)); } internal static bool Applies(Requirement req, CraftingStation station) { if ((Object)(object)req?.m_resItem == (Object)null) { return false; } bool flag = Acc.IsUpgraderResource(req); if (!((Object)(object)station != (Object)null)) { return !flag; } return Acc.StationIsUpgrader(station) == flag; } private static void Diag(Recipe r, string n, int need, Player pl) { string text = (Object.op_Implicit((Object)(object)r.m_item) ? ((Object)r.m_item).name : "?") + "|" + n; if (_diag.Add(text)) { Plugin.Log.LogInfo((object)$"[Totem] {text}: need {need}, inventory {((Humanoid)pl).GetInventory().CountItems(n, -1, true)}, chests {CountInSources(pl, n)}"); } } internal static int TakeFromChests(Player pl, string name, int amount) { if (amount <= 0) { return 0; } List<Container> source = Sources(pl); int num = amount; foreach (Container item in source.Where((Container c) => Acc.NView(c).IsOwner())) { if (num <= 0) { break; } num -= TakeFrom(item.GetInventory(), name, num, out var _); } foreach (Container item2 in source.Where((Container c) => !Acc.NView(c).IsOwner())) { if (num <= 0) { break; } int num2 = Mathf.Min(num, item2.GetInventory().CountItems(name, -1, true)); if (num2 > 0) { Acc.NView(item2).InvokeRPC("SoroQoL_Take", new object[2] { name, num2 }); num -= num2; } } return amount - num; } private static int TakeFrom(Inventory inv, string name, int amount, out ItemData proto) { proto = null; int num = 0; foreach (ItemData item in (from i in inv.GetAllItems() where i.m_shared.m_name == name select i).ToList()) { if (num >= amount) { break; } int num2 = Mathf.Min(item.m_stack, amount - num); proto = proto ?? item.Clone(); if (inv.RemoveItem(item, num2)) { num += num2; } } return num; } } internal static class EternalLights { [HarmonyPatch(typeof(Fireplace), "UpdateFireplace")] private static class Patch { private static void Prefix(Fireplace __instance) { try { Impl(__instance); } catch (Exception e) { Safe.Report("EternalLights", e); } } private static void Impl(Fireplace f) { if (!Cfg.EternalLights || (Object)(object)f == (Object)null || f.m_infiniteFuel) { return; } ZNetView val = Acc.NView(f); if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner() && IsLight(f)) { ZDO zDO = val.GetZDO(); if (zDO.GetFloat(ZDOVars.s_fuel, 0f) < f.m_maxFuel) { zDO.Set(ZDOVars.s_fuel, f.m_maxFuel); } } } } private static readonly HashSet<string> Known = new HashSet<string> { "piece_groundtorch", "piece_groundtorch_wood", "piece_groundtorch_green", "piece_groundtorch_blue", "piece_groundtorch_mist", "piece_walltorch", "piece_brazierceiling01", "piece_brazierfloor01", "piece_brazierfloor02", "piece_jackoturnip", "piece_dvergr_lantern", "piece_dvergr_lantern_pole", "piece_dvergr_wood_lantern", "CandleSconce", "Candle_resin", "piece_Lantern", "piece_lantern", "piece_sconce", "piece_groundtorch_flaming", "piece_brazier_charred", "piece_charred_torch" }; private static readonly string[] Words = new string[7] { "torch", "sconce", "brazier", "lantern", "lamp", "candle", "jackoturnip" }; private static readonly string[] NotLights = new string[11] { "fire_pit", "firepit", "hearth", "bonfire", "cooking", "oven", "kiln", "smelter", "furnace", "bathtub", "hottub" }; private static readonly Dictionary<string, bool> _cache = new Dictionary<string, bool>(); public static bool IsLight(Fireplace f) { if ((Object)(object)f == (Object)null) { return false; } string prefabName = Utils.GetPrefabName(((Component)f).gameObject); if (_cache.TryGetValue(prefabName, out var value)) { return value; } value = Classify(f, prefabName); _cache[prefabName] = value; return value; } private static bool Classify(Fireplace f, string name) { if (Known.Contains(name)) { return true; } if (Object.op_Implicit((Object)(object)((Component)f).GetComponent<CookingStation>()) || Object.op_Implicit((Object)(object)((Component)f).GetComponentInParent<Smelter>())) { return false; } string text = name.ToLowerInvariant(); string[] notLights = NotLights; foreach (string value in notLights) { if (text.Contains(value)) { return false; } } notLights = Words; foreach (string value2 in notLights) { if (text.Contains(value2)) { return true; } } return false; } } internal static class FeederLogic { public static void Tick(SpecialChest chest) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: 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) Inventory inv = chest.m_container.GetInventory(); if (inv == null || inv.GetAllItems().Count == 0) { return; } ChestMode mode = chest.Mode; Vector3 pos = ((Component)chest).transform.position; float range = chest.Range; if (mode == ChestMode.AnimalFeeding) { if (Cfg.AnimalFeeding) { AnimalFeeder.Tick(chest, inv); } return; } bool fuelOnly = mode == ChestMode.Fuel; foreach (Smelter s in from x in SpecialChest.Near<Smelter>(pos, range) orderby Vector3.Distance(((Component)x).transform.position, pos) select x) { Safe.Run("Feeder.Smelter", delegate { FeedSmelter(s, inv, mode, fuelOnly); }); } foreach (CookingStation c in from x in SpecialChest.Near<CookingStation>(pos, range) orderby Vector3.Distance(((Component)x).transform.position, pos) select x) { Safe.Run("Feeder.Cooking", delegate { FeedCooking(c, inv, mode, fuelOnly); }); } if (!fuelOnly) { foreach (Fermenter f in SpecialChest.Near<Fermenter>(pos, range)) { Safe.Run("Feeder.Fermenter", delegate { FeedFermenter(f, inv, mode); }); } } foreach (Fireplace f2 in SpecialChest.Near<Fireplace>(pos, range)) { Safe.Run("Feeder.Fire", delegate { FeedFire(f2, inv, mode, fuelOnly); }); } } private static ItemData Find(Inventory inv, ItemDrop prefabItem) { if ((Object)(object)prefabItem == (Object)null) { return null; } string n = prefabItem.m_itemData.m_shared.m_name; return ((IEnumerable<ItemData>)inv.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => i.m_shared.m_name == n && i.m_stack > 0)); } private static bool IsOutputOf(Smelter s, ItemData x) { string name = x.m_shared.m_name; foreach (ItemConversion item in s.m_conversion) { if ((Object)(object)item?.m_to != (Object)null && item.m_to.m_itemData.m_shared.m_name == name) { return true; } } return false; } private static bool IsOutputOf(CookingStation s, ItemData x) { string name = x.m_shared.m_name; if ((Object)(object)s.m_overCookedItem != (Object)null && s.m_overCookedItem.m_itemData.m_shared.m_name == name) { return true; } foreach (ItemConversion item in s.m_conversion) { if ((Object)(object)item?.m_to != (Object)null && item.m_to.m_itemData.m_shared.m_name == name) { return true; } } return false; } private static bool IsOutputOf(Fermenter s, ItemData x) { string name = x.m_shared.m_name; foreach (ItemConversion item in s.m_conversion) { if ((Object)(object)item?.m_to != (Object)null && item.m_to.m_itemData.m_shared.m_name == name) { return true; } } return false; } private static bool Push(Inventory inv, ItemData it, ZNetView nv, Func<float> probe, Action send) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (it == null || (Object)(object)nv == (Object)null || !nv.IsValid() || !nv.IsOwner()) { return false; } float num = probe(); ItemData val = it.Clone(); val.m_stack = 1; if (!inv.RemoveItem(it, 1)) { return false; } bool flag = false; try { send(); flag = Mathf.Abs(probe() - num) > 0.0001f; } catch (Exception e) { Safe.Report("Feeder.Push", e); } if (!flag) { int num2 = ItemNet.AddAsMuch(inv, val); if (num2 > 0) { ItemNet.Drop(val, num2, ((Component)nv).transform.position); } } return flag; } private static float SlotsUsed(CookingStation c) { int num = 0; for (int i = 0; i < c.m_slots.Length; i++) { Acc.Cooking_GetSlot(c, i, out var item, out var _, out var _, out var _); if (!string.IsNullOrEmpty(item)) { num++; } } return num; } private static bool TakeOne(Inventory inv, ItemData it) { if (it != null) { return inv.RemoveItem(it, 1); } return false; } private static void FeedSmelter(Smelter s, Inventory inv, ChestMode mode, bool fuelOnly) { ZNetView nv = Acc.NView(s); StationKind kind = Kinds.Of(s); if ((!fuelOnly && !Kinds.Matches(mode, kind)) || !SpecialChest.StationReady(nv)) { return; } bool flag = false; int itemsPerTick = Cfg.ItemsPerTick; if ((Object)(object)s.m_fuelItem != (Object)null) { int num = s.m_maxFuel - Mathf.CeilToInt(Acc.Smelter_GetFuel(s)); for (int i = 0; i < Mathf.Min(num, itemsPerTick); i++) { ItemData it = Find(inv, s.m_fuelItem); if (!Push(inv, it, nv, () => Acc.Smelter_GetFuel(s), delegate { nv.InvokeRPC("RPC_AddFuel", Array.Empty<object>()); })) { break; } flag = true; } } if (!fuelOnly && kind != StationKind.HotTub) { int num2 = s.m_maxOre - Acc.Smelter_GetQueueSize(s); for (int num3 = 0; num3 < Mathf.Min(num2, itemsPerTick); num3++) { ItemData val = ((IEnumerable<ItemData>)inv.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData x) => x.m_stack > 0 && (Object)(object)x.m_dropPrefab != (Object)null && Acc.Smelter_IsItemAllowed(s, x) && !IsOutputOf(s, x) && (kind != StationKind.Kiln || Cfg.KilnAllWood || (!(((Object)x.m_dropPrefab).name == "FineWood") && !(((Object)x.m_dropPrefab).name == "RoundLog"))))); if (val == null) { break; } string prefab = ((Object)val.m_dropPrefab).name; if (!Push(inv, val, nv, () => Acc.Smelter_GetQueueSize(s), delegate { nv.InvokeRPC("RPC_AddOre", new object[2] { prefab, false }); })) { break; } flag = true; } } if (flag) { SpecialChest.MarkStation(nv); } } private static void FeedCooking(CookingStation c, Inventory inv, ChestMode mode, bool fuelOnly) { ZNetView nv = Acc.NView(c); StationKind k = Kinds.Of(c); if ((!fuelOnly && !Kinds.Matches(mode, k)) || !SpecialChest.StationReady(nv)) { return; } bool flag = false; if (c.m_useFuel && (Object)(object)c.m_fuelItem != (Object)null) { int num = c.m_maxFuel - Mathf.CeilToInt(Acc.Cooking_GetFuel(c)); for (int i = 0; i < Mathf.Min(num, Cfg.ItemsPerTick); i++) { if (!Push(inv, Find(inv, c.m_fuelItem), nv, () => Acc.Cooking_GetFuel(c), delegate { nv.InvokeRPC("RPC_AddFuel", Array.Empty<object>()); })) { break; } flag = true; } } if (!fuelOnly && (!Cfg.CookRequireFire || !c.m_requireFire || Acc.Cooking_IsFireLit(c))) { int num2 = 0; for (int num3 = 0; num3 < c.m_slots.Length; num3++) { Acc.Cooking_GetSlot(c, num3, out var item, out var _, out var _, out var _); if (string.IsNullOrEmpty(item)) { num2++; } } for (int num4 = 0; num4 < num2; num4++) { ItemData val = ((IEnumerable<ItemData>)inv.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData x) => x.m_stack > 0 && (Object)(object)x.m_dropPrefab != (Object)null && Acc.Cooking_IsItemAllowed(c, x) && !IsOutputOf(c, x))); if (val == null) { break; } string prefab = ((Object)val.m_dropPrefab).name; if (!Push(inv, val, nv, () => SlotsUsed(c), delegate { nv.InvokeRPC("RPC_AddItem", new object[2] { prefab, false }); })) { break; } flag = true; } } if (flag) { SpecialChest.MarkStation(nv); } } private static void FeedFermenter(Fermenter f, Inventory inv, ChestMode mode) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!Kinds.Matches(mode, StationKind.Fermenter)) { return; } ZNetView nv = Acc.NView(f); if (!SpecialChest.StationReady(nv) || (int)Acc.Fermenter_GetStatus(f) != 0) { return; } ItemData val = ((IEnumerable<ItemData>)inv.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData x) => x.m_stack > 0 && (Object)(object)x.m_dropPrefab != (Object)null && Acc.Fermenter_IsItemAllowed(f, x) && !IsOutputOf(f, x))); if (val != null) { int hash = StringExtensionMethods.GetStableHashCode(((Object)val.m_dropPrefab).name); if (Push(inv, val, nv, () => (float)Acc.Fermenter_GetStatus(f), delegate { nv.InvokeRPC("RPC_AddItem", new object[2] { hash, false }); })) { SpecialChest.MarkStation(nv); } } } private static void FeedFire(Fireplace f, Inventory inv, ChestMode mode, bool fuelOnly) { if ((EternalLights.IsLight(f) && Cfg.EternalLights) || (!fuelOnly && !Kinds.Matches(mode, StationKind.Fire)) || f.m_infiniteFuel || !f.m_canRefill || (Object)(object)f.m_fuelItem == (Object)null) { return; } ZNetView nv = Acc.NView(f); if (!SpecialChest.StationReady(nv)) { return; } float num = nv.GetZDO().GetFloat(ZDOVars.s_fuel, 0f); int num2 = Mathf.FloorToInt(f.m_maxFuel - num); bool flag = false; for (int i = 0; i < Mathf.Min(num2, Cfg.ItemsPerTick); i++) { if (!Push(inv, Find(inv, f.m_fuelItem), nv, () => nv.GetZDO().GetFloat(ZDOVars.s_fuel, 0f), delegate { nv.InvokeRPC("RPC_AddFuel", Array.Empty<object>()); })) { break; } flag = true; } if (flag) { SpecialChest.MarkStation(nv); } } } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] internal static class FullFoodPatch { private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr) { try { PostfixImpl(__instance, ref hp, ref stamina, ref eitr); } catch (Exception e) { Safe.Report("FullFood.cs:Postfix", e); } } private static void PostfixImpl(Player __instance, ref float hp, ref float stamina, ref float eitr) { try { List<Food> list = (((Object)(object)__instance == (Object)null) ? null : Acc.Player_foods.Invoke(__instance)); if (!Cfg.FullFood || list == null) { return; } float num = 0f; float num2 = 0f; float num3 = 0f; foreach (Food item in list) { SharedData val = item?.m_item?.m_shared; if (val != null && !(item.m_time <= 0f)) { num += Math.Max(0f, val.m_food - item.m_health); num2 += Math.Max(0f, val.m_foodStamina - item.m_stamina); num3 += Math.Max(0f, val.m_foodEitr - item.m_eitr); } } hp += num; stamina += num2; eitr += num3; } catch (Exception e) { Safe.Report("FullFood", e); } } } internal static class ItemNet { public static void Write(ZPackage p, ItemData it) { p.Write(Object.op_Implicit((Object)(object)it.m_dropPrefab) ? ((Object)it.m_dropPrefab).name : ""); p.Write(it.m_stack); p.Write(it.m_quality); p.Write(it.m_variant); p.Write(it.m_durability); p.Write(it.m_crafterID); p.Write(it.m_crafterName ?? ""); p.Write(it.m_worldLevel); p.Write(it.m_customData?.Count ?? 0); if (it.m_customData == null) { return; } foreach (KeyValuePair<string, string> customDatum in it.m_customData) { p.Write(customDatum.Key); p.Write(customDatum.Value); } } public static ItemData Read(ZPackage p) { string text = p.ReadString(); int stack = p.ReadInt(); int quality = p.ReadInt(); int variant = p.ReadInt(); float durability = p.ReadSingle(); long crafterID = p.ReadLong(); string crafterName = p.ReadString(); int worldLevel = p.ReadInt(); int num = p.ReadInt(); Dictionary<string, string> dictionary = new Dictionary<string, string>(); for (int i = 0; i < num; i++) { dictionary[p.ReadString()] = p.ReadString(); } GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(text) : null); ItemDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)("Unknown item prefab in RPC: " + text)); return null; } ItemData obj = val2.m_itemData.Clone(); obj.m_dropPrefab = val; obj.m_stack = stack; obj.m_quality = quality; obj.m_variant = variant; obj.m_durability = durability; obj.m_crafterID = crafterID; obj.m_crafterName = crafterName; obj.m_worldLevel = worldLevel; obj.m_customData = dictionary; return obj; } public static ItemData FromPrefab(string prefabName, int stack) { GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(prefabName) : null); ItemDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 == (Object)null) { return null; } ItemData obj = val2.m_itemData.Clone(); obj.m_dropPrefab = val; obj.m_stack = stack; return obj; } public static int AddAsMuch(Inventory inv, ItemData item) { int num = item.m_stack; int num2 = Mathf.Max(1, item.m_shared.m_maxStackSize); while (num > 0) { int num3 = Mathf.Min(num, num2); ItemData val = item.Clone(); val.m_stack = num3; if (inv.CanAddItem(val, num3) && inv.AddItem(val)) { num -= num3; continue; } ItemData val2 = item.Clone(); val2.m_stack = 1; if (!inv.CanAddItem(val2, 1) || !inv.AddItem(val2)) { break; } num--; } return num; } public static void Drop(ItemData item, int amount, Vector3 pos) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (item != null && amount > 0) { ItemDrop.DropItem(item, amount, pos + Vector3.up, Quaternion.identity); } } public static void GiveLocalPlayer(ItemData item) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && item != null) { int num = AddAsMuch(((Humanoid)localPlayer).GetInventory(), item); if (num > 0) { Drop(item, num, ((Component)localPlayer).transform.position); } } } } [HarmonyPatch(typeof(ZNetScene), "CreateObject")] internal static class LegacyChests { private static readonly int FeederHash = StringExtensionMethods.GetStableHashCode("soro_feeder_chest"); private static readonly int CollectorHash = StringExtensionMethods.GetStableHashCode("soro_collector_chest"); private static readonly int ProductionHash = StringExtensionMethods.GetStableHashCode("soro_production_chest"); internal static readonly Dictionary<ZDOID, bool> Pending = new Dictionary<ZDOID, bool>(); internal static void Apply(ZDO zdo) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || Pending.Count == 0 || !Pending.TryGetValue(zdo.m_uid, out var value) || !zdo.IsOwner()) { return; } Pending.Remove(zdo.m_uid); int num = default(int); if (!zdo.GetInt("soro_role", ref num)) { zdo.Set("soro_role", (!value) ? 1 : 0); if (value) { zdo.Set("soro_paused", 1); } if (!value && SpecialChest.InputOnly((ChestMode)zdo.GetInt("soro_mode", 0))) { zdo.Set("soro_mode", 0); } } } private static void Prefix(ZDO zdo) { try { PrefixImpl(zdo); } catch (Exception e) { Safe.Report("LegacyChests.cs:Prefix", e); } } private static void PrefixImpl(ZDO zdo) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (zdo == null) { return; } int prefab = zdo.GetPrefab(); if (prefab == FeederHash || prefab == CollectorHash) { bool flag = prefab == FeederHash; zdo.SetPrefab(ProductionHash); int num = default(int); if (!zdo.GetInt("soro_role", ref num)) { Pending[zdo.m_uid] = flag; } Apply(zdo); Plugin.Log.LogInfo((object)("Converted old " + (flag ? "Feeder" : "Collector") + " chest to Production Chest (" + (flag ? "Input" : "Output") + ")")); } } } internal static class MultiUserChest { [HarmonyPatch(typeof(Container), "Awake")] private static class ContainerAwake { private static void Postfix(Container __instance) { Safe.Run("MUC.Reg", delegate { ZNetView val = Acc.NView(__instance); if (!((Object)(object)val == (Object)null) && val.GetZDO() != null) { val.Register<bool>("SoroQoL_MucView", (Action<long, bool>)delegate(long s, bool open) { OnView(__instance, s, open); }); val.Register<int, int, int, string>("SoroQoL_MucTake", (Method<int, int, int, string>)delegate(long s, int x, int y, int n, string prefab) { OnTake(__instance, s, x, y, n, prefab); }); val.Register<int, int, ZPackage>("SoroQoL_MucPut", (Action<long, int, int, ZPackage>)delegate(long s, int x, int y, ZPackage pkg) { OnPut(__instance, s, x, y, pkg); }); } }); } } [HarmonyPatch(typeof(Game), "Start")] private static class GameStart { private static void Postfix() { Safe.Run("MUC.RegGive", delegate { ZRoutedRpc.instance.Register<ZPackage>("SoroQoL_MucGive", (Action<long, ZPackage>)delegate(long s, ZPackage pkg) { Safe.Run("MUC.Give", delegate { ItemNet.GiveLocalPlayer(ItemNet.Read(pkg)); }); }); }); } } [HarmonyPatch(typeof(Container), "RPC_RequestOpen")] private static class RequestOpen { private static bool Prefix(Container __instance, long uid, long playerID) { try { return PrefixImpl(__instance, uid, playerID); } catch (Exception e) { Safe.Report("MultiUserChest.cs:Prefix", e); return true; } } private static bool PrefixImpl(Container __instance, long uid, long playerID) { try { if (!On || !Acc.NView(__instance).IsOwner()) { return true; } if (!Acc.Container_CheckAccess(__instance, playerID)) { return true; } if ((!__instance.IsInUse() && (!Object.op_Implicit((Object)(object)__instance.m_wagon) || !__instance.m_wagon.InUse())) || uid == ZNet.GetUID()) { return true; } bool flag = 1 + ActiveViewers(__instance, uid) < Mathf.Max(1, Cfg.MaxViewers); if (flag) { OnView(__instance, uid, open: true); } Acc.NView(__instance).InvokeRPC(uid, "RPC_OpenResponse", new object[1] { flag }); return false; } catch (Exception e) { Safe.Report("MUC.Open", e); return true; } } } [HarmonyPatch(typeof(Container), "SetInUse")] private static class SetInUse { private static bool Prefix(Container __instance) { try { return PrefixImpl(__instance); } catch (Exception e) { Safe.Report("MultiUserChest.cs:Prefix", e); return true; } } private static bool PrefixImpl(Container __instance) { try { return !On || (Object)(object)Acc.NView(__instance) == (Object)null || !Acc.NView(__instance).IsValid() || Acc.NView(__instance).IsOwner(); } catch (Exception e) { Safe.Report("MUC.SetInUse", e); return true; } } } [HarmonyPatch(typeof(InventoryGui), "UpdateContainer")] private static class UpdateContainer { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> ins) { MethodInfo isOwner = AccessTools.Method(typeof(Container), "IsOwner", (Type[])null, (Type[])null); MethodInfo repl = AccessTools.Method(typeof(UpdateContainer), "CanView", (Type[])null, (Type[])null); foreach (CodeInstruction @in in ins) { if ((@in.opcode == OpCodes.Callvirt || @in.opcode == OpCodes.Call) && @in.operand as MethodInfo == isOwner) { yield return new CodeInstruction(OpCodes.Call, (object)repl); } else { yield return @in; } } } private static bool SafeIsOwner(Container c) { try { return c.IsOwner(); } catch { return false; } } private static bool CanViewImpl(Container c) { if (!c.IsOwner()) { if (On && (Object)(object)Acc.NView(c) != (Object)null) { return Acc.NView(c).IsValid(); } return false; } return true; } public static bool CanView(Container c) { try { return CanViewImpl(c); } catch (Exception e) { Safe.Report("MUC.CanView", e); return SafeIsOwner(c); } } private static void Postfix(InventoryGui __instance) { Safe.Run("MUC.Update", delegate { Container val = Acc.CurrentContainer(__instance); if (On && !((Object)(object)val == (Object)null) && !((Object)(object)Acc.NView(val) == (Object)null) && Acc.NView(val).IsValid() && !val.IsOwner()) { Acc.Container_CheckForChanges(val); if (Time.time >= _nextPing) { _nextPing = Time.time + 2f; Acc.NView(val).InvokeRPC("SoroQoL_MucView", new object[1] { true }); } } }); } } [HarmonyPatch(typeof(InventoryGui), "CloseContainer")] private static class Close { private static void Prefix(InventoryGui __instance) { Safe.Run("MUC.Close", delegate { Container val = Acc.CurrentContainer(__instance); if (On && (Object)(object)val != (Object)null && (Object)(object)Acc.NView(val) != (Object)null && Acc.NView(val).IsValid() && !val.IsOwner()) { Acc.NView(val).InvokeRPC("SoroQoL_MucView", new object[1] { false }); } }); } } [HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")] private static class Selected { private static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos, Modifier mod) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) try { return PrefixImpl(__instance, grid, item, pos, mod); } catch (Exception e) { Safe.Report("MultiUserChest.cs:Prefix", e); return true; } } private static bool PrefixImpl(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos, Modifier mod) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Invalid comparison between Unknown and I4 try { if (!Viewing(__instance, out var c)) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return true; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); bool flag = (Object)(object)grid == (Object)(object)Acc.Gui_containerGrid.Invoke(__instance); ItemData val = Acc.Gui_dragItem.Invoke(__instance); if (flag && val == null && item != null) { int num = (((int)mod == 1) ? Mathf.Max(1, item.m_stack / 2) : item.m_stack); Acc.NView(c).InvokeRPC("SoroQoL_MucTake", new object[4] { item.m_gridPos.x, item.m_gridPos.y, num, Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : "" }); return false; } if (flag && val != null && Acc.Gui_dragInventory.Invoke(__instance) == inventory) { SendPut(c, localPlayer, val, Acc.Gui_dragAmount.Invoke(__instance), pos.x, pos.y); Acc.Gui_SetupDragItem(__instance, null, null, 1); return false; } if (!flag && val == null && item != null && (int)mod == 2) { SendPut(c, localPlayer, item, item.m_stack, -1, -1); return false; } if (val != null && Acc.Gui_dragInventory.Invoke(__instance) == c.GetInventory()) { Acc.Gui_SetupDragItem(__instance, null, null, 1); return false; } return true; } catch (Exception e) { Safe.Report("MUC.Select", e); return true; } } } [HarmonyPatch(typeof(InventoryGui), "OnRightClickItem")] private static class RightClick { private static bool Prefix(InventoryGui __instance, InventoryGrid grid) { try { return PrefixImpl(__instance, grid); } catch (Exception e) { Safe.Report("MultiUserChest.cs:Prefix", e); return true; } } private static bool PrefixImpl(InventoryGui __instance, InventoryGrid grid) { try { Container c; return !Viewing(__instance, out c) || !((Object)(object)grid == (Object)(object)Acc.Gui_containerGrid.Invoke(__instance)); } catch (Exception e) { Safe.Report("MUC.RightClick", e); return true; } } } [HarmonyPatch(typeof(InventoryGui), "OnTakeAll")] private static class TakeAll { private static bool Prefix(InventoryGui __instance) { try { return PrefixImpl(__instance); } catch (Exception e) { Safe.Report("MultiUserChest.cs:Prefix", e); return true; } } private static bool PrefixImpl(InventoryGui __instance) { Container c; try { if (!Viewing(__instance, out c)) { return true; } } catch (Exception e) { Safe.Report("MUC.TakeAll", e); return true; } Safe.Run("MUC.TakeAll", delegate { foreach (ItemData item in c.GetInventory().GetAllItems().ToList()) { Acc.NView(c).InvokeRPC("SoroQoL_MucTake", new object[4] { item.m_gridPos.x, item.m_gridPos.y, item.m_stack, Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : "" }); } }); return false; } } [HarmonyPatch(typeof(InventoryGui), "OnStackAll")] private static class StackAll { private static bool Prefix(InventoryGui __instance) { try { return PrefixImpl(__instance); } catch (Exception e) { Safe.Report("MultiUserChest.cs:Prefix", e); return true; } } private static bool PrefixImpl(InventoryGui __instance) { try { if (!Viewing(__instance, out var _)) { return true; } } catch (Exception e) { Safe.Report("MUC.StackAll", e); return true; } Acc.Msg("Stack-all is only available to the first player using this chest."); return false; } } private const string RpcView = "SoroQoL_MucView"; private const string RpcTake = "SoroQoL_MucTake"; private const string RpcPut = "SoroQoL_MucPut"; private const string RpcGive = "SoroQoL_MucGive"; private static readonly Dictionary<ZDOID, Dictionary<long, float>> _viewers = new Dictionary<ZDOID, Dictionary<long, float>>(); private static float _nextPing; private static bool On => Cfg.MultiUser; private static bool IsSpecialOrNormal(Container c) { if ((Object)(object)c != (Object)null && (Object)(object)Acc.NView(c) != (Object)null) { return Acc.NView(c).IsValid(); } return false; } private static int ActiveViewers(Container c, long except) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (!_viewers.TryGetValue(Acc.NView(c).GetZDO().m_uid, out var value)) { return 0; } float now = Time.time; foreach (long item in (from kv in value where now - kv.Value > 6f select kv.Key).ToList()) { value.Remove(item); } return value.Keys.Count((long k) => k != except); } private static void GiveBack(long peer, ItemData it) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown if (it != null && it.m_stack > 0) { if (peer == ZNet.GetUID()) { ItemNet.GiveLocalPlayer(it); return; } ZPackage val = new ZPackage(); ItemNet.Write(val, it); ZRoutedRpc.instance.InvokeRoutedRPC(peer, "SoroQoL_MucGive", new object[1] { val }); } } private static void OnView(Container c, long sender, bool open) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (Acc.NView(c).IsOwner()) { ZDOID uid = Acc.NView(c).GetZDO().m_uid; if (!_viewers.TryGetValue(uid, out var value)) { value = (_viewers[uid] = new Dictionary<long, float>()); } if (open) { value[sender] = Time.time; } else { value.Remove(sender); } } } private static void OnTake(Container c, long sender, int x, int y, int amount, string prefab) { Safe.Run("MUC.Take", delegate { if (Acc.NView(c).IsOwner()) { Inventory inventory = c.GetInventory(); ItemData itemAt = inventory.GetItemAt(x, y); if (itemAt != null && !((Object)(object)itemAt.m_dropPrefab == (Object)null) && !(((Object)itemAt.m_dropPrefab).name != prefab)) { int num = Mathf.Clamp(amount, 1, itemAt.m_stack); ItemData val = itemAt.Clone(); val.m_stack = num; if (inventory.RemoveItem(itemAt, num)) { GiveBack(sender, val); } } } }); } private static void OnPut(Container c, long sender, int x, int y, ZPackage pkg) { ItemData val = null; try { val = ItemNet.Read(pkg); if (val == null) { return; } if (!Acc.NView(c).IsOwner()) { GiveBack(sender, val); return; } Inventory inventory = c.GetInventory(); if (x >= 0 && y >= 0) { inventory.GetItemAt(x, y); } int num = val.m_stack; if (x >= 0 && y >= 0 && x < inventory.GetWidth()) { inventory.GetHeight(); } if (num > 0) { ItemData val2 = val.Clone(); val2.m_stack = num; num = ItemNet.AddAsMuch(inventory, val2); } if (num > 0) { ItemData val3 = val.Clone(); val3.m_stack = num; GiveBack(sender, val3); } } catch (Exception e) { Safe.Report("MUC.Put", e); if (val != null) { GiveBack(sender, val); } } } private static bool Viewing(InventoryGui g, out Container c) { c = Acc.CurrentContainer(g); if (On && (Object)(object)c != (Object)null && (Object)(object)Acc.NView(c) != (Object)null && Acc.NView(c).IsValid()) { return !c.IsOwner(); } return false; } private static void SendPut(Container c, Player pl, ItemData item, int amount, int x, int y) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown Inventory inventory = ((Humanoid)pl).GetInventory(); amount = Mathf.Clamp(amount, 1, item.m_stack); if (((Humanoid)pl).IsItemEquiped(item)) { ((Humanoid)pl).UnequipItem(item, false); } ItemData val = item.Clone(); val.m_stack = amount; if (inventory.RemoveItem(item, amount)) { ZPackage val2 = new ZPackage(); ItemNet.Write(val2, val); Acc.NView(c).InvokeRPC("SoroQoL_MucPut", new object[3] { x, y, val2 }); } } } internal static class Pieces { [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetSceneAwake { private static void Postfix() { Safe.Run("Pieces.ZNetScene", Ensure); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDBAwake { private static void Postfix() { Safe.Run("Pieces.ObjectDB", Ensure); } } public const string ProductionName = "soro_production_chest"; public const string ReinforcedName = "soro_production_chest_reinforced"; private const string ReinforcedBase = "piece_chest"; public const string TransferName = "soro_transfer_chest"; public const string TotemName = "soro_crafting_totem"; private const string ChestBase = "piece_chest_wood"; private static readonly string[] TotemBases = new string[3] { "piece_banner01", "wood_pole2", "guard_stone" }; private const string Workbench = "piece_workbench"; private static GameObject _holder; private static GameObject _production; private static GameObject _reinforced; private static GameObject _transfer; private static GameObject _totem; private static GameObject FindPrefab(string name) { if ((Object)(object)ZNetScene.instance != (Object)null)