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 CollectionChest v1.0.0
CollectionChest.dll
Decompiled 8 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; 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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("CollectionChest")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("A switch in the chest menu that makes a chest pull in items dropped right next to it.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("CollectionChest")] [assembly: AssemblyTitle("CollectionChest")] [assembly: AssemblyVersion("1.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 CollectionChest { internal class Collector : MonoBehaviour { private const string RpcSetCollecting = "CollectionChest_SetCollecting"; private static readonly int CollectingKey = StringExtensionMethods.GetStableHashCode("CollectionChest_Collecting"); private const int MaxDropsPerScan = 16; private static readonly Collider[] Hits = (Collider[])(object)new Collider[128]; private static readonly HashSet<ItemDrop> Seen = new HashSet<ItemDrop>(); private static int _itemMask; private Container _container; private ZNetView _nview; private Collider[] _colliders = Array.Empty<Collider>(); private float _scheduledInterval; private bool _wasLeavingItems; private bool _loggedError; internal bool IsCollecting { get { if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { return _nview.GetZDO().GetBool(CollectingKey, false); } return false; } } internal bool IsFull { get { Inventory val = (((Object)(object)_container != (Object)null) ? _container.GetInventory() : null); if (val != null) { return val.GetEmptySlots() <= 0; } return false; } } internal static void TryAttach(Container container) { ZNetView component = ((Component)container).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.GetZDO() != null && IsEligible(container) && !((Object)(object)((Component)container).GetComponent<Collector>() != (Object)null)) { ((Component)container).gameObject.AddComponent<Collector>(); } } internal static bool IsEligible(Container container) { if ((Object)(object)container.m_rootObjectOverride != (Object)null || (Object)(object)container.m_wagon != (Object)null) { return false; } if (container.m_autoDestroyEmpty) { return false; } if ((Object)(object)((Component)container).GetComponent<Piece>() == (Object)null) { return false; } if ((Object)(object)((Component)container).GetComponentInParent<Incinerator>() != (Object)null) { return false; } if ((Object)(object)((Component)container).GetComponentInParent<TombStone>() != (Object)null) { return false; } if ((Object)(object)((Component)container).GetComponentInParent<Corpse>() != (Object)null) { return false; } if ((Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null) { return false; } if ((Object)(object)((Component)container).GetComponentInParent<Vagon>() != (Object)null) { return false; } return true; } internal void RequestCollecting(bool on) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { _nview.InvokeRPC("CollectionChest_SetCollecting", new object[1] { on }); } } private void Awake() { _container = ((Component)this).GetComponent<Container>(); _nview = ((Component)this).GetComponent<ZNetView>(); List<Collider> list = new List<Collider>(); Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if (!val.isTrigger) { list.Add(val); } } _colliders = list.ToArray(); try { _nview.Register<bool>("CollectionChest_SetCollecting", (Action<long, bool>)RPC_SetCollecting); } catch (ArgumentException) { } Schedule(); } private void RPC_SetCollecting(long sender, bool on) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set(CollectingKey, on); if (ModConfig.VerboseLogging.Value) { Plugin.Log.LogInfo((object)(Describe() + ": auto-collect " + (on ? "on" : "off") + ".")); } if (on) { Scan(); } } } private void Schedule() { _scheduledInterval = ModConfig.ScanInterval.Value; ((MonoBehaviour)this).CancelInvoke("Scan"); ((MonoBehaviour)this).InvokeRepeating("Scan", Random.Range(0f, _scheduledInterval), _scheduledInterval); } private void Scan() { if (!Mathf.Approximately(_scheduledInterval, ModConfig.ScanInterval.Value)) { Schedule(); } else { if (!ModConfig.Enabled.Value || !IsCollecting || !_nview.IsOwner()) { return; } try { Collect(); } catch (Exception arg) { if (!_loggedError) { _loggedError = true; Plugin.Log.LogError((object)$"{Describe()}: collecting failed: {arg}"); } } } } private void Collect() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNetScene.instance == (Object)null) { return; } Inventory inventory = _container.GetInventory(); if (inventory == null || !GameAccess.TryRefresh(_container)) { return; } if (!Intake.HasAnyRoom(inventory)) { NoteLeavingItems(leaving: true); return; } if (_itemMask == 0) { _itemMask = LayerMask.GetMask(new string[1] { "item" }); } Bounds val = ChestBounds(); float value = ModConfig.Range.Value; Vector3 center = ((Bounds)(ref val)).center; Vector3 extents = ((Bounds)(ref val)).extents; int num = Physics.OverlapSphereNonAlloc(center, ((Vector3)(ref extents)).magnitude + value, Hits, _itemMask); int num2 = 0; bool leaving = false; try { for (int i = 0; i < num; i++) { if (num2 >= 16) { break; } ItemDrop val2 = Intake.DropFor(Hits[i]); if ((Object)(object)val2 == (Object)null || !Seen.Add(val2) || DistanceTo(((Component)val2).transform.position) > value) { continue; } string arg = val2.m_itemData?.m_shared?.m_name; int stored; switch (Intake.TryStore(val2, inventory, out stored)) { case Intake.Outcome.Stored: num2++; if (ModConfig.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"{Describe()}: stored {stored}x {arg}."); } break; case Intake.Outcome.Waiting: num2++; break; case Intake.Outcome.NoRoom: leaving = true; break; } } } finally { Array.Clear(Hits, 0, num); Seen.Clear(); } NoteLeavingItems(leaving); } private Bounds ChestBounds() { //IL_0004: 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_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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) //IL_003d: 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) bool flag = false; Bounds result = default(Bounds); Collider[] colliders = _colliders; foreach (Collider val in colliders) { if (Usable(val)) { if (flag) { ((Bounds)(ref result)).Encapsulate(val.bounds); continue; } result = val.bounds; flag = true; } } if (!flag) { return new Bounds(((Component)this).transform.position + Vector3.up * 0.5f, Vector3.one); } return result; } private float DistanceTo(Vector3 point) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) float num = float.MaxValue; Collider[] colliders = _colliders; Bounds val2; foreach (Collider val in colliders) { if (Usable(val)) { Vector3 val3; if (!HasExactClosestPoint(val)) { val2 = val.bounds; val3 = ((Bounds)(ref val2)).ClosestPoint(point); } else { val3 = val.ClosestPoint(point); } Vector3 val4 = val3; float num2 = num; Vector3 val5 = val4 - point; num = Mathf.Min(num2, ((Vector3)(ref val5)).sqrMagnitude); } } if (num == float.MaxValue) { val2 = ChestBounds(); num = ((Bounds)(ref val2)).SqrDistance(point); } return Mathf.Sqrt(num); } private static bool Usable(Collider collider) { if ((Object)(object)collider != (Object)null && collider.enabled) { return ((Component)collider).gameObject.activeInHierarchy; } return false; } private static bool HasExactClosestPoint(Collider collider) { if (!(collider is BoxCollider) && !(collider is SphereCollider) && !(collider is CapsuleCollider)) { MeshCollider val = (MeshCollider)(object)((collider is MeshCollider) ? collider : null); if (val != null) { return val.convex; } return false; } return true; } private void NoteLeavingItems(bool leaving) { if (leaving != _wasLeavingItems) { _wasLeavingItems = leaving; if (ModConfig.VerboseLogging.Value) { Plugin.Log.LogInfo((object)(leaving ? (Describe() + ": out of room, leaving items on the ground.") : (Describe() + ": has room again."))); } } } private string Describe() { //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_0027: 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_0043: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)this).transform.position; return $"{_container.m_name} at ({position.x:F0}, {position.y:F0}, {position.z:F0})"; } } internal static class CollectToggle { [CompilerGenerated] private static class <>O { public static UnityAction <0>__OnClick; } private const string ObjectName = "CollectionChest_AutoCollect"; private const float Width = 190f; private const float Gap = 8f; private const string OnLabel = "Auto-collect: <color=#9BD86B>ON</color>"; private const string OffLabel = "Auto-collect: <color=#A0A0A0>OFF</color>"; private static InventoryGui _builtFor; private static GameObject _button; private static TMP_Text _label; private static Collector _target; private static int _shownState = -1; internal static void Refresh(InventoryGui gui) { Container val = GameAccess.CurrentContainer(gui); Collector collector = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Collector>() : null); bool flag = (Object)(object)collector != (Object)null && ModConfig.Enabled.Value; if (flag) { EnsureBuilt(gui); } if ((Object)(object)_button == (Object)null) { return; } if (_button.activeSelf != flag) { _button.SetActive(flag); } _target = (flag ? collector : null); if (!flag) { return; } int num = (collector.IsCollecting ? 1 : 0); if (num != _shownState) { _shownState = num; if ((Object)(object)_label != (Object)null) { _label.text = ((num == 1) ? "Auto-collect: <color=#9BD86B>ON</color>" : "Auto-collect: <color=#A0A0A0>OFF</color>"); } } } private static void EnsureBuilt(InventoryGui gui) { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0118: 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_0123: Expected O, but got Unknown if ((Object)(object)_button != (Object)null && _builtFor == gui) { return; } if ((Object)(object)_button != (Object)null) { Object.Destroy((Object)(object)_button); } _builtFor = gui; _button = null; _label = null; _shownState = -1; Button takeAllButton = gui.m_takeAllButton; RectTransform container = gui.m_container; if ((Object)(object)takeAllButton == (Object)null || (Object)(object)container == (Object)null) { return; } GameObject val = Object.Instantiate<GameObject>(((Component)takeAllButton).gameObject, (Transform)(object)container, false); ((Object)val).name = "CollectionChest_AutoCollect"; val.SetActive(false); UIGamePad[] componentsInChildren = val.GetComponentsInChildren<UIGamePad>(true); foreach (UIGamePad val2 in componentsInChildren) { if ((Object)(object)val2.m_hint != (Object)null) { Object.DestroyImmediate((Object)(object)val2.m_hint); } Object.DestroyImmediate((Object)(object)val2); } Localize[] componentsInChildren2 = val.GetComponentsInChildren<Localize>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } Button component = val.GetComponent<Button>(); component.onClick = new ButtonClickedEvent(); ButtonClickedEvent onClick = component.onClick; object obj = <>O.<0>__OnClick; if (obj == null) { UnityAction val3 = OnClick; <>O.<0>__OnClick = val3; obj = (object)val3; } ((UnityEvent)onClick).AddListener((UnityAction)obj); ((Selectable)component).interactable = true; RectTransform val4 = (RectTransform)val.transform; val4.anchorMin = Vector2.zero; val4.anchorMax = Vector2.zero; val4.pivot = new Vector2(0f, 1f); val4.anchoredPosition = new Vector2(0f, -8f); val4.sizeDelta = new Vector2(190f, val4.sizeDelta.y); Transform val5 = val.transform.Find("Text"); _label = (((Object)(object)val5 != (Object)null) ? ((Component)val5).GetComponent<TMP_Text>() : val.GetComponentInChildren<TMP_Text>(true)); _button = val; if (ModConfig.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Auto-collect switch added under {((Object)container).name} (label found: {(Object)(object)_label != (Object)null})."); } } private static void OnClick() { if (!((Object)(object)_target == (Object)null)) { _target.RequestCollecting(!_target.IsCollecting); } } } internal static class GameAccess { private static Func<Container, bool> _containerLoad; private static bool _containerLoadResolved; private static FieldRef<InventoryGui, Container> _currentContainer; private static bool _currentContainerResolved; internal static bool TryRefresh(Container container) { if (!_containerLoadResolved) { _containerLoadResolved = true; try { _containerLoad = AccessTools.MethodDelegate<Func<Container, bool>>(AccessTools.Method(typeof(Container), "Load", Type.EmptyTypes, (Type[])null), (object)null, true); } catch (Exception ex) { _containerLoad = null; Plugin.Log.LogError((object)("Container.Load not found (" + ex.GetType().Name + "); chests will not collect, because a chest this client cannot refresh might overwrite another player's changes.")); } } if (_containerLoad == null) { return false; } _containerLoad(container); return true; } internal static Container CurrentContainer(InventoryGui gui) { if ((Object)(object)gui == (Object)null) { return null; } if (!_currentContainerResolved) { _currentContainerResolved = true; try { _currentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer"); } catch (Exception ex) { _currentContainer = null; Plugin.Log.LogError((object)("InventoryGui.m_currentContainer not found (" + ex.GetType().Name + "); the chest menu switch is disabled. Chests already switched on keep collecting.")); } } FieldRef<InventoryGui, Container> currentContainer = _currentContainer; if (currentContainer == null) { return null; } return currentContainer.Invoke(gui); } } internal static class Intake { internal enum Outcome { Ignored, NoRoom, Waiting, Stored } internal static ItemDrop DropFor(Collider hit) { Rigidbody attachedRigidbody = hit.attachedRigidbody; if ((Object)(object)attachedRigidbody == (Object)null) { return null; } ItemDrop component = ((Component)attachedRigidbody).GetComponent<ItemDrop>(); if ((Object)(object)component != (Object)null) { return component; } FloatingTerrainDummy component2 = ((Component)attachedRigidbody).GetComponent<FloatingTerrainDummy>(); if ((Object)(object)component2 == (Object)null || (Object)(object)component2.m_parent == (Object)null) { return null; } return ((Component)component2.m_parent).GetComponent<ItemDrop>(); } internal static Outcome TryStore(ItemDrop drop, Inventory inventory, out int stored) { stored = 0; ZNetView component = ((Component)drop).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return Outcome.Ignored; } drop.Load(); if (!IsCollectable(drop)) { return Outcome.Ignored; } ItemData itemData = drop.m_itemData; if (itemData.m_stack <= 0) { return Outcome.Ignored; } int num = RoomFor(inventory, itemData); if (num <= 0) { return Outcome.NoRoom; } if (!drop.CanPickup(true)) { drop.RequestOwn(); return Outcome.Waiting; } stored = Store(drop, component, inventory, num); if (stored <= 0) { return Outcome.NoRoom; } return Outcome.Stored; } internal static int RoomFor(Inventory inventory, ItemData item) { int num = Mathf.Max(0, inventory.GetEmptySlots()); int maxStackSize = item.m_shared.m_maxStackSize; if (maxStackSize <= 1) { return num; } long num2 = (long)num * (long)maxStackSize; foreach (ItemData allItem in inventory.GetAllItems()) { if (SameStack(allItem, item) && allItem.m_stack < allItem.m_shared.m_maxStackSize) { num2 += allItem.m_shared.m_maxStackSize - allItem.m_stack; } } return (int)Math.Min(num2, 2147483647L); } internal static bool HasAnyRoom(Inventory inventory) { if (inventory.GetEmptySlots() > 0) { return true; } foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_stack < allItem.m_shared.m_maxStackSize) { return true; } } return false; } private static bool IsCollectable(ItemDrop drop) { if (drop.IsPiece()) { return false; } ItemData itemData = drop.m_itemData; if (itemData == null || itemData.m_shared == null) { return false; } if ((Object)(object)itemData.m_dropPrefab == (Object)null) { return false; } ItemDrop component = itemData.m_dropPrefab.GetComponent<ItemDrop>(); if ((Object)(object)component != (Object)null && !component.m_autoPickup) { return false; } if (itemData.m_shared.m_questItem) { return false; } Sprite[] icons = itemData.m_shared.m_icons; if (icons == null || icons.Length == 0 || itemData.m_variant >= icons.Length) { return false; } if (drop.InTar()) { return false; } Fish component2 = ((Component)drop).GetComponent<Fish>(); if ((Object)(object)component2 != (Object)null && !component2.IsOutOfWater()) { return false; } return true; } private static int Store(ItemDrop drop, ZNetView nview, Inventory inventory, int room) { ItemData itemData = drop.m_itemData; int stack = itemData.m_stack; int num = CountOf(inventory, itemData); int num2 = 0; try { AddUpTo(inventory, itemData, Mathf.Min(stack, room)); } finally { num2 = CountOf(inventory, itemData) - num; if (num2 >= stack) { ZNetScene.instance.Destroy(((Component)drop).gameObject); } else if (num2 > 0) { itemData.m_stack = stack - num2; ItemDrop.SaveToZDO(itemData, nview.GetZDO(), -1); } } return Mathf.Max(0, num2); } internal static void AddUpTo(Inventory inventory, ItemData item, int want) { int num = Mathf.Max(1, item.m_shared.m_maxStackSize); int num2 = want; while (num2 > 0) { ItemData val = item.Clone(); val.m_stack = Mathf.Min(num2, num); val.m_equipped = false; int stack = val.m_stack; bool flag = inventory.AddItem(val); int num3 = (flag ? stack : (stack - val.m_stack)); if (num3 > 0) { num2 -= num3; if (!flag) { break; } continue; } break; } } internal static int CountOf(Inventory inventory, ItemData item) { int num = 0; foreach (ItemData allItem in inventory.GetAllItems()) { if (SameStack(allItem, item)) { num += allItem.m_stack; } } return num; } private static bool SameStack(ItemData a, ItemData b) { if (a.m_shared.m_name == b.m_shared.m_name && a.m_quality == b.m_quality) { return a.m_worldLevel == b.m_worldLevel; } return false; } } internal static class ModConfig { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> Range; internal static ConfigEntry<float> ScanInterval; internal static ConfigEntry<bool> ShowHoverStatus; internal static ConfigEntry<bool> VerboseLogging; internal static void Bind(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown Enabled = config.Bind<bool>("General", "Enabled", true, "Master switch. While off no chest collects anything and the switch is hidden from the chest menu. Chests you have already switched on remember it and pick back up when you turn this on again."); Range = config.Bind<float>("Collection", "Range", 1f, new ConfigDescription("How far a dropped item can be from the chest and still get pulled in, in metres. Measured from the chest's sides and lid, not its centre, so an item resting on the chest is at 0 and a bigger chest does not reach further than a small one. Kept tight on purpose: a chest under a smelter should catch that smelter's output and not the one beside it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 4f), Array.Empty<object>())); ScanInterval = config.Bind<float>("Collection", "ScanInterval", 1f, new ConfigDescription("Seconds between each switched-on chest checking for dropped items. Machines produce every 30 seconds or more, so there is little to gain below 1.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>())); ShowHoverStatus = config.Bind<bool>("Display", "ShowHoverStatus", true, "Add a line to a switched-on chest's hover text, and say when it is full."); VerboseLogging = config.Bind<bool>("Advanced", "VerboseLogging", false, "Log every item a chest collects, and why it left one on the ground, to the BepInEx console."); } } [BepInPlugin("com.ljindustries.valheim.collectionchest", "CollectionChest", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string ModGuid = "com.ljindustries.valheim.collectionchest"; public const string ModName = "CollectionChest"; public const string ModVersion = "1.0.0"; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModConfig.Bind(((BaseUnityPlugin)this).Config); _harmony = new Harmony("com.ljindustries.valheim.collectionchest"); Type[] types = typeof(Plugin).Assembly.GetTypes(); foreach (Type type in types) { try { _harmony.CreateClassProcessor(type).Patch(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Harmony skip " + type.FullName + ": " + ex.GetType().Name + ": " + ex.Message)); } } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace CollectionChest.Patches { [HarmonyPatch(typeof(Container), "Awake")] internal static class ContainerAwakePatch { private static void Postfix(Container __instance) { Collector.TryAttach(__instance); } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class ContainerHoverTextPatch { private static void Postfix(Container __instance, ref string __result) { if (ModConfig.Enabled.Value && ModConfig.ShowHoverStatus.Value) { Collector component = ((Component)__instance).GetComponent<Collector>(); if (!((Object)(object)component == (Object)null) && component.IsCollecting) { __result += (component.IsFull ? "\n<color=#E8A33D>Auto-collect on - full</color>" : "\n<color=#9BD86B>Auto-collect on</color>"); } } } } [HarmonyPatch(typeof(InventoryGui), "UpdateContainer")] internal static class InventoryGuiUpdateContainerPatch { private static void Postfix(InventoryGui __instance) { CollectToggle.Refresh(__instance); } } }