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 Cat Cosmetics v1.4.0
CatCosmetics.dll
Decompiled a week agousing 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; } }