using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("SwampKeyBundle")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("FSOS-X R10 EXP")] [assembly: AssemblyProduct("SwampKeyBundle")] [assembly: AssemblyCopyright("Copyright © FSOS-X R10 EXP 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4e3c96f9-75e1-43a1-a13d-36cda88fc6ad")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace ValheimCryptKeySlotHUD; [HarmonyPatch(typeof(Door), "Interact")] public static class DoorInteractKeyInjectionPatch { public static void Prefix(Door __instance, Humanoid character, bool hold, bool alt) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown if ((Object)(object)character != (Object)null && ((Character)character).IsPlayer() && (Object)(object)__instance.m_keyItem != (Object)null && __instance.m_keyItem.m_itemData.m_shared.m_name == "$item_cryptkey") { Player val = (Player)character; if (CryptKeySlotHUDMod.VirtualKeyInventory != null && !((Humanoid)val).GetInventory().ContainsItem(__instance.m_keyItem.m_itemData) && CryptKeySlotHUDMod.VirtualKeyInventory.GetItem("$item_cryptkey", -1, false) != null) { ((Humanoid)val).GetInventory().AddItem(((Component)__instance.m_keyItem).gameObject, 1); ((MonoBehaviour)val).StartCoroutine(RemoveKeyNextFrame(val)); } } } private static IEnumerator RemoveKeyNextFrame(Player player) { yield return null; if ((Object)(object)player != (Object)null && ((Humanoid)player).GetInventory() != null) { ItemData item = ((Humanoid)player).GetInventory().GetItem("$item_cryptkey", -1, false); if (item != null) { ((Humanoid)player).GetInventory().RemoveItem(item); } } } } [HarmonyPatch(typeof(Door), "GetHoverText")] public static class DoorHoverTextPatch { public static void Postfix(Door __instance, ref string __result) { if ((Object)(object)__instance.m_keyItem != (Object)null && __instance.m_keyItem.m_itemData.m_shared.m_name == "$item_cryptkey" && (Object)(object)Player.m_localPlayer != (Object)null && CryptKeySlotHUDMod.VirtualKeyInventory != null && CryptKeySlotHUDMod.VirtualKeyInventory.GetItem("$item_cryptkey", -1, false) != null && (__result.Contains("$piece_dungeon_cryptkey_required") || __result.Contains("Swamp Key") || __result.Contains("Need key"))) { __result = __instance.m_name + "\n[E] Open"; } } } public class CryptKeyClickComponent : MonoBehaviour, IPointerClickHandler, IEventSystemHandler, IPointerEnterHandler, IPointerExitHandler { public void OnPointerEnter(PointerEventData eventData) { } public void OnPointerExit(PointerEventData eventData) { } public void OnPointerClick(PointerEventData eventData) { //IL_0020: 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_00ff: 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) Player localPlayer = Player.m_localPlayer; InventoryGui instance = InventoryGui.instance; if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance == (Object)null) { return; } if ((int)eventData.button == 0) { FieldInfo field = typeof(InventoryGui).GetField("m_dragItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field2 = typeof(InventoryGui).GetField("m_dragInventory", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo method = typeof(InventoryGui).GetMethod("SetupDragItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { field = typeof(InventoryGui).GetField("dragItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (field2 == null) { field2 = typeof(InventoryGui).GetField("dragInventory", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (method == null) { method = typeof(InventoryGui).GetMethod("SetDragItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } ItemData val = ((!(field != null)) ? ((ItemData)null) : ((ItemData)field.GetValue(instance))); Inventory val2 = ((!(field2 != null)) ? ((Inventory)null) : ((Inventory)field2.GetValue(instance))); if (val != null) { if (val.m_shared.m_name == "$item_cryptkey" && CryptKeySlotHUDMod.VirtualKeyInventory.GetItem("$item_cryptkey", -1, false) == null) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("CryptKey"); if ((Object)(object)itemPrefab != (Object)null) { CryptKeySlotHUDMod.VirtualKeyInventory.AddItem(itemPrefab, 1); if (val2 != null) { if (val.m_stack > 1) { val.m_stack--; } else { val2.RemoveItem(val); } } ClearDragItem(method, instance); if ((Object)(object)itemPrefab.GetComponent() != (Object)null) { itemPrefab.GetComponent().m_itemData.m_shared.m_itemType = (ItemType)1; } if ((Object)(object)CryptKeySlotHUDMod.KeyPanel != (Object)null) { CryptKeySlotHUDMod.KeyPanel.GetComponent().StartCoroutine(CryptKeySlotHUDMod.FlashGreenGlow()); } } } } else if (val == null) { ItemData item = CryptKeySlotHUDMod.VirtualKeyInventory.GetItem("$item_cryptkey", -1, false); if (item != null) { GameObject itemPrefab2 = ObjectDB.instance.GetItemPrefab("CryptKey"); if ((Object)(object)itemPrefab2 != (Object)null) { ItemData val3 = ((Humanoid)localPlayer).PickupPrefab(itemPrefab2, 1, true); if (val3 != null) { CryptKeySlotHUDMod.VirtualKeyInventory.RemoveItem(item); if (method != null) { try { method.Invoke(instance, new object[3] { val3, ((Humanoid)localPlayer).GetInventory(), 1 }); } catch { method.Invoke(instance, new object[2] { val3, ((Humanoid)localPlayer).GetInventory() }); } } } } } } } CryptKeySlotHUDMod.UpdateSlotVisuals(); instance.m_playerGrid.UpdateInventory(((Humanoid)localPlayer).GetInventory(), localPlayer, (ItemData)null); } private void ClearDragItem(MethodInfo setupDragMethod, InventoryGui gui) { if (setupDragMethod != null) { try { setupDragMethod.Invoke(gui, new object[3] { null, null, 0 }); } catch { setupDragMethod.Invoke(gui, null); } } } } [BepInPlugin("EndosCryptKeySlot", "EndosCryptKeySlotMod", "1.0.0")] public class CryptKeySlotHUDMod : BaseUnityPlugin { public static Image GlowIconImage; public const string ModGUID = "EndosCryptKeySlot"; public const string ModName = "EndosCryptKeySlotMod"; public const string ModVersion = "1.0.0"; private Harmony harmony; public static GameObject KeyPanel; public static Text SlotText; public static Image SlotIconImage; public static Inventory VirtualKeyInventory; public static ConfigEntry ConfigPosX; public static ConfigEntry ConfigPosY; public static void CreateKeySlotUI(InventoryGui gui) { if ((Object)(object)gui != (Object)null && ((Component)gui).gameObject.activeInHierarchy) { CryptKeySlotHUDMod cryptKeySlotHUDMod = Object.FindAnyObjectByType(); if ((Object)(object)cryptKeySlotHUDMod != (Object)null) { ((MonoBehaviour)cryptKeySlotHUDMod).StartCoroutine(DelayedCreateUI(gui)); } } } private static IEnumerator DelayedCreateUI(InventoryGui gui) { yield return (object)new WaitForSecondsRealtime(0.15f); if ((Object)(object)gui == (Object)null || (Object)(object)KeyPanel != (Object)null) { yield break; } GameObject val = GameObject.Find("ArmorSlots") ?? GameObject.Find("EquipmentAndQuickSlots") ?? GameObject.Find("EquipmentPanel") ?? GameObject.Find("EquipmentGui"); if ((Object)(object)val == (Object)null && (Object)(object)((Component)gui).transform.parent != (Object)null) { Transform[] componentsInChildren = ((Component)((Component)gui).transform.parent).GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { if ((((Object)((Component)val2).gameObject).name.Contains("Equipment") || ((Object)((Component)val2).gameObject).name.Contains("ArmorSlots")) && ((Component)val2).gameObject.activeInHierarchy) { val = ((Component)val2).gameObject; break; } } } Transform val3 = (((Object)(object)val != (Object)null) ? val.transform : ((Component)gui.m_playerGrid).transform.parent); if ((Object)(object)val3 == (Object)null) { yield break; } KeyPanel = new GameObject("CryptKeySlotHUD", new Type[4] { typeof(RectTransform), typeof(Image), typeof(CanvasGroup), typeof(CryptKeyClickComponent) }); KeyPanel.transform.SetParent(val3, false); Image component = KeyPanel.GetComponent(); ((Graphic)component).raycastTarget = true; Sprite val4 = null; Image[] array = Resources.FindObjectsOfTypeAll(); foreach (Image val5 in array) { if ((Object)(object)val5 != (Object)null && (Object)(object)val5.sprite != (Object)null) { switch (((Object)val5.sprite).name.ToLower()) { case "ac_bkg": case "stat_bkg": case "bkg": case "damage_bkg": case "armor_bkg": break; default: continue; } val4 = val5.sprite; ((Graphic)component).material = ((Graphic)val5).material; ((Graphic)component).color = ((Graphic)val5).color; break; } } if ((Object)(object)val4 == (Object)null) { GameObject val6 = GameObject.Find("ac") ?? GameObject.Find("ac_bkg") ?? GameObject.Find("Armor") ?? GameObject.Find("ac_icon"); if ((Object)(object)val6 != (Object)null) { Image val7 = val6.GetComponent() ?? val6.GetComponentInChildren(true); if ((Object)(object)val7 != (Object)null && (Object)(object)val7.sprite != (Object)null) { val4 = val7.sprite; ((Graphic)component).material = ((Graphic)val7).material; ((Graphic)component).color = ((Graphic)val7).color; } } } if ((Object)(object)val4 != (Object)null) { component.sprite = val4; component.type = (Type)0; ((Graphic)component).color = Color.white; } else { ((Graphic)component).color = new Color(0f, 0f, 0f, 0.4f); } RectTransform component2 = KeyPanel.GetComponent(); component2.anchorMin = new Vector2(0f, 1f); component2.anchorMax = new Vector2(0f, 1f); component2.pivot = new Vector2(0.5f, 0.5f); component2.sizeDelta = new Vector2(54f, 60f); UpdateSlotPosition(); GameObject val8 = new GameObject("SlotGlow", new Type[2] { typeof(RectTransform), typeof(Image) }); val8.transform.SetParent(KeyPanel.transform, false); GlowIconImage = val8.GetComponent(); ((Graphic)GlowIconImage).raycastTarget = false; GlowIconImage.sprite = component.sprite; ((Graphic)GlowIconImage).material = ((Graphic)component).material; GlowIconImage.type = (Type)0; ((Graphic)GlowIconImage).color = new Color(0f, 1f, 0.2f, 0f); RectTransform component3 = val8.GetComponent(); component3.anchorMin = new Vector2(0f, 0f); component3.anchorMax = new Vector2(1f, 1f); component3.offsetMin = new Vector2(0f, 0f); component3.offsetMax = new Vector2(0f, 0f); GameObject val9 = new GameObject("SlotInside", new Type[2] { typeof(RectTransform), typeof(Image) }); val9.transform.SetParent(KeyPanel.transform, false); Image component4 = val9.GetComponent(); ((Graphic)component4).raycastTarget = false; ((Graphic)component4).color = new Color(0f, 0f, 0f, 0f); RectTransform component5 = val9.GetComponent(); component5.anchorMin = new Vector2(0f, 0f); component5.anchorMax = new Vector2(1f, 1f); component5.offsetMin = new Vector2(0f, 0f); component5.offsetMax = new Vector2(0f, 0f); GameObject val10 = new GameObject("KeyIcon", new Type[2] { typeof(RectTransform), typeof(Image) }); val10.transform.SetParent(val9.transform, false); SlotIconImage = val10.GetComponent(); ((Graphic)SlotIconImage).raycastTarget = false; RectTransform component6 = val10.GetComponent(); component6.anchorMin = new Vector2(0.5f, 0.5f); component6.anchorMax = new Vector2(0.5f, 0.5f); component6.pivot = new Vector2(0.5f, 0.5f); component6.sizeDelta = new Vector2(40f, 40f); component6.anchoredPosition = new Vector2(0f, 4f); GameObject val11 = new GameObject("KeySlotText", new Type[2] { typeof(RectTransform), typeof(Text) }); val11.transform.SetParent(val9.transform, false); SlotText = val11.GetComponent(); ((Graphic)SlotText).raycastTarget = false; Font[] array2 = Resources.FindObjectsOfTypeAll(); foreach (Font val12 in array2) { if (((Object)val12).name.Contains("Averia")) { SlotText.font = val12; break; } } if ((Object)(object)SlotText.font == (Object)null) { ? val13 = SlotText; Object builtinResource = Resources.GetBuiltinResource(typeof(Font), "Arial.ttf"); ((Text)val13).font = (Font)(object)((builtinResource is Font) ? builtinResource : null); } SlotText.fontSize = 10; ((Graphic)SlotText).color = new Color(1f, 0.85f, 0.4f, 0.8f); SlotText.alignment = (TextAnchor)7; Shadow obj = val11.AddComponent(); obj.effectColor = Color.black; obj.effectDistance = new Vector2(1f, -1f); RectTransform component7 = val11.GetComponent(); component7.anchorMin = new Vector2(0f, 0f); component7.anchorMax = new Vector2(1f, 1f); component7.offsetMin = new Vector2(0f, 4f); component7.offsetMax = new Vector2(0f, 0f); UpdateSlotVisuals(); } public static IEnumerator FlashGreenGlow() { if (!((Object)(object)GlowIconImage == (Object)null)) { float duration = 0.4f; float elapsed = 0f; while (elapsed < duration) { elapsed += Time.unscaledDeltaTime; float num = Mathf.Lerp(0f, 0.75f, elapsed / duration); ((Graphic)GlowIconImage).color = new Color(0.1f, 1f, 0.3f, num); yield return null; } elapsed = 0f; while (elapsed < duration) { elapsed += Time.unscaledDeltaTime; float num2 = Mathf.Lerp(0.75f, 0f, elapsed / duration); ((Graphic)GlowIconImage).color = new Color(0.1f, 1f, 0.3f, num2); yield return null; } ((Graphic)GlowIconImage).color = new Color(0.1f, 1f, 0.3f, 0f); } } private void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown harmony = new Harmony("EndosCryptKeySlot"); harmony.PatchAll(); ConfigPosX = ((BaseUnityPlugin)this).Config.Bind("Position", "Slot X Position", 160f, "The horizontal position relative to the equipment panel."); ConfigPosY = ((BaseUnityPlugin)this).Config.Bind("Position", "Slot Y Position", -72f, "The vertical position relative to the equipment panel."); ConfigPosX.SettingChanged += delegate { UpdateSlotPosition(); }; ConfigPosY.SettingChanged += delegate { UpdateSlotPosition(); }; VirtualKeyInventory = new Inventory("VirtualCryptKeyInv", (Sprite)null, 1, 1); Inventory virtualKeyInventory = VirtualKeyInventory; virtualKeyInventory.m_onChanged = (Action)Delegate.Combine(virtualKeyInventory.m_onChanged, new Action(UpdateSlotVisuals)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"=== EndosCryptKeySlot successfully loaded! ==="); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } public static void UpdateSlotPosition() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)KeyPanel != (Object)null) { RectTransform component = KeyPanel.GetComponent(); if ((Object)(object)component != (Object)null) { component.anchoredPosition = new Vector2(ConfigPosX.Value, ConfigPosY.Value); } } } public static void UpdateSlotVisuals() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) if (VirtualKeyInventory == null || (Object)(object)SlotIconImage == (Object)null) { return; } ItemData item = VirtualKeyInventory.GetItem("$item_cryptkey", -1, false); if (item != null && item.m_shared.m_icons != null && item.m_shared.m_icons.Length != 0) { SlotIconImage.sprite = item.m_shared.m_icons[0]; ((Graphic)SlotIconImage).color = Color.white; if ((Object)(object)SlotText != (Object)null) { SlotText.text = ""; } return; } if ((Object)(object)ObjectDB.instance != (Object)null) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("CryptKey"); if ((Object)(object)itemPrefab != (Object)null) { ItemDrop component = itemPrefab.GetComponent(); if ((Object)(object)component != (Object)null && component.m_itemData.m_shared.m_icons != null && component.m_itemData.m_shared.m_icons.Length != 0) { SlotIconImage.sprite = component.m_itemData.m_shared.m_icons[0]; ((Graphic)SlotIconImage).color = new Color(0f, 0f, 0f, 0.4f); } } } if ((Object)(object)SlotText != (Object)null) { SlotText.text = "Key"; } } public static void EmptySlot() { if (VirtualKeyInventory == null) { return; } foreach (ItemData item in new List(VirtualKeyInventory.GetAllItems())) { VirtualKeyInventory.RemoveItem(item); } } } [HarmonyPatch(typeof(InventoryGui), "Show")] public static class InventoryGuiShowPatch { private static void Postfix(InventoryGui __instance) { if ((Object)(object)CryptKeySlotHUDMod.KeyPanel == (Object)null) { CryptKeySlotHUDMod.CreateKeySlotUI(__instance); } if ((Object)(object)CryptKeySlotHUDMod.KeyPanel != (Object)null) { CryptKeySlotHUDMod.KeyPanel.SetActive(true); CryptKeySlotHUDMod.UpdateSlotPosition(); CryptKeySlotHUDMod.UpdateSlotVisuals(); } } } [HarmonyPatch(typeof(InventoryGui), "Hide")] public static class InventoryGuiHidePatch { private static void Postfix() { if ((Object)(object)CryptKeySlotHUDMod.KeyPanel != (Object)null) { CryptKeySlotHUDMod.KeyPanel.SetActive(false); } } } [HarmonyPatch(typeof(Player), "Save")] public static class PlayerSavePatch { public static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { bool flag = CryptKeySlotHUDMod.VirtualKeyInventory.GetItem("$item_cryptkey", -1, false) != null; __instance.m_customData["cryptkey_slot_has_key"] = (flag ? "1" : "0"); } } } [HarmonyPatch(typeof(Player), "Load")] public static class PlayerLoadPatch { public static void Postfix(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } CryptKeySlotHUDMod.EmptySlot(); if (__instance.m_customData.TryGetValue("cryptkey_slot_has_key", out var value) && value == "1" && (Object)(object)ObjectDB.instance != (Object)null) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("CryptKey"); if ((Object)(object)itemPrefab != (Object)null) { CryptKeySlotHUDMod.VirtualKeyInventory.AddItem(itemPrefab, 1); } } CryptKeySlotHUDMod.UpdateSlotVisuals(); } } [HarmonyPatch(typeof(Player), "OnDeath")] public static class PlayerCreateTombStonePatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { bool flag = CryptKeySlotHUDMod.VirtualKeyInventory.GetItem("$item_cryptkey", -1, false) != null; __instance.m_customData["cryptkey_slot_has_key"] = (flag ? "1" : "0"); } } } [HarmonyPatch(typeof(Game), "Logout")] public static class GameLogoutPatch { private static void Prefix() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && CryptKeySlotHUDMod.VirtualKeyInventory != null) { bool flag = CryptKeySlotHUDMod.VirtualKeyInventory.GetItem("$item_cryptkey", -1, false) != null; localPlayer.m_customData["cryptkey_slot_has_key"] = (flag ? "1" : "0"); CryptKeySlotHUDMod.EmptySlot(); CryptKeySlotHUDMod.UpdateSlotVisuals(); } } }