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 Cats v1.5.1
Cats.dll
Decompiled 3 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using REPOLib.Modules; 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 Cats; internal enum Rarity { Common, Uncommon, Rare } public class MaterialVariants : MonoBehaviour { public Material[] variants; } [BepInPlugin("eberk30.cats", "Cats", "1.4.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class CatsPlugin : BaseUnityPlugin { [CompilerGenerated] private sealed class <AssignCatNames>d__26 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private float <waited>5__2; private int <expected>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <AssignCatNames>d__26(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: { <>1__state = -1; int num = PhotonNetwork.PlayerList.Length - 1; Log.LogDebug((object)$"[Cats] requesting configs from {num} other player(s)"); RequestConfigsEvent.RaiseEvent((object)"", NetworkingEvents.RaiseOthers, SendOptions.SendReliable); <waited>5__2 = 0f; <expected>5__3 = PhotonNetwork.PlayerList.Length; break; } case 2: <>1__state = -1; <waited>5__2 += Time.deltaTime; break; } if (_receivedConfigs.Count < <expected>5__3 && <waited>5__2 < 8f) { <>2__current = null; <>1__state = 2; return true; } if (<waited>5__2 >= 8f) { Log.LogWarning((object)$"[Cats] timed out waiting for name configs ({_receivedConfigs.Count}/{<expected>5__3})"); } StringBuilder stringBuilder = new StringBuilder(); ValuableObject[] array = Object.FindObjectsOfType<ValuableObject>(); foreach (ValuableObject val in array) { string catType = GetCatType(((Object)((Component)val).gameObject).name); if (catType == null) { continue; } PhotonView component = ((Component)val).GetComponent<PhotonView>(); if ((Object)(object)component == (Object)null) { continue; } List<string> list = new List<string>(); foreach (string value2 in _receivedConfigs.Values) { list.AddRange(GetNamesFromConfig(value2, catType)); } if (list.Count != 0) { string value = list[Random.Range(0, list.Count)]; AssignedNames[component.ViewID] = value; if (stringBuilder.Length > 0) { stringBuilder.Append('|'); } stringBuilder.Append(component.ViewID).Append('=').Append(value); } } if (stringBuilder.Length > 0) { AssignNamesEvent.RaiseEvent((object)stringBuilder.ToString(), NetworkingEvents.RaiseAll, SendOptions.SendReliable); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <BakeItemAttributesIntoCatPrefabs>d__10 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private int <expected>5__2; private float <waited>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <BakeItemAttributesIntoCatPrefabs>d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <expected>5__2 = CatTypes.Count; <waited>5__3 = 0f; break; case 1: <>1__state = -1; <waited>5__3 += 0.25f; break; } if (<waited>5__3 < 10f) { int num = 0; foreach (PrefabRef registeredValuable in Valuables.RegisteredValuables) { if (CatTypes.ContainsKey(registeredValuable.PrefabName) && !((Object)(object)registeredValuable.Prefab == (Object)null)) { if ((Object)(object)registeredValuable.Prefab.GetComponent<ItemAttributes>() == (Object)null) { registeredValuable.Prefab.AddComponent<ItemAttributes>(); } num++; } } if (num >= <expected>5__2) { return false; } <>2__current = (object)new WaitForSeconds(0.25f); <>1__state = 1; return true; } Log.LogWarning((object)"[Cats] bake timed out, some cats may desync for late joiners"); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static CatsPlugin Instance; internal static ManualLogSource Log; public static ConfigEntry<bool> ControlledSpawning; public static ConfigEntry<int> SpawnCount; public static ConfigEntry<float> CommonWeight; public static ConfigEntry<float> UncommonWeight; public static ConfigEntry<float> RareWeight; internal static readonly Dictionary<string, ConfigEntry<string>> CatDisplayNames = new Dictionary<string, ConfigEntry<string>>(); internal static readonly Dictionary<string, Rarity> CatTypes = new Dictionary<string, Rarity> { { "Black Cat", Rarity.Common }, { "Siamese", Rarity.Common }, { "Russian Blue", Rarity.Common }, { "White Cat", Rarity.Common }, { "Calico", Rarity.Common }, { "Blue Point", Rarity.Common }, { "Gray Tabby", Rarity.Common }, { "Orange Tabby", Rarity.Common }, { "Scottish Fold", Rarity.Common }, { "Photosynthesis Cat", Rarity.Uncommon }, { "Tuxedo", Rarity.Uncommon }, { "Pink Cat", Rarity.Uncommon }, { "Cyberpunk Cat", Rarity.Uncommon }, { "Tortoise", Rarity.Uncommon }, { "Sphynx", Rarity.Rare }, { "Alien Cat", Rarity.Rare }, { "Gold Cat Statue", Rarity.Rare }, { "Galaxy Cat", Rarity.Rare } }; public static NetworkedEvent ShareNamesEvent; public static NetworkedEvent AssignNamesEvent; public static NetworkedEvent RequestConfigsEvent; private static readonly Dictionary<int, string> _receivedConfigs = new Dictionary<int, string>(); internal static readonly Dictionary<int, string> AssignedNames = new Dictionary<int, string>(); private static bool _sentThisLevel = false; private static string _lastLevel = ""; private void Awake() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Expected O, but got Unknown //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Expected O, but got Unknown //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Expected O, but got Unknown //IL_01d4: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; ControlledSpawning = ((BaseUnityPlugin)this).Config.Bind<bool>("Controlled Spawning", "Controlled Spawning", false, "Take over spawning. On = Control spawning using count/weight settings below; Off = let the game spawn cats normally."); SpawnCount = ((BaseUnityPlugin)this).Config.Bind<int>("Controlled Spawning", "Spawn Count", 3, new ConfigDescription("How many cats appear per level.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>())); CommonWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Controlled Spawning", "Common Weight", 1f, new ConfigDescription("Black Cat, Blue Point, Calico, Gray Tabby, Orange Tabby, Russian Blue, Scottish Fold, Siamese, White Cat", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); UncommonWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Controlled Spawning", "Uncommon Weight", 0.35f, new ConfigDescription("Cyberpunk Cat, Photosynthesis Cat, Pink Cat, Tortoise, Tuxedo", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); RareWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Controlled Spawning", "Rare Weight", 0.1f, new ConfigDescription("Alien Cat, Galaxy Cat, Gold Cat Statue, Sphynx", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); foreach (string key in CatTypes.Keys) { CatDisplayNames[key] = ((BaseUnityPlugin)this).Config.Bind<string>("Cat Names", key, "", "Name shown when holding " + key + ". Comma-separate for random pick: Bob, Bill. Leave blank for no name."); } ShareNamesEvent = new NetworkedEvent("CatsShareNames", (Action<EventData>)OnShareNames); AssignNamesEvent = new NetworkedEvent("CatsAssignNames", (Action<EventData>)OnAssignNames); RequestConfigsEvent = new NetworkedEvent("CatsRequestCfgs", (Action<EventData>)OnRequestConfigs); new Harmony("eberk30.cats").PatchAll(); ((MonoBehaviour)this).StartCoroutine(BakeItemAttributesIntoCatPrefabs()); } [IteratorStateMachine(typeof(<BakeItemAttributesIntoCatPrefabs>d__10))] private IEnumerator BakeItemAttributesIntoCatPrefabs() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <BakeItemAttributesIntoCatPrefabs>d__10(0); } internal static string GetCatType(string name) { foreach (string key in CatTypes.Keys) { if (name.Contains(key)) { return key; } } return null; } internal static bool IsCat(string name) { return GetCatType(name) != null; } private static void OnShareNames(EventData photonEvent) { if (photonEvent.CustomData is string text) { _receivedConfigs[photonEvent.Sender] = text; Log.LogDebug((object)$"[Cats] got config from actor {photonEvent.Sender} ({text.Length} bytes)"); } } private static void OnRequestConfigs(EventData photonEvent) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) Log.LogDebug((object)$"[Cats] received config request (isMaster={SemiFunc.IsMasterClientOrSingleplayer()})"); if (!SemiFunc.IsMasterClientOrSingleplayer()) { ShareNamesEvent.RaiseEvent((object)PackConfig(), NetworkingEvents.RaiseMasterClient, SendOptions.SendReliable); Log.LogDebug((object)"[Cats] replied with config"); } } private static void OnAssignNames(EventData photonEvent) { if (!(photonEvent.CustomData is string text)) { return; } string[] array = text.Split(new char[1] { '|' }); foreach (string text2 in array) { int num = text2.IndexOf('='); if (num >= 0) { if (!int.TryParse(text2.Substring(0, num), out var result)) { Log.LogWarning((object)("[Cats] couldn't parse viewID: " + text2)); } else { AssignedNames[result] = text2.Substring(num + 1); } } } ValuableObject[] array2 = Object.FindObjectsOfType<ValuableObject>(); foreach (ValuableObject val in array2) { PhotonView component = ((Component)val).GetComponent<PhotonView>(); if (!((Object)(object)component == (Object)null) && AssignedNames.TryGetValue(component.ViewID, out var value)) { ItemAttributes component2 = ((Component)val).GetComponent<ItemAttributes>(); if ((Object)(object)component2 != (Object)null && (Object)(object)component2.item != (Object)null) { component2.item.itemName = value; } } } } private static string PackConfig() { return string.Join("|", CatDisplayNames.Select((KeyValuePair<string, ConfigEntry<string>> kvp) => kvp.Key + "=" + kvp.Value.Value)); } internal static void TrySendConfig() { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) RunManager instance = RunManager.instance; object obj; if (instance == null) { obj = null; } else { Level levelCurrent = instance.levelCurrent; obj = ((levelCurrent != null) ? ((Object)levelCurrent).name : null); } if (obj == null) { obj = ""; } Room currentRoom = PhotonNetwork.CurrentRoom; string text = (string?)obj + "|" + ((currentRoom != null) ? currentRoom.Name : null); if (text != _lastLevel) { _lastLevel = text; _sentThisLevel = false; AssignedNames.Clear(); if (SemiFunc.IsMasterClientOrSingleplayer()) { _receivedConfigs.Clear(); } } if (!_sentThisLevel && PhotonNetwork.InRoom) { _sentThisLevel = true; if (SemiFunc.IsMasterClientOrSingleplayer()) { _receivedConfigs[PhotonNetwork.LocalPlayer.ActorNumber] = PackConfig(); Log.LogDebug((object)"[Cats] host stored own config"); } else { ShareNamesEvent.RaiseEvent((object)PackConfig(), NetworkingEvents.RaiseMasterClient, SendOptions.SendReliable); Log.LogDebug((object)"[Cats] client sent config to master"); } } } private static List<string> GetNamesFromConfig(string serialized, string catType) { List<string> list = new List<string>(); string text = catType + "="; string[] array = serialized.Split(new char[1] { '|' }); foreach (string text2 in array) { if (!text2.StartsWith(text)) { continue; } string[] array2 = text2.Substring(text.Length).Split(new char[1] { ',' }); for (int j = 0; j < array2.Length; j++) { string text3 = array2[j].Trim(); if (text3.Length > 0) { list.Add(text3); } } break; } return list; } [IteratorStateMachine(typeof(<AssignCatNames>d__26))] internal IEnumerator AssignCatNames() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <AssignCatNames>d__26(0); } } [HarmonyPatch(typeof(ValuableObject), "Start")] internal static class CatAttributesPatch { [HarmonyPostfix] private static void Postfix(ValuableObject __instance) { if (CatsPlugin.IsCat(((Object)((Component)__instance).gameObject).name) && !((Object)(object)((Component)__instance).gameObject.GetComponent<ItemAttributes>() != (Object)null)) { ((Component)__instance).gameObject.AddComponent<ItemAttributes>(); } } } [HarmonyPatch(typeof(ItemAttributes), "Awake")] internal static class CatItemAwakePatch { [HarmonyPostfix] private static void Postfix(ItemAttributes __instance) { string catType = CatsPlugin.GetCatType(((Object)((Component)__instance).gameObject).name); if (catType == null) { return; } CatsPlugin.TrySendConfig(); if ((Object)(object)__instance.item != (Object)null) { return; } Item val = ScriptableObject.CreateInstance<Item>(); val.value = ScriptableObject.CreateInstance<Value>(); PhotonView component = ((Component)__instance).GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null && CatsPlugin.AssignedNames.TryGetValue(component.ViewID, out var value)) { val.itemName = value; } else { ConfigEntry<string> value2; string[] array = (from s in (CatsPlugin.CatDisplayNames.TryGetValue(catType, out value2) ? value2.Value : "").Split(new char[1] { ',' }) select s.Trim() into s where s.Length > 0 select s).ToArray(); val.itemName = ((array.Length != 0) ? array[Random.Range(0, array.Length)] : ""); } __instance.item = val; if (!((Object)(object)component != (Object)null)) { return; } MaterialVariants componentInChildren = ((Component)__instance).GetComponentInChildren<MaterialVariants>(); if ((Object)(object)componentInChildren != (Object)null && componentInChildren.variants != null && componentInChildren.variants.Length != 0) { Renderer componentInChildren2 = ((Component)__instance).GetComponentInChildren<Renderer>(); if ((Object)(object)componentInChildren2 != (Object)null) { int num = Mathf.Abs(component.ViewID) % componentInChildren.variants.Length; componentInChildren2.material = componentInChildren.variants[num]; } } } } [HarmonyPatch(typeof(ItemAttributes), "Start")] internal static class CatItemStartPatch { [HarmonyPrefix] private static void Prefix(ItemAttributes __instance) { if (CatsPlugin.GetCatType(((Object)((Component)__instance).gameObject).name) != null) { CatsPlugin.TrySendConfig(); if (!((Object)(object)__instance.item != (Object)null)) { Item val = ScriptableObject.CreateInstance<Item>(); val.value = ScriptableObject.CreateInstance<Value>(); val.itemName = ""; __instance.item = val; } } } [HarmonyPostfix] private static void Postfix(ItemAttributes __instance) { if (CatsPlugin.GetCatType(((Object)((Component)__instance).gameObject).name) != null) { ItemManager instance = ItemManager.instance; if ((Object)(object)instance != (Object)null) { instance.spawnedItems.Remove(__instance); } } } } [HarmonyPatch(typeof(ItemAttributes), "ShowingInfo")] internal static class CatNamePatch { private static FieldInfo _promptNameField; [HarmonyPostfix] private static void Postfix(ItemAttributes __instance) { if ((Object)(object)__instance.item == (Object)null) { return; } string name = ((Object)((Component)__instance).gameObject).name; foreach (string key in CatsPlugin.CatTypes.Keys) { if (name.Contains(key)) { if (_promptNameField == null) { _promptNameField = typeof(ItemAttributes).GetField("promptName", BindingFlags.Instance | BindingFlags.NonPublic); } _promptNameField?.SetValue(__instance, __instance.item.itemName); break; } } } } [HarmonyPatch(typeof(ItemToggle), "ToggleItemLogic")] internal static class EPressPlaySoundPatch { [HarmonyPostfix] private static void Postfix(ItemToggle __instance, bool toggle) { if (!toggle || !CatsPlugin.IsCat(((Object)((Component)__instance).gameObject).name)) { return; } PhysGrabObject component = ((Component)__instance).GetComponent<PhysGrabObject>(); if (!((Object)(object)component == (Object)null) && component.grabbedLocal) { AudioSource component2 = ((Component)__instance).GetComponent<AudioSource>(); if ((Object)(object)component2 != (Object)null) { component2.Play(); } } } } [HarmonyPatch(typeof(ValuableDirector), "SetupHost")] internal static class SpawnPatch { [HarmonyPostfix] private static void Postfix() { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } RunManager instance = RunManager.instance; Level levelCurrent = instance.levelCurrent; if ((Object)(object)levelCurrent == (Object)(object)instance.levelMainMenu || (Object)(object)levelCurrent == (Object)(object)instance.levelLobbyMenu || (Object)(object)levelCurrent == (Object)(object)instance.levelLobby || !PhotonNetwork.InRoom) { return; } CatsPlugin.TrySendConfig(); if (!CatsPlugin.ControlledSpawning.Value) { ((MonoBehaviour)CatsPlugin.Instance).StartCoroutine(CatsPlugin.Instance.AssignCatNames()); return; } List<PrefabRef> list = Valuables.RegisteredValuables.Where((PrefabRef v) => CatsPlugin.CatTypes.ContainsKey(v.PrefabName)).ToList(); if (list.Count == 0) { return; } Dictionary<Type, List<ValuableVolume>> dictionary = new Dictionary<Type, List<ValuableVolume>>(); ValuableVolume[] array = Object.FindObjectsOfType<ValuableVolume>(); foreach (ValuableVolume val in array) { if (!dictionary.ContainsKey(val.VolumeType)) { dictionary[val.VolumeType] = new List<ValuableVolume>(); } dictionary[val.VolumeType].Add(val); } int num = 0; List<Vector3> occupied = new List<Vector3>(); ValuableObject[] array2 = Object.FindObjectsOfType<ValuableObject>(); foreach (ValuableObject val2 in array2) { occupied.Add(((Component)val2).transform.position); if (CatsPlugin.IsCat(((Object)((Component)val2).gameObject).name)) { num++; } } if (num >= CatsPlugin.SpawnCount.Value) { return; } foreach (List<ValuableVolume> value2 in dictionary.Values) { value2.RemoveAll(delegate(ValuableVolume v) { //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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_0022: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)v).transform.position; for (int l = 0; l < occupied.Count; l++) { Vector3 val5 = occupied[l] - position; if (((Vector3)(ref val5)).sqrMagnitude < 1f) { return true; } } return false; }); } List<int> list2 = new List<int>(); for (int j = 0; j < list.Count; j++) { int num2 = Mathf.Max(1, Mathf.RoundToInt(GetWeight(list[j].PrefabName) * 10f)); for (int k = 0; k < num2; k++) { list2.Add(j); } } int num3 = CatsPlugin.SpawnCount.Value - num; int num4 = 0; int num5 = 0; while (num4 < num3 && num5 < 20) { num5++; int index = list2[Random.Range(0, list2.Count)]; PrefabRef val3 = list[index]; ValuableObject val4 = (((Object)(object)val3.Prefab != (Object)null) ? val3.Prefab.GetComponent<ValuableObject>() : null); if (!((Object)(object)val4 == (Object)null) && dictionary.TryGetValue(val4.volumeType, out var value) && value.Count != 0) { int index2 = Random.Range(0, value.Count); CatsPlugin.Log.LogInfo((object)("[Cats] spawning " + val3.PrefabName + " into " + ((Object)value[index2]).name)); Valuables.SpawnValuable(val3, ((Component)value[index2]).transform.position, ((Component)value[index2]).transform.rotation); value.RemoveAt(index2); num4++; } } if (num4 > 0) { ((MonoBehaviour)CatsPlugin.Instance).StartCoroutine(CatsPlugin.Instance.AssignCatNames()); } } private static float GetWeight(string name) { if (!CatsPlugin.CatTypes.TryGetValue(name, out var value)) { return CatsPlugin.CommonWeight.Value; } return value switch { Rarity.Rare => CatsPlugin.RareWeight.Value, Rarity.Uncommon => CatsPlugin.UncommonWeight.Value, _ => CatsPlugin.CommonWeight.Value, }; } }