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.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Coroner.LCAPI;
using GameNetcodeStuff;
using HarmonyLib;
using LC_API.ServerAPI;
using Microsoft.CodeAnalysis;
using TMPro;
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("Rework the Performance Report with new info, including cause of death.")]
[assembly: AssemblyFileVersion("1.6.2.0")]
[assembly: AssemblyInformationalVersion("1.6.2+1423f3c70e45a54deba89478a72d486dd8313c83")]
[assembly: AssemblyProduct("Coroner")]
[assembly: AssemblyTitle("Coroner")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.6.2.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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace Coroner
{
public class AdvancedDeathTracker
{
public const int PLAYER_CAUSE_OF_DEATH_DROPSHIP = 300;
public const int PLAYER_CAUSE_OF_DEATH_LADDER = 301;
private static readonly Dictionary<int, AdvancedCauseOfDeath> PlayerCauseOfDeath = new Dictionary<int, AdvancedCauseOfDeath>();
public static void ClearDeathTracker()
{
PlayerCauseOfDeath.Clear();
}
public static void SetCauseOfDeath(int playerIndex, AdvancedCauseOfDeath causeOfDeath, bool broadcast = true)
{
PlayerCauseOfDeath[playerIndex] = causeOfDeath;
if (broadcast)
{
DeathBroadcaster.BroadcastCauseOfDeath(playerIndex, causeOfDeath);
}
}
public static void SetCauseOfDeath(int playerIndex, CauseOfDeath causeOfDeath, bool broadcast = true)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
SetCauseOfDeath(playerIndex, ConvertCauseOfDeath(causeOfDeath), broadcast);
}
public static void SetCauseOfDeath(PlayerControllerB playerController, CauseOfDeath causeOfDeath, bool broadcast = true)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
SetCauseOfDeath((int)playerController.playerClientId, ConvertCauseOfDeath(causeOfDeath), broadcast);
}
public static void SetCauseOfDeath(PlayerControllerB playerController, AdvancedCauseOfDeath causeOfDeath, bool broadcast = true)
{
SetCauseOfDeath((int)playerController.playerClientId, causeOfDeath, broadcast);
}
public static AdvancedCauseOfDeath GetCauseOfDeath(int playerIndex)
{
PlayerControllerB playerController = StartOfRound.Instance.allPlayerScripts[playerIndex];
return GetCauseOfDeath(playerController);
}
public static bool HasCauseOfDeath(int playerIndex)
{
return PlayerCauseOfDeath.ContainsKey(playerIndex);
}
public static bool HasCauseOfDeath(PlayerControllerB playerController)
{
return HasCauseOfDeath((int)playerController.playerClientId);
}
public static AdvancedCauseOfDeath GetCauseOfDeath(PlayerControllerB playerController)
{
if (!PlayerCauseOfDeath.ContainsKey((int)playerController.playerClientId))
{
Plugin.Instance.PluginLogger.LogDebug($"Player {playerController.playerClientId} has no custom cause of death stored! Using fallback...");
return GuessCauseOfDeath(playerController);
}
Plugin.Instance.PluginLogger.LogDebug($"Player {playerController.playerClientId} has custom cause of death stored! {PlayerCauseOfDeath[(int)playerController.playerClientId]}");
return PlayerCauseOfDeath[(int)playerController.playerClientId];
}
public static AdvancedCauseOfDeath GuessCauseOfDeath(PlayerControllerB playerController)
{
//IL_0041: 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_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: 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 ConvertCauseOfDeath(playerController.causeOfDeath);
}
return AdvancedCauseOfDeath.Unknown;
}
public static bool IsHoldingJetpack(PlayerControllerB playerController)
{
GrabbableObject currentlyHeldObjectServer = playerController.currentlyHeldObjectServer;
if ((Object)(object)currentlyHeldObjectServer == (Object)null)
{
return false;
}
GameObject gameObject = ((Component)currentlyHeldObjectServer).gameObject;
if ((Object)(object)gameObject == (Object)null)
{
return false;
}
GrabbableObject component = gameObject.GetComponent<GrabbableObject>();
if ((Object)(object)component == (Object)null)
{
return false;
}
if (component is JetpackItem)
{
return true;
}
return false;
}
public 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_003b: Expected I4, but got Unknown
return (int)causeOfDeath switch
{
0 => AdvancedCauseOfDeath.Unknown,
1 => AdvancedCauseOfDeath.Bludgeoning,
2 => AdvancedCauseOfDeath.Gravity,
3 => AdvancedCauseOfDeath.Blast,
4 => AdvancedCauseOfDeath.Strangulation,
5 => AdvancedCauseOfDeath.Suffocation,
6 => AdvancedCauseOfDeath.Mauling,
7 => AdvancedCauseOfDeath.Gunshots,
8 => AdvancedCauseOfDeath.Crushing,
9 => AdvancedCauseOfDeath.Drowning,
10 => AdvancedCauseOfDeath.Abandoned,
11 => AdvancedCauseOfDeath.Electrocution,
_ => AdvancedCauseOfDeath.Unknown,
};
}
public static string StringifyCauseOfDeath(CauseOfDeath causeOfDeath)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return StringifyCauseOfDeath(ConvertCauseOfDeath(causeOfDeath), Plugin.RANDOM);
}
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");
}
return causeOfDeath switch
{
AdvancedCauseOfDeath.Bludgeoning => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathBludgeoning"),
AdvancedCauseOfDeath.Gravity => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathGravity"),
AdvancedCauseOfDeath.Blast => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathBlast"),
AdvancedCauseOfDeath.Strangulation => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathStrangulation"),
AdvancedCauseOfDeath.Suffocation => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathSuffocation"),
AdvancedCauseOfDeath.Mauling => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathMauling"),
AdvancedCauseOfDeath.Gunshots => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathGunshots"),
AdvancedCauseOfDeath.Crushing => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathCrushing"),
AdvancedCauseOfDeath.Drowning => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathDrowning"),
AdvancedCauseOfDeath.Abandoned => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathAbandoned"),
AdvancedCauseOfDeath.Electrocution => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathElectrocution"),
AdvancedCauseOfDeath.Kicking => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathKicking"),
AdvancedCauseOfDeath.Enemy_Bracken => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyBracken"),
AdvancedCauseOfDeath.Enemy_EyelessDog => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyEyelessDog"),
AdvancedCauseOfDeath.Enemy_ForestGiant => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyForestGiant"),
AdvancedCauseOfDeath.Enemy_CircuitBees => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyCircuitBees"),
AdvancedCauseOfDeath.Enemy_GhostGirl => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyGhostGirl"),
AdvancedCauseOfDeath.Enemy_EarthLeviathan => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyEarthLeviathan"),
AdvancedCauseOfDeath.Enemy_BaboonHawk => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyBaboonHawk"),
AdvancedCauseOfDeath.Enemy_Jester => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyJester"),
AdvancedCauseOfDeath.Enemy_CoilHead => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyCoilHead"),
AdvancedCauseOfDeath.Enemy_SnareFlea => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemySnareFlea"),
AdvancedCauseOfDeath.Enemy_Hygrodere => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyHygrodere"),
AdvancedCauseOfDeath.Enemy_HoarderBug => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyHoarderBug"),
AdvancedCauseOfDeath.Enemy_SporeLizard => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemySporeLizard"),
AdvancedCauseOfDeath.Enemy_BunkerSpider => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyBunkerSpider"),
AdvancedCauseOfDeath.Enemy_Thumper => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyThumper"),
AdvancedCauseOfDeath.Enemy_MaskedPlayer_Wear => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyMaskedPlayerWear"),
AdvancedCauseOfDeath.Enemy_MaskedPlayer_Victim => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyMaskedPlayerVictim"),
AdvancedCauseOfDeath.Enemy_Nutcracker_Kicked => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyNutcrackerKicked"),
AdvancedCauseOfDeath.Enemy_Nutcracker_Shot => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathEnemyNutcrackerShot"),
AdvancedCauseOfDeath.Player_Jetpack_Gravity => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathPlayerJetpackGravity"),
AdvancedCauseOfDeath.Player_Jetpack_Blast => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathPlayerJetpackBlast"),
AdvancedCauseOfDeath.Player_Ladder => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathPlayerLadder"),
AdvancedCauseOfDeath.Player_Murder_Melee => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathPlayerMurderMelee"),
AdvancedCauseOfDeath.Player_Murder_Shotgun => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathPlayerMurderShotgun"),
AdvancedCauseOfDeath.Player_Quicksand => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathPlayerQuicksand"),
AdvancedCauseOfDeath.Player_StunGrenade => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathPlayerStunGrenade"),
AdvancedCauseOfDeath.Other_DepositItemsDesk => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathOtherDepositItemsDesk"),
AdvancedCauseOfDeath.Other_Dropship => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathOtherItemDropship"),
AdvancedCauseOfDeath.Other_Landmine => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathOtherLandmine"),
AdvancedCauseOfDeath.Other_Turret => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathOtherTurret"),
AdvancedCauseOfDeath.Other_Lightning => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathOtherLightning"),
_ => Plugin.Instance.LanguageHandler.GetValuesByTag("DeathUnknown"),
};
}
internal static void SetCauseOfDeath(PlayerControllerB playerControllerB, object enemy_BaboonHawk)
{
throw new NotImplementedException();
}
}
public enum AdvancedCauseOfDeath
{
Unknown,
Bludgeoning,
Gravity,
Blast,
Strangulation,
Suffocation,
Mauling,
Gunshots,
Crushing,
Drowning,
Abandoned,
Electrocution,
Kicking,
Enemy_BaboonHawk,
Enemy_Bracken,
Enemy_CircuitBees,
Enemy_CoilHead,
Enemy_EarthLeviathan,
Enemy_EyelessDog,
Enemy_ForestGiant,
Enemy_GhostGirl,
Enemy_Hygrodere,
Enemy_Jester,
Enemy_SnareFlea,
Enemy_SporeLizard,
Enemy_HoarderBug,
Enemy_Thumper,
Enemy_BunkerSpider,
Enemy_MaskedPlayer_Wear,
Enemy_MaskedPlayer_Victim,
Enemy_Nutcracker_Kicked,
Enemy_Nutcracker_Shot,
Player_Jetpack_Gravity,
Player_Jetpack_Blast,
Player_Quicksand,
Player_Ladder,
Player_Murder_Melee,
Player_Murder_Shotgun,
Player_StunGrenade,
Other_Landmine,
Other_Turret,
Other_Lightning,
Other_DepositItemsDesk,
Other_Dropship
}
internal class DeathBroadcaster
{
private const string SIGNATURE_DEATH = "com.elitemastereric.coroner.death";
public static void Initialize()
{
if (Plugin.Instance.IsLCAPIPresent)
{
DeathBroadcasterLCAPI.Initialize();
}
else
{
Plugin.Instance.PluginLogger.LogInfo("LC_API is not present! Skipping registration...");
}
}
public static void BroadcastCauseOfDeath(int playerId, AdvancedCauseOfDeath causeOfDeath)
{
AttemptBroadcast(BuildDataCauseOfDeath(playerId, causeOfDeath), "com.elitemastereric.coroner.death");
}
private static string BuildDataCauseOfDeath(int playerId, AdvancedCauseOfDeath causeOfDeath)
{
string text = playerId.ToString();
int num = (int)causeOfDeath;
return text + "|" + num;
}
private static void AttemptBroadcast(string data, string signature)
{
if (Plugin.Instance.IsLCAPIPresent)
{
DeathBroadcasterLCAPI.AttemptBroadcast(data, signature);
}
else
{
Plugin.Instance.PluginLogger.LogInfo("LC_API is not present! Skipping broadcast...");
}
}
}
public class LanguageHandler
{
public const string DEFAULT_LANGUAGE = "en";
public static readonly string[] AVAILABLE_LANGUAGES = new string[11]
{
"en", "de", "es", "fr", "hu", "it", "ko", "nl", "pt-br", "ru",
"zh-cn"
};
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_ENEMY_BRACKEN = "DeathEnemyBracken";
public const string TAG_DEATH_ENEMY_EYELESS_DOG = "DeathEnemyEyelessDog";
public const string TAG_DEATH_ENEMY_FOREST_GIANT = "DeathEnemyForestGiant";
public const string TAG_DEATH_ENEMY_CIRCUIT_BEES = "DeathEnemyCircuitBees";
public const string TAG_DEATH_ENEMY_GHOST_GIRL = "DeathEnemyGhostGirl";
public const string TAG_DEATH_ENEMY_EARTH_LEVIATHAN = "DeathEnemyEarthLeviathan";
public const string TAG_DEATH_ENEMY_BABOON_HAWK = "DeathEnemyBaboonHawk";
public const string TAG_DEATH_ENEMY_JESTER = "DeathEnemyJester";
public const string TAG_DEATH_ENEMY_COILHEAD = "DeathEnemyCoilHead";
public const string TAG_DEATH_ENEMY_SNARE_FLEA = "DeathEnemySnareFlea";
public const string TAG_DEATH_ENEMY_HYGRODERE = "DeathEnemyHygrodere";
public const string TAG_DEATH_ENEMY_HOARDER_BUG = "DeathEnemyHoarderBug";
public const string TAG_DEATH_ENEMY_SPORE_LIZARD = "DeathEnemySporeLizard";
public const string TAG_DEATH_ENEMY_BUNKER_SPIDER = "DeathEnemyBunkerSpider";
public const string TAG_DEATH_ENEMY_THUMPER = "DeathEnemyThumper";
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_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_MELEE = "DeathPlayerMurderMelee";
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_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_UNKNOWN = "DeathUnknown";
public string languageCode;
private XDocument languageData;
public LanguageHandler(string languageCode)
{
Plugin.Instance.PluginLogger.LogInfo("Coroner loading language support: " + languageCode);
this.languageCode = languageCode;
ValidateLanguage(languageCode);
LoadLanguageData(languageCode);
}
private void ValidateLanguage(string languageCode)
{
if (!AVAILABLE_LANGUAGES.Contains(languageCode))
{
Plugin.Instance.PluginLogger.LogWarning("Coroner Unknown language code: " + languageCode);
Plugin.Instance.PluginLogger.LogWarning("Coroner There may be issues loading language data.");
}
}
private void LoadLanguageData(string languageCode)
{
try
{
Plugin.Instance.PluginLogger.LogInfo("Loading language data from config folder: " + Plugin.Instance.GetConfigPath());
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.");
}
}
else if (!File.Exists(Plugin.Instance.GetConfigPath() + "/Strings_" + languageCode + ".xml"))
{
Plugin.Instance.PluginLogger.LogError("Localization File not found at: " + Plugin.Instance.GetConfigPath());
}
else
{
languageData = XDocument.Load(Plugin.Instance.GetConfigPath() + "/Strings_" + languageCode + ".xml");
}
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error loading language data: " + ex.Message);
Plugin.Instance.PluginLogger.LogError(ex.StackTrace);
}
}
public static string GetLanguageList()
{
return "(" + string.Join(", ", AVAILABLE_LANGUAGES) + ")";
}
public string GetValueByTag(string tag)
{
if (languageData == null && languageCode != "en")
{
return Plugin.Instance.FallbackLanguageHandler.GetValueByTag(tag);
}
string text = languageData.Descendants(tag).FirstOrDefault()?.Attribute("text")?.Value;
if (text == null || text.Length == 0)
{
Plugin.Instance.PluginLogger.LogWarning("No values found for tag '" + tag + "' in language '" + languageCode + "', displaying error text...");
return "{'" + tag + "'}";
}
return text;
}
public string[] GetValuesByTag(string tag)
{
if (languageData == null && languageCode != "en")
{
return Plugin.Instance.FallbackLanguageHandler.GetValuesByTag(tag);
}
IEnumerable<XElement> source = languageData.Descendants(tag);
IEnumerable<string> source2 = source.Select((XElement item) => item.Attribute("text")?.Value);
IEnumerable<string> source3 = source2.Where((string item) => item != null);
string[] array = source3.ToArray();
if (array.Length == 0 && languageCode != "en")
{
Plugin.Instance.PluginLogger.LogWarning("No values found for tag '" + tag + "' in language '" + languageCode + "', using fallback...");
return Plugin.Instance.FallbackLanguageHandler.GetValuesByTag(tag);
}
if (array.Length == 0)
{
Plugin.Instance.PluginLogger.LogWarning("No values found for tag '" + tag + "' in language '" + languageCode + "', displaying error text...");
return new string[1] { "{'" + tag + "'}" };
}
return array;
}
}
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 = "1.6.2";
public const string PLUGIN_GUID = "com.elitemastereric.coroner";
}
[BepInPlugin("com.elitemastereric.coroner", "Coroner", "1.6.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
public static readonly Random RANDOM = new Random();
public PluginLogger PluginLogger;
public PluginConfig PluginConfig;
public LanguageHandler LanguageHandler;
public LanguageHandler FallbackLanguageHandler;
public bool IsLCAPIPresent = false;
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_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Expected O, but got Unknown
Instance = this;
PluginLogger = new PluginLogger(((BaseUnityPlugin)this).Logger, (LogLevel)16);
Harmony val = new Harmony("com.elitemastereric.coroner");
val.PatchAll();
PluginLogger.LogInfo("Plugin Coroner (com.elitemastereric.coroner) is loaded!");
LoadConfig();
LoadLanguageHandlers();
QueryLCAPI();
DeathBroadcaster.Initialize();
}
public string GetConfigPath()
{
return Paths.ConfigPath + "/EliteMasterEric-Coroner";
}
public void LoadLanguageHandlers()
{
LanguageHandler = new LanguageHandler(PluginConfig.GetSelectedLanguage());
FallbackLanguageHandler = new LanguageHandler("en");
}
private void QueryLCAPI()
{
PluginLogger.LogInfo("Checking for LC_API...");
if (Chainloader.PluginInfos.ContainsKey("LC_API"))
{
Chainloader.PluginInfos.TryGetValue("LC_API", out var value);
if (value == null)
{
PluginLogger.LogError("Detected LC_API, but could not get plugin info!");
IsLCAPIPresent = false;
}
else
{
PluginLogger.LogInfo("LCAPI is present! " + value.Metadata.GUID + ":" + value.Metadata.Version);
IsLCAPIPresent = true;
}
}
else
{
PluginLogger.LogInfo("LCAPI is not present.");
IsLCAPIPresent = false;
}
}
private void LoadConfig()
{
PluginConfig = new PluginConfig();
PluginConfig.BindConfig(((BaseUnityPlugin)this).Config);
}
}
public class PluginLogger
{
private ManualLogSource manualLogSource;
private LogLevel logLevel;
public PluginLogger(ManualLogSource manualLogSource, LogLevel logLevel = 16)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
this.manualLogSource = manualLogSource;
this.logLevel = logLevel;
}
public void LogFatal(object data)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Invalid comparison between Unknown and I4
if ((int)logLevel >= 1)
{
manualLogSource.LogFatal(data);
}
}
public void LogError(object data)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Invalid comparison between Unknown and I4
if ((int)logLevel >= 2)
{
manualLogSource.LogError(data);
}
}
public void LogWarning(object data)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Invalid comparison between Unknown and I4
if ((int)logLevel >= 4)
{
manualLogSource.LogWarning(data);
}
}
public void LogMessage(object data)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Invalid comparison between Unknown and I4
if ((int)logLevel >= 8)
{
manualLogSource.LogMessage(data);
}
}
public void LogInfo(object data)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Invalid comparison between Unknown and I4
if ((int)logLevel >= 16)
{
manualLogSource.LogInfo(data);
}
}
public void LogDebug(object data)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Invalid comparison between Unknown and I4
if ((int)logLevel >= 32)
{
manualLogSource.LogDebug(data);
}
}
}
public class PluginConfig
{
private ConfigEntry<bool> DisplayCauseOfDeath;
private ConfigEntry<bool> SeriousDeathMessages;
private ConfigEntry<bool> DisplayFunnyNotes;
private ConfigEntry<bool> DeathReplacesNotes;
private ConfigEntry<string> LanguagePicker;
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", "Select a language to use " + LanguageHandler.GetLanguageList());
}
public bool ShouldDisplayCauseOfDeath()
{
return DisplayCauseOfDeath.Value;
}
public bool ShouldUseSeriousDeathMessages()
{
return SeriousDeathMessages.Value;
}
public bool ShouldDisplayFunnyNotes()
{
return DisplayFunnyNotes.Value;
}
public bool ShouldDeathReplaceNotes()
{
return DeathReplacesNotes.Value;
}
public string GetSelectedLanguage()
{
return LanguagePicker.Value.Replace('-', '_');
}
}
}
namespace Coroner.Patch
{
[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 ((int)causeOfDeath == 300)
{
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 ((int)causeOfDeath == 301)
{
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
{
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(DepositItemsDesk))]
[HarmonyPatch("AnimationGrabPlayer")]
internal class DepositItemsDeskAnimationGrabPlayerPatch
{
public static void Postfix(int playerID)
{
try
{
Plugin.Instance.PluginLogger.LogDebug("Accessing state after tentacle devouring...");
PlayerControllerB playerController = StartOfRound.Instance.allPlayerScripts[playerID];
Plugin.Instance.PluginLogger.LogDebug("Player is dying! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(playerController, AdvancedCauseOfDeath.Other_DepositItemsDesk);
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in DepositItemsDeskAnimationGrabPlayerPatch.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 is now dead! 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(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 is now dead! 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(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 is now dead! 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(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 is now dead! 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(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 is now dead! 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(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 is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(playerBeingEaten, AdvancedCauseOfDeath.Enemy_ForestGiant);
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in ForestGiantAIEatPlayerAnimationPatch.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 is now dead! 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(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 is now dead! 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(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(PlayerControllerB))]
[HarmonyPatch("DamagePlayerFromOtherClientClientRpc")]
internal class PlayerControllerBDamagePlayerFromOtherClientClientRpcPatch
{
public static void Postfix(PlayerControllerB __instance)
{
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Invalid comparison between Unknown and I4
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Invalid comparison between Unknown and I4
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Invalid comparison between Unknown and I4
try
{
Plugin.Instance.PluginLogger.LogDebug("Handling friendly fire damage...");
if ((Object)(object)__instance == (Object)null)
{
Plugin.Instance.PluginLogger.LogWarning("Could not access victim after death!");
}
else if (__instance.isPlayerDead)
{
if ((int)__instance.causeOfDeath == 1)
{
Plugin.Instance.PluginLogger.LogDebug("Player is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(__instance, AdvancedCauseOfDeath.Player_Murder_Melee);
}
else if ((int)__instance.causeOfDeath == 6)
{
Plugin.Instance.PluginLogger.LogDebug("Player is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(__instance, AdvancedCauseOfDeath.Player_Murder_Melee);
}
else if ((int)__instance.causeOfDeath == 7)
{
Plugin.Instance.PluginLogger.LogDebug("Player is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(__instance, AdvancedCauseOfDeath.Player_Murder_Shotgun);
}
else
{
Plugin.Instance.PluginLogger.LogWarning("Player was killed by someone else but we don't know how! " + ((object)(CauseOfDeath)(ref __instance.causeOfDeath)).ToString());
}
}
else
{
Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping...");
}
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in PlayerControllerBDamagePlayerFromOtherClientClientRpcPatch.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 is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_SporeLizard);
}
else
{
Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping...");
}
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in PufferAIOnCollideWithPlayerPatch.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 is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_CoilHead);
}
else
{
Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping...");
}
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in SpringManAIOnCollideWithPlayerPatch.Postfix: " + ex);
Plugin.Instance.PluginLogger.LogError(ex.StackTrace);
}
}
}
[HarmonyPatch(typeof(BlobAI))]
[HarmonyPatch("SlimeKillPlayerEffectServerRpc")]
internal class BlobAISlimeKillPlayerEffectServerRpcPatch
{
public static void Postfix(int playerKilled)
{
try
{
PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerKilled];
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 is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(val, AdvancedCauseOfDeath.Enemy_Hygrodere);
}
else
{
Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping...");
}
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in BlobAISlimeKillPlayerEffectServerRpcPatch.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 is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_HoarderBug);
}
else
{
Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping...");
}
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in HoarderBugAIOnCollideWithPlayerPatch.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 is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_Thumper);
}
else
{
Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping...");
}
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in CrawlerAIOnCollideWithPlayerPatch.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 is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(component, AdvancedCauseOfDeath.Enemy_BunkerSpider);
}
else
{
Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping...");
}
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in SandSpiderAIOnCollideWithPlayerPatch.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 is dying! 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 is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(localPlayerController, AdvancedCauseOfDeath.Enemy_Nutcracker_Shot);
}
else
{
Plugin.Instance.PluginLogger.LogDebug("Player is now dead! 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(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 is now dead! 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(HauntedMaskItem))]
[HarmonyPatch("FinishAttaching")]
internal class HauntedMaskItemFinishAttachingPatch
{
public static void Postfix(HauntedMaskItem __instance)
{
try
{
Plugin.Instance.PluginLogger.LogDebug("Masked Player killed 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 is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(value, AdvancedCauseOfDeath.Enemy_MaskedPlayer_Wear);
}
else
{
Plugin.Instance.PluginLogger.LogDebug("Player is somehow still alive! Skipping...");
}
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in HauntedMaskItemFinishAttachingPatch.Postfix: " + ex);
Plugin.Instance.PluginLogger.LogError(ex.StackTrace);
}
}
}
[HarmonyPatch(typeof(ExtensionLadderItem))]
[HarmonyPatch("StartLadderAnimation")]
internal class ExtensionLadderItemStartLadderAnimationPatch
{
public static void Postfix(ExtensionLadderItem __instance)
{
//IL_00d3: 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.");
}
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.");
}
GameObject gameObject2 = ((Component)val).gameObject;
if ((Object)(object)gameObject2 == (Object)null)
{
Plugin.Instance.PluginLogger.LogError("Could not fetch KillTrigger GameObject from ExtensionLadderItem.");
}
KillLocalPlayer component = gameObject2.GetComponent<KillLocalPlayer>();
if ((Object)(object)component == (Object)null)
{
Plugin.Instance.PluginLogger.LogError("Could not fetch KillLocalPlayer from KillTrigger GameObject.");
}
component.causeOfDeath = (CauseOfDeath)301;
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in ExtensionLadderItemStartLadderAnimationPatch.Postfix: " + ex);
Plugin.Instance.PluginLogger.LogError(ex.StackTrace);
}
}
}
[HarmonyPatch(typeof(ItemDropship))]
[HarmonyPatch("Start")]
internal class ItemDropshipStartPatch
{
public static void Postfix(ItemDropship __instance)
{
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
try
{
Plugin.Instance.PluginLogger.LogDebug("Item dropship spawned! Modifying kill trigger...");
GameObject gameObject = ((Component)__instance).gameObject;
if ((Object)(object)gameObject == (Object)null)
{
Plugin.Instance.PluginLogger.LogError("Could not fetch GameObject from ItemDropship.");
}
Transform val = gameObject.transform.Find("ItemShip/KillTrigger");
if ((Object)(object)val == (Object)null)
{
Plugin.Instance.PluginLogger.LogError("Could not fetch KillTrigger Transform from ItemDropship.");
}
GameObject gameObject2 = ((Component)val).gameObject;
if ((Object)(object)gameObject2 == (Object)null)
{
Plugin.Instance.PluginLogger.LogError("Could not fetch KillTrigger GameObject from ItemDropship.");
}
KillLocalPlayer component = gameObject2.GetComponent<KillLocalPlayer>();
if ((Object)(object)component == (Object)null)
{
Plugin.Instance.PluginLogger.LogError("Could not fetch KillLocalPlayer from KillTrigger GameObject.");
}
component.causeOfDeath = (CauseOfDeath)300;
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in ItemDropshipStartPatch.Postfix: " + ex);
Plugin.Instance.PluginLogger.LogError(ex.StackTrace);
}
}
}
[HarmonyPatch(typeof(Turret))]
[HarmonyPatch("Update")]
public class TurretUpdatePatch
{
public static void Postfix(Turret __instance)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Invalid comparison between Unknown and I4
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Invalid comparison between Unknown and I4
if ((int)__instance.turretMode == 2)
{
PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
if (localPlayerController.isPlayerDead && (int)localPlayerController.causeOfDeath == 7)
{
Plugin.Instance.PluginLogger.LogDebug("Player is now dead! Setting special cause of death...");
AdvancedDeathTracker.SetCauseOfDeath(localPlayerController, AdvancedCauseOfDeath.Other_Turret);
}
}
}
}
[HarmonyPatch(typeof(Landmine))]
[HarmonyPatch("SpawnExplosion")]
public class LandmineSpawnExplosionPatch
{
private const string KILL_PLAYER_SIGNATURE = "Void KillPlayer(UnityEngine.Vector3, Boolean, CauseOfDeath, Int32)";
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 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)")
{
num = i;
break;
}
}
if (num == -1)
{
Plugin.Instance.PluginLogger.LogError("Could not find PlayerControllerB.KillPlayer call in LandmineSpawnExplosionPatch! Safely aborting...");
return instructions;
}
Plugin.Instance.PluginLogger.LogInfo("Injecting patch into Landmine.SpawnExplosion...");
list.InsertRange(num, list2);
Plugin.Instance.PluginLogger.LogInfo("Done.");
return list;
}
private static List<CodeInstruction> BuildInstructionsToInsert(MethodBase method)
{
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Expected O, but got Unknown
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Expected O, but got Unknown
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Expected O, but got Unknown
List<CodeInstruction> list = new List<CodeInstruction>();
int num = 2;
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 LandmineSpawnExplosionPatch!");
return null;
}
localVariableInfo = localVariableInfo2;
break;
}
}
list.Add(new CodeInstruction(OpCodes.Ldloc_S, (object)localVariableInfo.LocalIndex));
list.Add(new CodeInstruction(OpCodes.Ldarg, (object)num));
list.Add(new CodeInstruction(OpCodes.Call, (object)typeof(LandmineSpawnExplosionPatch).GetMethod("RewriteCauseOfDeath")));
return list;
}
public static void RewriteCauseOfDeath(PlayerControllerB targetPlayer, float killRange)
{
AdvancedCauseOfDeath causeOfDeath = AdvancedCauseOfDeath.Blast;
if (killRange == 5f)
{
causeOfDeath = AdvancedCauseOfDeath.Player_Jetpack_Blast;
}
else if (killRange == 5.7f)
{
causeOfDeath = AdvancedCauseOfDeath.Other_Landmine;
}
else if (killRange == 2.4f)
{
causeOfDeath = AdvancedCauseOfDeath.Other_Lightning;
}
AdvancedDeathTracker.SetCauseOfDeath(targetPlayer, causeOfDeath);
}
}
[HarmonyPatch(typeof(HUDManager))]
[HarmonyPatch("FillEndGameStats")]
internal class HUDManagerFillEndGameStatsPatch
{
private const string EMPTY_NOTES = "Notes: \n";
public static void Postfix(HUDManager __instance)
{
try
{
OverridePerformanceReport(__instance);
}
catch (Exception ex)
{
Plugin.Instance.PluginLogger.LogError("Error in HUDManagerFillEndGameStatsPatch.Postfix: " + ex);
Plugin.Instance.PluginLogger.LogError(ex.StackTrace);
}
}
private static Random BuildSyncedRandom()
{
int randomMapSeed = StartOfRound.Instance.randomMapSeed;
Plugin.Instance.PluginLogger.LogDebug("Syncing randomization to map seed: '" + randomMapSeed + "'");
return new Random(randomMapSeed);
}
private static void OverridePerformanceReport(HUDManager __instance)
{
Plugin.Instance.PluginLogger.LogDebug("Applying Coroner patches to player notes...");
Random random = BuildSyncedRandom();
for (int i = 0; i < __instance.statsUIElements.playerNotesText.Length; i++)
{
PlayerControllerB val = __instance.playersManager.allPlayerScripts[i];
if (!val.disconnectedMidGame && !val.isPlayerDead && !val.isPlayerControlled)
{
Plugin.Instance.PluginLogger.LogInfo("Player " + i + " is not controlled by a player. Skipping...");
continue;
}
TextMeshProUGUI val2 = __instance.statsUIElements.playerNotesText[i];
if (val.isPlayerDead)
{
if (Plugin.Instance.PluginConfig.ShouldDisplayCauseOfDeath())
{
if (Plugin.Instance.PluginConfig.ShouldDeathReplaceNotes())
{
Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " is dead! Replacing notes with Cause of Death...");
((TMP_Text)val2).text = Plugin.Instance.LanguageHandler.GetValueByTag("UICauseOfDeath") + "\n";
}
else
{
Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " is dead! Appending notes with Cause of Death...");
}
AdvancedCauseOfDeath causeOfDeath = AdvancedDeathTracker.GetCauseOfDeath(val);
((TMP_Text)val2).text = ((TMP_Text)val2).text + "* " + AdvancedDeathTracker.StringifyCauseOfDeath(causeOfDeath, random) + "\n";
}
else
{
Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " is dead, but Config says leave it be...");
}
}
else if (((TMP_Text)val2).text == "Notes: \n")
{
if (Plugin.Instance.PluginConfig.ShouldDisplayFunnyNotes())
{
Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " has no notes! Injecting something funny...");
((TMP_Text)val2).text = Plugin.Instance.LanguageHandler.GetValueByTag("UINotes") + "\n";
((TMP_Text)val2).text = ((TMP_Text)val2).text + "* " + AdvancedDeathTracker.StringifyCauseOfDeath(null, random) + "\n";
}
else
{
Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " has no notes, but Config says leave it be...");
}
}
else
{
Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + i + " has notes, don't override them...");
}
}
AdvancedDeathTracker.ClearDeathTracker();
}
}
}
namespace Coroner.LCAPI
{
internal class DeathBroadcasterLCAPI
{
private const string SIGNATURE_DEATH = "com.elitemastereric.coroner.death";
public static void Initialize()
{
Plugin.Instance.PluginLogger.LogDebug("Initializing DeathBroadcaster...");
if (Plugin.Instance.IsLCAPIPresent)
{
Plugin.Instance.PluginLogger.LogDebug("LC_API is present! Registering signature...");
Networking.GetString = (Action<string, string>)Delegate.Combine(Networking.GetString, new Action<string, string>(OnBroadcastString));
}
else
{
Plugin.Instance.PluginLogger.LogError("LC_API is not present! Why did you try to register the DeathBroadcaster?");
}
}
private static void OnBroadcastString(string data, string signature)
{
if (signature == "com.elitemastereric.coroner.death")
{
Plugin.Instance.PluginLogger.LogDebug("Broadcast has been received from LC_API!");
string[] array = data.Split('|');
int playerIndex = int.Parse(array[0]);
int num = int.Parse(array[1]);
AdvancedCauseOfDeath advancedCauseOfDeath = (AdvancedCauseOfDeath)num;
Plugin.Instance.PluginLogger.LogDebug("Player " + playerIndex + " died of " + AdvancedDeathTracker.StringifyCauseOfDeath((AdvancedCauseOfDeath?)advancedCauseOfDeath));
AdvancedDeathTracker.SetCauseOfDeath(playerIndex, advancedCauseOfDeath, broadcast: false);
}
}
public static void AttemptBroadcast(string data, string signature)
{
if (Plugin.Instance.IsLCAPIPresent)
{
Plugin.Instance.PluginLogger.LogDebug("LC_API is present! Broadcasting...");
Networking.Broadcast(data, signature);
}
else
{
Plugin.Instance.PluginLogger.LogDebug("LC_API is not present! Skipping broadcast...");
}
}
}
}