Decompiled source of LoudVoiceBoom v1.0.0

Zichen-LoudVoiceBoom.dll

Decompiled 9 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Zichen-LoudVoiceBoom")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Zichen-LoudVoiceBoom")]
[assembly: AssemblyTitle("Zichen-LoudVoiceBoom")]
[assembly: AssemblyVersion("1.0.0.0")]
[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;
		}
	}
}
[BepInPlugin("zichen.loudvoiceboom", "A.Loud Voice Boom", "1.0.0")]
public sealed class LoudVoiceBoomPlugin : BaseUnityPlugin
{
	private sealed class VoiceState
	{
		public string PlayerName = "Player";

		public PlayerAvatar PlayerAvatar;

		public bool IsLocal;

		public float ExplosionEnergy;

		public float Loudness;

		public float LoudnessProgress;

		public float DurationProgress;

		public float Cooldown;

		public float LastSeenTime;
	}

	[CompilerGenerated]
	private sealed class <ArmGrenadeNextFrame>d__91 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public GameObject grenade;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <ArmGrenadeNextFrame>d__91(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
			{
				<>1__state = -1;
				if ((Object)(object)grenade == (Object)null)
				{
					return false;
				}
				ItemToggle component = grenade.GetComponent<ItemToggle>();
				if ((Object)(object)component != (Object)null)
				{
					component.ToggleItem(true, -1);
				}
				return false;
			}
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <TriggerExplosion>d__88 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public PlayerAvatar explosionTarget;

		public LoudVoiceBoomPlugin <>4__this;

		public PlayerAvatar speakerAvatar;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <TriggerExplosion>d__88(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			int num = <>1__state;
			LoudVoiceBoomPlugin loudVoiceBoomPlugin = <>4__this;
			switch (num)
			{
			default:
				return false;
			case 0:
			{
				<>1__state = -1;
				if ((Object)(object)explosionTarget == (Object)null)
				{
					return false;
				}
				Vector3 explosionPosition = GetExplosionPosition(explosionTarget);
				loudVoiceBoomPlugin.SpawnGrenadeExplosion(speakerAvatar ?? explosionTarget, explosionPosition);
				<>2__current = (object)new WaitForSeconds(0.15f);
				<>1__state = 1;
				return true;
			}
			case 1:
				<>1__state = -1;
				if ((Object)(object)explosionTarget != (Object)null && (Object)(object)explosionTarget.playerHealth != (Object)null && !IsPlayerDeadSet(explosionTarget))
				{
					explosionTarget.playerHealth.HurtOther(100, Vector3.zero, false, -1, false);
				}
				return false;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	public const string PluginGuid = "zichen.loudvoiceboom";

	public const string PluginName = "A.Loud Voice Boom";

	public const string PluginVersion = "1.0.0";

	private const string InfoSection = "模组信息";

	private const string MainSection = "A.大声说话就爆炸";

	private const float DefaultSoftVoiceGain = 0.08f;

	private const float DefaultLoudVoiceFillSeconds = 0.25f;

	private const float DefaultEnergyDecayPerSecond = 0.22f;

	private const int DefaultExplosionTriggerThreshold = 10;

	private const float LoudnessThresholdScale = 0.1f;

	private const int DefaultExplosionDamage = 100;

	private const float SilenceLoudness = 0.002f;

	private const string TargetSelf = "自己爆炸";

	private const string TargetNearest = "最近玩家爆炸";

	private const string TargetRandom = "随机玩家爆炸";

	private const string ModuleNameChinese = "大声说话就爆炸";

	private const string ModuleNameEnglish = "Loud Voice Boom";

	private const string SyncPropertyKey = "zichen.loudvoiceboom.sync";

	private const float SyncIntervalSeconds = 0.1f;

	private const int SyncFreshMilliseconds = 1500;

	private static readonly Color LoudnessBarColor = new Color(1f, 0.72f, 0.15f, 0.95f);

	private static readonly Color EnergyBarColor = new Color(1f, 0.18f, 0.12f, 0.95f);

	private static readonly Color BarBackgroundColor = new Color(0.04f, 0.04f, 0.04f, 0.32f);

	private static readonly Color BarBorderColor = new Color(1f, 1f, 1f, 0.48f);

	private static readonly Color BarHighlightColor = new Color(1f, 1f, 1f, 0.18f);

	private static readonly FieldInfo ClipLoudnessNoTtsField = typeof(PlayerVoiceChat).GetField("clipLoudnessNoTTS", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo PlayerAvatarField = typeof(PlayerVoiceChat).GetField("playerAvatar", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo PlayerNameField = typeof(PlayerAvatar).GetField("playerName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo PlayerWorldSpaceUIPlayerNameField = typeof(PlayerAvatar).GetField("worldSpaceUIPlayerName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo PlayerAvatarIsDisabledField = typeof(PlayerAvatar).GetField("isDisabled", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo PlayerAvatarDeadSetField = typeof(PlayerAvatar).GetField("deadSet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo GameDirectorCurrentStateField = typeof(GameDirector).GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo RunManagerLevelIsShopField = typeof(RunManager).GetField("levelIsShop", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private readonly Dictionary<int, VoiceState> voiceStates = new Dictionary<int, VoiceState>();

	private readonly List<int> hudOrderBottomToTop = new List<int>();

	private readonly List<int> remoteHudKeys = new List<int>();

	private int hudPlayerListSignature;

	private bool gameplayActivePrevious;

	private bool gameplayActiveCurrent;

	private float syncTimer;

	private int syncedServerTimestamp;

	private GUIStyle hudLabelStyle;

	private Harmony harmony;

	private ConfigEntry<string> moduleNameInfo;

	private ConfigEntry<string> moduleVersionInfo;

	private ConfigEntry<string> contactInfo;

	private ConfigEntry<bool> featureEnabled;

	private ConfigEntry<int> explosionTriggerThreshold;

	private ConfigEntry<int> loudnessThreshold;

	private ConfigEntry<int> explosionCooldownSeconds;

	private ConfigEntry<string> explosionTargetMode;

	private ConfigEntry<bool> showProgressHud;

	public static LoudVoiceBoomPlugin Instance { get; private set; }

	private void Awake()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Expected O, but got Unknown
		Instance = this;
		BindConfig();
		harmony = new Harmony("zichen.loudvoiceboom.patch");
		harmony.Patch((MethodBase)AccessTools.Method(typeof(PlayerVoiceChat), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(LoudVoiceBoomPlugin), "PlayerVoiceChatUpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"zichen-loud-voice-boom loaded.");
	}

	private void OnDestroy()
	{
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
		harmony = null;
		voiceStates.Clear();
		if (Instance == this)
		{
			Instance = null;
		}
	}

	private void BindConfig()
	{
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Expected O, but got Unknown
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Expected O, but got Unknown
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Expected O, but got Unknown
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f6: Expected O, but got Unknown
		//IL_0264: Unknown result type (might be due to invalid IL or missing references)
		//IL_026e: Expected O, but got Unknown
		//IL_02af: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b9: Expected O, but got Unknown
		//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0305: Expected O, but got Unknown
		moduleNameInfo = ((BaseUnityPlugin)this).Config.Bind<string>("模组信息", "模组名称", "大声说话就爆炸", new ConfigDescription("当前模组的名称。此处仅用于显示,不影响功能。", (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				Order = 1000,
				CustomDrawer = DrawInfo,
				ReadOnly = true
			}
		}));
		moduleNameInfo.Value = "大声说话就爆炸";
		moduleVersionInfo = ((BaseUnityPlugin)this).Config.Bind<string>("模组信息", "模组版本号", "1.0.0", new ConfigDescription("当前模组版本号。此处仅用于显示,不影响功能。", (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				Order = 990,
				CustomDrawer = DrawInfo,
				ReadOnly = true
			}
		}));
		moduleVersionInfo.Value = "1.0.0";
		contactInfo = ((BaseUnityPlugin)this).Config.Bind<string>("模组信息", "REPO交流QQ群", "824639225", new ConfigDescription("REPO 游戏交流、BUG 反馈、优化建议、功能请求请加 QQ 群。此处仅用于显示,不影响功能。", (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				Order = 980,
				CustomDrawer = DrawInfo,
				ReadOnly = true
			}
		}));
		contactInfo.Value = "824639225";
		featureEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("A.大声说话就爆炸", "启用", true, ConfigDescriptionWithOrder("只需要主机安装即可生效。玩家语音过大时会在自己位置爆炸。", 900));
		explosionTargetMode = ((BaseUnityPlugin)this).Config.Bind<string>("A.大声说话就爆炸", "爆炸目标", "自己爆炸", new ConfigDescription("谁来承受爆炸。选择最近或随机时,只会从其他存活玩家中选。没有其他存活玩家时回退为自己爆炸。", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "自己爆炸", "最近玩家爆炸", "随机玩家爆炸" }), new object[1]
		{
			new ConfigurationManagerAttributes
			{
				Order = 895
			}
		}));
		showProgressHud = ((BaseUnityPlugin)this).Config.Bind<bool>("A.大声说话就爆炸", "左下角显示进度条", true, ConfigDescriptionWithOrder("开启后,屏幕左下角会显示每个玩家的语音响度和爆炸能量进度。", 890));
		explosionTriggerThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("A.大声说话就爆炸", "爆炸触发阈值", 10, new ConfigDescription("说话能量达到这个阈值时触发爆炸。单位为 1,值越高需要说话更久才会爆炸。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30), new object[1]
		{
			new ConfigurationManagerAttributes
			{
				Order = 885
			}
		}));
		loudnessThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("A.大声说话就爆炸", "爆炸加速响度", 2, new ConfigDescription("调整多大的声音会被当成大声说话。数字越小越灵敏,更容易爆炸;数字越大越不容易爆炸。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), new object[1]
		{
			new ConfigurationManagerAttributes
			{
				Order = 880
			}
		}));
		explosionCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("A.大声说话就爆炸", "爆炸后暂停秒数", 1, new ConfigDescription("爆炸后先停止计算几秒。这段时间内继续说话也不会立刻再次爆炸。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 30), new object[1]
		{
			new ConfigurationManagerAttributes
			{
				Order = 870
			}
		}));
	}

	private void DrawInfo(ConfigEntryBase entry)
	{
		GUILayout.Label(entry.BoxedValue?.ToString() ?? string.Empty, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(260f) });
	}

	private static ConfigDescription ConfigDescriptionWithOrder(string description, int order)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Expected O, but got Unknown
		return new ConfigDescription(description, (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				Order = order
			}
		});
	}

	private static void PlayerVoiceChatUpdatePostfix(PlayerVoiceChat __instance)
	{
		Instance?.CheckVoice(__instance);
	}

	private void Update()
	{
		gameplayActiveCurrent = ShouldRunGameplay();
		if (gameplayActivePrevious && !gameplayActiveCurrent)
		{
			ResetVoiceEnergies();
		}
		gameplayActivePrevious = gameplayActiveCurrent;
		if (!gameplayActiveCurrent)
		{
			return;
		}
		if (IsHostAuthority())
		{
			syncTimer -= Time.deltaTime;
			if (syncTimer <= 0f)
			{
				syncTimer = 0.1f;
				PublishVoiceStateSync();
			}
		}
		else
		{
			ReadVoiceStateSync();
		}
	}

	private void CheckVoice(PlayerVoiceChat voiceChat)
	{
		if ((Object)(object)voiceChat == (Object)null || !gameplayActiveCurrent || !IsHostAuthority())
		{
			return;
		}
		PlayerAvatar fieldValue = GetFieldValue<PlayerAvatar>(PlayerAvatarField, voiceChat, null);
		if ((Object)(object)fieldValue == (Object)null || (Object)(object)fieldValue.playerHealth == (Object)null || IsPlayerDisabled(fieldValue) || IsPlayerDeadSet(fieldValue))
		{
			return;
		}
		int playerKey = GetPlayerKey(fieldValue);
		if (!voiceStates.TryGetValue(playerKey, out var value))
		{
			value = new VoiceState();
			voiceStates[playerKey] = value;
		}
		value.PlayerName = GetPlayerName(fieldValue);
		value.PlayerAvatar = fieldValue;
		value.IsLocal = IsLocalPlayer(fieldValue);
		value.LastSeenTime = Time.time;
		if (IsPlayerDisabled(fieldValue) || IsPlayerDeadSet(fieldValue))
		{
			ClearVoiceStateProgress(value);
			return;
		}
		if (value.Cooldown > 0f)
		{
			value.Cooldown -= Time.deltaTime;
			value.LoudnessProgress = 0f;
			value.DurationProgress = 0f;
			return;
		}
		float num = (value.Loudness = GetFieldValue(ClipLoudnessNoTtsField, voiceChat, 0f));
		value.LoudnessProgress = Mathf.Clamp01(num / GetEffectiveLoudnessThreshold());
		UpdateExplosionEnergy(value, num);
		if (!(value.Cooldown > 0f) && !(value.ExplosionEnergy < GetExplosionTriggerThreshold()))
		{
			value.ExplosionEnergy = 0f;
			value.Cooldown = Mathf.Max(0f, (float)explosionCooldownSeconds.Value);
			((MonoBehaviour)this).StartCoroutine(TriggerExplosion(fieldValue, ResolveExplosionTarget(fieldValue)));
		}
	}

	private PlayerAvatar ResolveExplosionTarget(PlayerAvatar speaker)
	{
		if ((Object)(object)speaker == (Object)null)
		{
			return null;
		}
		string a = ((explosionTargetMode == null) ? "自己爆炸" : explosionTargetMode.Value);
		if (string.Equals(a, "最近玩家爆炸", StringComparison.Ordinal))
		{
			PlayerAvatar nearestAliveOtherPlayer = GetNearestAliveOtherPlayer(speaker);
			if (!((Object)(object)nearestAliveOtherPlayer != (Object)null))
			{
				return speaker;
			}
			return nearestAliveOtherPlayer;
		}
		if (string.Equals(a, "随机玩家爆炸", StringComparison.Ordinal))
		{
			PlayerAvatar randomAliveOtherPlayer = GetRandomAliveOtherPlayer(speaker);
			if (!((Object)(object)randomAliveOtherPlayer != (Object)null))
			{
				return speaker;
			}
			return randomAliveOtherPlayer;
		}
		return speaker;
	}

	private static PlayerAvatar GetNearestAliveOtherPlayer(PlayerAvatar speaker)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)GameDirector.instance == (Object)null || GameDirector.instance.PlayerList == null)
		{
			return null;
		}
		PlayerAvatar result = null;
		float num = float.MaxValue;
		Vector3 position = ((Component)speaker).transform.position;
		foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
		{
			if (IsAliveOtherPlayer(player, speaker))
			{
				Vector3 val = ((Component)player).transform.position - position;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (sqrMagnitude < num)
				{
					num = sqrMagnitude;
					result = player;
				}
			}
		}
		return result;
	}

	private static PlayerAvatar GetRandomAliveOtherPlayer(PlayerAvatar speaker)
	{
		if ((Object)(object)GameDirector.instance == (Object)null || GameDirector.instance.PlayerList == null)
		{
			return null;
		}
		PlayerAvatar result = null;
		int num = 0;
		foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
		{
			if (IsAliveOtherPlayer(player, speaker))
			{
				num++;
				if (Random.Range(0, num) == 0)
				{
					result = player;
				}
			}
		}
		return result;
	}

	private static bool IsAliveOtherPlayer(PlayerAvatar player, PlayerAvatar speaker)
	{
		if ((Object)(object)player != (Object)null && (Object)(object)player != (Object)(object)speaker && (Object)(object)player.playerHealth != (Object)null && !IsPlayerDisabled(player))
		{
			return !IsPlayerDeadSet(player);
		}
		return false;
	}

	private void PublishVoiceStateSync()
	{
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Expected O, but got Unknown
		//IL_011f: Expected O, but got Unknown
		if (PhotonNetwork.CurrentRoom == null)
		{
			return;
		}
		RefreshHudOrderIfNeeded();
		string text = PhotonNetwork.ServerTimestamp.ToString();
		foreach (int item in hudOrderBottomToTop)
		{
			if (voiceStates.TryGetValue(item, out var value))
			{
				if ((Object)(object)value.PlayerAvatar != (Object)null && (IsPlayerDisabled(value.PlayerAvatar) || IsPlayerDeadSet(value.PlayerAvatar)))
				{
					ClearVoiceStateProgress(value);
				}
				text = text + ";" + item + "," + Mathf.RoundToInt(value.LoudnessProgress * 1000f) + "," + Mathf.RoundToInt(value.DurationProgress * 1000f);
			}
		}
		Room currentRoom = PhotonNetwork.CurrentRoom;
		Hashtable val = new Hashtable();
		((Dictionary<object, object>)val).Add((object)"zichen.loudvoiceboom.sync", (object)text);
		currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
	}

	private void ReadVoiceStateSync()
	{
		if (PhotonNetwork.CurrentRoom == null || !((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"zichen.loudvoiceboom.sync", out object value) || !(value is string text))
		{
			syncedServerTimestamp = 0;
			return;
		}
		string[] array = text.Split(new char[1] { ';' });
		if (array.Length == 0 || !int.TryParse(array[0], out syncedServerTimestamp))
		{
			syncedServerTimestamp = 0;
			return;
		}
		RefreshHudOrderIfNeeded();
		for (int i = 1; i < array.Length; i++)
		{
			string[] array2 = array[i].Split(new char[1] { ',' });
			if (array2.Length >= 3 && int.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2) && int.TryParse(array2[2], out var result3))
			{
				if (!voiceStates.TryGetValue(result, out var value2))
				{
					value2 = new VoiceState();
					voiceStates[result] = value2;
				}
				value2.LoudnessProgress = Mathf.Clamp01((float)result2 * 0.001f);
				value2.DurationProgress = Mathf.Clamp01((float)result3 * 0.001f);
				value2.ExplosionEnergy = value2.DurationProgress;
				value2.LastSeenTime = Time.time;
			}
		}
	}

	private bool HasFreshVoiceStateSync()
	{
		if (syncedServerTimestamp == 0)
		{
			return false;
		}
		int num = PhotonNetwork.ServerTimestamp - syncedServerTimestamp;
		if (num >= 0)
		{
			return num <= 1500;
		}
		return false;
	}

	private void UpdateExplosionEnergy(VoiceState state, float loudness)
	{
		float effectiveLoudnessThreshold = GetEffectiveLoudnessThreshold();
		float num = GetExplosionTriggerThreshold();
		float num2 = Mathf.Clamp01(loudness / effectiveLoudnessThreshold);
		float num3 = Mathf.Lerp(0.08f, 1f, num2 * num2) / 0.25f;
		if (loudness <= 0.002f)
		{
			num3 = 0f;
		}
		state.ExplosionEnergy += num3 * 10f * Time.deltaTime;
		if (num2 < 0.05f)
		{
			state.ExplosionEnergy -= 2.2f * Time.deltaTime;
		}
		state.ExplosionEnergy = Mathf.Clamp(state.ExplosionEnergy, 0f, num);
		state.DurationProgress = Mathf.Clamp01(state.ExplosionEnergy / num);
	}

	private float GetExplosionTriggerThreshold()
	{
		return Mathf.Clamp((float)((explosionTriggerThreshold == null) ? 10 : explosionTriggerThreshold.Value), 1f, 30f);
	}

	private float GetEffectiveLoudnessThreshold()
	{
		float num = Mathf.Clamp((float)((loudnessThreshold == null) ? 2 : loudnessThreshold.Value), 1f, 5f);
		return Mathf.Max(0.001f, num * 0.1f);
	}

	private void OnGUI()
	{
		if (showProgressHud == null || !showProgressHud.Value || !gameplayActiveCurrent || (!IsHostAuthority() && !HasFreshVoiceStateSync()))
		{
			return;
		}
		float width = 174f;
		float x = 24f;
		float num = (float)Screen.height - 246f;
		RefreshHudOrderIfNeeded();
		for (int i = 0; i < hudOrderBottomToTop.Count; i++)
		{
			int key = hudOrderBottomToTop[i];
			if (voiceStates.TryGetValue(key, out var value))
			{
				if ((Object)(object)value.PlayerAvatar != (Object)null && (IsPlayerDisabled(value.PlayerAvatar) || IsPlayerDeadSet(value.PlayerAvatar)))
				{
					ClearVoiceStateProgress(value);
				}
				DrawPlayerProgress(x, num - (float)i * 64f, width, value);
			}
		}
	}

	private void RefreshHudOrderIfNeeded()
	{
		int playerListSignature = GetPlayerListSignature();
		if (playerListSignature == hudPlayerListSignature)
		{
			return;
		}
		hudPlayerListSignature = playerListSignature;
		hudOrderBottomToTop.Clear();
		remoteHudKeys.Clear();
		int num = 0;
		if ((Object)(object)GameDirector.instance != (Object)null && GameDirector.instance.PlayerList != null)
		{
			foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
			{
				if (!((Object)(object)player == (Object)null))
				{
					int playerKey = GetPlayerKey(player);
					if (IsLocalPlayer(player))
					{
						num = playerKey;
					}
					else
					{
						remoteHudKeys.Add(playerKey);
					}
					if (!voiceStates.TryGetValue(playerKey, out var value))
					{
						value = new VoiceState();
						voiceStates[playerKey] = value;
					}
					value.PlayerName = GetPlayerName(player);
					value.PlayerAvatar = player;
					value.IsLocal = IsLocalPlayer(player);
					value.LastSeenTime = Time.time;
				}
			}
		}
		if (num != 0)
		{
			hudOrderBottomToTop.Add(num);
		}
		foreach (int remoteHudKey in remoteHudKeys)
		{
			hudOrderBottomToTop.Add(remoteHudKey);
		}
	}

	private static int GetPlayerListSignature()
	{
		if ((Object)(object)GameDirector.instance == (Object)null || GameDirector.instance.PlayerList == null)
		{
			return 0;
		}
		int num = 17;
		foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
		{
			if (!((Object)(object)player == (Object)null))
			{
				num = num * 31 + GetPlayerKey(player);
				num = num * 31 + (IsLocalPlayer(player) ? 1 : 0);
			}
		}
		return num;
	}

	private void DrawPlayerProgress(float x, float y, float width, VoiceState state)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: 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_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Expected O, but got Unknown
		if (hudLabelStyle == null)
		{
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 16
			};
			val.normal.textColor = Color.white;
			hudLabelStyle = val;
		}
		GUI.Label(new Rect(x, y, width, 22f), state.PlayerName, hudLabelStyle);
		DrawBar(new Rect(x, y + 27f, width, 15f), state.LoudnessProgress, LoudnessBarColor);
		DrawBar(new Rect(x, y + 48f, width, 15f), state.DurationProgress, EnergyBarColor);
	}

	private static void DrawBar(Rect rect, float progress, Color fillColor)
	{
		//IL_0000: 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_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		Color color = GUI.color;
		DrawRoundedBar(rect, BarBackgroundColor);
		GUI.color = fillColor;
		float num = ((Rect)(ref rect)).width * Mathf.Clamp01(progress);
		if (num > 0f)
		{
			DrawRoundedBar(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, num, ((Rect)(ref rect)).height), fillColor);
			GUI.color = BarHighlightColor;
			DrawRoundedBar(new Rect(((Rect)(ref rect)).x + 2f, ((Rect)(ref rect)).y + 2f, Mathf.Max(0f, num - 4f), ((Rect)(ref rect)).height * 0.32f), BarHighlightColor);
		}
		DrawRoundedBorder(rect);
		GUI.color = color;
	}

	private static void DrawRoundedBar(Rect rect, Color color)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		if (!(((Rect)(ref rect)).width <= 0f) && !(((Rect)(ref rect)).height <= 0f))
		{
			float num = ((Rect)(ref rect)).height * 0.5f;
			GUI.color = color;
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + num, ((Rect)(ref rect)).y, Mathf.Max(0f, ((Rect)(ref rect)).width - ((Rect)(ref rect)).height), ((Rect)(ref rect)).height), (Texture)(object)Texture2D.whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y + num * 0.5f, ((Rect)(ref rect)).width, num), (Texture)(object)Texture2D.whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + num * 0.5f, ((Rect)(ref rect)).y + num * 0.2f, Mathf.Max(0f, ((Rect)(ref rect)).width - num), ((Rect)(ref rect)).height * 0.6f), (Texture)(object)Texture2D.whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + num * 0.2f, ((Rect)(ref rect)).y + num * 0.35f, Mathf.Max(0f, ((Rect)(ref rect)).width - num * 0.4f), ((Rect)(ref rect)).height * 0.3f), (Texture)(object)Texture2D.whiteTexture);
		}
	}

	private static void DrawRoundedBorder(Rect rect)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01da: Unknown result type (might be due to invalid IL or missing references)
		//IL_020d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0273: Unknown result type (might be due to invalid IL or missing references)
		GUI.color = BarBorderColor;
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + 7f, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width - 14f, 1f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + 7f, ((Rect)(ref rect)).yMax - 1f, ((Rect)(ref rect)).width - 14f, 1f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y + 7f, 1f, ((Rect)(ref rect)).height - 14f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).xMax - 1f, ((Rect)(ref rect)).y + 7f, 1f, ((Rect)(ref rect)).height - 14f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + 3f, ((Rect)(ref rect)).y + 3f, 5f, 1f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + 1f, ((Rect)(ref rect)).y + 5f, 1f, 5f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).xMax - 8f, ((Rect)(ref rect)).y + 3f, 5f, 1f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).xMax - 2f, ((Rect)(ref rect)).y + 5f, 1f, 5f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + 3f, ((Rect)(ref rect)).yMax - 4f, 5f, 1f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + 1f, ((Rect)(ref rect)).yMax - 10f, 1f, 5f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).xMax - 8f, ((Rect)(ref rect)).yMax - 4f, 5f, 1f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).xMax - 2f, ((Rect)(ref rect)).yMax - 10f, 1f, 5f), (Texture)(object)Texture2D.whiteTexture);
	}

	private bool ShouldRunGameplay()
	{
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Invalid comparison between Unknown and I4
		if (featureEnabled == null || !featureEnabled.Value || !SemiFunc.IsMultiplayer())
		{
			return false;
		}
		if (!SemiFunc.RunIsLevel() || SemiFunc.RunIsShop() || SemiFunc.RunIsArena())
		{
			return false;
		}
		if ((Object)(object)RunManager.instance != (Object)null && GetFieldValue(RunManagerLevelIsShopField, RunManager.instance, fallback: false))
		{
			return false;
		}
		if ((Object)(object)GameDirector.instance == (Object)null)
		{
			return false;
		}
		if (GameDirectorCurrentStateField?.GetValue(GameDirector.instance) is gameState val)
		{
			return (int)val == 2;
		}
		return false;
	}

	private void ResetVoiceEnergies()
	{
		foreach (VoiceState value in voiceStates.Values)
		{
			ClearVoiceStateProgress(value);
			value.Cooldown = 0f;
		}
	}

	private static void ClearVoiceStateProgress(VoiceState state)
	{
		state.ExplosionEnergy = 0f;
		state.Loudness = 0f;
		state.LoudnessProgress = 0f;
		state.DurationProgress = 0f;
	}

	private static string GetPlayerName(PlayerAvatar playerAvatar)
	{
		if ((Object)(object)playerAvatar == (Object)null)
		{
			return "Player";
		}
		if (PlayerNameField?.GetValue(playerAvatar) is string text && !string.IsNullOrWhiteSpace(text))
		{
			return text.Trim();
		}
		string worldSpacePlayerNameText = GetWorldSpacePlayerNameText(PlayerWorldSpaceUIPlayerNameField?.GetValue(playerAvatar));
		if (!string.IsNullOrWhiteSpace(worldSpacePlayerNameText))
		{
			return worldSpacePlayerNameText.Trim();
		}
		try
		{
			string text2 = SemiFunc.PlayerGetName(playerAvatar);
			if (!string.IsNullOrEmpty(text2))
			{
				return text2;
			}
		}
		catch
		{
		}
		if (!string.IsNullOrWhiteSpace(((Object)playerAvatar).name))
		{
			return ((Object)playerAvatar).name.Replace("(Clone)", string.Empty).Trim();
		}
		return "Player";
	}

	private static string GetWorldSpacePlayerNameText(object worldSpaceName)
	{
		if (worldSpaceName == null)
		{
			return null;
		}
		try
		{
			object obj = worldSpaceName.GetType().GetField("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(worldSpaceName);
			if (obj == null)
			{
				return null;
			}
			if (obj.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj, null) is string text && !string.IsNullOrWhiteSpace(text))
			{
				return text;
			}
			return obj.GetType().GetField("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj) as string;
		}
		catch
		{
			return null;
		}
	}

	private static int GetPlayerKey(PlayerAvatar playerAvatar)
	{
		if ((Object)(object)playerAvatar == (Object)null)
		{
			return 0;
		}
		if ((Object)(object)playerAvatar.photonView != (Object)null && playerAvatar.photonView.ViewID != 0)
		{
			return playerAvatar.photonView.ViewID;
		}
		return ((Object)playerAvatar).GetInstanceID();
	}

	private static bool IsLocalPlayer(PlayerAvatar playerAvatar)
	{
		if ((Object)(object)playerAvatar == (Object)null)
		{
			return false;
		}
		if ((Object)(object)playerAvatar.photonView != (Object)null)
		{
			return playerAvatar.photonView.IsMine;
		}
		return (Object)(object)PlayerAvatar.instance == (Object)(object)playerAvatar;
	}

	[IteratorStateMachine(typeof(<TriggerExplosion>d__88))]
	private IEnumerator TriggerExplosion(PlayerAvatar speakerAvatar, PlayerAvatar explosionTarget)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <TriggerExplosion>d__88(0)
		{
			<>4__this = this,
			speakerAvatar = speakerAvatar,
			explosionTarget = explosionTarget
		};
	}

	private static Vector3 GetExplosionPosition(PlayerAvatar playerAvatar)
	{
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)playerAvatar != (Object)null && (Object)(object)playerAvatar.PlayerVisionTarget != (Object)null && (Object)(object)playerAvatar.PlayerVisionTarget.VisionTransform != (Object)null)
		{
			return playerAvatar.PlayerVisionTarget.VisionTransform.position;
		}
		if (!((Object)(object)playerAvatar != (Object)null))
		{
			return Vector3.zero;
		}
		return ((Component)playerAvatar).transform.position + Vector3.up * 0.7f;
	}

	private void SpawnGrenadeExplosion(PlayerAvatar playerAvatar, Vector3 position)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			GameObject val = null;
			if (SemiFunc.IsMultiplayer())
			{
				val = PhotonNetwork.InstantiateRoomObject("Items/Item Grenade Explosive", position, Quaternion.identity, (byte)0, (object[])null);
			}
			else
			{
				GameObject val2 = Resources.Load<GameObject>("Items/Item Grenade Explosive");
				if ((Object)(object)val2 != (Object)null)
				{
					val = Object.Instantiate<GameObject>(val2, position, Quaternion.identity);
				}
			}
			if (!((Object)(object)val == (Object)null))
			{
				ItemGrenade component = val.GetComponent<ItemGrenade>();
				if ((Object)(object)component != (Object)null)
				{
					component.tickTime = 0.05f;
					component.SetActivator(playerAvatar);
				}
				((MonoBehaviour)this).StartCoroutine(ArmGrenadeNextFrame(val));
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to spawn loud voice explosion: " + ex.GetType().Name + ": " + ex.Message));
		}
	}

	[IteratorStateMachine(typeof(<ArmGrenadeNextFrame>d__91))]
	private static IEnumerator ArmGrenadeNextFrame(GameObject grenade)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <ArmGrenadeNextFrame>d__91(0)
		{
			grenade = grenade
		};
	}

	private static bool IsHostAuthority()
	{
		try
		{
			return SemiFunc.IsMasterClientOrSingleplayer();
		}
		catch
		{
			return !GameManager.Multiplayer() || PhotonNetwork.IsMasterClient;
		}
	}

	private static bool IsPlayerDisabled(PlayerAvatar playerAvatar)
	{
		return GetFieldValue(PlayerAvatarIsDisabledField, playerAvatar, fallback: false);
	}

	private static bool IsPlayerDeadSet(PlayerAvatar playerAvatar)
	{
		return GetFieldValue(PlayerAvatarDeadSetField, playerAvatar, fallback: false);
	}

	private static T GetFieldValue<T>(FieldInfo field, object instance, T fallback)
	{
		try
		{
			if (field != null)
			{
				object value = field.GetValue(instance);
				if (value is T)
				{
					return (T)value;
				}
			}
		}
		catch
		{
		}
		return fallback;
	}
}
internal sealed class ConfigurationManagerAttributes
{
	public bool? ShowRangeAsPercent;

	public Action<ConfigEntryBase> CustomDrawer;

	public bool? Browsable;

	public string Category;

	public object DefaultValue;

	public bool? HideDefaultButton;

	public bool? HideSettingName;

	public string Description;

	public string DispName;

	public int? Order;

	public bool? ReadOnly;

	public bool? IsAdvanced;
}