using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Photon.Pun; using UnityEngine; using com.github.zehsteam.MetadataUtils.Extensions; using com.github.zehsteam.MetadataUtils.Objects; using com.github.zehsteam.PlayerDamageTracker.Extensions; using com.github.zehsteam.PlayerDamageTracker.Helpers; using com.github.zehsteam.PlayerDamageTracker.Modules; using com.github.zehsteam.PlayerDamageTracker.MonoBehaviours; using com.github.zehsteam.PlayerDamageTracker.Patches; [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("Zehs")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2026 Zehs")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0+93b733fc51d3908dc7613f65dfd81b662bb274ab")] [assembly: AssemblyProduct("PlayerDamageTracker")] [assembly: AssemblyTitle("com.github.zehsteam.PlayerDamageTracker")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [CompilerGenerated] internal sealed class <>z__ReadOnlyList : IEnumerable, ICollection, IList, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { int ICollection.Count => _items.Count; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection.Count => _items.Count; T IReadOnlyList.this[int index] => _items[index]; int ICollection.Count => _items.Count; bool ICollection.IsReadOnly => true; T IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyList(List items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return _items.Contains(item); } void ICollection.CopyTo(T[] array, int arrayIndex) { _items.CopyTo(array, arrayIndex); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { return _items.IndexOf(item); } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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; } } } namespace com.github.zehsteam.PlayerDamageTracker { internal static class Logger { public static ManualLogSource ManualLogSource { get; private set; } public static void Initialize(ManualLogSource manualLogSource) { ManualLogSource = manualLogSource; } public static void LogDebug(object data) { Log((LogLevel)32, data); } public static void LogInfo(object data) { Log((LogLevel)16, data); } public static void LogMessage(object data) { Log((LogLevel)8, data); } public static void LogWarning(object data) { Log((LogLevel)4, data); } public static void LogError(object data) { Log((LogLevel)2, data); } public static void LogFatal(object data) { Log((LogLevel)1, data); } public static void Log(LogLevel logLevel, object data) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) ManualLogSource manualLogSource = ManualLogSource; if (manualLogSource != null) { manualLogSource.Log(logLevel, data); } } } [BepInPlugin("com.github.zehsteam.PlayerDamageTracker", "PlayerDamageTracker", "1.2.0")] internal class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("com.github.zehsteam.PlayerDamageTracker"); internal static Plugin Instance { get; private set; } private void Awake() { Instance = this; Logger.Initialize(Logger.CreateLogSource("com.github.zehsteam.PlayerDamageTracker")); Logger.LogInfo("PlayerDamageTracker has awoken!"); ((Object)this).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)this); _harmony.PatchAll(typeof(PlayerHealthPatch)); _harmony.PatchAll(typeof(HurtColliderPatch)); _harmony.PatchAll(typeof(ParticleScriptExplosionPatch)); _harmony.PatchAll(typeof(ItemGrenadeDuctTapedPatch)); PluginHelper.OnStart = (Action)Delegate.Combine(PluginHelper.OnStart, (Action)delegate { HurtOtherPatcher.PatchAll(_harmony); }); PluginHelper.Spawn(); } private void Start() { HurtOtherPatcher.PatchAll(_harmony); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "com.github.zehsteam.PlayerDamageTracker"; public const string PLUGIN_NAME = "PlayerDamageTracker"; public const string PLUGIN_VERSION = "1.2.0"; } } namespace com.github.zehsteam.PlayerDamageTracker.Patches { [HarmonyPatch(typeof(HurtCollider))] internal static class HurtColliderPatch { [HarmonyPatch("PlayerHurt")] [HarmonyTranspiler] private static IEnumerable PlayerHurtTranspiler(IEnumerable instructions) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown string text = "[HurtColliderPatch] PlayerHurt transpiler:"; MethodInfo methodInfo = AccessTools.Method(typeof(PlayerHealth), "Hurt", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PlayerHealthExtensions), "HurtWithCaller", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { Logger.LogError(text + " Failed to create transpiler. Required methods not found."); return instructions; } List list = new List(); foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, methodInfo)) { list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2)); Logger.LogDebug(text + " Replaced calls to " + methodInfo.Name + " with " + methodInfo2.Name); } else { list.Add(instruction); } } Logger.LogInfo(text + " Created transpiler!"); return list.AsEnumerable(); } } internal static class HurtOtherPatcher { private static readonly MethodInfo _hurtOtherMethod = AccessTools.Method(typeof(PlayerHealth), "HurtOther", (Type[])null, (Type[])null); private static readonly FieldInfo _hurtOtherCallerField = AccessTools.Field(typeof(PlayerHealthPatch), "HurtOtherCaller"); private static int _transpilersCreated; private static bool _patched; public static int TranspilersCreated => _transpilersCreated; public static void PatchAll(Harmony harmony) { if (_patched) { return; } _patched = true; LogInfo("Running patcher..."); if (_hurtOtherMethod == null) { LogError("Required methods not found for patcher."); return; } IEnumerable validAssemblies = GetValidAssemblies(); LogInfo($"Found {validAssemblies.Count()} valid assemblies."); foreach (Assembly item in validAssemblies) { LogDebug("Found assembly: " + item.FullName); } _transpilersCreated = 0; Parallel.ForEach(validAssemblies, delegate(Assembly assembly) { PatchAssembly(assembly, harmony); }); LogInfo($"Created {_transpilersCreated} transpilers."); LogInfo("Patcher finished."); } private static void PatchAssembly(Assembly assembly, Harmony harmony) { LogDebug("Patching assembly: " + assembly.FullName); IEnumerable validClasses = GetValidClasses(assembly); Parallel.ForEach(validClasses, delegate(Type type) { PatchClass(type, harmony); }); } private static void PatchClass(Type type, Harmony harmony) { LogDebug("Patching class: " + type.FullName); IEnumerable validMethods = GetValidMethods(type); Parallel.ForEach(validMethods, delegate(MethodInfo method) { PatchMethod(method, harmony); }); } private static void PatchMethod(MethodInfo method, Harmony harmony) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown try { if (ReflectionHelper.IsCoroutineMethod(method)) { MethodInfo coroutineMoveNextMethod = ReflectionHelper.GetCoroutineMoveNextMethod(method); if (coroutineMoveNextMethod == null) { return; } harmony.Patch((MethodBase)coroutineMoveNextMethod, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(HurtOtherPatcher), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); LogDebug($"Patched coroutine: {coroutineMoveNextMethod}"); } else { harmony.Patch((MethodBase)method, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(HurtOtherPatcher), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); LogDebug("Patched method: " + method.Name); } LogInfo("Created transpiler for " + method.GetFullName()); Interlocked.Increment(ref _transpilersCreated); } catch (Exception arg) { LogError($"Failed to patch method: {method}\n\n{arg}"); } } private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown if (_hurtOtherMethod == null) { LogError("Required methods not found for transpiler."); return instructions; } List list = new List(instructions); for (int num = list.Count - 1; num >= 0; num--) { CodeInstruction val = list[num]; if (CodeInstructionExtensions.Calls(val, _hurtOtherMethod)) { int num2 = ILHelper.FindArgLoadStart(list, _hurtOtherMethod, num); list.Insert(num2, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(num2 + 1, new CodeInstruction(OpCodes.Stsfld, (object)_hurtOtherCallerField)); } } return list.AsEnumerable(); } private static IEnumerable GetValidAssemblies() { List list = new List(); list.Add(typeof(MenuManager).Assembly); list.AddRange(DependencyHelper.GetModAssemblies()); return new <>z__ReadOnlyList(list); } private static IEnumerable GetValidClasses(Assembly assembly) { if (assembly == null) { return Array.Empty(); } try { return assembly.GetLoadableTypes().Where(IsValidClass); } catch (Exception ex) { LogWarning("Error loading types from assembly " + assembly.FullName + ": " + ex.Message); return Array.Empty(); } } private static bool IsValidClass(Type type) { try { if (type == null) { return false; } if (!type.IsClass || type.IsAbstract) { return false; } if (type == typeof(PlayerHealth)) { return false; } if (typeof(MonoBehaviour).IsAssignableFrom(type)) { return true; } return false; } catch (Exception ex) { LogWarning("Error loading type " + type.FullName + " from assembly " + type.Assembly.FullName + ": " + ex.Message); return false; } } private static IEnumerable GetValidMethods(Type type) { return type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(IsValidMethod); } private static bool IsValidMethod(MethodInfo method) { if (method == null) { return false; } if (method.IsGenericMethod || method.DeclaringType.IsGenericType) { return false; } return ILHelper.MethodCallsMethod(method, _hurtOtherMethod); } private static void LogDebug(object data) { Log((LogLevel)32, data); } private static void LogInfo(object data) { Log((LogLevel)16, data); } private static void LogWarning(object data) { Log((LogLevel)4, data); } private static void LogError(object data) { Log((LogLevel)2, data); } private static void Log(LogLevel logLevel, object data) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Logger.Log(logLevel, string.Format("[{0}] {1}", "HurtOtherPatcher", data)); } } [HarmonyPatch(typeof(ItemGrenadeDuctTaped))] internal static class ItemGrenadeDuctTapedPatch { [HarmonyPatch("Explosion")] [HarmonyTranspiler] private static IEnumerable ExplosionTranspiler(IEnumerable instructions) { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Expected O, but got Unknown string text = "[ItemGrenadeDuctTapedPatch] [Explosion transpiler:"; MethodInfo methodInfo = AccessTools.Method(typeof(Object), "Instantiate", new Type[3] { typeof(GameObject), typeof(Vector3), typeof(Quaternion) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(ItemGrenadeDuctTapedPatch), "InstantiateReplacement", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(PhotonNetwork), "Instantiate", (Type[])null, (Type[])null); MethodInfo methodInfo4 = AccessTools.Method(typeof(ItemGrenadeDuctTapedPatch), "PhotonNetworkInstantiateReplacement", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null) { Logger.LogError(text + " Failed to create transpiler. Required methods not found."); return instructions; } List list = new List(); foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, methodInfo)) { list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2)); Logger.LogDebug(text + " Replaced calls to " + methodInfo.Name + " with " + methodInfo2.Name); } else if (CodeInstructionExtensions.Calls(instruction, methodInfo3)) { list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo4)); Logger.LogDebug(text + " Replaced calls to " + methodInfo3.Name + " with " + methodInfo4.Name); } else { list.Add(instruction); } } Logger.LogInfo(text + " Created transpiler!"); return list.AsEnumerable(); } private static GameObject InstantiateReplacement(GameObject prefab, Vector3 position, Quaternion rotation, object caller = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate(prefab, position, rotation); AddMetadata(caller, val); return val; } private static GameObject PhotonNetworkInstantiateReplacement(string prefabName, Vector3 position, Quaternion rotation, byte group = 0, object[] data = null, object caller = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) GameObject val = PhotonNetwork.Instantiate(prefabName, position, rotation, group, data); AddMetadata(caller, val); return val; } private static void AddMetadata(object caller, GameObject gameObject) { if (caller != null && !((Object)(object)gameObject == (Object)null)) { ItemGrenadeDuctTaped val = (ItemGrenadeDuctTaped)((caller is ItemGrenadeDuctTaped) ? caller : null); PhysGrabObject val2 = default(PhysGrabObject); PhysGrabObject val3 = default(PhysGrabObject); if (val != null && ((Component)val).TryGetComponent(ref val2) && ComponentExtensions.HasMetadata((Component)(object)val2, true) && gameObject.TryGetComponent(ref val3)) { Metadata orCreateMetadata = ComponentExtensions.GetOrCreateMetadata((Component)(object)val2, true); Metadata orCreateMetadata2 = ComponentExtensions.GetOrCreateMetadata((Component)(object)val3, true); orCreateMetadata2.Set(orCreateMetadata); } } } } [HarmonyPatch(typeof(ParticleScriptExplosion))] internal static class ParticleScriptExplosionPatch { private class Cleanup : MonoBehaviour { private ParticlePrefabExplosion _particlePrefabExplosion; private void Awake() { _particlePrefabExplosion = ((Component)this).GetComponent(); } private void OnDestroy() { Explosions.Remove(_particlePrefabExplosion.HurtCollider); } } public static Dictionary Explosions { get; private set; } = new Dictionary(); [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch(ParticleScriptExplosion __instance) { Metadata val = null; PhysGrabObject val2 = default(PhysGrabObject); if (((Component)__instance).TryGetComponent(ref val2) && ComponentExtensions.HasMetadata((Component)(object)val2, true)) { val = ComponentExtensions.GetOrCreateMetadata((Component)(object)val2, true); } EnemyBang val3 = default(EnemyBang); if (((Component)__instance).TryGetComponent(ref val3) && ComponentExtensions.HasMetadata((Component)(object)val3, true)) { val = ComponentExtensions.GetOrCreateMetadata((Component)(object)val3, true); } if (val != null) { Metadata orCreateMetadata = ComponentExtensions.GetOrCreateMetadata((Component)(object)__instance, true); orCreateMetadata.Set("ParentMetadata", val); } } [HarmonyPatch("Spawn")] [HarmonyPostfix] private static void SpawnPatch(ParticleScriptExplosion __instance, ref ParticlePrefabExplosion __result) { Metadata val = default(Metadata); Metadata value = default(Metadata); if (ComponentExtensions.TryGetMetadata((Component)(object)__instance, ref val, true) && val.TryGet("ParentMetadata", ref value)) { Explosions[__result.HurtCollider] = value; ((Component)__result).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(PlayerHealth))] internal static class PlayerHealthPatch { public static object HurtOtherCaller; [HarmonyPatch("HurtOther")] [HarmonyTranspiler] private static IEnumerable HurtOtherTranspiler(IEnumerable instructions) { return GetHurtOtherTranspilerInstructions("[PlayerHealthPatch] HurtOther transpiler:", instructions); } [HarmonyPatch("HurtOtherRPC")] [HarmonyTranspiler] private static IEnumerable HurtOtherRPCTranspiler(IEnumerable instructions) { return GetHurtOtherTranspilerInstructions("[PlayerHealthPatch] HurtOtherRPC transpiler:", instructions); } private static IEnumerable GetHurtOtherTranspilerInstructions(string logHeader, IEnumerable instructions) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(PlayerHealth), "Hurt", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PlayerHealthExtensions), "HurtWithCaller", (Type[])null, (Type[])null); FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerHealthPatch), "HurtOtherCaller"); if (methodInfo == null || methodInfo2 == null || fieldInfo == null) { Logger.LogError(logHeader + " Failed to create transpiler. Required methods not found."); return instructions; } List list = new List(); foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, methodInfo)) { list.Add(new CodeInstruction(OpCodes.Ldsfld, (object)fieldInfo)); list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2)); Logger.LogDebug(logHeader + " Replaced calls to " + methodInfo.Name + " with " + methodInfo2.Name); } else { list.Add(instruction); } } Logger.LogInfo(logHeader + " Created transpiler!"); return list.AsEnumerable(); } } } namespace com.github.zehsteam.PlayerDamageTracker.MonoBehaviours { internal class PluginHelper : MonoBehaviour { private static PluginHelper _instance; public static Action OnStart; public static void Spawn() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("PlayerDamageTracker PluginHelper", new Type[1] { typeof(PluginHelper) }) { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)(object)val); } } private void Awake() { if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); } else { _instance = this; } } private void Start() { OnStart?.Invoke(); } } } namespace com.github.zehsteam.PlayerDamageTracker.Modules { public static class Events { public static event Action OnDamagedByEnemy; public static event Action OnDamagedByPhysGrabObject; public static event Action OnDamagedByExplosion; public static event Action OnDamagedByOther; public static event Action OnKilledByEnemy; public static event Action OnKilledByPhysGrabObject; public static event Action OnKilledByExplosion; public static event Action OnKilledByOther; internal static void InvokeOnDamagedByEnemy(EnemyParent enemyParent) { Events.OnDamagedByEnemy?.Invoke(enemyParent); } internal static void InvokeOnDamagedByPhysGrabObject(PhysGrabObject physGrabObject) { Events.OnDamagedByPhysGrabObject?.Invoke(physGrabObject); } internal static void InvokeOnDamagedByExplosion(Metadata metadata) { Events.OnDamagedByExplosion?.Invoke(metadata); } internal static void InvokeOnDamagedByOther(HurtCollider hurtCollider) { Events.OnDamagedByOther?.Invoke(hurtCollider); } internal static void InvokeOnKilledByEnemy(EnemyParent enemyParent) { Events.OnKilledByEnemy?.Invoke(enemyParent); } internal static void InvokeOnKilledByPhysGrabObject(PhysGrabObject physGrabObject) { Events.OnKilledByPhysGrabObject?.Invoke(physGrabObject); } internal static void InvokeOnKilledByExplosion(Metadata metadata) { Events.OnKilledByExplosion?.Invoke(metadata); } internal static void InvokeOnKilledByOther(HurtCollider hurtCollider) { Events.OnKilledByOther?.Invoke(hurtCollider); } } } namespace com.github.zehsteam.PlayerDamageTracker.Helpers { public static class DependencyHelper { public static IEnumerable GetModAssemblies() { List list = new List(); foreach (PluginInfo value in Chainloader.PluginInfos.Values) { if (value == null || (Object)(object)value.Instance == (Object)null) { continue; } try { Assembly assembly = ((object)value.Instance).GetType().Assembly; if (!(assembly == null)) { list.Add(assembly); } } catch (Exception arg) { Logger.LogError($"Failed to get loaded assembly: {arg}"); } } return list; } } internal static class ILHelper { private static DefaultAssemblyResolver _cachedResolver; private static readonly Dictionary _cachedModules = new Dictionary(); private static DefaultAssemblyResolver GetCachedResolver() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown if (_cachedResolver != null) { return _cachedResolver; } DefaultAssemblyResolver val = new DefaultAssemblyResolver(); ((BaseAssemblyResolver)val).AddSearchDirectory(Paths.ManagedPath); ((BaseAssemblyResolver)val).AddSearchDirectory(Paths.BepInExAssemblyDirectory); ((BaseAssemblyResolver)val).AddSearchDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); string[] directories = Directory.GetDirectories(Paths.PluginPath, "*", SearchOption.AllDirectories); foreach (string text in directories) { ((BaseAssemblyResolver)val).AddSearchDirectory(text); } _cachedResolver = val; return _cachedResolver; } public static IEnumerable GetInstructions(MethodInfo method) { if (method == null) { return Array.Empty(); } try { ModuleDefinition moduleDefinition = GetModuleDefinition(method.DeclaringType.Assembly); if (moduleDefinition == null) { return Array.Empty(); } TypeDefinition type = moduleDefinition.GetType(method.DeclaringType.FullName); MethodDefinition val = ((type != null) ? ((IEnumerable)type.Methods).FirstOrDefault((Func)((MethodDefinition m) => ((MemberReference)m).Name == method.Name)) : null); if (val == null || val.Body == null) { Logger.LogWarning("[ILHelper] Failed to get IL for method: " + method.GetFullName()); return Array.Empty(); } return (IEnumerable)val.Body.Instructions; } catch (Exception arg) { Logger.LogWarning(string.Format("[{0}] Exception while processing method {1}: {2}", "ILHelper", method.GetFullName(), arg)); return Array.Empty(); } } public static IEnumerable GetCoroutineInstructions(MethodInfo method) { if (method == null) { return Array.Empty(); } try { ModuleDefinition moduleDefinition = GetModuleDefinition(method.DeclaringType.Assembly); if (moduleDefinition == null) { return Array.Empty(); } TypeDefinition type = moduleDefinition.GetType(method.DeclaringType.FullName); TypeDefinition val = ((IEnumerable)type.NestedTypes).FirstOrDefault((Func)((TypeDefinition t) => ((MemberReference)t).Name.Contains("<" + method.Name + ">"))); if (val == null) { Logger.LogWarning("[ILHelper] State machine type for " + method.GetFullName() + " not found."); return Array.Empty(); } MethodDefinition val2 = ((IEnumerable)val.Methods).FirstOrDefault((Func)((MethodDefinition m) => ((MemberReference)m).Name == "MoveNext")); if (val2 == null) { Logger.LogWarning("[ILHelper] MoveNext method not found in state machine: " + ((MemberReference)val).Name); return Array.Empty(); } return (IEnumerable)val2.Body.Instructions; } catch (Exception arg) { Logger.LogWarning(string.Format("[{0}] Exception while processing coroutine method {1}: {2}", "ILHelper", method.GetFullName(), arg)); return Array.Empty(); } } public static ModuleDefinition GetModuleDefinition(Assembly assembly) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown if (assembly == null) { return null; } try { if (TryGetCachedModuleDefinition(assembly, out var module)) { return module; } DefaultAssemblyResolver cachedResolver = GetCachedResolver(); if (!string.IsNullOrEmpty(assembly.Location) && File.Exists(assembly.Location)) { ModuleDefinition val = ModuleDefinition.ReadModule(assembly.Location, new ReaderParameters { AssemblyResolver = (IAssemblyResolver)(object)cachedResolver }); CacheModuleDefinition(assembly, val); return val; } string text = assembly.GetName().Name + ".dll"; string text2 = Path.Combine(Paths.ManagedPath, text); if (File.Exists(text2)) { Logger.LogDebug("[ILHelper] Attempting to load " + text + " from Managed path: " + text2); ModuleDefinition val2 = ModuleDefinition.ReadModule(text2, new ReaderParameters { AssemblyResolver = (IAssemblyResolver)(object)cachedResolver }); CacheModuleDefinition(assembly, val2); return val2; } Logger.LogWarning("[ILHelper] Assembly location for " + assembly.FullName + " is null or invalid. Attempting to load from memory."); if (assembly.IsDynamic) { Logger.LogWarning("[ILHelper] Cannot process dynamic assembly: " + assembly.FullName); return null; } byte[] buffer = File.ReadAllBytes(assembly.ManifestModule.FullyQualifiedName); using MemoryStream memoryStream = new MemoryStream(buffer); ModuleDefinition val3 = ModuleDefinition.ReadModule((Stream)memoryStream, new ReaderParameters { AssemblyResolver = (IAssemblyResolver)(object)cachedResolver }); CacheModuleDefinition(assembly, val3); return val3; } catch (Exception arg) { Logger.LogWarning(string.Format("[{0}] Failed to get ModuleDefinition for assembly {1}. {2}", "ILHelper", assembly.FullName, arg)); return null; } } private static ModuleDefinition GetCachedModuleDefinition(Assembly assembly) { if (assembly == null) { return null; } if (_cachedModules.TryGetValue(assembly.FullName, out var value)) { return value; } return null; } private static bool TryGetCachedModuleDefinition(Assembly assembly, out ModuleDefinition module) { module = GetCachedModuleDefinition(assembly); return module != null; } private static void CacheModuleDefinition(Assembly assembly, ModuleDefinition module) { if (!(assembly == null) && module != null && assembly.FullName.StartsWith("Assembly-CSharp")) { _cachedModules[assembly.FullName] = module; } } public static bool MethodCallsMethod(MethodInfo method, MethodInfo targetMethod) { return InstructionsCallsMethod(GetInstructions(method), targetMethod); } public static bool MethodCallsEitherMethods(MethodInfo method, MethodInfo[] targetMethods) { if (ReflectionHelper.IsCoroutineMethod(method)) { return InstructionsCallsEitherMethods(GetCoroutineInstructions(method), targetMethods); } return InstructionsCallsEitherMethods(GetInstructions(method), targetMethods); } public static bool InstructionsCallsMethod(IEnumerable instructions, MethodInfo targetMethod) { return InstructionsCallsEitherMethods(instructions, new MethodInfo[1] { targetMethod }); } public static bool InstructionsCallsEitherMethods(IEnumerable instructions, MethodInfo[] targetMethods) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Invalid comparison between Unknown and I4 if (instructions == null || targetMethods == null || targetMethods.Length == 0) { return false; } foreach (Instruction instruction in instructions) { OpCode opCode = instruction.OpCode; if ((int)((OpCode)(ref opCode)).Code != 39) { opCode = instruction.OpCode; if ((int)((OpCode)(ref opCode)).Code != 110) { continue; } } object operand = instruction.Operand; MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null); if (val == null) { continue; } try { MethodDefinition val2 = val.Resolve(); if (val2 == null) { continue; } foreach (MethodInfo methodInfo in targetMethods) { if (!(methodInfo == null) && ((MemberReference)val2).Name == methodInfo.Name && ((MemberReference)val2.DeclaringType).FullName == methodInfo.DeclaringType.FullName) { return true; } } } catch (Exception arg) { Logger.LogWarning(string.Format("[{0}] Error while processing IL instructions. {1}", "ILHelper", arg)); } } return false; } public static int FindArgLoadStart(List instructions, MethodInfo method, int callIndex) { if (method == null) { return -1; } int num = method.GetParameters().Length; int num2 = 0; for (int num3 = callIndex - 1; num3 >= 0; num3--) { CodeInstruction val = instructions[num3]; if (val.opcode.Name.StartsWith("ld")) { num2++; if (num2 == num) { return num3; } } } return callIndex; } } internal static class ReflectionHelper { public static object GetClassInstanceFromCaller(object caller) { if (caller == null) { return null; } Type type = caller.GetType(); Type declaringType = type.DeclaringType; if (declaringType == null) { return caller; } Logger.LogDebug("ReflectionHelper: Analyzing caller type: " + type.FullName + ", parent type: " + declaringType.FullName); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { object value = fieldInfo.GetValue(caller); if (value != null && declaringType.IsAssignableFrom(value.GetType())) { Logger.LogDebug("ReflectionHelper: Found parent instance of type " + value.GetType().FullName + " in field " + fieldInfo.Name); return value; } if (value != null && IsCompilerGeneratedClass(value.GetType())) { object classInstanceFromCaller = GetClassInstanceFromCaller(value); if (classInstanceFromCaller != null) { return classInstanceFromCaller; } } } Logger.LogDebug("ReflectionHelper: No parent instance found for " + type.FullName + ", returning original caller."); return caller; } private static bool IsCompilerGeneratedClass(Type type) { if (type.Name.Contains("<") && type.Name.Contains(">")) { return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute)); } return false; } public static bool IsCoroutineMethod(MethodInfo method) { return method?.ReturnType == typeof(IEnumerator); } public static MethodInfo GetCoroutineMoveNextMethod(MethodInfo method) { return method?.DeclaringType.GetNestedTypes(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault((Type t) => t.Name.Contains("<" + method.Name + ">"))?.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.NonPublic); } } } namespace com.github.zehsteam.PlayerDamageTracker.Extensions { internal static class AssemblyExtensions { public static bool IsLocatedInPluginsFolder(this Assembly assembly) { if (assembly == null) { return false; } if (assembly.IsDynamic) { return false; } return assembly.Location.StartsWith(Paths.PluginPath, StringComparison.OrdinalIgnoreCase); } public static IEnumerable GetLoadableTypes(this Assembly assembly) { if (assembly == null) { return Array.Empty(); } try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.Where((Type type) => type != null); } } } internal static class HurtColliderExtensions { public static bool TryGetEnemyParent(this HurtCollider hurtCollider, out EnemyParent enemyParent) { if ((Object)(object)hurtCollider == (Object)null) { enemyParent = null; return false; } return ((Object)(object)hurtCollider).TryGetComponentInParents(out enemyParent); } public static bool TryGetPhysGrabObject(this HurtCollider hurtCollider, out PhysGrabObject physGrabObject) { if ((Object)(object)hurtCollider == (Object)null) { physGrabObject = null; return false; } return ((Object)(object)hurtCollider).TryGetComponentInParents(out physGrabObject); } public static bool TryGetExplosionMetadata(this HurtCollider hurtCollider, out Metadata metadata) { if ((Object)(object)hurtCollider == (Object)null) { metadata = null; return false; } return ParticleScriptExplosionPatch.Explosions.TryGetValue(hurtCollider, out metadata); } } internal static class ObjectExtensions { public static bool TryGetComponentInParent(this Object obj, out T result) where T : Component { if (!TryGetTransform(obj, out var transform)) { result = default(T); return false; } result = ((Component)transform).GetComponentInParent(); return (Object)(object)result != (Object)null; } public static T GetComponentInParents(this Object obj) where T : Component { Transform val = GetTransform(obj); T result = default(T); while ((Object)(object)val != (Object)null) { if (((Component)val).TryGetComponent(ref result)) { return result; } val = val.parent; } return default(T); } public static bool TryGetComponentInParents(this Object obj, out T result) where T : Component { result = obj.GetComponentInParents(); return (Object)(object)result != (Object)null; } public static string GetHierarchyPath(this Object obj) { if (!TryGetTransform(obj, out var transform)) { return string.Empty; } return transform.GetHierarchyPath(); } private static Transform GetTransform(Object obj) { Component val = (Component)(object)((obj is Component) ? obj : null); if (val == null) { GameObject val2 = (GameObject)(object)((obj is GameObject) ? obj : null); if (val2 != null) { return val2.transform; } return null; } return val.transform; } private static bool TryGetTransform(Object obj, out Transform transform) { transform = GetTransform(obj); return (Object)(object)transform != (Object)null; } } internal static class PlayerHealthExtensions { public static void HurtWithCaller(this PlayerHealth playerHealth, int damage, bool savingGrace, int enemyIndex, bool hurtByHeal, object caller) { if ((Object)(object)playerHealth == (Object)null) { return; } playerHealth.Hurt(damage, savingGrace, enemyIndex, hurtByHeal); if (damage <= 0 || caller == null) { return; } Logger.LogDebug($"PlayerHealthExtensions: HurtWithCaller() player: \"{SemiFunc.PlayerGetName(playerHealth.playerAvatar)}\", damage: {damage}, savingGrace: {savingGrace}, enemyIndex: {enemyIndex}, caller: \"{caller.GetType().FullName}\""); HurtCollider val = (HurtCollider)((caller is HurtCollider) ? caller : null); if (val != null) { HurtByHurtCollider(playerHealth, damage, savingGrace, enemyIndex, val); return; } Component val2 = (Component)((caller is Component) ? caller : null); Enemy enemy = default(Enemy); if (val2 != null && val2.TryGetComponent(ref enemy)) { HurtByEnemy(playerHealth, damage, savingGrace, enemyIndex, enemy); } else { Logger.LogDebug("PlayerHealthExtensions: HurtWithCaller() Failed to identify caller."); } } private static void HurtByHurtCollider(PlayerHealth playerHealth, int damage, bool savingGrace, int enemyIndex, HurtCollider hurtCollider) { bool deadSet = playerHealth.playerAvatar.deadSet; PhysGrabObject physGrabObject; Metadata metadata; if (hurtCollider.TryGetEnemyParent(out var enemyParent)) { Logger.LogDebug("PlayerHealthExtensions: HurtByHurtCollider() You were damaged by an enemy! \"" + enemyParent.enemyName + "\""); Events.InvokeOnDamagedByEnemy(enemyParent); if (deadSet) { Events.InvokeOnKilledByEnemy(enemyParent); } } else if (hurtCollider.TryGetPhysGrabObject(out physGrabObject)) { Logger.LogDebug("PlayerHealthExtensions: HurtByHurtCollider() You were damaged by a PhysGrabObject! \"" + ((Object)physGrabObject).name + "\""); Events.InvokeOnDamagedByPhysGrabObject(physGrabObject); if (deadSet) { Events.InvokeOnKilledByPhysGrabObject(physGrabObject); } } else if (hurtCollider.TryGetExplosionMetadata(out metadata)) { Logger.LogDebug("PlayerHealthExtensions: HurtByHurtCollider() You were damaged by an explosion!"); Events.InvokeOnDamagedByExplosion(metadata); if (deadSet) { Events.InvokeOnKilledByExplosion(metadata); } } else { Logger.LogDebug("PlayerHealthExtensions: HurtByHurtCollider() You were damaged by something else. \"" + ((Object)(object)hurtCollider).GetHierarchyPath() + "\""); Events.InvokeOnDamagedByOther(hurtCollider); if (deadSet) { Events.InvokeOnKilledByOther(hurtCollider); } } } private static void HurtByEnemy(PlayerHealth playerHealth, int damage, bool savingGrace, int enemyIndex, Enemy enemy) { bool deadSet = playerHealth.playerAvatar.deadSet; EnemyParent enemyParent = enemy.EnemyParent; Logger.LogDebug("PlayerHealthExtensions: HurtByEnemy() You were damaged by an enemy! \"" + enemyParent.enemyName + "\""); Events.InvokeOnDamagedByEnemy(enemyParent); if (deadSet) { Events.InvokeOnKilledByEnemy(enemyParent); } } } internal static class ReflectionExtensions { public static string GetFullName(this MethodInfo methodInfo) { if (methodInfo == null) { return "Method is null"; } Type declaringType = methodInfo.DeclaringType; string name = methodInfo.Name; string name2 = declaringType.Name; string name3 = declaringType.Assembly.GetName().Name; return methodInfo.ReturnType.Name + " " + name + "(), class: " + name2 + ", assembly: " + name3; } } public static class StringExtensions { public static bool EqualsAny(this string input, string[] values, StringComparison comparisonType = StringComparison.CurrentCulture) { if (input == null) { throw new ArgumentNullException("input"); } if (values == null) { throw new ArgumentNullException("values"); } foreach (string value in values) { if (input.Equals(value, comparisonType)) { return true; } } return false; } public static bool ContainsAny(this string input, string[] values, StringComparison comparisonType = StringComparison.CurrentCulture) { if (input == null) { throw new ArgumentNullException("input"); } if (values == null) { throw new ArgumentNullException("values"); } foreach (string value in values) { if (input.Contains(value, comparisonType)) { return true; } } return false; } public static bool StartsWithAny(this string input, string[] values, StringComparison comparisonType = StringComparison.CurrentCulture) { if (input == null) { throw new ArgumentNullException("input"); } if (values == null) { throw new ArgumentNullException("values"); } foreach (string value in values) { if (input.StartsWith(value, comparisonType)) { return true; } } return false; } } internal static class TransformExtensions { public static string GetHierarchyPath(this Transform transform) { if ((Object)(object)transform.parent == (Object)null) { return ((Object)transform).name; } return transform.parent.GetHierarchyPath() + "/" + ((Object)transform).name; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }