Decompiled source of Item Storage Categories v1.0.0

plugins/ChestLabels.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ChestLabels")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ChestLabels")]
[assembly: AssemblyTitle("ChestLabels")]
[assembly: AssemblyVersion("1.0.0.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 BenjSammy.ChestLabels
{
	internal static class ChestIcon
	{
		private const string AssetName = "BENJSAMMYCHESTLABELS";

		private static bool ready;

		private static bool failed;

		internal static bool IsReady()
		{
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Expected O, but got Unknown
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			if (ready || failed || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return ready;
			}
			ScriptableObject val = null;
			Material val2 = null;
			try
			{
				GameObject prefab = ZNetScene.instance.GetPrefab("piece_chest_wood");
				Piece val3 = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<Piece>());
				Sprite val4 = (Sprite)(((Object)(object)val3 == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
				if ((Object)(object)val4 == (Object)null)
				{
					throw new InvalidOperationException("Wooden chest sprite is unavailable.");
				}
				Type type = RequireType("TMPro.TMP_SpriteAsset");
				Type type2 = RequireType("TMPro.TMP_SpriteGlyph");
				Type type3 = RequireType("TMPro.TMP_SpriteCharacter");
				Type type4 = RequireType("TMPro.MaterialReferenceManager");
				Type type5 = AccessTools.TypeByName("TMPro.TMP_TextParsingUtilities");
				MethodInfo methodInfo = ((type5 == null) ? null : AccessTools.Method(type5, "GetHashCodeCaseInSensitive", new Type[1] { typeof(string) }, (Type[])null));
				Type type6 = AccessTools.TypeByName("TMPro.TMP_TextUtilities");
				MethodInfo methodInfo2 = ((type6 == null) ? null : AccessTools.Method(type6, "GetSimpleHashCode", new Type[1] { typeof(string) }, (Type[])null));
				int num = (int)((methodInfo ?? methodInfo2)?.Invoke(null, new object[1] { "BENJSAMMYCHESTLABELS" }) ?? throw new InvalidOperationException("TMP asset hash API unavailable."));
				Shader obj = Shader.Find("TextMeshPro/Sprite");
				if ((Object)(object)obj == (Object)null)
				{
					throw new InvalidOperationException("TMP sprite shader unavailable.");
				}
				val = ScriptableObject.CreateInstance(type);
				((Object)val).name = "BENJSAMMYCHESTLABELS";
				PropertyInfo property = type.GetProperty("version", AccessTools.all);
				if (property?.GetSetMethod(nonPublic: true) != null)
				{
					property.SetValue(val, "1.1.0");
				}
				else
				{
					Set(val, "m_Version", "1.1.0");
				}
				val2 = new Material(obj)
				{
					mainTexture = (Texture)(object)val4.texture
				};
				Set(val, "material", val2);
				Set(val, "spriteSheet", val4.texture);
				Rect textureRect = val4.textureRect;
				object obj2 = Activator.CreateInstance(type2);
				Set(obj2, "index", 0u);
				float num2 = 20f;
				float num3 = num2 * ((Rect)(ref textureRect)).width / ((Rect)(ref textureRect)).height;
				ConstructProperty(obj2, "metrics", num3, num2, 0f, 17f, num3 + 2f);
				ConstructProperty(obj2, "glyphRect", (int)((Rect)(ref textureRect)).x, (int)((Rect)(ref textureRect)).y, (int)((Rect)(ref textureRect)).width, (int)((Rect)(ref textureRect)).height);
				object obj3 = Activator.CreateInstance(type3, 57344u, val, obj2);
				Set(obj3, "name", "Chest");
				AddEntry(val, "spriteGlyphTable", obj2);
				AddEntry(val, "spriteCharacterTable", obj3);
				AccessTools.Method(type, "UpdateLookupTables", Type.EmptyTypes, (Type[])null).Invoke(val, null);
				MethodInfo methodInfo3 = AccessTools.Method(type4, "AddSpriteAsset", new Type[2]
				{
					typeof(int),
					type
				}, (Type[])null);
				if (methodInfo3 == null)
				{
					throw new InvalidOperationException("TMP sprite registration API unavailable.");
				}
				methodInfo3.Invoke(null, new object[2] { num, val });
				ready = true;
			}
			catch (Exception ex)
			{
				failed = true;
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)val2);
				}
				Logger.CreateLogSource("Item Storage Categories").LogWarning((object)("Chest icon unavailable, using text: " + ex.GetBaseException()));
			}
			return ready;
		}

		private static Type RequireType(string name)
		{
			return AccessTools.TypeByName(name) ?? throw new InvalidOperationException("Missing type " + name);
		}

		private static PropertyInfo Property(object target, string name)
		{
			return AccessTools.Property(target.GetType(), name) ?? throw new InvalidOperationException("Missing property " + name);
		}

		private static void Set(object target, string name, object value)
		{
			PropertyInfo property = target.GetType().GetProperty(name, AccessTools.all);
			if (property != null)
			{
				property.SetValue(target, value);
			}
			else
			{
				(AccessTools.Field(target.GetType(), name) ?? throw new MissingMemberException(name)).SetValue(target, value);
			}
		}

		private static void ConstructProperty(object target, string name, params object[] args)
		{
			PropertyInfo propertyInfo = Property(target, name);
			propertyInfo.SetValue(target, Activator.CreateInstance(propertyInfo.PropertyType, args));
		}

		private static void AddEntry(object target, string name, object entry)
		{
			PropertyInfo propertyInfo = Property(target, name);
			IList list = (IList)propertyInfo.GetValue(target);
			if (list == null)
			{
				list = (IList)Activator.CreateInstance(propertyInfo.PropertyType);
				propertyInfo.SetValue(target, list);
			}
			list.Add(entry);
		}
	}
	[BepInPlugin("benjsammy.chestlabels", "Item Storage Categories by BenjSammy", "1.0.0")]
	public sealed class ChestLabels : BaseUnityPlugin
	{
		private const string Id = "benjsammy.chestlabels";

		private static readonly Dictionary<string, string> Categories = new Dictionary<string, string>(StringComparer.Ordinal);

		private static readonly Dictionary<string, string> English = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["Bois"] = "Wood",
			["Pierre"] = "Stone",
			["Combustibles"] = "Fuel",
			["Décoration"] = "Decorations",
			["Minerais"] = "Ores",
			["Lingots"] = "Ingots",
			["Pièces fabriquées"] = "Crafted Parts",
			["Composants"] = "Components",
			["Cuir et tissus"] = "Leather and Cloth",
			["Moules et pièces"] = "Moulds and Casts",
			["Magie"] = "Magic",
			["Cuisine crue"] = "Raw Ingredients",
			["Repas"] = "Meals",
			["Fermentation"] = "Brewing",
			["Potions"] = "Potions",
			["Culture"] = "Farming",
			["Pêche"] = "Fishing",
			["Armes"] = "Weapons",
			["Armures"] = "Armor",
			["Boucliers"] = "Shields",
			["Munitions"] = "Ammo",
			["Outils"] = "Tools",
			["Trophées"] = "Trophies",
			["Trésors"] = "Treasures",
			["Clés et quêtes"] = "Keys and Quests"
		};

		private static FieldRef<ItemData, GameObject> dropPrefab;

		private static MethodInfo getLanguage;

		private static MethodInfo getLocalization;

		private static FieldInfo localizationField;

		private Harmony harmony;

		private const string CategoryStart = "<align=center><line-height=115%>";

		private void Awake()
		{
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Expected O, but got Unknown
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Expected O, but got Unknown
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Expected O, but got Unknown
			using (StreamReader streamReader = new StreamReader(typeof(ChestLabels).Assembly.GetManifestResourceStream("Categories.tsv")))
			{
				string text;
				while ((text = streamReader.ReadLine()) != null)
				{
					string[] array = text.Split('\t');
					if (array.Length != 2 || !English.ContainsKey(array[1]))
					{
						throw new InvalidDataException("Invalid chest category record.");
					}
					Categories.Add(array[0], array[1]);
				}
			}
			dropPrefab = AccessTools.FieldRefAccess<ItemData, GameObject>("m_dropPrefab");
			Type type = AccessTools.TypeByName("Localization");
			if (type != null)
			{
				getLanguage = AccessTools.Method(type, "GetSelectedLanguage", Type.EmptyTypes, (Type[])null);
				getLocalization = AccessTools.PropertyGetter(type, "instance");
				localizationField = AccessTools.Field(type, "instance");
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(ItemData), "GetTooltip", new Type[6]
			{
				typeof(ItemData),
				typeof(int),
				typeof(bool),
				typeof(float),
				typeof(int),
				typeof(bool)
			}, (Type[])null) ?? AccessTools.Method(typeof(ItemData), "GetTooltip", new Type[5]
			{
				typeof(ItemData),
				typeof(int),
				typeof(bool),
				typeof(float),
				typeof(int)
			}, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(ItemData), "GetTooltip", new Type[1] { typeof(int) }, (Type[])null);
			harmony = new Harmony("benjsammy.chestlabels");
			if (methodInfo2 != null && !methodInfo2.IsStatic && methodInfo2.ReturnType == typeof(string))
			{
				harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(ChestLabels), "AddInventoryCategory", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			if (methodInfo != null && methodInfo.IsStatic && methodInfo.ReturnType == typeof(string))
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(ChestLabels), "AddCategory", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Tooltip hooks: inventory={methodInfo2 != null}, shared={methodInfo != null}.");
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			Categories.Clear();
		}

		private static void AddInventoryCategory(ItemData __instance, ref string __result)
		{
			AddCategory(__instance, ref __result);
		}

		private static void AddCategory(ItemData __0, ref string __result)
		{
			if (__0 == null)
			{
				return;
			}
			string obj = __result;
			if (obj == null || !obj.StartsWith("<align=center><line-height=115%>", StringComparison.Ordinal))
			{
				object obj2 = getLocalization?.Invoke(null, null) ?? localizationField?.GetValue(null);
				string text = ((getLanguage == null || (obj2 == null && !getLanguage.IsStatic)) ? null : (getLanguage.Invoke(obj2, null) as string));
				bool flag = string.Equals(text, "French", StringComparison.OrdinalIgnoreCase) || string.Equals(text, "fr", StringComparison.OrdinalIgnoreCase) || string.Equals(text, "Français", StringComparison.OrdinalIgnoreCase) || (text?.StartsWith("fr-", StringComparison.OrdinalIgnoreCase) ?? false);
				GameObject val = dropPrefab.Invoke(__0);
				string text2 = (((Object)(object)val == (Object)null) ? "" : ((Object)val).name);
				if (text2.EndsWith("(Clone)", StringComparison.Ordinal))
				{
					text2 = text2.Substring(0, text2.Length - "(Clone)".Length).TrimEnd();
				}
				string value;
				bool flag2 = Categories.TryGetValue(text2, out value);
				string text3 = ((!flag) ? (flag2 ? English[value] : "Unknown") : (flag2 ? value : "Inconnue"));
				string text4 = (ChestIcon.IsReady() ? "<sprite=\"BENJSAMMYCHESTLABELS\" index=0> " : (flag ? "Coffre • " : "Chest • "));
				__result = "<align=center><line-height=115%>" + text4 + "<color=#E6BC72>" + text3 + "</color>\n</line-height></align>" + __result;
			}
		}
	}
}