using System; using System.Collections; 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 UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("com.sakurakite.revivemod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.5.2.0")] [assembly: AssemblyInformationalVersion("1.5.2")] [assembly: AssemblyProduct("com.sakurakite.revivemod")] [assembly: AssemblyTitle("HostReviveMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.5.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace HostReviveMod { [BepInPlugin("com.sakurakites.hostrevivemod", "HostReviveMod", "1.5.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private enum UiLanguage { ZhCn, EnUs } private enum ReviveAllPositionMode { HostPosition, OriginalPosition, CheckpointPosition } public static Plugin? instance; internal static ManualLogSource? logger; private ConfigEntry? uiLanguage; private ConfigEntry? holdReviveKey; private ConfigEntry? reviveAllKey; private ConfigEntry? holdDurationSeconds; private ConfigEntry? interactDistance; private ConfigEntry? includeHostInReviveAll; private ConfigEntry? reviveAllPositionMode; private ConfigEntry? hostReviveApplyVanillaPenalty; private ConfigEntry? enableDanceRevive; private ConfigEntry? danceReviveDistance; private ConfigEntry? danceReviveDuration; private ConfigEntry? danceEmoteActiveSeconds; private ConfigEntry? instantDanceRevive; private ConfigEntry? danceReviveApplyVanillaPenalty; private ConfigEntry? enableNotifications; private ConfigEntry? showReviveProgressBar; private ConfigEntry? broadcastReviveProgressMessage; 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 danceReviveProgressByTarget = new Dictionary(); private readonly HashSet danceStartAnnouncedTargets = new HashSet(); private int holdStartAnnouncedTarget = -1; private static readonly Dictionary PendingReviverByViewId = new Dictionary(); private static readonly Dictionary LastEmoteByViewId = new Dictionary(); private static readonly Dictionary LastDanceEmoteTimeByViewId = new Dictionary(); private static readonly PropertyInfo? CharacterCenterProperty = typeof(Character).GetProperty("Center", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo? CharacterDeathPosMethod = typeof(Character).GetMethod("DeathPos", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly int AnimatorEmoteHash = Animator.StringToHash("Emote"); private static readonly HashSet KnownDanceEmotes = new HashSet(StringComparer.OrdinalIgnoreCase) { "A_Scout_Emote_Dance1", "A_Scout_Emote_Dance2" }; private void Awake() { //IL_025e: Unknown result type (might be due to invalid IL or missing references) instance = this; logger = ((BaseUnityPlugin)this).Logger; uiLanguage = ((BaseUnityPlugin)this).Config.Bind("界面 / UI", "语言 / Language", UiLanguage.ZhCn, "切换提示文本语言(中文/英文)。Switch runtime notification language (Chinese/English)."); holdReviveKey = ((BaseUnityPlugin)this).Config.Bind("输入 / Input", "长按复活按键 / Hold Revive Key", (KeyCode)103, "对准倒地队友骨头/身体时,长按此键可复活。Hold to revive a downed teammate while aiming at their body/bones."); reviveAllKey = ((BaseUnityPlugin)this).Config.Bind("输入 / Input", "全体复活按键 / Revive All Key", (KeyCode)121, "房主按下此键复活全部倒地队友(位置由下方选项决定)。Host revives all downed teammates (spawn position depends on option below)."); holdDurationSeconds = ((BaseUnityPlugin)this).Config.Bind("复活 / Revive", "长按时长秒数 / Hold Duration (Seconds)", 5f, "房主对准倒地队友后,长按复活键达到该秒数才会生效。Seconds required to hold before revive triggers."); interactDistance = ((BaseUnityPlugin)this).Config.Bind("复活 / Revive", "复活检测距离 / Revive Distance", 6f, "对准倒地队友进行长按复活时的最大检测距离。Maximum aiming distance for hold-revive."); includeHostInReviveAll = ((BaseUnityPlugin)this).Config.Bind("复活 / Revive", "全体复活包含房主 / Include Host In Revive All", true, "开启后,房主倒地时按全体复活也会把自己复活(单人测试推荐开启)。If enabled, Revive All can also revive the host."); reviveAllPositionMode = ((BaseUnityPlugin)this).Config.Bind("复活 / Revive", "全体复活位置 / Revive All Position", ReviveAllPositionMode.HostPosition, "HostPosition=复活到房主位置;OriginalPosition=原地复活。HostPosition revives at host location; OriginalPosition revives at each target position."); hostReviveApplyVanillaPenalty = ((BaseUnityPlugin)this).Config.Bind("复活 / 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("复活 / Revive", "启用跳舞复活 / Enable Dance Revive", true, "允许玩家在倒地队友附近跳舞一段时间来复活。Allow reviving downed teammates by dancing nearby for a duration."); danceReviveDistance = ((BaseUnityPlugin)this).Config.Bind("复活 / Revive", "跳舞复活距离 / Dance Revive Distance", 5f, "跳舞复活的生效距离(米)。Effective distance in meters for dance revive."); danceReviveDuration = ((BaseUnityPlugin)this).Config.Bind("复活 / Revive", "跳舞复活时长秒数 / Dance Revive Duration (Seconds)", 3f, "需要连续跳舞多少秒才会复活。Required continuous dancing time to trigger revive."); danceEmoteActiveSeconds = ((BaseUnityPlugin)this).Config.Bind("复活 / Revive", "跳舞判定持续秒数 / Dance Active Window (Seconds)", 4f, "一次跳舞动作在多久内视为持续跳舞(用于网络同步与稳定触发)。How long a dance emote remains valid for revive checks."); instantDanceRevive = ((BaseUnityPlugin)this).Config.Bind("复活 / Revive", "跳舞即刻复活 / Instant Dance Revive", false, "开启后,检测到附近跳舞将立即复活(不等待进度)。Instantly revive when nearby dancing is detected."); danceReviveApplyVanillaPenalty = ((BaseUnityPlugin)this).Config.Bind("复活 / Revive", "跳舞复活使用原版惩罚 / Dance Revive Uses Vanilla Penalty", false, "跳舞复活是否应用原版饥饿和诅咒惩罚。Apply vanilla hunger+curse penalty to dance revive."); enableNotifications = ((BaseUnityPlugin)this).Config.Bind("界面 / UI", "启用复活提示 / Enable Notifications", true, "显示复活提示(本地提示,且会尽力发送到游戏内消息)。Show local and best-effort in-game notifications."); showReviveProgressBar = ((BaseUnityPlugin)this).Config.Bind("界面 / UI", "显示复活进度条 / Show Revive Progress Bar", true, "显示长按复活和跳舞复活进度条(房主端可见)。Show local progress bars for hold and dance revive."); broadcastReviveProgressMessage = ((BaseUnityPlugin)this).Config.Bind("界面 / UI", "广播复活进度提示 / Broadcast Revive Progress Message", true, "尝试通过游戏消息广播“谁正在复活谁”(若游戏消息接口可用则全员可见)。Broadcast revive progress via in-game messages when possible."); new Harmony("com.sakurakites.hostrevivemod").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[HostReviveMod] " + L("加载成功:房主长按复活与全体复活已启用", "Loaded: host hold-revive and revive-all are enabled"))); } private void Update() { TrackLocalReviveNotification(); if (!CanHostUseReviveFeatures()) { ResetHoldTarget(); return; } HandleHoldRevive(); HandleReviveAll(); HandleDanceRevive(); } private static bool CanHostUseReviveFeatures() { return PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient; } private void HandleHoldRevive() { //IL_002f: 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) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: 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? obj = broadcastReviveProgressMessage; if (obj != null && obj.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))); } return; } string localPlayerName2 = GetLocalPlayerName(); bool applyVanillaPenalty = hostReviveApplyVanillaPenalty?.Value ?? false; Vector3 downedCharacterAnchor = GetDownedCharacterAnchor(val); if (TryReviveCharacter(val, downedCharacterAnchor, 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_001c: 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) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) if (reviveAllKey == null || !Input.GetKeyDown(reviveAllKey.Value)) { return; } Vector3 hostPosition = GetHostPosition(); int num = 0; string localPlayerName = GetLocalPlayerName(); bool flag = reviveAllPositionMode == null || reviveAllPositionMode.Value == ReviveAllPositionMode.HostPosition; bool flag2 = reviveAllPositionMode != null && reviveAllPositionMode.Value == ReviveAllPositionMode.CheckpointPosition; bool applyVanillaPenalty = hostReviveApplyVanillaPenalty?.Value ?? false; foreach (Character allCharacter in Character.AllCharacters) { if (!IsDeadTeammate(allCharacter)) { ConfigEntry? obj = includeHostInReviveAll; if (obj == null || !obj.Value || !IsDeadLocalCharacter(allCharacter)) { continue; } } Vector3 position; Vector3 position2 = (flag ? hostPosition : ((!flag2 || !TryGetCheckpointRevivePosition(allCharacter, out position)) ? GetDownedCharacterAnchor(allCharacter) : position)); if (TryReviveCharacter(allCharacter, position2, localPlayerName, applyVanillaPenalty)) { num++; } } ManualLogSource? obj2 = logger; if (obj2 != null) { obj2.LogInfo((object)string.Format("[{0}] {1}: {2}", "HostReviveMod", L("全体复活触发", "Revive-all triggered"), num)); } if (num > 0) { string localMessage = L($"你触发了全体复活({num}人)", $"You triggered Revive All ({num} players)"); string arg = (flag ? L("复活到房主位置", "revived at host position") : (flag2 ? L("复活到存档点", "revived at checkpoint") : L("原地复活", "revived at original positions"))); string broadcastMessage = L($"房主 {localPlayerName} 复活了所有人({num}人,{arg})", $"Host {localPlayerName} revived everyone ({num}, {arg})"); NotifyReviveEvent(localMessage, broadcastMessage); } } private void HandleDanceRevive() { //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) ConfigEntry? obj = enableDanceRevive; if (obj == null || !obj.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; 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? obj2 = broadcastReviveProgressMessage; if (obj2 != null && obj2.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; Vector3 downedCharacterAnchor = GetDownedCharacterAnchor(allCharacter); if (TryReviveCharacter(allCharacter, downedCharacterAnchor, 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_003e: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_004c: 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 currentCharacterPosition = GetCurrentCharacterPosition(allCharacter); Vector3 downedCharacterAnchor = GetDownedCharacterAnchor(target); if (!(Vector3.Distance(currentCharacterPosition, downedCharacterAnchor) > range) && IsCharacterDancing(allCharacter)) { reviver = allCharacter; return true; } } } return false; } private static bool IsAliveCharacter(Character? character) { if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null) { return false; } return !character.data.dead && !character.data.fullyPassedOut; } private static bool IsCharacterDancing(Character character) { CharacterAnimations val = character.refs?.animations; if ((Object)(object)val == (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 string value)) { return false; } if (!IsDanceEmoteName(value)) { return false; } float num = Mathf.Max(0.5f, (instance?.danceEmoteActiveSeconds?.Value).GetValueOrDefault(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; } return KnownDanceEmotes.Contains(emoteName) || emoteName.IndexOf("_Emote_Dance", StringComparison.OrdinalIgnoreCase) >= 0; } internal static void RecordPlayedEmote(CharacterAnimations animations, string emoteName) { Character component = ((Component)animations).GetComponent(); 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_0025: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: 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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return null; } Ray val = default(Ray); ((Ray)(ref val))..ctor(((Component)main).transform.position, ((Component)main).transform.forward); RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val, ref val2, Mathf.Max(0.5f, maxDistance), -5, (QueryTriggerInteraction)2)) { Character componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent(); if (IsDeadTeammate(componentInParent)) { return componentInParent; } } Character val3 = 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)) { continue; } Vector3 downedCharacterAnchor = GetDownedCharacterAnchor(allCharacter); Vector3 val4 = downedCharacterAnchor - position; float magnitude = ((Vector3)(ref val4)).magnitude; if (!(magnitude > num2) && !(magnitude < 0.01f)) { float num3 = Vector3.Dot(forward, val4 / magnitude); if (!(num3 < 0.35f) && magnitude < num) { num = magnitude; val3 = allCharacter; } } } if ((Object)(object)val3 != (Object)null) { return val3; } 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; } return character.data.dead || character.data.fullyPassedOut; } 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; } return character.data.dead || character.data.fullyPassedOut; } 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) { continue; } return allCharacter; } return null; } private static bool TryReviveCharacter(Character character, Vector3 position, string reviverName, bool applyVanillaPenalty) { //IL_002d: 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) if ((Object)(object)((MonoBehaviourPun)character).photonView == (Object)null) { return false; } ((MonoBehaviourPun)character).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { position, applyVanillaPenalty, -1 }); Plugin? plugin = instance; if (plugin != null) { ((MonoBehaviour)plugin).StartCoroutine(ForceWarpAfterRevive(((MonoBehaviourPun)character).photonView, position)); } if (!applyVanillaPenalty) { CharacterRefs refs = character.refs; if (refs != null) { CharacterAfflictions afflictions = refs.afflictions; if (afflictions != null) { afflictions.ClearAllStatus(true); } } } PendingReviverByViewId[((MonoBehaviourPun)character).photonView.ViewID] = reviverName; return true; } private static IEnumerator ForceWarpAfterRevive(PhotonView view, 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) yield return (object)new WaitForSeconds(0.15f); view.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { position, true }); yield return (object)new WaitForSeconds(0.45f); view.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { position, false }); } 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 (((photonView != 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_002f: 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) //IL_0027: 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_0037: Unknown result type (might be due to invalid IL or missing references) Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null) { localCharacter = GetLocalCharacter(); } if ((Object)(object)localCharacter != (Object)null) { return GetCurrentCharacterPosition(localCharacter); } return Vector3.zero; } private static Vector3 GetCurrentCharacterPosition(Character character) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_002b: 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) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (CharacterCenterProperty != null && CharacterCenterProperty.GetValue(character) is Vector3 result) { return result; } return ((Component)character).transform.position; } private static Vector3 GetDownedCharacterAnchor(Character character) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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) if (CharacterDeathPosMethod != null && CharacterDeathPosMethod.Invoke(character, null) is Vector3 val) { return val + Vector3.up * 0.2f; } return GetCurrentCharacterPosition(character); } private void ResetHoldTarget() { currentHoldTarget = null; holdStartTime = 0f; holdTriggered = false; holdStartAnnouncedTarget = -1; ClearProgressUI(); } private static bool TryGetCheckpointRevivePosition(Character target, out Vector3 position) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) position = GetDownedCharacterAnchor(target); object data = target.data; if (data == null) { return false; } Type type = data.GetType(); object obj = type.GetField("checkpointFlags", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(data) ?? type.GetProperty("checkpointFlags", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(data); if (!(obj is IEnumerable enumerable)) { return false; } Vector3? val = null; foreach (object item in enumerable) { if (item == null) { continue; } Component val2 = (Component)((item is Component) ? item : null); if (val2 != null) { val = val2.transform.position + Vector3.up; continue; } object? obj2 = item.GetType().GetProperty("transform", BindingFlags.Instance | BindingFlags.Public)?.GetValue(item); Transform val3 = (Transform)((obj2 is Transform) ? obj2 : null); if (val3 != null) { val = val3.position + Vector3.up; } } if (val.HasValue) { position = val.Value; return true; } return false; } private void UpdateProgressUI(string text, float progress01) { ConfigEntry? obj = showReviveProgressBar; if (obj != null && obj.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? obj = enableNotifications; if (obj == null || !obj.Value) { return; } ShowLocalOverlay(localMessage); bool flag = TryPostSystemMessage(broadcastMessage); ManualLogSource? obj2 = logger; if (obj2 != null) { obj2.LogInfo((object)("[HostReviveMod] " + broadcastMessage)); } if (!flag) { ManualLogSource? obj3 = logger; if (obj3 != null) { obj3.LogDebug((object)("[HostReviveMod] " + L("未找到游戏内消息接口,已使用本地提示+日志回退", "No in-game message API found; using local overlay + log fallback"))); } } } private void TrackLocalReviveNotification() { ConfigEntry? obj = enableNotifications; if (obj == null || !obj.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 string 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: 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); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(((float)Screen.width - num) * 0.5f, (float)Screen.height * 0.08f, num, 56f); GUI.Box(val2, overlayText, val); } ConfigEntry? obj = showReviveProgressBar; if (obj != null && obj.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) { return (uiLanguage != null && uiLanguage.Value == UiLanguage.EnUs) ? en : zh; } } public static class PluginInfo { public const string PLUGIN_GUID = "com.sakurakites.hostrevivemod"; public const string PLUGIN_NAME = "HostReviveMod"; public const string PLUGIN_VERSION = "1.5.2"; } [HarmonyPatch(typeof(CharacterAnimations), "RPCA_PlayRemove")] public static class CharacterAnimationsEmotePatch { [HarmonyPostfix] private static void RPCA_PlayRemovePostfix(CharacterAnimations __instance, string emoteName) { Plugin.RecordPlayedEmote(__instance, emoteName); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }