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 CraftManager v1.0.2
BepInEx/plugins/CraftManager/CraftManager.dll
Decompiled a week agousing 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.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.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 CraftManager { [HarmonyPatch(typeof(InventoryGui), "Awake")] internal static class CraftingUiPatch { [CompilerGenerated] private static class <>O { public static UnityAction <0>__DecreaseRequestedCraftCount; public static UnityAction <1>__IncreaseRequestedCraftCount; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__19_0; internal void <CreateToggleButton>b__19_0() { SetModControlsVisible(!_modControlsVisible); } } private const string ButtonObjectName = "CraftManagerGetMaterialsButton"; private const int MinimumCraftCount = 1; private const int MaximumCraftCount = 99; private static int _requestedCraftCount = 1; private static Button? _getMaterialsButton; private static GameObject? _craftActionButtonObject; private static GameObject? _decreaseButtonObject; private static GameObject? _increaseButtonObject; private static readonly List<GameObject> ModControls = new List<GameObject>(); private static bool _modControlsVisible; private static void Postfix(InventoryGui __instance) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017f: 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_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Expected O, but got Unknown Button value = Traverse.Create((object)__instance).Field<Button>("m_craftButton").Value; RectTransform val = (RectTransform)(((Object)(object)value == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/); if ((Object)(object)value == (Object)null || (Object)(object)val == (Object)null || (Object)(object)((Transform)val).Find("CraftManagerGetMaterialsButton") != (Object)null) { return; } GameObject val2 = Object.Instantiate<GameObject>(((Component)value).gameObject, (Transform)(object)val); ((Object)val2).name = "CraftManagerGetMaterialsButton"; DisableLayoutComponents(val2); RectTransform component = ((Component)value).GetComponent<RectTransform>(); RectTransform component2 = val2.GetComponent<RectTransform>(); Rect rect = component.rect; float num = ((Rect)(ref rect)).width - 124f; float num2 = (num - 4f) / 2f; Vector3 position = ((Transform)component).position; rect = component.rect; Vector3 val3 = position + new Vector3(0f, 0f - (((Rect)(ref rect)).height + 2f), 0f); rect = component.rect; SetFixedButtonAnchors(component2, num2, ((Rect)(ref rect)).height); ((Transform)component2).position = val3 + new Vector3(0f - (num2 / 2f + 2f), 0f, 0f); Button component3 = val2.GetComponent<Button>(); ((UnityEventBase)component3.onClick).RemoveAllListeners(); ((UnityEvent)component3.onClick).AddListener((UnityAction)delegate { CraftManagerService.TryGetMaterials(__instance, _requestedCraftCount); }); _getMaterialsButton = component3; ModControls.Add(val2); UpdateGetMaterialsLabel(); rect = component.rect; CreateCraftButton(value, val, val3, num2, ((Rect)(ref rect)).height, __instance); object obj = <>O.<0>__DecreaseRequestedCraftCount; if (obj == null) { UnityAction val4 = DecreaseRequestedCraftCount; <>O.<0>__DecreaseRequestedCraftCount = val4; obj = (object)val4; } CreateQuantityButton(value, val, val3, num, "CraftManagerDecreaseButton", "−", -1f, (UnityAction)obj); object obj2 = <>O.<1>__IncreaseRequestedCraftCount; if (obj2 == null) { UnityAction val5 = IncreaseRequestedCraftCount; <>O.<1>__IncreaseRequestedCraftCount = val5; obj2 = (object)val5; } CreateQuantityButton(value, val, val3, num, "CraftManagerIncreaseButton", "+", 1f, (UnityAction)obj2); Button value2 = Traverse.Create((object)__instance).Field<Button>("m_repairButton").Value; if ((Object)(object)value2 != (Object)null) { RectTransform val6 = CreateToggleButton(value2, value); if ((Object)(object)val6 != (Object)null) { PositionControlsAsSideMenu(val6); } } SetModControlsVisible(visible: false); } private static void CreateCraftButton(Button template, RectTransform controlsRoot, Vector3 actionRowPosition, float width, float height, InventoryGui gui) { //IL_003b: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, (Transform)(object)controlsRoot); ((Object)val).name = "CraftManagerCraftButton"; DisableLayoutComponents(val); RectTransform component = val.GetComponent<RectTransform>(); SetFixedButtonAnchors(component, width, height); ((Transform)component).position = actionRowPosition + new Vector3(width / 2f + 2f, 0f, 0f); Button component2 = val.GetComponent<Button>(); ((UnityEventBase)component2.onClick).RemoveAllListeners(); ((UnityEvent)component2.onClick).AddListener((UnityAction)delegate { CraftManagerService.CraftSelectedRecipe(gui, _requestedCraftCount); }); ModControls.Add(val); _craftActionButtonObject = val; TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); for (int num = 0; num < componentsInChildren.Length; num++) { componentsInChildren[num].text = "Craft"; } } private static void CreateQuantityButton(Button template, RectTransform controlsRoot, Vector3 actionRowPosition, float actionAreaWidth, string objectName, string labelText, float side, UnityAction onClick) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, (Transform)(object)controlsRoot); ((Object)val).name = objectName; DisableLayoutComponents(val); RectTransform component = val.GetComponent<RectTransform>(); SetFixedButtonAnchors(component, 52f, 72f); float num = side * ((actionAreaWidth + 52f) / 2f + 6f); ((Transform)component).position = actionRowPosition + new Vector3(num, 0f, 0f); Button component2 = val.GetComponent<Button>(); ((UnityEventBase)component2.onClick).RemoveAllListeners(); ((UnityEvent)component2.onClick).AddListener(onClick); ModControls.Add(val); if (side < 0f) { _decreaseButtonObject = val; } else { _increaseButtonObject = val; } TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].text = labelText; } } private static void DisableLayoutComponents(GameObject buttonObject) { LayoutElement[] components = buttonObject.GetComponents<LayoutElement>(); for (int i = 0; i < components.Length; i++) { ((Behaviour)components[i]).enabled = false; } ContentSizeFitter[] components2 = buttonObject.GetComponents<ContentSizeFitter>(); for (int i = 0; i < components2.Length; i++) { ((Behaviour)components2[i]).enabled = false; } } private static void SetFixedButtonAnchors(RectTransform buttonTransform, float width, float height) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) buttonTransform.anchorMin = new Vector2(0.5f, 0.5f); buttonTransform.anchorMax = new Vector2(0.5f, 0.5f); buttonTransform.pivot = new Vector2(0.5f, 0.5f); buttonTransform.SetSizeWithCurrentAnchors((Axis)0, width); buttonTransform.SetSizeWithCurrentAnchors((Axis)1, height); } private static void DecreaseRequestedCraftCount() { _requestedCraftCount = Mathf.Max(1, _requestedCraftCount - 1); UpdateGetMaterialsLabel(); } private static void IncreaseRequestedCraftCount() { _requestedCraftCount = Mathf.Min(99, _requestedCraftCount + 1); UpdateGetMaterialsLabel(); } private static void UpdateGetMaterialsLabel() { if (!((Object)(object)_getMaterialsButton == (Object)null)) { TMP_Text[] componentsInChildren = ((Component)_getMaterialsButton).GetComponentsInChildren<TMP_Text>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].text = $"Get Materials x{_requestedCraftCount}"; } } } internal static void ResetRequestedCraftCount() { _requestedCraftCount = 1; UpdateGetMaterialsLabel(); SetModControlsVisible(visible: false); } private static RectTransform? CreateToggleButton(Button repairButton, Button textTemplate) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //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) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) Transform parent = ((Component)repairButton).transform.parent; if ((Object)(object)parent == (Object)null || (Object)(object)parent.Find("CraftManagerToggleButton") != (Object)null) { return null; } GameObject val = Object.Instantiate<GameObject>(((Component)repairButton).gameObject, parent); ((Object)val).name = "CraftManagerToggleButton"; DisableLayoutComponents(val); RectTransform component = ((Component)repairButton).GetComponent<RectTransform>(); RectTransform component2 = val.GetComponent<RectTransform>(); component2.anchorMin = component.anchorMin; component2.anchorMax = component.anchorMax; component2.pivot = component.pivot; Rect rect = component.rect; component2.SetSizeWithCurrentAnchors((Axis)0, ((Rect)(ref rect)).width); rect = component.rect; component2.SetSizeWithCurrentAnchors((Axis)1, ((Rect)(ref rect)).height); Vector3 position = ((Transform)component).position; rect = component.rect; ((Transform)component2).position = position - new Vector3(0f, ((Rect)(ref rect)).height + 6f, 0f); Button component3 = val.GetComponent<Button>(); ((UnityEventBase)component3.onClick).RemoveAllListeners(); ButtonClickedEvent onClick = component3.onClick; object obj = <>c.<>9__19_0; if (obj == null) { UnityAction val2 = delegate { SetModControlsVisible(!_modControlsVisible); }; <>c.<>9__19_0 = val2; obj = (object)val2; } ((UnityEvent)onClick).AddListener((UnityAction)obj); UITooltip component4 = val.GetComponent<UITooltip>(); if ((Object)(object)component4 != (Object)null) { Traverse.Create((object)component4).Field("m_text").SetValue((object)"Show/hide Craft Manager storage controls"); } Image[] componentsInChildren = val.GetComponentsInChildren<Image>(true); foreach (Image val3 in componentsInChildren) { if ((Object)(object)((Component)val3).gameObject != (Object)(object)val) { ((Behaviour)val3).enabled = false; } } TMP_Text val4 = ((Component)textTemplate).GetComponentsInChildren<TMP_Text>(true).FirstOrDefault(); if ((Object)(object)val4 == (Object)null) { return component2; } GameObject obj2 = Object.Instantiate<GameObject>(((Component)val4).gameObject, val.transform); DisableLayoutComponents(obj2); RectTransform component5 = obj2.GetComponent<RectTransform>(); component5.anchorMin = Vector2.zero; component5.anchorMax = Vector2.one; component5.offsetMin = Vector2.zero; component5.offsetMax = Vector2.zero; TMP_Text component6 = obj2.GetComponent<TMP_Text>(); component6.text = "▣"; component6.alignment = (TextAlignmentOptions)514; component6.fontSize = 32f; return component2; } private static void PositionControlsAsSideMenu(RectTransform toggleTransform) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0167: 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_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_getMaterialsButton == (Object)null) && !((Object)(object)_craftActionButtonObject == (Object)null) && !((Object)(object)_decreaseButtonObject == (Object)null) && !((Object)(object)_increaseButtonObject == (Object)null)) { RectTransform component = ((Component)_getMaterialsButton).GetComponent<RectTransform>(); RectTransform component2 = _craftActionButtonObject.GetComponent<RectTransform>(); RectTransform component3 = _decreaseButtonObject.GetComponent<RectTransform>(); RectTransform component4 = _increaseButtonObject.GetComponent<RectTransform>(); float x = ((Transform)toggleTransform).position.x; Rect rect = toggleTransform.rect; float num = x + ((Rect)(ref rect)).width / 2f; rect = component.rect; float num2 = num - ((Rect)(ref rect)).width / 2f; float y = ((Transform)toggleTransform).position.y; rect = toggleTransform.rect; float num3 = y - ((Rect)(ref rect)).height / 2f - 5f; rect = component.rect; float num4 = num3 - ((Rect)(ref rect)).height / 2f; rect = component.rect; float num5 = num4 - ((Rect)(ref rect)).height / 2f - 5f; rect = component2.rect; float num6 = num5 - ((Rect)(ref rect)).height / 2f; rect = component2.rect; float num7 = num6 - ((Rect)(ref rect)).height / 2f - 5f; rect = component3.rect; float num8 = num7 - ((Rect)(ref rect)).height / 2f; ((Transform)component).position = new Vector3(num2, num4, 0f); ((Transform)component2).position = new Vector3(num2, num6, 0f); rect = component.rect; float num9 = num - ((Rect)(ref rect)).width; rect = component3.rect; ((Transform)component3).position = new Vector3(num9 + ((Rect)(ref rect)).width / 2f, num8, 0f); rect = component4.rect; ((Transform)component4).position = new Vector3(num - ((Rect)(ref rect)).width / 2f, num8, 0f); } } private static void SetModControlsVisible(bool visible) { _modControlsVisible = visible; foreach (GameObject modControl in ModControls) { if ((Object)(object)modControl != (Object)null) { modControl.SetActive(visible); } } } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] internal static class CraftingMaterialTotalsPatch { private static readonly Regex QuantityLabelPattern = new Regex("^\\d+(?:/\\d+)?$"); private static readonly Regex ExistingTotalPattern = new Regex("/\\d+$"); private static readonly Regex RichTextTagPattern = new Regex("<.*?>"); private static readonly Regex RequiredAmountPattern = new Regex("^\\d+"); private static void Postfix(InventoryGui __instance) { Player localPlayer = Player.m_localPlayer; Recipe val = (((Object)(object)localPlayer == (Object)null) ? null : CraftManagerService.GetSelectedRecipe(__instance)); if ((Object)(object)localPlayer == (Object)null || (Object)(object)val == (Object)null) { return; } GameObject[] value = Traverse.Create((object)__instance).Field<GameObject[]>("m_recipeRequirementList").Value; if (value == null) { return; } IReadOnlyDictionary<string, int> nearbyStoredItemTotals = CraftManagerService.GetNearbyStoredItemTotals(localPlayer); Requirement[] array = val.m_resources.Where((Requirement requirement) => (Object)(object)requirement?.m_resItem != (Object)null).ToArray(); foreach (Requirement val2 in array) { string itemName = val2.m_resItem.m_itemData.m_shared.m_name; string localizedItemName = Localization.instance.Localize(itemName); GameObject val3 = ((IEnumerable<GameObject>)value).FirstOrDefault((Func<GameObject, bool>)((GameObject candidate) => (Object)(object)candidate != (Object)null && candidate.GetComponentsInChildren<TMP_Text>(true).Any((TMP_Text label) => RichTextTagPattern.Replace(label.text, string.Empty) == localizedItemName))); if ((Object)(object)val3 == (Object)null) { continue; } nearbyStoredItemTotals.TryGetValue(itemName, out var value2); int num2 = (from item in ((Humanoid)localPlayer).GetInventory().GetAllItems() where item.m_shared.m_name == itemName select item).Sum((ItemData item) => item.m_stack); TMP_Text val4 = ((IEnumerable<TMP_Text>)val3.GetComponentsInChildren<TMP_Text>(true)).FirstOrDefault((Func<TMP_Text, bool>)((TMP_Text label) => QuantityLabelPattern.IsMatch(RichTextTagPattern.Replace(label.text, string.Empty)))); if (!((Object)(object)val4 == (Object)null)) { string input = RichTextTagPattern.Replace(val4.text, string.Empty); input = ExistingTotalPattern.Replace(input, string.Empty); Match match = RequiredAmountPattern.Match(input); if (match.Success && int.TryParse(match.Value, out var result)) { string arg = ((num2 >= result) ? "white" : ((num2 + value2 >= result) ? "#FFD24A" : "#FF5555")); val4.text = $"<color={arg}>{result}</color>/<color=white>{value2}</color>"; } } } } } [HarmonyPatch(typeof(Hud), "SetupPieceInfo")] internal static class HammerMaterialTotalsPatch { private static readonly Regex QuantityLabelPattern = new Regex("^\\d+(?:/\\d+)?$"); private static readonly Regex ExistingTotalPattern = new Regex("/\\d+$"); private static readonly Regex RichTextTagPattern = new Regex("<.*?>"); private static readonly Regex RequiredAmountPattern = new Regex("^\\d+"); private static void Postfix(Hud __instance, Piece piece) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)piece == (Object)null) { return; } GameObject[] value = Traverse.Create((object)__instance).Field<GameObject[]>("m_requirementItems").Value; if (value == null) { return; } IReadOnlyDictionary<string, int> nearbyStoredItemTotals = CraftManagerService.GetNearbyStoredItemTotals(localPlayer); Requirement[] array = piece.m_resources.Where((Requirement requirement) => (Object)(object)requirement?.m_resItem != (Object)null).ToArray(); foreach (Requirement val in array) { string itemName = val.m_resItem.m_itemData.m_shared.m_name; string localizedItemName = Localization.instance.Localize(itemName); GameObject val2 = ((IEnumerable<GameObject>)value).FirstOrDefault((Func<GameObject, bool>)((GameObject candidate) => (Object)(object)candidate != (Object)null && candidate.GetComponentsInChildren<TMP_Text>(true).Any((TMP_Text label) => RichTextTagPattern.Replace(label.text, string.Empty) == localizedItemName))); if ((Object)(object)val2 == (Object)null) { continue; } nearbyStoredItemTotals.TryGetValue(itemName, out var value2); int num2 = (from item in ((Humanoid)localPlayer).GetInventory().GetAllItems() where item.m_shared.m_name == itemName select item).Sum((ItemData item) => item.m_stack); TMP_Text val3 = ((IEnumerable<TMP_Text>)val2.GetComponentsInChildren<TMP_Text>(true)).FirstOrDefault((Func<TMP_Text, bool>)((TMP_Text label) => QuantityLabelPattern.IsMatch(RichTextTagPattern.Replace(label.text, string.Empty)))); if (!((Object)(object)val3 == (Object)null)) { string input = ExistingTotalPattern.Replace(RichTextTagPattern.Replace(val3.text, string.Empty), string.Empty); Match match = RequiredAmountPattern.Match(input); if (match.Success && int.TryParse(match.Value, out var result)) { string arg = ((num2 >= result) ? "white" : ((num2 + value2 >= result) ? "#FFD24A" : "#FF5555")); val3.text = $"<color={arg}>{result}</color>/<color=white>{value2}</color>"; } } } } } [HarmonyPatch(typeof(InventoryGui), "Hide")] internal static class CraftingUiClosePatch { private static void Postfix() { CraftingUiPatch.ResetRequestedCraftCount(); } } [HarmonyPatch(typeof(InventoryGui), "Awake")] internal static class ContainerSortUiPatch { private const string SortButtonObjectName = "CraftManagerSortButton"; private static void Postfix(InventoryGui __instance) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_00fa: 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_012b: Expected O, but got Unknown Button value = Traverse.Create((object)__instance).Field<Button>("m_takeAllButton").Value; if (!((Object)(object)value == (Object)null) && !((Object)(object)((Component)value).transform.parent.Find("CraftManagerSortButton") != (Object)null)) { GameObject obj = Object.Instantiate<GameObject>(((Component)value).gameObject, ((Component)value).transform.parent); ((Object)obj).name = "CraftManagerSortButton"; DisableLayoutComponents(obj); RectTransform component = ((Component)value).GetComponent<RectTransform>(); RectTransform component2 = obj.GetComponent<RectTransform>(); component2.anchorMin = component.anchorMin; component2.anchorMax = component.anchorMax; component2.pivot = component.pivot; Rect rect = component.rect; component2.SetSizeWithCurrentAnchors((Axis)0, ((Rect)(ref rect)).width); rect = component.rect; component2.SetSizeWithCurrentAnchors((Axis)1, ((Rect)(ref rect)).height); Vector3 position = ((Transform)component).position; rect = component.rect; ((Transform)component2).position = position - new Vector3(0f, ((Rect)(ref rect)).height + 6f, 0f); Button component3 = obj.GetComponent<Button>(); ((UnityEventBase)component3.onClick).RemoveAllListeners(); ((UnityEvent)component3.onClick).AddListener((UnityAction)delegate { CraftManagerService.SortOpenContainer(__instance); }); TMP_Text[] componentsInChildren = obj.GetComponentsInChildren<TMP_Text>(true); for (int num = 0; num < componentsInChildren.Length; num++) { componentsInChildren[num].text = "Sort"; } } } private static void DisableLayoutComponents(GameObject buttonObject) { LayoutElement[] components = buttonObject.GetComponents<LayoutElement>(); for (int i = 0; i < components.Length; i++) { ((Behaviour)components[i]).enabled = false; } ContentSizeFitter[] components2 = buttonObject.GetComponents<ContentSizeFitter>(); for (int i = 0; i < components2.Length; i++) { ((Behaviour)components2[i]).enabled = false; } } } [HarmonyPatch(typeof(InventoryGui), "Awake")] internal static class TrashSlotUiPatch { private const string TrashObjectName = "CraftManagerTrashSlot"; internal static RectTransform? TrashTransform { get; private set; } private static void Postfix(InventoryGui __instance) { //IL_00bc: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: 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_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) TMP_Text value = Traverse.Create((object)__instance).Field<TMP_Text>("m_weight").Value; Button value2 = Traverse.Create((object)__instance).Field<Button>("m_repairButton").Value; Button value3 = Traverse.Create((object)__instance).Field<Button>("m_takeAllButton").Value; if ((Object)(object)value == (Object)null || (Object)(object)value2 == (Object)null || (Object)(object)value3 == (Object)null || (Object)(object)value.transform.parent.Find("CraftManagerTrashSlot") != (Object)null) { return; } GameObject val = Object.Instantiate<GameObject>(((Component)value2).gameObject, value.transform.parent); ((Object)val).name = "CraftManagerTrashSlot"; ContainerSortUiPatchDisableLayout(val); RectTransform component = ((Component)value).GetComponent<RectTransform>(); RectTransform component2 = ((Component)value2).GetComponent<RectTransform>(); RectTransform component3 = val.GetComponent<RectTransform>(); component3.anchorMin = component.anchorMin; component3.anchorMax = component.anchorMax; component3.pivot = component.pivot; Rect rect = component2.rect; component3.SetSizeWithCurrentAnchors((Axis)0, ((Rect)(ref rect)).width); rect = component2.rect; component3.SetSizeWithCurrentAnchors((Axis)1, ((Rect)(ref rect)).height); ((Transform)component3).position = ((Transform)component).position + new Vector3(0f, 85f, 0f); TrashTransform = component3; ((UnityEventBase)val.GetComponent<Button>().onClick).RemoveAllListeners(); UITooltip component4 = val.GetComponent<UITooltip>(); if ((Object)(object)component4 != (Object)null) { Traverse.Create((object)component4).Field("m_text").SetValue((object)"Permanently delete a dragged item"); } Image[] componentsInChildren = val.GetComponentsInChildren<Image>(true); foreach (Image val2 in componentsInChildren) { if ((Object)(object)((Component)val2).gameObject != (Object)(object)val) { ((Behaviour)val2).enabled = false; } } TMP_Text val3 = ((Component)value3).GetComponentsInChildren<TMP_Text>(true).FirstOrDefault(); if (!((Object)(object)val3 == (Object)null)) { GameObject obj = Object.Instantiate<GameObject>(((Component)val3).gameObject, val.transform); ContainerSortUiPatchDisableLayout(obj); RectTransform component5 = obj.GetComponent<RectTransform>(); component5.anchorMin = Vector2.zero; component5.anchorMax = Vector2.one; component5.offsetMin = Vector2.zero; component5.offsetMax = Vector2.zero; TMP_Text component6 = obj.GetComponent<TMP_Text>(); component6.text = string.Empty; component6.alignment = (TextAlignmentOptions)514; component6.fontSize = 34f; CreateTrashBinIcon(val.transform); CreateEmptyButton(value, value3, __instance); } } private static void CreateEmptyButton(TMP_Text weightLabel, Button template, InventoryGui gui) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown Transform parent = weightLabel.transform.parent; if (!((Object)(object)parent.Find("CraftManagerEmptyButton") != (Object)null)) { GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, parent); ((Object)val).name = "CraftManagerEmptyButton"; ContainerSortUiPatchDisableLayout(val); RectTransform component = ((Component)weightLabel).GetComponent<RectTransform>(); RectTransform component2 = val.GetComponent<RectTransform>(); component2.anchorMin = component.anchorMin; component2.anchorMax = component.anchorMax; component2.pivot = component.pivot; component2.SetSizeWithCurrentAnchors((Axis)0, 68f); component2.SetSizeWithCurrentAnchors((Axis)1, 29f); ((Transform)component2).position = ((Transform)component).position + new Vector3(5f, -48f, 0f); Button component3 = val.GetComponent<Button>(); ((UnityEventBase)component3.onClick).RemoveAllListeners(); ((UnityEvent)component3.onClick).AddListener((UnityAction)delegate { CraftManagerService.EmptyInventoryIntoExistingStacks(gui); }); TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text obj in componentsInChildren) { obj.text = "Empty"; obj.fontSize = 18f; } UITooltip component4 = val.GetComponent<UITooltip>(); if ((Object)(object)component4 != (Object)null) { Traverse.Create((object)component4).Field("m_text").SetValue((object)"Move non-hotbar, non-equipped items into matching nearby storage stacks"); } } } private static void CreateTrashBinIcon(Transform parent) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) Color color = default(Color); ((Color)(ref color))..ctor(0.94f, 0.63f, 0.18f, 1f); Color color2 = default(Color); ((Color)(ref color2))..ctor(0.36f, 0.2f, 0.06f, 1f); CreateIconPart(parent, "BinBody", 20f, 23f, new Vector2(0f, -3f), color); CreateIconPart(parent, "BinLid", 25f, 4f, new Vector2(0f, 11f), color); CreateIconPart(parent, "BinHandle", 9f, 4f, new Vector2(0f, 15f), color); CreateIconPart(parent, "BinLineLeft", 2f, 15f, new Vector2(-5f, -4f), color2); CreateIconPart(parent, "BinLineRight", 2f, 15f, new Vector2(5f, -4f), color2); } private static void CreateIconPart(Transform parent, string name, float width, float height, Vector2 position, Color color) { //IL_002e: 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) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = position; component.SetSizeWithCurrentAnchors((Axis)0, width); component.SetSizeWithCurrentAnchors((Axis)1, height); ((Graphic)val.GetComponent<Image>()).color = color; } private static void ContainerSortUiPatchDisableLayout(GameObject objectToAdjust) { LayoutElement[] components = objectToAdjust.GetComponents<LayoutElement>(); for (int i = 0; i < components.Length; i++) { ((Behaviour)components[i]).enabled = false; } ContentSizeFitter[] components2 = objectToAdjust.GetComponents<ContentSizeFitter>(); for (int i = 0; i < components2.Length; i++) { ((Behaviour)components2[i]).enabled = false; } } } [HarmonyPatch(typeof(InventoryGui), "UpdateItemDrag")] internal static class TrashSlotDropPatch { private static bool Prefix(InventoryGui __instance) { if (!Input.GetMouseButtonUp(0)) { return true; } return !TryDeleteDraggedItem(__instance); } private static bool TryDeleteDraggedItem(InventoryGui __instance) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) RectTransform trashTransform = TrashSlotUiPatch.TrashTransform; if ((Object)(object)trashTransform == (Object)null || !((Component)trashTransform).gameObject.activeInHierarchy || !RectTransformUtility.RectangleContainsScreenPoint(trashTransform, Vector2.op_Implicit(Input.mousePosition))) { return false; } Traverse val = Traverse.Create((object)__instance); ItemData value = val.Field<ItemData>("m_dragItem").Value; Inventory value2 = val.Field<Inventory>("m_dragInventory").Value; int value3 = val.Field<int>("m_dragAmount").Value; if (value == null || value2 == null || value3 <= 0) { return false; } if (!value2.RemoveItem(value, value3)) { return false; } GameObject value4 = val.Field<GameObject>("m_dragGo").Value; if ((Object)(object)value4 != (Object)null) { Object.Destroy((Object)(object)value4); } val.Field("m_dragGo").SetValue((object)null); val.Field("m_dragItem").SetValue((object)null); val.Field("m_dragInventory").SetValue((object)null); val.Field("m_dragAmount").SetValue((object)0); val.Property("IsSplitDropping", (object[])null).SetValue((object)false); return true; } } [BepInPlugin("com.alik9.valheim.craftmanager", "Craft Manager", "1.0.2")] public sealed class CraftManagerPlugin : BaseUnityPlugin { public const string PluginGuid = "com.alik9.valheim.craftmanager"; public const string PluginName = "Craft Manager"; public const string PluginVersion = "1.0.2"; internal static ConfigEntry<float> ContainerSearchRadius { get; private set; } internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; ContainerSearchRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Craft Manager", "Container search radius", 100f, "Maximum distance, in meters, for nearby containers. This first version searches loaded containers only."); new Harmony("com.alik9.valheim.craftmanager").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Craft Manager 1.0.2 loaded successfully. Crafting, storage totals, silent hammer material pulling, container sorting, trash, and inventory emptying are enabled."); } } internal static class CraftManagerService { private static readonly FieldInfo SelectedRecipeField = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe"); internal static void TryGetMaterials(InventoryGui gui, int craftCount) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !gui.InCraftTab()) { ShowMessage("Open the Craft tab and select a recipe first."); return; } Recipe selectedRecipe = GetSelectedRecipe(gui); if ((Object)(object)selectedRecipe == (Object)null) { ShowMessage("Select a craftable recipe first."); return; } int selectedQuality = GetSelectedQuality(gui); Dictionary<string, int> missingIngredients = GetMissingIngredients(selectedRecipe, selectedQuality, craftCount, ((Humanoid)localPlayer).GetInventory()); if (missingIngredients.Count == 0) { ShowMessage("You already have all required materials."); return; } List<Container> list = FindUsableContainers(localPlayer); CraftManagerPlugin.Log.LogInfo((object)($"Recipe '{selectedRecipe.m_item.m_itemData.m_shared.m_name}' x{craftCount} needs: {FormatRequirements(missingIngredients)}. " + $"Accessible containers found: {list.Count}.")); if (list.Count == 0) { ShowMessage($"No accessible containers were found within {CraftManagerPlugin.ContainerSearchRadius.Value:0} meters."); return; } int usedContainers; int num = MoveIngredients(((Humanoid)localPlayer).GetInventory(), list, missingIngredients, out usedContainers); if (num == 0) { ShowMessage("Nearby accessible containers were found, but none contain materials required by this recipe."); return; } int num2 = missingIngredients.Values.Sum(); string text = $"Moved {num} material(s) for up to {craftCount} craft(s) from {usedContainers} container(s)."; if (num2 > 0) { text += $" Still missing {num2}."; } Traverse.Create((object)gui).Method("UpdateCraftingPanel", new object[1] { false }).GetValue(); ShowMessage(text); } internal static void CraftSelectedRecipe(InventoryGui gui, int craftCount) { if (!gui.InCraftTab()) { ShowMessage("Open the Craft tab and select a recipe first."); return; } craftCount = Mathf.Max(1, craftCount); Recipe selectedRecipe = GetSelectedRecipe(gui); int selectedQuality = GetSelectedQuality(gui); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)selectedRecipe == (Object)null) { ShowCraftManagerMessage("Craft: select a recipe first."); return; } if (!localPlayer.HaveRequirements(selectedRecipe, false, selectedQuality, craftCount)) { TryGetMaterials(gui, craftCount); selectedRecipe = GetSelectedRecipe(gui); selectedQuality = GetSelectedQuality(gui); if ((Object)(object)selectedRecipe == (Object)null || !localPlayer.HaveRequirements(selectedRecipe, false, selectedQuality, craftCount)) { ShowCraftManagerMessage($"Craft: materials for x{craftCount} are still missing."); return; } } Traverse obj = Traverse.Create((object)gui); obj.Field("m_multiCraftAmount").SetValue((object)craftCount); obj.Field("m_touchMultiCrafting").SetValue((object)(craftCount > 1)); obj.Method("OnCraftPressed", Array.Empty<object>()).GetValue(); } internal static IReadOnlyDictionary<string, int> GetNearbyStoredItemTotals(Player player) { return (from item in (from container in FindUsableContainers(player) select container.GetInventory() into inventory where inventory != null select inventory).SelectMany((Inventory inventory) => inventory.GetAllItems()) group item by item.m_shared.m_name).ToDictionary((IGrouping<string, ItemData> group) => group.Key, (IGrouping<string, ItemData> group) => group.Sum((ItemData item) => item.m_stack)); } internal static void SortOpenContainer(InventoryGui gui) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) Container value = Traverse.Create((object)gui).Field<Container>("m_currentContainer").Value; if (!((Object)(object)value == (Object)null)) { Inventory inventory = value.GetInventory(); List<ItemData> list = inventory.GetAllItems().OrderBy<ItemData, string>((ItemData item) => Localization.instance.Localize(item.m_shared.m_name), StringComparer.CurrentCultureIgnoreCase).ThenBy((ItemData item) => item.m_quality) .ThenBy((ItemData item) => item.m_variant) .ToList(); int width = inventory.GetWidth(); for (int num = 0; num < list.Count; num++) { list[num].m_gridPos = new Vector2i(num % width, num / width); } Traverse.Create((object)inventory).Method("Changed", new object[2] { true, false }).GetValue(); Traverse.Create((object)value).Method("Save", Array.Empty<object>()).GetValue(); Traverse.Create((object)gui).Method("UpdateContainer", new object[1] { Player.m_localPlayer }).GetValue(); } } internal static void EmptyInventoryIntoExistingStacks(InventoryGui gui) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); List<Container> list = FindUsableContainers(localPlayer); HashSet<Container> hashSet = new HashSet<Container>(); int num = 0; ItemData[] array = inventory.GetAllItems().ToArray(); foreach (ItemData item in array) { if (item.m_gridPos.y == 0 || item.m_equipped) { continue; } foreach (Container item2 in list) { if (item.m_stack <= 0) { break; } Inventory inventory2 = item2.GetInventory(); if (inventory2 == null || !inventory2.GetAllItems().Any((ItemData storedItem) => storedItem.m_shared.m_name == item.m_shared.m_name)) { continue; } int largestTransferableAmount = GetLargestTransferableAmount(inventory2, item); if (largestTransferableAmount > 0) { ItemData val = item.Clone(); val.m_stack = largestTransferableAmount; if (inventory2.AddItem(val)) { inventory.RemoveItem(item, largestTransferableAmount); num += largestTransferableAmount; hashSet.Add(item2); } } } } foreach (Container item3 in hashSet) { Traverse.Create((object)item3.GetInventory()).Method("Changed", new object[2] { true, false }).GetValue(); Traverse.Create((object)item3).Method("Save", Array.Empty<object>()).GetValue(); } Traverse.Create((object)gui).Method("UpdateInventory", new object[1] { localPlayer }).GetValue(); if (num == 0) { ShowCraftManagerMessage("Empty: no matching nearby storage stacks were available."); } else { ShowCraftManagerMessage($"Empty: moved {num} item(s) into matching stacks in {hashSet.Count} nearby container(s)."); } } internal static void PullMaterialsForPlacement(Player player, Piece piece) { if ((Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)piece == (Object)null) { return; } Dictionary<string, int> missingRequirements = GetMissingRequirements(piece.m_resources, 1, 1, ((Humanoid)player).GetInventory(), skipUpgraderResources: false); if (missingRequirements.Count == 0) { CraftManagerPlugin.Log.LogInfo((object)("Hammer placement '" + piece.m_name + "': all materials are already carried.")); return; } List<Container> list = FindUsableContainers(player); CraftManagerPlugin.Log.LogInfo((object)("Hammer placement '" + piece.m_name + "' needs " + FormatRequirements(missingRequirements) + ". " + $"Accessible containers found: {list.Count}.")); if (list.Count != 0) { int usedContainers; int num = MoveIngredients(((Humanoid)player).GetInventory(), list, missingRequirements, out usedContainers); CraftManagerPlugin.Log.LogInfo((object)($"Hammer placement '{piece.m_name}': moved {num} material(s) from {usedContainers} container(s). " + "Still needed: " + FormatRequirements(missingRequirements) + ".")); } } internal static Recipe? GetSelectedRecipe(InventoryGui gui) { object value = SelectedRecipeField.GetValue(gui); if (value == null) { return null; } return Traverse.Create(value).Property<Recipe>("Recipe", (object[])null).Value; } private static int GetSelectedQuality(InventoryGui gui) { object value = SelectedRecipeField.GetValue(gui); return ((value == null) ? null : Traverse.Create(value).Property<ItemData>("ItemData", (object[])null).Value)?.m_quality ?? 1; } private static Dictionary<string, int> GetMissingIngredients(Recipe recipe, int quality, int craftCount, Inventory playerInventory) { return GetMissingRequirements(recipe.m_resources, quality, craftCount, playerInventory, skipUpgraderResources: true); } private static Dictionary<string, int> GetMissingRequirements(IEnumerable<Requirement> requirements, int quality, int multiplier, Inventory playerInventory, bool skipUpgraderResources) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (Requirement item in requirements ?? Array.Empty<Requirement>()) { if (!((Object)(object)item?.m_resItem == (Object)null) && (!skipUpgraderResources || !item.m_upgraderResource)) { string name = item.m_resItem.m_itemData.m_shared.m_name; int num = item.GetAmount(quality) * multiplier; dictionary[name] = (dictionary.TryGetValue(name, out var value) ? (value + num) : num); } } Dictionary<string, int> dictionary2 = new Dictionary<string, int>(); foreach (KeyValuePair<string, int> item2 in dictionary) { string itemName = item2.Key; int value2 = item2.Value; int num2 = (from item in playerInventory.GetAllItems() where item.m_shared.m_name == itemName select item).Sum((ItemData item) => item.m_stack); int num3 = Math.Max(0, value2 - num2); if (num3 > 0) { dictionary2[itemName] = num3; } } return dictionary2; } internal static List<Container> FindUsableContainers(Player player) { //IL_0033: 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) float range = Mathf.Max(0f, CraftManagerPlugin.ContainerSearchRadius.Value); Vector3 playerPosition = ((Component)player).transform.position; return (from container in Object.FindObjectsByType<Container>((FindObjectsSortMode)0) where (Object)(object)container != (Object)null && ((Behaviour)container).isActiveAndEnabled where container.GetInventory() != null where !container.IsInUse() where Vector3.Distance(playerPosition, ((Component)container).transform.position) <= range where HasAccess(container, player.GetPlayerID()) orderby Vector3.Distance(playerPosition, ((Component)container).transform.position) select container).ToList(); } private static bool HasAccess(Container container, long playerId) { return Traverse.Create((object)container).Method("CheckAccess", new object[1] { playerId }).GetValue<bool>(); } private static int MoveIngredients(Inventory playerInventory, IEnumerable<Container> containers, IDictionary<string, int> required, out int usedContainers) { int num = 0; usedContainers = 0; foreach (Container container in containers) { bool flag = false; Inventory inventory = container.GetInventory(); if (inventory == null) { continue; } string[] array = (from item in inventory.GetAllItems() where required.ContainsKey(item.m_shared.m_name) select $"{item.m_shared.m_name} x{item.m_stack}").ToArray(); if (array.Length != 0) { CraftManagerPlugin.Log.LogInfo((object)("Container '" + container.GetHoverName() + "' has matching stack(s): " + string.Join(", ", array) + ".")); } ItemData[] array2 = inventory.GetAllItems().ToArray(); foreach (ItemData val in array2) { string name = val.m_shared.m_name; if (!required.TryGetValue(name, out var value) || value <= 0) { continue; } int num3 = Math.Min(value, val.m_stack); if (!playerInventory.CanAddItem(val, num3)) { CraftManagerPlugin.Log.LogInfo((object)$"Player inventory has no room for {name} x{num3}."); continue; } ItemData val2 = val.Clone(); val2.m_stack = num3; if (!playerInventory.AddItem(val2)) { CraftManagerPlugin.Log.LogWarning((object)$"Valheim declined the transfer of {name} x{num3}."); } else if (!inventory.RemoveItem(val, num3)) { playerInventory.RemoveItem(val2, num3); CraftManagerPlugin.Log.LogWarning((object)$"Source container changed before {name} x{num3} could be removed."); } else { required[name] -= num3; num += num3; flag = true; } } if (flag) { usedContainers++; } if (required.Values.All((int amount) => amount <= 0)) { break; } } return num; } private static int GetLargestTransferableAmount(Inventory storageInventory, ItemData item) { for (int num = item.m_stack; num > 0; num--) { if (storageInventory.CanAddItem(item, num)) { return num; } } return 0; } private static string FormatRequirements(IReadOnlyDictionary<string, int> requirements) { return string.Join(", ", requirements.Select<KeyValuePair<string, int>, string>((KeyValuePair<string, int> entry) => $"{entry.Key} x{entry.Value}")); } private static void ShowMessage(string message) { CraftManagerPlugin.Log.LogInfo((object)message); if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)1, "Get Materials: " + message, 0, (Sprite)null, false, true); } } private static void ShowCraftManagerMessage(string message) { CraftManagerPlugin.Log.LogInfo((object)message); if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)1, message, 0, (Sprite)null, false, true); } } } [HarmonyPatch(typeof(Player), "UpdatePlacement", new Type[] { typeof(bool), typeof(float) })] internal static class HammerBuildingPatch { private static void Prefix(Player __instance) { if (ZInput.GetButtonDown("Attack") || ZInput.GetButtonDown("JoyPlace")) { Piece selectedPiece = __instance.GetSelectedPiece(); CraftManagerService.PullMaterialsForPlacement(__instance, selectedPiece); } } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] internal static class UpgradeAvailabilityPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo original = AccessTools.Method(typeof(Player), "HaveRequirements", new Type[4] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) }, (Type[])null); MethodInfo replacement = AccessTools.Method(typeof(UpgradeMaterials), "HaveRequirements", (Type[])null, (Type[])null); int replacements = 0; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, original)) { instruction.opcode = OpCodes.Call; instruction.operand = replacement; replacements++; } yield return instruction; } if (replacements != 1) { throw new InvalidOperationException($"Expected one upgrade button requirement check, found {replacements}."); } } } [HarmonyPatch(typeof(Inventory), "CountItems", new Type[] { typeof(string), typeof(int), typeof(bool) })] internal static class UpgradeStorageCountPatch { private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result) { if (__instance != UpgradeMaterials.CountingInventory || UpgradeMaterials.CountingStorage == null) { return; } foreach (Inventory item in UpgradeMaterials.CountingStorage) { __result += item.CountItems(name, quality, matchWorldLevel); } } } [HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")] internal static class NativeUpgradeButtonPatch { private static bool Prefix(InventoryGui __instance) { return UpgradeMaterials.PrepareUpgrade(__instance); } } internal static class UpgradeMaterials { [ThreadStatic] internal static Inventory? CountingInventory; [ThreadStatic] internal static List<Inventory>? CountingStorage; private static ItemData? SelectedItem(InventoryGui gui) { object value = Traverse.Create((object)gui).Field("m_selectedRecipe").GetValue(); if (value != null) { return Traverse.Create(value).Property<ItemData>("ItemData", (object[])null).Value; } return null; } internal static bool HaveRequirements(Player player, Recipe recipe, bool discover, int quality, int amount) { InventoryGui instance = InventoryGui.instance; if (player.HaveRequirements(recipe, discover, quality, amount)) { return true; } if (discover || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)instance == (Object)null || instance.InCraftTab() || SelectedItem(instance) == null || (Object)(object)CraftManagerService.GetSelectedRecipe(instance) != (Object)(object)recipe) { return false; } Inventory countingInventory = CountingInventory; List<Inventory> countingStorage = CountingStorage; try { CountingInventory = ((Humanoid)player).GetInventory(); CountingStorage = (from container in CraftManagerService.FindUsableContainers(player) select container.GetInventory() into inventory where inventory != null select inventory).ToList(); return player.HaveRequirements(recipe, discover, quality, amount); } finally { CountingInventory = countingInventory; CountingStorage = countingStorage; } } internal static bool PrepareUpgrade(InventoryGui gui) { //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Expected O, but got Unknown Player localPlayer = Player.m_localPlayer; ItemData val = SelectedItem(gui); Recipe selectedRecipe = CraftManagerService.GetSelectedRecipe(gui); if (gui.InCraftTab() || val == null || (Object)(object)localPlayer == (Object)null || (Object)(object)selectedRecipe == (Object)null) { return true; } if (Traverse.Create((object)gui).Field<float>("m_craftTimer").Value >= 0f) { return false; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); int num = val.m_quality + 1; CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); bool flag = (Object)(object)currentCraftingStation != (Object)null && currentCraftingStation.m_upgrader; if (!inventory.ContainsItem(val) || (!flag && num > selectedRecipe.m_item.m_itemData.m_shared.m_maxQuality)) { return false; } if (localPlayer.NoCostCheat() || ZoneSystem.instance.GetGlobalKey((GlobalKeys)25) || localPlayer.HaveRequirements(selectedRecipe, false, num, 1)) { return true; } if (!HaveRequirements(localPlayer, selectedRecipe, discover: false, num, 1)) { return false; } List<Container> source = CraftManagerService.FindUsableContainers(localPlayer); List<(Inventory, ItemData, int)> list = new List<(Inventory, ItemData, int)>(); Requirement[] resources = selectedRecipe.m_resources; foreach (Requirement val2 in resources) { if ((Object)(object)val2.m_resItem == (Object)null || val2.m_upgraderResource != flag) { continue; } string name = val2.m_resItem.m_itemData.m_shared.m_name; int amount = val2.GetAmount(num); bool flag2 = false; foreach (int resourceQuality in from num4 in Enumerable.Range(1, val2.m_resItem.m_itemData.m_shared.m_maxQuality) orderby inventory.CountItems(name, num4, true) descending select num4) { int num2 = Math.Max(0, amount - inventory.CountItems(name, resourceQuality, true)); List<(Inventory, ItemData)> list2 = (from container in source select container.GetInventory() into val6 where val6 != null select val6).SelectMany((Inventory val6) => from stack in val6.GetAllItems() where stack.m_shared.m_name == name && stack.m_quality == resourceQuality && stack.m_worldLevel >= Game.m_worldLevel select (source: val6, item: stack)).ToList(); if (list2.Sum<(Inventory, ItemData)>(((Inventory source, ItemData item) candidate) => candidate.item.m_stack) < num2) { continue; } foreach (var item in list2) { int num3 = Math.Min(num2, item.Item2.m_stack); if (num3 > 0) { list.Add((item.Item1, item.Item2, num3)); } num2 -= num3; if (num2 == 0) { break; } } flag2 = true; break; } if (selectedRecipe.m_requireOnlyOneIngredient && flag2) { break; } if (!flag2 && !selectedRecipe.m_requireOnlyOneIngredient) { return false; } } Inventory val3 = new Inventory("CraftManager upgrade capacity", (Sprite)null, inventory.GetWidth(), inventory.GetHeight()); foreach (ItemData allItem in inventory.GetAllItems()) { val3.GetAllItems().Add(allItem.Clone()); } foreach (var item2 in list) { ItemData val4 = item2.Item2.Clone(); val4.m_stack = item2.Item3; if (!val3.CanAddItem(val4, val4.m_stack) || !val3.AddItem(val4)) { ((Character)localPlayer).Message((MessageType)1, "$inventory_full", 0, (Sprite)null, false); return false; } } foreach (var item3 in list) { ItemData val5 = item3.Item2.Clone(); val5.m_stack = item3.Item3; if (!inventory.CanAddItem(val5, val5.m_stack) || !item3.Item1.RemoveItem(item3.Item2, item3.Item3)) { return false; } if (!inventory.AddItem(val5)) { item3.Item1.AddItem(val5); return false; } } CraftManagerPlugin.Log.LogInfo((object)$"Upgrade '{val.m_shared.m_name}' to quality {num}: pulled {list.Sum<(Inventory, ItemData, int)>(((Inventory source, ItemData item, int amount) transfer) => transfer.amount)} material(s)."); return localPlayer.HaveRequirements(selectedRecipe, false, num, 1); } } }