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 ExtraSlotsCustomSlots v1.0.23
ExtraSlotsCustomSlots.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using 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 System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using ConditionalConfigSync; using ExtraSlots; using ExtraSlotsCustomSlots.AdventureBackpacksCustomSlot; using ExtraSlotsCustomSlots.JudesEquipmentBackpacksCustomSlot; using ExtraSlotsCustomSlots.UserDefinedCustomSlots; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ExtraSlotsCustomSlots")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ExtraSlotsCustomSlots")] [assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("ee3d2a93-2e64-4701-bfd2-efd5a55cfe52")] [assembly: AssemblyFileVersion("1.0.23")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.23.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace ExtraSlotsCustomSlots { public class VikingsSummoner : CustomSlot { [HarmonyPatch] public static class VikingsSummoner_MagicSlot_AddCustomSlot_PreventCustomSlotAddition { public static MethodBase target; public static bool Prepare(MethodBase original) { if (!Chainloader.PluginInfos.TryGetValue("radamanto.Vikings_Summoner", out var value)) { return false; } if ((object)target == null) { target = AccessTools.Method(Assembly.GetAssembly(((object)value.Instance).GetType()).GetType("Vikings_Summoner.TomeCustomSlotManager"), "IsSlotSystemEnabled", (Type[])null, (Type[])null); } if (target == null) { return false; } if (original == null) { ExtraSlotsCustomSlots.LogInfo("Vikings_Summoner.TomeCustomSlotManager:IsSlotSystemEnabled method is patched to enable internal custom slot logic"); } return true; } public static MethodBase TargetMethod() { return target; } public static void Postfix(ref bool __result) { __result = ExtraSlotsCustomSlots.vikingsSummonerSlotEnabled.Value; } } public const string ID = "VikingsSummoner"; public const string pluginID = "radamanto.Vikings_Summoner"; public VikingsSummoner() { CustomSlot.slots.Add(this); GUID = "radamanto.Vikings_Summoner"; slotID = "VikingsSummoner"; if (!base.PluginInstalled) { return; } Assembly assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["radamanto.Vikings_Summoner"].Instance).GetType()); MethodInfo isValid = AccessTools.Method(assembly.GetType("Vikings_Summoner.TomeCustomSlotManager"), "IsTomeItem", (Type[])null, (Type[])null); if (isValid == null) { ExtraSlotsCustomSlots.LogWarning("Vikings_Summoner mod is loaded but Vikings_Summoner.TomeCustomSlotManager:IsTomeItem is not found"); return; } itemIsValid = (ItemData item) => item != null && (bool)isValid.Invoke(null, new object[1] { item }); getName = () => ExtraSlotsCustomSlots.vikingsSummonerSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.vikingsSummonerSlotGlobalKey.Value, ExtraSlotsCustomSlots.vikingsSummonerSlotItemDiscovered.Value); initialized = true; } } public class JudesEquipmentBackpackSlot : CustomSlot { public const string ID = "JudesEquipmentBackpack"; public const string pluginID = "GoldenJude_JudesEquipment"; public static Assembly assembly; public static bool IsLoaded => Chainloader.PluginInfos.ContainsKey("GoldenJude_JudesEquipment"); public static bool IsActive => IsLoaded && ExtraSlotsCustomSlots.judesEquipmentBackpackSlotEnabled.Value; public JudesEquipmentBackpackSlot() { CustomSlot.slots.Add(this); GUID = "GoldenJude_JudesEquipment"; slotID = "JudesEquipmentBackpack"; if (base.PluginInstalled) { assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["GoldenJude_JudesEquipment"].Instance).GetType()); itemIsValid = (ItemData item) => item != null && (Object)(object)item.m_dropPrefab != (Object)null && (((Object)item.m_dropPrefab).name == "BackpackSimple" || ((Object)item.m_dropPrefab).name == "BackpackHeavy"); getName = () => ExtraSlotsCustomSlots.judesEquipmentBackpackSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.judesEquipmentBackpackSlotGlobalKey.Value, ExtraSlotsCustomSlots.judesEquipmentBackpackSlotItemDiscovered.Value); initialized = true; global::ExtraSlotsCustomSlots.JudesEquipmentBackpacksCustomSlot.CustomItemType.InitBackpackFunc(itemIsValid); } } } public class AdventureBackpacksSlot : CustomSlot { public const string ID = "AdventureBackpacks"; public const string pluginID = "vapok.mods.adventurebackpacks"; public static Assembly assembly; public static bool IsLoaded => Chainloader.PluginInfos.ContainsKey("vapok.mods.adventurebackpacks"); public static bool IsActive => IsLoaded && ExtraSlotsCustomSlots.adventureBackpackSlotEnabled.Value; public AdventureBackpacksSlot() { CustomSlot.slots.Add(this); GUID = "vapok.mods.adventurebackpacks"; slotID = "AdventureBackpacks"; if (!base.PluginInstalled) { return; } assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["vapok.mods.adventurebackpacks"].Instance).GetType()); MethodInfo isValid = AccessTools.Method(assembly.GetType("AdventureBackpacks.API.ABAPI"), "IsBackpack", (Type[])null, (Type[])null); if (isValid == null) { ExtraSlotsCustomSlots.LogWarning("AdventureBackpacks mod is loaded but AdventureBackpacks.API.ABAPI:IsBackpack is not found"); return; } itemIsValid = delegate(ItemData item) { int result; if (item != null) { MethodInfo methodInfo = isValid; object[] parameters = (object[])(object)new ItemData[1] { item }; result = (((bool)methodInfo.Invoke(null, parameters)) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }; getName = () => ExtraSlotsCustomSlots.adventureBackpackSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.adventureBackpackSlotGlobalKey.Value, ExtraSlotsCustomSlots.adventureBackpackSlotItemDiscovered.Value); initialized = true; global::ExtraSlotsCustomSlots.AdventureBackpacksCustomSlot.CustomItemType.InitBackpackFunc(itemIsValid); AdventureBackpacksPatches.UnpatchUnequip(); } } public static class AdventureBackpacksPatches { [HarmonyPatch] public static class AdventureBackpacks_PlayerExtensions_CustomSlotItem { public static List<MethodBase> targets; public static List<MethodBase> GetTargets() { List<MethodBase> list = new List<MethodBase>(); if (AdventureBackpacksSlot.assembly == null) { return list; } MethodInfo methodInfo = AccessTools.Method(AdventureBackpacksSlot.assembly.GetType("AdventureBackpacks.Extensions.PlayerExtensions"), "IsBackpackEquipped", (Type[])null, (Type[])null); if ((object)methodInfo != null) { ExtraSlotsCustomSlots.LogInfo("AdventureBackpacks.Extensions.PlayerExtensions:IsBackpackEquipped method is patched to make it work with custom slot"); list.Add(methodInfo); } else { ExtraSlotsCustomSlots.LogWarning("AdventureBackpacks.Extensions.PlayerExtensions:IsBackpackEquipped method was not found"); } MethodInfo methodInfo2 = AccessTools.Method(AdventureBackpacksSlot.assembly.GetType("AdventureBackpacks.Extensions.PlayerExtensions"), "IsThisBackpackEquipped", (Type[])null, (Type[])null); if ((object)methodInfo2 != null) { ExtraSlotsCustomSlots.LogInfo("AdventureBackpacks.Extensions.PlayerExtensions:IsThisBackpackEquipped method is patched to make it work with custom slot"); list.Add(methodInfo2); } else { ExtraSlotsCustomSlots.LogWarning("AdventureBackpacks.Extensions.PlayerExtensions:IsThisBackpackEquipped method was not found"); } MethodInfo methodInfo3 = AccessTools.Method(AdventureBackpacksSlot.assembly.GetType("AdventureBackpacks.Extensions.PlayerExtensions"), "GetEquippedBackpack", (Type[])null, (Type[])null); if ((object)methodInfo3 != null) { ExtraSlotsCustomSlots.LogInfo("AdventureBackpacks.Extensions.PlayerExtensions:GetEquippedBackpack method is patched to make it work with custom slot"); list.Add(methodInfo3); } else { ExtraSlotsCustomSlots.LogWarning("AdventureBackpacks.Extensions.PlayerExtensions:GetEquippedBackpack method was not found"); } return list; } public static bool Prepare() { return AdventureBackpacksSlot.IsLoaded && (targets ?? (targets = GetTargets())).Count > 0; } private static IEnumerable<MethodBase> TargetMethods() { return targets; } public static void Prefix(Player player, ref ItemData __state) { if (AdventureBackpacksSlot.IsActive) { __state = ((Humanoid)player).m_shoulderItem; ((Humanoid)player).m_shoulderItem = ((Humanoid)(object)player).GetAdventureBackpack(); } } public static void Postfix(Player player, ItemData __state) { if (AdventureBackpacksSlot.IsActive) { ((Humanoid)player).m_shoulderItem = __state; } } } [HarmonyPatch(typeof(Humanoid), "UnequipItem")] public static class Humanoid_UnequipItem_CustomItemType_FirstPrefix { public static bool Prepare() { return AdventureBackpacksSlot.IsLoaded; } private static void Prefix(Humanoid __instance, ItemData item) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (AdventureBackpacksSlot.IsActive && !(prefixHumanoidUnequip == null) && item != null && !((Object)(object)Player.m_localPlayer != (Object)(object)__instance)) { Scene activeScene = SceneManager.GetActiveScene(); if (!((Scene)(ref activeScene)).name.Equals("start") && global::ExtraSlotsCustomSlots.AdventureBackpacksCustomSlot.CustomItemType.IsBackpack(item) && item == __instance.GetAdventureBackpack() && item != __instance.m_shoulderItem) { ItemData shoulderItem = __instance.m_shoulderItem; __instance.m_shoulderItem = item; prefixHumanoidUnequip.Invoke(null, new object[1] { item }); __instance.m_shoulderItem = shoulderItem; ExtraSlotsCustomSlots.LogInfo($"Shoulder item {shoulderItem}"); ExtraSlotsCustomSlots.LogInfo("swapped with"); ExtraSlotsCustomSlots.LogInfo($"{item}"); } } } } public static MethodInfo prefixHumanoidUnequip; public static void UnpatchUnequip() { MethodInfo methodInfo = AccessTools.Method(typeof(Humanoid), "UnequipItem", (Type[])null, (Type[])null); prefixHumanoidUnequip = AccessTools.Method(AdventureBackpacksSlot.assembly.GetType("AdventureBackpacks.Patches.HumanoidPatches+HumanoidUnequipItemPatch"), "Prefix", (Type[])null, (Type[])null); if (methodInfo != null && prefixHumanoidUnequip != null) { ExtraSlotsCustomSlots.instance.harmony.Unpatch((MethodBase)methodInfo, prefixHumanoidUnequip); ExtraSlotsCustomSlots.LogInfo("AdventureBackpacks.Patches.HumanoidPatches+HumanoidUnequipItemPatch:Prefix was unpatched and will be called directly."); return; } if (methodInfo == null) { ExtraSlotsCustomSlots.LogWarning("Humanoid:UnequipItem was not found."); } if (prefixHumanoidUnequip == null) { ExtraSlotsCustomSlots.LogWarning("AdventureBackpacks.Patches.HumanoidPatches+HumanoidUnequipItemPatch:Prefix was not found."); } } } public class HipLanternSlot : CustomSlot { public const string ID = "HipLantern"; public const string pluginID = "shudnal.HipLantern"; public HipLanternSlot() { CustomSlot.slots.Add(this); GUID = "shudnal.HipLantern"; slotID = "HipLantern"; if (!base.PluginInstalled) { return; } Assembly assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["shudnal.HipLantern"].Instance).GetType()); MethodInfo isValid = AccessTools.Method(assembly.GetType("HipLantern.LanternItem"), "IsLanternItem", new Type[1] { typeof(ItemData) }, (Type[])null); if (isValid == null) { ExtraSlotsCustomSlots.LogWarning("HipLantern mod is loaded but HipLantern.LanternItem:IsLanternItem is not found"); return; } itemIsValid = delegate(ItemData item) { int result; if (item != null) { MethodInfo methodInfo = isValid; object[] parameters = (object[])(object)new ItemData[1] { item }; result = (((bool)methodInfo.Invoke(null, parameters)) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }; getName = () => ExtraSlotsCustomSlots.hipLanternSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.hipLanternSlotGlobalKey.Value, ExtraSlotsCustomSlots.hipLanternSlotItemDiscovered.Value); initialized = true; } } public class CircletExtendedSlot : CustomSlot { public const string ID = "CircletExtended"; public const string pluginID = "shudnal.CircletExtended"; public CircletExtendedSlot() { CustomSlot.slots.Add(this); GUID = "shudnal.CircletExtended"; slotID = "CircletExtended"; if (!base.PluginInstalled) { return; } Assembly assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["shudnal.CircletExtended"].Instance).GetType()); MethodInfo isValid = AccessTools.Method(assembly.GetType("CircletExtended.CircletItem"), "IsCircletItem", new Type[1] { typeof(ItemData) }, (Type[])null); if (isValid == null) { ExtraSlotsCustomSlots.LogWarning("CircletExtended mod is loaded but CircletExtended.CircletItem:IsCircletItem is not found"); return; } MethodInfo isCircletSlotKnown = AccessTools.Method(assembly.GetType("CircletExtended.CircletItem"), "IsCircletSlotKnown", (Type[])null, (Type[])null); itemIsValid = delegate(ItemData item) { int result; if (item != null) { MethodInfo methodInfo = isValid; object[] parameters = (object[])(object)new ItemData[1] { item }; result = (((bool)methodInfo.Invoke(null, parameters)) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }; getName = () => ExtraSlotsCustomSlots.circletExtendedSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.circletExtendedSlotGlobalKey.Value, ExtraSlotsCustomSlots.circletExtendedSlotItemDiscovered.Value) && (isCircletSlotKnown == null || (bool)isCircletSlotKnown.Invoke(null, null)); initialized = true; } } public class BowsBeforeHoesSlot : CustomSlot { public const string ID = "BowsBeforeHoes"; public const string pluginID = "Azumatt.BowsBeforeHoes"; public static bool _isActive; private static Func<ItemData, bool> _isQuiver; public static bool IsActive => _isActive && ExtraSlotsCustomSlots.bbhQuiverSlotEnabled.Value; public static bool IsQuiver(ItemData item) { return InventoryCompatibility.IsRuntimeItem(item) && _isQuiver != null && _isQuiver(item); } public BowsBeforeHoesSlot() { CustomSlot.slots.Add(this); GUID = "Azumatt.BowsBeforeHoes"; slotID = "BowsBeforeHoes"; if (!base.PluginInstalled) { return; } Assembly assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["Azumatt.BowsBeforeHoes"].Instance).GetType()); MethodInfo isValid = AccessTools.Method(assembly.GetType("BowsBeforeHoes.Util.Functions"), "IsQuiverSlot", (Type[])null, (Type[])null); if (isValid == null) { ExtraSlotsCustomSlots.LogWarning("BowsBeforeHoes mod is loaded but BowsBeforeHoes.Util.Functions:IsQuiverSlot is not found"); return; } itemIsValid = delegate(ItemData item) { int result; if (item != null) { MethodInfo methodInfo = isValid; object[] parameters = (object[])(object)new ItemData[1] { item }; result = (((bool)methodInfo.Invoke(null, parameters)) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }; getName = () => ExtraSlotsCustomSlots.bbhQuiverSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.bbhQuiverSlotGlobalKey.Value, ExtraSlotsCustomSlots.bbhQuiverSlotItemDiscovered.Value); initialized = true; _isActive = true; _isQuiver = itemIsValid; } } public static class BowsBeforeHoesCompat { [HarmonyPatch(typeof(Player), "AddKnownItem")] public static class Player_AddKnownItem_BBHQuiverType { private static void Prefix(ItemData item) { if (BowsBeforeHoesSlot.IsActive && BowsBeforeHoesSlot.IsQuiver(item)) { PatchBackpackItemData(item); } } } [HarmonyPatch(typeof(Player), "OnSpawned")] public class Player_OnSpawned_BBHQuiverType { public static void Postfix(Player __instance) { if (BowsBeforeHoesSlot.IsActive && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { PatchInventory(((Humanoid)__instance).GetInventory()); } } } [HarmonyPatch] public class Inventory_Load_BBHQuiverType { private static IEnumerable<MethodBase> TargetMethods() { return InventoryCompatibility.GetLoadMethods(); } public static void Postfix(Inventory __instance) { if (BowsBeforeHoesSlot.IsActive) { PatchInventory(__instance); } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] public static class ObjectDB_Awake_ChangeBackpackItemType { [HarmonyPriority(0)] private static void Postfix(ObjectDB __instance) { if (BowsBeforeHoesSlot.IsActive && __instance.m_items.Count != 0 && !((Object)(object)__instance.GetItemPrefab("Wood") == (Object)null)) { UpdateBackpacksItemType(); } } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] public static class ObjectDB_CopyOtherDB_AddPrefab { [HarmonyPriority(0)] private static void Postfix(ObjectDB __instance) { if (BowsBeforeHoesSlot.IsActive && __instance.m_items.Count != 0 && !((Object)(object)__instance.GetItemPrefab("Wood") == (Object)null)) { UpdateBackpacksItemType(); } } } public static ItemType GetItemType() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!BowsBeforeHoesSlot.IsActive) { return (ItemType)17; } return (ItemType)16; } public static void PatchBackpackItemData(ItemData itemData) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (InventoryCompatibility.IsRuntimeItem(itemData)) { itemData.m_shared.m_itemType = GetItemType(); } } public static void PatchInventory(Inventory inventory, bool force = false) { if ((!BowsBeforeHoesSlot.IsActive && !force) || !InventoryCompatibility.IsRuntimeInventory(inventory)) { return; } foreach (ItemData item in from item in inventory.GetAllItems() where BowsBeforeHoesSlot.IsQuiver(item) select item) { PatchBackpackItemData(item); } } public static void PatchBackpackItemOnConfigChange() { UpdateBackpacksItemType(force: true); Player localPlayer = Player.m_localPlayer; PatchInventory((localPlayer != null) ? ((Humanoid)localPlayer).GetInventory() : null, force: true); } public static void UpdateBackpacksItemType(bool force = false) { if ((!BowsBeforeHoesSlot.IsActive && !force) || !Object.op_Implicit((Object)(object)ObjectDB.instance)) { return; } foreach (GameObject item in ObjectDB.instance.m_items) { if ((Object)(object)item != (Object)null) { ItemData val = item.GetComponent<ItemDrop>()?.m_itemData; if (val != null && BowsBeforeHoesSlot.IsQuiver(val)) { PatchBackpackItemData(val); } } } } } public class JewelcraftingNeckSlot : CustomSlot { public const string ID = "JewelcraftingNeck"; public const string pluginID = "org.bepinex.plugins.jewelcrafting"; public JewelcraftingNeckSlot() { CustomSlot.slots.Add(this); GUID = "org.bepinex.plugins.jewelcrafting"; slotID = "JewelcraftingNeck"; if (!base.PluginInstalled) { return; } Assembly assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["org.bepinex.plugins.jewelcrafting"].Instance).GetType()); MethodInfo isValid = AccessTools.Method(assembly.GetType("Jewelcrafting.Visual"), "IsNeckItem", (Type[])null, (Type[])null); if (isValid == null) { ExtraSlotsCustomSlots.LogWarning("Jewelcrafting mod is loaded but Jewelcrafting.Visual:IsNeckItem is not found"); return; } itemIsValid = delegate(ItemData item) { int result; if (item != null) { MethodInfo methodInfo = isValid; object[] parameters = (object[])(object)new ItemData[1] { item }; result = (((bool)methodInfo.Invoke(null, parameters)) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }; getName = () => ExtraSlotsCustomSlots.jewelcraftingNeckSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.jewelcraftingNeckSlotGlobalKey.Value, ExtraSlotsCustomSlots.jewelcraftingNeckSlotItemDiscovered.Value); initialized = true; } } public class JewelcraftingRingSlot : CustomSlot { public const string ID = "JewelcraftingRing"; public const string pluginID = "org.bepinex.plugins.jewelcrafting"; public JewelcraftingRingSlot() { CustomSlot.slots.Add(this); GUID = "org.bepinex.plugins.jewelcrafting"; slotID = "JewelcraftingRing"; if (!base.PluginInstalled) { return; } Assembly assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["org.bepinex.plugins.jewelcrafting"].Instance).GetType()); MethodInfo isValid = AccessTools.Method(assembly.GetType("Jewelcrafting.Visual"), "IsFingerItem", (Type[])null, (Type[])null); if (isValid == null) { ExtraSlotsCustomSlots.LogWarning("Jewelcrafting mod is loaded but Jewelcrafting.Visual:IsFingerItem is not found"); return; } itemIsValid = delegate(ItemData item) { int result; if (item != null) { MethodInfo methodInfo = isValid; object[] parameters = (object[])(object)new ItemData[1] { item }; result = (((bool)methodInfo.Invoke(null, parameters)) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }; getName = () => ExtraSlotsCustomSlots.jewelcraftingRingSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.jewelcraftingRingSlotGlobalKey.Value, ExtraSlotsCustomSlots.jewelcraftingRingSlotItemDiscovered.Value); initialized = true; } } public class BackpacksSlot : CustomSlot { public const string ID = "Backpacks"; public const string pluginID = "org.bepinex.plugins.backpacks"; public BackpacksSlot() { CustomSlot.slots.Add(this); GUID = "org.bepinex.plugins.backpacks"; slotID = "Backpacks"; if (!base.PluginInstalled) { return; } Assembly assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["org.bepinex.plugins.backpacks"].Instance).GetType()); MethodInfo isValid = AccessTools.Method(assembly.GetType("Backpacks.Backpacks"), "validateBackpack", (Type[])null, (Type[])null); if (isValid == null) { ExtraSlotsCustomSlots.LogWarning("Backpacks mod is loaded but Backpacks.Backpacks:validateBackpack is not found"); return; } itemIsValid = delegate(ItemData item) { int result; if (item != null) { MethodInfo methodInfo = isValid; object[] parameters = (object[])(object)new ItemData[1] { item }; result = (((bool)methodInfo.Invoke(null, parameters)) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }; getName = () => ExtraSlotsCustomSlots.backpacksSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.backpacksSlotGlobalKey.Value, ExtraSlotsCustomSlots.backpacksSlotItemDiscovered.Value); initialized = true; } } internal class CustomConfigs { internal class ConfigurationManagerAttributes { [UsedImplicitly] public Action<ConfigEntryBase>? CustomDrawer; } internal static object? configManager; internal static Type? configManagerStyles; internal static GUIStyle GetStyle(GUIStyle other) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown if (configManagerStyles == null) { return other; } FieldInfo fieldInfo = AccessTools.Field(configManagerStyles, "fontSize"); if (fieldInfo == null) { return other; } return new GUIStyle(other) { fontSize = (int)fieldInfo.GetValue(configManagerStyles) }; } internal static void Awake() { Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "ConfigurationManager"); Type type = assembly?.GetType("ConfigurationManager.ConfigurationManager"); configManager = ((type == null) ? null : Chainloader.ManagerObject.GetComponent(type)); configManagerStyles = assembly?.GetType("ConfigurationManager.ConfigurationManagerStyles") ?? assembly?.GetType("ConfigurationManager.Utilities.ImguiUtils"); } internal static Action<ConfigEntryBase> DrawSeparatedStrings(string splitString) { return delegate(ConfigEntryBase cfg) { //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Expected O, but got Unknown bool valueOrDefault = cfg.Description.Tags.Select((object a) => (a.GetType().Name == "ConfigurationManagerAttributes") ? ((bool?)a.GetType().GetField("ReadOnly")?.GetValue(a)) : ((bool?)null)).FirstOrDefault((bool? v) => v.HasValue) == true; bool flag = false; GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); List<string> list = new List<string>(); List<string> list2 = ((string)cfg.BoxedValue).Split(new string[1] { splitString }, StringSplitOptions.None).ToList(); for (int num = 0; num < list2.Count; num++) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); string text = list2[num]; string text2 = GUILayout.TextField(text, GetStyle(GUI.skin.textField), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (text2 != text && !valueOrDefault) { flag = true; } if (GUILayout.Button("x", new GUIStyle(GetStyle(GUI.skin.button)) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>()) && !valueOrDefault) { flag = true; } else { list.Add(text2); } if (GUILayout.Button("+", new GUIStyle(GetStyle(GUI.skin.button)) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>()) && !valueOrDefault) { flag = true; list.Add(""); } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (flag) { cfg.BoxedValue = string.Join(splitString, list); } }; } internal static Action<ConfigEntryBase> DrawOrderedFixedStrings(string splitString) { return delegate(ConfigEntryBase cfg) { //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_00ff: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Expected O, but got Unknown bool valueOrDefault = cfg.Description.Tags.Select((object a) => (a.GetType().Name == "ConfigurationManagerAttributes") ? ((bool?)a.GetType().GetField("ReadOnly")?.GetValue(a)) : ((bool?)null)).FirstOrDefault((bool? v) => v.HasValue) == true; bool flag = false; GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); string[] array = ((string)cfg.BoxedValue).Split(new string[1] { splitString }, StringSplitOptions.None).ToArray(); for (int num = 0; num < array.Length; num++) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); string text = array[num]; GUILayout.Label(text, GetStyle(GUI.skin.textField), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (GUILayout.Button("ʌ", new GUIStyle(GetStyle(GUI.skin.button)) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>()) && !valueOrDefault && (flag = num > 0)) { ref string reference = ref array[num]; ref string reference2 = ref array[num - 1]; string text2 = array[num - 1]; string text3 = array[num]; reference = text2; reference2 = text3; } if (GUILayout.Button("v", new GUIStyle(GetStyle(GUI.skin.button)) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>()) && !valueOrDefault && (flag = num < array.Length - 1)) { ref string reference = ref array[num]; ref string reference3 = ref array[num + 1]; string text3 = array[num + 1]; string text2 = array[num]; reference = text3; reference3 = text2; } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (flag) { cfg.BoxedValue = string.Join(splitString, array); } }; } } public class CustomSlot { public const string slotPrefix = "ESCS"; public string GUID; public bool initialized; public string slotID; public Func<ItemData, bool> itemIsValid; public Func<string> getName; public Func<bool> isActive; public static readonly List<CustomSlot> slots = new List<CustomSlot>(); public static readonly string VanillaOrder = string.Join(",", GetVanillaOrder()); public bool PluginInstalled => Chainloader.PluginInfos.ContainsKey(GUID); private string GetName() { return getName?.Invoke() ?? ""; } private bool ItemIsValid(ItemData item) { return InventoryCompatibility.IsRuntimeItem(item) && (itemIsValid?.Invoke(item) ?? false); } private bool IsActive() { return initialized && (isActive?.Invoke() ?? true); } public bool AddSlot() { return initialized && API.AddSlot(GetSlotID(slotID), (Func<string>)GetName, (Func<ItemData, bool>)ItemIsValid, (Func<bool>)IsActive); } internal bool AddSlotAfter(CustomSlot precedingSlot) { return (precedingSlot == null) ? AddSlot() : (initialized && API.AddSlotAfter(GetSlotID(slotID), (Func<string>)GetName, (Func<ItemData, bool>)ItemIsValid, (Func<bool>)IsActive, new string[1] { GetSlotID(precedingSlot.slotID) })); } internal void UpdateDefinition(CustomSlot definition) { GUID = definition.GUID; initialized = definition.initialized; itemIsValid = definition.itemIsValid; getName = definition.getName; isActive = definition.isActive; } public bool RemoveSlot() { return initialized && (API.RemoveSlot(GetSlotID(slotID)) || API.RemoveSlot(slotID)); } public static string GetSlotID(string slotID) { return "ESCS" + slotID.ToString(); } public override string ToString() { return initialized ? slotID.ToString() : (GUID + " (inactive)"); } public static List<string> GetVanillaOrder() { List<string> list = new List<string> { "Backpacks", "AdventureBackpacks", "JudesEquipmentBackpack", "RustyBagsBag", "RustyBagsQuiver", "CircletExtended", "JewelcraftingNeck", "MagicPluginEarring", "JewelcraftingRing", "MagicPluginTome", "VikingsSummoner", "BowsBeforeHoes", "HipLantern" }; for (int i = 0; i < 8; i++) { list.Add(UserDefinedSlot.GetSlotID(i)); } return list; } public static bool IsSlotActive(string globalKey, string itemDiscovered) { bool flag = !Utility.IsNullOrWhiteSpace(globalKey); bool flag2 = !Utility.IsNullOrWhiteSpace(itemDiscovered); if (!flag && !flag2) { return true; } if (flag && flag2) { return API.IsAnyGlobalKeyActive(globalKey) || API.IsAnyMaterialDiscovered(itemDiscovered); } return flag ? API.IsAnyGlobalKeyActive(globalKey) : API.IsAnyMaterialDiscovered(itemDiscovered); } } [BepInDependency("shudnal.ExtraSlots", "1.2.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("shudnal.ExtraSlotsCustomSlots", "Extra Slots Custom Slots", "1.0.23")] public class ExtraSlotsCustomSlots : BaseUnityPlugin { public const string pluginID = "shudnal.ExtraSlotsCustomSlots"; public const string pluginName = "Extra Slots Custom Slots"; public const string pluginVersion = "1.0.23"; internal readonly Harmony harmony = new Harmony("shudnal.ExtraSlotsCustomSlots"); internal static readonly ConfigSync configSync = new ConfigSync("shudnal.ExtraSlotsCustomSlots") { DisplayName = "Extra Slots Custom Slots", CurrentVersion = "1.0.23", MinimumRequiredVersion = "1.0.23", ModRequired = false }; internal static ExtraSlotsCustomSlots instance; public static ConfigEntry<bool> configLocked; public static ConfigEntry<bool> loggingEnabled; public static ConfigEntry<string> slotsOrder; private static bool updatingSlots; private static bool slotUpdatePending; public static ConfigEntry<bool> adventureBackpackSlotEnabled; public static ConfigEntry<string> adventureBackpackSlotName; public static ConfigEntry<string> adventureBackpackSlotGlobalKey; public static ConfigEntry<string> adventureBackpackSlotItemDiscovered; public static ConfigEntry<bool> adventureBackpackItemIsVisible; public static ConfigEntry<bool> backpacksSlotEnabled; public static ConfigEntry<string> backpacksSlotName; public static ConfigEntry<string> backpacksSlotGlobalKey; public static ConfigEntry<string> backpacksSlotItemDiscovered; public static ConfigEntry<bool> bbhQuiverSlotEnabled; public static ConfigEntry<string> bbhQuiverSlotName; public static ConfigEntry<string> bbhQuiverSlotGlobalKey; public static ConfigEntry<string> bbhQuiverSlotItemDiscovered; public static ConfigEntry<bool> circletExtendedSlotEnabled; public static ConfigEntry<string> circletExtendedSlotName; public static ConfigEntry<string> circletExtendedSlotGlobalKey; public static ConfigEntry<string> circletExtendedSlotItemDiscovered; public static ConfigEntry<bool> hipLanternSlotEnabled; public static ConfigEntry<string> hipLanternSlotName; public static ConfigEntry<string> hipLanternSlotGlobalKey; public static ConfigEntry<string> hipLanternSlotItemDiscovered; public static ConfigEntry<bool> jewelcraftingNeckSlotEnabled; public static ConfigEntry<string> jewelcraftingNeckSlotName; public static ConfigEntry<string> jewelcraftingNeckSlotGlobalKey; public static ConfigEntry<string> jewelcraftingNeckSlotItemDiscovered; public static ConfigEntry<bool> jewelcraftingRingSlotEnabled; public static ConfigEntry<string> jewelcraftingRingSlotName; public static ConfigEntry<string> jewelcraftingRingSlotGlobalKey; public static ConfigEntry<string> jewelcraftingRingSlotItemDiscovered; public static ConfigEntry<bool> magicPluginTomeSlotEnabled; public static ConfigEntry<string> magicPluginTomeSlotName; public static ConfigEntry<string> magicPluginTomeSlotGlobalKey; public static ConfigEntry<string> magicPluginTomeSlotItemDiscovered; public static ConfigEntry<bool> magicPluginEarringSlotEnabled; public static ConfigEntry<string> magicPluginEarringSlotName; public static ConfigEntry<string> magicPluginEarringSlotGlobalKey; public static ConfigEntry<string> magicPluginEarringSlotItemDiscovered; public static ConfigEntry<bool> judesEquipmentBackpackSlotEnabled; public static ConfigEntry<string> judesEquipmentBackpackSlotName; public static ConfigEntry<string> judesEquipmentBackpackSlotGlobalKey; public static ConfigEntry<string> judesEquipmentBackpackSlotItemDiscovered; public static ConfigEntry<bool> judesEquipmentBackpackItemIsVisible; public static ConfigEntry<bool> rustyBagsSlotEnabled; public static ConfigEntry<string> rustyBagsSlotName; public static ConfigEntry<string> rustyBagsSlotGlobalKey; public static ConfigEntry<string> rustyBagsSlotItemDiscovered; public static ConfigEntry<bool> rustyBagsSlotCombineWithQuiver; public static ConfigEntry<bool> rustyBagsQuiverSlotEnabled; public static ConfigEntry<string> rustyBagsQuiverSlotName; public static ConfigEntry<string> rustyBagsQuiverSlotGlobalKey; public static ConfigEntry<string> rustyBagsQuiverSlotItemDiscovered; public static ConfigEntry<bool> vikingsSummonerSlotEnabled; public static ConfigEntry<string> vikingsSummonerSlotName; public static ConfigEntry<string> vikingsSummonerSlotGlobalKey; public static ConfigEntry<string> vikingsSummonerSlotItemDiscovered; private void Awake() { instance = this; ConfigInit(); ((ConditionalConfigSync)configSync).AddLockingConfigEntry<bool>(configLocked); EpicLootCompatibility.Prepare(); UpdateSlots(); harmony.PatchAll(); EpicLootCompatibility.Initialize(); } private void OnDestroy() { EpicLootCompatibility.Shutdown(); ((BaseUnityPlugin)this).Config.Save(); instance = null; Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } public void ConfigInit() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown configLocked = serverConfig("General", "Lock Configuration", defaultValue: true, "Configuration is locked and can be changed by server admins only."); loggingEnabled = config("General", "Logging enabled", defaultValue: false, "Enable logging. [Client controlled by default]", synchronizedSetting: false); slotsOrder = config("General", "Slots order", CustomSlot.VanillaOrder, new ConfigDescription("Comma-separated slot ID order of custom slots", (AcceptableValueBase)null, new object[1] { new CustomConfigs.ConfigurationManagerAttributes { CustomDrawer = CustomConfigs.DrawOrderedFixedStrings(",") } })); slotsOrder.SettingChanged += delegate { UpdateSlots(); }; adventureBackpackSlotEnabled = config("Mod - Adventure Backpacks", "Enabled", defaultValue: true, "Enable adventure backpack slot. Restart the game after change to avoid potential issues."); adventureBackpackSlotName = config("Mod - Adventure Backpacks", "Name", "Backpack", "Slot name. Use ExtraSlots translation files to add localized string."); adventureBackpackSlotGlobalKey = config("Mod - Adventure Backpacks", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); adventureBackpackSlotItemDiscovered = config("Mod - Adventure Backpacks", "Items discovered", "$vapok_mod_item_backpack_meadows,$vapok_mod_item_backpack_blackforest,$vapok_mod_item_backpack_swamp,$vapok_mod_item_backpack_mountains,$vapok_mod_item_backpack_plains,$vapok_mod_item_backpack_mistlands,$vapok_mod_item_rugged_backpack,$vapok_mod_item_arctic_backpack", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); adventureBackpackItemIsVisible = config("Mod - Adventure Backpacks", "Item is visible", defaultValue: true, "Make the equipped backpack visible on the player model."); adventureBackpackSlotEnabled.SettingChanged += delegate { AdventureBackpackItem.PatchBackpackItemOnConfigChange(); UpdateSlots(); }; adventureBackpackItemIsVisible.SettingChanged += delegate { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Humanoid)localPlayer).SetupEquipment(); } }; backpacksSlotEnabled = config("Mod - Backpacks", "Enabled", defaultValue: true, "Enable backpack slot"); backpacksSlotName = config("Mod - Backpacks", "Name", "$bp_backpack_slot_name", "Slot name"); backpacksSlotGlobalKey = config("Mod - Backpacks", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); backpacksSlotItemDiscovered = config("Mod - Backpacks", "Items discovered", "$item_explorer", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); backpacksSlotEnabled.SettingChanged += delegate { UpdateSlots(); }; bbhQuiverSlotEnabled = config("Mod - BowsBeforeHoes", "Enabled", defaultValue: true, "Enable quiver slot"); bbhQuiverSlotName = config("Mod - BowsBeforeHoes", "Name", "$bbh_slot_quiver", "Slot name"); bbhQuiverSlotGlobalKey = config("Mod - BowsBeforeHoes", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); bbhQuiverSlotItemDiscovered = config("Mod - BowsBeforeHoes", "Items discovered", "$item_quiver_blackforest,$item_quiver_seeker,$item_quiver_leather,$item_quiver_odinplus,$item_quiver_plainslox", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); bbhQuiverSlotEnabled.SettingChanged += delegate { UpdateSlots(); BowsBeforeHoesCompat.PatchBackpackItemOnConfigChange(); }; circletExtendedSlotEnabled = config("Mod - CircletExtended", "Enabled", defaultValue: true, "Enable circlet slot"); circletExtendedSlotName = config("Mod - CircletExtended", "Name", "Circlet", "Slot name. Use ExtraSlots translation files to add localized string."); circletExtendedSlotGlobalKey = config("Mod - CircletExtended", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); circletExtendedSlotItemDiscovered = config("Mod - CircletExtended", "Items discovered", "$item_helmet_dverger", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); circletExtendedSlotEnabled.SettingChanged += delegate { UpdateSlots(); }; hipLanternSlotEnabled = config("Mod - HipLantern", "Enabled", defaultValue: true, "Enable hip lantern slot"); hipLanternSlotName = config("Mod - HipLantern", "Name", "$hiplantern_slot", "Slot name. Use ExtraSlots translation files to add localized string."); hipLanternSlotGlobalKey = config("Mod - HipLantern", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); hipLanternSlotItemDiscovered = config("Mod - HipLantern", "Items discovered", "$item_hiplantern", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); hipLanternSlotEnabled.SettingChanged += delegate { UpdateSlots(); }; jewelcraftingNeckSlotEnabled = config("Mod - Jewelcrafting - Neck", "Enabled", defaultValue: true, "Enable neck slot"); jewelcraftingNeckSlotName = config("Mod - Jewelcrafting - Neck", "Name", "Neck", "Slot name. Use ExtraSlots translation files to add localized string."); jewelcraftingNeckSlotGlobalKey = config("Mod - Jewelcrafting - Neck", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); jewelcraftingNeckSlotItemDiscovered = config("Mod - Jewelcrafting - Neck", "Items discovered", "$jc_necklace_red,$jc_necklace_green,$jc_necklace_blue,$jc_necklace_yellow,$jc_necklace_purple,$jc_necklace_orange,$jc_necklace_dvergrnecklace,$jc_necklace_eitrnecklace,$jc_necklace_fireresistnecklace,$jc_necklace_frostresistnecklace,$jc_necklace_poisonresistnecklace,", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); jewelcraftingNeckSlotEnabled.SettingChanged += delegate { UpdateSlots(); }; jewelcraftingRingSlotEnabled = config("Mod - Jewelcrafting - Ring", "Enabled", defaultValue: true, "Enable Ring slot"); jewelcraftingRingSlotName = config("Mod - Jewelcrafting - Ring", "Name", "Finger", "Slot name. Use ExtraSlots translation files to add localized string."); jewelcraftingRingSlotGlobalKey = config("Mod - Jewelcrafting - Ring", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); jewelcraftingRingSlotItemDiscovered = config("Mod - Jewelcrafting - Ring", "Items discovered", "$jc_ring_purple,$jc_ring_green,$jc_ring_red,$jc_ring_blue,$jc_ring_black,$jc_ring_dvergrring,$jc_ring_eitrring,$jc_ring_fireresistring,$jc_ring_frostresistring,$jc_ring_poisonresistring", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); jewelcraftingRingSlotEnabled.SettingChanged += delegate { UpdateSlots(); }; magicPluginTomeSlotEnabled = config("Mod - Magic Plugin - Tome", "Enabled", defaultValue: true, "Enable tome slot"); magicPluginTomeSlotName = config("Mod - Magic Plugin - Tome", "Name", "$bmp_tomeslot", "Slot name"); magicPluginTomeSlotGlobalKey = config("Mod - Magic Plugin - Tome", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); magicPluginTomeSlotItemDiscovered = config("Mod - Magic Plugin - Tome", "Items discovered", "$bmp_advance_magicbook,$bmp_beginners_magicbook", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); magicPluginTomeSlotEnabled.SettingChanged += delegate { UpdateSlots(); }; magicPluginEarringSlotEnabled = config("Mod - Magic Plugin - Earring", "Enabled", defaultValue: true, "Enable earring slot"); magicPluginEarringSlotName = config("Mod - Magic Plugin - Earring", "Name", "$bmp_earringslot", "Slot name"); magicPluginEarringSlotGlobalKey = config("Mod - Magic Plugin - Earring", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); magicPluginEarringSlotItemDiscovered = config("Mod - Magic Plugin - Earring", "Items discovered", "$bmp_dvergr_earring,$bmp_fireresist_earring,$bmp_frostresist_earring,$bmp_poisonresist_earring,$bmp_eitr_earring", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); magicPluginEarringSlotEnabled.SettingChanged += delegate { UpdateSlots(); }; judesEquipmentBackpackSlotEnabled = config("Mod - Judes Equipment", "Enabled", defaultValue: true, "Enable Judes Equipment backpack slot. Restart the game after change to avoid potential issues."); judesEquipmentBackpackSlotName = config("Mod - Judes Equipment", "Name", "Backpack", "Slot name. Use ExtraSlots translation files to add localized string."); judesEquipmentBackpackSlotGlobalKey = config("Mod - Judes Equipment", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); judesEquipmentBackpackSlotItemDiscovered = config("Mod - Judes Equipment", "Items discovered", "$BackpackSimple,$BackpackHeavy", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); judesEquipmentBackpackItemIsVisible = config("Mod - Judes Equipment", "Item is visible", defaultValue: true, "Make the equipped backpack visible on the player model."); judesEquipmentBackpackSlotEnabled.SettingChanged += delegate { JudesEquipmentBackpackItem.PatchBackpackItemOnConfigChange(); UpdateSlots(); }; judesEquipmentBackpackItemIsVisible.SettingChanged += delegate { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Humanoid)localPlayer).SetupEquipment(); } }; rustyBagsSlotEnabled = config("Mod - Rusty Bags", "Enabled", defaultValue: true, "Enable Rusty Bags backpack slot."); rustyBagsSlotName = config("Mod - Rusty Bags", "Name", "Bag", "Slot name. Use ExtraSlots translation files to add localized string."); rustyBagsSlotGlobalKey = config("Mod - Rusty Bags", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); rustyBagsSlotItemDiscovered = config("Mod - Rusty Bags", "Items discovered", "LeatherBag_RS,BarrelBag_RS,MinerBag_RS,UnbjornBag_RS,DvergerBag_RS", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); rustyBagsSlotCombineWithQuiver = config("Mod - Rusty Bags", "Allow quivers", defaultValue: false, "By default quivers will not go into this slot. Enable to allow quivers. Do not forget to add quivers from quiver slot item list."); rustyBagsSlotEnabled.SettingChanged += delegate { UpdateSlots(); }; rustyBagsSlotCombineWithQuiver.SettingChanged += delegate { UpdateSlots(); }; rustyBagsQuiverSlotEnabled = config("Mod - Rusty Bags - Quiver", "Enabled", defaultValue: true, "Enable Rusty Bags backpack slot."); rustyBagsQuiverSlotName = config("Mod - Rusty Bags - Quiver", "Name", "Quiver", "Slot name. Use ExtraSlots translation files to add localized string."); rustyBagsQuiverSlotGlobalKey = config("Mod - Rusty Bags - Quiver", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); rustyBagsQuiverSlotItemDiscovered = config("Mod - Rusty Bags - Quiver", "Items discovered", "Quiver_RS,MountainQuiver_RS,CrossbowQuiver_RS", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); rustyBagsQuiverSlotEnabled.SettingChanged += delegate { UpdateSlots(); }; vikingsSummonerSlotEnabled = config("Mod - Vikings Summoner", "Enabled", defaultValue: true, "Enable Vikings Summoner grimoire slot."); vikingsSummonerSlotName = config("Mod - Vikings Summoner", "Name", "Grimoire", "Slot name. Use ExtraSlots translation files to add localized string."); vikingsSummonerSlotGlobalKey = config("Mod - Vikings Summoner", "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); vikingsSummonerSlotItemDiscovered = config("Mod - Vikings Summoner", "Items discovered", "RD_grimoire_01,RD_grimoire_02,RD_grimoire_03", "Comma-separated list of items. Slot will be active only if any item is discovered or list is not set."); vikingsSummonerSlotEnabled.SettingChanged += delegate { UpdateSlots(); }; for (int num = 0; num < 8; num++) { new UserDefinedSlot(num); } } public static void UpdateSlots() { if ((Object)(object)instance == (Object)null || slotsOrder == null || UserDefinedSlot.userDefinedSlots.Any((UserDefinedSlot slot) => slot == null)) { return; } if (updatingSlots) { slotUpdatePending = true; return; } updatingSlots = true; try { do { slotUpdatePending = false; UpdateSlotRegistrations(); } while (slotUpdatePending); } finally { updatingSlots = false; } } private static void UpdateSlotRegistrations() { List<CustomSlot> list = CustomSlot.slots.ToList(); List<CustomSlot> list2 = (from slot in list where slot.initialized group slot by slot.slotID into @group select @group.First()).ToList(); CustomSlot.slots.Clear(); try { CollectionExtensions.Do<string>((from id in slotsOrder.Value.Split(new char[1] { ',' }).Concat(CustomSlot.GetVanillaOrder()) select id.Trim() into id where !Utility.IsNullOrWhiteSpace(id) select id).Distinct(), (Action<string>)InitSlot); } catch { CustomSlot.slots.Clear(); CustomSlot.slots.AddRange(list); throw; } Dictionary<string, CustomSlot> dictionary = list2.ToDictionary((CustomSlot slot) => slot.slotID); for (int num = 0; num < CustomSlot.slots.Count; num++) { CustomSlot customSlot = CustomSlot.slots[num]; if (customSlot.initialized && dictionary.TryGetValue(customSlot.slotID, out var value)) { value.UpdateDefinition(customSlot); CustomSlot.slots[num] = value; } } List<CustomSlot> list3 = CustomSlot.slots.Where((CustomSlot slot) => slot.initialized).ToList(); int num2; for (num2 = 0; num2 < list2.Count && num2 < list3.Count && list2[num2].slotID == list3[num2].slotID && API.FindSlot(CustomSlot.GetSlotID(list3[num2].slotID)) != null; num2++) { } for (int num3 = list2.Count - 1; num3 >= num2; num3--) { if (list2[num3].RemoveSlot()) { LogInfo($"Slot {list2[num3]} was removed"); } } CustomSlot precedingSlot = ((num2 > 0) ? list3[num2 - 1] : null); for (int num4 = num2; num4 < list3.Count; num4++) { if (TryAddSlot(list3[num4], precedingSlot)) { precedingSlot = list3[num4]; } } UserDefinedSlot.RefreshSlots(); EpicLootCompatibility.InvalidatePlayerEffectCache(Player.m_localPlayer); } public static void TryAddSlot(CustomSlot slot) { TryAddSlot(slot, null); } private static bool TryAddSlot(CustomSlot slot, CustomSlot precedingSlot) { if (!slot.initialized) { return false; } if (API.RemoveSlot(slot.slotID)) { LogInfo($"Legacy slot {slot} was removed"); } if (slot.AddSlotAfter(precedingSlot)) { LogInfo($"Slot {slot} was added"); return true; } LogWarning($"Error while trying to add new slot {slot}. Check the available custom-slot capacity in ExtraSlots."); return false; } public static void InitSlot(string slotID) { switch (slotID) { case "Backpacks": if (!backpacksSlotEnabled.Value) { break; } new BackpacksSlot(); return; case "AdventureBackpacks": if (!adventureBackpackSlotEnabled.Value) { break; } new AdventureBackpacksSlot(); return; case "JudesEquipmentBackpack": if (!judesEquipmentBackpackSlotEnabled.Value) { break; } new JudesEquipmentBackpackSlot(); return; case "RustyBagsBag": if (!rustyBagsSlotEnabled.Value) { break; } new RustyBagsSlot(); return; case "RustyBagsQuiver": if (!rustyBagsQuiverSlotEnabled.Value) { break; } new RustyBagsQuiverSlot(); return; case "MagicPluginTome": if (!magicPluginTomeSlotEnabled.Value) { break; } new MagicPluginTomeSlot(); return; case "MagicPluginEarring": if (!magicPluginEarringSlotEnabled.Value) { break; } new MagicPluginEarringSlot(); return; case "JewelcraftingNeck": if (!jewelcraftingNeckSlotEnabled.Value) { break; } new JewelcraftingNeckSlot(); return; case "JewelcraftingRing": if (!jewelcraftingRingSlotEnabled.Value) { break; } new JewelcraftingRingSlot(); return; case "BowsBeforeHoes": if (!bbhQuiverSlotEnabled.Value) { break; } new BowsBeforeHoesSlot(); return; case "CircletExtended": if (!circletExtendedSlotEnabled.Value) { break; } new CircletExtendedSlot(); return; case "HipLantern": if (!hipLanternSlotEnabled.Value) { break; } new HipLanternSlot(); return; case "VikingsSummoner": if (!vikingsSummonerSlotEnabled.Value) { break; } new VikingsSummoner(); return; } if (UserDefinedSlot.IsUserDefinedSlot(slotID)) { UserDefinedSlot.UpdateSlot(slotID); } } public static void LogInfo(object data) { if (loggingEnabled.Value) { ((BaseUnityPlugin)instance).Logger.LogInfo(data); } } public static void LogMessage(object data) { ((BaseUnityPlugin)instance).Logger.LogMessage(data); } public static void LogWarning(object data) { ((BaseUnityPlugin)instance).Logger.LogWarning(data); } internal ConfigEntry<T> config<T>(string group, string name, T defaultValue, ConfigDescription description, bool synchronizedSetting = true) { return ((ConditionalConfigSync)configSync).AddConfigEntry<T>(((BaseUnityPlugin)this).Config, group, name, defaultValue, description, (ConfigSyncMode)1, synchronizedSetting).SourceConfig; } internal ConfigEntry<T> serverConfig<T>(string group, string name, T defaultValue, ConfigDescription description) { return ((ConditionalConfigSync)configSync).AddConfigEntry<T>(((BaseUnityPlugin)this).Config, group, name, defaultValue, description, (ConfigSyncMode)0, true).SourceConfig; } internal ConfigEntry<T> config<T>(string group, string name, T defaultValue, string description, bool synchronizedSetting = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return config(group, name, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } internal ConfigEntry<T> serverConfig<T>(string group, string name, T defaultValue, string description) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown return serverConfig(group, name, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>())); } } internal static class EpicLootCompatibility { private enum CompatibilityBranch { None, Legacy, Version013OrLater } private struct ItemTypePatchState { public bool Changed; public ItemType OriginalType; } [HarmonyPatch] private static class EpicLoot_DirectPlayerEquipmentMethods_AddCustomSlotItems { private static List<MethodBase> targets; private static bool Prepare() { if (!UsesDirectEquipmentPatches()) { return false; } targets = GetTargets(); return targets.Count > 0; } private static IEnumerable<MethodBase> TargetMethods() { return targets ?? (targets = GetTargets()); } private static List<MethodBase> GetTargets() { List<MethodBase> list = new List<MethodBase>(); Type type = GetEpicLootAssembly()?.GetType("EpicLoot.PlayerExtensions"); MethodInfo methodInfo = FindMethod(type, "GetMagicEquipment", typeof(Player)); string text = "GetMagicEquipment"; if (methodInfo == null) { methodInfo = FindMethod(type, "GetEquipment", typeof(Player)); text = "GetEquipment"; } if (methodInfo != null) { list.Add(methodInfo); ExtraSlotsCustomSlots.LogInfo("EpicLoot.PlayerExtensions:" + text + " will include items equipped in Extra Slots Custom Slots."); } return list; } [HarmonyPriority(0)] private static void Postfix(Player __0, List<ItemData> __result) { if (__result == null) { return; } foreach (ItemData extraEquippedItem in GetExtraEquippedItems(__0)) { if ((isMagicItem == null || isMagicItem(extraEquippedItem)) && !__result.Contains(extraEquippedItem)) { __result.Add(extraEquippedItem); } } } } [HarmonyPatch] private static class EpicLoot_ItemTypeChecks_TreatCustomBackpacksAsShoulder { private static List<MethodBase> targets; private static bool Prepare() { if (ResolveCompatibilityBranch() == CompatibilityBranch.None || !HasSupportedBackpackMod()) { return false; } targets = GetTargets(); return targets.Count > 0; } private static IEnumerable<MethodBase> TargetMethods() { return targets ?? (targets = GetTargets()); } private static List<MethodBase> GetTargets() { List<MethodBase> list = new List<MethodBase>(); list.AddRange(FindItemDataMethods("EpicLoot.Crafting.EnchantCostsHelper", EnchantingMethods)); list.AddRange(FindItemDataMethods("EpicLoot.EpicLoot", "CanBeMagicItem")); list.AddRange(FindItemDataMethods("EpicLoot.MagicItemEffectRequirements", "AllowByItemType", "ExcludeByItemType", "CheckRequirements")); return list.Distinct().ToList(); } [HarmonyPriority(800)] private static void Prefix(ItemData __0, ref ItemTypePatchState __state) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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) if (IsSupportedBackpack(__0)) { __state.Changed = true; __state.OriginalType = __0.m_shared.m_itemType; __0.m_shared.m_itemType = (ItemType)17; } } private static Exception Finalizer(ItemData __0, ItemTypePatchState __state, Exception __exception) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (__state.Changed && __0?.m_shared != null) { __0.m_shared.m_itemType = __state.OriginalType; } return __exception; } } [HarmonyPatch] private static class EpicLoot_Version013OrLater_ItemTypeClassifier_ClassifyCustomBackpacksAsShoulder { private static List<MethodBase> targets; private static bool Prepare() { if (!UsesVersion013OrLaterCompatibility() || !HasSupportedBackpackMod()) { return false; } targets = FindItemDataMethods("EpicLoot.GatedItemType.ItemTypeClassifier", "ClassifyFromFields"); return targets.Count > 0; } private static IEnumerable<MethodBase> TargetMethods() { return targets ?? (targets = FindItemDataMethods("EpicLoot.GatedItemType.ItemTypeClassifier", "ClassifyFromFields")); } [HarmonyPriority(0)] private static void Postfix(ItemData __0, ref string __result) { if (IsSupportedBackpack(__0)) { __result = "ShouldersArmor"; } } } [HarmonyPatch] private static class EpicLoot_Version013OrLater_ItemTypeClassifier_TryGetConfiguredType_TreatCustomBackpacksAsShoulder { private static MethodBase target; private static bool Prepare() { if (!UsesVersion013OrLaterCompatibility() || !HasSupportedBackpackMod()) { return false; } Type type = GetEpicLootAssembly()?.GetType("EpicLoot.GatedItemType.ItemTypeClassifier"); target = FindMethod(type, "TryGetConfiguredType", typeof(ItemData), typeof(string).MakeByRefType()); if (target != null) { ExtraSlotsCustomSlots.LogInfo("EpicLoot.GatedItemType.ItemTypeClassifier:TryGetConfiguredType will classify supported custom backpacks as shoulder armor."); } return target != null; } private static MethodBase TargetMethod() { return target; } [HarmonyPriority(0)] private static void Postfix(ItemData __0, ref string __1, ref bool __result) { if (IsSupportedBackpack(__0) && (!__result || string.IsNullOrEmpty(__1) || string.Equals(__1, "Utility", StringComparison.OrdinalIgnoreCase))) { __1 = "ShouldersArmor"; __result = true; } } } internal const string EpicLootGuid = "randyknapp.mods.epicloot"; private const string ProviderId = "shudnal.ExtraSlotsCustomSlots"; private const string ItemTypeClassifierTypeName = "EpicLoot.GatedItemType.ItemTypeClassifier"; private const string ShoulderItemInfoType = "ShouldersArmor"; private const string UtilityItemInfoType = "Utility"; private static readonly Version Version013 = new Version(0, 13, 0); private static readonly string[] EnchantingMethods = new string[5] { "GetSacrificeProducts", "GetEnchantCost", "GetRuneCost", "GetAugmentCost", "GetReAugmentCost" }; private static CompatibilityBranch compatibilityBranch; private static bool compatibilityBranchResolved; private static Version epicLootVersion; private static Assembly epicLootAssembly; private static MethodInfo registerEquipmentProvider; private static MethodInfo unregisterEquipmentProvider; private static MethodInfo invalidatePlayerEffectCache; private static MethodInfo resetLegacyEquipmentEffectCache; private static Func<ItemData, bool> isMagicItem; private static bool equipmentProviderRegistered; internal static void Prepare() { ResolveCompatibilityBranch(); } internal static void Initialize() { if (ResolveCompatibilityBranch() != CompatibilityBranch.Version013OrLater || equipmentProviderRegistered || registerEquipmentProvider == null) { return; } try { object obj = registerEquipmentProvider.Invoke(null, new object[2] { "shudnal.ExtraSlotsCustomSlots", new Func<Player, List<ItemData>>(GetExtraEquippedItems) }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } equipmentProviderRegistered = (byte)((uint)num & (flag ? 1u : 0u)) != 0; if (equipmentProviderRegistered) { ExtraSlotsCustomSlots.LogInfo("Registered Extra Slots Custom Slots equipment provider through the Epic Loot 0.13+ API."); InvalidatePlayerEffectCache(Player.m_localPlayer); } else { ExtraSlotsCustomSlots.LogWarning("Epic Loot rejected the Extra Slots Custom Slots equipment provider registration."); } } catch (Exception exception) { ExtraSlotsCustomSlots.LogWarning("Failed to register the Extra Slots Custom Slots equipment provider through Epic Loot API: " + GetExceptionMessage(exception)); } } internal static void Shutdown() { if (!equipmentProviderRegistered) { return; } try { unregisterEquipmentProvider?.Invoke(null, new object[1] { "shudnal.ExtraSlotsCustomSlots" }); } catch (Exception exception) { ExtraSlotsCustomSlots.LogWarning("Failed to unregister the Extra Slots Custom Slots equipment provider from Epic Loot API: " + GetExceptionMessage(exception)); } finally { equipmentProviderRegistered = false; } } internal static void InvalidatePlayerEffectCache(Player player) { if ((Object)(object)player == (Object)null) { return; } ResolveCompatibilityBranch(); MethodInfo methodInfo = ((compatibilityBranch == CompatibilityBranch.Version013OrLater) ? (invalidatePlayerEffectCache ?? resetLegacyEquipmentEffectCache) : resetLegacyEquipmentEffectCache); if (methodInfo == null) { return; } try { methodInfo.Invoke(null, new object[1] { player }); } catch (Exception exception) { ExtraSlotsCustomSlots.LogWarning("Failed to invalidate the Epic Loot equipment effect cache: " + GetExceptionMessage(exception)); } } private static CompatibilityBranch ResolveCompatibilityBranch() { if (compatibilityBranchResolved) { return compatibilityBranch; } compatibilityBranchResolved = true; if (!Chainloader.PluginInfos.TryGetValue("randyknapp.mods.epicloot", out var value)) { return compatibilityBranch = CompatibilityBranch.None; } epicLootAssembly = ((object)value.Instance)?.GetType().Assembly; BepInPlugin metadata = value.Metadata; epicLootVersion = ((metadata != null) ? metadata.Version : null); if (epicLootAssembly == null) { return compatibilityBranch = CompatibilityBranch.None; } Type type = epicLootAssembly.GetType("EpicLoot.API"); Type typeFromHandle = typeof(Func<Player, List<ItemData>>); registerEquipmentProvider = FindMethod(type, "RegisterEquipmentProvider", typeof(string), typeFromHandle); unregisterEquipmentProvider = FindMethod(type, "UnregisterEquipmentProvider", typeof(string)); invalidatePlayerEffectCache = FindMethod(type, "InvalidatePlayerEffectCache", typeof(Player)); Type type2 = epicLootAssembly.GetType("EpicLoot.EquipmentEffectCache"); resetLegacyEquipmentEffectCache = FindMethod(type2, "Reset", typeof(Player)); Type type3 = epicLootAssembly.GetType("EpicLoot.ItemDataExtensions"); MethodInfo methodInfo = FindMethod(type3, "IsMagic", typeof(ItemData)); if (methodInfo != null) { try { isMagicItem = (Func<ItemData, bool>)Delegate.CreateDelegate(typeof(Func<ItemData, bool>), methodInfo); } catch { isMagicItem = null; } } bool flag = registerEquipmentProvider != null; compatibilityBranch = ((!(epicLootVersion != null)) ? ((!flag) ? CompatibilityBranch.Legacy : CompatibilityBranch.Version013OrLater) : ((epicLootVersion.CompareTo(Version013) < 0) ? CompatibilityBranch.Legacy : CompatibilityBranch.Version013OrLater)); string text = epicLootVersion?.ToString() ?? "unknown version"; string text2 = ((compatibilityBranch == CompatibilityBranch.Version013OrLater) ? "0.13 or later compatibility" : "legacy pre-0.13 compatibility"); ExtraSlotsCustomSlots.LogInfo("Epic Loot " + text + ": using " + text2 + "."); return compatibilityBranch; } private static MethodInfo FindMethod(Type type, string methodName, params Type[] parameterTypes) { return type?.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); } private static Assembly GetEpicLootAssembly() { ResolveCompatibilityBranch(); return epicLootAssembly; } private static bool UsesDirectEquipmentPatches() { return ResolveCompatibilityBranch() switch { CompatibilityBranch.Version013OrLater => registerEquipmentProvider == null, CompatibilityBranch.Legacy => true, _ => false, }; } private static bool UsesVersion013OrLaterCompatibility() { return ResolveCompatibilityBranch() == CompatibilityBranch.Version013OrLater; } private static bool HasSupportedBackpackMod() { return AdventureBackpacksSlot.IsLoaded || JudesEquipmentBackpackSlot.IsLoaded; } private static List<ItemData> GetExtraEquippedItems(Player player) { List<ItemData> list = new List<ItemData>(); if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return list; } foreach (CustomSlot slot in CustomSlot.slots) { if (!slot.initialized) { continue; } Slot val = API.FindSlot(CustomSlot.GetSlotID(slot.slotID)); if (val != null && val.IsActive) { ItemData item = val.Item; if (item != null && ((Humanoid)player).IsItemEquiped(item) && !list.Contains(item)) { list.Add(item); } } } return list; } private static bool IsSupportedBackpack(ItemData item) { if (item?.m_shared == null) { return false; } if (AdventureBackpacksSlot.IsActive && global::ExtraSlotsCustomSlots.AdventureBackpacksCustomSlot.CustomItemType.IsBackpack != null && global::ExtraSlotsCustomSlots.AdventureBackpacksCustomSlot.CustomItemType.IsBackpack(item)) { return true; } return JudesEquipmentBackpackSlot.IsActive && global::ExtraSlotsCustomSlots.JudesEquipmentBackpacksCustomSlot.CustomItemType.IsBackpack != null && global::ExtraSlotsCustomSlots.JudesEquipmentBackpacksCustomSlot.CustomItemType.IsBackpack(item); } private static string GetExceptionMessage(Exception exception) { return (exception is TargetInvocationException { InnerException: not null } ex) ? ex.InnerException.Message : exception.Message; } private static List<MethodBase> FindItemDataMethods(string typeName, IEnumerable<string> methodNames) { List<MethodBase> list = new List<MethodBase>(); Type type = GetEpicLootAssembly()?.GetType(typeName); if (type == null) { return list; } MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (string methodName in methodNames) { List<MethodInfo> list2 = (from method in methods where method.Name == methodName where method.GetParameters().FirstOrDefault()?.ParameterType == typeof(ItemData) select method).ToList(); foreach (MethodInfo item in list2) { if (!list.Contains(item)) { list.Add(item); } } if (list2.Count > 0) { ExtraSlotsCustomSlots.LogInfo(typeName + ":" + methodName + " method" + ((list2.Count == 1) ? "" : " overloads") + " will treat supported custom backpacks as shoulder items."); } } return list; } private static List<MethodBase> FindItemDataMethods(string typeName, params string[] methodNames) { return FindItemDataMethods(typeName, (IEnumerable<string>)methodNames); } } internal sealed class EquipmentVisualMetadata { private readonly int variantKey; private readonly int qualityKey; private int variant; private int quality; private int renderedVariant; private int renderedQuality; internal EquipmentVisualMetadata(string key) { variantKey = StringExtensionMethods.GetStableHashCode(key + "Variant"); qualityKey = StringExtensionMethods.GetStableHashCode(key + "Quality"); } internal void Set(VisEquipment equipment, int itemVariant, int itemQuality) { variant = itemVariant; quality = itemQuality; if (Object.op_Implicit((Object)(object)equipment.m_nview) && equipment.m_nview.IsValid() && equipment.m_nview.IsOwner()) { ZDO zDO = equipment.m_nview.GetZDO(); zDO.Set(variantKey, variant, false); zDO.Set(qualityKey, quality, false); } } internal bool HasChanged(VisEquipment equipment) { Read(equipment, out var currentVariant, out var currentQuality); return renderedVariant != currentVariant || renderedQuality != currentQuality; } internal void Read(VisEquipment equipment, out int currentVariant, out int currentQuality) { ZDO val = (Object.op_Implicit((Object)(object)equipment.m_nview) ? equipment.m_nview.GetZDO() : null); currentVariant = ((val != null) ? val.GetInt(variantKey, 0) : variant); currentQuality = ((val != null) ? val.GetInt(qualityKey, 0) : quality); } internal void MarkRendered(int currentVariant, int currentQuality) { renderedVariant = currentVariant; renderedQuality = currentQuality; } } internal static class InventoryCompatibility { internal static bool IsRuntimeInventory(Inventory inventory) { return inventory != null && !inventory.m_temoraryInventory; } internal static bool IsRuntimeItem(ItemData item) { return item?.m_shared != null && !string.IsNullOrEmpty(item.m_shared.m_name); } internal static IEnumerable<MethodBase> GetLoadMethods() { yield return AccessTools.DeclaredMethod(typeof(Inventory), "Load", new Type[1] { typeof(ZPackage) }, (Type[])null) ?? throw new MissingMethodException("Inventory.Load(ZPackage) was not found. Valheim 1.0.7 is required."); yield return AccessTools.DeclaredMethod(typeof(Inventory), "Load", new Type[2] { typeof(ZPackage), typeof(bool) }, (Type[])null) ?? throw new MissingMethodException("Inventory.Load(ZPackage, bool) was not found. Valheim 1.0.7 is required."); } } public class RustyBagsSlot : CustomSlot { public const string ID = "RustyBagsBag"; public const string pluginID = "RustyMods.RustyBags"; public static Type bag; public static Type quiver; public RustyBagsSlot() { CustomSlot.slots.Add(this); GUID = "RustyMods.RustyBags"; slotID = "RustyBagsBag"; if (!base.PluginInstalled) { return; } Assembly assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["RustyMods.RustyBags"].Instance).GetType()); bag = AccessTools.GetTypesFromAssembly(assembly).FirstOrDefault((Type type) => type.FullName == "RustyBags.Bag"); if (bag == null) { ExtraSlotsCustomSlots.LogWarning("RustyBags mod is loaded but RustyBags.Bag type is not found"); return; } quiver = AccessTools.GetTypesFromAssembly(assembly).FirstOrDefault((Type type) => type.FullName == "RustyBags.Quiver"); if (quiver != null && !ExtraSlotsCustomSlots.rustyBagsSlotCombineWithQuiver.Value) { itemIsValid = (ItemData item) => item != null && bag.IsInstanceOfType(item) && !quiver.IsInstanceOfType(item); } else { itemIsValid = (ItemData item) => item != null && bag.IsInstanceOfType(item); } getName = () => ExtraSlotsCustomSlots.rustyBagsSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.rustyBagsSlotGlobalKey.Value, ExtraSlotsCustomSlots.rustyBagsSlotItemDiscovered.Value); initialized = true; } } public class RustyBagsQuiverSlot : CustomSlot { public const string ID = "RustyBagsQuiver"; public const string pluginID = "RustyMods.RustyBags"; public static Type quiver; public RustyBagsQuiverSlot() { CustomSlot.slots.Add(this); GUID = "RustyMods.RustyBags"; slotID = "RustyBagsQuiver"; if (!base.PluginInstalled) { return; } Assembly assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["RustyMods.RustyBags"].Instance).GetType()); quiver = AccessTools.GetTypesFromAssembly(assembly).FirstOrDefault((Type type) => type.FullName == "RustyBags.Quiver"); if (quiver == null) { ExtraSlotsCustomSlots.LogWarning("RustyBags mod is loaded but RustyBags.Quiver type is not found"); return; } itemIsValid = (ItemData item) => item != null && quiver.IsInstanceOfType(item); getName = () => ExtraSlotsCustomSlots.rustyBagsQuiverSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.rustyBagsQuiverSlotGlobalKey.Value, ExtraSlotsCustomSlots.rustyBagsQuiverSlotItemDiscovered.Value); initialized = true; } } public class MagicPluginTomeSlot : CustomSlot { public const string ID = "MagicPluginTome"; public const string pluginID = "blacks7ar.MagicPlugin"; public MagicPluginTomeSlot() { CustomSlot.slots.Add(this); GUID = "blacks7ar.MagicPlugin"; slotID = "MagicPluginTome"; if (!base.PluginInstalled) { return; } Assembly assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["blacks7ar.MagicPlugin"].Instance).GetType()); MethodInfo isValid = AccessTools.Method(assembly.GetType("MagicPlugin.Functions.MagicSlot"), "IsTomeItem", (Type[])null, (Type[])null); if (isValid == null) { ExtraSlotsCustomSlots.LogWarning("MagicPlugin mod is loaded but MagicPlugin.Functions.MagicSlot:IsTomeItem is not found"); return; } itemIsValid = delegate(ItemData item) { int result; if (item != null) { MethodInfo methodInfo = isValid; object[] parameters = (object[])(object)new ItemData[1] { item }; result = (((bool)methodInfo.Invoke(null, parameters)) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }; getName = () => ExtraSlotsCustomSlots.magicPluginTomeSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.magicPluginTomeSlotGlobalKey.Value, ExtraSlotsCustomSlots.magicPluginTomeSlotItemDiscovered.Value); initialized = true; } } public class MagicPluginEarringSlot : CustomSlot { public const string ID = "MagicPluginEarring"; public const string pluginID = "blacks7ar.MagicPlugin"; public MagicPluginEarringSlot() { CustomSlot.slots.Add(this); GUID = "blacks7ar.MagicPlugin"; slotID = "MagicPluginEarring"; if (!base.PluginInstalled) { return; } Assembly assembly = Assembly.GetAssembly(((object)Chainloader.PluginInfos["blacks7ar.MagicPlugin"].Instance).GetType()); MethodInfo isValid = AccessTools.Method(assembly.GetType("MagicPlugin.Functions.MagicSlot"), "IsEarringItem", (Type[])null, (Type[])null); if (isValid == null) { ExtraSlotsCustomSlots.LogWarning("MagicPlugin mod is loaded but MagicPlugin.Functions.MagicSlot:IsEarringItem is not found"); return; } itemIsValid = delegate(ItemData item) { int result; if (item != null) { MethodInfo methodInfo = isValid; object[] parameters = (object[])(object)new ItemData[1] { item }; result = (((bool)methodInfo.Invoke(null, parameters)) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }; getName = () => ExtraSlotsCustomSlots.magicPluginEarringSlotName.Value; isActive = () => CustomSlot.IsSlotActive(ExtraSlotsCustomSlots.magicPluginEarringSlotGlobalKey.Value, ExtraSlotsCustomSlots.magicPluginEarringSlotItemDiscovered.Value); initialized = true; } } [HarmonyPatch] public static class MagicPlugin_MagicSlot_AddCustomSlot_PreventCustomSlotAddition { public static MethodBase target; public static bool Prepare(MethodBase original) { if (!Chainloader.PluginInfos.TryGetValue("blacks7ar.MagicPlugin", out var value)) { return false; } if ((object)target == null) { target = AccessTools.Method(Assembly.GetAssembly(((object)value.Instance).GetType()).GetType("MagicPlugin.Functions.MagicSlot"), "AddCustomSlot", (Type[])null, (Type[])null); } if (target == null) { return false; } if (original == null) { ExtraSlotsCustomSlots.LogInfo("MagicPlugin.Functions.MagicSlot:AddCustomSlot method is patched to prevent adding custom slot call"); } return true; } public static MethodBase TargetMethod() { return target; } public static bool Prefix() { return false; } } [HarmonyPatch] public static class MagicPlugin_AzuEPI_IsLoaded_CustomSlotHandle { public static MethodBase target; public static bool Prepare(MethodBase original) { if (!Chainloader.PluginInfos.TryGetValue("blacks7ar.MagicPlugin", out var value)) { return false; } if ((object)target == null) { target = AccessTools.Method(Assembly.GetAssembly(((object)value.Instance).GetType()).GetType("AzuExtendedPlayerInventory.API"), "IsLoaded", (Type[])null, (Type[])null); } if (target == null) { return false; } if (original == null) { ExtraSlotsCustomSlots.LogInfo("MagicPlugin.AzuExtendedPlayerInventory.API:IsLoaded method is patched to enable custom slot handling"); } return true; } public static MethodBase TargetMethod() { return target; } public static void Postfix(ref bool __result) { __result = true; } } public class UserDefinedSlot : CustomSlot { public ConfigEntry<bool> slotEnabled; public ConfigEntry<string> slotName; public ConfigEntry<string> slotGlobalKey; public ConfigEntry<string> slotItemList; public ConfigEntry<bool> itemIsVisible; public string groupName; public List<string> itemList = new List<string>(); public const int maxAmount = 8; public static UserDefinedSlot[] userDefinedSlots = new UserDefinedSlot[8]; public const string UserDefinedSlotID = "CustomSlot"; public void UpdateItemList() { itemList.Clear(); CollectionExtensions.Do<string>(from s in slotItemList.Value.Split(new char[1] { ',' }) select s.Trim() into s where !Utility.IsNullOrWhiteSpace(s) select s, (Action<string>)itemList.Add); } public UserDefinedSlot(int index) { userDefinedSlots[index] = this; groupName = $"User defined - Custom slot {index + 1}"; slotEnabled = ExtraSlotsCustomSlots.instance.config(groupName, "Enabled", defaultValue: false, "Enable custom slot."); slotName = ExtraSlotsCustomSlots.instance.config(groupName, "Name", "Slot", "Slot name. Use ExtraSlots translation files to add localized string."); slotGlobalKey = ExtraSlotsCustomSlots.instance.config(groupName, "Global keys", "", "Comma-separated list of global keys and player unique keys. Slot will be active only if any key is enabled or list is not set."); slotItemList = ExtraSlotsCustomSlots.instance.config(groupName, "Item list", "", "Comma-separated list of items. Slot will be active only if any item is discovered."); itemIsVisible = ExtraSlotsCustomSlots.instance.config(groupName, "Item is visible", defaultValue: true, "Make item in that slot visible on player model (if supported by an item itself)."); slotEnabled.SettingChanged += delegate { ExtraSlotsCustomSlots.UpdateSlots(); }; slotItemList.SettingChanged += delegate { UpdateItemList(); if (initialized) { RefreshSlots(); } }; slotGlobalKey.SettingChanged += delegate { if (initialized) { RefreshSlots(); } }; slotName.SettingChanged += delegate { if (initialized) { RefreshSlots(); } }; itemIsVisible.SettingChanged += delegate { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Humanoid)localPlayer).SetupEquipment(); } }; UpdateItemList(); GUID = GetSlotID(index); slotID = GUID; itemIsValid = (ItemData item) => item != null && ((item.m_shared != null && itemList.Contains(item.m_shared.m_name)) || ((Object)(object)item.m_dropPrefab != (Object)null && itemList.Contains(((Object)item.m_dropPrefab).name))); getName = () => slotName.Value; isActive = () => CustomSlot.IsSlotActive(slotGlobalKey.Value, slotItemList.Value); initialized = true; } internal static void RefreshSlots() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && !localPlayer.m_isLoading && InventoryCompatibility.IsRuntimeInventory(((Humanoid)localPlayer).GetInventory())) { CustomItemSlots.SynchronizeEquipmentSlots(localPlayer); for (int i = 0; i < 8; i++) { ItemData item = CustomItemSlots.GetItem(i); if (item != null && !CustomItemSlots.CanUseSlot(i, item, out var _)) { ((Humanoid)localPlayer).UnequipItem(item, false); } } } API.UpdateSlots(); } public static void UpdateSlot(string slotID) { UserDefinedSlot userDefinedSlot = userDefinedSlots.FirstOrDefault((UserDefinedSlot slot) => slot != null && slot.slotID == slotID); if (userDefinedSlot != null && userDefinedSlot.slotEnabled.Value) { CustomSlot.slots.Add(userDefinedSlot); } } public static bool IsUserDefinedSlot(string slotID) { return slotID.StartsWith("CustomSlot"); } public static string GetSlotID(int index) { return string.Format("{0}{1}", "CustomSlot", index + 1); } public static bool IsItemInSlotVisible(int index) { UserDefinedSlot userDefinedSlot = userDefinedSlots[index]; return userDefinedSlot != null && userDefinedSlot.slotEnabled.Value && userDefinedSlot.itemIsVisible.Value; } } } namespace ExtraSlotsCustomSlots.UserDefinedCustomSlots { [Serializable] public class HumanoidCustomItemSlots { public ItemData customItem1; public ItemData customItem2; public ItemData customItem3; public ItemData customItem4; public ItemData customItem5; public ItemData customItem6; public ItemData customItem7; public ItemData customItem8; } public static class HumanoidExtension { private static readonly ConditionalWeakTable<Humanoid, HumanoidCustomItemSlots> data = new ConditionalWeakTable<Humanoid, HumanoidCustomItemSlots>(); public static HumanoidCustomItemSlots GetCustomItemData(this Humanoid humanoid) { return data.GetOrCreateValue(humanoid); } public static ItemData GetCustomItem(this Humanoid humanoid, int index) { if (1 == 0) { } ItemData result = (ItemData)(index switch { 0 => humanoid.GetCustomItemData().customItem1, 1 => humanoid.GetCustomItemData().customItem2, 2 => humanoid.GetCustomItemData().customItem3, 3 => humanoid.GetCustomItemData().customItem4, 4 => humanoid.GetCustomItemData().customItem5, 5 => humanoid.GetCustomItemData().customItem6, 6 => humanoid.GetCustomItemData().customItem7, 7 => humanoid.GetCustomItemData().customItem8, _ => null, }); if (1 == 0) { } return result; } public static ItemData SetCustomItem(this Humanoid humanoid, int index, ItemData item) { ItemData customItem = humanoid.GetCustomItem(index); if (1 == 0) { } ItemData val = (ItemData)(index switch { 0 => humanoid.GetCustomItemData().customItem1 = item, 1 => humanoid.GetCustomItemData().customItem2 = item, 2 => humanoid.GetCustomItemData().customItem3 = item, 3 => humanoid.GetCustomItemData().customItem4 = item, 4 => humanoid.GetCustomItemData().customItem5 = item, 5 => humanoid.GetCustomItemData().customItem6 = item, 6 => humanoid.GetCustomItemData().customItem7 = item, 7 => humanoid.GetCustomItemData().customItem8 = item, _ => null, }); if (1 == 0) { } ItemData val2 = val; if (customItem != val2) { EpicLootCompatibility.InvalidatePlayerEffectCache((Player)(object)((humanoid is Player) ? humanoid : null)); } return val2; } } [Serializable] public class VisEquipmentCustomItemState { public string m_item = ""; public List<GameObject> m_instances; public int m_hash = 0; internal EquipmentVisualMetadata metadata; } [Serializable] public class VisEquipmentCustomItem { public VisEquipmentCustomItemState customItem1 = new VisEquipmentCustomItemState(); public VisEquipmentCustomItemState customItem2 = new VisEquipmentCustomItemState(); public VisEquipmentCustomItemState customItem3 = new VisEquipmentCustomItemState(); public VisEquipmentCustomItemState customItem4 = new VisEquipmentCustomItemState(); public VisEquipmentCustomItemState customItem5 = new VisEquipmentCustomItemState(); public VisEquipmentCustomItemState customItem6 = new VisEquipmentCustomItemState(); public VisEquipmentCustomItemState customItem7 = new VisEquipmentCustomItemState(); public VisEquipmentCustomItemState customItem8 = new VisEquipmentCustomItemState(); } public static class VisEquipmentExtension { [HarmonyPatch(typeof(VisEquipment), "UpdateEquipmentVisuals")] public static class VisEquipment_UpdateEquipmentVisuals_CustomItemType { private static void Postfix(VisEquipment __instance) { ZDO val = (Object.op_Implicit((Object)(object)__instance.m_nview) ? __instance.m_nview.GetZDO() : null); bool flag = false; for (int i = 0; i < CustomItemSlots.SlotsAmount; i++) { int hash = 0; if (val != null) { hash = val.GetInt(customItemStateZdoHash[i], 0); } else { VisEquipmentCustomItemState customItemState = __instance.GetCustomItemState(i); if (!string.IsNullOrEmpty(customItemState.m_item)) { hash = StringExtensionMethods.GetStableHashCode(customItemState.m_item); } } if (__instance.SetCustomItemEquipped(hash, i)) { flag = true; } } if (flag) { __instance.UpdateLodgroup(); } } } [HarmonyPatch(typeof(Humanoid), "SetupVisEquipment")] public static class Humanoid_SetupVisEquipment_CustomItemType { private static void Postfix(Humanoid __instance, VisEquipment visEq) { if (Object.op_Implicit((Object)(object)visEq)) { for (int i = 0; i < CustomItemSlots.SlotsAmount; i++) { ItemData customItem = __instance.GetCustomItem(i); bool flag = (Object)(object)customItem?.m_dropPrefab != (Object)null && UserDefinedSlot.IsItemInSlotVisible(i); visEq.SetCustomItemState(i, flag ? ((Object)customItem.m_dropPrefab).name : ""); visEq.GetCustomItemState(i).metadata.Set(visEq, flag ? customItem.m_variant : 0, flag ? customItem.m_quality : 0); } } } } private static readonly List<int> customItemStateZdoHash = new List<int> { StringExtensionMethods.GetStableHashCode("ESCS_CustomItemState_1"), StringExtensionMethods.GetStableHashCode("ESCS_CustomItemState_2"), StringExtensionMethods.GetStableHashCode("ESCS_CustomItemState_3"), StringExtensionMethods.GetStableHashCode("ESCS_CustomItemState_4"), StringExtensionMethods.GetStableHashCode("ESCS_CustomItemState_5"), StringExtensionMethods.GetStableHashCode("ESCS_CustomItemState_6"), StringExtensionMethods.GetStableHashCode("ESCS_CustomItemState_7"), StringExtensionMethods.GetStableHashCode("ESCS_CustomItemState_8") }; private static readonly ConditionalWeakTable<VisEquipment, VisEquipmentCustomItem> data = new ConditionalWeakTable<VisEquipment, VisEquipmentCustomItem>(); public static VisEquipmentCustomItem GetCustomItemData(this VisEquipment visEquipment) { return data.GetOrCreateValue(visEquipment); } public static VisEquipmentCustomItemState GetCustomItemState(this VisEquipment humanoid, int index) { if (1 == 0) { } VisEquipmentCustomItemState visEquipmentCustomItemState = index switch { 0 => humanoid.GetCustomItemData().customItem1, 1 => humanoid.GetCustomItemData().customItem2, 2 => humanoid.GetCustomItemData().customItem3, 3 => humanoid.GetCustomItemData().customItem4, 4 => humanoid.GetCustomItemData().customItem5, 5 => humanoid.GetCustomItemData().customItem6, 6 => humanoid.GetCustomItemData().customItem7, 7 => humanoid.GetCustomItemData().customItem8, _ => null, }; if (1 == 0) { } VisEquipmentCustomItemState visEquipmentCustomItemState2 = visEquipmentCustomItemState; if (visEquipmentCustomItemState2 != null && visEquipmentCustomItemState2.metadata == null) { visEquipmentCustomItemState2.metadata = new EquipmentVisualMetadata($"ESCS_CustomItemState_{index + 1}"); } return visEquipmentCustomItemState2; } public static void SetCustomItemState(this VisEquipment visEquipment, int index, string name) { VisEquipmentCustomItemState customItemState = visEquipment.GetCustomItemState(index); if (customItemState != null) { customItemState.m_item = name ?? ""; if (Object.op_Implicit((Object)(object)visEquipment.m_nview) && visEquipment.m_nview.IsValid() && visEquipment.m_nview.IsOwner()) { visEquipment.m_nview.GetZDO().Set(customItemStateZdoHash[index], (!string.IsNullOrEmpty(name)) ? StringExtensionMethods.GetStableHashCode(name) : 0, false); } } } public static bool SetCustomItemEquipped(this VisEquipment visEquipment, int hash, int index) { VisEquipmentCustomItemState customItemState = visEquipment.GetCustomItemState(index); if (customItemState == null || (customItemState.m_hash == hash && !customItemState.metadata.HasChanged(visEquipment))) { return false; } if (customItemState.m_instances != null) { foreach (GameObject instance in customItemState.m_instances) { if (Object.op_Implicit((Object)(object)visEquipment.m_lodGroup)) { Utils.RemoveFromLodgroup(visEquipment.m_lodGroup, instance); } Object.Destroy((Object)(object)instance); } customItemState.m_instances = null; } customItemState.metadata.Read(visEquipment, out var currentVariant, out var currentQuality); customItemState.metadata.MarkRendered(currentVariant, currentQuality); customItemState.m_hash = hash; if (hash != 0) { customItemState.m_instances = visEquipment.AttachArmor(hash, currentVariant, currentQuality); } return true; } } public static class CustomItemSlots { private readonly struct EquippedItemsSnapshot { private readonly ItemData item0; private readonly ItemData item1; private readonly ItemData item2; private readonly ItemData item3; private readonly ItemData item4; private readonly ItemData item5; private readonly ItemData item6; private readonly ItemData item7; internal ItemData this[int index] { get { if (1 == 0) { } ItemData result = (ItemData)(index switch { 0 => item0, 1 => item1, 2 => item2, 3 => item3, 4 => item4, 5 => item5, 6 => item6, 7 => item7, _ => null, }); if (1 == 0) { } return result; } } internal EquippedItemsSnapshot(Humanoid humanoid) { HumanoidCustomItemSlots customItemData = humanoid.GetCustomItemData(); item0 = customItemData.customItem1; item1 = customItemData.customItem2; item2 = customItemData.customItem3; item3 = customItemData.customItem4; item4 = customItemData.customItem5; item5 = customItemData.customItem6; item6 = customItemData.customItem7; item7 = customItemData.customItem8; } } public static class CustomItemPatches { [HarmonyPatch(typeof(Player), "Awake")] private static class Player_Awake_PrepareModifierReaders { private static void Postfix() { GetModifierReaders(); } } [HarmonyPatch(typeof(Humanoid), "UpdateEquipmentStatusEffects")] private static class Humanoid_UpdateEquipmentStatusEffects_CustomItem { private static void Prefix(Humanoid __instance) { if (!IsValidPlayer(__instance)) { return; } tempEffects.Clear(); ItemData[] equippedItemsArray = GetEquippedItemsArray(); foreach (ItemData val in equippedItemsArray) { if (Object.op_Implicit((Object)(object)val.m_shared.m_equipStatusEffect)) { tempEffects.Add(val.m_shared.m_equipStatusEffect); } if (__instance.HaveSetEffect(val)) { tempEffects.Add(val.m_shared.m_setStatusEffect); } } } private static void Postfix(Humanoid __instance) { foreach (StatusEffect item in tempEffects.Where((StatusEffect item) => !__instance.m_equipmentStatusEffects.Contains(item))) { ((Character)__instance).m_seman.AddStatusEffect(item, false, 0, 0f, (short)(-1)); } __instance.m_equipmentStatusEffects.UnionWith(tempEffects); tempEffects.Clear(); } } [HarmonyPatch(typeof(SEMan), "RemoveStatusEffect", new Type[] { typeof(int), typeof(bool) })] private static class SEMan_RemoveStatusEffect_CustomItemPreventRemoval { private static void Prefix(SEMan __instance, ref int nameHash) { Player localPlayer = Player.m_localPlayer; if (__instance != ((localPlayer != null) ? ((Character)localPlayer).GetSEMan() : null) || tempEffects.Count == 0) { return; } foreach (StatusEffect tempEffect in tempEffects) { if (tempEffect.NameHash() == nameHash) { nameHash = 0; } } } } [HarmonyPatch(typeof(Humanoid), "GetEquipmentWeight")] private static class Humanoid_GetEquipmentWeight_CustomItem { private static void Postfix(Humanoid __instance, ref float __result) { if (!IsValidPlayer(__instance)) { return; } EquippedItemsSnapshot equippedItemsSnapshot = new EquippedItemsSnapshot(__instance); for (int i = 0; i < SlotsAmount; i++) { if (equippedItemsSnapshot[i]?.m_shared != null) { __result += equippedItemsSnapshot[i].m_shared.m_weight; } } } } [HarmonyPatch(typeof(Humanoid), "EquipItem")] private static class Humanoid_EquipItem_CustomItem { private sealed class EquipState { internal EquipState Previous; internal Humanoid Humanoid; internal ItemData Item; internal bool SelectionResolved; internal int SlotIndex = -1; } private static readonly ItemType customAssignmentType = (ItemType)767; [ThreadStatic] private static EquipState current; [HarmonyPriority(802)] private static bool Prefix(Humanoid __instance, ItemData item, out EquipState __state, ref bool __result)