Decompiled source of Coroner v2.2.0
Coroner.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; 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.2.0.0")] [assembly: AssemblyInformationalVersion("2.2.0+15b48f9fe2f9dd06a65afc16f50ee79252cbf332")] [assembly: AssemblyProduct("Coroner")] [assembly: AssemblyTitle("Coroner")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.2.0.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<int, AdvancedCauseOfDeath?> causeOfDeathDictionary = new Dictionary<int, AdvancedCauseOfDeath?>(); 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); } 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) { PlayerControllerB playerController = StartOfRound.Instance.allPlayerScripts[playerIndex]; return GetCauseOfDeath(playerController, shouldGuess); } public static bool HasCauseOfDeath(int playerIndex) { 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<GrabbableObject>(); } 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<string, AdvancedCauseOfDeath> Registry = new Dictionary<string, AdvancedCauseOfDeath>(); 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 Snipped = 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 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_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) { AdvancedDeathTracker.SetCauseOfDeath(player, causeOfDeath); } public static void SetCauseOfDeath(int playerId, AdvancedCauseOfDeath? causeOfDeath) { AdvancedDeathTracker.SetCauseOfDeath(playerId, causeOfDeath); } 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 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_SNIPPED = "DeathSnipped"; 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_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_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<string, List<string>> 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<string, List<string>>(); 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<string>(); } List<string> 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<string, List<string>>>((KeyValuePair<string, List<string>> 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<string> 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] 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.2.0"; public const string PLUGIN_GUID = "com.elitemastereric.coroner"; } [BepInPlugin("com.elitemastereric.coroner", "Coroner", "2.2.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<bool>? DisplayCauseOfDeath = null; private ConfigEntry<bool>? SeriousDeathMessages = null; private ConfigEntry<bool>? DisplayFunnyNotes = null; private ConfigEntry<bool>? DeathReplacesNotes = null; private ConfigEntry<string>? LanguagePicker = null; public void BindConfig(ConfigFile _config) { DisplayCauseOfDeath = _config.Bind<bool>("General", "DisplayCauseOfDeath", true, "Display the cause of death in the player notes."); SeriousDeathMessages = _config.Bind<bool>("General", "SeriousDeathMessages", false, "Cause of death messages are more to-the-point."); DisplayFunnyNotes = _config.Bind<bool>("General", "DisplayFunnyNotes", true, "Display a random note when the player has no notes."); DeathReplacesNotes = _config.Bind<bool>("General", "DeathReplacesNotes", true, "True to replace notes when the player dies, false to append."); LanguagePicker = _config.Bind<string>("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 { [HarmonyPatch(typeof(BaboonBirdAI))] [HarmonyPatch("OnCollideWithPlayer")] internal class BaboonBirdAIOnCollideWithPlayerPatch { public static void Postfix(Collider other) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Baboon Hawk damage..."); PlayerControllerB component = ((Component)other).gameObject.GetComponent<PlayerControllerB>(); if ((Object)(object)component == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); } else if (component.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player is now dead! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_BaboonHawk); } else { Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in BaboonBirdAIOnCollideWithPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(FlowermanAI))] [HarmonyPatch("killAnimation")] internal class FlowermanAIKillAnimationPatch { public static void Postfix(FlowermanAI __instance) { try { Plugin.Instance.PluginLogger.LogDebug("Accessing state after Bracken snapping neck..."); if ((Object)(object)((EnemyAI)__instance).inSpecialAnimationWithPlayer == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after snapping neck!"); return; } Plugin.Instance.PluginLogger.LogDebug("Player killed by Bracken! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(((EnemyAI)__instance).inSpecialAnimationWithPlayer, AdvancedCauseOfDeath.Enemy_Bracken); } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in FlowermanAIKillAnimationPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(SandSpiderAI))] [HarmonyPatch("OnCollideWithPlayer")] internal class SandSpiderAIOnCollideWithPlayerPatch { public static void Postfix(Collider other) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Bunker Spider damage..."); PlayerControllerB component = ((Component)other).gameObject.GetComponent<PlayerControllerB>(); if ((Object)(object)component == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); } else if (component.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player killed by Bunker Spider! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_BunkerSpider); } else { Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive after hit by Forest Spider! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in SandSpiderAIOnCollideWithPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(RedLocustBees))] [HarmonyPatch("BeeKillPlayerOnLocalClient")] internal class RedLocustBeesBeeKillPlayerOnLocalClientPatch { public static void Postfix(int playerId) { try { Plugin.Instance.PluginLogger.LogDebug("Accessing state after Circuit Bee electrocution..."); PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerId]; if ((Object)(object)val == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); } else if (val.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player killed by Circuit Bees! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(val, AdvancedCauseOfDeath.Enemy_CircuitBees); } else { Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in RedLocustBeesBeeKillPlayerOnLocalClientPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(SpringManAI))] [HarmonyPatch("OnCollideWithPlayer")] internal class SpringManAIOnCollideWithPlayerPatch { public static void Postfix(Collider other) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Coil Head damage..."); PlayerControllerB component = ((Component)other).gameObject.GetComponent<PlayerControllerB>(); if ((Object)(object)component == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); } else if (component.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player killed by Coil Head! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_CoilHead); } else { Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive after hit by Coil Head! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in SpringManAIOnCollideWithPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(SandWormAI))] [HarmonyPatch("EatPlayer")] internal class SandWormAIEatPlayerPatch { public static void Postfix(PlayerControllerB playerScript) { try { Plugin.Instance.PluginLogger.LogDebug("Accessing state after Sand Worm devouring..."); if ((Object)(object)playerScript == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); return; } Plugin.Instance.PluginLogger.LogDebug("Player was eaten by Earth Leviathan! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(playerScript, AdvancedCauseOfDeath.Enemy_EarthLeviathan); } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in SandWormAIEatPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(MouthDogAI))] [HarmonyPatch("KillPlayer")] internal class MouthDogAIKillPlayerPatch { public static void Postfix(int playerId) { try { Plugin.Instance.PluginLogger.LogDebug("Accessing state after dog devouring..."); PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerId]; if ((Object)(object)val == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); return; } Plugin.Instance.PluginLogger.LogDebug("Player was killed by Eyeless Dog! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(val, AdvancedCauseOfDeath.Enemy_EyelessDog); } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in MouthDogAIKillPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(ForestGiantAI))] [HarmonyPatch("EatPlayerAnimation")] internal class ForestGiantAIEatPlayerAnimationPatch { public static void Postfix(PlayerControllerB playerBeingEaten) { try { Plugin.Instance.PluginLogger.LogDebug("Accessing state after Forest Giant devouring..."); if ((Object)(object)playerBeingEaten == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); return; } Plugin.Instance.PluginLogger.LogDebug("Player was eaten by Forest Giant! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(playerBeingEaten, AdvancedCauseOfDeath.Enemy_ForestGiant_Eaten); } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in ForestGiantAIEatPlayerAnimationPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(ForestGiantAI))] [HarmonyPatch("AnimationEventA")] internal class ForestGiantAIAnimationEventAPatch { private const string KILL_PLAYER_SIGNATURE = "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)"; private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase method) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); List<CodeInstruction> list2 = BuildInstructionsToInsert(method); if (list2 == null) { Plugin.Instance.PluginLogger.LogError("Could not build instructions to insert in ForestGiantAIAnimationEventAPatch! Safely aborting..."); return instructions; } int num = -1; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Callvirt && val.operand.ToString() == "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)") { num = i; break; } } if (num == -1) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB.KillPlayer call in ForestGiantAIAnimationEventAPatch! Safely aborting..."); return instructions; } Plugin.Instance.PluginLogger.LogDebug("Injecting patch into ForestGiantAI.AnimationEventA..."); list.InsertRange(num + 1, list2); Plugin.Instance.PluginLogger.LogDebug("Done."); return list; } private static List<CodeInstruction>? BuildInstructionsToInsert(MethodBase method) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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 List<CodeInstruction> list = new List<CodeInstruction>(); IList<LocalVariableInfo> 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 ForestGiantAIAnimationEventAPatch!"); return null; } localVariableInfo = localVariableInfo2; break; } } if (localVariableInfo == null) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB local variable in ForestGiantAIAnimationEventAPatch!"); return null; } list.Add(new CodeInstruction(OpCodes.Ldloc_S, (object)localVariableInfo.LocalIndex)); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(ForestGiantAIAnimationEventAPatch).GetMethod("RewriteCauseOfDeath"))); return list; } public static void RewriteCauseOfDeath(PlayerControllerB targetPlayer) { Plugin.Instance.PluginLogger.LogDebug("Player was crushed by dying Forest Giant! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(targetPlayer, AdvancedCauseOfDeath.Enemy_ForestGiant_Death, forceOverride: true); } } [HarmonyPatch(typeof(DressGirlAI))] [HarmonyPatch("OnCollideWithPlayer")] internal class DressGirlAIOnCollideWithPlayerPatch { public static void Postfix(DressGirlAI __instance) { try { Plugin.Instance.PluginLogger.LogDebug("Processing Ghost Girl player collision..."); if ((Object)(object)__instance.hauntingPlayer == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after collision!"); } else if (__instance.hauntingPlayer.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player was killed by Ghost Girl! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__instance.hauntingPlayer, AdvancedCauseOfDeath.Enemy_GhostGirl); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in DressGirlAIOnCollideWithPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(HoarderBugAI))] [HarmonyPatch("OnCollideWithPlayer")] internal class HoarderBugAIOnCollideWithPlayerPatch { public static void Postfix(Collider other) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Hoarder Bug damage..."); PlayerControllerB component = ((Component)other).gameObject.GetComponent<PlayerControllerB>(); if ((Object)(object)component == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); } else if (component.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player was killed by Hoarder Bug! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_HoarderBug); } else { Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive after hit by Hoarder Bug! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in HoarderBugAIOnCollideWithPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(BlobAI))] [HarmonyPatch("OnCollideWithPlayer")] internal class BlobAIOnCollideWithPlayerPatch { public static void Postfix(Collider other) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Hygrodere damage..."); PlayerControllerB component = ((Component)other).gameObject.GetComponent<PlayerControllerB>(); if ((Object)(object)component == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); } else if (component.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player was killed by Hygrodere! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_Hygrodere); } else { Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive after hit by Hygrodere! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in BlobAIOnCollideWithPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(JesterAI))] [HarmonyPatch("killPlayerAnimation")] internal class JesterAIKillPlayerAnimationPatch { public static void Postfix(int playerId) { try { Plugin.Instance.PluginLogger.LogDebug("Accessing state after Jester mauling..."); PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerId]; if ((Object)(object)val == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); return; } Plugin.Instance.PluginLogger.LogDebug("Player was killed by Jester! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(val, AdvancedCauseOfDeath.Enemy_Jester); } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in JesterAIKillPlayerAnimationPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(CaveDwellerAI))] [HarmonyPatch("killAnimation")] internal class CaveDwellerAIKillAnimationPatch { public static void Postfix(CaveDwellerAI __instance, PlayerControllerB killingPlayer) { try { Plugin.Instance.PluginLogger.LogDebug("Accessing state after Maneater mauling..."); if ((Object)(object)killingPlayer == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); return; } Plugin.Instance.PluginLogger.LogDebug("Player was killed by Maneater! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(killingPlayer, AdvancedCauseOfDeath.Enemy_Maneater); } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in CaveDwellerAIKillAnimationPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(CentipedeAI))] [HarmonyPatch("DamagePlayerOnIntervals")] internal class CentipedeAIDamagePlayerOnIntervalsPatch { public static void Postfix(CentipedeAI __instance) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 try { Plugin.Instance.PluginLogger.LogDebug("Handling Snare Flea damage..."); if ((Object)(object)__instance.clingingToPlayer == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player being clung to!"); } else if (__instance.clingingToPlayer.isPlayerDead && (int)__instance.clingingToPlayer.causeOfDeath == 5) { Plugin.Instance.PluginLogger.LogDebug("Player was killed by Snare Flea! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__instance.clingingToPlayer, AdvancedCauseOfDeath.Enemy_SnareFlea); } else if (__instance.clingingToPlayer.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player somehow died while attacked by Snare Flea! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in CentipedeAIDamagePlayerOnIntervalsPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(PufferAI))] [HarmonyPatch("OnCollideWithPlayer")] internal class PufferAIOnCollideWithPlayerPatch { public static void Postfix(Collider other) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Spore Lizard damage..."); PlayerControllerB component = ((Component)other).gameObject.GetComponent<PlayerControllerB>(); if ((Object)(object)component == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); } else if (component.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player was killed by Spore Lizard! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_SporeLizard); } else { Plugin.Instance.PluginLogger.LogDebug("Player is alive after being hit by Spore Lizard! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in PufferAIOnCollideWithPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(CrawlerAI))] [HarmonyPatch("OnCollideWithPlayer")] internal class CrawlerAIOnCollideWithPlayerPatch { public static void Postfix(Collider other) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Thumper damage..."); PlayerControllerB component = ((Component)other).gameObject.GetComponent<PlayerControllerB>(); if ((Object)(object)component == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); } else if (component.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player was killed by Thumper! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_Thumper); } else { Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive after being hit by Thumper! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in CrawlerAIOnCollideWithPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(HauntedMaskItem))] [HarmonyPatch("FinishAttaching")] internal class HauntedMaskItemFinishAttachingPatch { public static void Postfix(HauntedMaskItem __instance) { try { Plugin.Instance.PluginLogger.LogDebug("Mask attached to someone..."); PlayerControllerB value = Traverse.Create((object)__instance).Field("previousPlayerHeldBy").GetValue<PlayerControllerB>(); if ((Object)(object)value == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); } else if (value.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player was killed by putting on a Mask! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(value, AdvancedCauseOfDeath.Enemy_MaskedPlayer_Wear); } else { Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive after putting on a Mask! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in HauntedMaskItemFinishAttachingPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(MaskedPlayerEnemy))] [HarmonyPatch("killAnimation")] internal class MaskedPlayerEnemykillAnimationPatch { public static void Postfix(MaskedPlayerEnemy __instance) { try { Plugin.Instance.PluginLogger.LogDebug("Masked Player killed someone..."); PlayerControllerB inSpecialAnimationWithPlayer = ((EnemyAI)__instance).inSpecialAnimationWithPlayer; if ((Object)(object)inSpecialAnimationWithPlayer == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); return; } Plugin.Instance.PluginLogger.LogDebug("Player was killed by Masked Player! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(inSpecialAnimationWithPlayer, AdvancedCauseOfDeath.Enemy_MaskedPlayer_Victim); } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in MaskedPlayerEnemykillAnimationPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(NutcrackerEnemyAI))] [HarmonyPatch("LegKickPlayer")] internal class NutcrackerEnemyAILegKickPlayerPatch { public static void Postfix(int playerId) { try { Plugin.Instance.PluginLogger.LogDebug("Nutcracker kicked a player to death!"); PlayerControllerB playerController = StartOfRound.Instance.allPlayerScripts[playerId]; Plugin.Instance.PluginLogger.LogDebug("Player was kicked by Nutcracker! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(playerController, AdvancedCauseOfDeath.Enemy_Nutcracker_Kicked); } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in NutcrackerEnemyAILegKickPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(ShotgunItem))] [HarmonyPatch("ShootGun")] internal class ShotgunItemShootGunPatch { public static void Postfix(ShotgunItem __instance) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Invalid comparison between Unknown and I4 try { Plugin.Instance.PluginLogger.LogDebug("Handling shotgun shot..."); PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access local player after shotgun shot!"); } else if (localPlayerController.isPlayerDead && (int)localPlayerController.causeOfDeath == 7) { if (((GrabbableObject)__instance).isHeldByEnemy) { Plugin.Instance.PluginLogger.LogDebug("Player was killed by Shotgun (Nutcracker)! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(localPlayerController, AdvancedCauseOfDeath.Enemy_Nutcracker_Shot); } else { Plugin.Instance.PluginLogger.LogDebug("Player was killed by Shotgun (Player)! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(localPlayerController, AdvancedCauseOfDeath.Player_Murder_Shotgun); } } else if (localPlayerController.isPlayerDead) { Plugin.Instance.PluginLogger.LogWarning("Player died while attacked by shotgun? Skipping... " + ((object)(CauseOfDeath)(ref localPlayerController.causeOfDeath)).ToString()); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in ShotgunItemShootGunPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(ButlerEnemyAI))] [HarmonyPatch("OnCollideWithPlayer")] internal class ButlerEnemyAIOnCollideWithPlayerPatch { public static void Postfix(Collider other) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Butler stab damage..."); PlayerControllerB component = ((Component)other).gameObject.GetComponent<PlayerControllerB>(); if ((Object)(object)component == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); } else if (component.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player was killed by Butler (Stabbing)! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_Butler_Stab); } else { Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in ButlerEnemyAIOnCollideWithPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(ButlerBeesEnemyAI))] [HarmonyPatch("OnCollideWithPlayer")] internal class ButlerBeesEnemyAIOnCollideWithPlayerPatch { public static void Postfix(Collider other) { try { Plugin.Instance.PluginLogger.LogDebug("Handling Mask Hornet stab damage..."); PlayerControllerB component = ((Component)other).gameObject.GetComponent<PlayerControllerB>(); if ((Object)(object)component == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not access player after death!"); } else if (component.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player was killed by Mask Hornets! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_MaskHornets); } else { Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in ButlerBeesEnemyAIOnCollideWithPlayerPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(FlowerSnakeEnemy))] [HarmonyPatch("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! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__instance.clingingToPlayer, AdvancedCauseOfDeath.Enemy_TulipSnake_Drop); } } } } [HarmonyPatch(typeof(RadMechAI))] [HarmonyPatch("CancelTorchPlayerAnimation")] internal class RadMechAICancelTorchPlayerAnimationPatch { public static void Prefix(RadMechAI __instance) { if ((Object)(object)((EnemyAI)__instance).inSpecialAnimationWithPlayer != (Object)null) { Plugin.Instance.PluginLogger.LogDebug("Player was torched to death by Old Bird, setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(((EnemyAI)__instance).inSpecialAnimationWithPlayer, AdvancedCauseOfDeath.Enemy_Old_Bird_Torch); } } } [HarmonyPatch(typeof(RadMechAI))] [HarmonyPatch("Stomp")] internal class RadMechAIStompPatch { public static void Postfix(RadMechAI __instance) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if (localPlayerController.isPlayerDead && !AdvancedDeathTracker.HasCauseOfDeath(localPlayerController) && localPlayerController.causeOfDeath == AdvancedCauseOfDeath.Crushing) { Plugin.Instance.PluginLogger.LogDebug("Player was crushed to death by Old Bird, setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(localPlayerController, AdvancedCauseOfDeath.Enemy_Old_Bird_Stomp); } } } [HarmonyPatch(typeof(BushWolfEnemy))] [HarmonyPatch("OnCollideWithPlayer")] internal class BushWolfOnCollideWithPlayerPatch { private const string KILL_PLAYER_SIGNATURE = "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)"; private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase method) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); List<CodeInstruction> list2 = BuildInstructionsToInsert(method); if (list2 == null) { Plugin.Instance.PluginLogger.LogError("Could not build instructions to insert in BushWolfOnCollideWithPlayerPatch! Safely aborting..."); return instructions; } int num = -1; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Callvirt && val.operand.ToString() == "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)") { num = i; break; } } if (num == -1) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB.KillPlayer call in BushWolfOnCollideWithPlayerPatch! Safely aborting..."); return instructions; } Plugin.Instance.PluginLogger.LogDebug("Injecting patch into BushWolf.OnCollideWithPlayer..."); list.InsertRange(num + 1, list2); Plugin.Instance.PluginLogger.LogDebug("Done."); return list; } private static List<CodeInstruction>? 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<CodeInstruction> list = new List<CodeInstruction>(); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(BushWolfOnCollideWithPlayerPatch).GetMethod("RewriteCauseOfDeath"))); return list; } public static void RewriteCauseOfDeath() { Plugin.Instance.PluginLogger.LogDebug("Player died to Kidnapper Wolf! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Enemy_KidnapperFox); } } [HarmonyPatch(typeof(PlayerControllerB))] [HarmonyPatch("KillPlayer")] internal class PlayerControllerBKillPlayerPatch { public static void Prefix(PlayerControllerB __instance, ref CauseOfDeath causeOfDeath) { try { if (AdvancedDeathTracker.HasCauseOfDeath(__instance)) { Plugin.Instance.PluginLogger.LogDebug("Player already has a known specific cause of death! Skipping advanced processing..."); } else if (causeOfDeath == AdvancedCauseOfDeath.Other_Dropship) { Plugin.Instance.PluginLogger.LogDebug("Player died from item dropship! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__instance, AdvancedCauseOfDeath.Other_Dropship); causeOfDeath = (CauseOfDeath)8; } else if (causeOfDeath == AdvancedCauseOfDeath.Player_Ladder) { Plugin.Instance.PluginLogger.LogDebug("Player died from ladder! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__instance, AdvancedCauseOfDeath.Player_Ladder); causeOfDeath = (CauseOfDeath)8; } else if (__instance.isSinking && (int)causeOfDeath == 5) { Plugin.Instance.PluginLogger.LogDebug("Player died of suffociation while sinking in quicksand! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__instance, AdvancedCauseOfDeath.Player_Quicksand); } else if ((int)causeOfDeath == 3) { GrabbableObject currentlyHeldObjectServer = __instance.currentlyHeldObjectServer; if (!((Object)(object)currentlyHeldObjectServer != (Object)null)) { return; } GameObject gameObject = ((Component)currentlyHeldObjectServer).gameObject; if ((Object)(object)gameObject != (Object)null) { GrabbableObject component = gameObject.GetComponent<GrabbableObject>(); if ((Object)(object)component != (Object)null && component is StunGrenadeItem) { Plugin.Instance.PluginLogger.LogDebug("Player died from stun grenade explosion! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__instance, AdvancedCauseOfDeath.Player_StunGrenade); } } } else if ((int)causeOfDeath == 17) { Plugin.Instance.PluginLogger.LogDebug("Player died to Snipped! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(__instance, AdvancedCauseOfDeath.Enemy_Barber); } else { Plugin.Instance.PluginLogger.LogDebug("Player is dying! No cause of death registered in hook..."); } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in PlayerControllerBKillPlayerPatch.Prefix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(PlayerControllerB))] [HarmonyPatch("DamagePlayerFromOtherClientClientRpc")] internal class PlayerControllerBDamagePlayerFromOtherClientClientRpcPatch { private const string DAMAGE_PLAYER_SIGNATURE = "Void DamagePlayer(Int32, Boolean, Boolean, CauseOfDeath, Int32, Boolean, UnityEngine.Vector3)"; private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase method) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); List<CodeInstruction> 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<CodeInstruction>? 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<CodeInstruction> list = new List<CodeInstruction>(); 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(ExtensionLadderItem))] [HarmonyPatch("StartLadderAnimation")] internal class ExtensionLadderItemStartLadderAnimationPatch { public static void Postfix(ExtensionLadderItem __instance) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) try { Plugin.Instance.PluginLogger.LogDebug("Extension ladder started animation! Modifying kill trigger..."); GameObject gameObject = ((Component)__instance).gameObject; if ((Object)(object)gameObject == (Object)null) { Plugin.Instance.PluginLogger.LogError("Could not fetch GameObject from ExtensionLadderItem."); return; } Transform val = gameObject.transform.Find("AnimContainer/MeshContainer/LadderMeshContainer/BaseLadder/LadderSecondPart/KillTrigger"); if ((Object)(object)val == (Object)null) { Plugin.Instance.PluginLogger.LogError("Could not fetch KillTrigger Transform from ExtensionLadderItem."); return; } GameObject gameObject2 = ((Component)val).gameObject; if ((Object)(object)gameObject2 == (Object)null) { Plugin.Instance.PluginLogger.LogError("Could not fetch KillTrigger GameObject from ExtensionLadderItem."); return; } KillLocalPlayer component = gameObject2.GetComponent<KillLocalPlayer>(); if ((Object)(object)component == (Object)null) { Plugin.Instance.PluginLogger.LogError("Could not fetch KillLocalPlayer from KillTrigger GameObject."); } else { component.causeOfDeath = AdvancedCauseOfDeath.Player_Ladder; } } catch (Exception ex) { Plugin.Instance.PluginLogger.LogError("Error in ExtensionLadderItemStartLadderAnimationPatch.Postfix: " + ex); Plugin.Instance.PluginLogger.LogError(ex.StackTrace); } } } [HarmonyPatch(typeof(VehicleController))] [HarmonyPatch("DestroyCar")] internal class VehicleControllerDestroyCarPatch { private const string KILL_PLAYER_SIGNATURE = "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)"; private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase method) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); List<CodeInstruction> list2 = BuildInstructionsToInsert(method); if (list2 == null) { Plugin.Instance.PluginLogger.LogError("Could not build instructions to insert in VehicleControllerDestroyCarPatch! Safely aborting..."); return instructions; } int num = -1; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Callvirt && val.operand.ToString() == "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)") { num = i; break; } } if (num == -1) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB.KillPlayer call in VehicleControllerDestroyCarPatch! Safely aborting..."); return instructions; } Plugin.Instance.PluginLogger.LogDebug("Injecting patch into VehicleController.DestroyCar..."); list.InsertRange(num, list2); Plugin.Instance.PluginLogger.LogDebug("Done."); return list; } private static List<CodeInstruction>? BuildInstructionsToInsert(MethodBase method) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(); list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(VehicleControllerDestroyCarPatch).GetMethod("RewriteCauseOfDeath"))); return list; } public static void RewriteCauseOfDeath(VehicleController vehicle) { Plugin.Instance.PluginLogger.LogDebug("Player died to Cruiser Explosion! Setting special cause of death..."); if ((Object)(object)vehicle == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not get reference to vehicle..."); AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Player_Cruiser_Explode_Bystander); return; } Plugin.Instance.PluginLogger.LogDebug($"Got vehicle controller. ({vehicle.localPlayerInControl}, {vehicle.localPlayerInPassengerSeat})"); if (vehicle.localPlayerInControl) { AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Player_Cruiser_Driver); return; } if (vehicle.localPlayerInPassengerSeat) { AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Player_Cruiser_Passenger); return; } Plugin.Instance.PluginLogger.LogWarning("Could not get reference to local player in control or passenger seat..."); AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Player_Cruiser_Explode_Bystander); } } [HarmonyPatch(typeof(VehicleController))] [HarmonyPatch("RemovePlayerControlOfVehicleClientRpc")] internal class VehicleControllerRemovePlayerControlOfVehicleClientRpcPatch { private static void Postfix(VehicleController __instance, int playerId, bool setIgnitionStarted) { Plugin.Instance.PluginLogger.LogDebug($"Removed player control of vehicle: {playerId} ({setIgnitionStarted})"); } } [HarmonyPatch(typeof(VehicleController))] [HarmonyPatch("DamagePlayerInVehicle")] internal class VehicleControllerDamagePlayerInVehiclePatch { private const string KILL_PLAYER_SIGNATURE = "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)"; private const string DAMAGE_PLAYER_SIGNATURE = "Void DamagePlayer(Int32, Boolean, Boolean, CauseOfDeath, Int32, Boolean, UnityEngine.Vector3)"; private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase method) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); List<CodeInstruction> list2 = BuildInstructionsToInsertKill(method); if (list2 == null) { Plugin.Instance.PluginLogger.LogError("Could not build instructions (kill) to insert in VehicleControllerDamagePlayerInVehiclePatch! Safely aborting..."); return instructions; } List<CodeInstruction> list3 = BuildInstructionsToInsertDamage(method); if (list3 == null) { Plugin.Instance.PluginLogger.LogError("Could not build instructions (damage) to insert in VehicleControllerDamagePlayerInVehiclePatch! Safely aborting..."); return instructions; } int num = -1; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Callvirt && val.operand.ToString() == "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)") { num = i; } } if (num == -1) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB.KillPlayer call in VehicleControllerDamagePlayerInVehiclePatch! Safely aborting..."); return instructions; } Plugin.Instance.PluginLogger.LogDebug("Injecting kill patches into VehicleController.DamagePlayer..."); list.InsertRange(num + 1, list2); Plugin.Instance.PluginLogger.LogDebug("Done."); int num2 = -1; for (int j = 0; j < list.Count; j++) { CodeInstruction val2 = list[j]; if (val2.opcode == OpCodes.Callvirt && val2.operand.ToString() == "Void DamagePlayer(Int32, Boolean, Boolean, CauseOfDeath, Int32, Boolean, UnityEngine.Vector3)") { num2 = j; } } if (num2 == -1) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB.DamagePlayer call in VehicleControllerDamagePlayerInVehiclePatch! Safely aborting..."); return instructions; } Plugin.Instance.PluginLogger.LogDebug("Injecting damage patches into VehicleController.DamagePlayerInVehicle..."); list.InsertRange(num2 + 1, list3); Plugin.Instance.PluginLogger.LogDebug("Done."); Plugin.Instance.PluginLogger.LogDebug("VehicleController.DamagePlayerInVehicle patch done."); return list; } private static List<CodeInstruction>? BuildInstructionsToInsertKill(MethodBase method) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(); list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(VehicleControllerDamagePlayerInVehiclePatch).GetMethod("RewriteCauseOfDeath"))); return list; } private static List<CodeInstruction>? BuildInstructionsToInsertDamage(MethodBase method) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(); list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(VehicleControllerDamagePlayerInVehiclePatch).GetMethod("MaybeRewriteCauseOfDeath"))); return list; } public static void MaybeRewriteCauseOfDeath(VehicleController vehicle) { PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if (localPlayerController.isPlayerDead) { Plugin.Instance.PluginLogger.LogDebug("Player died from car accident damage"); RewriteCauseOfDeath(vehicle); } else { Plugin.Instance.PluginLogger.LogDebug($"Player did not die from car accident (left at ${localPlayerController.health} health)"); } } public static void RewriteCauseOfDeath(VehicleController vehicle) { Plugin.Instance.PluginLogger.LogDebug("Player died to Cruiser Explosion! Setting special cause of death..."); if ((Object)(object)vehicle == (Object)null) { Plugin.Instance.PluginLogger.LogWarning("Could not get reference to vehicle..."); AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Player_Cruiser_Ran_Over); return; } Plugin.Instance.PluginLogger.LogDebug($"Got vehicle controller. ({vehicle.localPlayerInControl}, {vehicle.localPlayerInPassengerSeat})"); if (vehicle.localPlayerInControl) { AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Player_Cruiser_Driver); return; } if (vehicle.localPlayerInPassengerSeat) { AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Player_Cruiser_Passenger); return; } Plugin.Instance.PluginLogger.LogWarning("Could not get reference to local player in control or passenger seat..."); AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Player_Cruiser_Ran_Over); } } [HarmonyPatch(typeof(VehicleCollisionTrigger))] [HarmonyPatch("OnTriggerEnter")] internal class VehicleCollisionTriggerOnTriggerEnterPatch { private const string KILL_PLAYER_SIGNATURE = "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)"; private const string DAMAGE_PLAYER_SIGNATURE = "Void DamagePlayer(Int32, Boolean, Boolean, CauseOfDeath, Int32, Boolean, UnityEngine.Vector3)"; private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase method) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); List<CodeInstruction> list2 = BuildInstructionsToInsertKill(method); if (list2 == null) { Plugin.Instance.PluginLogger.LogError("Could not build instructions (kill) to insert in VehicleCollisionTriggerOnTriggerEnterPatch! Safely aborting..."); return instructions; } List<CodeInstruction> list3 = BuildInstructionsToInsertDamage(method); if (list3 == null) { Plugin.Instance.PluginLogger.LogError("Could not build instructions (damage) to insert in VehicleCollisionTriggerOnTriggerEnterPatch! Safely aborting..."); return instructions; } int num = -1; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Callvirt && val.operand.ToString() == "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)") { num = i; } } if (num == -1) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB.KillPlayer call in VehicleCollisionTriggerOnTriggerEnterPatch! Safely aborting..."); return instructions; } Plugin.Instance.PluginLogger.LogDebug("Injecting patch #1 into VehicleCollisionTrigger.OnTriggerEnter..."); list.InsertRange(num + 1, list2); Plugin.Instance.PluginLogger.LogDebug("Done."); int num2 = -1; for (int j = 0; j < list.Count; j++) { CodeInstruction val2 = list[j]; if (val2.opcode == OpCodes.Callvirt && val2.operand.ToString() == "Void DamagePlayer(Int32, Boolean, Boolean, CauseOfDeath, Int32, Boolean, UnityEngine.Vector3)") { num2 = j; } } if (num2 == -1) { Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB.DamagePlayer call in VehicleCollisionTriggerOnTriggerEnterPatch! Safely aborting..."); return instructions; } Plugin.Instance.PluginLogger.LogDebug("Injecting patch #2 into VehicleCollisionTrigger.OnTriggerEnter..."); list.InsertRange(num2 + 1, list3); Plugin.Instance.PluginLogger.LogDebug("Done."); Plugin.Instance.PluginLogger.LogDebug("Done with all VehicleCollisionTriggerOnTriggerEnterPatch patches."); return list; } private static List<CodeInstruction>? BuildInstructionsToInsertKill(MethodBase method) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(); list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(VehicleControllerDamagePlayerInVehiclePatch).GetMethod("RewriteCauseOfDeath"))); return list; } private static List<CodeInstruction>? BuildInstructionsToInsertDamage(MethodBase method) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(); list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(VehicleControllerDamagePlayerInVehiclePatch).GetMethod("MaybeRewriteCauseOfDeath"))); return list; } public static void MaybeRewriteCauseOfDeath() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_0054: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if (localPlayerController.isPlayerDead) { if ((int)localPlayerController.causeOfDeath == 8) { Plugin.Instance.PluginLogger.LogDebug("Player died from car accident damage"); RewriteCauseOfDeath(); } else { Plugin.Instance.PluginLogger.LogWarning($"Player was hit by a car but died of something else? {localPlayerController.causeOfDeath}"); } } else { Plugin.Instance.PluginLogger.LogDebug($"Player did not die from car accident (left at ${localPlayerController.health} health)"); } } public static void RewriteCauseOfDeath() { Plugin.Instance.PluginLogger.LogDebug("Player died to run over by Cruiser! Setting special cause of death..."); AdvancedDeathTracker.SetCauseOfDeath(GameNetworkManager.Instance.localPlayerController, AdvancedCauseOfDeath.Player_Cruiser_Ran_Over); } } [HarmonyPatch(typeof(Landmine))] [HarmonyPatch("SpawnExplosion")] internal class LandmineSpawnExplosionPatch { private const string KILL_PLAYER_SIGNATURE = "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)"; private const string DAMAGE_PLAYER_SIGNATURE = "Void DamagePlayer(Int32, Boolean, Boolean, CauseOfDeath, Int32, Boolean, UnityEngine.Vector3)"; private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase method) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); List<CodeInstruction> list2 = BuildInstructionsToInsertKill(method); if (list2 == null) { Plugin.Instance.PluginLogger.LogError("Could not build instructions (kill) to insert in LandmineSpawnExplosionPatch! Safely aborting..."); return instructions; } List<CodeInstruction> list3 = BuildInstructionsToInsertDamage(method); if (list3 == null) { Plugin.Instance.PluginLogger.LogError("Could not build instructions (damage) to insert in LandmineSpawnExplosionPatch! Safely aborting..."); return instructions; } int num = -1; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Callvirt && val.operand.ToString() == "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32, UnityEngine.Vector3)") { num = i;