Decompiled source of Cat Cosmetics v1.4.0

CatCosmetics.dll

Decompiled a week 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 Steamworks;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace CatCosmetics;

public class CosmeticGift : MonoBehaviour
{
	public string[] steamIds;
}
[BepInPlugin("eberk30.catcosmetics", "Cat Cosmetics", "1.2.0")]
public class CatCosmeticsPlugin : BaseUnityPlugin
{
	public const string PLUGIN_GUID = "eberk30.catcosmetics";

	public const string PLUGIN_NAME = "Cat Cosmetics";

	public const string PLUGIN_VERSION = "1.2.0";

	internal static ManualLogSource Log;

	private static readonly FieldInfo _saveReady;

	private static readonly FieldInfo _cosmeticUnlocks;

	private static readonly FieldInfo _assetId;

	internal static readonly FieldInfo _iconField;

	private static readonly MethodInfo _getAllLoadedBundlesMethod;

	private static readonly MethodInfo _loadAssetMethod;

	private static readonly Dictionary<string, Sprite> _loadedIconCache;

	static CatCosmeticsPlugin()
	{
		_saveReady = typeof(MetaManager).GetField("saveReady", BindingFlags.Instance | BindingFlags.NonPublic);
		_cosmeticUnlocks = typeof(MetaManager).GetField("cosmeticUnlocks", BindingFlags.Instance | BindingFlags.NonPublic);
		_assetId = typeof(CosmeticAsset).GetField("assetId", BindingFlags.Instance | BindingFlags.NonPublic);
		_iconField = typeof(CosmeticAsset).GetField("icon", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		_loadedIconCache = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);
		Type type = Type.GetType("UnityEngine.AssetBundle, UnityEngine.AssetBundleModule") ?? Type.GetType("UnityEngine.AssetBundle, UnityEngine");
		if (!(type != null))
		{
			return;
		}
		_getAllLoadedBundlesMethod = type.GetMethod("GetAllLoadedAssetBundles", BindingFlags.Static | BindingFlags.Public);
		MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);
		foreach (MethodInfo methodInfo in methods)
		{
			if (methodInfo.Name == "LoadAsset" && methodInfo.IsGenericMethodDefinition && methodInfo.GetParameters().Length == 1 && methodInfo.GetParameters()[0].ParameterType == typeof(string))
			{
				_loadAssetMethod = methodInfo.MakeGenericMethod(typeof(Sprite));
				break;
			}
		}
	}

	private void Awake()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		new Harmony("eberk30.catcosmetics").PatchAll();
		((MonoBehaviour)this).StartCoroutine(GiftCosmeticRoutine());
	}

	private static Sprite TryLoadFromBundles(string[] searchNames)
	{
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Expected O, but got Unknown
		if (_getAllLoadedBundlesMethod == null || _loadAssetMethod == null)
		{
			return null;
		}
		try
		{
			IEnumerable enumerable = (IEnumerable)_getAllLoadedBundlesMethod.Invoke(null, null);
			if (enumerable == null)
			{
				return null;
			}
			foreach (object item in enumerable)
			{
				if (item == null)
				{
					continue;
				}
				foreach (string text in searchNames)
				{
					if (!string.IsNullOrEmpty(text))
					{
						Sprite val = (Sprite)_loadAssetMethod.Invoke(item, new object[1] { text });
						if ((Object)(object)val != (Object)null)
						{
							return val;
						}
					}
				}
			}
		}
		catch
		{
		}
		return null;
	}

	public static Sprite TryGetOrLoadCustomIcon(CosmeticAsset asset)
	{
		if ((Object)(object)asset == (Object)null)
		{
			return null;
		}
		string text = ((!string.IsNullOrEmpty(asset.assetName)) ? asset.assetName : ((Object)asset).name);
		if (string.IsNullOrEmpty(text))
		{
			return null;
		}
		if (_loadedIconCache.TryGetValue(text, out var value))
		{
			return value;
		}
		string[] array = new string[3]
		{
			asset.assetName,
			((Object)asset).name,
			((Object)asset).name.Replace("Cosmetic - ", "").Trim()
		};
		string text2 = Path.Combine(Path.GetDirectoryName(typeof(CatCosmeticsPlugin).Assembly.Location), "Icons");
		string text3 = null;
		if (Directory.Exists(text2))
		{
			string[] array2 = array;
			foreach (string text4 in array2)
			{
				if (!string.IsNullOrEmpty(text4))
				{
					string text5 = Path.Combine(text2, text4 + ".png");
					if (File.Exists(text5))
					{
						text3 = text5;
						break;
					}
				}
			}
			if (text3 == null)
			{
				array2 = Directory.GetFiles(text2, "*.png");
				foreach (string text6 in array2)
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text6);
					string[] array3 = array;
					foreach (string text7 in array3)
					{
						if (!string.IsNullOrEmpty(text7) && string.Equals(fileNameWithoutExtension, text7, StringComparison.OrdinalIgnoreCase))
						{
							text3 = text6;
							break;
						}
					}
					if (text3 != null)
					{
						break;
					}
				}
			}
		}
		if (text3 != null)
		{
			try
			{
				Sprite val = SemiFunc.LoadSpriteFromFile(text3);
				if ((Object)(object)val != (Object)null)
				{
					_loadedIconCache[text] = val;
					return val;
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[CatCosmetics] Failed to load icon from " + text3 + ": " + ex.Message));
			}
		}
		Sprite val2 = TryLoadFromBundles(array);
		if ((Object)(object)val2 != (Object)null)
		{
			_loadedIconCache[text] = val2;
			return val2;
		}
		return null;
	}

	private IEnumerator GiftCosmeticRoutine()
	{
		float waited = 0f;
		while ((Object)(object)MetaManager.instance == (Object)null || !(bool)_saveReady.GetValue(MetaManager.instance))
		{
			yield return null;
			waited += Time.deltaTime;
			if (waited > 30f)
			{
				Log.LogWarning((object)$"[CatCosmetics] meta save not ready after {waited:F0}s, skipping gifts");
				yield break;
			}
		}
		if (!SteamClient.IsValid)
		{
			yield break;
		}
		string me = SteamClient.SteamId.Value.ToString();
		HashSet<CosmeticAsset> seen = new HashSet<CosmeticAsset>();
		for (int pass = 0; pass < 60; pass++)
		{
			MetaManager instance = MetaManager.instance;
			foreach (CosmeticAsset cosmeticAsset in instance.cosmeticAssets)
			{
				if ((Object)(object)cosmeticAsset == (Object)null || seen.Contains(cosmeticAsset))
				{
					continue;
				}
				string text = (string)_assetId.GetValue(cosmeticAsset);
				if (text != null && text.StartsWith("vanilla:"))
				{
					seen.Add(cosmeticAsset);
					continue;
				}
				GameObject val = ((cosmeticAsset.prefab != null && ((PrefabRef<GameObject>)(object)cosmeticAsset.prefab).IsValid()) ? ((PrefabRef<GameObject>)(object)cosmeticAsset.prefab).Prefab : null);
				if (!((Object)(object)val == (Object)null))
				{
					seen.Add(cosmeticAsset);
					CosmeticGift component = val.GetComponent<CosmeticGift>();
					if (!((Object)(object)component == (Object)null) && component.steamIds != null && Array.Exists(component.steamIds, (string s) => s != null && s.Trim() == me) && !((List<int>)_cosmeticUnlocks.GetValue(instance)).Contains(instance.cosmeticAssets.IndexOf(cosmeticAsset)) && instance.CosmeticUnlock(cosmeticAsset))
					{
						Log.LogInfo((object)("[CatCosmetics] gifted '" + cosmeticAsset.assetName + "' to " + SteamClient.Name + " (" + me + ")"));
					}
				}
			}
			yield return (object)new WaitForSeconds(1f);
		}
	}
}
[HarmonyPatch(typeof(MenuElementCosmeticButton), "LoadIconAsync")]
public static class MenuElementCosmeticButtonLoadIconPatch
{
	private static readonly FieldInfo _cosmeticAssetField = typeof(MenuElementCosmeticButton).GetField("cosmeticAsset", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	[HarmonyPrefix]
	public static void Prefix(MenuElementCosmeticButton __instance)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		if (_cosmeticAssetField == null)
		{
			return;
		}
		CosmeticAsset val = (CosmeticAsset)_cosmeticAssetField.GetValue(__instance);
		if ((Object)(object)val != (Object)null)
		{
			Sprite val2 = CatCosmeticsPlugin.TryGetOrLoadCustomIcon(val);
			if ((Object)(object)val2 != (Object)null && CatCosmeticsPlugin._iconField != null)
			{
				CatCosmeticsPlugin._iconField.SetValue(val, val2);
			}
		}
	}
}
[HarmonyPatch(typeof(Cosmetic), "EquipAnimation")]
public static class CosmeticEquipAnimationPatch
{
	private static readonly FieldInfo _meshParentsScaleField = typeof(Cosmetic).GetField("meshParentsScale", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	[HarmonyPrefix]
	public static bool Prefix(Cosmetic __instance)
	{
		if (__instance.meshParents == null || __instance.meshParents.Count == 0)
		{
			return false;
		}
		if (_meshParentsScaleField != null)
		{
			List<Vector3> list = (List<Vector3>)_meshParentsScaleField.GetValue(__instance);
			if (list == null || list.Count < __instance.meshParents.Count)
			{
				return false;
			}
		}
		return true;
	}
}
[HarmonyPatch(typeof(Cosmetic), "CustomTypesLogic")]
public static class CosmeticCustomTypesPatch
{
	private static readonly FieldInfo _playerCosmeticsField = typeof(Cosmetic).GetField("playerCosmetics", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	[HarmonyPrefix]
	public static bool Prefix(Cosmetic __instance)
	{
		if (_playerCosmeticsField == null)
		{
			return true;
		}
		return _playerCosmeticsField.GetValue(__instance) != null;
	}
}
[HarmonyPatch(typeof(CosmeticBlocked), "CollisionChecksDisabled")]
public static class CosmeticBlockedPatch
{
	private static readonly FieldInfo _cosmeticField = typeof(CosmeticBlocked).GetField("cosmetic", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo _playerCosmeticsField = typeof(Cosmetic).GetField("playerCosmetics", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	[HarmonyPrefix]
	public static bool Prefix(CosmeticBlocked __instance, ref bool __result)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		Cosmetic val = ((!(_cosmeticField != null)) ? ((Cosmetic)null) : ((Cosmetic)_cosmeticField.GetValue(__instance)));
		if ((Object)(object)val == (Object)null)
		{
			__result = true;
			return false;
		}
		if (((_playerCosmeticsField != null) ? _playerCosmeticsField.GetValue(val) : null) == null)
		{
			__result = true;
			return false;
		}
		return true;
	}
}