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 KittyMod v0.0.2
plugins/KittyMod/Kittyo_mod.dll
Decompiled 4 months agousing System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; 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("Kittyo_mod")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Kittyo_mod")] [assembly: AssemblyTitle("Kittyo_mod")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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; } } } public class KittyoAI : EnemyAI { } namespace KittyMod { [BepInPlugin("com.jami.kittymod", "KittyMod", "0.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string ModGUID = "com.jami.kittymod"; public const string ModName = "KittyMod"; public const string ModVersion = "0.0.1"; private ConfigEntry<int> spawnRarity; private ConfigEntry<string> assetBundleName; private ConfigEntry<string> enemyTypeAssetName; private void Awake() { spawnRarity = ((BaseUnityPlugin)this).Config.Bind<int>("Spawn", "Rarity", 999999, "Debug spawn weight. Very high value makes Kittyo dominate the indoor spawn pool for testing."); assetBundleName = ((BaseUnityPlugin)this).Config.Bind<string>("Assets", "AssetBundleName", "kittyo", "Asset bundle file name placed next to Kittyo_mod.dll."); enemyTypeAssetName = ((BaseUnityPlugin)this).Config.Bind<string>("Assets", "EnemyTypeAssetName", "KittyoEnemyType", "EnemyType asset name inside the Kittyo asset bundle."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"KittyMod loaded. Registering Kittyo with debug 100% style spawn settings."); try { RegisterKittyo(); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Kittyo registration failed: {arg}"); } } private void RegisterKittyo() { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Paths.PluginPath, assetBundleName.Value); if (!File.Exists(text)) { ((BaseUnityPlugin)this).Logger.LogError((object)("Kittyo cannot spawn: asset bundle was not found at '" + text + "'.")); return; } EnemyType val = LoadEnemyType(text, enemyTypeAssetName.Value); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)("Kittyo cannot spawn: EnemyType '" + enemyTypeAssetName.Value + "' was not found.")); return; } ConfigureEnemyForGuaranteedIndoorTesting(val); PreparePrefab(val.enemyPrefab); if (!RegisterWithLethalLib(val)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Kittyo cannot spawn: LethalLib RegisterEnemy was not found. Install LethalLib."); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Kittyo registered on all levels as indoor enemy with rarity {spawnRarity.Value}."); } } private static void ConfigureEnemyForGuaranteedIndoorTesting(EnemyType enemyType) { SetFieldOrProperty(enemyType, "isOutsideEnemy", false); SetFieldOrProperty(enemyType, "isDaytimeEnemy", false); SetFieldOrProperty(enemyType, "PowerLevel", 0f); SetFieldOrProperty(enemyType, "MaxCount", 20); SetFieldOrProperty(enemyType, "spawnInGroupsOf", 1); SetFieldOrProperty(enemyType, "numberSpawned", 0); } private static void PreparePrefab(GameObject prefab) { if (!((Object)(object)prefab == (Object)null)) { if ((Object)(object)prefab.GetComponent<KittyoAI>() == (Object)null) { prefab.AddComponent<KittyoAI>(); } AddComponentIfAvailable(prefab, "Unity.Netcode.NetworkObject, Unity.Netcode.Runtime"); AddComponentIfAvailable(prefab, "UnityEngine.AI.NavMeshAgent, UnityEngine.AIModule"); } } private static void AddComponentIfAvailable(GameObject target, string assemblyQualifiedTypeName) { Type type = Type.GetType(assemblyQualifiedTypeName); if (!(type == null) && typeof(Component).IsAssignableFrom(type) && (Object)(object)target.GetComponent(type) == (Object)null) { target.AddComponent(type); } } private static EnemyType? LoadEnemyType(string bundlePath, string assetName) { Type type = Type.GetType("UnityEngine.AssetBundle, UnityEngine.AssetBundleModule"); object obj = (type?.GetMethod("LoadFromFile", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null))?.Invoke(null, new object[1] { bundlePath }); if (obj == null || type == null) { return null; } object? obj2 = type.GetMethod("LoadAsset", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(string), typeof(Type) }, null)?.Invoke(obj, new object[2] { assetName, typeof(EnemyType) }); return (EnemyType?)((obj2 is EnemyType) ? obj2 : null); } private bool RegisterWithLethalLib(EnemyType enemyType) { Type type = FindType("LethalLib.Modules.Enemies"); Type type2 = FindType("LethalLib.Modules.Levels"); if (type == null || type2 == null) { return false; } Type nestedType = type2.GetNestedType("LevelTypes", BindingFlags.Public); if (nestedType == null) { return false; } MethodInfo methodInfo = FindRegisterEnemy(type, nestedType); if (methodInfo == null) { return false; } TerminalNode val = ScriptableObject.CreateInstance<TerminalNode>(); val.creatureName = "Kittyo"; val.displayText = "Kittyo\n\nA suspiciously cute house cat.\n"; TerminalKeyword val2 = ScriptableObject.CreateInstance<TerminalKeyword>(); val2.word = "kittyo"; object enumValue = GetEnumValue(nestedType, new string[3] { "All", "AllLevels", "Vanilla" }); object[] parameters = BuildRegisterArguments(methodInfo, enemyType, enumValue, val, val2); methodInfo.Invoke(null, parameters); return true; } private object?[] BuildRegisterArguments(MethodInfo registerEnemy, EnemyType enemyType, object allLevels, TerminalNode terminalNode, TerminalKeyword terminalKeyword) { ParameterInfo[] parameters = registerEnemy.GetParameters(); if (parameters.Length == 6) { object enumValue = GetEnumValue(parameters[3].ParameterType, new string[3] { "Inside", "Indoor", "Default" }); return new object[6] { enemyType, spawnRarity.Value, allLevels, enumValue, terminalNode, terminalKeyword }; } return new object[5] { enemyType, spawnRarity.Value, allLevels, terminalNode, terminalKeyword }; } private static MethodInfo? FindRegisterEnemy(Type enemiesType, Type levelTypesType) { MethodInfo result = null; MethodInfo[] methods = enemiesType.GetMethods(BindingFlags.Static | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != "RegisterEnemy")) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 6 && parameters[0].ParameterType == typeof(EnemyType) && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == levelTypesType && parameters[4].ParameterType == typeof(TerminalNode) && parameters[5].ParameterType == typeof(TerminalKeyword)) { return methodInfo; } if (parameters.Length == 5 && parameters[0].ParameterType == typeof(EnemyType) && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == levelTypesType && parameters[3].ParameterType == typeof(TerminalNode) && parameters[4].ParameterType == typeof(TerminalKeyword)) { result = methodInfo; } } } return result; } private static Type? FindType(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType(fullName); if (type != null) { return type; } } return Type.GetType(fullName); } private static object GetEnumValue(Type enumType, string[] preferredNames) { foreach (string value in preferredNames) { if (Enum.IsDefined(enumType, value)) { return Enum.Parse(enumType, value); } } return Enum.GetValues(enumType).GetValue(0); } private static void SetFieldOrProperty(object target, string name, object value) { Type type = target.GetType(); FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value2 = ConvertValue(value, field.FieldType); field.SetValue(target, value2); return; } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { object value3 = ConvertValue(value, property.PropertyType); property.SetValue(target, value3); } } private static object ConvertValue(object value, Type targetType) { if (targetType.IsInstanceOfType(value)) { return value; } if (targetType == typeof(int)) { return Convert.ToInt32(value); } if (targetType == typeof(float)) { return Convert.ToSingle(value); } if (targetType == typeof(bool)) { return Convert.ToBoolean(value); } return value; } } }