Decompiled source of CosmeticArmor v1.0.2

CosmeticArmor.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExtraSlots;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CosmeticArmor")]
[assembly: AssemblyDescription("ExtraSlots add-on with cosmetic armor slots that change how your armor looks")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: InternalsVisibleTo("CosmeticCheck")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CosmeticArmor
{
	internal enum Part
	{
		Helmet,
		Chest,
		Legs,
		Cape,
		Utility,
		Trinket
	}
	internal enum Look
	{
		Cosmetic,
		Armor,
		Hidden
	}
	internal static class CosmeticSlots
	{
		internal static readonly Part[] Parts = new Part[6]
		{
			Part.Helmet,
			Part.Chest,
			Part.Legs,
			Part.Cape,
			Part.Utility,
			Part.Trinket
		};

		internal const string LooksKey = "CosmeticArmor_Looks";

		internal static Func<Part, ItemData> SlotItem = delegate(Part part)
		{
			Slot obj = API.FindSlot(SlotId(part));
			return (obj == null) ? null : obj.Item;
		};

		internal static Func<Dictionary<string, string>> SavedData = () => Player.m_localPlayer?.m_customData;

		internal static Func<ItemData, bool> IsWorn = delegate(ItemData item)
		{
			Player localPlayer = Player.m_localPlayer;
			return localPlayer != null && ((Humanoid)localPlayer).IsItemEquiped(item);
		};

		private static readonly string[] SlotIds = Parts.Select((Part p) => "CosmeticArmor_" + p).ToArray();

		private static string _parsedFrom;

		private static readonly Look[] Parsed = new Look[Parts.Length];

		internal static string SlotId(Part part)
		{
			return SlotIds[(int)part];
		}

		internal static ItemType TypeOf(Part part)
		{
			return (ItemType)(part switch
			{
				Part.Helmet => 6, 
				Part.Chest => 7, 
				Part.Legs => 11, 
				Part.Utility => 18, 
				Part.Trinket => 24, 
				_ => 17, 
			});
		}

		internal static string SlotName(Part part)
		{
			if (!Layout.GroupPlaced)
			{
				return NameOf(part);
			}
			return part.ToString();
		}

		internal static string NameOf(Part part)
		{
			return part switch
			{
				Part.Helmet => "Cosmetic helmet", 
				Part.Chest => "Cosmetic chest", 
				Part.Legs => "Cosmetic legs", 
				Part.Utility => "Cosmetic utility", 
				Part.Trinket => "Cosmetic trinket", 
				_ => "Cosmetic cape", 
			};
		}

		internal static bool Fits(Part part, ItemData item)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (item?.m_shared != null && item.m_shared.m_itemType == TypeOf(part))
			{
				return !IsWorn(item);
			}
			return false;
		}

		internal static void Register()
		{
			Part[] parts = Parts;
			foreach (Part part in parts)
			{
				Part p = part;
				if (!API.AddSlot(SlotId(p), (Func<string>)(() => SlotName(p)), (Func<ItemData, bool>)((ItemData item) => Fits(p, item)), (Func<bool>)(() => Plugin.Enabled.Value)))
				{
					Plugin.Log.LogWarning((object)("ExtraSlots refused the slot " + SlotId(p) + ", check its free custom slots"));
				}
			}
		}

		internal static ItemData ItemIn(Part part)
		{
			try
			{
				return SlotItem(part);
			}
			catch
			{
				return null;
			}
		}

		internal static bool IsCosmeticItem(ItemData item)
		{
			//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)
			//IL_002b: 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 (item?.m_shared == null)
			{
				return false;
			}
			ItemType itemType = item.m_shared.m_itemType;
			Part[] parts = Parts;
			foreach (Part part in parts)
			{
				if (TypeOf(part) == itemType)
				{
					return ItemIn(part) == item;
				}
			}
			return false;
		}

		internal static List<ItemData> CosmeticItems()
		{
			return (from i in Parts.Select(ItemIn)
				where i != null
				select i).ToList();
		}

		internal static Look GetLook(Part part)
		{
			Dictionary<string, string> dictionary = SavedData();
			if (dictionary == null || !dictionary.TryGetValue("CosmeticArmor_Looks", out var value))
			{
				return Look.Cosmetic;
			}
			if ((object)value != _parsedFrom)
			{
				string[] array = (value ?? "").Split(new char[1] { ',' });
				for (int i = 0; i < Parsed.Length; i++)
				{
					Parsed[i] = ((i < array.Length && int.TryParse(array[i], out var result) && result >= 0 && result <= 2) ? ((Look)result) : Look.Cosmetic);
				}
				_parsedFrom = value;
			}
			return Parsed[(int)part];
		}

		internal static void SetLook(Part part, Look look)
		{
			Dictionary<string, string> dictionary = SavedData();
			if (dictionary != null)
			{
				Look[] array = Parts.Select(GetLook).ToArray();
				array[(int)part] = look;
				dictionary["CosmeticArmor_Looks"] = string.Join(",", array.Select(delegate(Look l)
				{
					int num = (int)l;
					return num.ToString();
				}));
			}
		}

		internal static Look Shown(Part part)
		{
			Look look = GetLook(part);
			if (look != Look.Cosmetic || ItemIn(part) != null)
			{
				return look;
			}
			return Look.Armor;
		}

		internal static Look Next(Look shown, bool hasItem)
		{
			switch (shown)
			{
			case Look.Cosmetic:
				return Look.Armor;
			case Look.Armor:
				return Look.Hidden;
			default:
				if (!hasItem)
				{
					return Look.Armor;
				}
				return Look.Cosmetic;
			}
		}

		internal static void Cycle(Part part)
		{
			Look look = Next(Shown(part), ItemIn(part) != null);
			SetLook(part, look);
			if (Plugin.LogLooks.Value)
			{
				Plugin.Log.LogInfo((object)$"{part} look set to {look}");
			}
			Looks.Refresh();
		}
	}
	internal static class CustomSlotItems
	{
		internal static Func<ItemData, bool> FitsOtherCustomSlot = delegate(ItemData item)
		{
			Slot[] customSlots = Slots.GetCustomSlots(true);
			foreach (Slot val in customSlots)
			{
				if (val != null && !Layout.IsOurs(val.ID) && val.ItemFits(item))
				{
					return true;
				}
			}
			return false;
		};

		private static bool _changedOnce;

		internal static void Patch(Harmony harmony)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method("ExtraSlots.Slots:IsCustomSlotItem", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.Log.LogWarning((object)"ExtraSlots.Slots.IsCustomSlotItem not found, extra utility slots may stay blocked by the cosmetic slots");
				return;
			}
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(CustomSlotItems), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Plugin.Log.LogInfo((object)"custom slot check: the cosmetic slots no longer count, extra utility slots work with them");
		}

		internal static void Postfix(ItemData item, ref bool __result)
		{
			if (!__result || item?.m_shared == null || FitsOtherCustomSlot(item))
			{
				return;
			}
			__result = false;
			if (!_changedOnce)
			{
				_changedOnce = true;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("custom slot check: " + item.m_shared.m_name + " fits only a cosmetic slot, ExtraSlots treats it as normal equipment (first time this session)"));
				}
			}
		}
	}
	internal static class ExtraUtilityLooks
	{
		[HarmonyPatch(typeof(Humanoid), "SetupVisEquipment")]
		[HarmonyAfter(new string[] { "shudnal.ExtraSlots" })]
		private static class AfterSetup
		{
			private static void Postfix(Humanoid __instance, VisEquipment visEq)
			{
				if (!((Object)(object)visEq == (Object)null) && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && Plugin.Enabled.Value && HideExtras())
				{
					for (int i = 0; i < 4; i++)
					{
						Clear(visEq, i);
					}
					if (!_loggedOnce || Plugin.LogLooks.Value)
					{
						_loggedOnce = true;
						Plugin.Log.LogInfo((object)$"extra utility items hidden ({CosmeticSlots.Shown(Part.Utility)})");
					}
				}
			}
		}

		private const int ExtraVisuals = 4;

		private static bool _loggedOnce;

		internal static Action<VisEquipment, int> Clear = delegate(VisEquipment vis, int index)
		{
			VisEquipmentExtension.SetCustomItemState(vis, index, "");
		};

		internal static bool HideExtras()
		{
			return CosmeticSlots.Shown(Part.Utility) != Look.Armor;
		}
	}
	internal static class Layout
	{
		internal struct SlotPos
		{
			public string Id;

			public Vector2 Pos;

			public bool Equipment;
		}

		internal const float Gap = 0.2f;

		internal const float TitleHeight = 20f;

		internal static bool GroupPlaced;

		private static float _widthDelta;

		private static float _heightDelta;

		private static string _lastLog;

		private static FieldRef<Slot, Vector2> _position;

		private const float DefaultPitch = 70f;

		private static FieldInfo _background;

		private static FieldInfo _selectedFrame;

		private static Vector2 _baseSize;

		private static Vector2 _basePos;

		private static bool _hasBase;

		internal static RectTransform Background
		{
			get
			{
				object? obj = _background?.GetValue(null);
				return (RectTransform)((obj is RectTransform) ? obj : null);
			}
		}

		internal static bool IsOurs(string id)
		{
			if (id != null)
			{
				if (!id.StartsWith("CosmeticArmor_"))
				{
					return id.StartsWith("CustomCosmeticArmor_");
				}
				return true;
			}
			return false;
		}

		internal static float Pitch(List<SlotPos> equipment, float fallback)
		{
			//IL_0017: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			float num = float.MaxValue;
			for (int i = 0; i < equipment.Count; i++)
			{
				for (int j = i + 1; j < equipment.Count; j++)
				{
					Vector2 val = equipment[i].Pos - equipment[j].Pos;
					float num2 = Mathf.Abs(val.x);
					float num3 = Mathf.Abs(val.y);
					if (num2 < 0.5f && num3 > 0.5f)
					{
						num = Mathf.Min(num, num3);
					}
					if (num3 < 0.5f && num2 > 0.5f)
					{
						num = Mathf.Min(num, num2);
					}
				}
			}
			if (!(num < float.MaxValue))
			{
				return fallback;
			}
			return num;
		}

		internal static Dictionary<string, Vector2> Plan(List<SlotPos> slots, float tile, out float widthDelta)
		{
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, Vector2> moves = new Dictionary<string, Vector2>();
			widthDelta = 0f;
			List<SlotPos> list = slots.Where((SlotPos s) => s.Equipment).ToList();
			List<SlotPos> list2 = list.Where((SlotPos s) => IsOurs(s.Id)).ToList();
			if (list2.Count == 0 || tile <= 0f)
			{
				return moves;
			}
			List<SlotPos> list3 = list.Where((SlotPos s) => !IsOurs(s.Id)).ToList();
			tile = Pitch(list, tile);
			float x0 = list.Min((SlotPos s) => s.Pos.x);
			if (list.Any((SlotPos s) => Mathf.Abs((s.Pos.x - x0) / tile - (float)Col(s.Pos)) > 0.1f))
			{
				return moves;
			}
			int currentLast = list.Max((SlotPos s) => Col(s.Pos));
			List<SlotPos> list4 = list3.Concat(slots.Where((SlotPos s) => !s.Equipment && Col(s.Pos) <= currentLast)).ToList();
			int num = ((list4.Count > 0) ? list4.Max((SlotPos s) => Col(s.Pos)) : (-1));
			int num2 = Math.Max(0, currentLast - num);
			float num3 = x0 + (float)num * tile;
			Vector2 val = default(Vector2);
			foreach (SlotPos item in slots.Where((SlotPos s) => !s.Equipment && Col(s.Pos) > currentLast))
			{
				((Vector2)(ref val))..ctor(item.Pos.x - (float)num2 * tile, item.Pos.y);
				moves[item.Id] = val;
				num3 = Mathf.Max(num3, val.x);
			}
			List<SlotPos> source = ((list3.Count > 0) ? list3 : list);
			List<float> list5 = (from s in source
				select s.Pos.y into y
				orderby y descending
				select y).ToList();
			float top = list5[0];
			float num4 = 0f;
			for (int num5 = 1; num5 < list5.Count; num5++)
			{
				float num6 = list5[num5 - 1] - list5[num5];
				if (num6 > 1f && (num4 == 0f || num6 < num4))
				{
					num4 = num6;
				}
			}
			float rowStep = ((num4 > 0f) ? (0f - num4) : (0f - tile));
			int num7 = Math.Max(2, source.Select((SlotPos s) => Mathf.RoundToInt((s.Pos.y - top) / rowStep)).Distinct().Count());
			int num8 = (list2.Count + num7 - 1) / num7;
			float num9 = num3 + tile * 1.2f;
			for (int num10 = 0; num10 < list2.Count; num10++)
			{
				moves[list2[num10].Id] = new Vector2(num9 + (float)(num10 / num7) * tile, top + (float)(num10 % num7) * rowStep);
			}
			Vector2 value;
			List<(int, int)> list6 = (from s in slots
				select (!moves.TryGetValue(s.Id, out value)) ? s.Pos : value into p
				select (Mathf.RoundToInt(p.x), Mathf.RoundToInt(p.y))).ToList();
			if (list6.Distinct().Count() != list6.Count)
			{
				moves.Clear();
				return moves;
			}
			widthDelta = tile * ((float)num8 + 0.2f - (float)num2);
			return moves;
			int Col(Vector2 p)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				return Mathf.RoundToInt((p.x - x0) / tile);
			}
		}

		internal static void Grow(Vector2 size, Vector2 pos, Vector2 pivot, float width, float height, out Vector2 newSize, out Vector2 newPos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			newSize = size + new Vector2(width, height);
			newPos = pos + new Vector2(width * pivot.x, height * pivot.y);
		}

		internal static void Patch(Harmony harmony)
		{
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("ExtraSlots.EquipmentPanel");
			MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "SetSlotsPositions", (Type[])null, (Type[])null));
			MethodInfo methodInfo2 = ((type == null) ? null : AccessTools.Method(type, "UpdateBackground", (Type[])null, (Type[])null));
			_background = ((type == null) ? null : AccessTools.Field(type, "equipmentBackground"));
			_selectedFrame = ((type == null) ? null : AccessTools.Field(type, "selectedFrame"));
			if (AccessTools.Field(typeof(Slot), "_position")?.FieldType == typeof(Vector2))
			{
				_position = AccessTools.FieldRefAccess<Slot, Vector2>("_position");
			}
			if (methodInfo == null || methodInfo2 == null || _position == null || _background == null)
			{
				Plugin.Log.LogWarning((object)"this ExtraSlots version has another panel layout, the cosmetic slots stay in the armor grid");
				return;
			}
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Layout), "AfterSlotsPositions", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(Layout), "AfterBackground", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void AfterSlotsPositions()
		{
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			_widthDelta = 0f;
			_heightDelta = 0f;
			GroupPlaced = false;
			if (!Plugin.Enabled.Value || Plugin.UseExtraSlotsLayout.Value)
			{
				ApplyWidth();
				return;
			}
			try
			{
				List<Slot> equipment = (from s in API.GetEquipmentSlots()
					where s != null && s.IsActive
					select s).ToList();
				List<Slot> list = (from s in API.GetFoodSlots().Concat(API.GetAmmoSlots()).Concat(API.GetMiscSlots())
						.Concat(API.GetQuickSlots())
					where s != null && s.IsActive && !equipment.Contains(s)
					select s).Distinct().ToList();
				List<Slot> list2 = equipment.Concat(list).ToList();
				Dictionary<string, Vector2> dictionary = Plan(list2.Select((Slot s) => new SlotPos
				{
					Id = s.ID,
					Pos = s.Position,
					Equipment = equipment.Contains(s)
				}).ToList(), 70f, out _widthDelta);
				foreach (Slot item in list2)
				{
					if (dictionary.TryGetValue(item.ID, out var value))
					{
						_position.Invoke(item) = value;
					}
				}
				GroupPlaced = dictionary.Keys.Any(IsOurs);
				_heightDelta = ((GroupPlaced && Plugin.ShowTitle.Value) ? 20f : 0f);
				string text = $"layout: {equipment.Count} armor slots, {list.Count} others, moved {dictionary.Count}, panel {_widthDelta:+0;-0;0} px wider, {_heightDelta:0} px taller";
				if (Plugin.LogLooks.Value && text != _lastLog)
				{
					Plugin.Log.LogInfo((object)text);
				}
				_lastLog = text;
				ApplyWidth();
			}
			catch (Exception ex)
			{
				_widthDelta = 0f;
				_heightDelta = 0f;
				GroupPlaced = false;
				ApplyWidth();
				Plugin.Log.LogWarning((object)("could not place the cosmetic group: " + ex.Message));
			}
		}

		private static void AfterBackground()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			object? value = _background.GetValue(null);
			RectTransform val = (RectTransform)((value is RectTransform) ? value : null);
			if (val != null && !((Object)(object)val == (Object)null))
			{
				_baseSize = val.sizeDelta;
				_basePos = val.anchoredPosition;
				_hasBase = true;
				ApplyWidth();
			}
		}

		private static void ApplyWidth()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if (!_hasBase)
			{
				return;
			}
			object? value = _background.GetValue(null);
			RectTransform val = (RectTransform)((value is RectTransform) ? value : null);
			if (val != null && !((Object)(object)val == (Object)null))
			{
				Grow(_baseSize, _basePos, val.pivot, _widthDelta, _heightDelta, out var newSize, out var newPos);
				val.sizeDelta = newSize;
				val.anchoredPosition = newPos;
				object? obj = _selectedFrame?.GetValue(null);
				RectTransform val2 = (RectTransform)((obj is RectTransform) ? obj : null);
				if (val2 != null && (Object)(object)val2 != (Object)null)
				{
					val2.sizeDelta = newSize + Vector2.one * 26f;
					val2.anchoredPosition = newPos;
				}
			}
		}
	}
	internal static class LookButtons
	{
		[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
		[HarmonyAfter(new string[] { "shudnal.ExtraSlots" })]
		private static class AddButtons
		{
			private static void Postfix(InventoryGrid __instance)
			{
				if ((Object)(object)InventoryGui.instance == (Object)null || (Object)(object)__instance != (Object)(object)InventoryGui.instance.m_playerGrid)
				{
					return;
				}
				Title.Update(ElementsRef.Invoke(__instance));
				if (_failed || !Plugin.Enabled.Value)
				{
					return;
				}
				try
				{
					Part[] parts = CosmeticSlots.Parts;
					foreach (Part part in parts)
					{
						UpdateButton(__instance, part);
					}
				}
				catch (Exception arg)
				{
					_failed = true;
					Plugin.Log.LogError((object)$"look buttons switched off: {arg}");
				}
			}
		}

		private class Tag
		{
			internal InventoryElement Element;

			internal Transform Button;

			internal TMP_Text Text;

			internal Image Background;

			internal UITooltip Tooltip;

			internal Look Shown;
		}

		private const string ButtonName = "CosmeticArmor_Look";

		private static readonly FieldRef<InventoryGrid, List<InventoryElement>> ElementsRef = AccessTools.FieldRefAccess<InventoryGrid, List<InventoryElement>>("m_elements");

		private static bool _failed;

		private const float FadedIcon = 0.35f;

		private static readonly Tag[] Tags = new Tag[CosmeticSlots.Parts.Length];

		internal static string Label(Look shown)
		{
			return shown switch
			{
				Look.Cosmetic => "Show", 
				Look.Armor => "Armor", 
				_ => "Hide", 
			};
		}

		internal static string Tooltip(Part part, Look shown)
		{
			return CosmeticSlots.NameOf(part) + ": " + shown switch
			{
				Look.Cosmetic => "shows the cosmetic item", 
				Look.Armor => "shows your worn armor", 
				_ => "shows nothing", 
			} + ".\nClick to switch: Show (the cosmetic item), Armor (your worn armor), Hide (nothing).";
		}

		internal static Color ColorOf(Look shown)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(shown switch
			{
				Look.Cosmetic => new Color(0.85f, 0.62f, 0.1f, 0.95f), 
				Look.Armor => new Color(0.2f, 0.42f, 0.7f, 0.95f), 
				_ => new Color(0.62f, 0.14f, 0.12f, 0.95f), 
			});
		}

		internal static InventoryElement ElementAt(List<InventoryElement> elements, Vector2i position)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			foreach (InventoryElement element in elements)
			{
				if ((Object)(object)element != (Object)null && element.Position == position)
				{
					return element;
				}
			}
			return null;
		}

		private static void UpdateButton(InventoryGrid grid, Part part)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			Slot val = API.FindSlot(CosmeticSlots.SlotId(part));
			if (val == null || !val.IsActive)
			{
				return;
			}
			InventoryElement val2 = ElementAt(ElementsRef.Invoke(grid), val.GridPosition);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			Tag tag = Tags[(int)part] ?? (Tags[(int)part] = new Tag());
			if ((Object)(object)tag.Element != (Object)(object)val2 || (Object)(object)tag.Button == (Object)null)
			{
				Transform val3 = ((Component)val2).transform.Find("CosmeticArmor_Look");
				if ((Object)(object)val3 == (Object)null)
				{
					val3 = Create(val2, part);
				}
				tag.Element = val2;
				tag.Button = val3;
				tag.Text = ((Component)val3).GetComponentInChildren<TMP_Text>(true);
				tag.Background = ((Component)val3).GetComponent<Image>();
				tag.Tooltip = ((Component)val3).GetComponent<UITooltip>();
				tag.Shown = (Look)(-1);
			}
			Look look = CosmeticSlots.Shown(part);
			if (look != tag.Shown)
			{
				tag.Shown = look;
				if ((Object)(object)tag.Text != (Object)null)
				{
					tag.Text.text = Label(look);
				}
				if ((Object)(object)tag.Background != (Object)null)
				{
					((Graphic)tag.Background).color = ColorOf(look);
				}
				if ((Object)(object)tag.Tooltip != (Object)null)
				{
					tag.Tooltip.m_text = Tooltip(part, look);
				}
			}
			if ((Object)(object)val2.m_icon != (Object)null && ((Behaviour)val2.m_icon).enabled && look != Look.Cosmetic)
			{
				Color color = ((Graphic)val2.m_icon).color;
				color.a = 0.35f;
				((Graphic)val2.m_icon).color = color;
			}
			tag.Button.SetAsLastSibling();
		}

		private static Transform Create(InventoryElement element, Part part)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("CosmeticArmor_Look", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Button)
			});
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(((Component)element).transform, false);
			val2.anchorMin = new Vector2(0.06f, 0f);
			val2.anchorMax = new Vector2(0.94f, 0f);
			val2.pivot = new Vector2(0.5f, 0f);
			val2.anchoredPosition = new Vector2(0f, 2f);
			val2.sizeDelta = new Vector2(0f, 17f);
			((UnityEvent)val.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				CosmeticSlots.Cycle(part);
			});
			GameObject val3 = new GameObject("Label", new Type[1] { typeof(RectTransform) });
			RectTransform val4 = (RectTransform)val3.transform;
			((Transform)val4).SetParent((Transform)(object)val2, false);
			val4.anchorMin = Vector2.zero;
			val4.anchorMax = Vector2.one;
			Vector2 offsetMin = (val4.offsetMax = Vector2.zero);
			val4.offsetMin = offsetMin;
			TextMeshProUGUI val5 = val3.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)element.m_quality != (Object)null)
			{
				((TMP_Text)val5).font = element.m_quality.font;
			}
			((TMP_Text)val5).fontSize = 13f;
			((TMP_Text)val5).fontStyle = (FontStyles)1;
			((Graphic)val5).color = Color.white;
			((TMP_Text)val5).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val5).textWrappingMode = (TextWrappingModes)0;
			((Graphic)val5).raycastTarget = false;
			if ((Object)(object)element.m_tooltip != (Object)null)
			{
				UITooltip obj = val.AddComponent<UITooltip>();
				obj.m_tooltipPrefab = element.m_tooltip.m_tooltipPrefab;
				obj.m_topic = "Cosmetic Armor";
			}
			val.transform.SetAsLastSibling();
			return val.transform;
		}
	}
	internal static class Looks
	{
		[HarmonyPatch(typeof(VisEquipment), "SetHelmetItem")]
		private static class SetHelmetItem
		{
			private static void Prefix(VisEquipment __instance, ref int itemHash)
			{
				int variant = 0;
				int quality = 0;
				Apply(__instance, Part.Helmet, ref itemHash, ref variant, ref quality);
			}
		}

		[HarmonyPatch(typeof(VisEquipment), "SetChestItem")]
		private static class SetChestItem
		{
			private static void Prefix(VisEquipment __instance, ref int itemHash)
			{
				int variant = 0;
				int quality = 0;
				Apply(__instance, Part.Chest, ref itemHash, ref variant, ref quality);
			}
		}

		[HarmonyPatch(typeof(VisEquipment), "SetLegItem")]
		private static class SetLegItem
		{
			private static void Prefix(VisEquipment __instance, ref int itemHash)
			{
				int variant = 0;
				int quality = 0;
				Apply(__instance, Part.Legs, ref itemHash, ref variant, ref quality);
			}
		}

		[HarmonyPatch(typeof(VisEquipment), "SetShoulderItem")]
		private static class SetShoulderItem
		{
			private static void Prefix(VisEquipment __instance, ref int itemHash, ref int variant, ref int quality)
			{
				Apply(__instance, Part.Cape, ref itemHash, ref variant, ref quality);
			}
		}

		[HarmonyPatch(typeof(VisEquipment), "SetUtilityItem")]
		private static class SetUtilityItem
		{
			private static void Prefix(VisEquipment __instance, ref int itemHash)
			{
				int variant = 0;
				int quality = 0;
				Apply(__instance, Part.Utility, ref itemHash, ref variant, ref quality);
			}
		}

		[HarmonyPatch(typeof(VisEquipment), "SetTrinketItem")]
		private static class SetTrinketItem
		{
			private static void Prefix(VisEquipment __instance, ref string name)
			{
				if (Plugin.Enabled.Value && IsLocal(__instance))
				{
					string text = name;
					name = ChooseName(CosmeticSlots.Shown(Part.Trinket), CosmeticSlots.ItemIn(Part.Trinket), name);
					if (Plugin.LogLooks.Value && name != text)
					{
						Plugin.Log.LogInfo((object)string.Format("Trinket shows {0} ({1})", string.IsNullOrEmpty(name) ? "nothing" : name, CosmeticSlots.Shown(Part.Trinket)));
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		private static class WatchInventory
		{
			private static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					Inventory inventory = ((Humanoid)__instance).GetInventory();
					inventory.m_onChanged = (Action)Delegate.Remove(inventory.m_onChanged, new Action(Refresh));
					inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(Refresh));
					Refresh();
				}
			}
		}

		private static readonly FieldRef<Humanoid, VisEquipment> VisEquipmentRef = AccessTools.FieldRefAccess<Humanoid, VisEquipment>("m_visEquipment");

		private static bool IsLocal(VisEquipment vis)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && (Object)(object)vis != (Object)null)
			{
				return (Object)(object)VisEquipmentRef.Invoke((Humanoid)(object)localPlayer) == (Object)(object)vis;
			}
			return false;
		}

		internal static int HashOf(ItemData item)
		{
			if (!((Object)(object)item?.m_dropPrefab == (Object)null))
			{
				return StringExtensionMethods.GetStableHashCode(((Object)item.m_dropPrefab).name);
			}
			return 0;
		}

		internal static bool Choose(Look shown, ItemData cosmetic, ref int itemHash, ref int variant, ref int quality)
		{
			switch (shown)
			{
			case Look.Hidden:
				itemHash = 0;
				variant = 0;
				return true;
			case Look.Cosmetic:
				if (cosmetic != null)
				{
					int num = HashOf(cosmetic);
					if (num == 0)
					{
						return false;
					}
					itemHash = num;
					variant = cosmetic.m_variant;
					quality = cosmetic.m_quality;
					return true;
				}
				break;
			}
			return false;
		}

		private static void Apply(VisEquipment vis, Part part, ref int itemHash, ref int variant, ref int quality)
		{
			if (!Plugin.Enabled.Value || !IsLocal(vis))
			{
				return;
			}
			int num = itemHash;
			Look look = CosmeticSlots.Shown(part);
			if (!Choose(look, CosmeticSlots.ItemIn(part), ref itemHash, ref variant, ref quality) || !Plugin.LogLooks.Value || itemHash == num)
			{
				return;
			}
			ManualLogSource log = Plugin.Log;
			object arg = part;
			object arg2;
			if (itemHash != 0)
			{
				ItemData obj = CosmeticSlots.ItemIn(part);
				if (obj == null)
				{
					arg2 = null;
				}
				else
				{
					GameObject dropPrefab = obj.m_dropPrefab;
					arg2 = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
				}
			}
			else
			{
				arg2 = "nothing";
			}
			log.LogInfo((object)$"{arg} shows {arg2} ({look})");
		}

		internal static void Refresh()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				VisEquipment val = VisEquipmentRef.Invoke((Humanoid)(object)localPlayer);
				if ((Object)(object)val != (Object)null)
				{
					Traverse.Create((object)localPlayer).Method("SetupVisEquipment", new Type[2]
					{
						typeof(VisEquipment),
						typeof(bool)
					}, (object[])null).GetValue(new object[2] { val, false });
				}
			}
		}

		internal static string ChooseName(Look shown, ItemData cosmetic, string worn)
		{
			switch (shown)
			{
			case Look.Hidden:
				return "";
			case Look.Cosmetic:
				if ((Object)(object)cosmetic?.m_dropPrefab != (Object)null)
				{
					return ((Object)cosmetic.m_dropPrefab).name;
				}
				break;
			}
			return worn;
		}
	}
	[BepInPlugin("onononoki.CosmeticArmor", "CosmeticArmor", "1.0.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInIncompatibility("Transmog")]
	[BepInIncompatibility("vanity")]
	[BepInIncompatibility("vktr.vanityoutfit")]
	[BepInIncompatibility("advize.Armoire")]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "onononoki.CosmeticArmor";

		public const string ModName = "CosmeticArmor";

		public const string ModVersion = "1.0.2";

		internal const string ExtraSlotsGuid = "shudnal.ExtraSlots";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> ToGrave;

		internal static ConfigEntry<bool> LogLooks;

		internal static ConfigEntry<bool> UseExtraSlotsLayout;

		internal static ConfigEntry<bool> ShowTitle;

		private void Awake()
		{
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			//IL_014b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Cosmetic slots change how your armor looks. Off shows your worn armor again and hides the slots (their items stay safe in your inventory).");
			ToGrave = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CosmeticItemsToGrave", false, "Off: cosmetic items stay with you when you die. On: they go to your grave like everything else (anything that does not fit stays with you).");
			UseExtraSlotsLayout = ((BaseUnityPlugin)this).Config.Bind<bool>("Layout", "UseExtraSlotsLayout", false, "Fallback. Off: the cosmetic slots sit in their own group to the right of the food slots. On: ExtraSlots places them itself, in the armor grid with its other slots (use this if the group looks wrong after an ExtraSlots update).");
			UseExtraSlotsLayout.SettingChanged += delegate
			{
				API.UpdateSlots();
			};
			ShowTitle = ((BaseUnityPlugin)this).Config.Bind<bool>("Layout", "ShowTitle", true, "Shows a \"Cosmetic\" title above the cosmetic group (the panel gets a little taller at the top). Off: no title, the panel keeps ExtraSlots' height.");
			ShowTitle.SettingChanged += delegate
			{
				API.UpdateSlots();
			};
			LogLooks = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogLooks", false, "Writes a log line whenever a cosmetic slot changes what your character shows.");
			Enabled.SettingChanged += delegate
			{
				API.UpdateSlots();
				Looks.Refresh();
			};
			CosmeticSlots.Register();
			Harmony val = new Harmony("onononoki.CosmeticArmor");
			val.PatchAll(Assembly.GetExecutingAssembly());
			Layout.Patch(val);
			CustomSlotItems.Patch(val);
			Log.LogInfo((object)"CosmeticArmor 1.0.2 loaded");
		}
	}
	internal static class Title
	{
		private const string TitleName = "CosmeticArmor_Title";

		internal const string Text = "Cosmetic";

		internal const float Lift = 1f;

		internal const float BoxHeight = 18f;

		private static readonly Vector3[] Corners = (Vector3[])(object)new Vector3[4];

		private static bool _failed;

		internal static Vector2 Spot(float left, float right, float top)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2((left + right) / 2f, top + 1f);
		}

		internal static void Update(List<InventoryElement> elements)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			if (_failed)
			{
				return;
			}
			try
			{
				RectTransform background = Layout.Background;
				if ((Object)(object)background == (Object)null)
				{
					return;
				}
				Transform val = ((Transform)background).Find("CosmeticArmor_Title");
				if (!Plugin.Enabled.Value || !Plugin.ShowTitle.Value || !Layout.GroupPlaced || !GroupEdges(background, elements, out var left, out var right, out var top, out var font))
				{
					if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf)
					{
						((Component)val).gameObject.SetActive(false);
					}
					return;
				}
				if ((Object)(object)val == (Object)null)
				{
					val = Create(background, font);
				}
				if (!((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(true);
				}
				RectTransform val2 = (RectTransform)val;
				Vector2 anchorMin = (val2.anchorMax = background.pivot);
				val2.anchorMin = anchorMin;
				val2.sizeDelta = new Vector2(right - left, 18f);
				val2.anchoredPosition = Spot(left, right, top);
				val.SetAsLastSibling();
			}
			catch (Exception arg)
			{
				_failed = true;
				Plugin.Log.LogError((object)$"cosmetic title switched off: {arg}");
			}
		}

		private static bool GroupEdges(RectTransform panel, List<InventoryElement> elements, out float left, out float right, out float top, out TMP_FontAsset font)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			left = float.MaxValue;
			right = float.MinValue;
			top = float.MinValue;
			font = null;
			bool result = false;
			Part[] parts = CosmeticSlots.Parts;
			for (int i = 0; i < parts.Length; i++)
			{
				Slot val = API.FindSlot(CosmeticSlots.SlotId(parts[i]));
				if (val == null || !val.IsActive)
				{
					continue;
				}
				InventoryElement val2 = LookButtons.ElementAt(elements, val.GridPosition);
				if (!((Object)(object)val2 == (Object)null) && ((Component)val2).gameObject.activeInHierarchy)
				{
					((RectTransform)((Component)val2).transform).GetWorldCorners(Corners);
					Vector3[] corners = Corners;
					foreach (Vector3 val3 in corners)
					{
						Vector3 val4 = ((Transform)panel).InverseTransformPoint(val3);
						left = Mathf.Min(left, val4.x);
						right = Mathf.Max(right, val4.x);
						top = Mathf.Max(top, val4.y);
					}
					if ((Object)(object)font == (Object)null && (Object)(object)val2.m_quality != (Object)null)
					{
						font = val2.m_quality.font;
					}
					result = true;
				}
			}
			return result;
		}

		private static Transform Create(RectTransform panel, TMP_FontAsset font)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("CosmeticArmor_Title", new Type[1] { typeof(RectTransform) });
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent((Transform)(object)panel, false);
			val2.pivot = new Vector2(0.5f, 0f);
			TextMeshProUGUI val3 = val.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)font != (Object)null)
			{
				((TMP_Text)val3).font = font;
			}
			((TMP_Text)val3).text = "Cosmetic";
			((TMP_Text)val3).fontSize = 16f;
			((TMP_Text)val3).fontStyle = (FontStyles)1;
			((Graphic)val3).color = new Color(0.96f, 0.8f, 0.45f, 1f);
			((TMP_Text)val3).alignment = (TextAlignmentOptions)1026;
			((TMP_Text)val3).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)val3).overflowMode = (TextOverflowModes)0;
			((Graphic)val3).raycastTarget = false;
			return val.transform;
		}
	}
	internal static class WeightAndDeath
	{
		[HarmonyPatch(typeof(ItemData), "GetWeight")]
		[HarmonyAfter(new string[] { "shudnal.ExtraSlots" })]
		[HarmonyPriority(0)]
		private static class NoWeight
		{
			private static void Postfix(ItemData __instance, ref float __result)
			{
				if (__result != 0f && CosmeticSlots.IsCosmeticItem(__instance))
				{
					__result = 0f;
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "MoveInventoryToGrave")]
		[HarmonyPriority(800)]
		private static class KeepOnDeath
		{
			private static void Prefix(Inventory original, ref List<ItemData> __state)
			{
				if (original == null || original != PlayerInventory())
				{
					return;
				}
				List<ItemData> cosmetic = CosmeticSlots.CosmeticItems();
				__state = cosmetic;
				if (cosmetic.Count != 0 && !Plugin.ToGrave.Value)
				{
					ItemsRef.Invoke(original).RemoveAll((ItemData i) => cosmetic.Contains(i));
				}
			}

			private static void Postfix(Inventory __instance, Inventory original, List<ItemData> __state)
			{
				if (__state == null || __state.Count == 0)
				{
					return;
				}
				List<ItemData> list = ItemsRef.Invoke(original);
				int num = 0;
				foreach (ItemData item in __state)
				{
					if (!list.Contains(item) && (!Plugin.ToGrave.Value || !__instance.ContainsItem(item)))
					{
						list.Add(item);
						num++;
					}
				}
				if (num > 0)
				{
					Changed(original);
				}
				Plugin.Log.LogInfo((object)(Plugin.ToGrave.Value ? $"death: {__state.Count - num} cosmetic item(s) went to the grave, {num} stayed with you" : $"death: {num} cosmetic item(s) stayed with you"));
			}
		}

		internal static Func<Inventory> PlayerInventory = delegate
		{
			Player localPlayer = Player.m_localPlayer;
			return (localPlayer == null) ? null : ((Humanoid)localPlayer).GetInventory();
		};

		private static readonly FieldRef<Inventory, List<ItemData>> ItemsRef = AccessTools.FieldRefAccess<Inventory, List<ItemData>>("m_inventory");

		private static readonly Action<Inventory> Changed = delegate(Inventory inventory)
		{
			Traverse.Create((object)inventory).Method("Changed", new Type[2]
			{
				typeof(bool),
				typeof(bool)
			}, (object[])null).GetValue(new object[2] { false, false });
		};
	}
}