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 CustomSlotItemLib v1.1.2
CustomSlotItemLib.dll
Decompiled 2 years 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.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("CustomSlotItemLib")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Riintouge")] [assembly: AssemblyProduct("CustomSlotItemLib")] [assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("6bca374e-6da0-4450-b33c-ceeed956ac8b")] [assembly: AssemblyFileVersion("1.1.2.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.1.2.0")] namespace CustomSlotItemLib; public class CustomSlotData : MonoBehaviour { public string slotName; } [BepInPlugin("com.riintouge.customslotitemlib", "CustomSlotItemLib", "1.1.1")] [BepInProcess("valheim.exe")] public class CustomSlotItemLib : BaseUnityPlugin { [HarmonyPatch(typeof(Humanoid))] [HarmonyPriority(600)] public class HumanoidPatch { public static HashSet<StatusEffect> GetStatusEffectsFromCustomSlotItems(Humanoid __instance) { HashSet<StatusEffect> hashSet = new HashSet<StatusEffect>(); foreach (ItemData item in CustomSlotManager.AllSlotItems(__instance)) { if (Object.op_Implicit((Object)(object)item.m_shared.m_equipStatusEffect)) { hashSet.Add(item.m_shared.m_equipStatusEffect); } if (Traverse.Create((object)__instance).Method("HaveSetEffect", new Type[1] { typeof(ItemData) }, (object[])null).GetValue<bool>(new object[1] { item })) { hashSet.Add(item.m_shared.m_setStatusEffect); } } return hashSet; } [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePostfix(ref Humanoid __instance) { CustomSlotManager.Register(__instance); } [HarmonyPatch("EquipItem")] [HarmonyPostfix] private static void EquipItemPostfix(ref bool __result, ref Humanoid __instance, ItemData item, bool triggerEquipEffects = true) { if (__result && CustomSlotManager.IsCustomSlotItem(item)) { string customSlotName = CustomSlotManager.GetCustomSlotName(item); ItemData slotItem = CustomSlotManager.GetSlotItem(__instance, customSlotName); if (slotItem != null) { __instance.UnequipItem(slotItem, triggerEquipEffects); } CustomSlotManager.SetSlotItem(__instance, customSlotName, item); item.m_equipped = __instance.IsItemEquiped(item); Traverse.Create((object)__instance).Method("SetupEquipment", Array.Empty<object>()).GetValue(); if (item.m_equipped && triggerEquipEffects) { Traverse.Create((object)__instance).Method("TriggerEquipEffect", new Type[1] { typeof(ItemData) }, (object[])null).GetValue(new object[1] { item }); } __result = true; } } [HarmonyPatch("GetEquipmentWeight")] [HarmonyPostfix] private static void GetEquipmentWeightPostfix(ref float __result, ref Humanoid __instance) { foreach (ItemData item in CustomSlotManager.AllSlotItems(__instance)) { __result += item.m_shared.m_weight; } } [HarmonyPatch("GetSetCount")] [HarmonyPostfix] private static void GetSetCountPostfix(ref int __result, ref Humanoid __instance, string setName) { foreach (ItemData item in CustomSlotManager.AllSlotItems(__instance)) { if (item.m_shared.m_setName == setName) { __result++; } } } [HarmonyPatch("IsItemEquiped")] [HarmonyPostfix] private static void IsItemEquipedPostfix(ref bool __result, ref Humanoid __instance, ItemData item) { if (CustomSlotManager.IsCustomSlotItem(item)) { string customSlotName = CustomSlotManager.GetCustomSlotName(item); __result |= CustomSlotManager.GetSlotItem(__instance, customSlotName) == item; } } [HarmonyPatch("UnequipAllItems")] [HarmonyPostfix] private static void UnequipAllItemsPostfix(ref Humanoid __instance) { foreach (ItemData item in CustomSlotManager.AllSlotItems(__instance)) { __instance.UnequipItem(item, false); } } [HarmonyPatch("UnequipItem")] [HarmonyPostfix] private static void UnequipItemPostfix(ref Humanoid __instance, ItemData item, bool triggerEquipEffects = true) { if (item != null) { string customSlotName = CustomSlotManager.GetCustomSlotName(item); if (item == CustomSlotManager.GetSlotItem(__instance, customSlotName)) { CustomSlotManager.SetSlotItem(__instance, customSlotName, null); item.m_equipped = __instance.IsItemEquiped(item); Traverse.Create((object)__instance).Method("UpdateEquipmentStatusEffects", Array.Empty<object>()).GetValue(); } } } [HarmonyPatch("UpdateEquipmentStatusEffects")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> UpdateEquipmentStatusEffectsTranspiler(IEnumerable<CodeInstruction> instructionsIn) { List<CodeInstruction> instructions = instructionsIn.ToList(); if (instructions[0].opcode != OpCodes.Newobj || instructions[1].opcode != OpCodes.Stloc_0) { throw new Exception("CustomSlotItemLib transpiler injection point not found!"); } yield return instructions[0]; yield return instructions[1]; yield return new CodeInstruction(OpCodes.Ldloc_0, (object)null); yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null); yield return CodeInstruction.Call(typeof(HumanoidPatch), "GetStatusEffectsFromCustomSlotItems", (Type[])null, (Type[])null); yield return CodeInstruction.Call(typeof(HashSet<StatusEffect>), "UnionWith", (Type[])null, (Type[])null); for (int index = 2; index < instructions.Count; index++) { yield return instructions[index]; } } } [HarmonyPatch(typeof(ItemData))] [HarmonyPriority(600)] private class ItemDropItemDataPatch { [HarmonyPatch("IsEquipable")] [HarmonyPostfix] private static void IsEquipablePostfix(ref bool __result, ref ItemData __instance) { __result |= CustomSlotManager.IsCustomSlotItem(__instance); } } [HarmonyPatch(typeof(Player))] [HarmonyPriority(600)] internal class PlayerPatch { [HarmonyPatch("Load")] [HarmonyPostfix] private static void LoadPostfix(ref Player __instance) { foreach (ItemData equippedItem in ((Humanoid)__instance).GetInventory().GetEquippedItems()) { string customSlotName = CustomSlotManager.GetCustomSlotName(equippedItem); if (customSlotName != null) { CustomSlotManager.SetSlotItem((Humanoid)(object)__instance, customSlotName, equippedItem); } } } } [HarmonyPatch(typeof(ZNetScene))] [HarmonyPriority(600)] public class ZNetScenePatch { [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePostfix(ref ZNetScene __instance) { if (Utility.IsNullOrWhiteSpace(ItemSlotPairs.Value)) { return; } try { string[] array = ItemSlotPairs.Value.Split(new char[1] { ';' }); for (int i = 0; i < array.Length; i++) { string[] array2 = ValidateItemSlotPair(array[i]); CustomSlotManager.ApplyCustomSlotItem(__instance.GetPrefab(array2[0]), array2[1]); } } catch (Exception value) { Console.WriteLine(value); } } } public static ConfigEntry<bool> LoadOnStart; public static ConfigEntry<string> ItemSlotPairs; private readonly Harmony Harmony = new Harmony("com.riintouge.customslotitemlib"); private void Awake() { LoadOnStart = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Core", "LoadOnStart", true, "Whether this plugin loads on game start."); ItemSlotPairs = ((BaseUnityPlugin)this).Config.Bind<string>("1 - General", "ItemSlotPairs", "Demister,wisplight;Wishbone,wishbone", "\"ItemName1,SlotName;...;ItemNameN,SlotName\"\nMultiple items can go in the same slot (not all at once), but an item cannot go in multiple slots.\nThe game must be restarted for changes to take effect."); if (LoadOnStart.Value) { Harmony.PatchAll(); } } private static string[] ValidateItemSlotPair(string rawPair) { if (rawPair == null) { throw new ArgumentNullException("rawPair"); } string[] array = rawPair.Split(new char[1] { ',' }); if (array.Length < 2) { throw new ArgumentException("Item slot pair does not name a slot!"); } if (array.Length > 2) { throw new ArgumentException("Item slot pair lists more than a Item and a slot!"); } if (Utility.IsNullOrWhiteSpace(array[0])) { throw new ArgumentException("Item name is null or whitespace!"); } if (Utility.IsNullOrWhiteSpace(array[1])) { throw new ArgumentException("Slot name is null or whitespace!"); } if ((Object)(object)ZNetScene.instance.GetPrefab(array[0]) == (Object)null) { throw new NullReferenceException("Item \"" + array[0] + "\" is NULL!"); } return array; } } public static class CustomSlotManager { private static readonly Dictionary<Humanoid, Dictionary<string, ItemData>> customSlotItemData = new Dictionary<Humanoid, Dictionary<string, ItemData>>(); public static void Register(Humanoid humanoid) { customSlotItemData[humanoid] = new Dictionary<string, ItemData>(); } public static void Unregister(Humanoid humanoid) { customSlotItemData.Remove(humanoid); } public static bool IsCustomSlotItem(ItemData item) { return GetCustomSlotName(item) != null; } public static string GetCustomSlotName(ItemData item) { if (item == null) { return null; } GameObject dropPrefab = item.m_dropPrefab; if (dropPrefab == null) { return null; } return dropPrefab.GetComponent<CustomSlotData>()?.slotName; } private static Dictionary<string, ItemData> GetCustomSlots(Humanoid humanoid) { if (!((Object)(object)humanoid != (Object)null) || !customSlotItemData.ContainsKey(humanoid)) { return null; } return customSlotItemData[humanoid]; } public static bool DoesSlotExist(Humanoid humanoid, string slotName) { return GetCustomSlots(humanoid)?.ContainsKey(slotName) ?? false; } public static bool IsSlotOccupied(Humanoid humanoid, string slotName) { return GetSlotItem(humanoid, slotName) != null; } public static ItemData GetSlotItem(Humanoid humanoid, string slotName) { Dictionary<string, ItemData> dictionary = ((slotName != null) ? GetCustomSlots(humanoid) : null); if (dictionary == null || !dictionary.ContainsKey(slotName)) { return null; } return dictionary[slotName]; } public static void SetSlotItem(Humanoid humanoid, string slotName, ItemData item) { if (!((Object)(object)humanoid == (Object)null) && slotName != null) { customSlotItemData[humanoid][slotName] = item; } } public static IEnumerable<ItemData> AllSlotItems(Humanoid humanoid) { if ((Object)(object)humanoid == (Object)null || !customSlotItemData.ContainsKey(humanoid)) { return Enumerable.Empty<ItemData>(); } return customSlotItemData[humanoid].Values.Where((ItemData x) => x != null).ToList(); } public static void ApplyCustomSlotItem(GameObject gameObject, string slotName) { //IL_00ce: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gameObject == (Object)null) { throw new ArgumentNullException("gameObject"); } if (slotName == null) { throw new ArgumentNullException("slotName"); } CustomSlotData component = gameObject.GetComponent<CustomSlotData>(); if ((Object)(object)component != (Object)null) { if (component.slotName != slotName) { throw new InvalidOperationException("GameObject \"" + ((Object)gameObject).name + "\" already has component CustomSlotData! (\"" + component.slotName + "\" != \"" + slotName + "\")"); } } else { if ((Object)(object)gameObject.GetComponent<ItemDrop>() == (Object)null) { throw new InvalidOperationException("GameObject \"" + ((Object)gameObject).name + "\" does not have component ItemDrop!"); } gameObject.AddComponent<CustomSlotData>().slotName = slotName; gameObject.GetComponent<ItemDrop>().m_itemData.m_shared.m_itemType = (ItemType)0; } } }