Decompiled source of HostReviveMod v1.7.0

com.sakurakite.revivemod.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("com.sakurakite.revivemod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.7.0.0")]
[assembly: AssemblyInformationalVersion("1.7.0")]
[assembly: AssemblyProduct("com.sakurakite.revivemod")]
[assembly: AssemblyTitle("HostReviveMod")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.7.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 HostReviveMod
{
	[BepInPlugin("com.sakurakites.hostrevivemod", "HostReviveMod", "1.7.0")]
	public class Plugin : BaseUnityPlugin
	{
		private enum UiLanguage
		{
			ZhCn,
			EnUs
		}

		private enum ReviveAllPositionMode
		{
			HostPosition,
			OriginalPosition,
			CheckpointPosition
		}

		private enum AutoRevivePositionMode
		{
			OriginalPosition,
			CheckpointPosition
		}

		public static Plugin? instance;

		internal static ManualLogSource? logger;

		private ConfigEntry<UiLanguage>? uiLanguage;

		private ConfigEntry<KeyCode>? holdReviveKey;

		private ConfigEntry<KeyCode>? reviveAllKey;

		private ConfigEntry<float>? holdDurationSeconds;

		private ConfigEntry<float>? interactDistance;

		private ConfigEntry<bool>? includeHostInReviveAll;

		private ConfigEntry<ReviveAllPositionMode>? reviveAllPositionMode;

		private ConfigEntry<bool>? autoReviveEnabled;

		private ConfigEntry<float>? autoReviveDelaySeconds;

		private ConfigEntry<AutoRevivePositionMode>? autoRevivePositionMode;

		private ConfigEntry<bool>? hostReviveApplyVanillaPenalty;

		private ConfigEntry<bool>? enableDanceRevive;

		private ConfigEntry<float>? danceReviveDistance;

		private ConfigEntry<float>? danceReviveDuration;

		private ConfigEntry<float>? danceEmoteActiveSeconds;

		private ConfigEntry<bool>? instantDanceRevive;

		private ConfigEntry<bool>? danceReviveApplyVanillaPenalty;

		private ConfigEntry<bool>? enableNotifications;

		private ConfigEntry<bool>? showReviveProgressBar;

		private ConfigEntry<bool>? broadcastReviveProgressMessage;

		private ConfigEntry<float>? reviveNearRadius;

		private Character? currentHoldTarget;

		private float holdStartTime;

		private bool holdTriggered;

		private bool localWasDead;

		private string overlayText = string.Empty;

		private float overlayHideTime;

		private string progressText = string.Empty;

		private float progressValue;

		private float progressHideTime;

		private readonly Dictionary<int, float> danceReviveProgressByTarget = new Dictionary<int, float>();

		private readonly HashSet<int> danceStartAnnouncedTargets = new HashSet<int>();

		private readonly Dictionary<int, float> autoReviveStartTimes = new Dictionary<int, float>();

		private int holdStartAnnouncedTarget = -1;

		private static readonly Dictionary<int, string> PendingReviverByViewId = new Dictionary<int, string>();

		private static readonly Dictionary<int, string> LastEmoteByViewId = new Dictionary<int, string>();

		private static readonly Dictionary<int, float> LastDanceEmoteTimeByViewId = new Dictionary<int, float>();

		private static string lastCheckpointSceneName = string.Empty;

		private static Vector3 cachedCheckpointPosition = Vector3.zero;

		private static bool hasCachedCheckpointPosition = false;

		private static float lastCheckpointScanTime;

		private const float CheckpointCaptureIntervalSeconds = 2f;

		private static readonly string[] CampfireActivationPropertyNames = new string[9] { "isLit", "IsLit", "lit", "Lit", "isOn", "IsOn", "on", "On", "HasFire" };

		private static readonly int AnimatorEmoteHash = Animator.StringToHash("Emote");

		private static readonly HashSet<string> KnownDanceEmotes = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "A_Scout_Emote_Dance1", "A_Scout_Emote_Dance2" };

		private void Awake()
		{
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Expected O, but got Unknown
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Expected O, but got Unknown
			instance = this;
			logger = ((BaseUnityPlugin)this).Logger;
			uiLanguage = ((BaseUnityPlugin)this).Config.Bind<UiLanguage>("界面 / UI", "语言 / Language", UiLanguage.ZhCn, "切换提示文本语言(中文/英文)。Switch runtime notification language (Chinese/English).");
			holdReviveKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("输入 / Input", "长按复活按键 / Hold Revive Key", (KeyCode)103, "对准倒地队友骨头/身体时,长按此键可复活。Hold to revive a downed teammate while aiming at their body/bones.");
			reviveAllKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("输入 / Input", "全体复活按键 / Revive All Key", (KeyCode)121, "房主按下此键复活全部倒地队友(位置由下方选项决定)。Host revives all downed teammates (spawn position depends on option below).");
			holdDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("复活 / Revive", "长按时长秒数 / Hold Duration (Seconds)", 5f, "房主对准倒地队友后,长按复活键达到该秒数才会生效。Seconds required to hold before revive triggers.");
			interactDistance = ((BaseUnityPlugin)this).Config.Bind<float>("复活 / Revive", "复活检测距离 / Revive Distance", 6f, "对准倒地队友进行长按复活时的最大检测距离。Maximum aiming distance for hold-revive.");
			includeHostInReviveAll = ((BaseUnityPlugin)this).Config.Bind<bool>("复活 / Revive", "全体复活包含房主 / Include Host In Revive All", true, "开启后,房主倒地时按全体复活也会把自己复活(单人测试推荐开启)。If enabled, Revive All can also revive the host.");
			reviveAllPositionMode = ((BaseUnityPlugin)this).Config.Bind<ReviveAllPositionMode>("复活 / Revive", "全体复活位置 / Revive All Position", ReviveAllPositionMode.HostPosition, "HostPosition=复活到房主位置;OriginalPosition=原地复活;CheckpointPosition=复活到当前篝火/存档点。HostPosition revives at host location; OriginalPosition revives at each target position; CheckpointPosition revives at the current active checkpoint/campfire position.");
			autoReviveEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("复活 / Revive", "启用自动倒计时复活 / Enable Auto Revive", false, "开启后,倒地队友会在设定秒数后自动复活。When enabled, downed teammates will auto-revive after the configured delay.");
			autoReviveDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("复活 / Revive", "自动倒计时秒数 / Auto Revive Delay (Seconds)", 20f, "倒地后多久自动复活(秒)。Seconds before a downed player is automatically revived.");
			autoRevivePositionMode = ((BaseUnityPlugin)this).Config.Bind<AutoRevivePositionMode>("复活 / Revive", "自动复活位置 / Auto Revive Position", AutoRevivePositionMode.CheckpointPosition, "OriginalPosition=死亡原位;CheckpointPosition=当前已激活篝火/存档点位置。OriginalPosition revives at the death location; CheckpointPosition revives at the current active checkpoint/campfire position.");
			reviveNearRadius = ((BaseUnityPlugin)this).Config.Bind<float>("复活 / Revive", "复活靠近半径 / Revive Near Radius", 6f, "当选择原地复活(OriginalPosition)时,尝试在死者附近的活人旁复活,搜索半径(米)。When OriginalPosition is selected, try to revive near a nearby living player within this radius.");
			hostReviveApplyVanillaPenalty = ((BaseUnityPlugin)this).Config.Bind<bool>("复活 / Revive", "房主复活使用原版惩罚 / Host Revive Uses Vanilla Penalty", false, "房主触发的复活(长按复活+全体复活)是否应用原版饥饿和诅咒惩罚。Apply vanilla hunger+curse penalty to host-triggered revives (hold-revive and revive-all).");
			enableDanceRevive = ((BaseUnityPlugin)this).Config.Bind<bool>("复活 / Revive", "启用跳舞复活 / Enable Dance Revive", true, "允许玩家在倒地队友附近跳舞一段时间来复活。Allow reviving downed teammates by dancing nearby for a duration.");
			danceReviveDistance = ((BaseUnityPlugin)this).Config.Bind<float>("复活 / Revive", "跳舞复活距离 / Dance Revive Distance", 5f, "跳舞复活的生效距离(米)。Effective distance in meters for dance revive.");
			danceReviveDuration = ((BaseUnityPlugin)this).Config.Bind<float>("复活 / Revive", "跳舞复活时长秒数 / Dance Revive Duration (Seconds)", 3f, "需要连续跳舞多少秒才会复活。Required continuous dancing time to trigger revive.");
			danceEmoteActiveSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("复活 / Revive", "跳舞判定持续秒数 / Dance Active Window (Seconds)", 4f, "一次跳舞动作在多久内视为持续跳舞(用于网络同步与稳定触发)。How long a dance emote remains valid for revive checks.");
			instantDanceRevive = ((BaseUnityPlugin)this).Config.Bind<bool>("复活 / Revive", "跳舞即刻复活 / Instant Dance Revive", false, "开启后,检测到附近跳舞将立即复活(不等待进度)。Instantly revive when nearby dancing is detected.");
			danceReviveApplyVanillaPenalty = ((BaseUnityPlugin)this).Config.Bind<bool>("复活 / Revive", "跳舞复活使用原版惩罚 / Dance Revive Uses Vanilla Penalty", false, "跳舞复活是否应用原版饥饿和诅咒惩罚。Apply vanilla hunger+curse penalty to dance revive.");
			enableNotifications = ((BaseUnityPlugin)this).Config.Bind<bool>("界面 / UI", "启用复活提示 / Enable Notifications", true, "显示复活提示(本地提示,且会尽力发送到游戏内消息)。Show local and best-effort in-game notifications.");
			showReviveProgressBar = ((BaseUnityPlugin)this).Config.Bind<bool>("界面 / UI", "显示复活进度条 / Show Revive Progress Bar", true, "显示长按复活和跳舞复活进度条(房主端可见)。Show local progress bars for hold and dance revive.");
			broadcastReviveProgressMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("界面 / UI", "广播复活进度提示 / Broadcast Revive Progress Message", true, "尝试通过游戏消息广播“谁正在复活谁”(若游戏消息接口可用则全员可见)。Broadcast revive progress via in-game messages when possible.");
			try
			{
				Harmony val = new Harmony("com.sakurakites.hostrevivemod");
				MethodInfo methodInfo = AccessTools.Method(typeof(CharacterAnimations), "RPCA_PlayRemove", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
					{
						val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(CharacterAnimationsEmotePatch), "RPCA_PlayRemovePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					}
					else
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)string.Format("[HostReviveMod] CharacterAnimations.RPCA_PlayRemove signature mismatch (parameters={0}, firstType={1}); emote patch skipped.", parameters.Length, (parameters.Length != 0) ? parameters[0].ParameterType.Name : "<none>"));
					}
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[HostReviveMod] CharacterAnimations.RPCA_PlayRemove not found; emote patch skipped.");
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[HostReviveMod] Failed to install Harmony patches: " + ex));
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[HostReviveMod] " + L("加载成功:房主长按复活与全体复活已启用", "Loaded: host hold-revive and revive-all are enabled")));
		}

		private void Update()
		{
			try
			{
				RefreshCheckpointPositionCache();
				TrackLocalReviveNotification();
				if (!CanHostUseReviveFeatures())
				{
					ResetHoldTarget();
					return;
				}
				HandleAutoRevive();
				HandleHoldRevive();
				HandleReviveAll();
				HandleDanceRevive();
			}
			catch (Exception arg)
			{
				ManualLogSource? obj = logger;
				if (obj != null)
				{
					obj.LogError((object)$"[HostReviveMod][FATAL] Update exception: {arg}");
				}
			}
		}

		private static bool CanHostUseReviveFeatures()
		{
			if (PhotonNetwork.InRoom)
			{
				return PhotonNetwork.IsMasterClient;
			}
			return false;
		}

		private void HandleAutoRevive()
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			if (autoReviveEnabled == null || !autoReviveEnabled.Value || autoReviveDelaySeconds == null || autoRevivePositionMode == null)
			{
				autoReviveStartTimes.Clear();
			}
			else
			{
				if (Character.AllCharacters == null)
				{
					return;
				}
				float num = Mathf.Max(1f, autoReviveDelaySeconds.Value);
				foreach (Character allCharacter in Character.AllCharacters)
				{
					if ((Object)(object)allCharacter == (Object)null || (Object)(object)((MonoBehaviourPun)allCharacter).photonView == (Object)null)
					{
						continue;
					}
					if (!IsDeadTeammate(allCharacter) && !IsDeadLocalCharacter(allCharacter))
					{
						autoReviveStartTimes.Remove(((MonoBehaviourPun)allCharacter).photonView.ViewID);
						continue;
					}
					int viewID = ((MonoBehaviourPun)allCharacter).photonView.ViewID;
					if (!autoReviveStartTimes.TryGetValue(viewID, out var value))
					{
						autoReviveStartTimes[viewID] = Time.time;
						value = Time.time;
					}
					if (!(Time.time - value < num))
					{
						Vector3 position2;
						Vector3 position = ((autoRevivePositionMode.Value != AutoRevivePositionMode.CheckpointPosition) ? GetCharacterCenterPosition(allCharacter) : ((!TryGetCheckpointRevivePosition(allCharacter, out position2)) ? GetCharacterCenterPosition(allCharacter) : position2));
						if (TryReviveCharacter(allCharacter, position, GetLocalPlayerName(), applyVanillaPenalty: false))
						{
							autoReviveStartTimes.Remove(viewID);
						}
					}
				}
			}
		}

		private void HandleHoldRevive()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			if (holdReviveKey == null || holdDurationSeconds == null || interactDistance == null)
			{
				return;
			}
			if (!Input.GetKey(holdReviveKey.Value))
			{
				ResetHoldTarget();
				return;
			}
			Character val = FindDeadTeammateInSight(interactDistance.Value);
			if ((Object)(object)val == (Object)null)
			{
				ResetHoldTarget();
			}
			else if ((Object)(object)val != (Object)(object)currentHoldTarget)
			{
				currentHoldTarget = val;
				holdStartTime = Time.time;
				holdTriggered = false;
				holdStartAnnouncedTarget = -1;
			}
			else
			{
				if (holdTriggered)
				{
					return;
				}
				if (Time.time - holdStartTime < Mathf.Max(0.1f, holdDurationSeconds.Value))
				{
					float progress = Mathf.Clamp01((Time.time - holdStartTime) / Mathf.Max(0.1f, holdDurationSeconds.Value));
					UpdateProgressUI(L("长按复活: " + GetCharacterDisplayName(val), "Hold Revive: " + GetCharacterDisplayName(val)), progress);
					ConfigEntry<bool> val2 = broadcastReviveProgressMessage;
					if (val2 != null && val2.Value && (Object)(object)((MonoBehaviourPun)val).photonView != (Object)null && holdStartAnnouncedTarget != ((MonoBehaviourPun)val).photonView.ViewID)
					{
						holdStartAnnouncedTarget = ((MonoBehaviourPun)val).photonView.ViewID;
						string localPlayerName = GetLocalPlayerName();
						TryPostSystemMessage(L(localPlayerName + " 正在长按复活 " + GetCharacterDisplayName(val), localPlayerName + " is hold-reviving " + GetCharacterDisplayName(val)));
					}
				}
				else
				{
					string localPlayerName2 = GetLocalPlayerName();
					bool applyVanillaPenalty = hostReviveApplyVanillaPenalty?.Value ?? false;
					if (TryReviveCharacter(val, GetCharacterCenterPosition(val), localPlayerName2, applyVanillaPenalty))
					{
						holdTriggered = true;
						ClearProgressUI();
						string characterDisplayName = GetCharacterDisplayName(val);
						NotifyReviveEvent(L("你复活了 " + characterDisplayName, "You revived " + characterDisplayName), L(localPlayerName2 + " 复活了 " + characterDisplayName, localPlayerName2 + " revived " + characterDisplayName));
					}
				}
			}
		}

		private void HandleReviveAll()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			if (reviveAllKey == null || !Input.GetKeyDown(reviveAllKey.Value))
			{
				return;
			}
			try
			{
				ManualLogSource val = logger;
				if (val != null)
				{
					val.LogInfo((object)$"[HostReviveMod][DEBUG] ReviveAll invoked. PhotonNetwork.InRoom={PhotonNetwork.InRoom}, IsMasterClient={PhotonNetwork.IsMasterClient}, AllCharactersCount={((Character.AllCharacters != null) ? Character.AllCharacters.Count : 0)}");
					if (Character.AllCharacters != null)
					{
						for (int i = 0; i < Character.AllCharacters.Count; i++)
						{
							Character val2 = Character.AllCharacters[i];
							if ((Object)(object)val2 == (Object)null)
							{
								val.LogInfo((object)$"[HostReviveMod][DEBUG] Character[{i}] is null");
								continue;
							}
							int num = -1;
							PhotonView photonView = ((MonoBehaviourPun)val2).photonView;
							if ((Object)(object)photonView != (Object)null)
							{
								num = photonView.ViewID;
							}
							bool num2 = (Object)(object)val2.data != (Object)null;
							bool flag = num2 && val2.data.dead;
							bool flag2 = num2 && val2.data.fullyPassedOut;
							bool isBot = val2.isBot;
							bool flag3 = (Object)(object)photonView != (Object)null && photonView.IsMine;
							val.LogInfo((object)$"[HostReviveMod][DEBUG] Character[{i}] name={((Object)val2).name} viewId={num} dead={flag} passedOut={flag2} isBot={isBot} isLocal={flag3}");
						}
					}
				}
			}
			catch (Exception arg)
			{
				ManualLogSource? obj = logger;
				if (obj != null)
				{
					obj.LogError((object)$"[HostReviveMod][ERROR] Exception while logging revive-all debug: {arg}");
				}
			}
			Vector3 hostPosition = GetHostPosition();
			int num3 = 0;
			string localPlayerName = GetLocalPlayerName();
			bool flag4 = reviveAllPositionMode == null || reviveAllPositionMode.Value == ReviveAllPositionMode.HostPosition;
			bool flag5 = reviveAllPositionMode != null && reviveAllPositionMode.Value == ReviveAllPositionMode.CheckpointPosition;
			bool applyVanillaPenalty = hostReviveApplyVanillaPenalty?.Value ?? false;
			if (Character.AllCharacters == null)
			{
				return;
			}
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if (!IsDeadTeammate(allCharacter))
				{
					ConfigEntry<bool> val3 = includeHostInReviveAll;
					if (val3 == null || !val3.Value || !IsDeadLocalCharacter(allCharacter))
					{
						continue;
					}
				}
				Vector3 val4;
				if (flag4)
				{
					val4 = hostPosition;
				}
				else if (flag5)
				{
					val4 = ((!TryGetCheckpointRevivePosition(allCharacter, out var position)) ? GetCharacterCenterPosition(allCharacter) : position);
				}
				else
				{
					val4 = GetCharacterCenterPosition(allCharacter);
					try
					{
						if (reviveNearRadius != null && TryFindNearbyLivingReviver(allCharacter, reviveNearRadius.Value, out Character reviver))
						{
							Vector3 characterCenterPosition = GetCharacterCenterPosition(reviver);
							Vector3 forward = ((Component)reviver).transform.forward;
							val4 = characterCenterPosition + forward * 1.2f + Vector3.up * 0.5f;
							ManualLogSource? obj2 = logger;
							if (obj2 != null)
							{
								obj2.LogInfo((object)$"[HostReviveMod][DEBUG] ReviveAll using nearby reviver name={GetCharacterDisplayName(reviver)} viewId={(((Object)(object)((MonoBehaviourPun)reviver).photonView != (Object)null) ? ((MonoBehaviourPun)reviver).photonView.ViewID : (-1))} for target={GetCharacterDisplayName(allCharacter)} pos={val4}");
							}
						}
					}
					catch (Exception arg2)
					{
						ManualLogSource? obj3 = logger;
						if (obj3 != null)
						{
							obj3.LogError((object)$"[HostReviveMod][ERROR] Exception while finding nearby reviver: {arg2}");
						}
					}
				}
				try
				{
					ManualLogSource? obj4 = logger;
					if (obj4 != null)
					{
						obj4.LogInfo((object)$"[HostReviveMod][DEBUG] ReviveAll target name={GetCharacterDisplayName(allCharacter)} viewId={(((Object)(object)((MonoBehaviourPun)allCharacter).photonView != (Object)null) ? ((MonoBehaviourPun)allCharacter).photonView.ViewID : (-1))} chosenPos={val4} modeHostPos={flag4}");
					}
				}
				catch (Exception arg3)
				{
					ManualLogSource? obj5 = logger;
					if (obj5 != null)
					{
						obj5.LogError((object)$"[HostReviveMod][ERROR] Exception while logging revive target: {arg3}");
					}
				}
				if (TryReviveCharacter(allCharacter, val4, localPlayerName, applyVanillaPenalty))
				{
					num3++;
				}
			}
			ManualLogSource val5 = logger;
			if (val5 != null)
			{
				val5.LogInfo((object)string.Format("[{0}] {1}: {2}", "HostReviveMod", L("全体复活触发", "Revive-all triggered"), num3));
			}
			if (num3 > 0)
			{
				string localMessage = L($"你触发了全体复活({num3}人)", $"You triggered Revive All ({num3} players)");
				string arg4 = (flag4 ? L("复活到房主位置", "revived at host position") : (flag5 ? L("复活到存档点", "revived at checkpoint") : L("原地复活", "revived at original positions")));
				string broadcastMessage = L($"房主 {localPlayerName} 复活了所有人({num3}人,{arg4})", $"Host {localPlayerName} revived everyone ({num3}, {arg4})");
				NotifyReviveEvent(localMessage, broadcastMessage);
			}
		}

		private void HandleDanceRevive()
		{
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<bool> val = enableDanceRevive;
			if (val == null || !val.Value || danceReviveDistance == null || danceReviveDuration == null)
			{
				danceReviveProgressByTarget.Clear();
				danceStartAnnouncedTargets.Clear();
				return;
			}
			float range = Mathf.Max(0.5f, danceReviveDistance.Value);
			float num = Mathf.Max(0.1f, danceReviveDuration.Value);
			bool flag = instantDanceRevive?.Value ?? false;
			if (Character.AllCharacters == null)
			{
				return;
			}
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if ((!IsDeadTeammate(allCharacter) && !IsDeadLocalCharacter(allCharacter)) || (Object)(object)((MonoBehaviourPun)allCharacter).photonView == (Object)null)
				{
					continue;
				}
				int viewID = ((MonoBehaviourPun)allCharacter).photonView.ViewID;
				if (!TryGetNearbyDancingReviver(allCharacter, range, out Character reviver))
				{
					danceReviveProgressByTarget.Remove(viewID);
					danceStartAnnouncedTargets.Remove(viewID);
					continue;
				}
				float num2 = 0f;
				if (danceReviveProgressByTarget.TryGetValue(viewID, out var value))
				{
					num2 = value;
				}
				num2 += Time.deltaTime;
				danceReviveProgressByTarget[viewID] = num2;
				float progress = Mathf.Clamp01(num2 / num);
				UpdateProgressUI(L("跳舞复活: " + GetCharacterDisplayName(allCharacter), "Dance Revive: " + GetCharacterDisplayName(allCharacter)), progress);
				ConfigEntry<bool> val2 = broadcastReviveProgressMessage;
				if (val2 != null && val2.Value && !danceStartAnnouncedTargets.Contains(viewID))
				{
					danceStartAnnouncedTargets.Add(viewID);
					string characterDisplayName = GetCharacterDisplayName(reviver);
					TryPostSystemMessage(L(characterDisplayName + " 正在跳舞复活 " + GetCharacterDisplayName(allCharacter), characterDisplayName + " is dance-reviving " + GetCharacterDisplayName(allCharacter)));
				}
				if (flag || !(num2 < num))
				{
					string characterDisplayName2 = GetCharacterDisplayName(reviver);
					bool applyVanillaPenalty = danceReviveApplyVanillaPenalty?.Value ?? false;
					if (TryReviveCharacter(allCharacter, GetCharacterCenterPosition(allCharacter), characterDisplayName2, applyVanillaPenalty))
					{
						ClearProgressUI();
						string characterDisplayName3 = GetCharacterDisplayName(allCharacter);
						NotifyReviveEvent(L(characterDisplayName2 + " 通过跳舞复活了 " + characterDisplayName3, characterDisplayName2 + " revived " + characterDisplayName3 + " by dancing"), L(characterDisplayName2 + " 通过跳舞复活了 " + characterDisplayName3, characterDisplayName2 + " revived " + characterDisplayName3 + " by dancing"));
					}
					danceReviveProgressByTarget.Remove(viewID);
					danceStartAnnouncedTargets.Remove(viewID);
				}
			}
		}

		private static bool TryGetNearbyDancingReviver(Character target, float range, out Character? reviver)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			reviver = null;
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if (IsAliveCharacter(allCharacter) && !((Object)(object)allCharacter == (Object)(object)target) && !(Vector3.Distance(((Component)allCharacter).transform.position, ((Component)target).transform.position) > range) && IsCharacterDancing(allCharacter))
				{
					reviver = allCharacter;
					return true;
				}
			}
			return false;
		}

		private static bool TryFindNearbyLivingReviver(Character target, float range, out Character? reviver)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			reviver = null;
			if (Character.AllCharacters == null)
			{
				return false;
			}
			float num = float.MaxValue;
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)allCharacter.data == (Object)null) && !((Object)(object)allCharacter == (Object)(object)target) && !allCharacter.data.dead && !allCharacter.data.fullyPassedOut)
				{
					float num2 = Vector3.Distance(((Component)allCharacter).transform.position, ((Component)target).transform.position);
					if (num2 <= range && num2 < num)
					{
						num = num2;
						reviver = allCharacter;
					}
				}
			}
			return (Object)(object)reviver != (Object)null;
		}

		private static bool IsAliveCharacter(Character? character)
		{
			if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null)
			{
				return false;
			}
			if (!character.data.dead)
			{
				return !character.data.fullyPassedOut;
			}
			return false;
		}

		private static bool IsCharacterDancing(Character character)
		{
			if ((Object)(object)character.refs?.animations == (Object)null)
			{
				return false;
			}
			if ((Object)(object)((MonoBehaviourPun)character).photonView == (Object)null)
			{
				return false;
			}
			int viewID = ((MonoBehaviourPun)character).photonView.ViewID;
			if (!LastEmoteByViewId.TryGetValue(viewID, out var value))
			{
				return false;
			}
			if (!IsDanceEmoteName(value))
			{
				return false;
			}
			float num = Mathf.Max(0.5f, instance?.danceEmoteActiveSeconds?.Value ?? 4f);
			if (LastDanceEmoteTimeByViewId.TryGetValue(viewID, out var value2))
			{
				return Time.time - value2 <= num;
			}
			return false;
		}

		private static bool IsDanceEmoteName(string emoteName)
		{
			if (string.IsNullOrWhiteSpace(emoteName))
			{
				return false;
			}
			if (!KnownDanceEmotes.Contains(emoteName))
			{
				return emoteName.IndexOf("_Emote_Dance", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		internal static void RecordPlayedEmote(CharacterAnimations animations, string emoteName)
		{
			Character component = ((Component)animations).GetComponent<Character>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)((MonoBehaviourPun)component).photonView == (Object)null))
			{
				int viewID = ((MonoBehaviourPun)component).photonView.ViewID;
				LastEmoteByViewId[viewID] = emoteName;
				if (IsDanceEmoteName(emoteName))
				{
					LastDanceEmoteTimeByViewId[viewID] = Time.time;
				}
			}
		}

		private static Character? FindDeadTeammateInSight(float maxDistance)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return null;
			}
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(new Ray(((Component)main).transform.position, ((Component)main).transform.forward), ref val, Mathf.Max(0.5f, maxDistance), -5, (QueryTriggerInteraction)2))
			{
				Character componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Character>();
				if (IsDeadTeammate(componentInParent))
				{
					return componentInParent;
				}
			}
			Character val2 = null;
			float num = float.MaxValue;
			Vector3 position = ((Component)main).transform.position;
			Vector3 forward = ((Component)main).transform.forward;
			float num2 = Mathf.Max(0.5f, maxDistance);
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if (IsDeadTeammate(allCharacter))
				{
					Vector3 val3 = ((Component)allCharacter).transform.position - position;
					float magnitude = ((Vector3)(ref val3)).magnitude;
					if (!(magnitude > num2) && !(magnitude < 0.01f) && !(Vector3.Dot(forward, val3 / magnitude) < 0.35f) && magnitude < num)
					{
						num = magnitude;
						val2 = allCharacter;
					}
				}
			}
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
			return null;
		}

		private static bool IsDeadTeammate(Character? character)
		{
			if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null)
			{
				return false;
			}
			Character localCharacter = GetLocalCharacter();
			if ((Object)(object)localCharacter != (Object)null && (Object)(object)character == (Object)(object)localCharacter)
			{
				return false;
			}
			if (!character.data.dead)
			{
				return character.data.fullyPassedOut;
			}
			return true;
		}

		private static bool IsDeadLocalCharacter(Character? character)
		{
			if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null)
			{
				return false;
			}
			Character localCharacter = GetLocalCharacter();
			if ((Object)(object)localCharacter == (Object)null || (Object)(object)character != (Object)(object)localCharacter)
			{
				return false;
			}
			if (!character.data.dead)
			{
				return character.data.fullyPassedOut;
			}
			return true;
		}

		private static Character? GetLocalCharacter()
		{
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)((MonoBehaviourPun)allCharacter).photonView == (Object)null) && ((MonoBehaviourPun)allCharacter).photonView.IsMine)
				{
					return allCharacter;
				}
			}
			return null;
		}

		private static bool TryReviveCharacter(Character character, Vector3 position, string reviverName, bool applyVanillaPenalty)
		{
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((MonoBehaviourPun)character).photonView == (Object)null)
			{
				return false;
			}
			PhotonView photonView = ((MonoBehaviourPun)character).photonView;
			int num = -1;
			if ((Object)(object)photonView != (Object)null)
			{
				num = photonView.ViewID;
			}
			try
			{
				ManualLogSource? obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)$"[HostReviveMod][DEBUG] TryReviveCharacter viewId={num} name={GetCharacterDisplayName(character)} pos={position} reviver={reviverName} applyPenalty={applyVanillaPenalty}");
				}
			}
			catch (Exception arg)
			{
				ManualLogSource? obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)$"[HostReviveMod][ERROR] Exception while logging TryReviveCharacter: {arg}");
				}
			}
			if ((Object)(object)photonView == (Object)null)
			{
				return false;
			}
			Vector3 val = position;
			try
			{
				if (position == Vector3.zero)
				{
					ManualLogSource? obj3 = logger;
					if (obj3 != null)
					{
						obj3.LogWarning((object)"[HostReviveMod] TryReviveCharacter: provided position was Vector3.zero; attempting to find safe position.");
					}
				}
				val = TryGetSafePosition(position);
				ManualLogSource? obj4 = logger;
				if (obj4 != null)
				{
					obj4.LogInfo((object)$"[HostReviveMod][DEBUG] Final safe revive pos: {val}");
				}
			}
			catch (Exception arg2)
			{
				ManualLogSource? obj5 = logger;
				if (obj5 != null)
				{
					obj5.LogError((object)$"[HostReviveMod][ERROR] Exception while computing safe revive position: {arg2}");
				}
			}
			try
			{
				if (photonView.Owner != null)
				{
					ManualLogSource? obj6 = logger;
					if (obj6 != null)
					{
						obj6.LogDebug((object)$"[HostReviveMod][DEBUG] Sending RPCA_ReviveAtPosition to owner ActorNumber={photonView.Owner.ActorNumber}");
					}
					photonView.RPC("RPCA_ReviveAtPosition", photonView.Owner, new object[3] { val, applyVanillaPenalty, -1 });
				}
				else
				{
					photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { val, applyVanillaPenalty, -1 });
				}
			}
			catch (Exception arg3)
			{
				ManualLogSource? obj7 = logger;
				if (obj7 != null)
				{
					obj7.LogError((object)$"[HostReviveMod][ERROR] Exception while sending revive RPC: {arg3}");
				}
				photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { val, applyVanillaPenalty, -1 });
			}
			PendingReviverByViewId[num] = reviverName;
			return true;
		}

		private static Vector3 GetCharacterCenterPosition(Character character)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null)
			{
				return Vector3.zero;
			}
			try
			{
				PropertyInfo property = typeof(Character).GetProperty("Center", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.PropertyType == typeof(Vector3))
				{
					object value = property.GetValue(character);
					if (value is Vector3)
					{
						return (Vector3)value;
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? obj = logger;
				if (obj != null)
				{
					obj.LogDebug((object)("[HostReviveMod][DEBUG] GetCharacterCenterPosition fallback for " + ((Object)character).name + ": " + ex.Message));
				}
			}
			return ((Component)character).transform.position;
		}

		private static string GetLocalPlayerName()
		{
			if (!string.IsNullOrWhiteSpace(PhotonNetwork.NickName))
			{
				return PhotonNetwork.NickName;
			}
			return "Host";
		}

		private static string GetCharacterDisplayName(Character character)
		{
			PhotonView photonView = ((MonoBehaviourPun)character).photonView;
			if ((((Object)(object)photonView != (Object)null) ? photonView.Owner : null) != null && !string.IsNullOrWhiteSpace(((MonoBehaviourPun)character).photonView.Owner.NickName))
			{
				return ((MonoBehaviourPun)character).photonView.Owner.NickName;
			}
			return ((Object)character).name;
		}

		private static Vector3 GetHostPosition()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			Character localCharacter = GetLocalCharacter();
			if ((Object)(object)localCharacter != (Object)null)
			{
				return GetCharacterCenterPosition(localCharacter);
			}
			if (Character.AllCharacters != null)
			{
				foreach (Character allCharacter in Character.AllCharacters)
				{
					if (!((Object)(object)allCharacter == (Object)null))
					{
						PhotonView photonView = ((MonoBehaviourPun)allCharacter).photonView;
						if ((Object)(object)photonView != (Object)null && photonView.Owner != null && photonView.Owner == PhotonNetwork.LocalPlayer)
						{
							return GetCharacterCenterPosition(allCharacter);
						}
					}
				}
			}
			Player masterClient = PhotonNetwork.MasterClient;
			if (masterClient != null && Character.AllCharacters != null)
			{
				foreach (Character allCharacter2 in Character.AllCharacters)
				{
					if (!((Object)(object)allCharacter2 == (Object)null))
					{
						PhotonView photonView2 = ((MonoBehaviourPun)allCharacter2).photonView;
						if ((Object)(object)photonView2 != (Object)null && photonView2.Owner != null && photonView2.Owner.ActorNumber == masterClient.ActorNumber)
						{
							return GetCharacterCenterPosition(allCharacter2);
						}
					}
				}
			}
			Camera main = Camera.main;
			if ((Object)(object)main != (Object)null)
			{
				return ((Component)main).transform.position;
			}
			ManualLogSource? obj = logger;
			if (obj != null)
			{
				obj.LogWarning((object)"[HostReviveMod] GetHostPosition: could not determine host position; returning Vector3.zero");
			}
			return Vector3.zero;
		}

		private static Vector3 TryGetSafePosition(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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)
			//IL_00c0: 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)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: 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)
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(pos + Vector3.up * 5f, Vector3.down, ref val, 30f, -1, (QueryTriggerInteraction)1))
			{
				return ((RaycastHit)(ref val)).point + Vector3.up * 0.5f;
			}
			float[] array = new float[5] { 0f, 1f, -1f, 2f, -2f };
			foreach (float num in array)
			{
				if (Physics.Raycast(pos + new Vector3(num, 5f, 0f), Vector3.down, ref val, 30f, -1, (QueryTriggerInteraction)1))
				{
					return ((RaycastHit)(ref val)).point + Vector3.up * 0.5f;
				}
				if (Physics.Raycast(pos + new Vector3(0f, 5f, num), Vector3.down, ref val, 30f, -1, (QueryTriggerInteraction)1))
				{
					return ((RaycastHit)(ref val)).point + Vector3.up * 0.5f;
				}
			}
			ManualLogSource? obj = logger;
			if (obj != null)
			{
				obj.LogWarning((object)$"[HostReviveMod] TryGetSafePosition: no ground found near {pos}; returning original pos+up");
			}
			return pos + Vector3.up * 1.5f;
		}

		private void ResetHoldTarget()
		{
			currentHoldTarget = null;
			holdStartTime = 0f;
			holdTriggered = false;
			holdStartAnnouncedTarget = -1;
			ClearProgressUI();
		}

		private static void RefreshCheckpointPositionCache()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (SceneManager.sceneCount <= 0)
				{
					return;
				}
				Scene activeScene = SceneManager.GetActiveScene();
				if (!((Scene)(ref activeScene)).IsValid())
				{
					return;
				}
				string name = ((Scene)(ref activeScene)).name;
				if (name != lastCheckpointSceneName)
				{
					lastCheckpointSceneName = name;
					hasCachedCheckpointPosition = false;
					cachedCheckpointPosition = Vector3.zero;
					lastCheckpointScanTime = 0f;
				}
				if (hasCachedCheckpointPosition && Time.time - lastCheckpointScanTime < 2f)
				{
					return;
				}
				lastCheckpointScanTime = Time.time;
				Character localCharacter = GetLocalCharacter();
				if ((Object)(object)localCharacter == (Object)null)
				{
					return;
				}
				GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
				if (rootGameObjects == null || rootGameObjects.Length == 0)
				{
					return;
				}
				bool flag = false;
				float num = float.MaxValue;
				GameObject[] array = rootGameObjects;
				foreach (GameObject val in array)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					Queue<Transform> queue = new Queue<Transform>();
					queue.Enqueue(val.transform);
					while (queue.Count > 0)
					{
						Transform val2 = queue.Dequeue();
						if ((Object)(object)val2 == (Object)null)
						{
							continue;
						}
						string text = ((Object)val2).name ?? string.Empty;
						if (string.IsNullOrWhiteSpace(text))
						{
							for (int j = 0; j < val2.childCount; j++)
							{
								queue.Enqueue(val2.GetChild(j));
							}
						}
						else if (text.IndexOf("Campfire", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Camp Fire", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Bonfire", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Fire", StringComparison.OrdinalIgnoreCase) < 0)
						{
							for (int k = 0; k < val2.childCount; k++)
							{
								queue.Enqueue(val2.GetChild(k));
							}
						}
						else
						{
							if (!((Component)val2).gameObject.activeInHierarchy)
							{
								continue;
							}
							if (TryGetCampfireActivationPosition(((Component)val2).gameObject, out var position))
							{
								float num2 = Vector3.Distance(((Component)localCharacter).transform.position, position);
								if (num2 < num)
								{
									num = num2;
									cachedCheckpointPosition = position;
									hasCachedCheckpointPosition = true;
									flag = true;
								}
							}
							for (int l = 0; l < val2.childCount; l++)
							{
								queue.Enqueue(val2.GetChild(l));
							}
						}
					}
				}
			}
			catch (Exception arg)
			{
				ManualLogSource? obj = logger;
				if (obj != null)
				{
					obj.LogWarning((object)$"[HostReviveMod] RefreshCheckpointPositionCache failure: {arg}");
				}
				cachedCheckpointPosition = Vector3.zero;
				hasCachedCheckpointPosition = false;
			}
		}

		private static bool TryGetCampfireActivationPosition(GameObject candidate, out Vector3 position)
		{
			//IL_0001: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			if ((Object)(object)candidate == (Object)null)
			{
				return false;
			}
			Transform transform = candidate.transform;
			if ((Object)(object)transform == (Object)null)
			{
				return false;
			}
			Component[] components = candidate.GetComponents<Component>();
			bool flag = default(bool);
			bool flag2 = default(bool);
			foreach (Component val in components)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Type type = ((object)val).GetType();
				string[] campfireActivationPropertyNames = CampfireActivationPropertyNames;
				foreach (string name in campfireActivationPropertyNames)
				{
					FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field != null && field.FieldType == typeof(bool))
					{
						object value = field.GetValue(val);
						int num;
						if (value is bool)
						{
							flag = (bool)value;
							num = 1;
						}
						else
						{
							num = 0;
						}
						if (((uint)num & (flag ? 1u : 0u)) != 0)
						{
							position = transform.position;
							return true;
						}
					}
					if (property != null && property.PropertyType == typeof(bool))
					{
						object value2 = property.GetValue(val, null);
						int num2;
						if (value2 is bool)
						{
							flag2 = (bool)value2;
							num2 = 1;
						}
						else
						{
							num2 = 0;
						}
						if (((uint)num2 & (flag2 ? 1u : 0u)) != 0)
						{
							position = transform.position;
							return true;
						}
					}
				}
			}
			return false;
		}

		private static bool TryGetCheckpointRevivePosition(Character target, out Vector3 position)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			position = GetCharacterCenterPosition(target);
			RefreshCheckpointPositionCache();
			if (hasCachedCheckpointPosition && cachedCheckpointPosition != Vector3.zero)
			{
				position = cachedCheckpointPosition;
				return true;
			}
			return false;
		}

		private void UpdateProgressUI(string text, float progress01)
		{
			ConfigEntry<bool> val = showReviveProgressBar;
			if (val != null && val.Value)
			{
				progressText = text;
				progressValue = Mathf.Clamp01(progress01);
				progressHideTime = Time.time + 0.2f;
			}
		}

		private void ClearProgressUI()
		{
			progressText = string.Empty;
			progressValue = 0f;
			progressHideTime = 0f;
		}

		private void NotifyReviveEvent(string localMessage, string broadcastMessage)
		{
			ConfigEntry<bool> val = enableNotifications;
			if (val == null || !val.Value)
			{
				return;
			}
			ShowLocalOverlay(localMessage);
			bool num = TryPostSystemMessage(broadcastMessage);
			ManualLogSource val2 = logger;
			if (val2 != null)
			{
				val2.LogInfo((object)("[HostReviveMod] " + broadcastMessage));
			}
			if (!num)
			{
				ManualLogSource val3 = logger;
				if (val3 != null)
				{
					val3.LogDebug((object)("[HostReviveMod] " + L("未找到游戏内消息接口,已使用本地提示+日志回退", "No in-game message API found; using local overlay + log fallback")));
				}
			}
		}

		private void TrackLocalReviveNotification()
		{
			ConfigEntry<bool> val = enableNotifications;
			if (val == null || !val.Value)
			{
				return;
			}
			Character localCharacter = GetLocalCharacter();
			if (!((Object)(object)localCharacter == (Object)null) && !((Object)(object)((MonoBehaviourPun)localCharacter).photonView == (Object)null))
			{
				bool flag = (Object)(object)localCharacter.data != (Object)null && (localCharacter.data.dead || localCharacter.data.fullyPassedOut);
				if (localWasDead && !flag && PendingReviverByViewId.TryGetValue(((MonoBehaviourPun)localCharacter).photonView.ViewID, out var value))
				{
					ShowLocalOverlay(L(value + " 复活了你", value + " revived you"));
					PendingReviverByViewId.Remove(((MonoBehaviourPun)localCharacter).photonView.ViewID);
				}
				localWasDead = flag;
			}
		}

		private void ShowLocalOverlay(string message)
		{
			overlayText = message;
			overlayHideTime = Time.time + 3f;
		}

		private void OnGUI()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			if (!string.IsNullOrEmpty(overlayText) && Time.time <= overlayHideTime)
			{
				GUIStyle val = new GUIStyle(GUI.skin.box)
				{
					fontSize = 20,
					alignment = (TextAnchor)4,
					wordWrap = true
				};
				float num = Mathf.Min(700f, (float)Screen.width * 0.85f);
				GUI.Box(new Rect(((float)Screen.width - num) * 0.5f, (float)Screen.height * 0.08f, num, 56f), overlayText, val);
			}
			ConfigEntry<bool> val2 = showReviveProgressBar;
			if (val2 != null && val2.Value && !string.IsNullOrEmpty(progressText) && !(Time.time > progressHideTime))
			{
				GUIStyle val3 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 16,
					alignment = (TextAnchor)4
				};
				val3.normal.textColor = Color.white;
				GUIStyle val4 = val3;
				float num2 = Mathf.Min(500f, (float)Screen.width * 0.7f);
				float num3 = ((float)Screen.width - num2) * 0.5f;
				float num4 = (float)Screen.height * 0.16f;
				GUI.Box(new Rect(num3, num4, num2, 20f), GUIContent.none);
				GUI.Box(new Rect(num3 + 2f, num4 + 2f, (num2 - 4f) * progressValue, 16f), GUIContent.none);
				GUI.Label(new Rect(num3, num4 - 24f, num2, 20f), $"{progressText} ({Mathf.RoundToInt(progressValue * 100f)}%)", val4);
			}
		}

		private static bool TryPostSystemMessage(string message)
		{
			Assembly assembly = typeof(Character).Assembly;
			string[] array = new string[5] { "ChatManager", "ChatUI", "UI_Chat", "NotificationManager", "GameUI" };
			string[] singletonNames = new string[4] { "Instance", "instance", "Singleton", "m_instance" };
			string[] array2 = new string[7] { "AddSystemMessage", "AddMessage", "PostMessage", "ShowNotification", "ShowMessage", "DisplayMessage", "Notify" };
			string[] array3 = array;
			foreach (string name in array3)
			{
				Type type = assembly.GetType(name);
				if (type == null)
				{
					continue;
				}
				object singletonInstance = GetSingletonInstance(type, singletonNames);
				if (singletonInstance == null)
				{
					continue;
				}
				string[] array4 = array2;
				foreach (string name2 in array4)
				{
					MethodInfo method = type.GetMethod(name2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null);
					if (!(method == null))
					{
						method.Invoke(singletonInstance, new object[1] { message });
						return true;
					}
				}
			}
			return false;
		}

		private static object? GetSingletonInstance(Type type, string[] singletonNames)
		{
			foreach (string name in singletonNames)
			{
				PropertyInfo property = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null)
				{
					object value = property.GetValue(null);
					if (value != null)
					{
						return value;
					}
				}
				FieldInfo field = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					object value2 = field.GetValue(null);
					if (value2 != null)
					{
						return value2;
					}
				}
			}
			return null;
		}

		private string L(string zh, string en)
		{
			if (uiLanguage == null || uiLanguage.Value != UiLanguage.EnUs)
			{
				return zh;
			}
			return en;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.sakurakites.hostrevivemod";

		public const string PLUGIN_NAME = "HostReviveMod";

		public const string PLUGIN_VERSION = "1.7.0";
	}
	public static class CharacterAnimationsEmotePatch
	{
		public static void RPCA_PlayRemovePostfix(CharacterAnimations __instance, string emoteName)
		{
			Plugin.RecordPlayedEmote(__instance, emoteName);
		}
	}
}