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>? 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>? 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 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 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 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<string> KnownDanceEmotes = new HashSet<string>(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<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=原地复活。HostPosition revives at host location; OriginalPosition revives at each target position.");
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.");
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<bool>? 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<bool>? 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<bool>? 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<bool>? 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<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_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<Character>();
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<bool>? 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<bool>? 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<bool>? 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<bool>? 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)
{
}
}
}