Decompiled source of DeadTTS v1.0.12

REPO-DeadTTS.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using REPO_DeadTTS.Config;
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: AssemblyTitle("REPO-DeadTTS")]
[assembly: AssemblyDescription("Mod created by flipf17")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("REPO-DeadTTS")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8e05cd18-c8aa-419a-b430-33faaf371490")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace REPO_DeadTTS
{
	[BepInPlugin("flipf17.DeadTTS", "DeadTTS", "1.0.12")]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		public static Plugin instance;

		private static ManualLogSource logger;

		private void Awake()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			instance = this;
			CreateCustomLogger();
			ConfigSettings.BindConfigSettings();
			_harmony = new Harmony("DeadTTS");
			PatchAll();
			Log("DeadTTS loaded");
		}

		private void PatchAll()
		{
			IEnumerable<Type> enumerable;
			try
			{
				enumerable = Assembly.GetExecutingAssembly().GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				enumerable = ex.Types.Where((Type t) => t != null);
			}
			foreach (Type item in enumerable)
			{
				_harmony.PatchAll(item);
			}
		}

		private void CreateCustomLogger()
		{
			try
			{
				logger = Logger.CreateLogSource(string.Format("{0}-{1}", "DeadTTS", "1.0.12"));
			}
			catch
			{
				logger = ((BaseUnityPlugin)this).Logger;
			}
		}

		internal static void Log(string message)
		{
			logger.LogInfo((object)message);
		}

		internal static void LogError(string message)
		{
			logger.LogError((object)message);
		}

		internal static void LogWarning(string message)
		{
			logger.LogWarning((object)message);
		}

		internal static void LogVerbose(string message)
		{
			if (ConfigSettings.verboseLogs.Value)
			{
				logger.LogInfo((object)("[VERBOSE] " + message));
			}
		}

		internal static void LogErrorVerbose(string message)
		{
			if (ConfigSettings.verboseLogs.Value)
			{
				logger.LogError((object)("[VERBOSE] " + message));
			}
		}

		internal static void LogWarningVerbose(string message)
		{
			if (ConfigSettings.verboseLogs.Value)
			{
				logger.LogWarning((object)("[VERBOSE] " + message));
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "flipf17.DeadTTS";

		public const string PLUGIN_NAME = "DeadTTS";

		public const string PLUGIN_VERSION = "1.0.12";
	}
}
namespace REPO_DeadTTS.Patches
{
	[HarmonyPatch]
	public static class UIPatcher
	{
		private static HashSet<WorldSpaceUITTS> deadTTSElements = new HashSet<WorldSpaceUITTS>();

		private static HashSet<WorldSpaceUITTS> deadTTSElementsFollowLog = new HashSet<WorldSpaceUITTS>();

		private static Dictionary<PlayerAvatar, bool> isDisabledStates = new Dictionary<PlayerAvatar, bool>();

		private static FieldInfo textField = typeof(WorldSpaceUITTS).GetField("text", BindingFlags.Instance | BindingFlags.NonPublic);

		private static FieldInfo playerAvatarField = typeof(WorldSpaceUITTS).GetField("playerAvatar", BindingFlags.Instance | BindingFlags.NonPublic);

		private static FieldInfo followTransformField = typeof(WorldSpaceUITTS).GetField("followTransform", BindingFlags.Instance | BindingFlags.NonPublic);

		private static FieldInfo worldPositionField = typeof(WorldSpaceUITTS).GetField("worldPosition", BindingFlags.Instance | BindingFlags.NonPublic);

		private static FieldInfo followPositionField = typeof(WorldSpaceUITTS).GetField("followPosition", BindingFlags.Instance | BindingFlags.NonPublic);

		private static FieldInfo wordTimeField = typeof(WorldSpaceUITTS).GetField("wordTime", BindingFlags.Instance | BindingFlags.NonPublic);

		private static FieldInfo ttsVoiceField = typeof(WorldSpaceUITTS).GetField("ttsVoice", BindingFlags.Instance | BindingFlags.NonPublic);

		[HarmonyPatch(typeof(WorldSpaceUIParent), "TTS")]
		[HarmonyPrefix]
		public static void OnTTSUI(PlayerAvatar _player, string _text, float _time, WorldSpaceUIParent __instance)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			if (!GameManager.Multiplayer() || (int)GameDirector.instance.currentState != 2 || (!SemiFunc.RunIsLevel() && !SemiFunc.RunIsTutorial() && !SemiFunc.RunIsShop() && !SemiFunc.RunIsArena()) || !ConfigSettings.deadTTSSpatialAudio.Value || !Object.op_Implicit((Object)(object)_player) || !PlayerPatcher.IsPlayerDead(_player))
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)_player.playerDeathHead))
			{
				Plugin.LogErrorVerbose("Failed to re-create TTS UI component. PlayerDeathHead was not set by the game.");
				return;
			}
			if (string.IsNullOrEmpty(_text))
			{
				Plugin.LogErrorVerbose("Failed to re-create TTS UI component. Passed text value was null or empty.");
				return;
			}
			if (!ConfigSettings.enableWhenDiscovered.Value || (bool)PlayerPatcher.serverSeenField.GetValue(_player.playerDeathHead) || PlayerPatcher.IsLocalPlayerDead() || !SemiFunc.RunIsLevel())
			{
				try
				{
					WorldSpaceUITTS component = Object.Instantiate<GameObject>(__instance.TTSPrefab, ((Component)__instance).transform.position, ((Component)__instance).transform.rotation, ((Component)__instance).transform).GetComponent<WorldSpaceUITTS>();
					if (!Object.op_Implicit((Object)(object)component))
					{
						Plugin.LogError("Failed to create Dead TTS WorldSpaceUITTS component. Invalid prefab?");
						return;
					}
					TextMeshProUGUI val = (TextMeshProUGUI)textField.GetValue(component);
					((TMP_Text)val).text = _text;
					if (!PlayerPatcher.IsLocalPlayerDead())
					{
						string text = ((TMP_Text)val).text;
						string text2 = ConfigSettings.deadTTSColor.Value.Trim(new char[1] { ' ' }).TrimStart(new char[1] { '#' });
						if (text2.Length == 6)
						{
							((TMP_Text)val).richText = true;
							try
							{
								text = "<color=#" + text2 + ">" + ((TMP_Text)val).text + "</color>";
								((TMP_Text)val).text = text;
							}
							catch (Exception ex)
							{
								Plugin.LogError("Failed to apply dead TTS color: " + ConfigSettings.deadTTSColor.Value + "\n" + ex);
							}
						}
					}
					playerAvatarField.SetValue(component, _player);
					Transform transform = ((Component)_player.playerDeathHead).transform;
					followTransformField.SetValue(component, transform);
					worldPositionField.SetValue(component, transform.position);
					followPositionField.SetValue(component, transform.position);
					wordTimeField.SetValue(component, _time);
					PlayerVoiceChat val2 = (PlayerVoiceChat)PlayerPatcher.voiceChatField.GetValue(_player);
					if (Object.op_Implicit((Object)(object)val2))
					{
						ttsVoiceField.SetValue(component, val2.ttsVoice);
					}
					deadTTSElements.Add(component);
					try
					{
						deadTTSElements.RemoveWhere((WorldSpaceUITTS obj) => (Object)(object)obj == (Object)null);
						deadTTSElementsFollowLog.RemoveWhere((WorldSpaceUITTS obj) => (Object)(object)obj == (Object)null);
						return;
					}
					catch
					{
						return;
					}
				}
				catch (Exception ex2)
				{
					Plugin.LogError("Error initializing dead TTS UI:\n" + ex2);
					return;
				}
			}
			try
			{
				Plugin.LogWarningVerbose("Not creating TTS UI Element for dead player. ConfigEnableWhenDiscovered: " + ConfigSettings.enableWhenDiscovered.Value + " | PlayerDiscovered: " + (ConfigSettings.enableWhenDiscovered.Value ? ((bool)PlayerPatcher.serverSeenField.GetValue(_player.playerDeathHead)).ToString() : "N/A") + " | IsLocalPlayerDead: " + PlayerPatcher.IsLocalPlayerDead() + " | RunIsLevel: " + SemiFunc.RunIsLevel());
			}
			catch (Exception ex3)
			{
				Plugin.LogErrorVerbose("Error logging state for OnTTSUI: " + ex3);
			}
		}

		[HarmonyPatch(typeof(WorldSpaceUITTS), "Update")]
		[HarmonyPrefix]
		public static void UpdateUIPositionPrefix(WorldSpaceUITTS __instance)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			if (!deadTTSElements.Contains(__instance))
			{
				return;
			}
			try
			{
				PlayerAvatar val = (PlayerAvatar)playerAvatarField.GetValue(__instance);
				bool value = (bool)PlayerPatcher.isDisabledField.GetValue(val);
				isDisabledStates[val] = value;
				PlayerPatcher.isDisabledField.SetValue(val, false);
				if (!deadTTSElementsFollowLog.Contains(__instance))
				{
					deadTTSElementsFollowLog.Add(__instance);
					TextMeshProUGUI val2 = (TextMeshProUGUI)textField.GetValue(__instance);
					Transform val3 = (Transform)followTransformField.GetValue(__instance);
					TTSVoice val4 = (TTSVoice)ttsVoiceField.GetValue(__instance);
					bool flag = Object.op_Implicit((Object)(object)val4) && (bool)PlayerPatcher.isSpeakingField.GetValue(val4);
					if (!Object.op_Implicit((Object)(object)val4))
					{
						Plugin.LogWarningVerbose("FollowTransform: " + (((Object)(object)val3 != (Object)null) ? ((Object)val3).name : "NONE") + " | TTSVoice.IsSpeaking: " + (((Object)(object)val4 != (Object)null) ? flag.ToString() : "TTSVoice Not Set!"));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.LogError("Error (A) updating dead TTS UI location:\n" + ex);
				deadTTSElements.Remove(__instance);
			}
		}

		[HarmonyPatch(typeof(WorldSpaceUITTS), "Update")]
		[HarmonyPostfix]
		public static void UpdateUIPositionPostfix(WorldSpaceUITTS __instance)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			if (!deadTTSElements.Contains(__instance))
			{
				return;
			}
			try
			{
				PlayerAvatar val = (PlayerAvatar)playerAvatarField.GetValue(__instance);
				if (isDisabledStates.TryGetValue(val, out var value))
				{
					PlayerPatcher.isDisabledField.SetValue(val, value);
				}
			}
			catch (Exception ex)
			{
				Plugin.LogError("Error (B) updating dead TTS UI location:\n" + ex);
				deadTTSElements.Remove(__instance);
			}
		}
	}
	[HarmonyPatch]
	public static class PlayerPatcher
	{
		internal static PlayerAvatar localPlayer;

		internal static FieldInfo voiceChatField = typeof(PlayerAvatar).GetField("voiceChat", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static FieldInfo isDisabledField = typeof(PlayerAvatar).GetField("isDisabled", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static FieldInfo serverSeenField = typeof(PlayerDeathHead).GetField("serverSeen", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static FieldInfo eyeMaterialField = typeof(PlayerDeathHead).GetField("eyeMaterial", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static FieldInfo eyeMaterialAmountField = typeof(PlayerDeathHead).GetField("eyeMaterialAmount", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static FieldInfo eyeFlashLerpField = typeof(PlayerDeathHead).GetField("eyeFlashLerp", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static FieldInfo isSpeakingField = typeof(TTSVoice).GetField("isSpeaking", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static Dictionary<PlayerAvatar, float> deadPlayersVoicePitch = new Dictionary<PlayerAvatar, float>();

		[HarmonyPatch(typeof(PlayerAvatar), "Awake")]
		[HarmonyPostfix]
		public static void InitPlayer(ref bool ___isLocal, PlayerAvatar __instance)
		{
			if (___isLocal)
			{
				localPlayer = __instance;
			}
		}

		[HarmonyPatch(typeof(RoundDirector), "StartRoundLogic")]
		[HarmonyPrefix]
		public static void RandomizeTTSPitch(int value, RoundDirector __instance)
		{
			int num = value;
			deadPlayersVoicePitch.Clear();
			for (int i = 0; i < GameDirector.instance.PlayerList.Count; i++)
			{
				PlayerAvatar val = GameDirector.instance.PlayerList[i];
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				float num2 = 1f;
				if (GameManager.Multiplayer() && value > 0)
				{
					int num3 = -1;
					int seed = -1;
					try
					{
						num3 = val.photonView.Owner.ActorNumber;
					}
					catch (Exception ex)
					{
						Plugin.LogWarning("Failed to get player id for player: " + ((Object)val).name + " when calculating random seed. Don't worry about this.");
						Plugin.LogWarningVerbose("Error: " + ex);
					}
					if (num3 != -1)
					{
						seed = num + num3;
						Random random = new Random(seed);
						float value2 = ConfigSettings.minRandomPitch.Value;
						float value3 = ConfigSettings.maxRandomPitch.Value;
						num2 = (float)(random.NextDouble() * (double)(value3 - value2) + (double)value2);
					}
					if (deadPlayersVoicePitch.TryGetValue(val, out var value4) && num2 != value4)
					{
						Plugin.Log("Setting dead TTS pitch for player with id: " + num3 + " to: " + num2);
					}
					Plugin.LogVerbose("BaseSeed: " + num + " PlayerId: " + num3 + " PlayerSeed: " + seed);
				}
				deadPlayersVoicePitch[val] = num2;
			}
		}

		[HarmonyPatch(typeof(PlayerVoiceChat), "TtsFollowVoiceSettings")]
		[HarmonyPostfix]
		public static void OnTtsFollowVoiceSettings(ref PlayerAvatar ___playerAvatar, ref AudioLowPassLogic ___lowPassLogicTTS, ref bool ___inLobbyMixerTTS, ref float ___clipLoudnessTTS, PlayerVoiceChat __instance)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Expected O, but got Unknown
			if (!GameManager.Multiplayer() || (int)GameDirector.instance.currentState != 2 || !LevelGenerator.Instance.Generated || (!SemiFunc.RunIsLevel() && !SemiFunc.RunIsTutorial() && !SemiFunc.RunIsShop() && !SemiFunc.RunIsArena()) || !Object.op_Implicit((Object)(object)___playerAvatar) || !(IsPlayerDead(___playerAvatar) & ___inLobbyMixerTTS))
			{
				return;
			}
			if (!ConfigSettings.enableWhenDiscovered.Value || !Object.op_Implicit((Object)(object)___playerAvatar.playerDeathHead) || (bool)serverSeenField.GetValue(___playerAvatar.playerDeathHead) || IsLocalPlayerDead() || !SemiFunc.RunIsLevel())
			{
				if (Object.op_Implicit((Object)(object)__instance.ttsAudioSource) && Object.op_Implicit((Object)(object)__instance.mixerTTSSound))
				{
					if ((Object)(object)__instance.ttsAudioSource.outputAudioMixerGroup != (Object)(object)__instance.mixerTTSSound)
					{
						__instance.ttsAudioSource.outputAudioMixerGroup = __instance.mixerTTSSound;
						if (!Object.op_Implicit((Object)(object)___playerAvatar.playerDeathHead))
						{
							Plugin.LogWarning("Game did not assign player a death head.");
						}
						if (!Object.op_Implicit((Object)(object)__instance.ttsVoice))
						{
							Plugin.LogWarning("Game did not assign player a tts voice.");
						}
						else
						{
							Plugin.LogVerbose("The game has toggled ON lobby chat for player: " + ((Object)___playerAvatar).name + ". Disabling TTS lobby mixer.");
							__instance.ttsVoice.setVoice(1);
							__instance.ttsVoice.StopAndClearVoice();
						}
					}
					float pitch = (deadPlayersVoicePitch.ContainsKey(___playerAvatar) ? deadPlayersVoicePitch[___playerAvatar] : 1f);
					__instance.ttsAudioSource.pitch = pitch;
					if ((!ConfigSettings.disableWhileDead.Value || !IsLocalPlayerDead()) && (Object)(object)___playerAvatar != (Object)(object)localPlayer)
					{
						__instance.ttsAudioSource.volume = ConfigSettings.deadTTSVolume.Value;
						if (ConfigSettings.deadTTSSpatialAudio.Value)
						{
							__instance.ttsAudioSource.spatialBlend = 1f;
						}
					}
					else
					{
						__instance.ttsAudioSource.volume = 1f;
					}
				}
				else
				{
					string text = (Object.op_Implicit((Object)(object)__instance.ttsAudioSource) ? "Game did not assign player a ttsAudioSource. " : "");
					text += (Object.op_Implicit((Object)(object)__instance.mixerTTSSound) ? "Game did not assign player a mixerTTSSound." : "");
					if (!string.IsNullOrEmpty(text))
					{
						Plugin.LogErrorVerbose(text.TrimEnd(new char[1] { ' ' }));
					}
				}
			}
			if (Object.op_Implicit((Object)(object)___playerAvatar.playerDeathHead))
			{
				bool flag = (bool)isSpeakingField.GetValue(__instance.ttsVoice);
				Material val = (Material)eyeMaterialField.GetValue(___playerAvatar.playerDeathHead);
				int num = (int)eyeMaterialAmountField.GetValue(___playerAvatar.playerDeathHead);
				if (flag)
				{
					float num2 = (float)eyeFlashLerpField.GetValue(___playerAvatar.playerDeathHead);
					float num3 = Mathf.Clamp01(Mathf.Max(___clipLoudnessTTS, 0f) / 0.2f);
					num2 = Mathf.Lerp(num2, num3, 20f * Time.deltaTime);
					val.SetFloat(num, Mathf.Pow(num2, 0.5f));
					eyeFlashLerpField.SetValue(___playerAvatar.playerDeathHead, num2);
				}
			}
		}

		[HarmonyPatch(typeof(PlayerVoiceChat), "ToggleLobby")]
		[HarmonyPostfix]
		public static void OnToggleOffLobbyChat(bool _toggle, ref PlayerAvatar ___playerAvatar, PlayerVoiceChat __instance)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			if (GameManager.Multiplayer() && (int)GameDirector.instance.currentState == 2 && (SemiFunc.RunIsLevel() || SemiFunc.RunIsTutorial() || SemiFunc.RunIsShop() || SemiFunc.RunIsArena()) && !_toggle)
			{
				Plugin.LogVerbose("The game has toggled OFF lobby chat for player: " + ((Object)___playerAvatar).name);
				if (Object.op_Implicit((Object)(object)__instance.ttsAudioSource) && Object.op_Implicit((Object)(object)__instance.mixerTTSSound))
				{
					__instance.ttsAudioSource.volume = 1f;
					__instance.ttsAudioSource.pitch = 1f;
					__instance.ttsVoice.setVoice(0);
				}
				if (Object.op_Implicit((Object)(object)___playerAvatar.playerDeathHead))
				{
					Material val = (Material)eyeMaterialField.GetValue(___playerAvatar.playerDeathHead);
					int num = (int)eyeMaterialAmountField.GetValue(___playerAvatar.playerDeathHead);
					val.SetFloat(num, 0f);
				}
			}
		}

		[HarmonyPatch(typeof(PlayerVoiceChat), "LateUpdate")]
		[HarmonyPrefix]
		public static void MoveTTSAudioTransform(ref PlayerAvatar ___playerAvatar, ref bool ___inLobbyMixerTTS, PlayerVoiceChat __instance)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			if (LevelGenerator.Instance.Generated && Object.op_Implicit((Object)(object)___playerAvatar) && GameManager.Multiplayer() && (int)GameDirector.instance.currentState == 2 && (SemiFunc.RunIsLevel() || SemiFunc.RunIsTutorial() || SemiFunc.RunIsShop() || SemiFunc.RunIsArena()) && ___inLobbyMixerTTS && IsPlayerDead(___playerAvatar) && Object.op_Implicit((Object)(object)___playerAvatar.playerDeathHead) && Object.op_Implicit((Object)(object)__instance.ttsVoice))
			{
				((Component)__instance).transform.position = Vector3.Lerp(((Component)__instance).transform.position, ((Component)___playerAvatar.playerDeathHead).transform.position, 30f * Time.deltaTime);
			}
		}

		[HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathDone")]
		[HarmonyPrefix]
		public static void TryFixMissingPlayerDeathHead(ref bool ___isDisabled, ref string ___playerName, PlayerAvatar __instance)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Invalid comparison between Unknown and I4
			if (___isDisabled || Object.op_Implicit((Object)(object)__instance.playerDeathHead) || !ConfigSettings.fixMissingDeathHeads.Value)
			{
				return;
			}
			bool flag = (int)GameDirector.instance.currentState == 2 && (SemiFunc.RunIsLevel() || SemiFunc.RunIsTutorial() || SemiFunc.RunIsShop() || SemiFunc.RunIsArena());
			if (flag)
			{
				Plugin.LogWarning("[PlayerDeathDone] Player: " + ___playerName + " was not assigned a player death head by the game. Attempting to find and re-assign new head.");
			}
			PlayerDeathHead val = null;
			PlayerDeathHead[] array = Object.FindObjectsOfType<PlayerDeathHead>();
			foreach (PlayerDeathHead val2 in array)
			{
				PlayerAvatar val3 = val2?.playerAvatar;
				if (!Object.op_Implicit((Object)(object)val3) || (Object)(object)val3.playerDeathHead != (Object)(object)val2)
				{
					val = val2;
					break;
				}
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				PlayerAvatar val4 = val?.playerAvatar;
				if (flag)
				{
					Plugin.LogWarning("(" + ((!Object.op_Implicit((Object)(object)val4)) ? "A" : "B") + ") Found unassigned player death head and assigned to dead player: " + ___playerName);
				}
				__instance.playerDeathHead = val;
				val.playerAvatar = __instance;
			}
			else if (flag)
			{
				Plugin.LogError("Could not find replacement player death head. Dead TTS may not work properly for player: " + ___playerName);
			}
		}

		public static bool IsLocalPlayerDead()
		{
			return IsPlayerDead(PlayerAvatar.instance);
		}

		public static bool IsPlayerDead(PlayerAvatar playerAvatar)
		{
			return Object.op_Implicit((Object)(object)playerAvatar) && (bool)isDisabledField.GetValue(playerAvatar) && (!Object.op_Implicit((Object)(object)playerAvatar.playerDeathHead) || ((Behaviour)playerAvatar.playerDeathHead).isActiveAndEnabled);
		}
	}
}
namespace REPO_DeadTTS.Config
{
	[Serializable]
	public static class ConfigSettings
	{
		public static ConfigEntry<float> minRandomPitch;

		public static ConfigEntry<float> maxRandomPitch;

		public static ConfigEntry<float> deadTTSVolume;

		public static ConfigEntry<bool> displayDeadTTSText;

		public static ConfigEntry<bool> deadTTSSpatialAudio;

		public static ConfigEntry<bool> enableWhenDiscovered;

		public static ConfigEntry<bool> disableWhileDead;

		public static ConfigEntry<string> deadTTSColor;

		public static ConfigEntry<bool> fixMissingDeathHeads;

		public static ConfigEntry<bool> verboseLogs;

		public static Dictionary<string, ConfigEntryBase> currentConfigEntries = new Dictionary<string, ConfigEntryBase>();

		internal static void BindConfigSettings()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Expected O, but got Unknown
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Expected O, but got Unknown
			Plugin.Log("Binding Configs");
			minRandomPitch = AddConfigEntry<float>(((BaseUnityPlugin)Plugin.instance).Config.Bind<float>("General", "Dead TTS Random Pitch Min", 0.8f, new ConfigDescription("The lower range limit when randomizing dead players pitch.\nValues will be clamped between 0.8 and 2.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.8f, 2f), Array.Empty<object>())));
			maxRandomPitch = AddConfigEntry<float>(((BaseUnityPlugin)Plugin.instance).Config.Bind<float>("General", "Dead TTS Random Pitch Max", 1.5f, new ConfigDescription("The upper range limit when randomizing dead players pitch.\nValues will be clamped between 0.8 and 2.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.8f, 2f), Array.Empty<object>())));
			deadTTSVolume = AddConfigEntry<float>(((BaseUnityPlugin)Plugin.instance).Config.Bind<float>("General", "Dead TTS Volume", 0.5f, new ConfigDescription("Affects the TTS volume of all dead players.\nSet to 0 to mute the TTS of dead players. If muted, the TTS text will still appear.\nValues will be clamped between 0.0 and 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())));
			displayDeadTTSText = AddConfigEntry<bool>(((BaseUnityPlugin)Plugin.instance).Config.Bind<bool>("General", "Display Dead TTS Text", true, "If true, TTS Text will appear from dead players' heads."));
			deadTTSSpatialAudio = AddConfigEntry<bool>(((BaseUnityPlugin)Plugin.instance).Config.Bind<bool>("General", "Use Spatial Audio", true, "If true, TTS audio from dead players should be 3D directional.\nIf false, the audio should appear as if it's in your head all the time."));
			enableWhenDiscovered = AddConfigEntry<bool>(((BaseUnityPlugin)Plugin.instance).Config.Bind<bool>("General", "Enable When Discovered", false, "If true, you will only hear DeadTTS from players once their head is \"discovered\"."));
			disableWhileDead = AddConfigEntry<bool>(((BaseUnityPlugin)Plugin.instance).Config.Bind<bool>("General", "Disable While Dead", false, "Dead TTS will be disabled while you are dead."));
			deadTTSColor = AddConfigEntry<string>(((BaseUnityPlugin)Plugin.instance).Config.Bind<string>("General", "Dead TTS Text Color Hex", "CC3333", new ConfigDescription("Hex color value for dead TTS text color. Hex string must be 6 characters long. Leave this field blank to use the vanilla TTS color.", (AcceptableValueBase)null, Array.Empty<object>())));
			fixMissingDeathHeads = AddConfigEntry<bool>(((BaseUnityPlugin)Plugin.instance).Config.Bind<bool>("General", "Fix Missing Death Heads", true, new ConfigDescription("Fixes an uncommon bug where the game may not assign a player a death head.", (AcceptableValueBase)null, Array.Empty<object>())));
			verboseLogs = AddConfigEntry<bool>(((BaseUnityPlugin)Plugin.instance).Config.Bind<bool>("General", "Verbose Logs", false, new ConfigDescription("Enables verbose logs. Useful for debugging.", (AcceptableValueBase)null, Array.Empty<object>())));
			if (minRandomPitch.Value < 0.8f)
			{
				minRandomPitch.Value = (float)((ConfigEntryBase)minRandomPitch).DefaultValue;
			}
			if (maxRandomPitch.Value > 2f)
			{
				maxRandomPitch.Value = (float)((ConfigEntryBase)maxRandomPitch).DefaultValue;
			}
			minRandomPitch.Value = Mathf.Clamp(minRandomPitch.Value, 0.8f, 2f);
			maxRandomPitch.Value = Mathf.Max(maxRandomPitch.Value, minRandomPitch.Value);
			deadTTSVolume.Value = Mathf.Clamp(deadTTSVolume.Value, 0f, 2f);
			deadTTSColor.Value = deadTTSColor.Value.Trim(new char[1] { ' ' });
		}

		internal static ConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry)
		{
			currentConfigEntries.Add(((ConfigEntryBase)configEntry).Definition.Key, (ConfigEntryBase)(object)configEntry);
			return configEntry;
		}
	}
}