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