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 LynxLeftovers v1.0.1
plugins/LynxLeftovers.dll
Decompiled 14 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace LynxLeftovers; internal static class Content { public static void Register() { RegisterLeftovers(); RegisterGrinder(); RegisterStewpot(); } private static void RegisterLeftovers() { //IL_0129: 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_0177: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Expected O, but got Unknown //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Expected O, but got Unknown GameObject val = PrefabManager.Instance.CreateClonedPrefab("LynxLeftovers", "Entrails"); SharedData shared = val.GetComponent<ItemDrop>().m_itemData.m_shared; shared.m_name = "$item_lynx_leftovers"; shared.m_description = "$item_lynx_leftovers_desc"; shared.m_maxStackSize = 50; shared.m_weight = 0.3f; shared.m_food = 0f; shared.m_foodStamina = 0f; shared.m_foodEitr = 0f; shared.m_teleportable = true; Collider[] componentsInChildren = val.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } Renderer[] componentsInChildren2 = val.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } MeshFilter[] componentsInChildren3 = val.GetComponentsInChildren<MeshFilter>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[i]); } LODGroup[] componentsInChildren4 = val.GetComponentsInChildren<LODGroup>(true); for (int i = 0; i < componentsInChildren4.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren4[i]); } GameObject val2 = CopyChild(PrefabManager.Instance.GetPrefab("piece_chest_barrel"), "New/blackmetalchest", val.transform, Vector3.zero, new Vector3(0f, 180f, 0f), 0.25f); ((Object)val2).name = "leftovers_jar"; Transform val3 = val.transform.Find("attach"); if ((Object)(object)val3 == (Object)null) { val3 = new GameObject("attach").transform; val3.SetParent(val.transform, false); } foreach (Transform item in ((IEnumerable)val3).Cast<Transform>().ToList()) { Object.DestroyImmediate((Object)(object)((Component)item).gameObject); } Vector3 position = val2.transform.position; Quaternion rotation = val2.transform.rotation; Vector3 lossyScale = val2.transform.lossyScale; val2.transform.SetParent(val3, true); val2.transform.position = position; val2.transform.rotation = rotation; Vector3 lossyScale2 = val3.lossyScale; val2.transform.localScale = new Vector3(lossyScale.x / lossyScale2.x, lossyScale.y / lossyScale2.y, lossyScale.z / lossyScale2.z); BoxCollider obj = val.AddComponent<BoxCollider>(); obj.center = new Vector3(0f, 0.112f, 0f); obj.size = new Vector3(0.2f, 0.225f, 0.2f); SetLayerRecursive(val2, val.layer); Sprite val4 = RenderManager.Instance.Render(new RenderRequest(val) { Rotation = RenderManager.IsometricRotation, Width = 128, Height = 128, UseCache = false }); if ((Object)(object)val4 != (Object)null) { shared.m_icons = (Sprite[])(object)new Sprite[1] { val4 }; } else { Plugin.Log.LogWarning((object)"Leftovers icon render failed; keeping the Entrails icon"); } ItemManager.Instance.AddItem(new CustomItem(val, false)); } private static void RegisterGrinder() { //IL_004e: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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_00f0: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Expected O, but got Unknown //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Expected O, but got Unknown //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Expected O, but got Unknown //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Expected O, but got Unknown //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Expected O, but got Unknown GameObject val = PrefabManager.Instance.CreateClonedPrefab("LynxMeatGrinder", "piece_chest_barrel"); Transform transform = val.transform; GameObject prefab = PrefabManager.Instance.GetPrefab("windmill"); PrepareContainerBase(val, "$piece_lynx_grinder", stripBarrelMesh: false); GameObject val2 = CopyChild(prefab, "grindstone", transform, new Vector3(0f, 0.32999998f, 0f), Vector3.zero, 0.5f); float num = 1.44f; float num2 = num + 0.45f; Material mat = FirstMaterial(prefab, "grindstone"); AddCylinder(transform, "mast", new Vector3(0f, (num + num2) / 2f, 0f), new Vector3(0.06f, (num2 - num) / 2f + 0.03f, 0.06f), mat); Transform val3 = prefab.transform.Find("rotating/propeller"); GameObject val4 = CopyTransform(val3, transform, new Vector3(0f, num2, -0.285f), val3.localEulerAngles, 0.15f); GameObject val5 = CopyChild(prefab, "_enabled", transform, new Vector3(0f, num - 0.684f, 0f), Vector3.zero, 0.6f); DestroyChild(val5.transform, "smoke (1)"); val5.SetActive(false); Transform transform2 = new GameObject("output").transform; transform2.SetParent(transform, false); transform2.localPosition = new Vector3(0f, 0.5f, -0.75f); MeatGrinder meatGrinder = val.AddComponent<MeatGrinder>(); meatGrinder.m_activeVisual = val5; meatGrinder.m_outputPoint = transform2; meatGrinder.m_spinY = (Transform[])(object)new Transform[1] { val2.transform }; meatGrinder.m_spinZ = (Transform[])(object)new Transform[1] { val4.transform }; meatGrinder.m_spinYSpeed = 150f; meatGrinder.m_spinZSpeed = -300f; Sprite icon = prefab.GetComponent<Piece>()?.m_icon; ApplyVanillaCategory(val); PieceManager instance = PieceManager.Instance; PieceConfig val6 = new PieceConfig(); val6.Name = "$piece_lynx_grinder"; val6.Description = "$piece_lynx_grinder_desc"; val6.PieceTable = "Hammer"; val6.Category = CustomCategoryOrNull(); val6.CraftingStation = "forge"; val6.Icon = icon; val6.Requirements = (RequirementConfig[])(object)new RequirementConfig[3] { new RequirementConfig("Iron", 3, 0, true), new RequirementConfig("SurtlingCore", 1, 0, true), new RequirementConfig("BarrelRings", 2, 0, true) }; instance.AddPiece(new CustomPiece(val, false, val6)); } private static void RegisterStewpot() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: 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_0168: 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_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Expected O, but got Unknown //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Expected O, but got Unknown //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Expected O, but got Unknown //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Expected O, but got Unknown GameObject val = PrefabManager.Instance.CreateClonedPrefab("LynxStockCask", "piece_chest_barrel"); Transform transform = val.transform; GameObject prefab = PrefabManager.Instance.GetPrefab("cauldron_ext7_smoker"); GameObject prefab2 = PrefabManager.Instance.GetPrefab("fire_pit"); PrepareContainerBase(val, "$piece_lynx_stockcask", stripBarrelMesh: true); Transform parent = transform.Find("New"); MakeMetal(CopyChild(prefab, "new/high", parent, Vector3.zero, Vector3.zero, 1f)); GameObject val2 = new GameObject("_simmer"); val2.transform.SetParent(transform, false); CopyChild(prefab, "new/SmokerFX", val2.transform, new Vector3(-0.621f, 1.088f, 0f), Vector3.zero, 1f); CopyChild(prefab2, "_enabled_high/Point light", val2.transform, new Vector3(0f, 0.35f, -0.5f), Vector3.zero, 1f); val2.SetActive(false); Transform transform2 = new GameObject("output").transform; transform2.SetParent(transform, false); transform2.localPosition = new Vector3(0f, 0.45f, 0.65f); GameObject val3 = new GameObject("collider") { layer = LayerMask.NameToLayer("piece") }; val3.transform.SetParent(transform, false); BoxCollider obj = val3.AddComponent<BoxCollider>(); obj.center = new Vector3(-0.02f, 0.52f, 0f); obj.size = new Vector3(1.05f, 1.02f, 0.66f); Stewpot stewpot = val.AddComponent<Stewpot>(); stewpot.m_activeVisual = val2; stewpot.m_outputPoint = transform2; Sprite icon = prefab.GetComponent<Piece>()?.m_icon; ApplyVanillaCategory(val); PieceManager instance = PieceManager.Instance; PieceConfig val4 = new PieceConfig(); val4.Name = "$piece_lynx_stockcask"; val4.Description = "$piece_lynx_stockcask_desc"; val4.PieceTable = "Hammer"; val4.Category = CustomCategoryOrNull(); val4.CraftingStation = "forge"; val4.Icon = icon; val4.Requirements = (RequirementConfig[])(object)new RequirementConfig[2] { new RequirementConfig("Iron", 5, 0, true), new RequirementConfig("BarrelRings", 1, 0, true) }; instance.AddPiece(new CustomPiece(val, false, val4)); } private static bool VanillaCategory(out PieceCategory cat) { string text = (Plugin.BuildCategory.Value ?? "").Trim(); cat = (PieceCategory)1; if (text.Length == 0) { return true; } if (Enum.TryParse<PieceCategory>(text, ignoreCase: true, out cat) && (int)cat != 100) { return (int)cat != 9; } return false; } private static void ApplyVanillaCategory(GameObject go) { //IL_000f: 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) if (VanillaCategory(out var cat)) { go.GetComponent<Piece>().m_category = cat; } } private static string CustomCategoryOrNull() { if (!VanillaCategory(out var _)) { return Plugin.BuildCategory.Value.Trim(); } return null; } private static void MakeMetal(GameObject go) { Shader standard = FindStandardShader(); Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true); foreach (Renderer obj in componentsInChildren) { obj.sharedMaterials = ((IEnumerable<Material>)obj.sharedMaterials).Select((Func<Material, Material>)delegate(Material m) { //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_0100: Expected O, but got Unknown //IL_0022: 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_003e: Expected O, but got Unknown //IL_0122: 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) if ((Object)(object)m == (Object)null) { return m; } Material val; if ((Object)(object)standard != (Object)null) { val = new Material(standard) { name = ((Object)m).name + "_lynxsteel" }; if (m.HasProperty("_MainTex")) { val.SetTexture("_MainTex", m.GetTexture("_MainTex")); } if (m.HasProperty("_BumpMap") && (Object)(object)m.GetTexture("_BumpMap") != (Object)null) { val.SetTexture("_BumpMap", m.GetTexture("_BumpMap")); val.EnableKeyword("_NORMALMAP"); } val.SetFloat("_Metallic", 0.85f); val.SetFloat("_Glossiness", 0.55f); val.color = new Color(0.78f, 0.8f, 0.86f, 1f); } else { val = new Material(m) { name = ((Object)m).name + "_lynxsteel" }; if (val.HasProperty("_Color")) { val.color = new Color(0.62f, 0.66f, 0.72f, 1f); } } return val; }).ToArray(); } } private static Shader FindStandardShader() { Shader val = Shader.Find("Standard"); if ((Object)(object)val != (Object)null) { return val; } GameObject prefab = PrefabManager.Instance.GetPrefab("smelter"); Transform val2 = (((Object)(object)prefab != (Object)null) ? prefab.transform.Find("Worn/default") : null); Renderer val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<Renderer>() : null); if (!((Object)(object)val3 != (Object)null) || !((Object)(object)val3.sharedMaterial != (Object)null)) { return null; } return val3.sharedMaterial.shader; } private static void PrepareContainerBase(GameObject go, string name, bool stripBarrelMesh) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown Transform transform = go.transform; Container component = go.GetComponent<Container>(); component.m_name = name; component.m_width = 4; component.m_height = 2; GameObject val = new GameObject("lid_none"); val.transform.SetParent(transform, false); component.m_open = val; component.m_closed = val; Transform val2 = transform.Find("New"); if ((Object)(object)val2 != (Object)null) { LODGroup component2 = ((Component)val2).GetComponent<LODGroup>(); if (Object.op_Implicit((Object)(object)component2)) { Object.DestroyImmediate((Object)(object)component2); } DestroyChild(val2, "Open"); DestroyChild(val2, "Closed"); DestroyChild(val2, "blackmetalchestLOD"); if (stripBarrelMesh) { DestroyChild(val2, "blackmetalchest"); } } DestroyChild(transform, "floor_2x2_snow"); if (stripBarrelMesh) { DestroyChild(transform, "collider"); } Piece component3 = go.GetComponent<Piece>(); if ((Object)(object)component3 != (Object)null) { component3.m_name = name; } } private static GameObject CopyChild(GameObject srcPrefab, string path, Transform parent, Vector3 pos, Vector3 euler, float scale) { //IL_0079: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown Transform val = srcPrefab.transform.Find(path); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("Missing " + ((Object)srcPrefab).name + "/" + path + "; skipping that visual")); GameObject val2 = new GameObject("missing_" + path.Replace('/', '_')); val2.transform.SetParent(parent, false); return val2; } return CopyTransform(val, parent, pos, euler, scale); } private static GameObject CopyTransform(Transform src, Transform parent, Vector3 pos, Vector3 euler, float scale) { //IL_0027: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_017c: 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) GameObject val = Object.Instantiate<GameObject>(((Component)src).gameObject, parent, false); ((Object)val).name = ((Object)src).name; val.SetActive(true); val.transform.localPosition = pos; val.transform.localRotation = Quaternion.Euler(euler); val.transform.localScale = src.localScale * scale; Collider[] componentsInChildren = val.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } LODGroup[] componentsInChildren2 = val.GetComponentsInChildren<LODGroup>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } Transform[] array = val.GetComponentsInChildren<Transform>(true).ToArray(); foreach (Transform val2 in array) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)val.transform)) { string text = ((Object)val2).name.ToLowerInvariant(); if (text == "low" || text == "lod" || text.EndsWith("lod")) { Object.DestroyImmediate((Object)(object)((Component)val2).gameObject); } } } MonoBehaviour[] componentsInChildren3 = val.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val3 in componentsInChildren3) { if (!((Object)(object)val3 == (Object)null)) { string name = ((object)val3).GetType().Name; if (!(name == "LightFlicker") && !(name == "LightLod")) { Object.DestroyImmediate((Object)(object)val3); } } } ParticleSystem[] componentsInChildren4 = val.GetComponentsInChildren<ParticleSystem>(true); for (int i = 0; i < componentsInChildren4.Length; i++) { MainModule main = componentsInChildren4[i].main; ((MainModule)(ref main)).scalingMode = (ParticleSystemScalingMode)0; } SetLayerRecursive(val, LayerMask.NameToLayer("piece_nonsolid")); return val; } private static void AddCylinder(Transform parent, string name, Vector3 pos, Vector3 scale, Material mat) { //IL_002c: 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) GameObject val = GameObject.CreatePrimitive((PrimitiveType)2); ((Object)val).name = name; Object.DestroyImmediate((Object)(object)val.GetComponent<Collider>()); val.transform.SetParent(parent, false); val.transform.localPosition = pos; val.transform.localScale = scale; if ((Object)(object)mat != (Object)null) { val.GetComponent<Renderer>().sharedMaterial = mat; } val.layer = LayerMask.NameToLayer("piece_nonsolid"); } private static Material FirstMaterial(GameObject prefab, string path) { Transform val = prefab.transform.Find(path); Renderer val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInChildren<Renderer>(true) : null); if (!((Object)(object)val2 != (Object)null)) { return null; } return val2.sharedMaterial; } private static void DestroyChild(Transform parent, string name) { Transform val = parent.Find(name); if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } } private static void SetLayerRecursive(GameObject go, int layer) { if (layer >= 0) { Transform[] componentsInChildren = go.GetComponentsInChildren<Transform>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Component)componentsInChildren[i]).gameObject.layer = layer; } } } } internal static class DrawersCompat { public const string ItemDrawersGuid = "com.rossdwest.itemdrawers"; private static FieldInfo _instancesField; private static readonly List<KeyValuePair<ItemDrop, ItemData>> Blanked = new List<KeyValuePair<ItemDrop, ItemData>>(); public static void TryApply(Harmony harmony) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown //IL_014c: Expected O, but got Unknown if (!Chainloader.PluginInfos.ContainsKey("com.rossdwest.itemdrawers")) { return; } try { Type type = AccessTools.TypeByName("ItemDrawers.Game.DrawerComponent"); Type type2 = AccessTools.TypeByName("ItemDrawers.Game.DrawerManager"); Type type3 = AccessTools.TypeByName("ItemDrawers.Game.ItemFacts"); _instancesField = AccessTools.Field(typeof(ItemDrop), "s_instances"); int num = 0; MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "UseItem", (Type[])null, (Type[])null) : null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DrawersCompat), "UseItemPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } MethodInfo methodInfo2 = ((type3 != null) ? AccessTools.Method(type3, "PrefabNameOf", (Type[])null, (Type[])null) : null); if (methodInfo2 != null) { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(DrawersCompat), "PrefabNameOfPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } MethodInfo methodInfo3 = ((type2 != null) ? AccessTools.Method(type2, "RunAutoPickup", (Type[])null, (Type[])null) : null); if (methodInfo3 != null && _instancesField != null) { harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(DrawersCompat), "PickupPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(DrawersCompat), "PickupFinalizer", (Type[])null), (HarmonyMethod)null); num++; } Plugin.Log.LogInfo((object)$"ItemDrawers found: applied {num}/3 Hearty-food compatibility patches"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("ItemDrawers compatibility patch failed (Hearty food may lose its bonus in drawers): " + ex.Message)); } } private static bool UseItemPrefix(Humanoid __0, ItemData __1, ref bool __result) { if (!FoodRules.IsHearty(__1)) { return true; } if (__0 != null) { ((Character)__0).Message((MessageType)2, "Drawers can't keep Hearty food Hearty", 0, (Sprite)null, false); } __result = true; return false; } private static void PrefabNameOfPostfix(ItemData __0, ref string __result) { if (FoodRules.IsHearty(__0)) { __result = null; } } private static void PickupPrefix() { Blanked.Clear(); if (!(_instancesField.GetValue(null) is List<ItemDrop> list)) { return; } foreach (ItemDrop item in list) { if ((Object)(object)item != (Object)null && FoodRules.IsHearty(item.m_itemData)) { Blanked.Add(new KeyValuePair<ItemDrop, ItemData>(item, item.m_itemData)); item.m_itemData = null; } } } private static Exception PickupFinalizer(Exception __exception) { foreach (KeyValuePair<ItemDrop, ItemData> item in Blanked) { if ((Object)(object)item.Key != (Object)null) { item.Key.m_itemData = item.Value; } } Blanked.Clear(); return __exception; } } public static class FoodRules { public const string LeftoversPrefab = "LynxLeftovers"; public const int HeartyQuality = 2; private static HashSet<string> _excluded; private static string _excludedConfigSnapshot; public static string PrefabName(ItemData item) { if (item == null || (Object)(object)item.m_dropPrefab == (Object)null) { return null; } return ((Object)item.m_dropPrefab).name; } public static float Value(ItemData item) { if (item == null || item.m_shared == null) { return 0f; } SharedData shared = item.m_shared; return Mathf.Max(0f, shared.m_food) + Mathf.Max(0f, shared.m_foodStamina) + Mathf.Max(0f, shared.m_foodEitr); } public static bool IsHeartyCapable(ItemData item) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 if (item != null && item.m_shared != null && (int)item.m_shared.m_itemType == 2 && item.m_shared.m_maxQuality <= 1) { return Value(item) > 0f; } return false; } public static bool IsHearty(ItemData item) { if (item != null && item.m_quality >= 2) { return IsHeartyCapable(item); } return false; } public static bool IsLeftovers(ItemData item) { return PrefabName(item) == "LynxLeftovers"; } public static bool IsEligibleFood(ItemData item) { if (!IsHeartyCapable(item) || IsHearty(item)) { return false; } string text = PrefabName(item); if (string.IsNullOrEmpty(text)) { return false; } return !Excluded().Contains(text); } public static float Multiplier(ItemData item) { if (!IsHearty(item)) { return 1f; } return Plugin.HeartyMultiplier.Value; } public static float Health(ItemData item) { return item.m_shared.m_food * Multiplier(item); } public static float Stamina(ItemData item) { return item.m_shared.m_foodStamina * Multiplier(item); } public static float Eitr(ItemData item) { return item.m_shared.m_foodEitr * Multiplier(item); } private static HashSet<string> Excluded() { string text = Plugin.ExcludedFoods.Value ?? ""; if (_excluded != null && text == _excludedConfigSnapshot) { return _excluded; } if ((Object)(object)ZNetScene.instance == (Object)null) { return _excluded ?? new HashSet<string>(); } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); string[] array = text.Split(','); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length > 0) { hashSet.Add(text2); } } int num = 0; foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } Pickable[] componentsInChildren = prefab.GetComponentsInChildren<Pickable>(true); foreach (Pickable val in componentsInChildren) { if ((Object)(object)val != (Object)null && (Object)(object)val.m_itemPrefab != (Object)null && hashSet.Add(((Object)val.m_itemPrefab).name)) { num++; } } } _excluded = hashSet; _excludedConfigSnapshot = text; Plugin.Log.LogInfo((object)$"Food exclusion list built: {hashSet.Count} items ({num} from pickables)"); return hashSet; } } internal static class HeartyMultiplyTranspiler { private static readonly Dictionary<MethodBase, Func<CodeInstruction[]>> ItemLoaders = new Dictionary<MethodBase, Func<CodeInstruction[]>>(); public static bool Patch(Harmony harmony, MethodBase target, Func<CodeInstruction[]> loadItem, string label) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown if (target == null) { Plugin.Log.LogWarning((object)(label + ": method not found; Hearty numbers there will show base values")); return false; } ItemLoaders[target] = loadItem; harmony.Patch(target, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(HeartyMultiplyTranspiler), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); return true; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original) { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); if (!ItemLoaders.TryGetValue(original, out var value)) { return list; } HashSet<FieldInfo> hashSet = new HashSet<FieldInfo> { AccessTools.Field(typeof(SharedData), "m_food"), AccessTools.Field(typeof(SharedData), "m_foodStamina"), AccessTools.Field(typeof(SharedData), "m_foodEitr") }; MethodInfo methodInfo = AccessTools.Method(typeof(FoodRules), "Multiplier", (Type[])null, (Type[])null); int num = 0; for (int i = 0; i < list.Count; i++) { if (!(list[i].opcode != OpCodes.Ldfld) && list[i].operand is FieldInfo item && hashSet.Contains(item)) { List<CodeInstruction> list2 = value().ToList(); list2.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo)); list2.Add(new CodeInstruction(OpCodes.Mul, (object)null)); list.InsertRange(i + 1, list2); i += list2.Count; num++; } } Plugin.Log.LogDebug((object)$"Hearty multiply inserted in {original.DeclaringType?.Name}.{original.Name}: {num}"); return list; } } internal static class PovCompat { public const string Guid = "treextr.pathofvalheiman"; private static MethodInfo _stamp; private static MethodInfo _refresh; private static MethodInfo _bonus; private static MethodInfo _cookBonuses; private static MethodInfo _roll; public static bool Active { get; private set; } public static void TryApply(Harmony harmony) { if (!Chainloader.PluginInfos.ContainsKey("treextr.pathofvalheiman")) { return; } try { Type type = AccessTools.TypeByName("PassiveTree.FoodMasteries"); Type foodType = typeof(Food); MethodInfo target = type?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "Value" && m.GetParameters().Length == 2 && m.GetParameters()[0].ParameterType == foodType); FieldInfo foodItem = AccessTools.Field(foodType, "m_item"); HeartyMultiplyTranspiler.Patch(harmony, target, () => (CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)foodItem) }, "PoV food masteries"); Type type2 = AccessTools.TypeByName("PassiveTree.UI.ItemTooltip"); MethodInfo target2 = ((type2 != null) ? AccessTools.Method(type2, "MainStats", (Type[])null, (Type[])null) : null); HeartyMultiplyTranspiler.Patch(harmony, target2, () => (CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldarg_1, (object)null) }, "PoV item tooltip"); Type type3 = AccessTools.TypeByName("PassiveTree.Credit"); Type type4 = AccessTools.TypeByName("PassiveTree.Crafting"); Type type5 = AccessTools.TypeByName("PassiveTree.ChainRolls"); _stamp = ((type3 != null) ? AccessTools.Method(type3, "Stamp", (Type[])null, (Type[])null) : null); _refresh = ((type3 != null) ? AccessTools.Method(type3, "Refresh", (Type[])null, (Type[])null) : null); _bonus = ((type3 != null) ? AccessTools.Method(type3, "Bonus", (Type[])null, (Type[])null) : null); _cookBonuses = ((type4 != null) ? AccessTools.Method(type4, "CookBonuses", (Type[])null, (Type[])null) : null); _roll = ((type5 != null) ? AccessTools.Method(type5, "Roll", (Type[])null, (Type[])null) : null); Active = true; bool flag = _stamp != null && _refresh != null && _bonus != null && _cookBonuses != null; Plugin.Log.LogInfo((object)("Path of Valheiman found: Hearty patched into food masteries/tooltip; cooking credit " + (flag ? "on" : "unavailable"))); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Path of Valheiman compatibility failed: " + ex.Message)); } } public static void StampLoader(ZNetView view, Player by) { if (!Active || _stamp == null || _cookBonuses == null || (Object)(object)view == (Object)null || (Object)(object)by == (Object)null) { return; } try { _stamp.Invoke(null, new object[3] { view, by, _cookBonuses.Invoke(null, null) }); } catch (Exception ex) { Plugin.Log.LogDebug((object)("PoV credit stamp failed: " + ex.Message)); } } public static void Refresh(ZNetView view) { if (!Active || _refresh == null || _cookBonuses == null || (Object)(object)view == (Object)null) { return; } try { _refresh.Invoke(null, new object[2] { view, _cookBonuses.Invoke(null, null) }); } catch (Exception ex) { Plugin.Log.LogDebug((object)("PoV credit refresh failed: " + ex.Message)); } } private static float Bonus(ZNetView view, string what) { if (!Active || _bonus == null || (Object)(object)view == (Object)null) { return 0f; } try { return (float)_bonus.Invoke(null, new object[2] { view, what }); } catch { return 0f; } } public static float SpeedFactor(ZNetView view) { return 1f + Mathf.Max(0f, Bonus(view, "cook")); } public static int ExtraRolls(ZNetView view, int produced) { float num = Bonus(view, "extra"); if (num <= 0f || _roll == null) { return 0; } int num2 = 0; try { for (int i = 0; i < produced; i++) { num2 += (int)_roll.Invoke(null, new object[1] { num }); } } catch { } return num2; } } internal static class SeneaLCompat { public const string Guid = "seneaL.valheim.ui"; private const string MarkerName = "lynx_hearty"; private static FieldInfo _root; private static FieldInfo _count; public static void TryApply(Harmony harmony) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown if (!Chainloader.PluginInfos.ContainsKey("seneaL.valheim.ui")) { return; } try { int num = 0; Type type = AccessTools.TypeByName("SeneaLUI.Inv.Tips"); MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "Food", new Type[1] { typeof(ItemData) }, (Type[])null) : null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(FoodStatPatch), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); num++; } Type type2 = AccessTools.TypeByName("SeneaLUI.Components.Slot"); MethodInfo methodInfo2 = ((type2 != null) ? AccessTools.Method(type2, "Set", new Type[1] { typeof(ItemData) }, (Type[])null) : null); _root = ((type2 != null) ? AccessTools.Field(type2, "Root") : null); _count = ((type2 != null) ? AccessTools.Field(type2, "_count") : null); if (methodInfo2 != null && _root != null && _count != null) { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(SeneaLCompat), "SlotSetPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } Plugin.Log.LogInfo((object)$"SeneaL UI found: applied {num}/2 Hearty display patches"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("SeneaL UI compatibility failed: " + ex.Message)); } } private static void SlotSetPostfix(object __instance, ItemData item) { //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_00a4: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) try { object? value = _root.GetValue(__instance); RectTransform val = (RectTransform)((value is RectTransform) ? value : null); if ((Object)(object)val == (Object)null) { return; } bool flag = FoodRules.IsHearty(item); Transform val2 = ((Transform)val).Find("lynx_hearty"); if ((Object)(object)val2 == (Object)null) { if (!flag) { return; } object? value2 = _count.GetValue(__instance); TextMeshProUGUI val3 = (TextMeshProUGUI)((value2 is TextMeshProUGUI) ? value2 : null); if ((Object)(object)val3 == (Object)null) { return; } GameObject obj = Object.Instantiate<GameObject>(((Component)val3).gameObject, (Transform)(object)val, false); ((Object)obj).name = "lynx_hearty"; TextMeshProUGUI component = obj.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component).text = "<color=#FFB060>H</color>"; ((TMP_Text)component).alignment = (TextAlignmentOptions)1025; RectTransform val4 = (RectTransform)obj.transform; val4.anchorMin = Vector2.zero; val4.anchorMax = Vector2.zero; val4.pivot = Vector2.zero; val4.anchoredPosition = new Vector2(4f, 2f); val4.sizeDelta = new Vector2(24f, 20f); val2 = obj.transform; } if (((Component)val2).gameObject.activeSelf != flag) { ((Component)val2).gameObject.SetActive(flag); } } catch { } } } [HarmonyPatch] internal static class FoodStatPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Player), "EatFood", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Player), "UpdateFood", (Type[])null, (Type[])null); MethodInfo methodInfo = AccessTools.GetDeclaredMethods(typeof(ItemData)).FirstOrDefault((MethodInfo m) => m.Name.Contains("printConsumable")); if (methodInfo != null) { yield return methodInfo; } else { Plugin.Log.LogWarning((object)"Tooltip consumable printer not found; Hearty tooltip numbers will show base values"); } } internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original, ILGenerator generator) { //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); FieldInfo fieldInfo = AccessTools.Field(typeof(ItemData), "m_shared"); Dictionary<FieldInfo, MethodInfo> dictionary = new Dictionary<FieldInfo, MethodInfo> { { AccessTools.Field(typeof(SharedData), "m_food"), AccessTools.Method(typeof(FoodRules), "Health", (Type[])null, (Type[])null) }, { AccessTools.Field(typeof(SharedData), "m_foodStamina"), AccessTools.Method(typeof(FoodRules), "Stamina", (Type[])null, (Type[])null) }, { AccessTools.Field(typeof(SharedData), "m_foodEitr"), AccessTools.Method(typeof(FoodRules), "Eitr", (Type[])null, (Type[])null) } }; int num = 0; LocalBuilder localBuilder = null; for (int i = 0; i < list.Count - 1; i++) { if (!CodeInstructionExtensions.LoadsField(list[i], fieldInfo, false)) { continue; } CodeInstruction val = list[i + 1]; if (!(val.operand is FieldInfo key) || !dictionary.TryGetValue(key, out var value)) { continue; } if (val.opcode == OpCodes.Ldfld) { list[i].opcode = OpCodes.Call; list[i].operand = value; val.opcode = OpCodes.Nop; val.operand = null; num++; } else if (val.opcode == OpCodes.Ldflda) { if (localBuilder == null) { localBuilder = generator.DeclareLocal(typeof(float)); } list[i].opcode = OpCodes.Call; list[i].operand = value; val.opcode = OpCodes.Stloc; val.operand = localBuilder; list.Insert(i + 2, new CodeInstruction(OpCodes.Ldloca, (object)localBuilder)); num++; } } Plugin.Log.LogDebug((object)$"Hearty stat reads patched in {original.Name}: {num}"); return list; } } internal static class PlayerAccess { private static readonly FieldInfo FoodsField = AccessTools.Field(typeof(Player), "m_foods"); public static List<Food> Foods(Player p) { return (List<Food>)FoodsField.GetValue(p); } } [HarmonyPatch(typeof(Player), "EatFood")] internal static class EatFoodPatch { private static List<Food> Foods(Player p) { return PlayerAccess.Foods(p); } private static void Postfix(Player __instance, ItemData item, bool __result) { if (!__result || item == null || !FoodRules.IsHeartyCapable(item)) { return; } foreach (Food item2 in Foods(__instance)) { if (item2.m_item != null && !(item2.m_item.m_shared.m_name != item.m_shared.m_name)) { ItemData val = item.Clone(); val.m_stack = 1; item2.m_item = val; } } } } [HarmonyPatch] internal static class SaveLoadPatch { private const string Key = "LynxLeftovers.HeartyFoods"; private static List<Food> Foods(Player p) { return PlayerAccess.Foods(p); } [HarmonyPrefix] [HarmonyPatch(typeof(Player), "Save")] private static void SavePrefix(Player __instance) { List<string> list = (from f in Foods(__instance) where FoodRules.IsHearty(f.m_item) select f.m_name).ToList(); if (list.Count > 0) { __instance.m_customData["LynxLeftovers.HeartyFoods"] = string.Join("|", list); } else { __instance.m_customData.Remove("LynxLeftovers.HeartyFoods"); } } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "Load")] private static void LoadPostfix(Player __instance) { if (!__instance.m_customData.TryGetValue("LynxLeftovers.HeartyFoods", out var value) || string.IsNullOrEmpty(value)) { return; } HashSet<string> hashSet = new HashSet<string>(value.Split('|')); foreach (Food item in Foods(__instance)) { if (item.m_item != null && hashSet.Contains(item.m_name)) { ItemData val = item.m_item.Clone(); val.m_quality = 2; item.m_item = val; } } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] internal static class TooltipPatch { private static void Postfix(ItemData item, ref string __result) { if (FoodRules.IsHearty(item)) { int num = Mathf.RoundToInt((Plugin.HeartyMultiplier.Value - 1f) * 100f); __result = $"<color=#FFB060>Hearty</color>: +{num}% health, stamina and eitr\n\n" + __result; } } } [HarmonyPatch(typeof(ItemDrop), "GetHoverName")] internal static class GroundNamePatch { private static void Postfix(ItemDrop __instance, ref string __result) { if (FoodRules.IsHearty(__instance.m_itemData)) { __result = "Hearty " + __result; } } } [HarmonyPatch(typeof(ItemData), "IsSameType")] internal static class SameTypePatch { private static void Postfix(ItemData __instance, ItemData other, ref bool __result) { if (__result && other != null && __instance.m_quality != other.m_quality && FoodRules.IsHeartyCapable(__instance)) { __result = false; } } } [HarmonyPatch(typeof(InventoryGrid), "DropItem")] internal static class GridMergePatch { private static readonly FieldInfo InvField = AccessTools.Field(typeof(InventoryGrid), "m_inventory"); private static Inventory Inv(InventoryGrid g) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown return (Inventory)InvField.GetValue(g); } private static bool Prefix(InventoryGrid __instance, ItemData item, Vector2i pos, ref bool __result) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) Inventory obj = Inv(__instance); ItemData val = ((obj != null) ? obj.GetItemAt(pos.x, pos.y) : null); if (val == null || val == item || item == null) { return true; } if (val.m_shared.m_name != item.m_shared.m_name || val.m_quality == item.m_quality) { return true; } if (!FoodRules.IsHeartyCapable(item)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] internal static class GridMarkerPatch { private const string MarkerName = "lynx_hearty"; private static readonly FieldInfo InvField = AccessTools.Field(typeof(InventoryGrid), "m_inventory"); private static readonly FieldInfo ElementsField = AccessTools.Field(typeof(InventoryGrid), "m_elements"); private static void Postfix(InventoryGrid __instance) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0059: 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) Inventory val = (Inventory)InvField.GetValue(__instance); List<InventoryElement> list = (List<InventoryElement>)ElementsField.GetValue(__instance); if (val == null || list == null) { return; } foreach (InventoryElement item in list) { if ((Object)(object)item == (Object)null || (Object)(object)item.m_quality == (Object)null) { continue; } bool flag = FoodRules.IsHearty(val.GetItemAt(item.Position.x, item.Position.y)); Transform val2 = item.m_quality.transform.parent.Find("lynx_hearty"); if ((Object)(object)val2 == (Object)null) { if (!flag) { continue; } val2 = CreateMarker(item); } if (((Component)val2).gameObject.activeSelf != flag) { ((Component)val2).gameObject.SetActive(flag); } } } private static Transform CreateMarker(InventoryElement el) { //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) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_00b7: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Object.Instantiate<GameObject>(((Component)el.m_quality).gameObject, el.m_quality.transform.parent, false); ((Object)obj).name = "lynx_hearty"; TMP_Text component = obj.GetComponent<TMP_Text>(); ((Behaviour)component).enabled = true; component.text = "<color=#FFB060>H</color>"; component.alignment = (TextAlignmentOptions)1025; RectTransform val = (RectTransform)obj.transform; val.anchorMin = new Vector2(0f, 0f); val.anchorMax = new Vector2(0f, 0f); val.pivot = new Vector2(0f, 0f); val.anchoredPosition = new Vector2(3f, 1f); val.sizeDelta = new Vector2(24f, 20f); return obj.transform; } } [HarmonyPatch(typeof(Container), "Interact")] internal static class ContainerAltInteractPatch { private static bool Prefix(Container __instance, Humanoid character, bool hold, bool alt, ref bool __result) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown LeftoverStation component = ((Component)__instance).GetComponent<LeftoverStation>(); if ((Object)(object)component == (Object)null) { return true; } if (!alt) { if (!hold && (Object)(object)character == (Object)(object)Player.m_localPlayer) { PovCompat.StampLoader(((Component)__instance).GetComponent<ZNetView>(), (Player)character); } return true; } if (!hold) { component.RequestTakeOutput(); } __result = true; return false; } } [HarmonyPatch(typeof(ItemStand), "CanAttach")] internal static class ItemStandPatch { private static void Postfix(ItemData item, ref bool __result) { if (!__result && FoodRules.IsLeftovers(item) && !((Object)(object)item.m_dropPrefab == (Object)null)) { __result = (Object)(object)ItemStand.GetAttachPrefab(item.m_dropPrefab) != (Object)null; } } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class ContainerHoverPatch { private static void Postfix(Container __instance, ref string __result) { LeftoverStation component = ((Component)__instance).GetComponent<LeftoverStation>(); if ((Object)(object)component != (Object)null) { __result += component.StatusText(); } } } [BepInPlugin("lynx.lynxleftovers", "LynxLeftovers", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "lynx.lynxleftovers"; public const string ModName = "LynxLeftovers"; public const string Version = "1.0.1"; public const string BuildLabel = "1.0.1"; public static Plugin Instance; public static ManualLogSource Log; public static ConfigEntry<float> PointsPerLeftover; public static ConfigEntry<float> GrindSeconds; public static ConfigEntry<float> StewSeconds; public static ConfigEntry<float> StewCostRatio; public static ConfigEntry<float> HeartyMultiplier; public static ConfigEntry<string> ExcludedFoods; public static ConfigEntry<float> MaxCatchUpMinutes; public static ConfigEntry<string> BuildCategory; private Harmony _harmony; private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Expected O, but got Unknown //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { IsAdminOnly = true }; PointsPerLeftover = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "PointsPerLeftover", 100f, new ConfigDescription("Food value (health + stamina + eitr) that makes one Leftovers. The Stewpot uses the same unit.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 1000f), new object[1] { val })); GrindSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "GrindSeconds", 10f, new ConfigDescription("Seconds the Meat Grinder takes per food item.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f), new object[1] { val })); StewSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "StewSeconds", 30f, new ConfigDescription("Seconds the Stewpot takes to make one food item Hearty.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f), new object[1] { val })); StewCostRatio = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "StewCostRatio", 1f, new ConfigDescription("Leftovers cost to make a food Hearty, as a multiple of that food's own value. 1.0 = one food's worth of scraps upgrades one food of equal worth.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 10f), new object[1] { val })); HeartyMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "HeartyMultiplier", 1.15f, new ConfigDescription("Multiplier applied to a Hearty food's health, stamina and eitr. Duration is unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 3f), new object[1] { val })); ExcludedFoods = ((BaseUnityPlugin)this).Config.Bind<string>("Balance", "ExcludedFoods", "Honey", new ConfigDescription("Comma-separated item prefab names the grinder and Stewpot refuse, in addition to anything that comes off a pickable plant/bush.", (AcceptableValueBase)null, new object[1] { val })); MaxCatchUpMinutes = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "MaxCatchUpMinutes", 60f, new ConfigDescription("When a station's area loads after being away, it catches up on at most this many minutes of work.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1440f), new object[1] { val })); BuildCategory = ((BaseUnityPlugin)this).Config.Bind<string>("General", "BuildCategory", "Leftovers", "Hammer menu tab for the Meat Grinder and Stock Cask. Any non-vanilla name gives them their own tab (default: Leftovers). Vanilla tab names (Misc, Crafting, Furniture...) are accepted but may only show them under the All tab. Restart to apply."); AddLocalization(); PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable; _harmony = new Harmony("lynx.lynxleftovers"); _harmony.PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)"LynxLeftovers 1.0.1 loaded"); } private void Start() { DrawersCompat.TryApply(_harmony); PovCompat.TryApply(_harmony); SeneaLCompat.TryApply(_harmony); } private void OnVanillaPrefabsAvailable() { PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable; try { Content.Register(); } catch (Exception ex) { Log.LogError((object)("Failed to register LynxLeftovers content: " + ex)); } } private static void AddLocalization() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "item_lynx_leftovers", "Leftovers" }, { "item_lynx_leftovers_desc", "Ground-up scraps of old meals. Rendered into stock in a Stock Cask." }, { "piece_lynx_grinder", "Meat Grinder" }, { "piece_lynx_grinder_desc", "Put cooked food you'll never eat inside. It grinds it into Leftovers." }, { "piece_lynx_stockcask", "Stock Cask" }, { "piece_lynx_stockcask_desc", "Put Leftovers and a food stack inside. The Leftovers become stock, and food steeped in it comes out Hearty." }, { "lynx_hearty", "Hearty" } }); } } public abstract class LeftoverStation : MonoBehaviour { protected const string KeyLast = "lynx_last"; protected const string KeyProgress = "lynx_progress"; protected const string KeyPoints = "lynx_points"; protected const string KeyActive = "lynx_active"; protected const string KeyStatus = "lynx_status"; protected const string KeyOutput = "lynx_out"; private const string RpcTake = "LynxLeftovers_TakeOutput"; public GameObject m_activeVisual; public Transform m_outputPoint; public Transform[] m_spinY; public Transform[] m_spinZ; public float m_spinYSpeed = 120f; public float m_spinZSpeed = -360f; protected ZNetView m_nview; protected Container m_container; private float m_tickTimer; private const string KeyOutInv = "lynx_outinv"; protected abstract int OutputQuality { get; } protected virtual void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); m_container = ((Component)this).GetComponent<Container>(); if ((Object)(object)m_nview != (Object)null && m_nview.GetZDO() != null) { m_nview.Register("LynxLeftovers_TakeOutput", (Action<long>)RPC_TakeOutput); } WearNTear component = ((Component)this).GetComponent<WearNTear>(); if ((Object)(object)component != (Object)null) { component.m_onDestroyed = (Action)Delegate.Combine(component.m_onDestroyed, new Action(OnDestroyedPiece)); } } private static Inventory LoadOut(ZDO zdo) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown Inventory val = new Inventory("lynx_out", (Sprite)null, 8, 8); byte[] byteArray = zdo.GetByteArray("lynx_outinv", (byte[])null); if (byteArray != null && byteArray.Length != 0) { val.Load(new ZPackage(byteArray)); } return val; } private static void SaveOut(ZDO zdo, Inventory inv) { //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(); inv.Save(val); zdo.Set("lynx_outinv", val.GetArray()); } protected void AddOutput(ZDO zdo, ItemData item) { Inventory val = LoadOut(zdo); MigrateOldOutput(zdo, val); if (!val.AddItem(item)) { DropItemStack(item, item.m_stack); } foreach (ItemData item2 in val.GetAllItems().ToList()) { int num = Mathf.Max(1, item2.m_shared.m_maxStackSize); if (item2.m_stack >= num) { DropItemStack(item2, item2.m_stack); val.RemoveItem(item2); } } SaveOut(zdo, val); } protected static ItemData NewItem(string prefab, int count) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefab) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? 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 = count; return obj; } private void MigrateOldOutput(ZDO zdo, Inventory inv) { string text = zdo.GetString("lynx_out", ""); if (string.IsNullOrEmpty(text)) { return; } string[] array = text.Split('|'); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(':'); if (array2.Length != 2 || !int.TryParse(array2[1], out var result) || result <= 0) { continue; } ItemData val = NewItem(array2[0], result); if (val != null) { val.m_quality = OutputQuality; if (!inv.AddItem(val)) { DropItemStack(val, result); } } } zdo.Set("lynx_out", ""); } private void DropAllOutput() { ZDO zDO = m_nview.GetZDO(); Inventory val = LoadOut(zDO); MigrateOldOutput(zDO, val); foreach (ItemData item in val.GetAllItems().ToList()) { DropItemStack(item, item.m_stack); } val.RemoveAll(); SaveOut(zDO, val); } private void DropItemStack(ItemData item, int count) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (item != null && count > 0) { ItemDrop.DropItem(item, count, OutputPos(), Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)); } } public void RequestTakeOutput() { if ((Object)(object)m_nview != (Object)null && m_nview.IsValid()) { m_nview.InvokeRPC("LynxLeftovers_TakeOutput", Array.Empty<object>()); } } private void RPC_TakeOutput(long sender) { if (m_nview.IsOwner()) { DropAllOutput(); } } private void OnDestroyedPiece() { if ((Object)(object)m_nview != (Object)null && m_nview.IsValid() && m_nview.IsOwner()) { DropAllOutput(); } } protected string OutputText() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return ""; } ZDO zDO = m_nview.GetZDO(); List<string> list = (from it in LoadOut(zDO).GetAllItems() select string.Format("{0} {1}{2}", it.m_stack, FoodRules.IsHearty(it) ? "Hearty " : "", Localize(it.m_shared.m_name))).ToList(); if (!string.IsNullOrEmpty(zDO.GetString("lynx_out", ""))) { list.Add("(older items)"); } if (list.Count == 0) { return ""; } return "\nReady: " + string.Join(", ", list) + "\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] Take it out now"; } protected virtual void Update() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return; } bool flag = m_nview.GetZDO().GetBool("lynx_active", false); if ((Object)(object)m_activeVisual != (Object)null && m_activeVisual.activeSelf != flag) { m_activeVisual.SetActive(flag); } if (flag) { float deltaTime = Time.deltaTime; if (m_spinY != null) { Transform[] spinY = m_spinY; foreach (Transform val in spinY) { if (Object.op_Implicit((Object)(object)val)) { val.Rotate(0f, m_spinYSpeed * deltaTime, 0f, (Space)1); } } } if (m_spinZ != null) { Transform[] spinY = m_spinZ; foreach (Transform val2 in spinY) { if (Object.op_Implicit((Object)(object)val2)) { val2.Rotate(0f, 0f, m_spinZSpeed * deltaTime, (Space)1); } } } } if (!m_nview.IsOwner()) { return; } m_tickTimer += Time.deltaTime; if (m_tickTimer < 1f) { return; } m_tickTimer = 0f; ZDO zDO = m_nview.GetZDO(); DateTime time = ZNet.instance.GetTime(); long num = zDO.GetLong("lynx_last", 0L); float dt = 1f; if (num != 0L) { dt = (float)(time - new DateTime(num)).TotalSeconds; dt = Mathf.Clamp(dt, 0f, Plugin.MaxCatchUpMinutes.Value * 60f + 1f); } zDO.Set("lynx_last", time.Ticks); Inventory val3 = (((Object)(object)m_container != (Object)null) ? m_container.GetInventory() : null); if (val3 == null) { return; } PovCompat.Refresh(m_nview); try { Tick(zDO, val3, dt); } catch (Exception arg) { Plugin.Log.LogError((object)$"{((Object)this).name} tick failed: {arg}"); } } protected abstract void Tick(ZDO zdo, Inventory inv, float dt); public abstract string StatusText(); protected static ItemData FindFirst(Inventory inv, Func<ItemData, bool> pred) { ItemData val = null; foreach (ItemData allItem in inv.GetAllItems()) { if (pred(allItem) && (val == null || allItem.m_gridPos.y < val.m_gridPos.y || (allItem.m_gridPos.y == val.m_gridPos.y && allItem.m_gridPos.x < val.m_gridPos.x))) { val = allItem; } } return val; } protected Vector3 OutputPos() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) return (((Object)(object)m_outputPoint != (Object)null) ? m_outputPoint.position : (((Component)this).transform.position + Vector3.up)) + Random.insideUnitSphere * 0.05f; } protected static string Localize(string s) { if (Localization.instance == null) { return s; } return Localization.instance.Localize(s); } } public class MeatGrinder : LeftoverStation { protected override int OutputQuality => 1; protected override void Tick(ZDO zdo, Inventory inv, float dt) { float num = zdo.GetFloat("lynx_progress", 0f) + dt; float num2 = zdo.GetFloat("lynx_points", 0f); float num3 = Mathf.Max(0.1f, Plugin.GrindSeconds.Value) / PovCompat.SpeedFactor(m_nview); float num4 = Mathf.Max(1f, Plugin.PointsPerLeftover.Value); bool flag = false; string text = ""; int num5 = 0; int num6 = 1000; while (num6-- > 0) { ItemData val = LeftoverStation.FindFirst(inv, FoodRules.IsEligibleFood); if (val == null) { num = 0f; break; } flag = true; text = val.m_shared.m_name; if (num < num3) { break; } num -= num3; num2 += FoodRules.Value(val); inv.RemoveItem(val, 1); while (num2 >= num4) { num2 -= num4; num5++; } } if (num5 > 0) { num5 += PovCompat.ExtraRolls(m_nview, num5); ItemData val2 = LeftoverStation.NewItem("LynxLeftovers", num5); if (val2 != null) { AddOutput(zdo, val2); } } zdo.Set("lynx_progress", num); zdo.Set("lynx_points", num2); zdo.Set("lynx_active", flag); zdo.Set("lynx_status", text); } public override string StatusText() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return ""; } ZDO zDO = m_nview.GetZDO(); float num = 100f * zDO.GetFloat("lynx_points", 0f) / Mathf.Max(1f, Plugin.PointsPerLeftover.Value); string arg = (zDO.GetBool("lynx_active", false) ? ("Grinding: " + LeftoverStation.Localize(zDO.GetString("lynx_status", ""))) : "<color=#a0a0a0>Idle - add cooked food</color>"); return LeftoverStation.Localize($"\n{arg}\nNext Leftovers: {num:0}%" + OutputText()); } } public class Stewpot : LeftoverStation { protected override int OutputQuality => 2; protected override void Tick(ZDO zdo, Inventory inv, float dt) { float num = zdo.GetFloat("lynx_progress", 0f) + dt; float num2 = zdo.GetFloat("lynx_points", 0f); float num3 = Mathf.Max(0.1f, Plugin.StewSeconds.Value) / PovCompat.SpeedFactor(m_nview); float num4 = Mathf.Max(1f, Plugin.PointsPerLeftover.Value); bool flag = false; string text = ""; int num5 = 1000; while (num5-- > 0) { ItemData val = LeftoverStation.FindFirst(inv, FoodRules.IsEligibleFood); if (val == null) { num = 0f; text = ""; break; } float num6; for (num6 = FoodRules.Value(val) * Plugin.StewCostRatio.Value / num4; num2 + 0.0001f < num6; num2 += 1f) { ItemData val2 = LeftoverStation.FindFirst(inv, FoodRules.IsLeftovers); if (val2 == null) { break; } inv.RemoveItem(val2, 1); } if (num2 + 0.0001f < num6) { num = 0f; text = "!" + val.m_shared.m_name + "|" + num6.ToString("0.00"); break; } flag = true; text = val.m_shared.m_name + "|" + num6.ToString("0.00"); if (num < num3) { break; } num -= num3; num2 = Mathf.Max(0f, num2 - num6); ItemData val3 = val.Clone(); val3.m_stack = 1; val3.m_quality = 2; inv.RemoveItem(val, 1); AddOutput(zdo, val3); } zdo.Set("lynx_progress", num); zdo.Set("lynx_points", num2); zdo.Set("lynx_active", flag); zdo.Set("lynx_status", text); } public override string StatusText() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return ""; } ZDO zDO = m_nview.GetZDO(); float num = zDO.GetFloat("lynx_points", 0f); string text = zDO.GetString("lynx_status", ""); string arg; if (string.IsNullOrEmpty(text)) { arg = "<color=#a0a0a0>Idle - add Leftovers and a food stack</color>"; } else { bool flag = text.StartsWith("!"); string[] array = text.TrimStart('!').Split('|'); string text2 = LeftoverStation.Localize(array[0]); string text3 = ((array.Length > 1) ? array[1] : "?"); arg = (flag ? ("<color=#ff8060>Needs " + text3 + " stock for " + text2 + "</color>") : ("Steeping: " + text2 + " (uses " + text3 + " stock)")); } float num2 = 0f; if ((Object)(object)m_container != (Object)null && m_container.GetInventory() != null) { foreach (ItemData allItem in m_container.GetInventory().GetAllItems()) { if (FoodRules.IsLeftovers(allItem)) { num2 += (float)allItem.m_stack; } } } return LeftoverStation.Localize($"\n{arg}\nStock: {num + num2:0.00}" + OutputText()); } }