Decompiled source of KittyMod v0.0.2

plugins/KittyMod/Kittyo_mod.dll

Decompiled 4 months ago
using 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;
		}
	}
}