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.Xml.Linq; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using StaticNetcodeLib; using TMPro; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("EliteMasterEric")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("A Lethal Company plugin which overhauls the end-of-mission performance report with new information, including cause of death for any deceased players with some fun easter eggs thrown in too.")] [assembly: AssemblyFileVersion("2.4.1.0")] [assembly: AssemblyInformationalVersion("2.4.1+8626d7985f5122271a270e3ab7373ebd9dfa5235")] [assembly: AssemblyProduct("Coroner")] [assembly: AssemblyTitle("Coroner")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.4.1.0")] [module: UnverifiableCode] [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; } } } namespace Coroner { internal class AdvancedDeathTracker { public static Dictionary causeOfDeathDictionary = new Dictionary(); public static void ClearDeathTracker() { PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { StoreLocalCauseOfDeath((int)val.playerClientId, null, overrideExisting: true); } } public static void SetCauseOfDeath(int playerIndex, AdvancedCauseOfDeath? causeOfDeath, bool forceOverride = false) { if (!causeOfDeath.HasValue) { NetworkRPC.ReportCauseOfDeathServerRpc(playerIndex, null, forceOverride); return; } AdvancedCauseOfDeath value = causeOfDeath.Value; Plugin.Instance.PluginLogger.LogDebug(string.Format("Serializing {0} to {1}{2}", value, value.GetLanguageTag(), forceOverride ? " (FORCED)" : "")); NetworkRPC.ReportCauseOfDeathServerRpc(playerIndex, value.GetLanguageTag(), forceOverride); StoreLocalCauseOfDeath(playerIndex, causeOfDeath, forceOverride); } public static void SetCauseOfDeath(PlayerControllerB playerController, AdvancedCauseOfDeath? causeOfDeath, bool forceOverride = false) { SetCauseOfDeath((int)playerController.playerClientId, causeOfDeath, forceOverride); } public static void StoreLocalCauseOfDeath(int playerId, AdvancedCauseOfDeath? causeOfDeath, bool overrideExisting) { if (!overrideExisting && (!causeOfDeath.HasValue || HasCauseOfDeath(playerId))) { if (!causeOfDeath.HasValue) { Plugin.Instance.PluginLogger.LogDebug($"Ignoring null cause of death for player {playerId}"); return; } string languageTag = causeOfDeath.Value.GetLanguageTag(); AdvancedCauseOfDeath? causeOfDeath2 = GetCauseOfDeath(playerId, shouldGuess: false); string arg = ((!causeOfDeath2.HasValue) ? "null" : causeOfDeath2.Value.GetLanguageTag()); Plugin.Instance.PluginLogger.LogWarning($"Player {playerId} already has a cause of death set ({arg}), not overwriting it with {languageTag}."); } else if (!causeOfDeath.HasValue) { Plugin.Instance.PluginLogger.LogDebug($"Clearing cause of death for player {playerId}"); causeOfDeathDictionary[playerId] = null; } else { AdvancedCauseOfDeath? causeOfDeath3 = GetCauseOfDeath(playerId, shouldGuess: false); string arg2 = ((!causeOfDeath3.HasValue) ? "null" : causeOfDeath3.Value.GetLanguageTag()); string languageTag2 = causeOfDeath.Value.GetLanguageTag(); Plugin.Instance.PluginLogger.LogDebug($"Storing cause of death {languageTag2} (overriding {arg2}) for player {playerId}!"); causeOfDeathDictionary[playerId] = causeOfDeath; } } private static AdvancedCauseOfDeath? FetchCauseOfDeathVariable(PlayerControllerB playerController) { if (!HasCauseOfDeath(playerController)) { return null; } return causeOfDeathDictionary[(int)playerController.playerClientId]; } public static AdvancedCauseOfDeath? GetCauseOfDeath(int playerIndex, bool shouldGuess = true) { if (playerIndex < 0 || playerIndex >= StartOfRound.Instance.allPlayerScripts.Length) { return null; } PlayerControllerB playerController = StartOfRound.Instance.allPlayerScripts[playerIndex]; return GetCauseOfDeath(playerController, shouldGuess); } public static bool HasCauseOfDeath(int playerIndex) { if (playerIndex < 0 || playerIndex >= StartOfRound.Instance.allPlayerScripts.Length) { return false; } return HasCauseOfDeath(StartOfRound.Instance.allPlayerScripts[playerIndex]); } public static bool HasCauseOfDeath(PlayerControllerB playerController) { return causeOfDeathDictionary.ContainsKey((int)playerController.playerClientId) && causeOfDeathDictionary[(int)playerController.playerClientId].HasValue; } public static AdvancedCauseOfDeath? GetCauseOfDeath(PlayerControllerB playerController, bool shouldGuess = true) { AdvancedCauseOfDeath? advancedCauseOfDeath = FetchCauseOfDeathVariable(playerController); if (advancedCauseOfDeath.HasValue) { AdvancedCauseOfDeath value = advancedCauseOfDeath.Value; Plugin.Instance.PluginLogger.LogDebug($"Player {playerController.playerClientId} has custom cause of death stored! {value.GetLanguageTag()}"); return value; } if (!shouldGuess) { Plugin.Instance.PluginLogger.LogDebug($"Player {playerController.playerClientId} has no custom cause of death stored! Returning null..."); return null; } Plugin.Instance.PluginLogger.LogDebug($"Player {playerController.playerClientId} has no custom cause of death stored! Using fallback..."); return GuessCauseOfDeath(playerController); } public static AdvancedCauseOfDeath GuessCauseOfDeath(PlayerControllerB playerController) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 if (playerController.isPlayerDead) { if (IsHoldingJetpack(playerController)) { if ((int)playerController.causeOfDeath == 2) { return AdvancedCauseOfDeath.Player_Jetpack_Gravity; } if ((int)playerController.causeOfDeath == 3) { return AdvancedCauseOfDeath.Player_Jetpack_Blast; } } return playerController.causeOfDeath; } return AdvancedCauseOfDeath.Unknown; } public static GrabbableObject? GetHeldObject(PlayerControllerB playerController) { GrabbableObject currentlyHeldObjectServer = playerController.currentlyHeldObjectServer; if ((Object)(object)currentlyHeldObjectServer == (Object)null) { return null; } GameObject gameObject = ((Component)currentlyHeldObjectServer).gameObject; if ((Object)(object)gameObject == (Object)null) { return null; } return gameObject.GetComponent(); } public static bool IsHoldingJetpack(PlayerControllerB playerController) { GrabbableObject heldObject = GetHeldObject(playerController); if ((Object)(object)heldObject == (Object)null) { return false; } if (heldObject is JetpackItem) { return true; } return false; } public static bool IsHoldingShovel(PlayerControllerB playerController) { GrabbableObject heldObject = GetHeldObject(playerController); if ((Object)(object)heldObject == (Object)null) { return false; } if (heldObject is Shovel && ((Object)((Component)heldObject).gameObject).name.StartsWith("Shovel")) { return true; } return false; } public static bool IsHoldingStopSign(PlayerControllerB playerController) { GrabbableObject heldObject = GetHeldObject(playerController); if ((Object)(object)heldObject == (Object)null) { return false; } if (heldObject is Shovel && ((Object)((Component)heldObject).gameObject).name.StartsWith("StopSign")) { return true; } return false; } public static bool IsHoldingYieldSign(PlayerControllerB playerController) { GrabbableObject heldObject = GetHeldObject(playerController); if ((Object)(object)heldObject == (Object)null) { return false; } if (heldObject is Shovel && ((Object)((Component)heldObject).gameObject).name.StartsWith("YieldSign")) { return true; } return false; } public static bool IsHoldingShotgun(PlayerControllerB playerController) { GrabbableObject heldObject = GetHeldObject(playerController); if ((Object)(object)heldObject == (Object)null) { return false; } if (heldObject is ShotgunItem) { return true; } return false; } public static bool IsHoldingKnife(PlayerControllerB playerController) { GrabbableObject heldObject = GetHeldObject(playerController); if ((Object)(object)heldObject == (Object)null) { return false; } if (heldObject is KnifeItem) { return true; } return false; } public static string StringifyCauseOfDeath(AdvancedCauseOfDeath? causeOfDeath) { return StringifyCauseOfDeath(causeOfDeath, Plugin.RANDOM); } public static string StringifyCauseOfDeath(AdvancedCauseOfDeath? causeOfDeath, Random random) { string[] array = SelectCauseOfDeath(causeOfDeath); if (array.Length > 1 && (!causeOfDeath.HasValue || !Plugin.Instance.PluginConfig.ShouldUseSeriousDeathMessages())) { int num = random.Next(array.Length); return array[num]; } return array[0]; } public static string[] SelectCauseOfDeath(AdvancedCauseOfDeath? causeOfDeath) { if (!causeOfDeath.HasValue) { return Plugin.Instance.LanguageHandler.GetValuesByTag("FunnyNote"); } if (AdvancedCauseOfDeath.IsCauseOfDeathRegistered(causeOfDeath)) { return causeOfDeath.Value.GetLanguageValues(); } return Plugin.Instance.LanguageHandler.GetValuesByTag("DeathUnknown"); } } public struct AdvancedCauseOfDeath { public static readonly Dictionary Registry = new Dictionary(); private static int NextId = 100; public static AdvancedCauseOfDeath Unknown = BuildFromExisting("DeathUnknown", (CauseOfDeath)0); public static AdvancedCauseOfDeath Bludgeoning = BuildFromExisting("DeathBludgeoning", (CauseOfDeath)1); public static AdvancedCauseOfDeath Gravity = BuildFromExisting("DeathGravity", (CauseOfDeath)2); public static AdvancedCauseOfDeath Blast = BuildFromExisting("DeathBlast", (CauseOfDeath)3); public static AdvancedCauseOfDeath Strangulation = BuildFromExisting("DeathStrangulation", (CauseOfDeath)4); public static AdvancedCauseOfDeath Suffocation = BuildFromExisting("DeathSuffocation", (CauseOfDeath)5); public static AdvancedCauseOfDeath Mauling = BuildFromExisting("DeathMauling", (CauseOfDeath)6); public static AdvancedCauseOfDeath Gunshots = BuildFromExisting("DeathGunshots", (CauseOfDeath)7); public static AdvancedCauseOfDeath Crushing = BuildFromExisting("DeathCrushing", (CauseOfDeath)8); public static AdvancedCauseOfDeath Drowning = BuildFromExisting("DeathDrowning", (CauseOfDeath)9); public static AdvancedCauseOfDeath Abandoned = BuildFromExisting("DeathAbandoned", (CauseOfDeath)10); public static AdvancedCauseOfDeath Electrocution = BuildFromExisting("DeathElectrocution", (CauseOfDeath)11); public static AdvancedCauseOfDeath Kicking = BuildFromExisting("DeathKicking", (CauseOfDeath)12); public static AdvancedCauseOfDeath Burning = BuildFromExisting("DeathBurning", (CauseOfDeath)13); public static AdvancedCauseOfDeath Stabbing = BuildFromExisting("DeathStabbing", (CauseOfDeath)14); public static AdvancedCauseOfDeath Fan = BuildFromExisting("DeathFan", (CauseOfDeath)15); public static AdvancedCauseOfDeath Inertia = BuildFromExisting("DeathInertia", (CauseOfDeath)16); public static AdvancedCauseOfDeath Scratching = BuildFromExisting("DeathScratching", (CauseOfDeath)18); public static AdvancedCauseOfDeath Snipping = BuildFromExisting("DeathSnipped", (CauseOfDeath)17); public static AdvancedCauseOfDeath Enemy_BaboonHawk = Build("DeathEnemyBaboonHawk"); public static AdvancedCauseOfDeath Enemy_Bracken = Build("DeathEnemyBracken"); public static AdvancedCauseOfDeath Enemy_BunkerSpider = Build("DeathEnemyBunkerSpider"); public static AdvancedCauseOfDeath Enemy_CircuitBees = Build("DeathEnemyCircuitBees"); public static AdvancedCauseOfDeath Enemy_CoilHead = Build("DeathEnemyCoilHead"); public static AdvancedCauseOfDeath Enemy_EarthLeviathan = Build("DeathEnemyEarthLeviathan"); public static AdvancedCauseOfDeath Enemy_EyelessDog = Build("DeathEnemyEyelessDog"); public static AdvancedCauseOfDeath Enemy_GhostGirl = Build("DeathEnemyGhostGirl"); public static AdvancedCauseOfDeath Enemy_HoarderBug = Build("DeathEnemyHoarderBug"); public static AdvancedCauseOfDeath Enemy_Hygrodere = Build("DeathEnemyHygrodere"); public static AdvancedCauseOfDeath Enemy_Jester = Build("DeathEnemyJester"); public static AdvancedCauseOfDeath Enemy_LassoMan = Build("DeathEnemyLassoMan"); public static AdvancedCauseOfDeath Enemy_SnareFlea = Build("DeathEnemySnareFlea"); public static AdvancedCauseOfDeath Enemy_SporeLizard = Build("DeathEnemySporeLizard"); public static AdvancedCauseOfDeath Enemy_Thumper = Build("DeathEnemyThumper"); public static AdvancedCauseOfDeath Enemy_ForestGiant_Eaten = Build("DeathEnemyForestGiantEaten"); public static AdvancedCauseOfDeath Enemy_ForestGiant_Death = Build("DeathEnemyForestGiantDeath"); public static AdvancedCauseOfDeath Enemy_MaskedPlayer_Wear = Build("DeathEnemyMaskedPlayerWear"); public static AdvancedCauseOfDeath Enemy_MaskedPlayer_Victim = Build("DeathEnemyMaskedPlayerVictim"); public static AdvancedCauseOfDeath Enemy_Nutcracker_Kicked = Build("DeathEnemyNutcrackerKicked"); public static AdvancedCauseOfDeath Enemy_Nutcracker_Shot = Build("DeathEnemyNutcrackerShot"); public static AdvancedCauseOfDeath Enemy_Butler_Stab = Build("DeathEnemyButlerStab"); public static AdvancedCauseOfDeath Enemy_Butler_Explode = Build("DeathEnemyButlerExplode"); public static AdvancedCauseOfDeath Enemy_MaskHornets = Build("DeathEnemyMaskHornets"); public static AdvancedCauseOfDeath Enemy_TulipSnake_Drop = Build("DeathEnemyTulipSnakeDrop"); public static AdvancedCauseOfDeath Enemy_Old_Bird_Rocket = Build("DeathEnemyOldBirdRocket"); public static AdvancedCauseOfDeath Enemy_Old_Bird_Charge = Build("DeathEnemyOldBirdCharge"); public static AdvancedCauseOfDeath Enemy_Old_Bird_Stomp = Build("DeathEnemyOldBirdStomp"); public static AdvancedCauseOfDeath Enemy_Old_Bird_Torch = Build("DeathEnemyOldBirdTorch"); public static AdvancedCauseOfDeath Enemy_KidnapperFox = Build("DeathEnemyKidnapperFox"); public static AdvancedCauseOfDeath Enemy_Barber = Build("DeathEnemyBarber"); public static AdvancedCauseOfDeath Enemy_Maneater = Build("DeathEnemyManeater"); public static AdvancedCauseOfDeath Enemy_Giant_Sapsucker = Build("DeathEnemyGiantSapsucker"); public static AdvancedCauseOfDeath Enemy_Cadaver_Growth = Build("DeathEnemyCadaverGrowth"); public static AdvancedCauseOfDeath Enemy_Cadaver_Bloom = Build("DeathEnemyCadaverBloom"); public static AdvancedCauseOfDeath Enemy_Feiopar = Build("DeathEnemyFeiopar"); public static AdvancedCauseOfDeath Player_Jetpack_Gravity = Build("DeathPlayerJetpackGravity"); public static AdvancedCauseOfDeath Player_Jetpack_Blast = Build("DeathPlayerJetpackBlast"); public static AdvancedCauseOfDeath Player_Quicksand = Build("DeathPlayerQuicksand"); public static AdvancedCauseOfDeath Player_Ladder = Build("DeathPlayerLadder"); public static AdvancedCauseOfDeath Player_Murder_Shovel = Build("DeathPlayerMurderShovel"); public static AdvancedCauseOfDeath Player_Murder_Stop_Sign = Build("DeathPlayerMurderStopSign"); public static AdvancedCauseOfDeath Player_Murder_Yield_Sign = Build("DeathPlayerMurderYieldSign"); public static AdvancedCauseOfDeath Player_Murder_Shotgun = Build("DeathPlayerMurderShotgun"); public static AdvancedCauseOfDeath Player_Murder_Knife = Build("DeathPlayerMurderKnife"); public static AdvancedCauseOfDeath Player_StunGrenade = Build("DeathPlayerStunGrenade"); public static AdvancedCauseOfDeath Player_EasterEgg = Build("DeathPlayerEasterEgg"); public static AdvancedCauseOfDeath Player_Electric_Chair = Build("DeathPlayerElectricChair"); public static AdvancedCauseOfDeath Player_Vomiting = Build("DeathPlayerVomiting"); public static AdvancedCauseOfDeath Player_Cruiser_Driver = Build("DeathPlayerCruiserDriver"); public static AdvancedCauseOfDeath Player_Cruiser_Passenger = Build("DeathPlayerCruiserPassenger"); public static AdvancedCauseOfDeath Player_Cruiser_Explode_Bystander = Build("DeathPlayerCruiserExplodeBystander"); public static AdvancedCauseOfDeath Player_Cruiser_Ran_Over = Build("DeathPlayerCruiserRanOver"); public static AdvancedCauseOfDeath Pit_Generic = Build("DeathPitGeneric"); public static AdvancedCauseOfDeath Pit_Facility_Pit = Build("DeathPitFacilityPit"); public static AdvancedCauseOfDeath Pit_Facility_Catwalk_Jump = Build("DeathPitFacilityCatwalkJump"); public static AdvancedCauseOfDeath Pit_Mine_Pit = Build("DeathPitMinePit"); public static AdvancedCauseOfDeath Pit_Mine_Cave = Build("DeathPitMineCave"); public static AdvancedCauseOfDeath Pit_Mine_Elevator = Build("DeathPitMineElevator"); public static AdvancedCauseOfDeath Other_Landmine = Build("DeathOtherLandmine"); public static AdvancedCauseOfDeath Other_Turret = Build("DeathOtherTurret"); public static AdvancedCauseOfDeath Other_Lightning = Build("DeathOtherLightning"); public static AdvancedCauseOfDeath Other_Meteor = Build("DeathOtherMeteor"); public static AdvancedCauseOfDeath Other_DepositItemsDesk = Build("DeathOtherDepositItemsDesk"); public static AdvancedCauseOfDeath Other_Dropship = Build("DeathOtherItemDropship"); public static AdvancedCauseOfDeath Other_Spike_Trap = Build("DeathOtherSpikeTrap"); public static AdvancedCauseOfDeath Other_OutOfBounds = Build("DeathOtherOutOfBounds"); private int statusCode; private string languageTag; public static AdvancedCauseOfDeath Build(string languageTag) { int nextId = NextId; NextId++; AdvancedCauseOfDeath advancedCauseOfDeath = default(AdvancedCauseOfDeath); advancedCauseOfDeath.statusCode = nextId; advancedCauseOfDeath.languageTag = languageTag; AdvancedCauseOfDeath advancedCauseOfDeath2 = advancedCauseOfDeath; Register(languageTag, advancedCauseOfDeath2); return advancedCauseOfDeath2; } public static AdvancedCauseOfDeath BuildFromExisting(string languageTag, CauseOfDeath statusCode) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected I4, but got Unknown AdvancedCauseOfDeath advancedCauseOfDeath = default(AdvancedCauseOfDeath); advancedCauseOfDeath.statusCode = (int)statusCode; advancedCauseOfDeath.languageTag = languageTag; AdvancedCauseOfDeath advancedCauseOfDeath2 = advancedCauseOfDeath; Register(languageTag, advancedCauseOfDeath2); return advancedCauseOfDeath2; } private static void Register(string key, AdvancedCauseOfDeath value) { if (IsTagRegistered(key)) { Plugin.Instance.PluginLogger.LogError("Tried to register duplicate Cause of Death key (" + key + ")!"); } else if (IsCauseOfDeathRegistered(value)) { Plugin.Instance.PluginLogger.LogError($"Tried to register Cause of Death twice ({value})!"); } else { Registry.Add(key, value); } } public static AdvancedCauseOfDeath? Fetch(string? key) { if (key == null) { return null; } if (!Registry.ContainsKey(key)) { return null; } return Registry[key]; } public static bool IsTagRegistered(string key) { return Registry.ContainsKey(key); } public static bool IsCauseOfDeathRegistered(AdvancedCauseOfDeath? value) { if (!value.HasValue) { return false; } return Registry.ContainsValue(value.Value); } private static AdvancedCauseOfDeath ConvertCauseOfDeath(CauseOfDeath causeOfDeath) { //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) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected I4, but got Unknown return (int)causeOfDeath switch { 0 => Unknown, 1 => Bludgeoning, 2 => Gravity, 3 => Blast, 4 => Strangulation, 5 => Suffocation, 6 => Mauling, 7 => Gunshots, 8 => Crushing, 9 => Drowning, 10 => Abandoned, 11 => Electrocution, 13 => Burning, 15 => Fan, 14 => Stabbing, _ => Unknown, }; } public string GetLanguageTag() { return languageTag; } public string[] GetLanguageValues() { return Plugin.Instance.LanguageHandler.GetValuesByTag(languageTag); } public override bool Equals(object obj) { return obj is AdvancedCauseOfDeath advancedCauseOfDeath && statusCode == advancedCauseOfDeath.statusCode; } public override int GetHashCode() { return HashCode.Combine(statusCode, languageTag); } public static bool operator ==(AdvancedCauseOfDeath left, AdvancedCauseOfDeath right) { return left.statusCode == right.statusCode; } public static bool operator !=(AdvancedCauseOfDeath left, AdvancedCauseOfDeath right) { return left.statusCode != right.statusCode; } public static bool operator ==(CauseOfDeath left, AdvancedCauseOfDeath right) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 return (int)left == right.statusCode; } public static bool operator !=(CauseOfDeath left, AdvancedCauseOfDeath right) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 return (int)left != right.statusCode; } public static bool operator ==(AdvancedCauseOfDeath left, CauseOfDeath right) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between I4 and Unknown return left.statusCode == (int)right; } public static bool operator !=(AdvancedCauseOfDeath left, CauseOfDeath right) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between I4 and Unknown return left.statusCode != (int)right; } public static implicit operator AdvancedCauseOfDeath(CauseOfDeath value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return ConvertCauseOfDeath(value); } public static implicit operator CauseOfDeath(AdvancedCauseOfDeath value) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) return (CauseOfDeath)value.statusCode; } public override string ToString() { return "AdvancedCauseOfDeath(" + languageTag + ")"; } } public class API { public static void SetCauseOfDeath(PlayerControllerB player, AdvancedCauseOfDeath causeOfDeath) { bool flag = false; AdvancedDeathTracker.SetCauseOfDeath(player, causeOfDeath); } public static void SetCauseOfDeath(int playerId, AdvancedCauseOfDeath causeOfDeath) { bool flag = false; AdvancedDeathTracker.SetCauseOfDeath(playerId, causeOfDeath); } public static void ClearCauseOfDeath(PlayerControllerB player) { ClearCauseOfDeath((int)player.playerClientId); } public static void ClearCauseOfDeath(int playerId) { AdvancedDeathTracker.StoreLocalCauseOfDeath(playerId, null, overrideExisting: true); } public static AdvancedCauseOfDeath? GetCauseOfDeath(PlayerControllerB player) { return AdvancedDeathTracker.GetCauseOfDeath(player); } public static AdvancedCauseOfDeath? GetCauseOfDeath(int playerId) { return AdvancedDeathTracker.GetCauseOfDeath(playerId); } public static AdvancedCauseOfDeath Register(string key) { return AdvancedCauseOfDeath.Build(key); } public static bool IsRegistered(string key) { return AdvancedCauseOfDeath.IsTagRegistered(key); } public static string StringifyCauseOfDeath(AdvancedCauseOfDeath causeOfDeath, Random? random) { return AdvancedDeathTracker.StringifyCauseOfDeath(causeOfDeath, (random != null) ? random : Plugin.RANDOM); } } internal class EnumeratorPatch : IEnumerable { public IEnumerator targetEnumerator; public Action? prefixAction; public Action? postfixAction; public Action? preStepAction; public Action? postStepAction; public Func? stepAction; public EnumeratorPatch(IEnumerator targetEnumerator) { this.targetEnumerator = targetEnumerator; } public IEnumerator GetEnumerator() { if (prefixAction != null) { prefixAction(); } while (targetEnumerator.MoveNext()) { object value = targetEnumerator.Current; if (preStepAction != null) { preStepAction(value); } yield return (stepAction != null) ? stepAction(value) : value; if (postStepAction != null) { postStepAction(value); } } if (postfixAction != null) { postfixAction(); } } } internal class LanguageHandler { public const string DEFAULT_LANGUAGE = "en-us"; public const string TAG_FUNNY_NOTES = "FunnyNote"; public const string TAG_UI_NOTES = "UINotes"; public const string TAG_UI_DEATH = "UICauseOfDeath"; public const string TAG_DEATH_GENERIC_BLUDGEONING = "DeathBludgeoning"; public const string TAG_DEATH_GENERIC_GRAVITY = "DeathGravity"; public const string TAG_DEATH_GENERIC_BLAST = "DeathBlast"; public const string TAG_DEATH_GENERIC_STRANGULATION = "DeathStrangulation"; public const string TAG_DEATH_GENERIC_SUFFOCATION = "DeathSuffocation"; public const string TAG_DEATH_GENERIC_MAULING = "DeathMauling"; public const string TAG_DEATH_GENERIC_GUNSHOTS = "DeathGunshots"; public const string TAG_DEATH_GENERIC_CRUSHING = "DeathCrushing"; public const string TAG_DEATH_GENERIC_DROWNING = "DeathDrowning"; public const string TAG_DEATH_GENERIC_ABANDONED = "DeathAbandoned"; public const string TAG_DEATH_GENERIC_ELECTROCUTION = "DeathElectrocution"; public const string TAG_DEATH_GENERIC_KICKING = "DeathKicking"; public const string TAG_DEATH_GENERIC_BURNING = "DeathBurning"; public const string TAG_DEATH_GENERIC_STABBING = "DeathStabbing"; public const string TAG_DEATH_GENERIC_FAN = "DeathFan"; public const string TAG_DEATH_GENERIC_INERTIA = "DeathInertia"; public const string TAG_DEATH_GENERIC_SNIPPING = "DeathSnipped"; public const string TAG_DEATH_GENERIC_SCRATCHING = "DeathScratching"; public const string TAG_DEATH_ENEMY_BABOON_HAWK = "DeathEnemyBaboonHawk"; public const string TAG_DEATH_ENEMY_BRACKEN = "DeathEnemyBracken"; public const string TAG_DEATH_ENEMY_BUNKER_SPIDER = "DeathEnemyBunkerSpider"; public const string TAG_DEATH_ENEMY_CIRCUIT_BEES = "DeathEnemyCircuitBees"; public const string TAG_DEATH_ENEMY_COILHEAD = "DeathEnemyCoilHead"; public const string TAG_DEATH_ENEMY_EARTH_LEVIATHAN = "DeathEnemyEarthLeviathan"; public const string TAG_DEATH_ENEMY_EYELESS_DOG = "DeathEnemyEyelessDog"; public const string TAG_DEATH_ENEMY_GHOST_GIRL = "DeathEnemyGhostGirl"; public const string TAG_DEATH_ENEMY_HOARDER_BUG = "DeathEnemyHoarderBug"; public const string TAG_DEATH_ENEMY_HYGRODERE = "DeathEnemyHygrodere"; public const string TAG_DEATH_ENEMY_JESTER = "DeathEnemyJester"; public const string TAG_DEATH_ENEMY_LASSO_MAN = "DeathEnemyLassoMan"; public const string TAG_DEATH_ENEMY_SNARE_FLEA = "DeathEnemySnareFlea"; public const string TAG_DEATH_ENEMY_SPORE_LIZARD = "DeathEnemySporeLizard"; public const string TAG_DEATH_ENEMY_THUMPER = "DeathEnemyThumper"; public const string TAG_DEATH_ENEMY_FOREST_GIANT_EATEN = "DeathEnemyForestGiantEaten"; public const string TAG_DEATH_ENEMY_FOREST_GIANT_DEATH = "DeathEnemyForestGiantDeath"; public const string TAG_DEATH_ENEMY_MASKED_PLAYER_WEAR = "DeathEnemyMaskedPlayerWear"; public const string TAG_DEATH_ENEMY_MASKED_PLAYER_VICTIM = "DeathEnemyMaskedPlayerVictim"; public const string TAG_DEATH_ENEMY_NUTCRACKER_KICKED = "DeathEnemyNutcrackerKicked"; public const string TAG_DEATH_ENEMY_NUTCRACKER_SHOT = "DeathEnemyNutcrackerShot"; public const string TAG_DEATH_ENEMY_BUTLER_STAB = "DeathEnemyButlerStab"; public const string TAG_DEATH_ENEMY_BUTLER_EXPLODE = "DeathEnemyButlerExplode"; public const string TAG_DEATH_ENEMY_MASK_HORNETS = "DeathEnemyMaskHornets"; public const string TAG_DEATH_ENEMY_TULIP_SNAKE_DROP = "DeathEnemyTulipSnakeDrop"; public const string TAG_DEATH_ENEMY_OLD_BIRD_ROCKET = "DeathEnemyOldBirdRocket"; public const string TAG_DEATH_ENEMY_OLD_BIRD_STOMP = "DeathEnemyOldBirdStomp"; public const string TAG_DEATH_ENEMY_OLD_BIRD_CHARGE = "DeathEnemyOldBirdCharge"; public const string TAG_DEATH_ENEMY_OLD_BIRD_TORCH = "DeathEnemyOldBirdTorch"; public const string TAG_DEATH_ENEMY_KIDNAPPER_FOX = "DeathEnemyKidnapperFox"; public const string TAG_DEATH_ENEMY_BARBER = "DeathEnemyBarber"; public const string TAG_DEATH_ENEMY_MANEATER = "DeathEnemyManeater"; public const string TAG_DEATH_ENEMY_GIANT_SAPSUCKER = "DeathEnemyGiantSapsucker"; public const string TAG_DEATH_ENEMY_CADAVER_GROWTH = "DeathEnemyCadaverGrowth"; public const string TAG_DEATH_ENEMY_CADAVER_BLOOM = "DeathEnemyCadaverBloom"; public const string TAG_DEATH_ENEMY_FEIOPAR = "DeathEnemyFeiopar"; public const string TAG_DEATH_PLAYER_JETPACK_GRAVITY = "DeathPlayerJetpackGravity"; public const string TAG_DEATH_PLAYER_JETPACK_BLAST = "DeathPlayerJetpackBlast"; public const string TAG_DEATH_PLAYER_LADDER = "DeathPlayerLadder"; public const string TAG_DEATH_PLAYER_MURDER_SHOVEL = "DeathPlayerMurderShovel"; public const string TAG_DEATH_PLAYER_MURDER_STOP_SIGN = "DeathPlayerMurderStopSign"; public const string TAG_DEATH_PLAYER_MURDER_YIELD_SIGN = "DeathPlayerMurderYieldSign"; public const string TAG_DEATH_PLAYER_MURDER_KNIFE = "DeathPlayerMurderKnife"; public const string TAG_DEATH_PLAYER_EASTER_EGG = "DeathPlayerEasterEgg"; public const string TAG_DEATH_PLAYER_MURDER_SHOTGUN = "DeathPlayerMurderShotgun"; public const string TAG_DEATH_PLAYER_QUICKSAND = "DeathPlayerQuicksand"; public const string TAG_DEATH_PLAYER_STUN_GRENADE = "DeathPlayerStunGrenade"; public const string TAG_DEATH_PLAYER_ELECTRIC_CHAIR = "DeathPlayerElectricChair"; public const string TAG_DEATH_PLAYER_VOMITING = "DeathPlayerVomiting"; public const string TAG_DEATH_PLAYER_CRUISER_DRIVER = "DeathPlayerCruiserDriver"; public const string TAG_DEATH_PLAYER_CRUISER_PASSENGER = "DeathPlayerCruiserPassenger"; public const string TAG_DEATH_PLAYER_CRUISER_EXPLODE_BYSTANDER = "DeathPlayerCruiserExplodeBystander"; public const string TAG_DEATH_PLAYER_CRUISER_RAN_OVER = "DeathPlayerCruiserRanOver"; public const string TAG_DEATH_PIT_GENERIC = "DeathPitGeneric"; public const string TAG_DEATH_PIT_FACILITY_PIT = "DeathPitFacilityPit"; public const string TAG_DEATH_PIT_FACILITY_CATWALK_JUMP = "DeathPitFacilityCatwalkJump"; public const string TAG_DEATH_PIT_MINE_PIT = "DeathPitMinePit"; public const string TAG_DEATH_PIT_MINE_CAVE = "DeathPitMineCave"; public const string TAG_DEATH_PIT_MINE_ELEVATOR = "DeathPitMineElevator"; public const string TAG_DEATH_OTHER_DEPOSIT_ITEMS_DESK = "DeathOtherDepositItemsDesk"; public const string TAG_DEATH_OTHER_ITEM_DROPSHIP = "DeathOtherItemDropship"; public const string TAG_DEATH_OTHER_LANDMINE = "DeathOtherLandmine"; public const string TAG_DEATH_OTHER_TURRET = "DeathOtherTurret"; public const string TAG_DEATH_OTHER_LIGHTNING = "DeathOtherLightning"; public const string TAG_DEATH_OTHER_METEOR = "DeathOtherMeteor"; public const string TAG_DEATH_OTHER_SPIKE_TRAP = "DeathOtherSpikeTrap"; public const string TAG_DEATH_OTHER_OUT_OF_BOUNDS = "DeathOtherOutOfBounds"; public const string TAG_DEATH_UNKNOWN = "DeathUnknown"; public string languageCode; private Dictionary> languageData; private bool fallback; public LanguageHandler(string languageCode, bool fallback = false) { Plugin.Instance.PluginLogger.LogInfo("Coroner loading " + (fallback ? "fallback " : "") + "language support: " + languageCode); this.languageCode = languageCode; this.fallback = fallback; languageData = new Dictionary>(); LoadLanguageData(languageCode); } private void LoadLanguageData(string languageCode) { if (!Directory.Exists(Plugin.Instance.GetConfigPath())) { Plugin.Instance.PluginLogger.LogError("Config folder not found at: " + Plugin.Instance.GetConfigPath()); string path = Plugin.AssemblyDirectory + "/BepInEx/config/EliteMasterEric-Coroner/Strings_" + languageCode + ".xml"; if (File.Exists(path)) { Plugin.Instance.PluginLogger.LogError("IMPORTANT: You didn't install the mod correctly! Move the BepInEx/config folder to the right spot!"); } else { Plugin.Instance.PluginLogger.LogError("Try reinstalling the mod from scratch."); } return; } if (!File.Exists(Plugin.Instance.GetConfigPath() + "/Strings_" + languageCode + ".xml")) { Plugin.Instance.PluginLogger.LogError("Localization File not found at: " + Plugin.Instance.GetConfigPath()); return; } Plugin.Instance.PluginLogger.LogInfo("Loading language data from config folder: " + Plugin.Instance.GetConfigPath()); XDocument xDocument = XDocument.Load(Plugin.Instance.GetConfigPath() + "/Strings_" + languageCode + ".xml"); if (xDocument == null) { Plugin.Instance.PluginLogger.LogError("Localization could not be parsed at: " + Plugin.Instance.GetConfigPath() + "/Strings_" + languageCode + ".xml"); return; } PopulateLanguageData(xDocument); string[] array = Directory.GetFiles(Plugin.Instance.GetConfigPath(), "Strings_" + languageCode + "_*.xml").ToArray(); Plugin.Instance.PluginLogger.LogInfo($"Loading {array.Length} additional language data files from config folder"); for (int i = 0; i < array.Length; i++) { Plugin.Instance.PluginLogger.LogInfo("Loading additional language data file: " + array[i]); XDocument languageDoc = XDocument.Load(array[i]); PopulateLanguageData(languageDoc, append: true); } Plugin.Instance.PluginLogger.LogInfo($"Success, loaded {languageData.Count()} types of language tags with {CountLanguageEntries()} total entries."); } public void PopulateLanguageData(XDocument languageDoc, bool append = false) { if (!append) { languageData.Clear(); } XElement xElement = languageDoc.Descendants("strings").First(); foreach (XElement item in xElement.Descendants()) { string text = item.Name.ToString(); string value = item.Attribute("text").Value; if (!languageData.ContainsKey(text)) { languageData[text] = new List(); } List list = languageData[text]; if (list != null) { list.Add(value); languageData[text] = list; } else { Plugin.Instance.PluginLogger.LogError("Current values for key '" + text + "' is null!"); } } } public int CountLanguageEntries() { return languageData.Sum>>((KeyValuePair> x) => x.Value.Count); } public string GetFirstValueByTag(string tag) { return GetValuesByTag(tag)[0]; } public string[] GetValuesByTag(string tag) { if (languageData.Count == 0 && languageCode != "en-us") { Plugin.Instance.PluginLogger.LogWarning("No language data loaded for '" + languageCode + "', displaying fallback language en-us..."); return Plugin.Instance.FallbackLanguageHandler.GetValuesByTag(tag); } if (languageData.Count == 0) { Plugin.Instance.PluginLogger.LogWarning("No language data loaded for default language, displaying error text..."); return new string[1] { "{'" + tag + "'}" }; } if (!languageData.ContainsKey(tag) && languageCode != "en-us") { Plugin.Instance.PluginLogger.LogWarning("No values found for tag '" + tag + "' in language '" + languageCode + "', displaying fallback language en-us..."); return Plugin.Instance.FallbackLanguageHandler.GetValuesByTag(tag); } if (!languageData.ContainsKey(tag)) { Plugin.Instance.PluginLogger.LogWarning("No values found for tag '" + tag + "' in language '" + languageCode + "', displaying error text..."); return new string[1] { "{'" + tag + "'}" }; } List list = languageData[tag]; if ((list == null || list.Count == 0) && languageCode != "en-us") { Plugin.Instance.PluginLogger.LogWarning("No values found for tag '" + tag + "' in language '" + languageCode + "', displaying fallback language en-us..."); return Plugin.Instance.FallbackLanguageHandler.GetValuesByTag(tag); } if (list == null || list.Count == 0) { Plugin.Instance.PluginLogger.LogWarning("No values found for tag '" + tag + "' in language '" + languageCode + "', displaying error text..."); return new string[1] { "{'" + tag + "'}" }; } return list.ToArray(); } } [StaticNetcode] internal class NetworkRPC { [ServerRpc(RequireOwnership = false)] public static void ReportCauseOfDeathServerRpc(int playerClientId, string? codLanguageTag, bool forceOverride) { Plugin.Instance.PluginLogger.LogDebug(string.Format("Server received cause of death via RPC: ({0}, {1})", playerClientId, (codLanguageTag == null) ? "null" : codLanguageTag)); BroadcastCauseOfDeathClientRpc(playerClientId, codLanguageTag, forceOverride); } [ClientRpc(/*Could not decode attribute arguments.*/)] public static void BroadcastCauseOfDeathClientRpc(int playerClientId, string? codLanguageTag, bool forceOverride) { Plugin.Instance.PluginLogger.LogDebug(string.Format("Client received cause of death via RPC: ({0}, {1})", playerClientId, (codLanguageTag == null) ? "null" : codLanguageTag)); if (codLanguageTag == null || !AdvancedCauseOfDeath.IsTagRegistered(codLanguageTag)) { Plugin.Instance.PluginLogger.LogError("Could not deserialize cause of death (" + codLanguageTag + ")"); return; } AdvancedCauseOfDeath? advancedCauseOfDeath = AdvancedCauseOfDeath.Fetch(codLanguageTag); Plugin.Instance.PluginLogger.LogDebug($"Deserialized cause of death to {advancedCauseOfDeath}"); AdvancedDeathTracker.StoreLocalCauseOfDeath(playerClientId, advancedCauseOfDeath, forceOverride); } } public static class PluginInfo { public const string PLUGIN_ID = "Coroner"; public const string PLUGIN_NAME = "Coroner"; public const string PLUGIN_AUTHOR = "EliteMasterEric"; public const string PLUGIN_VERSION = "2.3.0"; public const string PLUGIN_GUID = "com.elitemastereric.coroner"; } [BepInPlugin("com.elitemastereric.coroner", "Coroner", "2.3.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public static readonly Random RANDOM = new Random(); public PluginLogger PluginLogger; internal PluginConfig PluginConfig; internal LanguageHandler LanguageHandler; internal LanguageHandler FallbackLanguageHandler; public static Plugin Instance { get; private set; } public static string AssemblyDirectory { get { string codeBase = Assembly.GetExecutingAssembly().CodeBase; UriBuilder uriBuilder = new UriBuilder(codeBase); string path = Uri.UnescapeDataString(uriBuilder.Path); return Path.GetDirectoryName(path); } } private void Awake() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown Instance = this; PluginLogger = new PluginLogger(((BaseUnityPlugin)this).Logger); Harmony val = new Harmony("com.elitemastereric.coroner"); val.PatchAll(); PluginLogger.LogInfo("Plugin Coroner (com.elitemastereric.coroner) is loaded!"); LoadConfig(); LoadLanguageHandlers(); } public string GetConfigPath() { return Paths.ConfigPath + "/EliteMasterEric-Coroner"; } public void LoadLanguageHandlers() { LanguageHandler = new LanguageHandler(PluginConfig.GetSelectedLanguage()); FallbackLanguageHandler = new LanguageHandler("en-us", fallback: true); } private void LoadConfig() { PluginConfig = new PluginConfig(); PluginConfig.BindConfig(((BaseUnityPlugin)this).Config); } } public class PluginLogger { private ManualLogSource manualLogSource; public PluginLogger(ManualLogSource manualLogSource) { this.manualLogSource = manualLogSource; } public void LogFatal(object data) { manualLogSource.LogFatal(data); } public void LogError(object data) { manualLogSource.LogError(data); } public void LogWarning(object data) { manualLogSource.LogWarning(data); } public void LogMessage(object data) { manualLogSource.LogMessage(data); } public void LogInfo(object data) { manualLogSource.LogInfo(data); } public void LogDebug(object data) { manualLogSource.LogDebug(data); } } internal class PluginConfig { private ConfigEntry? DisplayCauseOfDeath = null; private ConfigEntry? SeriousDeathMessages = null; private ConfigEntry? DisplayFunnyNotes = null; private ConfigEntry? DeathReplacesNotes = null; private ConfigEntry? LanguagePicker = null; public void BindConfig(ConfigFile _config) { DisplayCauseOfDeath = _config.Bind("General", "DisplayCauseOfDeath", true, "Display the cause of death in the player notes."); SeriousDeathMessages = _config.Bind("General", "SeriousDeathMessages", false, "Cause of death messages are more to-the-point."); DisplayFunnyNotes = _config.Bind("General", "DisplayFunnyNotes", true, "Display a random note when the player has no notes."); DeathReplacesNotes = _config.Bind("General", "DeathReplacesNotes", true, "True to replace notes when the player dies, false to append."); LanguagePicker = _config.Bind("Language", "LanguagePicker", "en-us", "Select a language to use."); } public bool ShouldDisplayCauseOfDeath() { if (DisplayCauseOfDeath == null) { Plugin.Instance.PluginLogger.LogWarning("Invalid access to uninstantiated config value DisplayCauseOfDeath"); return true; } return DisplayCauseOfDeath.Value; } public bool ShouldUseSeriousDeathMessages() { if (SeriousDeathMessages == null) { Plugin.Instance.PluginLogger.LogWarning("Invalid access to uninstantiated config value SeriousDeathMessages"); return false; } return SeriousDeathMessages.Value; } public bool ShouldDisplayFunnyNotes() { if (DisplayFunnyNotes == null) { Plugin.Instance.PluginLogger.LogWarning("Invalid access to uninstantiated config value DisplayFunnyNotes"); return true; } return DisplayFunnyNotes.Value; } public bool ShouldDeathReplaceNotes() { if (DeathReplacesNotes == null) { Plugin.Instance.PluginLogger.LogWarning("Invalid access to uninstantiated config value DeathReplacesNotes"); return true; } return DeathReplacesNotes.Value; } public string GetSelectedLanguage() { if (LanguagePicker == null) { Plugin.Instance.PluginLogger.LogWarning("Invalid access to uninstantiated config value LanguagePicker"); return "en-us"; } return LanguagePicker.Value.Replace('_', '-'); } } } namespace Coroner.Patch { internal class CauseOfDeathPatch { public const string KILL_PLAYER_SIGNATURE = "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3, Boolean)"; public const string DAMAGE_PLAYER_SIGNATURE = "Void DamagePlayer(Int32, Boolean, Boolean, CauseOfDeath, Int32, Boolean, UnityEngine.Vector3)"; public static void LogException(Exception e, string location) { Plugin.Instance.PluginLogger.LogError("Caught exception in " + location + ": " + e.Message); Plugin.Instance.PluginLogger.LogError(e.StackTrace); } public static bool IsPlayer(Collider collider) { if ((Object)(object)collider == (Object)null) { return false; } return (Object)(object)((Component)collider).gameObject.GetComponent() != (Object)null; } public static int LocateKillPlayerCall(List instructions) { for (int i = 0; i < instructions.Count; i++) { CodeInstruction val = instructions[i]; if (val.opcode == OpCodes.Callvirt && val.operand.ToString() == "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3, Boolean)") { return i; } } return -1; } public static int LocateDamagePlayerCall(List instructions) { for (int i = 0; i < instructions.Count; i++) { CodeInstruction val = instructions[i]; if (val.opcode == OpCodes.Callvirt && val.operand.ToString() == "Void DamagePlayer(Int32, Boolean, Boolean, CauseOfDeath, Int32, Boolean, UnityEngine.Vector3)") { return i; } } return -1; } public static void OverrideKillLocalPlayer(KillLocalPlayer target, AdvancedCauseOfDeath causeOfDeath) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)target == (Object)null)) { target.causeOfDeath = causeOfDeath; } } public static void OverrideKillLocalPlayer(GameObject target, AdvancedCauseOfDeath causeOfDeath) { if (!((Object)(object)target == (Object)null)) { OverrideKillLocalPlayer(target.GetComponent(), causeOfDeath); } } public static void OverrideKillLocalPlayer(Transform target, AdvancedCauseOfDeath causeOfDeath) { if (!((Object)(object)target == (Object)null)) { OverrideKillLocalPlayer(((Component)target).gameObject, causeOfDeath); } } } internal class CauseOfDeathPatchState { private int targetPlayerIndex; private bool wasPlayerQueried; public bool previousIsPlayerDead; public CauseOfDeath? previousCauseOfDeath = null; public bool wasHoldingJetpack; public CauseOfDeathPatchState() { targetPlayerIndex = -1; wasPlayerQueried = false; } public void TrySetPlayer(int targetPlayerIndex) { if (targetPlayerIndex < 0) { Plugin.Instance.PluginLogger.LogWarning("Could not access dying player: Invalid player index! " + targetPlayerIndex); } else { this.targetPlayerIndex = targetPlayerIndex; } } public void TrySetPlayer(PlayerControllerB playerControllerB) { if ((Object)(object)playerControllerB == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access dying player: PlayerController was null"); } else { TrySetPlayer((int)playerControllerB.playerClientId); } } public void TrySetPlayer(Collider collider) { if ((Object)(object)collider == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access dying player: Collider was null!"); return; } if (!CauseOfDeathPatch.IsPlayer(collider)) { Plugin.Instance.PluginLogger.LogWarning("Could not access dying player: Collider was not a player!"); return; } PlayerControllerB component = ((Component)collider).gameObject.GetComponent(); TrySetPlayer(component); } public void QueryPlayerState() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (wasPlayerQueried) { Plugin.Instance.PluginLogger.LogWarning("Tried to query player state, but we already did that? " + ToString()); return; } PlayerControllerB val = FetchPlayer(); if (!((Object)(object)val == (Object)null)) { Plugin.Instance.PluginLogger.LogDebug("Querying target player parameters pre-death..."); wasPlayerQueried = true; previousIsPlayerDead = val.isPlayerDead; previousCauseOfDeath = val.causeOfDeath; wasHoldingJetpack = AdvancedDeathTracker.IsHoldingJetpack(val); Plugin.Instance.PluginLogger.LogDebug("Query successful!" + wasPlayerQueried); } } public int FetchPlayerIndex() { if (targetPlayerIndex == -1) { Plugin.Instance.PluginLogger.LogWarning("Could not access dying player: Index not assigned!"); return -1; } return targetPlayerIndex; } public PlayerControllerB? FetchPlayer() { if (targetPlayerIndex == -1) { Plugin.Instance.PluginLogger.LogWarning("Could not access dying player: Index not assigned!"); return null; } if (targetPlayerIndex >= StartOfRound.Instance.allPlayerScripts.Length) { Plugin.Instance.PluginLogger.LogWarning("Could not access dying player: Index out of bounds! " + targetPlayerIndex); return null; } return StartOfRound.Instance.allPlayerScripts[targetPlayerIndex]; } public PlayerControllerB GetPlayer() { PlayerControllerB val = FetchPlayer(); if ((Object)(object)val == (Object)null) { throw new Exception("Could not retrieve player from state!"); } return val; } public bool ValidateWasntAlreadyDead() { if (!wasPlayerQueried) { return false; } PlayerControllerB val = FetchPlayer(); if ((Object)(object)val == (Object)null) { return false; } if (previousIsPlayerDead) { Plugin.Instance.PluginLogger.LogWarning("Could not access dying player: Player was already dead!"); return false; } return true; } public bool ValidateIsPlayerDead(bool verbose = true) { if (!wasPlayerQueried) { return false; } PlayerControllerB val = FetchPlayer(); if ((Object)(object)val == (Object)null) { return false; } if (!val.isPlayerDead) { if (verbose) { Plugin.Instance.PluginLogger.LogWarning("Could not access dying player: Player is still alive!"); } return false; } return true; } public bool ValidateHasNoCauseOfDeath() { if (!wasPlayerQueried) { return false; } if (AdvancedDeathTracker.HasCauseOfDeath(FetchPlayerIndex())) { Plugin.Instance.PluginLogger.LogWarning("Could not access dying player: Player already had a precise cause of death!"); return false; } return true; } public override string ToString() { return $"CauseOfDeathPatchState({targetPlayerIndex}:{wasPlayerQueried}, {previousIsPlayerDead}==false?)"; } } internal class CauseOfDeathEnumerator : EnumeratorPatch { public Action? preDeathAction; public Action? postDeathAction; public Action? postDeathStepAction; public CauseOfDeathEnumerator(IEnumerator targetEnumerator) : base(targetEnumerator) { CauseOfDeathPatchState state = new CauseOfDeathPatchState(); prefixAction = delegate { preDeathAction?.Invoke(state); Plugin.Instance.PluginLogger.LogDebug("Post step action done: " + state.ToString()); }; postfixAction = delegate { postDeathAction?.Invoke(state); Plugin.Instance.PluginLogger.LogDebug("Post step action done: " + state.ToString()); }; postStepAction = delegate { postDeathStepAction?.Invoke(state); Plugin.Instance.PluginLogger.LogDebug("Post step action done: " + state.ToString()); }; } } [HarmonyPatch(typeof(BaboonBirdAI), "OnCollideWithPlayer")] internal class BaboonBirdAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "BaboonBirdAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Baboon Hawk damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Baboon Hawk killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_BaboonHawk); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "BaboonBirdAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(ButlerBeesEnemyAI), "OnCollideWithPlayer")] internal class ButlerBeesEnemyAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ButlerBeesEnemyAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Mask Hornet damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Mask Hornet killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_MaskHornets); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ButlerBeesEnemyAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(ButlerEnemyAI), "OnCollideWithPlayer")] internal class ButlerEnemyAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ButlerEnemyAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Butler damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Butler killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Butler_Stab); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ButlerEnemyAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(CadaverBloomAI), "OnCollideWithPlayer")] internal class CadaverBloomAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "CadaverBloomAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Cadaver Bloom damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Cadaver Bloom killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Cadaver_Bloom); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "CadaverBloomAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(GiantKiwiAI), "AnimationEventB")] internal class GiantKiwiAIAnimationEventBPatch { public static void Prefix(ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(GameNetworkManager.Instance.localPlayerController); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "GiantKiwiAI.AnimationEventB:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Giant Sapsucker damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Giant Sapsucker killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Giant_Sapsucker); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "GiantKiwiAI.AnimationEventB:Postfix"); } } } [HarmonyPatch(typeof(LassoManAI), "OnCollideWithPlayer")] internal class LassoManAIOnCollideWithPlayer { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "LassoManAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Lasso Man damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Lasso Man killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_LassoMan); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "LassoManAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(MoveToExitSpecialAnimation), "shockChair")] internal class MoveToExitSpecialAnimationShockChairPatch { public static void Prefix(MoveToExitSpecialAnimation __instance, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(((Component)__instance.interactTrigger.lockedPlayer).GetComponent()); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "MoveToExitSpecialAnimation.shockChair:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Lasso Man damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Electric Chair killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Player_Electric_Chair); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "MoveToExitSpecialAnimation.shockChair:Postfix"); } } } [HarmonyPatch(typeof(PufferAI), "OnCollideWithPlayer")] internal class PufferAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "PufferAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Spore Lizard damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Spore Lizard killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_SporeLizard); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "PufferAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(PumaAI), "OnCollideWithPlayer")] internal class PumaAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "PumaAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Feiopar damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Feiopar killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Feiopar); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "PumaAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(RadMechAI), "Stomp")] internal class RadMechAIStompPatch { public static void Prefix(ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(GameNetworkManager.Instance.localPlayerController); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "RadMechAI.Stomp:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Old Bird (Stomp) damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Old Bird killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Old_Bird_Stomp); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "RadMechAI.Stomp:Postfix"); } } } [HarmonyPatch(typeof(RadMechAI), "TorchPlayerAnimation")] internal class RadMechAITorchPlayerAnimationPatch { public static void Postfix(RadMechAI __instance, ref IEnumerator __result) { RadMechAI __instance2 = __instance; try { CauseOfDeathEnumerator causeOfDeathEnumerator = new CauseOfDeathEnumerator(__result) { preDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorPrefix(__instance2, __state); }, postDeathStepAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); }, postDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); } }; __result = causeOfDeathEnumerator.GetEnumerator(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "RadMechAI.TorchPlayerAnimation:Postfix"); } } private static void EnumeratorPrefix(RadMechAI __instance, CauseOfDeathPatchState __state) { try { __state.TrySetPlayer(((EnemyAI)__instance).inSpecialAnimationWithPlayer); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "RadMechAI.TorchPlayerAnimation:EnumeratorPrefix"); } } private static void EnumeratorStepPostfix(RadMechAI __instance, CauseOfDeathPatchState __state) { try { PlayerControllerB player = __state.GetPlayer(); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Old Bird killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Old_Bird_Torch); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "RadMechAI.TorchPlayerAnimation:EnumeratorStepPostfix"); } } } [HarmonyPatch(typeof(SandSpiderAI), "OnCollideWithPlayer")] internal class SandSpiderAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "SandSpiderAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Bunker Spider damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Bunker Spider killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_BunkerSpider); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "SandSpiderAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(BlobAI), "OnCollideWithPlayer")] internal class BlobAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "BlobAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Bunker Spider damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Bunker Spider killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Hygrodere); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "BlobAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(CentipedeAI), "DamagePlayerOnIntervals")] internal class CentipedeAIDamagePlayerOnIntervalsPatch { public static void Prefix(CentipedeAI __instance, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(__instance.clingingToPlayer); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "CentipedeAI.DamagePlayerOnIntervals:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Centipede damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Centipede killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_SnareFlea); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "CentipedeAI.DamagePlayerOnIntervals:Postfix"); } } } [HarmonyPatch(typeof(CrawlerAI), "OnCollideWithPlayer")] internal class CrawlerAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "CrawlerAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Thumper damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Thumper killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Thumper); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "CrawlerAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(RedLocustBees), "BeeKillPlayerOnLocalClient")] internal class RedLocustBeesBeeKillPlayerOnLocalClientPatch { public static void Prefix(int playerId, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(playerId); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "RedLocustBees.BeeKillPlayerOnLocalClient:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Circuit Bees damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Circuit Bees killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_CircuitBees); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "RedLocustBees.BeeKillPlayerOnLocalClient:Postfix"); } } } [HarmonyPatch(typeof(HoarderBugAI), "OnCollideWithPlayer")] internal class HoarderBugAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "HoarderBugAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Hoarder Bug damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Hoarder Bug killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_HoarderBug); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "HoarderBugAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(SpringManAI), "OnCollideWithPlayer")] internal class SpringManAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "SpringManAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Coil-Head damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Coil-Head killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_CoilHead); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "SpringManAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(ShotgunItem), "ShootGun")] internal class ShotgunItemShootGunPatch { public static void Prefix(ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(GameNetworkManager.Instance.localPlayerController); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ShotgunItem.ShootGun:Prefix"); } } public static void Postfix(ShotgunItem __instance, ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Shotgun damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Shotgun killed Player! Checking wielder..."); if (((GrabbableObject)__instance).isHeldByEnemy) { Plugin.Instance.PluginLogger.LogDebug("Shotgun (Nutcracker) killed player! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Nutcracker_Shot); } else { Plugin.Instance.PluginLogger.LogDebug("Shotgun (Player) killed player! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Player_Murder_Shotgun); } } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ShotgunItem.ShootGun:Postfix"); } } } [HarmonyPatch(typeof(SprayPaintItem), "HealPlayerInfection")] internal class SprayPaintItemHealPlayerInfectionPatch { public static void Prefix(ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(GameNetworkManager.Instance.localPlayerController); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "SprayPaintItem.HealPlayerInfection:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling vomiting damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Vomiting killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Player_Vomiting); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "SprayPaintItem.HealPlayerInfection:Postfix"); } } } [HarmonyPatch(typeof(StunGrenadeItem), "StunExplosion")] internal class StunGrenadeItemStunExplosionPatch { public static void Prefix(StunGrenadeItem __instance, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(((GrabbableObject)__instance).playerHeldBy); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "StunGrenadeItem.StunExplosion:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Stun Grenade damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Stun Grenade killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Player_StunGrenade); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "StunGrenadeItem.StunExplosion:Postfix"); } } } [HarmonyPatch(typeof(VehicleCollisionTrigger), "OnTriggerEnter")] internal class VehicleCollisionTriggerOnTriggerEnterPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } if (!((Component)other).gameObject.CompareTag("Player")) { Plugin.Instance.PluginLogger.LogDebug("Vehicle collision with non-player..."); return; } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "VehicleCollisionTrigger.OnTriggerEnter:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Vehicle damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Vehicle (Collision) killed Player (Pedestrian)! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Player_Cruiser_Ran_Over); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "VehicleCollisionTrigger.OnTriggerEnter:Postfix"); } } } [HarmonyPatch(typeof(VehicleController), "DamagePlayerInVehicle")] internal class VehicleControllerDamagePlayerInVehiclePatch { public static void Prefix(VehicleController __instance, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } if (__instance.localPlayerInControl || __instance.localPlayerInPassengerSeat) { __state.TrySetPlayer(GameNetworkManager.Instance.localPlayerController); __state.QueryPlayerState(); } else { Plugin.Instance.PluginLogger.LogDebug("Couldn't determine player in vehicle..."); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "VehicleController.DamagePlayerInVehicle:Prefix"); } } public static void Postfix(VehicleController __instance, ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Vehicle damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { if (__instance.localPlayerInControl) { Plugin.Instance.PluginLogger.LogDebug("Vehicle (Collision) killed Player (Driver)! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Player_Cruiser_Driver); } else if (__instance.localPlayerInPassengerSeat) { Plugin.Instance.PluginLogger.LogDebug("Vehicle (Collision) killed Player (Passenger)! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Player_Cruiser_Passenger); } else { Plugin.Instance.PluginLogger.LogDebug("Couldn't determine player in vehicle..."); } } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "VehicleController.DamagePlayerInVehicle:Postfix"); } } } [HarmonyPatch(typeof(PlayerControllerB), "PlayerHitGroundEffects")] internal class PlayerControllerBPlayerHitGroundEffectsPatch { public static void Prefix(PlayerControllerB __instance, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(__instance); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "PlayerControllerB.PlayerHitGroundEffects:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { if (__state.ValidateIsPlayerDead(verbose: false) && __state.ValidateWasntAlreadyDead() && __state.ValidateHasNoCauseOfDeath()) { PlayerControllerB player = __state.GetPlayer(); FootstepSurface val = StartOfRound.Instance.footstepSurfaces[player.currentFootstepSurfaceIndex]; if (val != null) { Plugin.Instance.PluginLogger.LogDebug("Fall damage (surface tag: $" + val.surfaceTag + ") killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(player, AdvancedCauseOfDeath.Gravity); } else { Plugin.Instance.PluginLogger.LogDebug("Fall damage (unknown surface) killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(player, AdvancedCauseOfDeath.Gravity); } } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "PlayerControllerB.PlayerHitGroundEffects:Postfix"); } } } [HarmonyPatch(typeof(PlayerControllerB), "DamagePlayerFromOtherClientClientRpc")] internal class PlayerControllerBDamagePlayerFromOtherClientClientRpcPatch { private const string DAMAGE_PLAYER_SIGNATURE = "Void DamagePlayer(Int32, Boolean, Boolean, CauseOfDeath, Int32, Boolean, UnityEngine.Vector3)"; public static void Prefix(PlayerControllerB __instance, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(__instance); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "PlayerControllerB.DamagePlayerFromOtherClientClientRpc:Prefix"); } } public static void Postfix(int playerWhoHit, ref CauseOfDeathPatchState __state) { //IL_01e8: Unknown result type (might be due to invalid IL or missing references) try { Plugin.Instance.PluginLogger.LogDebug("Handling friendly fire damage..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { PlayerControllerB player = __state.GetPlayer(); PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerWhoHit]; if ((Object)(object)val == (Object)null) { Plugin.Instance.PluginLogger.LogError("Damage from other player: attacker is null!"); } else if (AdvancedDeathTracker.IsHoldingShotgun(val)) { Plugin.Instance.PluginLogger.LogDebug("Player was murdered by Shotgun! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(player, AdvancedCauseOfDeath.Player_Murder_Shotgun); } else if (AdvancedDeathTracker.IsHoldingKnife(val)) { Plugin.Instance.PluginLogger.LogDebug("Player was murdered by Knife! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(player, AdvancedCauseOfDeath.Player_Murder_Knife); } else if (AdvancedDeathTracker.IsHoldingShovel(val)) { Plugin.Instance.PluginLogger.LogDebug("Player was murdered by Shovel! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(player, AdvancedCauseOfDeath.Player_Murder_Shovel); } else if (AdvancedDeathTracker.IsHoldingStopSign(val)) { Plugin.Instance.PluginLogger.LogDebug("Player was murdered by Stop Sign! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(player, AdvancedCauseOfDeath.Player_Murder_Stop_Sign); } else if (AdvancedDeathTracker.IsHoldingYieldSign(val)) { Plugin.Instance.PluginLogger.LogDebug("Player was murdered by Yield Sign! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(player, AdvancedCauseOfDeath.Player_Murder_Yield_Sign); } else { Plugin.Instance.PluginLogger.LogWarning($"Player was murdered, by an unknown item {AdvancedDeathTracker.GetHeldObject(val)}! Setting cause of death to: " + ((object)(CauseOfDeath)(ref player.causeOfDeath)).ToString()); AdvancedDeathTracker.SetCauseOfDeath(player, player.causeOfDeath); } } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "PlayerControllerBDamagePlayerFromOtherClientClientRpcPatch:Postfix"); } } private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator, MethodBase method) { List list = new List(instructions); List list2 = BuildInstructionsToInsert(method); if (list2 == null) { Plugin.Instance.PluginLogger.LogError("Could not build instructions to insert in PlayerControllerBDamagePlayerFromOtherClientClientRpcPatch! Safely aborting..."); return instructions; } int num = -1; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Call && val.operand.ToString() == "Void DamagePlayer(Int32, Boolean, Boolean, CauseOfDeath, Int32, Boolean, UnityEngine.Vector3)") { num = i; } } if (num == -1) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB.DamagePlayer call in PlayerControllerBDamagePlayerFromOtherClientClientRpcPatch! Safely aborting..."); return instructions; } Plugin.Instance.PluginLogger.LogDebug("Injecting patch into PlayerControllerB.DamagePlayerFromOtherClientClientRpc..."); list.InsertRange(num + 1, list2); Plugin.Instance.PluginLogger.LogDebug("Done."); Plugin.Instance.PluginLogger.LogDebug("Done with all PlayerControllerBDamagePlayerFromOtherClientClientRpcPatch patches."); return list; } private static List? BuildInstructionsToInsert(MethodBase method) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown List list = new List(); int num = 0; int num2 = 1; int num3 = 2; int num4 = 3; int num5 = 4; list.Add(new CodeInstruction(OpCodes.Ldarg, (object)num)); list.Add(new CodeInstruction(OpCodes.Ldarg, (object)num2)); list.Add(new CodeInstruction(OpCodes.Ldarg, (object)num3)); list.Add(new CodeInstruction(OpCodes.Ldarg, (object)num4)); list.Add(new CodeInstruction(OpCodes.Ldarg, (object)num5)); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(PlayerControllerBDamagePlayerFromOtherClientClientRpcPatch).GetMethod("MaybeRewriteCauseOfDeath"))); return list; } public static void MaybeRewriteCauseOfDeath(PlayerControllerB targetPlayer, int damageAmount, Vector3 hitDirection, int playerWhoHit, int newHealthAmount) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) Plugin.Instance.PluginLogger.LogDebug($"Player damaged another player ${targetPlayer}({damageAmount}, {hitDirection}, {playerWhoHit}, {newHealthAmount})"); if (targetPlayer.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player died from friendly fire damage"); RewriteCauseOfDeath(targetPlayer, playerWhoHit); } else { Plugin.Instance.PluginLogger.LogDebug($"Player did not die from friendly fire (left at ${targetPlayer.health} health)"); } } public static void RewriteCauseOfDeath(PlayerControllerB targetPlayer, int playerWhoHitIndex) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerWhoHitIndex]; if ((Object)(object)targetPlayer == (Object)null) { Plugin.Instance.PluginLogger.LogError("Damage from other client: victim is null!"); return; } if ((Object)(object)val == (Object)null) { Plugin.Instance.PluginLogger.LogError("Damage from other client: attacker is null!"); return; } Plugin.Instance.PluginLogger.LogDebug($"Player died from murder ({targetPlayer.causeOfDeath}), determining special cause of death..."); if (AdvancedDeathTracker.IsHoldingShotgun(val)) { Plugin.Instance.PluginLogger.LogDebug("Player was murdered by Shotgun! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(targetPlayer, AdvancedCauseOfDeath.Player_Murder_Shotgun); } else if (AdvancedDeathTracker.IsHoldingKnife(val)) { Plugin.Instance.PluginLogger.LogDebug("Player was murdered by Knife! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(targetPlayer, AdvancedCauseOfDeath.Player_Murder_Knife); } else if (AdvancedDeathTracker.IsHoldingShovel(val)) { Plugin.Instance.PluginLogger.LogDebug("Player was murdered by Shovel! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(targetPlayer, AdvancedCauseOfDeath.Player_Murder_Shovel); } else if (AdvancedDeathTracker.IsHoldingStopSign(val)) { Plugin.Instance.PluginLogger.LogDebug("Player was murdered by Stop Sign! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(targetPlayer, AdvancedCauseOfDeath.Player_Murder_Stop_Sign); } else if (AdvancedDeathTracker.IsHoldingYieldSign(val)) { Plugin.Instance.PluginLogger.LogDebug("Player was murdered by Yield Sign! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(targetPlayer, AdvancedCauseOfDeath.Player_Murder_Yield_Sign); } else { Plugin.Instance.PluginLogger.LogWarning($"Player was killed by someone else, holding an unknown item {AdvancedDeathTracker.GetHeldObject(val)}! " + ((object)(CauseOfDeath)(ref targetPlayer.causeOfDeath)).ToString()); AdvancedDeathTracker.SetCauseOfDeath(targetPlayer, targetPlayer.causeOfDeath); } } } [HarmonyPatch(typeof(AnimatedObjectFloatSetter), "KillPlayerAtPoint")] internal class AnimatedObjectFloatSetterKillPlayerAtPointPatch { public static void Prefix(ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(GameNetworkManager.Instance.localPlayerController); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "AnimatedObjectFloatSetter.KillPlayerAtPoint:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling AnimatedObjectFloatSetter death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogWarning("AnimatedObjectFloatSetter killed Player! Unknown cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Unknown); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "AnimatedObjectFloatSetter.KillPlayerAtPoint:Postfix"); } } } [HarmonyPatch(typeof(BushWolfEnemy), "OnCollideWithPlayer")] internal class BushWolfOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "BushWolf.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Kidnapper Fox death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogWarning("Kidnapper Fox killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_KidnapperFox); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "BushWolf.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(CadaverBloomAI), "BurstForth")] internal class CadaverBloomAIBurstForthPatch { public static void Prefix(PlayerControllerB player, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(player); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "CadaverBloomAI.BurstForth:Prefix"); } } public static void Postfix(bool kill, ref CauseOfDeathPatchState __state) { try { if (kill) { Plugin.Instance.PluginLogger.LogDebug("Handling Cadaver Growth death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogWarning("Cadaver Growth killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Cadaver_Growth); } } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "CadaverBloomAI.BurstForth:Postfix"); } } } [HarmonyPatch(typeof(CaveDwellerAI), "KillPlayerAnimationClientRpc")] internal class CaveDwellerAIKillPlayerAnimationClientRpcPatch { public static void Prefix(int playerObjectId, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(playerObjectId); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "CaveDwellerAI.KillPlayerAnimationClientRpc:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Maneater death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogWarning("Maneater killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Maneater); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "CaveDwellerAI.KillPlayerAnimationClientRpc:Postfix"); } } } [HarmonyPatch(typeof(ClaySurgeonAI), "OnCollideWithPlayer")] internal class ClaySurgeonAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ClaySurgeonAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Barber death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Barber killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Barber); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ClaySurgeonAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(DepositItemsDesk), "AnimationGrabPlayer")] internal class DepositItemsDeskAnimationGrabPlayerPatch { public static void Postfix(DepositItemsDesk __instance, int playerID, ref IEnumerator __result) { DepositItemsDesk __instance2 = __instance; try { CauseOfDeathEnumerator causeOfDeathEnumerator = new CauseOfDeathEnumerator(__result) { preDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorPrefix(__instance2, playerID, __state); }, postDeathStepAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); }, postDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); } }; __result = causeOfDeathEnumerator.GetEnumerator(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "DepositItemsDesk.AnimationGrabPlayer:Postfix"); } } private static void EnumeratorPrefix(DepositItemsDesk __instance, int playerID, CauseOfDeathPatchState __state) { try { __state.TrySetPlayer(playerID); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "DepositItemsDesk.AnimationGrabPlayer:EnumeratorPrefix"); } } private static void EnumeratorStepPostfix(DepositItemsDesk __instance, CauseOfDeathPatchState __state) { try { PlayerControllerB player = __state.GetPlayer(); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Deposit Desk killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Other_DepositItemsDesk); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "DepositItemsDesk.AnimationGrabPlayer:EnumeratorStepPostfix"); } } } [HarmonyPatch(typeof(HauntedMaskItem), "FinishAttaching")] internal class HauntedMaskItemFinishAttachingPatch { public static void Prefix(HauntedMaskItem __instance, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } PlayerControllerB value = Traverse.Create((object)__instance).Field("previousPlayerHeldBy").GetValue(); __state.TrySetPlayer(value); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "HauntedMaskItem.FinishAttaching:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Haunted Mask death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Haunted Mask killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_MaskedPlayer_Wear); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "HauntedMaskItem.FinishAttaching:Postfix"); } } } [HarmonyPatch(typeof(JesterAI), "killPlayerAnimation")] internal class JesterAIKillPlayerAnimationPatch { public static void Postfix(JesterAI __instance, int playerId, ref IEnumerator __result) { JesterAI __instance2 = __instance; try { CauseOfDeathEnumerator causeOfDeathEnumerator = new CauseOfDeathEnumerator(__result) { preDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorPrefix(__instance2, playerId, __state); }, postDeathStepAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); }, postDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); } }; __result = causeOfDeathEnumerator.GetEnumerator(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "JesterAI.killPlayerAnimation:Postfix"); } } private static void EnumeratorPrefix(JesterAI __instance, int playerId, CauseOfDeathPatchState __state) { try { __state.TrySetPlayer(playerId); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "JesterAI.killPlayerAnimation:EnumeratorPrefix"); } } private static void EnumeratorStepPostfix(JesterAI __instance, CauseOfDeathPatchState __state) { try { PlayerControllerB player = __state.GetPlayer(); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Jester killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Jester); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "JesterAI.killPlayerAnimation:EnumeratorStepPostfix"); } } } [HarmonyPatch(typeof(JetpackItem), "Update")] internal class JetpackItemUpdatePatch { public static void Prefix(JetpackItem __instance, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(((GrabbableObject)__instance).playerHeldBy); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "JetpackItem.Update:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { if (__state.ValidateIsPlayerDead()) { Plugin.Instance.PluginLogger.LogDebug("Handling Jetpack collision death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Jetpack (Falling/Collision) killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Player_Jetpack_Gravity); } } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "JetpackItem.Update:Postfix"); } } } [HarmonyPatch(typeof(MaskedPlayerEnemy), "FinishKillAnimation")] internal class MaskedPlayerEnemyFinishKillAnimationPatch { public static void Prefix(MaskedPlayerEnemy __instance, bool killedPlayer, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } if (killedPlayer) { __state.TrySetPlayer(((EnemyAI)__instance).inSpecialAnimationWithPlayer); __state.QueryPlayerState(); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "MaskedPlayerEnemyFinishKillAnimationPatch.Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Masked Player death..."); if (__state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Masked Player killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_MaskedPlayer_Victim); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "MaskedPlayerEnemyFinishKillAnimationPatch.Postfix"); } } } [HarmonyPatch(typeof(NutcrackerEnemyAI), "LegKickPlayer")] internal class NutcrackerEnemyAILegKickPlayerPatch { public static void Prefix(int playerId, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(playerId); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "NutcrackerEnemyAILegKickPlayerPatch.Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Nutcracker death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Nutcracker (Kicking) killed player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Nutcracker_Kicked); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "NutcrackerEnemyAILegKickPlayerPatch.Postfix"); } } } [HarmonyPatch(typeof(OutOfBoundsTrigger), "OnTriggerEnter")] internal class OutOfBoundsTriggerOnTriggerEnterPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "OutOfBoundsTrigger.OnTriggerEnter:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Out of Bounds death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Out of Bounds trigger killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Barber); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "OutOfBoundsTrigger.OnTriggerEnter:Postfix"); } } } [HarmonyPatch(typeof(SandWormAI), "EatPlayer")] internal class SandWormAIEatPlayerPatch { public static void Prefix(PlayerControllerB playerScript, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(playerScript); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "SandWormAIEatPlayerPatch.Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Earth Leviathan death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Earth Leviathan trigger killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_EarthLeviathan); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "SandWormAIEatPlayerPatch.Postfix"); } } } [HarmonyPatch(typeof(QuickMenuManager), "Debug_KillLocalPlayer")] internal class QuickMenuManagerDebugKillLocalPlayerPatch { public static void Prefix(ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(GameNetworkManager.Instance.localPlayerController); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "QuickMenuManager.Debug_KillLocalPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling debug death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Debug manager killed Player! Unknown cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Unknown); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "QuickMenuManager.Debug_KillLocalPlayer:Postfix"); } } } [HarmonyPatch(typeof(DressGirlAI), "OnCollideWithPlayer")] internal class DressGirlAIOnCollideWithPlayerPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "DressGirlAI.OnCollideWithPlayer:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Ghost Girl death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Ghost Girl killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_GhostGirl); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "DressGirlAI.OnCollideWithPlayer:Postfix"); } } } [HarmonyPatch(typeof(FlowermanAI), "killAnimation")] internal class FlowermanAIKillAnimationPatch { public static void Postfix(FlowermanAI __instance, ref IEnumerator __result) { FlowermanAI __instance2 = __instance; try { CauseOfDeathEnumerator causeOfDeathEnumerator = new CauseOfDeathEnumerator(__result) { preDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorPrefix(__instance2, __state); }, postDeathStepAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); }, postDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); } }; __result = causeOfDeathEnumerator.GetEnumerator(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "FlowermanAI.killAnimation:Postfix"); } } private static void EnumeratorPrefix(FlowermanAI __instance, CauseOfDeathPatchState __state) { try { __state.TrySetPlayer(((EnemyAI)__instance).inSpecialAnimationWithPlayer); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "FlowermanAI.killAnimation:Postfix"); } } private static void EnumeratorStepPostfix(FlowermanAI __instance, CauseOfDeathPatchState __state) { try { PlayerControllerB player = __state.GetPlayer(); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Bracken killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_Bracken); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "FlowermanAI.killAnimation:Postfix"); } } } [HarmonyPatch(typeof(ForestGiantAI), "AnimationEventA")] internal class ForestGiantAnimationEventAPatch { public static void Prefix(ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(GameNetworkManager.Instance.localPlayerController); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ForestGiantAI.AnimationEventA:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Dying Forest Giant death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Dying Forest Giant killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_ForestGiant_Death); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ForestGiantAI.AnimationEventA:Postfix"); } } } [HarmonyPatch(typeof(ForestGiantAI), "EatPlayerAnimation")] internal class ForestGiantAIEatPlayerAnimationPatch { public static void Postfix(ForestGiantAI __instance, PlayerControllerB playerBeingEaten, ref IEnumerator __result) { ForestGiantAI __instance2 = __instance; PlayerControllerB playerBeingEaten2 = playerBeingEaten; try { CauseOfDeathEnumerator causeOfDeathEnumerator = new CauseOfDeathEnumerator(__result) { preDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorPrefix(__instance2, playerBeingEaten2, __state); }, postDeathStepAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); }, postDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); } }; __result = causeOfDeathEnumerator.GetEnumerator(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ForestGiantAI.EatPlayerAnimation:Postfix"); } } private static void EnumeratorPrefix(ForestGiantAI __instance, PlayerControllerB playerBeingEaten, CauseOfDeathPatchState __state) { try { __state.TrySetPlayer(playerBeingEaten); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ForestGiantAI.EatPlayerAnimation:EnumeratorPrefix"); } } private static void EnumeratorStepPostfix(ForestGiantAI __instance, CauseOfDeathPatchState __state) { try { PlayerControllerB player = __state.GetPlayer(); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Forest Giant killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_ForestGiant_Eaten); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ForestGiantAI.EatPlayerAnimation:EnumeratorStepPostfix"); } } } [HarmonyPatch(typeof(MouthDogAI), "KillPlayer")] internal class MouthDogAIKillPlayerPatch { public static void Postfix(MouthDogAI __instance, int playerId, ref IEnumerator __result) { MouthDogAI __instance2 = __instance; try { CauseOfDeathEnumerator causeOfDeathEnumerator = new CauseOfDeathEnumerator(__result) { preDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorPrefix(__instance2, playerId, __state); }, postDeathStepAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); }, postDeathAction = delegate(CauseOfDeathPatchState __state) { EnumeratorStepPostfix(__instance2, __state); } }; __result = causeOfDeathEnumerator.GetEnumerator(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "MouthDogAI.KillPlayer:Postfix"); } } private static void EnumeratorPrefix(MouthDogAI __instance, int playerId, CauseOfDeathPatchState __state) { try { __state.TrySetPlayer(playerId); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "MouthDogAI.KillPlayer:EnumeratorPrefix"); } } private static void EnumeratorStepPostfix(MouthDogAI __instance, CauseOfDeathPatchState __state) { try { PlayerControllerB player = __state.GetPlayer(); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Eyeless Dog killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Enemy_EyelessDog); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "MouthDogAI.KillPlayer:EnumeratorStepPostfix"); } } } [HarmonyPatch(typeof(SpikeRoofTrap), "OnTriggerStay")] internal class SpikeRoofTrapOnTriggerStayPatch { public static void Prefix(Collider other, ref CauseOfDeathPatchState __state) { try { if (__state == null) { __state = new CauseOfDeathPatchState(); } __state.TrySetPlayer(other); __state.QueryPlayerState(); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "SpikeRoofTrap.OnTriggerStay:Prefix"); } } public static void Postfix(ref CauseOfDeathPatchState __state) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Spike Trap death..."); if (__state.ValidateWasntAlreadyDead() && __state.ValidateIsPlayerDead() && __state.ValidateHasNoCauseOfDeath()) { Plugin.Instance.PluginLogger.LogDebug("Spike Trap killed Player! Setting cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__state.GetPlayer(), AdvancedCauseOfDeath.Other_Spike_Trap); } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "SpikeRoofTrap.OnTriggerStay:Postfix"); } } } [HarmonyPatch(typeof(Landmine), "SpawnExplosion")] internal class LandmineSpawnExplosionPatch { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator, MethodBase method) { List list = new List(instructions); List list2 = BuildInstructionsToInsertKill(method); if (list2 == null) { Plugin.Instance.PluginLogger.LogError("Could not build injected patch (kill) to insert in LandmineSpawnExplosionPatch!"); return instructions; } List list3 = BuildInstructionsToInsertDamage(method); if (list3 == null) { Plugin.Instance.PluginLogger.LogError("Could not build injected patch (damage) to insert in LandmineSpawnExplosionPatch!"); return instructions; } int num = CauseOfDeathPatch.LocateKillPlayerCall(list); if (num == -1) { Plugin.Instance.PluginLogger.LogError("Could not locate KillPlayer() call in LandmineSpawnExplosionPatch!"); return instructions; } Plugin.Instance.PluginLogger.LogDebug("Injecting patch #1 into Landmine.SpawnExplosion..."); list.InsertRange(num + 1, list2); Plugin.Instance.PluginLogger.LogDebug(" Success."); int num2 = CauseOfDeathPatch.LocateDamagePlayerCall(list); if (num2 == -1) { Plugin.Instance.PluginLogger.LogError("Could not locate DamagePlayer() call in LandmineSpawnExplosionPatch!"); return instructions; } Plugin.Instance.PluginLogger.LogDebug("Injecting patch #2 into Landmine.SpawnExplosion..."); list.InsertRange(num2 + 1, list3); Plugin.Instance.PluginLogger.LogDebug(" Success."); Plugin.Instance.PluginLogger.LogDebug("Landmine.SpawnExplosion() injected patches successfully."); return list; } private static List? BuildInstructionsToInsertKill(MethodBase method) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown List list = new List(); int num = 2; int num2 = 5; IList localVariables = method.GetMethodBody().LocalVariables; LocalVariableInfo localVariableInfo = null; for (int i = 0; i < localVariables.Count; i++) { LocalVariableInfo localVariableInfo2 = localVariables[i]; if (localVariableInfo2.LocalType == typeof(PlayerControllerB)) { if (localVariableInfo != null) { Plugin.Instance.PluginLogger.LogError("Found multiple PlayerControllerB local variables in LandmineSpawnExplosionPatch!"); return null; } localVariableInfo = localVariableInfo2; break; } } if (localVariableInfo == null) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB local variable in LandmineSpawnExplosionPatch!"); return null; } list.Add(new CodeInstruction(OpCodes.Ldloc_S, (object)localVariableInfo.LocalIndex)); list.Add(new CodeInstruction(OpCodes.Ldarg, (object)num)); list.Add(new CodeInstruction(OpCodes.Ldarg, (object)num2)); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(LandmineSpawnExplosionPatch).GetMethod("RewriteCauseOfDeath"))); return list; } private static List? BuildInstructionsToInsertDamage(MethodBase method) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown List list = new List(); int num = 2; int num2 = 5; IList localVariables = method.GetMethodBody().LocalVariables; LocalVariableInfo localVariableInfo = null; for (int i = 0; i < localVariables.Count; i++) { LocalVariableInfo localVariableInfo2 = localVariables[i]; if (localVariableInfo2.LocalType == typeof(PlayerControllerB)) { if (localVariableInfo != null) { Plugin.Instance.PluginLogger.LogError("Found multiple PlayerControllerB local variables in LandmineSpawnExplosionPatch!"); return null; } localVariableInfo = localVariableInfo2; break; } } if (localVariableInfo == null) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB local variable in LandmineSpawnExplosionPatch!"); return null; } list.Add(new CodeInstruction(OpCodes.Ldloc_S, (object)localVariableInfo.LocalIndex)); list.Add(new CodeInstruction(OpCodes.Ldarg, (object)num)); list.Add(new CodeInstruction(OpCodes.Ldarg, (object)num2)); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(LandmineSpawnExplosionPatch).GetMethod("MaybeRewriteCauseOfDeath"))); return list; } public static void MaybeRewriteCauseOfDeath(PlayerControllerB targetPlayer, float killRange, float physicsForce) { if (targetPlayer.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player died from landmine damage"); RewriteCauseOfDeath(targetPlayer, killRange, physicsForce); } else { Plugin.Instance.PluginLogger.LogDebug($"Player did not die from landmine (left at ${targetPlayer.health} health)"); } } public static void RewriteCauseOfDeath(PlayerControllerB targetPlayer, float killRange, float physicsForce) { AdvancedCauseOfDeath advancedCauseOfDeath = AdvancedCauseOfDeath.Blast; if (killRange == 0f && physicsForce == 80f) { advancedCauseOfDeath = AdvancedCauseOfDeath.Enemy_Butler_Explode; } else if (killRange == 5f && physicsForce == 0f) { advancedCauseOfDeath = AdvancedCauseOfDeath.Player_Jetpack_Blast; } else if (physicsForce == 50f) { advancedCauseOfDeath = AdvancedCauseOfDeath.Other_Meteor; } else if (killRange == 1f && physicsForce == 65f) { advancedCauseOfDeath = AdvancedCauseOfDeath.Enemy_Old_Bird_Rocket; } else if (killRange == 1f && physicsForce == 35f) { advancedCauseOfDeath = AdvancedCauseOfDeath.Enemy_Old_Bird_Rocket; } else if (killRange == 2f && physicsForce == 45f) { advancedCauseOfDeath = AdvancedCauseOfDeath.Enemy_Old_Bird_Charge; } else if (killRange == 5.7f && physicsForce == 0f) { advancedCauseOfDeath = AdvancedCauseOfDeath.Other_Landmine; } else if (killRange == 2.4f && physicsForce == 0f) { advancedCauseOfDeath = AdvancedCauseOfDeath.Other_Lightning; } else if (killRange == 0.5f && physicsForce == 45f) { advancedCauseOfDeath = AdvancedCauseOfDeath.Player_EasterEgg; } else if (killRange == 6f && physicsForce == 200f) { advancedCauseOfDeath = AdvancedCauseOfDeath.Player_Cruiser_Explode_Bystander; } else { Plugin.Instance.PluginLogger.LogWarning($"Could not identify explosion (killRange: {killRange}, physicsForce: {physicsForce})! Using generic cause of death for Blasts..."); } Plugin.Instance.PluginLogger.LogDebug($"Player died from Explosion({advancedCauseOfDeath})! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(targetPlayer, advancedCauseOfDeath); } } [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] internal class PlayerControllerBKillPlayerPatch { public static void Prefix(PlayerControllerB __instance, ref CauseOfDeath causeOfDeath) { try { if (!AdvancedDeathTracker.HasCauseOfDeath(__instance)) { if ((int)causeOfDeath == 5 && __instance.isSinking) { Plugin.Instance.PluginLogger.LogDebug("Player died of suffociation while sinking in quicksand! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__instance, AdvancedCauseOfDeath.Player_Quicksand); } else { Plugin.Instance.PluginLogger.LogDebug($"Player is dying! Unknown precise cause of death in final hook ({causeOfDeath})..."); } } } catch (Exception e) { CauseOfDeathPatch.LogException(e, "PlayerControllerB.KillPlayer:Prefix"); } } } [HarmonyPatch(typeof(Turret), "Update")] internal class TurretUpdatePatch { private const string KILL_PLAYER_SIGNATURE = "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)"; private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator, MethodBase method) { List list = new List(instructions); List list2 = BuildInstructionsToInsert(method); if (list2 == null) { Plugin.Instance.PluginLogger.LogError("Could not build instructions to insert in TurretUpdatePatch! Safely aborting..."); return instructions; } int num = CauseOfDeathPatch.LocateKillPlayerCall(list); if (num == -1) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB.KillPlayer call in TurretUpdatePatch! Safely aborting..."); return instructions; } Plugin.Instance.PluginLogger.LogDebug("Injecting patch into Turret.Update..."); list.InsertRange(num + 1, list2); Plugin.Instance.PluginLogger.LogDebug("Done."); return list; } private static List? BuildInstructionsToInsert(MethodBase method) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown List list = new List(); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(TurretUpdatePatch).GetMethod("RewriteCauseOfDeath"))); return list; } public static void RewriteCauseOfDeath() { Plugin.Instance.PluginLogger.LogDebug("Player died to Turret! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Other_Turret); } } [HarmonyPatch(typeof(ItemDropship), "Start")] internal class ItemDropshipStartPatch { public static void Postfix(ItemDropship __instance) { try { Plugin.Instance.PluginLogger.LogDebug("Item dropship spawned! Modifying kill trigger..."); GameObject gameObject = ((Component)__instance).gameObject; Transform target = gameObject.transform.Find("ItemShip/KillTrigger"); CauseOfDeathPatch.OverrideKillLocalPlayer(target, AdvancedCauseOfDeath.Other_Dropship); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ItemDropship.Start:Postfix"); } } } [HarmonyPatch(typeof(ExtensionLadderItem), "StartLadderAnimation")] internal class ExtensionLadderItemStartLadderAnimationPatch { public static void Postfix(ExtensionLadderItem __instance) { try { Plugin.Instance.PluginLogger.LogDebug("Extension ladder started animation! Modifying kill trigger..."); GameObject gameObject = ((Component)__instance).gameObject; Transform target = gameObject.transform.Find("AnimContainer/MeshContainer/LadderMeshContainer/BaseLadder/LadderSecondPart/KillTrigger"); CauseOfDeathPatch.OverrideKillLocalPlayer(target, AdvancedCauseOfDeath.Player_Ladder); } catch (Exception e) { CauseOfDeathPatch.LogException(e, "ExtensionLadderItem.StartLadderAnimation:Postfix"); } } } [HarmonyPatch(typeof(KillLocalPlayer), "KillPlayer")] internal class KillLocalPlayerKillPlayerPatch { public static void Postfix(KillLocalPlayer __instance, PlayerControllerB playerWhoTriggered) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) try { if (__instance.causeOfDeath == AdvancedCauseOfDeath.Gravity) { Plugin.Instance.PluginLogger.LogDebug("Player died to KillPlayerTrigger(Gravity)! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(playerWhoTriggered, DistinguishGravityKillTrigger(__instance)); } else if (__instance.causeOfDeath == AdvancedCauseOfDeath.Fan) { Plugin.Instance.PluginLogger.LogDebug("Player died to KillPlayerTrigger(Fan)! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(playerWhoTriggered, AdvancedCauseOfDeath.Fan); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in KillLocalPlayerStartPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } public static AdvancedCauseOfDeath DistinguishGravityKillTrigger(KillLocalPlayer __instance) { GameObject gameObject = ((Component)__instance).gameObject; Transform parent = ((Component)__instance).gameObject.transform.parent; if ((Object)(object)gameObject == (Object)null || (Object)(object)parent == (Object)null) { Plugin.Instance.PluginLogger.LogError("Could not fetch GameObject or parent from KillLocalPlayer."); return AdvancedCauseOfDeath.Pit_Generic; } string text = ((Object)parent).name.Replace("(Clone)", ""); switch (text) { case "4x4BigStairTile": return AdvancedCauseOfDeath.Pit_Facility_Pit; case "CatwalkTile2x1": return AdvancedCauseOfDeath.Pit_Facility_Pit; case "CatwalkTile2x1Split": return AdvancedCauseOfDeath.Pit_Facility_Catwalk_Jump; case "LargeForkTileB": return AdvancedCauseOfDeath.Pit_Facility_Pit; case "SmallStairTile": return AdvancedCauseOfDeath.Pit_Facility_Pit; case "CaveForkStairTile": return AdvancedCauseOfDeath.Pit_Mine_Cave; case "CaveLongRampTile": return AdvancedCauseOfDeath.Pit_Mine_Cave; case "DeepShaftTile": return AdvancedCauseOfDeath.Pit_Mine_Pit; case "MineshaftStartTile": return AdvancedCauseOfDeath.Pit_Mine_Elevator; default: Plugin.Instance.PluginLogger.LogError("Could not identify KillTrigger parent by name (got " + text + ")."); return AdvancedCauseOfDeath.Pit_Generic; } } } [HarmonyPatch(typeof(FlowerSnakeEnemy), "StopClingingOnLocalClient")] internal class FlowerSnakeEnemyStopClingingOnLocalClientPatch { public static void Prefix(FlowerSnakeEnemy __instance) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance.clingingToPlayer != (Object)null)) { return; } Plugin.Instance.PluginLogger.LogDebug("Tulip Snake let go of player..."); if (__instance.clingingToPlayer.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Tulip Snake let go of player because they died..."); if (__instance.clingingToPlayer.causeOfDeath == AdvancedCauseOfDeath.Gravity) { Plugin.Instance.PluginLogger.LogDebug("Tulip Snake let go of player because they died of gravity! Will assume they were involved..."); AdvancedDeathTracker.SetCauseOfDeath(__instance.clingingToPlayer, AdvancedCauseOfDeath.Enemy_TulipSnake_Drop); } } } } [HarmonyPatch(typeof(HUDManager))] [HarmonyPatch("FillEndGameStats")] internal class HUDManagerFillEndGameStatsPatch { private const string EMPTY_NOTES = "Notes: \n"; public static void Postfix(HUDManager __instance) { try { OverridePerformanceReport(__instance); } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in HUDManagerFillEndGameStatsPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } private static Random BuildSyncedRandom() { int randomMapSeed = StartOfRound.Instance.randomMapSeed; Plugin.Instance.PluginLogger.LogDebug("Syncing randomization to map seed: '" + randomMapSeed + "'"); return new Random(randomMapSeed); } private static void OverridePerformanceReport(HUDManager __instance) { Plugin.Instance.PluginLogger.LogDebug("Applying Coroner patches to player notes..."); Random random = BuildSyncedRandom(); for (int i = 0; i < __instance.statsUIElements.playerNotesText.Length; i++) { PlayerControllerB val = __instance.playersManager.allPlayerScripts[i]; if (!val.disconnectedMidGame && !val.isPlayerDead && !val.isPlayerControlled) { Plugin.Instance.PluginLogger.LogInfo("Player " + i + " is not controlled by a player. Skipping..."); continue; } TextMeshProUGUI val2 = __instance.statsUIElements.playerNotesText[i]; if (val.isPlayerDead) { if (Plugin.Instance.PluginConfig.ShouldDisplayCauseOfDeath()) { if (Plugin.Instance.PluginConfig.ShouldDeathReplaceNotes()) { Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " is dead! Replacing notes with Cause of Death..."); ((TMP_Text)val2).text = Plugin.Instance.LanguageHandler.GetFirstValueByTag("UICauseOfDeath") + "\n"; } else { Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " is dead! Appending notes with Cause of Death..."); } AdvancedCauseOfDeath? causeOfDeath = AdvancedDeathTracker.GetCauseOfDeath(val); ((TMP_Text)val2).text = ((TMP_Text)val2).text + "* " + AdvancedDeathTracker.StringifyCauseOfDeath(causeOfDeath, random) + "\n"; } else { Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " is dead, but Config says leave it be..."); } } else if (((TMP_Text)val2).text == "Notes: \n") { if (Plugin.Instance.PluginConfig.ShouldDisplayFunnyNotes()) { Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " has no notes! Injecting something funny..."); ((TMP_Text)val2).text = Plugin.Instance.LanguageHandler.GetFirstValueByTag("UINotes") + "\n"; ((TMP_Text)val2).text = ((TMP_Text)val2).text + "* " + AdvancedDeathTracker.StringifyCauseOfDeath(null, random) + "\n"; } else { Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " has no notes, but Config says leave it be..."); } } else { Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " has notes, don't override them..."); } } AdvancedDeathTracker.ClearDeathTracker(); } } [HarmonyPatch(typeof(StartOfRound))] [HarmonyPatch("StartGame")] internal class StartOfRoundStartGamePatch { public static void Postfix() { Plugin.Instance.PluginLogger.LogDebug("New round started! Resetting causes of death..."); AdvancedDeathTracker.ClearDeathTracker(); } } }