using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalCompanyInputUtils.Api; using Microsoft.CodeAnalysis; using TMPro; using UltimateRevive.Patches; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("UltimateRevive")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("UltimateRevive")] [assembly: AssemblyTitle("UltimateRevive")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace UltimateRevive { public static class DeathMarkerManager { [CompilerGenerated] private sealed class d__32 : IEnumerable<(string Path, bool FromConfiguredPath)>, IEnumerable, IEnumerator<(string Path, bool FromConfiguredPath)>, IEnumerator, IDisposable { private int <>1__state; private (string Path, bool FromConfiguredPath) <>2__current; private int <>l__initialThreadId; private HashSet 5__2; private (string RawPath, bool FromConfiguredPath)[] <>7__wrap2; private int <>7__wrap3; private (string RawPath, bool FromConfiguredPath) 5__5; private string 5__6; (string, bool) IEnumerator<(string, bool)>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__32(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; <>7__wrap2 = null; 5__5 = default((string, bool)); 5__6 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; 5__2 = new HashSet(StringComparer.OrdinalIgnoreCase); (string, bool)[] array = new(string, bool)[2] { (ModConfig.DeathTombAssetBundlePath, true), ("UltimateRevive/bundles/sm_tombstone_3_dark_rip.bundle", false) }; <>7__wrap2 = array; <>7__wrap3 = 0; goto IL_016d; } case 1: <>1__state = -1; goto IL_00f9; case 2: { <>1__state = -1; goto IL_014c; } IL_016d: if (<>7__wrap3 < <>7__wrap2.Length) { 5__5 = <>7__wrap2[<>7__wrap3]; string item = 5__5.RawPath; if (!string.IsNullOrWhiteSpace(item)) { 5__6 = (Path.IsPathRooted(item) ? item : Path.Combine(Paths.PluginPath, item)); if (5__2.Add(5__6)) { <>2__current = (5__6, 5__5.FromConfiguredPath); <>1__state = 1; return true; } goto IL_00f9; } goto IL_015f; } <>7__wrap2 = null; return false; IL_00f9: if (!Path.HasExtension(5__6)) { string text = 5__6 + ".bundle"; if (5__2.Add(text)) { <>2__current = (text, 5__5.FromConfiguredPath); <>1__state = 2; return true; } } goto IL_014c; IL_014c: 5__6 = null; 5__5 = default((string, bool)); goto IL_015f; IL_015f: <>7__wrap3++; goto IL_016d; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<(string Path, bool FromConfiguredPath)> IEnumerable<(string, bool)>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__32(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<(string, bool)>)this).GetEnumerator(); } } private const float TombWidth = 0.6f; private const float TombHeight = 1.35f; private const float TombDepth = 0.35f; private static readonly Dictionary ActiveMarkers = new Dictionary(); private static readonly Dictionary LastMarkerDecision = new Dictionary(); private static readonly Dictionary MarkerRadarIndexes = new Dictionary(); private static readonly Dictionary TombDeadBodies = new Dictionary(); private static ManualLogSource _log; private static int _lastTickFrame = -1; private static AssetBundle _assetBundle; private static bool _assetBundleLoadAttempted; private static GameObject _cachedPrefab; public static void SetLogSource(ManualLogSource logSource) { _log = logSource; } public static void InvalidateBundleCache() { _assetBundleLoadAttempted = false; _cachedPrefab = null; if ((Object)(object)_assetBundle != (Object)null) { _assetBundle.Unload(false); _assetBundle = null; } } public static void Tick() { if (ModState.Active && ModConfig.EnableDeathTombFallback && Time.frameCount != _lastTickFrame) { _lastTickFrame = Time.frameCount; StartOfRound instance = StartOfRound.Instance; if (instance?.allPlayerScripts != null) { _ = instance.mapScreen; } } } public static bool IsTombDeadBody(int playerClientId, DeadBodyInfo deadBody) { if ((Object)(object)deadBody != (Object)null && TombDeadBodies.TryGetValue(playerClientId, out var value)) { return (Object)(object)value == (Object)(object)deadBody; } return false; } public static bool TryGetTombOwnerPlayerId(DeadBodyInfo deadBody, out int playerClientId) { playerClientId = -1; if ((Object)(object)deadBody == (Object)null) { return false; } foreach (KeyValuePair tombDeadBody in TombDeadBodies) { if ((Object)(object)tombDeadBody.Value == (Object)(object)deadBody) { playerClientId = tombDeadBody.Key; return true; } } return false; } private static void DebugLog(string message) { if (ModConfig.EnableDebugLogs) { ManualLogSource log = _log; if (log != null) { log.LogInfo((object)message); } } } public static bool IsTombRagdollGrabbable(RagdollGrabbableObject body) { if ((Object)(object)body == (Object)null) { return false; } foreach (DeadBodyInfo value in TombDeadBodies.Values) { if ((Object)(object)value != (Object)null && (Object)(object)((Component)value).gameObject == (Object)(object)((Component)body).gameObject) { return true; } } return false; } public static bool TrySpawnTombForPlayer(PlayerControllerB player, Vector3 position, string reason = null) { //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) if (!ModState.Active || !ModConfig.EnableDeathTombFallback || (Object)(object)player == (Object)null) { return false; } int num = (int)player.playerClientId; if (ActiveMarkers.TryGetValue(num, out var value) && (Object)(object)value != (Object)null) { DeadBodyInfo component = value.GetComponent(); if ((Object)(object)component != (Object)null) { TombDeadBodies[num] = component; } GeneralUtil.SetPlayerDeathState(num, PlayerDeathType.Body, 0uL, value.transform.position, string.IsNullOrWhiteSpace(reason) ? "TombAlreadyActive" : (reason + ":alreadyActive")); return true; } ClearMarker(num); GameObject val = null; try { GameObject markerPrefab = GetMarkerPrefab(); val = (((Object)(object)markerPrefab != (Object)null) ? Object.Instantiate(markerPrefab) : CreateProceduralTombMarker()); } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Tomb prefab instantiate failed, using procedural marker: " + ex.Message)); } val = CreateProceduralTombMarker(); } if ((Object)(object)val == (Object)null) { return false; } ((Object)val).name = $"UltimateReviveTomb_{num}"; position = ProjectTombPositionToGround(position, num); val.transform.position = position; KeepMarkerUpright(val); DeadBodyInfo val2 = TombDeadBodySetup.SetupTombAsDeadBody(player, val, position); if ((Object)(object)val2 == (Object)null) { Object.Destroy((Object)(object)val); return false; } ActiveMarkers[num] = val; TombDeadBodies[num] = val2; GeneralUtil.SetPlayerDeathState(num, PlayerDeathType.Body, 0uL, position, string.IsNullOrWhiteSpace(reason) ? "TombSpawned" : reason); ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)string.Format("[DeathMarker] tombSpawned player={0} pos=({1:0.00},{2:0.00},{3:0.00}) reason={4}", num, position.x, position.y, position.z, string.IsNullOrWhiteSpace(reason) ? "unspecified" : reason)); } return true; } private static Vector3 ProjectTombPositionToGround(Vector3 deathPosition, int playerClientId) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_003f: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: 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_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0100: 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) float num = Mathf.Max(0f, ModConfig.DeathTombGroundOffset); float num2 = Mathf.Max(1f, ModConfig.DeathTombSpawnHeight); if (TryRaycastGroundBelow(deathPosition + Vector3.up * num2, out var point)) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(deathPosition.x, point.y + num, deathPosition.z); DebugLog($"[DeathMarker] tombGroundSnap player={playerClientId} " + $"from=({deathPosition.x:0.00},{deathPosition.y:0.00},{deathPosition.z:0.00}) " + $"to=({val.x:0.00},{val.y:0.00},{val.z:0.00})"); return val; } ManualLogSource log = _log; if (log != null) { log.LogWarning((object)($"[DeathMarker] tombGroundSnapFailed player={playerClientId} " + $"pos=({deathPosition.x:0.00},{deathPosition.y:0.00},{deathPosition.z:0.00})")); } return deathPosition; } private static bool TryRaycastGroundBelow(Vector3 origin, out Vector3 point) { //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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_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_010a: 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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) point = Vector3.zero; RaycastHit[] array = Physics.RaycastAll(origin, Vector3.down, 120f, -1, (QueryTriggerInteraction)1); if (array == null || array.Length == 0) { return false; } RaycastHit val = default(RaycastHit); float num = float.PositiveInfinity; bool flag = false; for (int i = 0; i < array.Length; i++) { RaycastHit val2 = array[i]; Collider collider = ((RaycastHit)(ref val2)).collider; if (!((Object)(object)collider == (Object)null) && collider.enabled && !collider.isTrigger && !((Object)(object)((Component)collider).GetComponentInParent() != (Object)null) && !((Object)(object)((Component)collider).GetComponentInParent() != (Object)null) && !((Object)(object)((Component)collider).GetComponentInParent() != (Object)null) && !((Object)(object)((Component)collider).GetComponentInParent() != (Object)null)) { Transform root = ((Component)collider).transform.root; if ((!((Object)(object)root != (Object)null) || !((Object)root).name.StartsWith("UltimateReviveTomb_")) && ((RaycastHit)(ref val2)).distance < num) { num = ((RaycastHit)(ref val2)).distance; val = val2; flag = true; } } } if (!flag) { return false; } point = ((RaycastHit)(ref val)).point; return true; } public static void ClearMarker(int playerClientId) { if (!ActiveMarkers.TryGetValue(playerClientId, out var value)) { return; } if (TombDeadBodies.TryGetValue(playerClientId, out var value2)) { PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(playerClientId); if ((Object)(object)playerByClientId != (Object)null && (Object)(object)playerByClientId.deadBody == (Object)(object)value2) { playerByClientId.deadBody = null; } TombDeadBodies.Remove(playerClientId); } UnregisterMarkerFromRadar(playerClientId); if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } ActiveMarkers.Remove(playerClientId); } public static bool HasActiveMarker(int playerClientId) { if (ActiveMarkers.TryGetValue(playerClientId, out var value)) { return (Object)(object)value != (Object)null; } return false; } public static bool TryGetMarkerObject(int playerClientId, out GameObject markerObject) { if (ActiveMarkers.TryGetValue(playerClientId, out var value) && (Object)(object)value != (Object)null) { markerObject = value; return true; } markerObject = null; return false; } public static bool TryResolveTargetedMarkerPlayerId(ManualCameraRenderer mapScreen, out int playerClientId) { playerClientId = -1; PlayerControllerB val = mapScreen?.targetedPlayer; if ((Object)(object)val == (Object)null) { return false; } DeadBodyInfo deadBody = val.deadBody; if ((Object)(object)deadBody == (Object)null) { return false; } int num = (int)val.playerClientId; if (IsTombDeadBody(num, deadBody)) { playerClientId = num; return true; } foreach (KeyValuePair tombDeadBody in TombDeadBodies) { if ((Object)(object)tombDeadBody.Value == (Object)(object)deadBody) { playerClientId = tombDeadBody.Key; return true; } } return false; } public static bool TryGetMarkerPosition(int playerClientId, out Vector3 position) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (ActiveMarkers.TryGetValue(playerClientId, out var value) && (Object)(object)value != (Object)null && (Object)(object)value.transform != (Object)null) { position = value.transform.position; return true; } position = default(Vector3); return false; } public static void Reset() { foreach (KeyValuePair tombDeadBody in TombDeadBodies) { PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(tombDeadBody.Key); if ((Object)(object)playerByClientId != (Object)null && (Object)(object)playerByClientId.deadBody == (Object)(object)tombDeadBody.Value) { playerByClientId.deadBody = null; } } TombDeadBodies.Clear(); foreach (GameObject value in ActiveMarkers.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } ActiveMarkers.Clear(); LastMarkerDecision.Clear(); MarkerRadarIndexes.Clear(); _lastTickFrame = -1; InvalidateBundleCache(); } private static void UnregisterMarkerFromRadar(int playerClientId) { MarkerRadarIndexes.Remove(playerClientId); } private static void KeepMarkerUpright(GameObject marker) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0037: 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) if (!((Object)(object)marker == (Object)null) && !((Object)(object)marker.transform == (Object)null)) { Quaternion rotation = marker.transform.rotation; Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles; marker.transform.rotation = Quaternion.Euler(0f, eulerAngles.y, 0f); } } private static GameObject CreateProceduralTombMarker() { //IL_0026: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = "ReviveDeathMarker_ProceduralCube"; obj.transform.localScale = new Vector3(0.6f, 1.35f, 0.35f); obj.transform.localPosition = new Vector3(0f, 0.675f, 0f); Renderer component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { Material val = new Material(Shader.Find("Standard")); val.color = new Color(0.42f, 0.42f, 0.42f, 1f); component.material = val; } return obj; } private static GameObject GetMarkerPrefab() { if ((Object)(object)_cachedPrefab != (Object)null) { return _cachedPrefab; } if (_assetBundleLoadAttempted) { return null; } _assetBundleLoadAttempted = true; List<(string, bool)> list = BuildCandidateBundlePaths().ToList(); if (list.Count == 0) { return null; } for (int i = 0; i < list.Count; i++) { string item = list[i].Item1; bool flag = !list[i].Item2; if (!File.Exists(item)) { continue; } try { _assetBundle = AssetBundle.LoadFromFile(item); if ((Object)(object)_assetBundle == (Object)null) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Failed to load death marker AssetBundle: " + item)); } continue; } string deathTombPrefabName = ModConfig.DeathTombPrefabName; if (!string.IsNullOrWhiteSpace(deathTombPrefabName)) { _cachedPrefab = _assetBundle.LoadAsset(deathTombPrefabName); } if ((Object)(object)_cachedPrefab == (Object)null) { _cachedPrefab = _assetBundle.LoadAsset("sm_tombstone_3_dark_rip"); } if ((Object)(object)_cachedPrefab == (Object)null) { GameObject[] array = _assetBundle.LoadAllAssets(); _cachedPrefab = ((array != null && array.Length != 0) ? array[0] : null); } if ((Object)(object)_cachedPrefab != (Object)null) { if (flag) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)("Configured death marker bundle failed, fallback loaded: " + item)); } } return _cachedPrefab; } ManualLogSource log3 = _log; if (log3 != null) { log3.LogWarning((object)("Death marker AssetBundle has no GameObject prefab: " + item)); } _assetBundle.Unload(false); _assetBundle = null; } catch (Exception ex) { ManualLogSource log4 = _log; if (log4 != null) { log4.LogWarning((object)("Death marker loading failed for " + item + ": " + ex.Message)); } if ((Object)(object)_assetBundle != (Object)null) { _assetBundle.Unload(false); _assetBundle = null; } } } ManualLogSource log5 = _log; if (log5 != null) { log5.LogWarning((object)"No valid death marker bundle found. Using primitive fallback marker."); } return null; } [IteratorStateMachine(typeof(d__32))] private static IEnumerable<(string Path, bool FromConfiguredPath)> BuildCandidateBundlePaths() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__32(-2); } } public static class GeneralUtil { private static ManualLogSource _log; private static readonly BindingFlags InstanceFieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static readonly FieldInfo BodyPlayerScriptField = typeof(RagdollGrabbableObject).GetField("playerScript", InstanceFieldFlags); private static readonly FieldInfo BodyPlayerObjectScriptField = typeof(RagdollGrabbableObject).GetField("playerObjectScript", InstanceFieldFlags); private static readonly FieldInfo BodySourcePlayerField = typeof(RagdollGrabbableObject).GetField("sourcePlayer", InstanceFieldFlags); public static void SetLogSource(ManualLogSource logSource) { _log = logSource; } public static PlayerControllerB GetPlayerByClientId(int playerClientId) { if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null) { return null; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if ((Object)(object)val != (Object)null && (int)val.playerClientId == playerClientId) { return val; } } return null; } public static PlayerControllerB GetClosestAlivePlayer(Vector3 position) { //IL_005a: 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) if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null) { return null; } PlayerControllerB result = null; float num = float.MaxValue; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (!((Object)(object)val == (Object)null) && !val.isPlayerDead && val.isPlayerControlled) { float num2 = Vector3.Distance(((Component)val).transform.position, position); if (num2 < num) { num = num2; result = val; } } } return result; } public static RagdollGrabbableObject GetBodyForPlayer(int playerClientId) { RagdollGrabbableObject bodyFromDeadBodyReference = GetBodyFromDeadBodyReference(GetPlayerByClientId(playerClientId)); if ((Object)(object)bodyFromDeadBodyReference != (Object)null) { return bodyFromDeadBodyReference; } RagdollGrabbableObject[] array = Object.FindObjectsOfType(); foreach (RagdollGrabbableObject val in array) { if (TryGetBodyOwner(val, out var targetPlayerClientId, out var _) && targetPlayerClientId == playerClientId) { return val; } } return null; } public static RagdollGrabbableObject GetBodyFromDeadBodyReference(PlayerControllerB player) { if ((Object)(object)player?.deadBody == (Object)null) { return null; } DeadBodyInfo deadBody = player.deadBody; RagdollGrabbableObject val = ((Component)deadBody).GetComponent() ?? ((Component)deadBody).GetComponentInChildren() ?? ((Component)deadBody).GetComponentInParent(); if ((Object)(object)val != (Object)null) { return val; } if ((Object)(object)((Component)deadBody).transform == (Object)null) { return null; } RagdollGrabbableObject[] array = Object.FindObjectsOfType(); foreach (RagdollGrabbableObject val2 in array) { if (!((Object)(object)((val2 != null) ? ((Component)val2).transform : null) == (Object)null) && ((Object)(object)((Component)val2).transform == (Object)(object)((Component)deadBody).transform || ((Component)val2).transform.IsChildOf(((Component)deadBody).transform) || ((Component)deadBody).transform.IsChildOf(((Component)val2).transform))) { return val2; } } return null; } public static RagdollGrabbableObject GetBodyByNetworkObjectId(ulong networkObjectId) { if (networkObjectId == 0L) { return null; } if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.SpawnManager != null && NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(networkObjectId, out var value) && (Object)(object)value != (Object)null) { RagdollGrabbableObject component = ((Component)value).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } component = ((Component)value).GetComponentInChildren(); if ((Object)(object)component != (Object)null) { return component; } } RagdollGrabbableObject[] array = Object.FindObjectsOfType(); foreach (RagdollGrabbableObject val in array) { if ((Object)(object)((val != null) ? ((NetworkBehaviour)val).NetworkObject : null) != (Object)null && ((NetworkBehaviour)val).NetworkObject.NetworkObjectId == networkObjectId) { return val; } } return null; } public static RagdollGrabbableObject GetBodyNearPosition(Vector3 position, float maxDistance = 12f) { //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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) RagdollGrabbableObject[] array = Object.FindObjectsOfType(); RagdollGrabbableObject result = null; float num = maxDistance * maxDistance; RagdollGrabbableObject[] array2 = array; foreach (RagdollGrabbableObject val in array2) { if (!((Object)(object)((val != null) ? ((Component)val).transform : null) == (Object)null)) { Vector3 val2 = ((Component)val).transform.position - position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude <= num) { num = sqrMagnitude; result = val; } } } return result; } public static DeadBodyInfo GetDeadBodyNearPosition(Vector3 position, float maxDistance = 12f) { //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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) DeadBodyInfo[] array = Object.FindObjectsOfType(); DeadBodyInfo result = null; float num = maxDistance * maxDistance; DeadBodyInfo[] array2 = array; foreach (DeadBodyInfo val in array2) { if (!((Object)(object)((val != null) ? ((Component)val).transform : null) == (Object)null)) { Vector3 val2 = ((Component)val).transform.position - position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude <= num) { num = sqrMagnitude; result = val; } } } return result; } public static bool TryGetBodyOwner(RagdollGrabbableObject body, out int targetPlayerClientId, out PlayerControllerB targetPlayer) { targetPlayerClientId = -1; targetPlayer = null; if ((Object)(object)body == (Object)null) { return false; } targetPlayer = body.ragdoll?.playerScript; if ((Object)(object)targetPlayer != (Object)null) { targetPlayerClientId = (int)targetPlayer.playerClientId; return true; } object? obj = BodyPlayerScriptField?.GetValue(body); PlayerControllerB val = (PlayerControllerB)(((obj is PlayerControllerB) ? obj : null) ?? ((object)(/*isinst with value type is only supported in some contexts*/ ?? /*isinst with value type is only supported in some contexts*/))); if ((Object)(object)val != (Object)null) { targetPlayer = val; targetPlayerClientId = (int)val.playerClientId; return true; } if (StartOfRound.Instance?.allPlayerScripts != null) { PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val2 in allPlayerScripts) { if (!((Object)(object)val2 == (Object)null)) { DeadBodyInfo deadBody = val2.deadBody; if (!((Object)(object)deadBody == (Object)null) && (deadBody == body || ((Object)(object)((Component)deadBody).transform != (Object)null && (Object)(object)((Component)body).transform != (Object)null && ((Object)(object)((Component)deadBody).transform == (Object)(object)((Component)body).transform || ((Component)deadBody).transform.IsChildOf(((Component)body).transform) || ((Component)body).transform.IsChildOf(((Component)deadBody).transform))))) { targetPlayer = val2; targetPlayerClientId = (int)val2.playerClientId; return true; } } } } return false; } public static PlayerReviveInfo GetOrCreateInfo(int playerClientId) { //IL_0055: 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) PlayerReviveInfo playerReviveInfo = ModState.PlayerInfos.FirstOrDefault((PlayerReviveInfo x) => x.PlayerClientId == playerClientId); if (playerReviveInfo != null) { return playerReviveInfo; } playerReviveInfo = new PlayerReviveInfo { PlayerClientId = playerClientId, TimeDiedAt = Time.time, LastDeathType = PlayerDeathType.Unknown, LastDeathNetworkObjectId = 0uL, LastDeathPosition = Vector3.zero, HasLastDeathPosition = false }; ModState.PlayerInfos.Add(playerReviveInfo); return playerReviveInfo; } public static void ResetAllPlayerInfos() { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) ModState.PlayerInfos.Clear(); if (StartOfRound.Instance?.allPlayerScripts == null) { return; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (!((Object)(object)val == (Object)null)) { ModState.PlayerInfos.Add(new PlayerReviveInfo { PlayerClientId = (int)val.playerClientId, TimeDiedAt = Time.time, HasBeenTeleported = false, TimesRevivedThisLevel = 0, LastDeathType = PlayerDeathType.Unknown, LastDeathNetworkObjectId = 0uL, LastDeathPosition = Vector3.zero, HasLastDeathPosition = false }); } } } public static void SetPlayerDiedAt(int playerClientId) { SetPlayerDeathState(playerClientId, PlayerDeathType.Body, 0uL, "SetPlayerDiedAt"); } public static void SetPlayerDeathState(int playerClientId, PlayerDeathType deathType, ulong networkObjectId = 0uL, string reason = null) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) SetPlayerDeathState(playerClientId, deathType, networkObjectId, Vector3.zero, hasPosition: false, reason); } public static void SetPlayerDeathState(int playerClientId, PlayerDeathType deathType, ulong networkObjectId, Vector3 deathPosition, string reason = null) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) SetPlayerDeathState(playerClientId, deathType, networkObjectId, deathPosition, hasPosition: true, reason); } private static void SetPlayerDeathState(int playerClientId, PlayerDeathType deathType, ulong networkObjectId, Vector3 deathPosition, bool hasPosition, string reason) { //IL_001d: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) PlayerReviveInfo orCreateInfo = GetOrCreateInfo(playerClientId); PlayerDeathType lastDeathType = orCreateInfo.LastDeathType; ulong lastDeathNetworkObjectId = orCreateInfo.LastDeathNetworkObjectId; bool hasLastDeathPosition = orCreateInfo.HasLastDeathPosition; Vector3 lastDeathPosition = orCreateInfo.LastDeathPosition; if (orCreateInfo.TimeDiedAt == 0f) { orCreateInfo.TimeDiedAt = Time.time; } orCreateInfo.LastDeathType = deathType; orCreateInfo.LastDeathNetworkObjectId = networkObjectId; orCreateInfo.HasLastDeathPosition = hasPosition; orCreateInfo.LastDeathPosition = (hasPosition ? deathPosition : Vector3.zero); if (lastDeathType == deathType && lastDeathNetworkObjectId == networkObjectId && hasLastDeathPosition == hasPosition) { if (!hasPosition) { return; } if (hasLastDeathPosition) { Vector3 val = lastDeathPosition - deathPosition; if (!(((Vector3)(ref val)).sqrMagnitude > 0.0025f)) { return; } } } string text = (hasLastDeathPosition ? $"{lastDeathType}/obj:{lastDeathNetworkObjectId}/pos:{FormatVector(lastDeathPosition)}" : $"{lastDeathType}/obj:{lastDeathNetworkObjectId}/pos:none"); string text2 = (hasPosition ? $"{deathType}/obj:{networkObjectId}/pos:{FormatVector(deathPosition)}" : $"{deathType}/obj:{networkObjectId}/pos:none"); Plugin.DebugLog(string.Format("[DeathState] player={0} from={1} to={2} reason={3}", playerClientId, text, text2, string.IsNullOrWhiteSpace(reason) ? "unspecified" : reason)); } private static string FormatVector(Vector3 value) { //IL_0005: 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_001b: Unknown result type (might be due to invalid IL or missing references) return $"({value.x:0.00},{value.y:0.00},{value.z:0.00})"; } public static PlayerDeathType GetPlayerLastDeathType(int playerClientId) { return GetOrCreateInfo(playerClientId).LastDeathType; } public static ulong GetPlayerLastDeathNetworkObjectId(int playerClientId) { return GetOrCreateInfo(playerClientId).LastDeathNetworkObjectId; } public static bool IsLatestDeathType(int playerClientId, PlayerDeathType expectedType) { return GetPlayerLastDeathType(playerClientId) == expectedType; } public static bool TryGetPlayerLastDeathPosition(int playerClientId, out Vector3 position) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) PlayerReviveInfo orCreateInfo = GetOrCreateInfo(playerClientId); position = orCreateInfo.LastDeathPosition; return orCreateInfo.HasLastDeathPosition; } public static void ClearPlayerDeathState(int playerClientId) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) PlayerReviveInfo orCreateInfo = GetOrCreateInfo(playerClientId); orCreateInfo.LastDeathType = PlayerDeathType.Unknown; orCreateInfo.LastDeathNetworkObjectId = 0uL; orCreateInfo.LastDeathPosition = Vector3.zero; orCreateInfo.HasLastDeathPosition = false; orCreateInfo.TimeDiedAt = 0f; } public static float GetPlayerDiedAtTime(int playerClientId) { return GetOrCreateInfo(playerClientId).TimeDiedAt; } public static void MarkTeleported(int playerClientId) { GetOrCreateInfo(playerClientId).HasBeenTeleported = true; } public static bool HasPlayerTeleported(int playerClientId) { return GetOrCreateInfo(playerClientId).HasBeenTeleported; } public static int IncrementReviveCountAndGetHealth(int playerClientId) { PlayerReviveInfo orCreateInfo = GetOrCreateInfo(playerClientId); orCreateInfo.TimesRevivedThisLevel++; return Mathf.Max(1, ModConfig.ReviveHealth - (orCreateInfo.TimesRevivedThisLevel - 1) * ModConfig.ExtraHealthLostPerRevive); } public static void SetRemainingRevivesFromPlayerCount() { int num = 0; if (StartOfRound.Instance?.allPlayerScripts != null) { num = StartOfRound.Instance.allPlayerScripts.Count((PlayerControllerB p) => (Object)(object)p != (Object)null && p.isPlayerControlled); } if (!ModConfig.LimitedRevives) { ModState.RemainingRevives = int.MaxValue; } else if (ModConfig.FixedRevivesPerLevel > 0) { ModState.RemainingRevives = ModConfig.FixedRevivesPerLevel; } else { ModState.RemainingRevives = Mathf.RoundToInt((float)num * ModConfig.RevivesPerLevelMultiplier); } ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"Remaining revives for this level: {ModState.RemainingRevives}"); } } public static bool IsNetworkReady() { if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.CustomMessagingManager != null) { return NetworkManager.Singleton.IsListening; } return false; } public static float GetReviveValidationDistance(PlayerControllerB reviver) { if ((Object)(object)reviver == (Object)null) { return 0f; } float num = Mathf.Max(0.1f, reviver.grabDistance); float num2 = Mathf.Max(0.1f, ModConfig.MaxReviveDistance); return Mathf.Max(num, num2); } public static float GetTombReviveValidationDistance(PlayerControllerB reviver) { if ((Object)(object)reviver == (Object)null) { return 0f; } float num = Mathf.Max(0.1f, reviver.grabDistance); float num2 = Mathf.Max(0.1f, ModConfig.MaxReviveDistanceTomb); return Mathf.Max(num, num2); } public static bool IsReviverCloseEnough(PlayerControllerB reviver, Vector3 targetPosition) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)reviver == (Object)null) { return false; } float reviveValidationDistance = GetReviveValidationDistance(reviver); return IsReviverCloseEnoughInternal(reviver, targetPosition, reviveValidationDistance); } public static bool IsReviverCloseEnoughToTomb(PlayerControllerB reviver, Vector3 targetPosition) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)reviver == (Object)null) { return false; } float tombReviveValidationDistance = GetTombReviveValidationDistance(reviver); return IsReviverCloseEnoughInternal(reviver, targetPosition, tombReviveValidationDistance); } private static bool IsReviverCloseEnoughInternal(PlayerControllerB reviver, Vector3 targetPosition, float maxDistance) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_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_0075: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; Vector3 val2; if ((Object)(object)val != (Object)null && (Object)(object)val == (Object)(object)reviver && (Object)(object)reviver.gameplayCamera != (Object)null) { val2 = ((Component)reviver.gameplayCamera).transform.position; } else { if (!((Object)(object)((Component)reviver).transform != (Object)null)) { return false; } val2 = ((Component)reviver).transform.position + Vector3.up * 1.6f; maxDistance += 1.5f; } return Vector3.Distance(val2, targetPosition) <= maxDistance; } public static MaskedPlayerEnemy GetConvertedMaskedForPlayer(int playerClientId, bool requireDead = false) { if (!ModConfig.EnableMaskedPlayerRevive) { return null; } MaskedPlayerEnemy[] array = Object.FindObjectsOfType(); foreach (MaskedPlayerEnemy val in array) { if (!((Object)(object)val == (Object)null) && (!requireDead || MaskedConversionTracker.IsMaskedDead(val)) && TryResolveConvertedMaskedPlayer(val, out var playerClientId2, out var _) && playerClientId2 == playerClientId) { return val; } } return null; } public static MaskedPlayerEnemy GetConvertedMaskedCorpseForPlayer(int playerClientId) { return GetConvertedMaskedForPlayer(playerClientId, requireDead: true); } public static bool TryResolveConvertedMaskedPlayer(MaskedPlayerEnemy masked, out int playerClientId, out string source) { playerClientId = -1; source = "none"; if ((Object)(object)masked == (Object)null) { return false; } if (ModConfig.EnableMaskedPlayerRevive && MaskedConversionTracker.IsConvertedMasked(masked, out playerClientId)) { source = "InternalTag"; return true; } return false; } public static MaskedPlayerEnemy GetMaskedByNetworkObjectId(ulong networkObjectId) { if (networkObjectId == 0L) { return null; } if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.SpawnManager != null && NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(networkObjectId, out var value) && (Object)(object)value != (Object)null) { MaskedPlayerEnemy component = ((Component)value).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } component = ((Component)value).GetComponentInChildren(); if ((Object)(object)component != (Object)null) { return component; } } MaskedPlayerEnemy[] array = Object.FindObjectsOfType(); foreach (MaskedPlayerEnemy val in array) { if (!((Object)(object)val == (Object)null)) { NetworkObject component2 = ((Component)val).GetComponent(); if ((Object)(object)component2 != (Object)null && component2.NetworkObjectId == networkObjectId) { return val; } } } return null; } private static bool IsReviveableConvertedMaskedCorpse(MaskedPlayerEnemy masked) { int playerClientId; string source; if ((Object)(object)masked != (Object)null && MaskedConversionTracker.IsMaskedDead(masked)) { return TryResolveConvertedMaskedPlayer(masked, out playerClientId, out source); } return false; } internal static bool TryResolveConvertedMaskedPlayer(object clientMasked, out int maskedOwnerId, out string _) { throw new NotImplementedException(); } } public static class MaskedConversionTracker { internal sealed class PendingConversion { public int PlayerClientId; public MaskedOrigin Origin; public Vector3 Position; public float TimeRegistered; } private const float PendingLifetimeSeconds = 20f; private const string MaskedTriggerHostName = "UltimateReviveMaskedTrigger"; private static readonly List PendingConversions = new List(); private static ManualLogSource _log; public static int? GetPlayerIdForMasked(MaskedPlayerEnemy masked) { if ((Object)(object)masked == (Object)null) { return null; } if ((Object)(object)masked.mimickingPlayer != (Object)null) { return (int)masked.mimickingPlayer.playerClientId; } return null; } public static void SetLogSource(ManualLogSource logSource) { _log = logSource; } public static void Reset() { PendingConversions.Clear(); } public static bool HasPendingForPlayer(int playerClientId) { CleanupExpiredPending(); return PendingConversions.Any((PendingConversion x) => x.PlayerClientId == playerClientId); } public static void TagMaskedAsConverted(MaskedPlayerEnemy masked, int playerClientId, MaskedOrigin origin, string reason = null) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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) if (!((Object)(object)masked == (Object)null) && ModConfig.EnableMaskedPlayerRevive && playerClientId >= 0) { if (origin != MaskedOrigin.ConvertedByMaskItem && origin != MaskedOrigin.ConvertedByMaskedEnemy) { origin = MaskedOrigin.ConvertedByMaskedEnemy; } MaskedOriginInfo orAddInfo = GetOrAddInfo(masked); orAddInfo.Origin = origin; orAddInfo.FormerPlayerClientId = playerClientId; orAddInfo.TaggedAt = Time.time; PendingConversions.RemoveAll((PendingConversion x) => x.PlayerClientId == playerClientId); ulong networkObjectId = GetNetworkObjectId(masked); Vector3 deathPosition = (((Object)(object)((Component)masked).transform != (Object)null) ? ((Component)masked).transform.position : Vector3.zero); GeneralUtil.SetPlayerDeathState(playerClientId, PlayerDeathType.Masked, networkObjectId, deathPosition, string.IsNullOrWhiteSpace(reason) ? "MaskedTag:direct" : reason); ReviveInteractTriggerManager.ForceRefreshPlayer(playerClientId, string.IsNullOrWhiteSpace(reason) ? "MaskedTag:direct" : reason); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)string.Format("Tagged Masked {0} as {1} from player {2} ({3}).", networkObjectId, origin, playerClientId, string.IsNullOrWhiteSpace(reason) ? "direct" : reason)); } } } public static bool TryTagMaskedFromPending(MaskedPlayerEnemy masked) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_00a3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)masked == (Object)null || !ModConfig.EnableMaskedPlayerRevive) { return false; } CleanupExpiredPending(); if (PendingConversions.Count == 0) { return false; } PendingConversion pendingConversion = null; int mimicId = GetMimickingPlayerClientId(masked); if (mimicId >= 0) { pendingConversion = PendingConversions.FirstOrDefault((PendingConversion x) => x.PlayerClientId == mimicId); } if (pendingConversion == null && PendingConversions.Count == 1) { PendingConversion pendingConversion2 = PendingConversions[0]; Vector3 val = (((Object)(object)((Component)masked).transform != (Object)null) ? ((Component)masked).transform.position : pendingConversion2.Position); Vector3 val2 = pendingConversion2.Position - val; if (((Vector3)(ref val2)).sqrMagnitude <= 900f) { pendingConversion = pendingConversion2; } } if (pendingConversion == null) { return false; } ApplyConvertedTag(masked, GetOrAddInfo(masked), pendingConversion); return true; } public static void RegisterPending(PlayerControllerB player, MaskedOrigin origin) { //IL_0048: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.EnableMaskedPlayerRevive && !((Object)(object)player == (Object)null) && (origin == MaskedOrigin.ConvertedByMaskItem || origin == MaskedOrigin.ConvertedByMaskedEnemy)) { int playerClientId = (int)player.playerClientId; Vector3 val = (((Object)(object)((Component)player).transform != (Object)null) ? ((Component)player).transform.position : Vector3.zero); PendingConversions.RemoveAll((PendingConversion x) => x.PlayerClientId == playerClientId); PendingConversions.Add(new PendingConversion { PlayerClientId = playerClientId, Origin = origin, Position = val, TimeRegistered = Time.time }); GeneralUtil.SetPlayerDeathState(playerClientId, PlayerDeathType.Masked, 0uL, val, $"MaskedPending:{origin}"); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"Registered pending Masked conversion: player={playerClientId}, origin={origin}."); } } } public static MaskedPlayerEnemy GetMaskedForPlayer(int playerClientId) { MaskedPlayerEnemy[] array = Object.FindObjectsOfType(); foreach (MaskedPlayerEnemy val in array) { MaskedOriginInfo component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null && component.FormerPlayerClientId == playerClientId && (component.Origin == MaskedOrigin.ConvertedByMaskItem || component.Origin == MaskedOrigin.ConvertedByMaskedEnemy)) { return val; } } return null; } public static void TagMaskedOnSpawn(MaskedPlayerEnemy masked) { if ((Object)(object)masked == (Object)null || !ModConfig.EnableMaskedPlayerRevive) { return; } MaskedOriginInfo orAddInfo = GetOrAddInfo(masked); if (orAddInfo.Origin == MaskedOrigin.ConvertedByMaskItem || orAddInfo.Origin == MaskedOrigin.ConvertedByMaskedEnemy || TryTagMaskedFromPending(masked)) { return; } if (orAddInfo.Origin == MaskedOrigin.Unknown) { if (!TryTagFromMimickingPlayer(masked, orAddInfo)) { orAddInfo.Origin = MaskedOrigin.NaturalSpawn; orAddInfo.FormerPlayerClientId = -1; orAddInfo.TaggedAt = Time.time; } } else if (orAddInfo.Origin == MaskedOrigin.NaturalSpawn) { TryTagFromMimickingPlayer(masked, orAddInfo); } } private static bool TryTagFromMimickingPlayer(MaskedPlayerEnemy masked, MaskedOriginInfo info) { int mimickingPlayerClientId = GetMimickingPlayerClientId(masked); if (mimickingPlayerClientId < 0) { return false; } PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(mimickingPlayerClientId); if ((Object)(object)playerByClientId == (Object)null) { return false; } EnemyAI redirectToEnemy = playerByClientId.redirectToEnemy; MaskedPlayerEnemy val = (MaskedPlayerEnemy)(object)((redirectToEnemy is MaskedPlayerEnemy) ? redirectToEnemy : null); if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)masked) { return false; } if (!playerByClientId.isPlayerDead && (Object)(object)val != (Object)(object)masked) { return false; } TagMaskedAsConverted(masked, mimickingPlayerClientId, MaskedOrigin.ConvertedByMaskItem, "TagMasked:mimickingPlayerFallback"); return true; } public static bool IsConvertedMasked(MaskedPlayerEnemy masked, out int playerClientId) { playerClientId = -1; if ((Object)(object)masked == (Object)null || !ModConfig.EnableMaskedPlayerRevive) { return false; } MaskedOriginInfo component = ((Component)masked).GetComponent(); if ((Object)(object)component == (Object)null) { TagMaskedOnSpawn(masked); component = ((Component)masked).GetComponent(); } if ((Object)(object)component == (Object)null) { return false; } if (component.Origin != MaskedOrigin.ConvertedByMaskItem && component.Origin != MaskedOrigin.ConvertedByMaskedEnemy) { return false; } playerClientId = component.FormerPlayerClientId; return playerClientId >= 0; } public static bool IsMaskedDead(MaskedPlayerEnemy masked) { if ((Object)(object)masked != (Object)null) { return ((EnemyAI)masked).isEnemyDead; } return false; } public static ulong GetNetworkObjectId(MaskedPlayerEnemy masked) { if ((Object)(object)masked == (Object)null) { return 0uL; } if ((Object)(object)((masked != null) ? ((NetworkBehaviour)masked).NetworkObject : null) == (Object)null) { return 0uL; } return ((NetworkBehaviour)masked).NetworkObject.NetworkObjectId; } public static void ForgetPlayer(int playerClientId) { PendingConversions.RemoveAll((PendingConversion x) => x.PlayerClientId == playerClientId); } private static void ApplyConvertedTag(MaskedPlayerEnemy masked, MaskedOriginInfo info, PendingConversion pending) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) info.Origin = pending.Origin; info.FormerPlayerClientId = pending.PlayerClientId; info.TaggedAt = Time.time; ulong networkObjectId = GetNetworkObjectId(masked); Vector3 deathPosition = (((Object)(object)((Component)masked).transform != (Object)null) ? ((Component)masked).transform.position : pending.Position); GeneralUtil.SetPlayerDeathState(pending.PlayerClientId, PlayerDeathType.Masked, networkObjectId, deathPosition, "MaskedTagAssigned"); ReviveInteractTriggerManager.ForceRefreshPlayer(pending.PlayerClientId, "MaskedTagAssigned"); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"Tagged Masked {GetNetworkObjectId(masked)} as {pending.Origin} from player {pending.PlayerClientId}."); } } private static void RemoveMaskedTriggerChild(MaskedPlayerEnemy masked) { if (!((Object)(object)masked == (Object)null) && !((Object)(object)((Component)masked).transform == (Object)null)) { Transform val = ((Component)masked).transform.Find("UltimateReviveMaskedTrigger"); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } } private static MaskedOriginInfo GetOrAddInfo(MaskedPlayerEnemy masked) { MaskedOriginInfo maskedOriginInfo = ((Component)masked).GetComponent(); if ((Object)(object)maskedOriginInfo == (Object)null) { maskedOriginInfo = ((Component)masked).gameObject.AddComponent(); } return maskedOriginInfo; } private static int GetMimickingPlayerClientId(MaskedPlayerEnemy masked) { try { PlayerControllerB value = Traverse.Create((object)masked).Field("mimickingPlayer").GetValue(); if ((Object)(object)value != (Object)null) { return (int)value.playerClientId; } } catch { } return -1; } private static void CleanupExpiredPending() { float now = Time.time; PendingConversions.RemoveAll((PendingConversion x) => now - x.TimeRegistered > 20f); } } public enum MaskedOrigin { Unknown, NaturalSpawn, ConvertedByMaskItem, ConvertedByMaskedEnemy } public sealed class MaskedOriginInfo : MonoBehaviour { public MaskedOrigin Origin; public int FormerPlayerClientId = -1; public float TaggedAt; } public static class ModConfig { public const string DefaultDeathTombBundlePath = "UltimateRevive/bundles/sm_tombstone_3_dark_rip.bundle"; public const string DefaultDeathTombPrefabName = "sm_tombstone_3_dark_rip"; public static float ReviveTime; public static bool CanPickUpBodies; public static float DeadBodyWeight; public static bool CanReviveTeleportedBodies; public static int ReviveHealth; public static int ExtraHealthLostPerRevive; public static bool LimitedRevives; public static float RevivesPerLevelMultiplier; public static int FixedRevivesPerLevel; public static bool InfiniteReviveTime; public static int TimeUntilCannotBeRevived; public static float MaxReviveDistance; public static float MaxReviveDistanceTomb; public static bool EnableMaskedPlayerRevive; public static bool EnableDeathTombFallback; public static bool EnableDeathTombCollider; public static string DeathTombAssetBundlePath; public static string DeathTombPrefabName; public static float DeathTombGroundOffset; public static float DeathTombSpawnHeight; public static bool EnableDebugLogs; public static bool DebugLogging { get; internal set; } public static void Bind(ConfigFile config) { ReviveTime = config.Bind("Revive", "ReviveTime", 5f, "How long, in seconds, the revive button must be held.").Value; CanPickUpBodies = config.Bind("Bodies", "CanPickUpBodies", true, "If false, pressing interact on bodies is blocked so the revive prompt is easier to use.").Value; DeadBodyWeight = config.Bind("Bodies", "DeadBodyWeight", 1.35f, "Weight multiplier applied to dead bodies.").Value; CanReviveTeleportedBodies = config.Bind("Rules", "CanReviveTeleportedBodies", true, "If false, bodies teleported back to the ship cannot be revived.").Value; ReviveHealth = config.Bind("Rules", "HealthYouReviveWith", 35, "Base health after revive.").Value; ExtraHealthLostPerRevive = config.Bind("Rules", "ExtraHealthLostPerRevive", 5, "Additional health penalty each time the same player is revived in the same round.").Value; LimitedRevives = config.Bind("Rules", "LimitAmountOfRevives", true, "If true, revives are limited per level.").Value; RevivesPerLevelMultiplier = config.Bind("Rules", "RevivesPerLevelMultiplier", 1.25f, "Revives per level = controlled players * this value, unless FixedRevivesPerLevel is above 0.").Value; FixedRevivesPerLevel = config.Bind("Rules", "FixedRevivesPerLevel", 0, "Overrides RevivesPerLevelMultiplier when above 0.").Value; InfiniteReviveTime = config.Bind("Rules", "InfiniteReviveTime", false, "If true, players can be revived no matter how long they have been dead.").Value; TimeUntilCannotBeRevived = config.Bind("Rules", "TimeUntilCannotBeRevived", 120, "How long someone can be dead and still be revived, in seconds.").Value; MaxReviveDistance = config.Bind("Revive", "MaxReviveDistance", 3f, "Maximum distance from reviver camera to body.").Value; MaxReviveDistanceTomb = config.Bind("Revive", "MaxReviveDistanceTomb", 4.5f, "Maximum distance from reviver camera to tomb revive source.").Value; EnableMaskedPlayerRevive = config.Bind("Masked", "EnableMaskedPlayerRevive", true, "If true, a player converted into a Masked by a mask item or by a Masked enemy can be revived after the converted Masked is killed.").Value; EnableDeathTombFallback = config.Bind("DeathMarker", "EnableDeathTombFallback", true, "If true, spawn a 3D tomb marker at the last death position when the latest revive source is missing.").Value; EnableDeathTombCollider = config.Bind("DeathMarker", "EnableDeathTombCollider", true, "If false, the death tomb will have no collision, including colliders already present on bundle prefabs.").Value; DeathTombAssetBundlePath = config.Bind("DeathMarker", "DeathTombAssetBundlePath", "UltimateRevive/bundles/sm_tombstone_3_dark_rip.bundle", "Optional absolute or relative path to an AssetBundle containing your tomb prefab.\n Valid options for this mod:\n -UltimateRevive/bundles/sm_tombstone_3_dark_rip.bundle.\n -UltimateRevive/bundles/sm_tombstone_3_dark_text.bundle.\n -UltimateRevive/bundles/sm_tombstone_3_light_rip.bundle.\n -UltimateRevive/bundles/sm_tombstone_3_light_text.bundle.").Value; DeathTombPrefabName = config.Bind("DeathMarker", "DeathTombPrefabName", "sm_tombstone_3_dark_rip", "Prefab name inside the AssetBundle to instantiate as tomb marker.\n Valid options for this mod:\n -sm_tombstone_3_dark_rip.\n -sm_tombstone_3_dark_text.\n -sm_tombstone_3_light_rip.\n -sm_tombstone_3_light_text.").Value; DeathTombGroundOffset = config.Bind("DeathMarker", "DeathTombGroundOffset", 0.02f, "Vertical offset applied above detected ground.").Value; DeathTombSpawnHeight = config.Bind("DeathMarker", "DeathTombSpawnHeight", 4f, "Height above death position used for downward ground detection and gravity settle.").Value; EnableDebugLogs = config.Bind("Debug", "EnableDebugLogs", false, "If true, emit local-only debug logs (not synchronized from host).").Value; } public static void ApplySyncedConfig(float reviveTime, bool canPickUpBodies, float deadBodyWeight, bool canReviveTeleportedBodies, int reviveHealth, int extraHealthLostPerRevive, bool limitedRevives, float revivesPerLevelMultiplier, int fixedRevivesPerLevel, bool infiniteReviveTime, int timeUntilCannotBeRevived, float maxReviveDistance, float maxReviveDistanceTomb, bool enableMaskedPlayerRevive, bool enableDeathTombFallback, bool enableDeathTombCollider, string deathTombAssetBundlePath, string deathTombPrefabName, float deathTombGroundOffset, float deathTombSpawnHeight) { ReviveTime = reviveTime; CanPickUpBodies = canPickUpBodies; DeadBodyWeight = deadBodyWeight; CanReviveTeleportedBodies = canReviveTeleportedBodies; ReviveHealth = reviveHealth; ExtraHealthLostPerRevive = extraHealthLostPerRevive; LimitedRevives = limitedRevives; RevivesPerLevelMultiplier = revivesPerLevelMultiplier; FixedRevivesPerLevel = fixedRevivesPerLevel; InfiniteReviveTime = infiniteReviveTime; TimeUntilCannotBeRevived = timeUntilCannotBeRevived; MaxReviveDistance = maxReviveDistance; MaxReviveDistanceTomb = maxReviveDistanceTomb; EnableMaskedPlayerRevive = enableMaskedPlayerRevive; EnableDeathTombFallback = enableDeathTombFallback; EnableDeathTombCollider = enableDeathTombCollider; DeathTombAssetBundlePath = deathTombAssetBundlePath; DeathTombPrefabName = deathTombPrefabName; DeathTombGroundOffset = deathTombGroundOffset; DeathTombSpawnHeight = deathTombSpawnHeight; DeathMarkerManager.InvalidateBundleCache(); } } public static class ModState { public static bool Active; public static int RemainingRevives = int.MaxValue; public static readonly List PlayerInfos = new List(); public static void Reset() { Active = false; RemainingRevives = int.MaxValue; PlayerInfos.Clear(); MaskedConversionTracker.Reset(); DeathMarkerManager.Reset(); ReviveInteractTriggerManager.Reset(); } } public sealed class PlayerReviveInfo { public int PlayerClientId; public bool HasBeenTeleported; public float TimeDiedAt; public int TimesRevivedThisLevel; public PlayerDeathType LastDeathType; public ulong LastDeathNetworkObjectId; public Vector3 LastDeathPosition; public bool HasLastDeathPosition; } public enum PlayerDeathType { Unknown, Body, Masked } [BepInPlugin("chaps.UltimateRevive", "UltimateRevive", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { private sealed class RuntimeDriver : MonoBehaviour { } public const string ModGuid = "chaps.UltimateRevive"; public const string ModName = "UltimateRevive"; public const string ModVersion = "1.1.0"; internal static ManualLogSource Log; internal static ReviveInputActions InputActions; private Harmony _harmony; private bool _isQuitting; private static RuntimeDriver _runtimeDriver; private float _nextMaintenanceAt; private string _lastReviveBindingPath; public static Plugin Instance { get; private set; } internal static InputAction ReviveAction => InputActions?.Revive; private void Awake() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); InputActions = new ReviveInputActions(); ModConfig.Bind(((BaseUnityPlugin)this).Config); GeneralUtil.SetLogSource(Log); ReviveNetwork.SetLogSource(Log); ReviveLogic.SetLogSource(Log); MaskedConversionTracker.SetLogSource(Log); DeathMarkerManager.SetLogSource(Log); _harmony = new Harmony("chaps.UltimateRevive"); try { _harmony.PatchAll(); VerifyHarmonyHooks(); } catch (Exception arg) { Log.LogError((object)$"Harmony patching failed: {arg}"); } InteractTriggerPatch.TryPatch(_harmony); Log.LogInfo((object)"UltimateRevive 1.1.0 loaded."); } private void Update() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_0075: Unknown result type (might be due to invalid IL or missing references) try { if (Time.unscaledTime < _nextMaintenanceAt) { return; } _nextMaintenanceAt = Time.unscaledTime + 1f; ReviveNetwork.TryRegisterHandlers(); ReviveNetwork.SyncConfigForNewClients(); if (InputActions?.Revive == null) { return; } object obj; if (InputActions.Revive.bindings.Count <= 0) { obj = null; } else { InputBinding val = InputActions.Revive.bindings[0]; obj = ((InputBinding)(ref val)).effectivePath; } string text = (string)obj; if (_lastReviveBindingPath != text) { InputActions.RefreshReviveAction(); _lastReviveBindingPath = text; ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("[UltimateRevive] Revive binding changed, action refreshed: " + text)); } } } catch (Exception arg) { Log.LogError((object)$"Runtime Update failed: {arg}"); } } private void OnDestroy() { if (_isQuitting) { ReviveNetwork.UnregisterHandlers(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } private void OnApplicationQuit() { _isQuitting = true; } internal static void DebugLog(string message) { if (ModConfig.EnableDebugLogs) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)message); } } } internal static string GetReviveBindingLabel() { InputAction reviveAction = ReviveAction; if (reviveAction == null) { return "key"; } string bindingDisplayString = InputActionRebindingExtensions.GetBindingDisplayString(reviveAction, (DisplayStringOptions)0, (string)null); if (!string.IsNullOrWhiteSpace(bindingDisplayString)) { return bindingDisplayString; } return "key"; } private void VerifyHarmonyHooks() { VerifyPatched(typeof(PlayerControllerB), "Update"); VerifyPatched(typeof(PlayerControllerB), "SetHoverTipAndCurrentInteractTrigger"); VerifyPatched(typeof(PlayerControllerB), "Interact_performed"); VerifyPatched(typeof(PlayerControllerB), "KillPlayerClientRpc"); VerifyPatched(typeof(StartOfRound), "Start"); VerifyPatched(typeof(StartOfRound), "openingDoorsSequence"); } private void VerifyPatched(Type type, string methodName) { MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null); if (methodInfo == null) { Log.LogWarning((object)("Harmony target missing: " + type.Name + "." + methodName)); return; } Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); if (patchInfo != null && ((patchInfo.Prefixes != null && patchInfo.Prefixes.Any((Patch p) => p.owner == "chaps.UltimateRevive")) || (patchInfo.Postfixes != null && patchInfo.Postfixes.Any((Patch p) => p.owner == "chaps.UltimateRevive")) || (patchInfo.Transpilers != null && patchInfo.Transpilers.Any((Patch p) => p.owner == "chaps.UltimateRevive")) || (patchInfo.Finalizers != null && patchInfo.Finalizers.Any((Patch p) => p.owner == "chaps.UltimateRevive")))) { Log.LogInfo((object)("Harmony hook active: " + type.Name + "." + methodName)); } else { Log.LogWarning((object)("Harmony hook NOT active: " + type.Name + "." + methodName)); } } private static void EnsureRuntimeDriver() { //IL_0025: 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_0030: Expected O, but got Unknown if (!((Object)(object)_runtimeDriver != (Object)null) || !((Object)(object)((Component)_runtimeDriver).gameObject != (Object)null)) { GameObject val = new GameObject("UltimateRevive.RuntimeDriver"); Object.DontDestroyOnLoad((Object)val); _runtimeDriver = val.AddComponent(); } } internal static void RunCoroutineSafe(IEnumerator routine) { if (routine == null) { return; } try { if ((Object)(object)Instance != (Object)null && (Object)(object)((Component)Instance).gameObject != (Object)null && ((Behaviour)Instance).isActiveAndEnabled) { ((MonoBehaviour)Instance).StartCoroutine(routine); return; } if ((Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)((Component)StartOfRound.Instance).gameObject != (Object)null && ((Behaviour)StartOfRound.Instance).isActiveAndEnabled) { ((MonoBehaviour)StartOfRound.Instance).StartCoroutine(routine); return; } EnsureRuntimeDriver(); if ((Object)(object)_runtimeDriver != (Object)null && (Object)(object)((Component)_runtimeDriver).gameObject != (Object)null && ((Behaviour)_runtimeDriver).isActiveAndEnabled) { ((MonoBehaviour)_runtimeDriver).StartCoroutine(routine); return; } ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"[UltimateRevive] No active MonoBehaviour available for coroutine."); } } catch (Exception arg) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogError((object)$"[UltimateRevive] Failed to start coroutine: {arg}"); } } } } public static class ReviveAPI { public static bool CanRevive(RagdollGrabbableObject body) { if ((Object)(object)body == (Object)null) { return false; } if (!GeneralUtil.TryGetBodyOwner(body, out var targetPlayerClientId, out var _)) { return false; } return CanRevivePlayer(targetPlayerClientId); } public static bool CanRevivePlayer(int targetPlayerClientId) { PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(targetPlayerClientId); if (PassesGlobalRules(targetPlayerClientId, playerByClientId)) { return HasRevivableSource(targetPlayerClientId); } return false; } public static bool CanReviveMasked(MaskedPlayerEnemy masked) { if ((Object)(object)masked == (Object)null || !ModConfig.EnableMaskedPlayerRevive) { return false; } if (!GeneralUtil.TryResolveConvertedMaskedPlayer(masked, out var playerClientId, out var _)) { return false; } return CanRevivePlayer(playerClientId); } public static void RevivePlayer(int targetPlayerClientId) { ReviveNetwork.RequestRevive(targetPlayerClientId); } private static bool PassesGlobalRules(int targetPlayerClientId, PlayerControllerB targetPlayer) { if (!ModState.Active) { return false; } if ((Object)(object)targetPlayer == (Object)null || !targetPlayer.isPlayerDead) { return false; } if (ModConfig.LimitedRevives && ModState.RemainingRevives <= 0) { return false; } if (!ModConfig.CanReviveTeleportedBodies && GeneralUtil.HasPlayerTeleported(targetPlayerClientId)) { return false; } if (!ModConfig.InfiniteReviveTime && Time.time - GeneralUtil.GetPlayerDiedAtTime(targetPlayerClientId) > (float)ModConfig.TimeUntilCannotBeRevived) { return false; } return true; } private static bool HasRevivableSource(int targetPlayerClientId) { PlayerDeathType playerLastDeathType = GeneralUtil.GetPlayerLastDeathType(targetPlayerClientId); ulong playerLastDeathNetworkObjectId = GeneralUtil.GetPlayerLastDeathNetworkObjectId(targetPlayerClientId); Vector3 position; if (playerLastDeathType == PlayerDeathType.Masked) { if (!ModConfig.EnableMaskedPlayerRevive) { return false; } MaskedPlayerEnemy val = ((playerLastDeathNetworkObjectId != 0L) ? GeneralUtil.GetMaskedByNetworkObjectId(playerLastDeathNetworkObjectId) : null); if ((Object)(object)val == (Object)null) { val = GeneralUtil.GetConvertedMaskedCorpseForPlayer(targetPlayerClientId); } if ((Object)(object)val != (Object)null) { return true; } if (ModConfig.EnableDeathTombFallback) { return GeneralUtil.TryGetPlayerLastDeathPosition(targetPlayerClientId, out position); } return false; } if ((Object)(object)((playerLastDeathNetworkObjectId != 0L) ? GeneralUtil.GetBodyByNetworkObjectId(playerLastDeathNetworkObjectId) : GeneralUtil.GetBodyForPlayer(targetPlayerClientId)) != (Object)null) { return true; } if (ModConfig.EnableDeathTombFallback) { return GeneralUtil.TryGetPlayerLastDeathPosition(targetPlayerClientId, out position); } return false; } } public sealed class ReviveInputActions : LcInputActions { [InputAction(/*Could not decode attribute arguments.*/)] public InputAction Revive { get; set; } public void RefreshReviveAction() { InputAction revive = Revive; if (revive != null) { revive.Disable(); } InputAction revive2 = Revive; if (revive2 != null) { revive2.Enable(); } } } public static class ReviveInteractTriggerManager { private enum ReviveSourceKind { None, Body, Masked, Tomb } private sealed class ReviveTriggerEntry { public int TargetPlayerId; public ReviveSourceKind SourceKind; public ulong SourceObjectId; public GameObject RootObject; public GameObject TriggerHostObject; public InteractTrigger Trigger; public Collider AddedCollider; public bool OwnsTrigger; public bool OwnsTriggerHostObject; public bool ChangedLayer; public int OriginalLayer; public GameObject LayerAdjustedObject; public Transform FollowTransform; public Vector3 StaticPosition; } private const string CustomBodyTriggerHostName = "UltimateReviveBodyTrigger"; private const string CustomTombTriggerHostName = "UltimateReviveTombTrigger"; private const float HoverGraceSeconds = 0.45f; private static readonly Vector3 MaskedTriggerAliveLocalOffset = new Vector3(0f, 0.9f, 0f); private static readonly Vector3 MaskedTriggerDeadLocalOffset = new Vector3(0f, 0.35f, 0f); private const float MaskedTriggerDeadForwardShift = 0.95f; private const float MaskedTriggerDeadVerticalLift = 0.35f; private static readonly Dictionary EntriesByPlayer = new Dictionary(); private static readonly Dictionary TriggerInstanceToPlayer = new Dictionary(); private static readonly string[] PreferredPlayerTriggerFieldNames = new string[4] { "hoveringOverTrigger", "currentInteractTrigger", "currentTriggerInRange", "hoveredOverTrigger" }; private static readonly BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static FieldInfo[] _cachedPlayerTriggerFields; private static PropertyInfo[] _cachedPlayerTriggerProperties; private static int _lastLoggedHoverTarget = -2; private static ReviveSourceKind _lastLoggedHoverKind = ReviveSourceKind.None; private static string _lastLoggedHoverPath = string.Empty; private static bool _lastLoggedHoverCanRevive; private static bool _hadHover; private static int _lastHoveredTargetId = -1; private static float _lastHoveredSeenAt = -999f; private static readonly Dictionary _lastResolveDiagnosticsByPlayer = new Dictionary(); private static readonly Dictionary _lastTickDiagnosticsByPlayer = new Dictionary(); private static readonly Dictionary _lastForceDiagnosticsByPlayer = new Dictionary(); private static readonly Dictionary _lastObservedTriggerDiagnosticsByPlayer = new Dictionary(); private static string _lastTickGateDiagnostic = string.Empty; public static void WarmUpCache() { CachePlayerTriggerMembers(); FieldInfo[] cachedPlayerTriggerFields = _cachedPlayerTriggerFields; Plugin.DebugLog($"[ReviveTrigger] cache warmed: fields={((cachedPlayerTriggerFields != null) ? cachedPlayerTriggerFields.Length : 0)}"); } public static void Tick() { //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; _ = instance?.mapScreen; PlayerControllerB[] array = instance?.allPlayerScripts; PlayerControllerB[] array2; if (array != null) { array2 = array; foreach (PlayerControllerB val in array2) { if (!((Object)(object)val == (Object)null)) { int playerClientId = (int)val.playerClientId; if (DeathMarkerManager.HasActiveMarker(playerClientId) && !val.isPlayerDead) { DeathMarkerManager.ClearMarker(playerClientId); } } } } if (!ModState.Active || StartOfRound.Instance?.allPlayerScripts == null) { LogTickGateDiagnostic($"gate=blocked active={ModState.Active} hasStartOfRound={(Object)(object)StartOfRound.Instance != (Object)null} hasPlayers={StartOfRound.Instance?.allPlayerScripts != null} trackedInfos={ModState.PlayerInfos.Count}"); Reset(); return; } LogTickGateDiagnostic($"gate=running players={StartOfRound.Instance.allPlayerScripts.Length} trackedInfos={ModState.PlayerInfos.Count}"); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; HashSet seenPlayerIds = new HashSet(); array2 = allPlayerScripts; foreach (PlayerControllerB val2 in array2) { if ((Object)(object)val2 == (Object)null) { continue; } int num = (int)val2.playerClientId; PlayerDeathType playerLastDeathType = GeneralUtil.GetPlayerLastDeathType(num); bool flag = !val2.isPlayerDead && playerLastDeathType != 0 && !val2.isPlayerControlled; if (flag) { LogTickDiagnostic(num, $"overrideAliveSlot trackedDeath={playerLastDeathType} isControlled={val2.isPlayerControlled}"); } if (!val2.isPlayerDead && !flag) { seenPlayerIds.Add(num); RemoveEntry(num); LogTickDiagnostic(num, $"skipAlive trackedDeath={playerLastDeathType} isControlled={val2.isPlayerControlled}"); continue; } seenPlayerIds.Add(num); if (!TryResolveCurrentReviveSource(num, out var sourceKind, out var sourceObjectId, out var followTransform, out var staticPosition)) { RemoveEntry(num); LogTickDiagnostic(num, "resolveFailed from=allPlayerScripts"); } else { EnsureOrUpdateEntry(num, sourceKind, sourceObjectId, followTransform, staticPosition); LogTickDiagnostic(num, $"resolveSuccess from=allPlayerScripts source={sourceKind} obj={sourceObjectId}"); } } foreach (PlayerReviveInfo playerInfo in ModState.PlayerInfos) { if (playerInfo == null) { continue; } int playerClientId2 = playerInfo.PlayerClientId; if (seenPlayerIds.Contains(playerClientId2)) { continue; } if (playerInfo.LastDeathType == PlayerDeathType.Unknown) { RemoveEntry(playerClientId2); LogTickDiagnostic(playerClientId2, "skipTrackedUnknown"); continue; } seenPlayerIds.Add(playerClientId2); if (!TryResolveCurrentReviveSource(playerClientId2, out var sourceKind2, out var sourceObjectId2, out var followTransform2, out var staticPosition2)) { RemoveEntry(playerClientId2); LogTickDiagnostic(playerClientId2, "resolveFailed from=trackedInfos"); } else { EnsureOrUpdateEntry(playerClientId2, sourceKind2, sourceObjectId2, followTransform2, staticPosition2); LogTickDiagnostic(playerClientId2, $"resolveSuccess from=trackedInfos source={sourceKind2} obj={sourceObjectId2}"); } } foreach (int item in EntriesByPlayer.Keys.Where((int id) => !seenPlayerIds.Contains(id)).ToList()) { RemoveEntry(item); } } public static void Reset() { foreach (int item in EntriesByPlayer.Keys.ToList()) { RemoveEntry(item); } EntriesByPlayer.Clear(); TriggerInstanceToPlayer.Clear(); _lastResolveDiagnosticsByPlayer.Clear(); _lastTickDiagnosticsByPlayer.Clear(); _lastForceDiagnosticsByPlayer.Clear(); _lastObservedTriggerDiagnosticsByPlayer.Clear(); _lastTickGateDiagnostic = string.Empty; _lastHoveredTargetId = -1; _lastHoveredSeenAt = -999f; } public static void ForceRefreshPlayer(int playerId, string reason = null) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (ModState.Active) { if (!TryResolveCurrentReviveSource(playerId, out var sourceKind, out var sourceObjectId, out var followTransform, out var staticPosition)) { RemoveEntry(playerId); LogForceDiagnostic(playerId, "result=none reason=" + (string.IsNullOrWhiteSpace(reason) ? "unspecified" : reason)); } else { EnsureOrUpdateEntry(playerId, sourceKind, sourceObjectId, followTransform, staticPosition); LogForceDiagnostic(playerId, string.Format("result={0} obj={1} reason={2}", sourceKind, sourceObjectId, string.IsNullOrWhiteSpace(reason) ? "unspecified" : reason)); } } } public static bool TryGetHoveredReviveTarget(PlayerControllerB reviver, out int targetPlayerId, out string reason, out bool canRevive) { targetPlayerId = -1; reason = "no revive trigger"; canRevive = false; if (!TryGetHoveredEntry(reviver, out var entry)) { if (_hadHover) { _hadHover = false; _lastLoggedHoverTarget = -2; _lastLoggedHoverKind = ReviveSourceKind.None; _lastLoggedHoverPath = string.Empty; _lastLoggedHoverCanRevive = false; Plugin.DebugLog("[ReviveHover] cleared"); } return false; } targetPlayerId = entry.TargetPlayerId; canRevive = EvaluateCanRevive(entry, reviver, out var resolvedTargetId, out reason); if (resolvedTargetId >= 0) { targetPlayerId = resolvedTargetId; } string text = ((entry.SourceKind == ReviveSourceKind.Body) ? "vanilla-body" : "custom"); if (entry.SourceKind != ReviveSourceKind.Body && ((Object)(object)entry.Trigger == (Object)null || !TriggerInstanceToPlayer.ContainsKey(((Object)entry.Trigger).GetInstanceID()))) { text = "unmapped"; } if (!_hadHover || _lastLoggedHoverTarget != targetPlayerId || _lastLoggedHoverKind != entry.SourceKind || _lastLoggedHoverPath != text || _lastLoggedHoverCanRevive != canRevive) { _hadHover = true; _lastLoggedHoverTarget = targetPlayerId; _lastLoggedHoverKind = entry.SourceKind; _lastLoggedHoverPath = text; _lastLoggedHoverCanRevive = canRevive; Plugin.DebugLog($"[ReviveHover] player={targetPlayerId} source={entry.SourceKind} path={text} canRevive={canRevive} reason={reason}"); } return true; } public static bool IsHoveringTriggerForTarget(PlayerControllerB reviver, int targetPlayerId) { if (targetPlayerId < 0) { return false; } if (!TryGetHoveredEntry(reviver, out var entry)) { return false; } if (entry != null) { return entry.TargetPlayerId == targetPlayerId; } return false; } public static bool IsHoveringReviveTrigger(PlayerControllerB reviver) { ReviveTriggerEntry entry; return TryGetHoveredEntry(reviver, out entry); } private static void EnsureOrUpdateEntry(int playerId, ReviveSourceKind sourceKind, ulong sourceObjectId, Transform followTransform, Vector3 staticPosition) { //IL_009b: 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) if (!TryResolveSourceHostObject(playerId, sourceKind, sourceObjectId, followTransform, out var hostObject) || (Object)(object)hostObject == (Object)null) { RemoveEntry(playerId); return; } if (!EntriesByPlayer.TryGetValue(playerId, out var value) || value == null || (Object)(object)value.Trigger == (Object)null || (Object)(object)value.RootObject == (Object)null || (Object)(object)value.RootObject != (Object)(object)hostObject || value.SourceKind != sourceKind || value.SourceObjectId != sourceObjectId) { RemoveEntry(playerId); value = CreateEntry(playerId, sourceKind, sourceObjectId, hostObject); if (value == null) { return; } EntriesByPlayer[playerId] = value; } value.FollowTransform = followTransform; value.StaticPosition = staticPosition; if (sourceKind != ReviveSourceKind.Body) { ConfigureTrigger(value.Trigger, playerId, sourceKind); } if (sourceKind == ReviveSourceKind.Masked) { UpdateMaskedTriggerAnchor(value); } } private static ReviveTriggerEntry CreateEntry(int playerId, ReviveSourceKind sourceKind, ulong sourceObjectId, GameObject hostObject) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hostObject == (Object)null) { return null; } switch (sourceKind) { case ReviveSourceKind.Body: return CreateBodyEntryUsingVanillaTrigger(playerId, sourceObjectId, hostObject); case ReviveSourceKind.Masked: return CreateMaskedEntryUsingChildTrigger(playerId, sourceObjectId, hostObject); case ReviveSourceKind.Tomb: return CreateTombEntryUsingChildTrigger(playerId, sourceObjectId, hostObject); default: { bool flag = false; InteractTrigger obj = hostObject.GetComponent(); bool flag2 = (Object)(object)obj == (Object)null; if (obj == null) { obj = hostObject.AddComponent(); } InteractTrigger val = obj; Collider val2 = null; if (!HasUsableInteractCollider(hostObject)) { SphereCollider obj2 = hostObject.AddComponent(); ((Collider)obj2).isTrigger = true; obj2.radius = 0.8f; obj2.center = new Vector3(0f, 0.9f, 0f); val2 = (Collider)(object)obj2; } int num = LayerMask.NameToLayer("InteractableObject"); bool changedLayer = false; int layer = hostObject.layer; if (num >= 0 && hostObject.layer != num) { hostObject.layer = num; changedLayer = true; } ConfigureTrigger(val, playerId, sourceKind); RegisterTriggerMapping(val, playerId, sourceKind, hostObject); Collider component = hostObject.GetComponent(); bool flag3 = HasUsableInteractCollider(hostObject); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[ReviveTrigger] attached source={sourceKind} player={playerId} host={((Object)hostObject).name} triggerHost={((Object)hostObject).name} ownsTrigger={flag2} ownsHost={flag} addedCollider={(Object)(object)val2 != (Object)null} hasCollider={(Object)(object)component != (Object)null} usableCollider={flag3} triggerId={((Object)val).GetInstanceID()} layer={hostObject.layer}"); } return new ReviveTriggerEntry { TargetPlayerId = playerId, SourceKind = sourceKind, SourceObjectId = sourceObjectId, RootObject = hostObject, TriggerHostObject = hostObject, Trigger = val, AddedCollider = val2, OwnsTrigger = flag2, OwnsTriggerHostObject = flag, ChangedLayer = changedLayer, OriginalLayer = layer, LayerAdjustedObject = hostObject, FollowTransform = null, StaticPosition = Vector3.zero }; } } } private static ReviveTriggerEntry CreateMaskedEntryUsingChildTrigger(int playerId, ulong sourceObjectId, GameObject hostObject) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hostObject == (Object)null) { return null; } Transform val = hostObject.transform.Find("UltimateReviveMaskedTrigger"); bool flag = (Object)(object)val == (Object)null; GameObject val2 = (GameObject)(((Object)(object)val != (Object)null) ? ((object)((Component)val).gameObject) : ((object)new GameObject("UltimateReviveMaskedTrigger"))); if (flag) { val2.transform.SetParent(hostObject.transform, false); val2.transform.localPosition = MaskedTriggerAliveLocalOffset; } SphereCollider obj = val2.GetComponent() ?? val2.AddComponent(); ((Collider)obj).isTrigger = true; obj.radius = 0.6f; obj.center = Vector3.zero; InteractTrigger obj2 = val2.GetComponent(); bool ownsTrigger = (Object)(object)obj2 == (Object)null; if (obj2 == null) { obj2 = val2.AddComponent(); } InteractTrigger val3 = obj2; int num = LayerMask.NameToLayer("InteractableObject"); bool changedLayer = false; int layer = val2.layer; if (num >= 0 && val2.layer != num) { val2.layer = num; changedLayer = true; } ConfigureTrigger(val3, playerId, ReviveSourceKind.Masked); RegisterTriggerMapping(val3, playerId, ReviveSourceKind.Masked, val2); bool flag2 = false; MaskedPlayerEnemy val4 = hostObject.GetComponent() ?? hostObject.GetComponentInChildren(true); if ((Object)(object)val4 != (Object)null) { flag2 = MaskedConversionTracker.IsMaskedDead(val4); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[ReviveTrigger] maskedChildAttached player={playerId} host={((Object)hostObject).name} child={((Object)val2).name} ownsTriggerHost={flag} triggerId={((Object)val3).GetInstanceID()} layer={val2.layer} maskedDead={flag2}"); } return new ReviveTriggerEntry { TargetPlayerId = playerId, SourceKind = ReviveSourceKind.Masked, SourceObjectId = sourceObjectId, RootObject = hostObject, TriggerHostObject = val2, Trigger = val3, AddedCollider = null, OwnsTrigger = ownsTrigger, OwnsTriggerHostObject = flag, ChangedLayer = changedLayer, OriginalLayer = layer, LayerAdjustedObject = val2, FollowTransform = null, StaticPosition = Vector3.zero }; } private static ReviveTriggerEntry CreateTombEntryUsingChildTrigger(int playerId, ulong sourceObjectId, GameObject hostObject) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hostObject == (Object)null) { return null; } Transform val = hostObject.transform.Find("UltimateReviveTombTrigger"); bool flag = (Object)(object)val == (Object)null; GameObject val2 = (GameObject)(((Object)(object)val != (Object)null) ? ((object)((Component)val).gameObject) : ((object)new GameObject("UltimateReviveTombTrigger"))); if (flag) { val2.transform.SetParent(hostObject.transform, false); val2.transform.localPosition = new Vector3(0f, 0.8f, 0f); } SphereCollider obj = val2.GetComponent() ?? val2.AddComponent(); ((Collider)obj).isTrigger = true; obj.radius = 0.8f; obj.center = Vector3.zero; InteractTrigger obj2 = val2.GetComponent(); bool ownsTrigger = (Object)(object)obj2 == (Object)null; if (obj2 == null) { obj2 = val2.AddComponent(); } InteractTrigger val3 = obj2; int num = LayerMask.NameToLayer("InteractableObject"); bool changedLayer = false; int layer = val2.layer; if (num >= 0 && val2.layer != num) { val2.layer = num; changedLayer = true; } ConfigureTrigger(val3, playerId, ReviveSourceKind.Tomb); RegisterTriggerMapping(val3, playerId, ReviveSourceKind.Tomb, val2); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[ReviveTrigger] tombChildAttached player={playerId} host={((Object)hostObject).name} child={((Object)val2).name} ownsTriggerHost={flag} triggerId={((Object)val3).GetInstanceID()} layer={val2.layer}"); } return new ReviveTriggerEntry { TargetPlayerId = playerId, SourceKind = ReviveSourceKind.Tomb, SourceObjectId = sourceObjectId, RootObject = hostObject, TriggerHostObject = val2, Trigger = val3, AddedCollider = null, OwnsTrigger = ownsTrigger, OwnsTriggerHostObject = flag, ChangedLayer = changedLayer, OriginalLayer = layer, LayerAdjustedObject = val2, FollowTransform = null, StaticPosition = Vector3.zero }; } private static void UpdateMaskedTriggerAnchor(ReviveTriggerEntry entry) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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) if (entry == null || entry.SourceKind != ReviveSourceKind.Masked || (Object)(object)entry.TriggerHostObject == (Object)null) { return; } MaskedPlayerEnemy val = (((Object)(object)entry.RootObject != (Object)null) ? entry.RootObject.GetComponent() : null); if ((Object)(object)val == (Object)null) { return; } Transform transform = entry.TriggerHostObject.transform; if ((Object)(object)transform == (Object)null) { return; } bool flag = MaskedConversionTracker.IsMaskedDead(val); ConfigureMaskedTriggerText(entry, flag); if (!flag) { transform.localPosition = MaskedTriggerAliveLocalOffset; return; } Vector3 val2 = Vector3.ProjectOnPlane(((Component)val).transform.forward, Vector3.up); if (((Vector3)(ref val2)).sqrMagnitude > 0.0001f) { ((Vector3)(ref val2)).Normalize(); } else { val2 = ((Component)val).transform.forward; } if (TryGetMaskedDeadAnchorWorld(val, out var anchor)) { transform.position = anchor; } else { transform.position = ((Component)val).transform.position + Vector3.up * MaskedTriggerDeadLocalOffset.y + val2 * 0.95f; } } public static void OnMaskedKilled(MaskedPlayerEnemy masked) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)masked == (Object)null)) { if (!GeneralUtil.TryResolveConvertedMaskedPlayer(masked, out var playerClientId, out var source)) { MaskedConversionTracker.TagMaskedOnSpawn(masked); GeneralUtil.TryResolveConvertedMaskedPlayer(masked, out playerClientId, out source); } if (playerClientId >= 0) { ulong networkObjectId = MaskedConversionTracker.GetNetworkObjectId(masked); Vector3 deathPosition = (((Object)(object)((Component)masked).transform != (Object)null) ? ((Component)masked).transform.position : Vector3.zero); GeneralUtil.SetPlayerDeathState(playerClientId, PlayerDeathType.Masked, networkObjectId, deathPosition, "Masked.KillEnemy"); ForceRefreshPlayer(playerClientId, "Masked.KillEnemy"); } ReviveTriggerEntry reviveTriggerEntry = EntriesByPlayer.Values.FirstOrDefault((ReviveTriggerEntry e) => e != null && (Object)(object)e.RootObject == (Object)(object)((Component)masked).gameObject); if (reviveTriggerEntry != null) { UpdateMaskedTriggerAnchor(reviveTriggerEntry); } } } private static bool TryGetMaskedDeadAnchorWorld(MaskedPlayerEnemy masked, out Vector3 anchor) { //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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_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_00e0: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) anchor = Vector3.zero; if ((Object)(object)masked == (Object)null || (Object)(object)((Component)masked).transform == (Object)null) { return false; } Collider[] componentsInChildren = ((Component)masked).GetComponentsInChildren(true); Collider val = null; float num = -1f; Collider[] array = componentsInChildren; Bounds bounds; foreach (Collider val2 in array) { if (!((Object)(object)val2 == (Object)null) && !val2.isTrigger) { bounds = val2.bounds; Vector3 size = ((Bounds)(ref bounds)).size; float num2 = size.x * size.y * size.z; if (num2 > num) { val = val2; num = num2; } } } if ((Object)(object)val == (Object)null) { return false; } Vector3 val3 = Vector3.ProjectOnPlane(((Component)masked).transform.forward, Vector3.up); if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f) { val3 = Vector3.zero; } else { ((Vector3)(ref val3)).Normalize(); } bounds = val.bounds; float y = ((Bounds)(ref bounds)).center.y; bounds = val.bounds; float num3 = Mathf.Min(y, ((Bounds)(ref bounds)).min.y + 0.35f); bounds = val.bounds; float x = ((Bounds)(ref bounds)).center.x; bounds = val.bounds; anchor = new Vector3(x, num3, ((Bounds)(ref bounds)).center.z) + val3 * 0.95f; return true; } private static ReviveTriggerEntry CreateBodyEntryUsingVanillaTrigger(int playerId, ulong sourceObjectId, GameObject hostObject) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_0281: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hostObject == (Object)null) { return null; } RagdollGrabbableObject val = hostObject.GetComponent() ?? hostObject.GetComponentInParent() ?? hostObject.GetComponentInChildren(true); if ((Object)(object)val == (Object)null && (Object)(object)hostObject.transform != (Object)null) { val = GeneralUtil.GetBodyNearPosition(hostObject.transform.position, 8f); } if ((Object)(object)val == (Object)null) { val = GeneralUtil.GetBodyFromDeadBodyReference(GeneralUtil.GetPlayerByClientId(playerId)); } if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[ReviveTrigger] bodyVanillaPending player={playerId} host={((Object)hostObject).name} reason=no-ragdoll-yet"); } return null; } Transform transform = ((Component)val).transform; Vector3 position = transform.position; InteractTrigger val2 = SelectBestVanillaBodyTrigger(val); GameObject triggerHostObject = (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : null); Collider addedCollider = null; bool ownsTrigger = false; bool ownsTriggerHostObject = false; bool changedLayer = false; int originalLayer = 0; GameObject layerAdjustedObject = null; if ((Object)(object)val2 == (Object)null) { val2 = CreateCustomBodyTrigger(val, playerId, out triggerHostObject, out addedCollider, out changedLayer, out originalLayer, out layerAdjustedObject, out ownsTrigger, out ownsTriggerHostObject); if ((Object)(object)val2 == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[ReviveTrigger] bodyVanillaPending player={playerId} host={((Object)hostObject).name} reason=no-trigger-yet ragdoll={((Object)val).name}"); } return null; } ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[ReviveTrigger] bodyCustomAttached player={playerId} host={((Object)hostObject).name} trigger={((Object)val2).name} triggerId={((Object)val2).GetInstanceID()} triggerObj={((Object)((Component)val2).gameObject).name} ragdoll={((Object)val).name}"); } } else { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)$"[ReviveTrigger] bodyVanillaAttached player={playerId} host={((Object)hostObject).name} trigger={((Object)val2).name} triggerId={((Object)val2).GetInstanceID()} triggerObj={((Object)((Component)val2).gameObject).name} hasRagdoll={(Object)(object)val != (Object)null}"); } } ConfigureTrigger(val2, playerId, ReviveSourceKind.Body); RegisterTriggerMapping(val2, playerId, ReviveSourceKind.Body, triggerHostObject); return new ReviveTriggerEntry { TargetPlayerId = playerId, SourceKind = ReviveSourceKind.Body, SourceObjectId = sourceObjectId, RootObject = ((Component)val).gameObject, TriggerHostObject = triggerHostObject, Trigger = val2, AddedCollider = addedCollider, OwnsTrigger = ownsTrigger, OwnsTriggerHostObject = ownsTriggerHostObject, ChangedLayer = changedLayer, OriginalLayer = originalLayer, LayerAdjustedObject = layerAdjustedObject, FollowTransform = transform, StaticPosition = (((Object)(object)transform != (Object)null) ? transform.position : position) }; } private static InteractTrigger SelectBestBodyTriggerFromHost(GameObject hostObject, Vector3 anchor) { //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: 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) if ((Object)(object)hostObject == (Object)null) { return null; } List list = new List(); InteractTrigger component = hostObject.GetComponent(); if ((Object)(object)component != (Object)null) { list.Add(component); } InteractTrigger componentInParent = hostObject.GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { list.Add(componentInParent); } InteractTrigger[] componentsInChildren = hostObject.GetComponentsInChildren(true); foreach (InteractTrigger val in componentsInChildren) { if ((Object)(object)val != (Object)null) { list.Add(val); } } Transform val2 = (((Object)(object)hostObject.transform != (Object)null) ? hostObject.transform.root : null); if ((Object)(object)val2 != (Object)null) { componentsInChildren = ((Component)val2).GetComponentsInChildren(true); foreach (InteractTrigger val3 in componentsInChildren) { if ((Object)(object)val3 != (Object)null) { list.Add(val3); } } } Dictionary dictionary = new Dictionary(); foreach (InteractTrigger item in list) { int instanceID = ((Object)item).GetInstanceID(); if (!dictionary.ContainsKey(instanceID)) { dictionary[instanceID] = item; } } if (dictionary.Count == 0) { string text = (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "none"); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[ReviveTrigger] bodyVanillaSearch host={((Object)hostObject).name} root={text} candidates=0 anchor=({anchor.x:0.00},{anchor.y:0.00},{anchor.z:0.00})"); } return null; } string text2 = (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "none"); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[ReviveTrigger] bodyVanillaSearch host={((Object)hostObject).name} root={text2} candidates={dictionary.Count} anchor=({anchor.x:0.00},{anchor.y:0.00},{anchor.z:0.00})"); } Collider primaryCollider = GetPrimaryCollider(hostObject, anchor); string text3 = (((Object)(object)primaryCollider != (Object)null) ? ((Object)primaryCollider).name : "none"); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)("[ReviveTrigger] bodyVanillaPrimaryCollider host=" + ((Object)hostObject).name + " collider=" + text3)); } InteractTrigger val4 = null; float num = float.MaxValue; foreach (KeyValuePair item2 in dictionary) { InteractTrigger value = item2.Value; if ((Object)(object)value == (Object)null || (Object)(object)((Component)value).transform == (Object)null) { continue; } float num2 = Vector3.SqrMagnitude(((Component)value).transform.position - anchor); if ((Object)(object)primaryCollider != (Object)null && (Object)(object)((Component)value).gameObject == (Object)(object)((Component)primaryCollider).gameObject) { num2 -= 1000f; } string text4 = (((Object)(object)((Component)value).gameObject != (Object)null) ? ((Object)((Component)value).gameObject).name : string.Empty); if (!string.IsNullOrWhiteSpace(text4)) { if (text4.IndexOf("ragdoll", StringComparison.OrdinalIgnoreCase) >= 0) { num2 -= 20f; } if (text4.IndexOf("body", StringComparison.OrdinalIgnoreCase) >= 0) { num2 -= 10f; } if (text4.IndexOf("player", StringComparison.OrdinalIgnoreCase) >= 0) { num2 -= 5f; } } Collider component2 = ((Component)value).GetComponent(); if ((Object)(object)component2 != (Object)null && component2.enabled) { num2 -= 5f; } int instanceID2 = ((Object)value).GetInstanceID(); string text5 = (((Object)(object)((Component)value).gameObject != (Object)null) ? ((Object)((Component)value).gameObject).name : "unknown"); string text6 = BuildTransformPath(((Component)value).transform); ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)$"[ReviveTrigger] bodyVanillaCandidate id={instanceID2} name={((Object)value).name} obj={text5} score={num2:0.000} path={text6}"); } if ((Object)(object)val4 == (Object)null || num2 < num || (Mathf.Approximately(num2, num) && instanceID2 < ((Object)val4).GetInstanceID())) { num = num2; val4 = value; } } if ((Object)(object)val4 != (Object)null) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogInfo((object)$"[ReviveTrigger] bodyVanillaSelected id={((Object)val4).GetInstanceID()} name={((Object)val4).name} score={num:0.000} host={((Object)hostObject).name}"); } } return val4; } private static InteractTrigger SelectBestVanillaBodyTrigger(RagdollGrabbableObject body) { //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: 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) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)body == (Object)null) { return null; } List list = new List(); InteractTrigger component = ((Component)body).GetComponent(); if ((Object)(object)component != (Object)null) { list.Add(component); } InteractTrigger componentInParent = ((Component)body).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { list.Add(componentInParent); } InteractTrigger[] componentsInChildren = ((Component)body).GetComponentsInChildren(true); foreach (InteractTrigger val in componentsInChildren) { if ((Object)(object)val != (Object)null) { list.Add(val); } } if (list.Count == 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[ReviveTrigger] bodyRagdollSearch body=" + ((Object)body).name + " candidates=0")); } return null; } Dictionary dictionary = new Dictionary(); foreach (InteractTrigger item in list) { int instanceID = ((Object)item).GetInstanceID(); if (!dictionary.ContainsKey(instanceID)) { dictionary[instanceID] = item; } } Collider primaryRagdollCollider = GetPrimaryRagdollCollider(body); Vector3 val2; if (!((Object)(object)primaryRagdollCollider != (Object)null)) { val2 = ((Component)body).transform.position; } else { Bounds bounds = primaryRagdollCollider.bounds; val2 = ((Bounds)(ref bounds)).center; } Vector3 val3 = val2; string arg = (((Object)(object)primaryRagdollCollider != (Object)null) ? ((Object)primaryRagdollCollider).name : "none"); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[ReviveTrigger] bodyRagdollSearch body={((Object)body).name} candidates={dictionary.Count} primaryCollider={arg}"); } InteractTrigger val4 = null; float num = float.MaxValue; foreach (KeyValuePair item2 in dictionary) { InteractTrigger value = item2.Value; if (!((Object)(object)value == (Object)null) && !((Object)(object)((Component)value).transform == (Object)null)) { float num2 = Vector3.SqrMagnitude(((Component)value).transform.position - val3); if ((Object)(object)primaryRagdollCollider != (Object)null && (Object)(object)((Component)value).gameObject == (Object)(object)((Component)primaryRagdollCollider).gameObject) { num2 -= 1000f; } Collider component2 = ((Component)value).GetComponent(); if ((Object)(object)component2 != (Object)null && component2.enabled) { num2 -= 5f; } string text = (((Object)(object)((Component)value).gameObject != (Object)null) ? ((Object)((Component)value).gameObject).name : "unknown"); string text2 = BuildTransformPath(((Component)value).transform); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[ReviveTrigger] bodyRagdollCandidate id={((Object)value).GetInstanceID()} name={((Object)value).name} obj={text} score={num2:0.000} path={text2}"); } if (num2 < num) { num = num2; val4 = value; } } } if ((Object)(object)val4 != (Object)null) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)$"[ReviveTrigger] bodyRagdollSelected id={((Object)val4).GetInstanceID()} name={((Object)val4).name} score={num:0.000} body={((Object)body).name}"); } } return val4; } private static Collider GetPrimaryRagdollCollider(RagdollGrabbableObject body) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_008e: 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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)body == (Object)null) { return null; } Collider component = ((Component)body).GetComponent(); if ((Object)(object)component != (Object)null && component.enabled && !component.isTrigger) { return component; } Collider[] componentsInChildren = ((Component)body).GetComponentsInChildren(true); Collider val = null; float num = -1f; float num2 = float.MaxValue; Vector3 position = ((Component)body).transform.position; Collider[] array = componentsInChildren; foreach (Collider val2 in array) { if (!((Object)(object)val2 == (Object)null) && val2.enabled && !val2.isTrigger) { Bounds bounds = val2.bounds; Vector3 size = ((Bounds)(ref bounds)).size; float num3 = size.x * size.y * size.z; bounds = val2.bounds; float num4 = Vector3.SqrMagnitude(((Bounds)(ref bounds)).center - position); if (num3 > num || (Mathf.Approximately(num3, num) && num4 < num2)) { val = val2; num = num3; num2 = num4; } } } if ((Object)(object)val != (Object)null) { return val; } return component; } private static InteractTrigger CreateCustomBodyTrigger(RagdollGrabbableObject body, int playerId, out GameObject triggerHostObject, out Collider addedCollider, out bool changedLayer, out int originalLayer, out GameObject layerAdjustedObject, out bool ownsTrigger, out bool ownsTriggerHostObject) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00ca: 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_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) triggerHostObject = null; addedCollider = null; changedLayer = false; originalLayer = 0; layerAdjustedObject = null; ownsTrigger = false; ownsTriggerHostObject = false; if ((Object)(object)body == (Object)null || (Object)(object)((Component)body).transform == (Object)null) { return null; } Transform val = ((Component)body).transform.Find("UltimateReviveBodyTrigger"); if ((Object)(object)val != (Object)null) { triggerHostObject = ((Component)val).gameObject; } if ((Object)(object)triggerHostObject == (Object)null) { triggerHostObject = new GameObject("UltimateReviveBodyTrigger"); triggerHostObject.transform.SetParent(((Component)body).transform, false); ownsTriggerHostObject = true; } Collider primaryRagdollCollider = GetPrimaryRagdollCollider(body); Vector3 val2; if (!((Object)(object)primaryRagdollCollider != (Object)null)) { val2 = ((Component)body).transform.position + Vector3.up * 0.9f; } else { Bounds bounds = primaryRagdollCollider.bounds; val2 = ((Bounds)(ref bounds)).center; } Vector3 val3 = val2; triggerHostObject.transform.position = val3; triggerHostObject.transform.rotation = Quaternion.identity; InteractTrigger val4 = triggerHostObject.GetComponent(); if ((Object)(object)val4 == (Object)null) { val4 = triggerHostObject.AddComponent(); ownsTrigger = true; } SphereCollider val5 = triggerHostObject.GetComponent(); if ((Object)(object)val5 == (Object)null) { val5 = (SphereCollider)(object)(addedCollider = (Collider)(object)triggerHostObject.AddComponent()); } float num = 0.5f; ((Collider)val5).isTrigger = true; val5.radius = num; val5.center = Vector3.zero; triggerHostObject.layer = 0; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[ReviveTrigger] bodyCustomTrigger player={playerId} body={((Object)body).name} host={((Object)triggerHostObject).name} radius={num:0.00} center=({val3.x:0.00},{val3.y:0.00},{val3.z:0.00})"); } return val4; } private static string BuildTransformPath(Transform transform) { if ((Object)(object)transform == (Object)null) { return "none"; } List list = new List(); Transform val = transform; while ((Object)(object)val != (Object)null) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list); } private static Collider GetPrimaryCollider(GameObject rootObject, Vector3 rootPosition) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00ab: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rootObject == (Object)null) { return null; } Collider component = rootObject.GetComponent(); if ((Object)(object)component != (Object)null && component.enabled && !component.isTrigger) { return component; } Collider[] componentsInChildren = rootObject.GetComponentsInChildren(true); Collider val = null; float num = -1f; float num2 = float.MaxValue; Collider[] array = componentsInChildren; foreach (Collider val2 in array) { if (!((Object)(object)val2 == (Object)null) && val2.enabled && !val2.isTrigger) { Bounds bounds = val2.bounds; Vector3 size = ((Bounds)(ref bounds)).size; float num3 = size.x * size.y * size.z; bounds = val2.bounds; float num4 = Vector3.SqrMagnitude(((Bounds)(ref bounds)).center - rootPosition); if (num3 > num || (Mathf.Approximately(num3, num) && num4 < num2)) { val = val2; num = num3; num2 = num4; } } } if ((Object)(object)val != (Object)null) { return val; } return component; } private static bool TryResolveSourceHostObject(int playerId, ReviveSourceKind sourceKind, ulong sourceObjectId, Transform followTransform, out GameObject hostObject) { hostObject = null; switch (sourceKind) { case ReviveSourceKind.Body: { PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(playerId); RagdollGrabbableObject val = ((sourceObjectId != 0L) ? GeneralUtil.GetBodyByNetworkObjectId(sourceObjectId) : GeneralUtil.GetBodyForPlayer(playerId)); if ((Object)(object)val == (Object)null) { val = GeneralUtil.GetBodyFromDeadBodyReference(playerByClientId); } if ((Object)(object)val != (Object)null) { hostObject = ((Component)val).gameObject; return true; } if ((Object)(object)playerByClientId?.deadBody != (Object)null) { hostObject = ((Component)playerByClientId.deadBody).gameObject; return (Object)(object)hostObject != (Object)null; } if ((Object)(object)followTransform != (Object)null) { hostObject = ((Component)followTransform).gameObject; return (Object)(object)hostObject != (Object)null; } return false; } case ReviveSourceKind.Masked: if (sourceObjectId != 0L) { MaskedPlayerEnemy maskedByNetworkObjectId = GeneralUtil.GetMaskedByNetworkObjectId(sourceObjectId); if ((Object)(object)maskedByNetworkObjectId != (Object)null) { hostObject = ((Component)maskedByNetworkObjectId).gameObject; return (Object)(object)hostObject != (Object)null; } } if ((Object)(object)followTransform != (Object)null) { hostObject = ((Component)followTransform).gameObject; return (Object)(object)hostObject != (Object)null; } return false; case ReviveSourceKind.Tomb: if (DeathMarkerManager.TryGetMarkerObject(playerId, out hostObject)) { return (Object)(object)hostObject != (Object)null; } return false; default: return false; } } private static void ConfigureTrigger(InteractTrigger trigger, int playerId, ReviveSourceKind sourceKind) { if (!((Object)(object)trigger == (Object)null)) { InitializeInteractTriggerFromScratch(trigger); string text = GeneralUtil.GetPlayerByClientId(playerId)?.playerUsername; if (string.IsNullOrWhiteSpace(text)) { text = $"Player {playerId}"; } string text2 = sourceKind switch { ReviveSourceKind.Masked => "masked body", ReviveSourceKind.Tomb => "tomb", _ => "body", }; trigger.interactable = true; trigger.hoverTip = "Revive " + text; trigger.disabledHoverTip = string.Empty; SetFieldOrPropertyIfExists(trigger, "interactTip", "Revive (" + text2 + ")"); } } private static void ConfigureMaskedTriggerText(ReviveTriggerEntry entry, bool maskedDead) { if (entry != null && !((Object)(object)entry.Trigger == (Object)null)) { string text = GeneralUtil.GetPlayerByClientId(entry.TargetPlayerId)?.playerUsername; if (string.IsNullOrWhiteSpace(text)) { text = $"Player {entry.TargetPlayerId}"; } if (!maskedDead) { entry.Trigger.interactable = true; entry.Trigger.hoverTip = "Kill masked to revive " + text; entry.Trigger.disabledHoverTip = "Kill masked to revive " + text; SetFieldOrPropertyIfExists(entry.Trigger, "interactTip", "Kill masked first"); } else { entry.Trigger.interactable = true; entry.Trigger.hoverTip = "Revive " + text; entry.Trigger.disabledHoverTip = string.Empty; SetFieldOrPropertyIfExists(entry.Trigger, "interactTip", "Revive (masked body)"); } } } private static void InitializeInteractTriggerFromScratch(InteractTrigger trigger) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown if (!((Object)(object)trigger == (Object)null)) { trigger.interactable = true; trigger.holdInteraction = false; trigger.timeToHold = 0f; trigger.oneHandedItemAllowed = true; trigger.twoHandedItemAllowed = true; trigger.hoverTip = "Revive"; trigger.disabledHoverTip = ""; SetFieldOrPropertyIfExists(trigger, "specialCharacterAnimation", ""); SetFieldOrPropertyIfExists(trigger, "stopAnimationManually", false); SetFieldOrPropertyIfExists(trigger, "interactAnimation", ""); SetFieldOrPropertyIfExists(trigger, "interactTip", "Revive"); if (trigger.onInteract == null) { trigger.onInteract = new InteractEvent(); } } } private static InteractTrigger GetVanillaBodyTriggerTemplate() { return null; } private static void SetFieldOrPropertyIfExists(object instance, string memberName, object value) { if (instance == null) { return; } Type type = value?.GetType(); Type type2 = instance.GetType(); FieldInfo field = type2.GetField(memberName, InstanceFlags); if (field != null && (type == null || field.FieldType.IsAssignableFrom(type))) { field.SetValue(instance, value); return; } PropertyInfo property = type2.GetProperty(memberName, InstanceFlags); if (property != null && property.CanWrite && (type == null || property.PropertyType.IsAssignableFrom(type))) { property.SetValue(instance, value); } } private static bool EvaluateCanRevive(ReviveTriggerEntry entry, PlayerControllerB reviver, out int resolvedTargetId, out string reason) { //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019c: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) resolvedTargetId = entry.TargetPlayerId; reason = "source missing"; if (entry.SourceKind == ReviveSourceKind.Body) { PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(entry.TargetPlayerId); RagdollGrabbableObject val = TryResolveEntryBody(entry); if ((Object)(object)val == (Object)null) { val = ((entry.SourceObjectId != 0L) ? GeneralUtil.GetBodyByNetworkObjectId(entry.SourceObjectId) : GeneralUtil.GetBodyForPlayer(entry.TargetPlayerId)); } if ((Object)(object)val == (Object)null) { val = GeneralUtil.GetBodyFromDeadBodyReference(playerByClientId); } if ((Object)(object)val != (Object)null) { if (ReviveRules.CanRevive(reviver, val, out resolvedTargetId, out reason)) { return true; } if (string.Equals(reason, "no body", StringComparison.Ordinal)) { Vector3 targetPosition = (((Object)(object)((Component)val).transform != (Object)null) ? ((Component)val).transform.position : entry.StaticPosition); if (!GeneralUtil.IsReviverCloseEnoughToTomb(reviver, targetPosition)) { reason = "too far from body"; return false; } resolvedTargetId = entry.TargetPlayerId; return ReviveRules.CanReviveAtTomb(reviver, entry.TargetPlayerId, out reason); } return false; } Vector3 targetPosition2 = (((Object)(object)entry.RootObject != (Object)null) ? entry.RootObject.transform.position : entry.StaticPosition); if (!GeneralUtil.IsReviverCloseEnoughToTomb(reviver, targetPosition2)) { reason = "too far from body"; return false; } resolvedTargetId = entry.TargetPlayerId; return ReviveRules.CanReviveAtTomb(reviver, entry.TargetPlayerId, out reason); } if (entry.SourceKind == ReviveSourceKind.Masked) { MaskedPlayerEnemy val2 = ((entry.SourceObjectId != 0L) ? GeneralUtil.GetMaskedByNetworkObjectId(entry.SourceObjectId) : GeneralUtil.GetConvertedMaskedForPlayer(entry.TargetPlayerId)); if ((Object)(object)val2 == (Object)null) { reason = "masked missing"; return false; } return ReviveRules.CanReviveMasked(reviver, val2, out resolvedTargetId, out reason); } Vector3 targetPosition3 = (((Object)(object)entry.RootObject != (Object)null) ? entry.RootObject.transform.position : entry.StaticPosition); if (!GeneralUtil.IsReviverCloseEnoughToTomb(reviver, targetPosition3)) { reason = "too far from body"; return false; } return ReviveRules.CanReviveAtTomb(reviver, entry.TargetPlayerId, out reason); } private static RagdollGrabbableObject TryResolveEntryBody(ReviveTriggerEntry entry) { if (entry == null) { return null; } GameObject rootObject = entry.RootObject; if ((Object)(object)rootObject != (Object)null) { RagdollGrabbableObject val = rootObject.GetComponent() ?? rootObject.GetComponentInParent() ?? rootObject.GetComponentInChildren(true); if ((Object)(object)val != (Object)null) { return val; } } Transform followTransform = entry.FollowTransform; if ((Object)(object)followTransform == (Object)null) { return null; } return ((Component)followTransform).GetComponent() ?? ((Component)followTransform).GetComponentInParent() ?? ((Component)followTransform).GetComponentInChildren(true); } private static bool TryResolveCurrentReviveSource(int playerId, out ReviveSourceKind sourceKind, out ulong sourceObjectId, out Transform followTransform, out Vector3 staticPosition) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_041a: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03ce: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) sourceKind = ReviveSourceKind.None; sourceObjectId = 0uL; followTransform = null; staticPosition = Vector3.zero; PlayerDeathType playerLastDeathType = GeneralUtil.GetPlayerLastDeathType(playerId); ulong playerLastDeathNetworkObjectId = GeneralUtil.GetPlayerLastDeathNetworkObjectId(playerId); if (playerLastDeathType == PlayerDeathType.Masked && ModConfig.EnableMaskedPlayerRevive) { MaskedPlayerEnemy val = null; string arg; string source; if (playerLastDeathNetworkObjectId != 0L) { MaskedPlayerEnemy maskedByNetworkObjectId = GeneralUtil.GetMaskedByNetworkObjectId(playerLastDeathNetworkObjectId); int playerClientId; if ((Object)(object)maskedByNetworkObjectId == (Object)null) { arg = "id-missing"; } else if (!GeneralUtil.TryResolveConvertedMaskedPlayer(maskedByNetworkObjectId, out playerClientId, out source)) { arg = "id-not-converted"; } else if (playerClientId != playerId) { arg = $"id-owner-mismatch:{playerClientId}"; } else { val = maskedByNetworkObjectId; arg = "id-match"; } } else { arg = "no-latest-id"; } string text = "not-checked"; if ((Object)(object)val == (Object)null) { MaskedPlayerEnemy convertedMaskedForPlayer = GeneralUtil.GetConvertedMaskedForPlayer(playerId); int playerClientId2; if ((Object)(object)convertedMaskedForPlayer == (Object)null) { text = "owner-none"; } else if (!GeneralUtil.TryResolveConvertedMaskedPlayer(convertedMaskedForPlayer, out playerClientId2, out source)) { text = "owner-not-converted"; } else if (playerClientId2 != playerId) { text = $"owner-mismatch:{playerClientId2}"; } else { val = convertedMaskedForPlayer; text = "owner-match"; } } else { text = "skipped-id-match"; } if ((Object)(object)val != (Object)null) { sourceKind = ReviveSourceKind.Masked; sourceObjectId = MaskedConversionTracker.GetNetworkObjectId(val); followTransform = ((Component)val).transform; LogResolveDiagnostic(playerId, $"resolve=masked sourceObj={sourceObjectId} latestObj={playerLastDeathNetworkObjectId} follow={(Object)(object)followTransform != (Object)null}"); return true; } LogResolveDiagnostic(playerId, $"resolve=masked strict-miss latestObj={playerLastDeathNetworkObjectId} byId={arg} ownerFallback={text}"); } if (DeathMarkerManager.TryGetMarkerObject(playerId, out var markerObject) && (Object)(object)markerObject != (Object)null && (Object)(object)markerObject.transform != (Object)null) { sourceKind = ReviveSourceKind.Tomb; sourceObjectId = 0uL; followTransform = markerObject.transform; staticPosition = markerObject.transform.position; LogResolveDiagnostic(playerId, "resolve=tomb marker sourceObj=0 follow=true"); return true; } if (playerLastDeathType == PlayerDeathType.Body || playerLastDeathType == PlayerDeathType.Unknown) { PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(playerId); RagdollGrabbableObject val2 = ((playerLastDeathNetworkObjectId != 0L) ? GeneralUtil.GetBodyByNetworkObjectId(playerLastDeathNetworkObjectId) : GeneralUtil.GetBodyForPlayer(playerId)); if ((Object)(object)val2 == (Object)null) { val2 = GeneralUtil.GetBodyFromDeadBodyReference(playerByClientId); } if ((Object)(object)val2 == (Object)null && GeneralUtil.TryGetPlayerLastDeathPosition(playerId, out var position)) { val2 = GeneralUtil.GetBodyNearPosition(position); } if ((Object)(object)val2 != (Object)null && DeathMarkerManager.IsTombRagdollGrabbable(val2)) { val2 = null; } if ((Object)(object)val2 != (Object)null) { sourceKind = ReviveSourceKind.Body; sourceObjectId = (((Object)(object)((NetworkBehaviour)val2).NetworkObject != (Object)null) ? ((NetworkBehaviour)val2).NetworkObject.NetworkObjectId : 0); followTransform = ((Component)val2).transform; LogResolveDiagnostic(playerId, $"resolve=body ragdoll sourceObj={sourceObjectId} latestObj={playerLastDeathNetworkObjectId} follow={(Object)(object)followTransform != (Object)null}"); return true; } if (GeneralUtil.TryGetPlayerLastDeathPosition(playerId, out var position2)) { DeadBodyInfo deadBodyNearPosition = GeneralUtil.GetDeadBodyNearPosition(position2); if ((Object)(object)deadBodyNearPosition != (Object)null && (Object)(object)((Component)deadBodyNearPosition).transform != (Object)null && IsDeadBodyOwnedByPlayer(deadBodyNearPosition, playerId, playerByClientId)) { sourceKind = ReviveSourceKind.Body; sourceObjectId = 0uL; followTransform = ((Component)deadBodyNearPosition).transform; staticPosition = ((Component)deadBodyNearPosition).transform.position; LogResolveDiagnostic(playerId, "resolve=body deadBodyNearPosition sourceObj=0 follow=true"); return true; } if ((Object)(object)deadBodyNearPosition != (Object)null) { LogResolveDiagnostic(playerId, "resolve=body deadBodyNearPosition skipped-owner-mismatch"); } } if ((Object)(object)playerByClientId?.deadBody != (Object)null && (Object)(object)((Component)playerByClientId.deadBody).transform != (Object)null && !DeathMarkerManager.IsTombDeadBody(playerId, playerByClientId.deadBody)) { sourceKind = ReviveSourceKind.Body; sourceObjectId = 0uL; followTransform = ((Component)playerByClientId.deadBody).transform; staticPosition = ((Component)playerByClientId.deadBody).transform.position; LogResolveDiagnostic(playerId, "resolve=body player.deadBody sourceObj=0 follow=true"); return true; } } if (GeneralUtil.TryGetPlayerLastDeathPosition(playerId, out var position3) && DeathMarkerManager.TryGetMarkerObject(playerId, out var markerObject2) && (Object)(object)markerObject2 != (Object)null) { sourceKind = ReviveSourceKind.Tomb; sourceObjectId = 0uL; followTransform = markerObject2.transform; staticPosition = position3; LogResolveDiagnostic(playerId, $"resolve=tomb forced sourceObj=0 pos=({position3.x:0.00},{position3.y:0.00},{position3.z:0.00})"); return true; } PlayerControllerB playerByClientId2 = GeneralUtil.GetPlayerByClientId(playerId); Vector3 position4; string text2 = (GeneralUtil.TryGetPlayerLastDeathPosition(playerId, out position4) ? $"({position4.x:0.00},{position4.y:0.00},{position4.z:0.00})" : "none"); LogResolveDiagnostic(playerId, $"resolve=none deathType={playerLastDeathType} latestObj={playerLastDeathNetworkObjectId} hasPlayer={(Object)(object)playerByClientId2 != (Object)null} hasDeadBodyRef={(Object)(object)playerByClientId2?.deadBody != (Object)null} deathPos={text2}"); return false; } private static bool IsDeadBodyOwnedByPlayer(DeadBodyInfo deadBody, int playerId, PlayerControllerB expectedPlayer) { if ((Object)(object)deadBody == (Object)null) { return false; } if (DeathMarkerManager.IsTombDeadBody(playerId, deadBody)) { return true; } if (DeathMarkerManager.TryGetTombOwnerPlayerId(deadBody, out var playerClientId)) { return playerClientId == playerId; } PlayerControllerB playerScript = deadBody.playerScript; if ((Object)(object)playerScript != (Object)null) { return (int)playerScript.playerClientId == playerId; } if ((Object)(object)expectedPlayer != (Object)null && (Object)(object)expectedPlayer.deadBody == (Object)(object)deadBody) { return true; } if (StartOfRound.Instance?.allPlayerScripts != null) { PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.deadBody != (Object)(object)deadBody)) { return (int)val.playerClientId == playerId; } } } return false; } private static void RemoveEntry(int playerId) { if (!EntriesByPlayer.TryGetValue(playerId, out var value) || value == null) { return; } if (value.OwnsTriggerHostObject && (Object)(object)value.TriggerHostObject != (Object)null) { if ((Object)(object)value.Trigger != (Object)null) { TriggerInstanceToPlayer.Remove(((Object)value.Trigger).GetInstanceID()); } Object.Destroy((Object)(object)value.TriggerHostObject); value.Trigger = null; } if ((Object)(object)value.Trigger != (Object)null) { TriggerInstanceToPlayer.Remove(((Object)value.Trigger).GetInstanceID()); if (value.OwnsTrigger) { Object.Destroy((Object)(object)value.Trigger); } } if ((Object)(object)value.AddedCollider != (Object)null) { Object.Destroy((Object)(object)value.AddedCollider); } if (value.ChangedLayer && (Object)(object)value.LayerAdjustedObject != (Object)null) { value.LayerAdjustedObject.layer = value.OriginalLayer; } Plugin.DebugLog($"[ReviveTrigger] removed source={value.SourceKind} player={playerId}"); EntriesByPlayer.Remove(playerId); _lastResolveDiagnosticsByPlayer.Remove(playerId); _lastTickDiagnosticsByPlayer.Remove(playerId); _lastForceDiagnosticsByPlayer.Remove(playerId); } private static void RegisterTriggerMapping(InteractTrigger trigger, int playerId, ReviveSourceKind sourceKind, GameObject hostObject) { if ((Object)(object)trigger == (Object)null) { return; } int instanceID = ((Object)trigger).GetInstanceID(); if (TriggerInstanceToPlayer.TryGetValue(instanceID, out var value) && value != playerId) { string text = "unknown"; if (EntriesByPlayer.TryGetValue(value, out var value2)) { object obj; if (value2 == null) { obj = null; } else { GameObject triggerHostObject = value2.TriggerHostObject; obj = ((triggerHostObject != null) ? triggerHostObject.transform : null); } if ((Object)obj != (Object)null) { text = BuildTransformPath(value2.TriggerHostObject.transform); } } string text2 = (((Object)(object)((hostObject != null) ? hostObject.transform : null) != (Object)null) ? BuildTransformPath(hostObject.transform) : "unknown"); ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[ReviveTrigger] id-collision triggerId={instanceID} oldPlayer={value} newPlayer={playerId} source={sourceKind} oldPath={text} newPath={text2}"); } } TriggerInstanceToPlayer[instanceID] = playerId; } private static void LogResolveDiagnostic(int playerId, string message) { if (!_lastResolveDiagnosticsByPlayer.TryGetValue(playerId, out var value) || !string.Equals(value, message, StringComparison.Ordinal)) { _lastResolveDiagnosticsByPlayer[playerId] = message; Plugin.DebugLog($"[ReviveResolve] player={playerId} {message}"); } } private static void LogTickDiagnostic(int playerId, string message) { if (!_lastTickDiagnosticsByPlayer.TryGetValue(playerId, out var value) || !string.Equals(value, message, StringComparison.Ordinal)) { _lastTickDiagnosticsByPlayer[playerId] = message; Plugin.DebugLog($"[ReviveTick] player={playerId} {message}"); } } private static void LogTickGateDiagnostic(string message) { if (!string.Equals(_lastTickGateDiagnostic, message, StringComparison.Ordinal)) { _lastTickGateDiagnostic = message; Plugin.DebugLog("[ReviveTick] " + message); } } private static void LogForceDiagnostic(int playerId, string message) { if (!_lastForceDiagnosticsByPlayer.TryGetValue(playerId, out var value) || !string.Equals(value, message, StringComparison.Ordinal)) { _lastForceDiagnosticsByPlayer[playerId] = message; Plugin.DebugLog($"[ReviveForce] player={playerId} {message}"); } } private static List DisableCompetingBodyTriggers(GameObject bodyRoot, InteractTrigger keepTrigger) { if ((Object)(object)bodyRoot == (Object)null) { return null; } InteractTrigger[] componentsInChildren = bodyRoot.GetComponentsInChildren(true); List list = null; InteractTrigger[] array = componentsInChildren; foreach (InteractTrigger val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)keepTrigger) && ((Behaviour)val).enabled) { ((Behaviour)val).enabled = false; if (list == null) { list = new List(); } list.Add(val); } } return list; } private static bool TryGetHoveredEntry(PlayerControllerB player, out ReviveTriggerEntry entry) { entry = null; if ((Object)(object)player == (Object)null) { return false; } if (TryGetCurrentInteractTrigger(player, out var trigger) && (Object)(object)trigger != (Object)null) { LogObservedTriggerDiagnostic(player, trigger); int instanceID = ((Object)trigger).GetInstanceID(); ReviveTriggerEntry value2; if (!TriggerInstanceToPlayer.TryGetValue(instanceID, out var value)) { if (TryCreateEntryFromVanillaBodyTrigger(trigger, out var entry2)) { entry = entry2; RememberHoveredEntry(entry); return true; } } else if (EntriesByPlayer.TryGetValue(value, out value2) && value2 != null && (Object)(object)value2.Trigger == (Object)(object)trigger) { entry = value2; RememberHoveredEntry(entry); return true; } } else { LogObservedTriggerDiagnostic(player, null); } if (TryGetHoveredBodyEntryBySight(player, out var entry3)) { entry = entry3; RememberHoveredEntry(entry); return true; } if (TryGetGraceHoveredEntry(player, out var entry4)) { entry = entry4; return true; } return false; } private static void RememberHoveredEntry(ReviveTriggerEntry entry) { if (entry != null) { _lastHoveredTargetId = entry.TargetPlayerId; _lastHoveredSeenAt = Time.time; } } private static bool TryGetGraceHoveredEntry(PlayerControllerB player, out ReviveTriggerEntry entry) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) entry = null; if ((Object)(object)player == (Object)null) { return false; } if (_lastHoveredTargetId < 0) { return false; } if (Time.time - _lastHoveredSeenAt > 0.45f) { return false; } if (!EntriesByPlayer.TryGetValue(_lastHoveredTargetId, out var value) || value == null) { return false; } Vector3 targetPosition = (((Object)(object)value.RootObject != (Object)null) ? value.RootObject.transform.position : value.StaticPosition); if (!((value.SourceKind == ReviveSourceKind.Tomb) ? GeneralUtil.IsReviverCloseEnoughToTomb(player, targetPosition) : GeneralUtil.IsReviverCloseEnough(player, targetPosition))) { return false; } entry = value; return true; } private static bool TryGetHoveredBodyEntryBySight(PlayerControllerB player, out ReviveTriggerEntry entry) { //IL_0054: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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) entry = null; if ((Object)(object)player == (Object)null) { return false; } Transform val = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform : ((Component)player).transform); if ((Object)(object)val == (Object)null) { return false; } float num = Mathf.Max(player.grabDistance + 1.5f, GeneralUtil.GetReviveValidationDistance(player)); RaycastHit[] array = Physics.RaycastAll(new Ray(val.position, val.forward), num, -1, (QueryTriggerInteraction)2); if (array == null || array.Length == 0) { return false; } Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int i = 0; i < array2.Length; i++) { RaycastHit val2 = array2[i]; Collider collider = ((RaycastHit)(ref val2)).collider; if (!((Object)(object)collider == (Object)null) && TryGetBodyEntryForCollider(collider, out entry)) { return true; } } return false; } private static bool TryGetBodyEntryForCollider(Collider collider, out ReviveTriggerEntry entry) { entry = null; if ((Object)(object)collider == (Object)null) { return false; } Transform transform = ((Component)collider).transform; foreach (ReviveTriggerEntry value in EntriesByPlayer.Values) { if (value == null) { continue; } if ((Object)(object)value.TriggerHostObject != (Object)null) { Transform transform2 = value.TriggerHostObject.transform; if ((Object)(object)transform == (Object)(object)transform2 || transform.IsChildOf(transform2) || transform2.IsChildOf(transform)) { entry = value; return true; } } RagdollGrabbableObject val = TryResolveEntryBody(value); Transform val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : value.FollowTransform); if ((Object)(object)val2 != (Object)null && ((Object)(object)transform == (Object)(object)val2 || transform.IsChildOf(val2) || val2.IsChildOf(transform))) { entry = value; return true; } if (value.SourceKind == ReviveSourceKind.Body) { PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(value.TargetPlayerId); Transform val3 = (((Object)(object)playerByClientId?.deadBody != (Object)null) ? ((Component)playerByClientId.deadBody).transform : null); if ((Object)(object)val3 != (Object)null && ((Object)(object)transform == (Object)(object)val3 || transform.IsChildOf(val3))) { entry = value; return true; } } } return false; } private static void LogObservedTriggerDiagnostic(PlayerControllerB player, InteractTrigger trigger) { if (!((Object)(object)player == (Object)null)) { int num = (int)player.playerClientId; string text; if ((Object)(object)trigger == (Object)null) { text = "observed=none"; } else { string text2 = (((Object)(object)((Component)trigger).gameObject != (Object)null) ? ((Object)((Component)trigger).gameObject).name : "none"); string text3 = (((Object)(object)((Component)trigger).transform != (Object)null) ? BuildTransformPath(((Component)trigger).transform) : "none"); int num2 = (((Object)(object)((Component)trigger).gameObject != (Object)null) ? ((Component)trigger).gameObject.layer : (-1)); bool enabled = ((Behaviour)trigger).enabled; Collider component = ((Component)trigger).GetComponent(); string text4 = (((Object)(object)component == (Object)null) ? "none" : $"{((object)component).GetType().Name}:{component.enabled}:trigger={component.isTrigger}"); RagdollGrabbableObject componentInParent = ((Component)trigger).GetComponentInParent(); string text5 = (((Object)(object)componentInParent != (Object)null) ? ((Object)componentInParent).name : "none"); ulong num3 = (((Object)(object)((componentInParent != null) ? ((NetworkBehaviour)componentInParent).NetworkObject : null) != (Object)null) ? ((NetworkBehaviour)componentInParent).NetworkObject.NetworkObjectId : 0); DeadBodyInfo componentInParent2 = ((Component)trigger).GetComponentInParent(); string text6 = (((Object)(object)componentInParent2 != (Object)null) ? ((Object)componentInParent2).name : "none"); int value; string text7 = (TriggerInstanceToPlayer.TryGetValue(((Object)trigger).GetInstanceID(), out value) ? value.ToString() : "none"); text = $"observed=id={((Object)trigger).GetInstanceID()} name={((Object)trigger).name} obj={text2} enabled={enabled} interactable={trigger.interactable} layer={num2} collider={text4} mappedPlayer={text7} body={text5}/obj:{num3} deadBody={text6} path={text3}"; } if (!_lastObservedTriggerDiagnosticsByPlayer.TryGetValue(num, out var value2) || !string.Equals(value2, text, StringComparison.Ordinal)) { _lastObservedTriggerDiagnosticsByPlayer[num] = text; Plugin.DebugLog($"[ReviveLook] viewer={num} {text}"); } } } private static bool TryCreateEntryFromVanillaBodyTrigger(InteractTrigger trigger, out ReviveTriggerEntry entry) { //IL_00c3: 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_00c8: Unknown result type (might be due to invalid IL or missing references) entry = null; if ((Object)(object)trigger == (Object)null) { return false; } RagdollGrabbableObject val = ((Component)trigger).GetComponentInParent(); if ((Object)(object)val == (Object)null) { val = ((Component)trigger).GetComponent(); } if ((Object)(object)val == (Object)null) { return false; } if (!GeneralUtil.TryGetBodyOwner(val, out var targetPlayerClientId, out var targetPlayer) || (Object)(object)targetPlayer == (Object)null || !targetPlayer.isPlayerDead) { return false; } ulong sourceObjectId = (((Object)(object)((NetworkBehaviour)val).NetworkObject != (Object)null) ? ((NetworkBehaviour)val).NetworkObject.NetworkObjectId : 0); entry = new ReviveTriggerEntry { TargetPlayerId = targetPlayerClientId, SourceKind = ReviveSourceKind.Body, SourceObjectId = sourceObjectId, RootObject = ((Component)val).gameObject, Trigger = trigger, FollowTransform = ((Component)val).transform, StaticPosition = (((Object)(object)((Component)val).transform != (Object)null) ? ((Component)val).transform.position : Vector3.zero) }; return true; } private static bool TryGetCurrentInteractTrigger(PlayerControllerB player, out InteractTrigger trigger) { trigger = null; if ((Object)(object)player == (Object)null) { return false; } CachePlayerTriggerMembers(); string[] preferredPlayerTriggerFieldNames = PreferredPlayerTriggerFieldNames; foreach (string fieldName in preferredPlayerTriggerFieldNames) { FieldInfo fieldInfo = _cachedPlayerTriggerFields.FirstOrDefault((FieldInfo f) => f.Name.Equals(fieldName, StringComparison.Ordinal)); if (!(fieldInfo == null)) { object? value = fieldInfo.GetValue(player); InteractTrigger val = (InteractTrigger)((value is InteractTrigger) ? value : null); if ((Object)(object)val != (Object)null) { trigger = val; return true; } } } FieldInfo[] cachedPlayerTriggerFields = _cachedPlayerTriggerFields; for (int i = 0; i < cachedPlayerTriggerFields.Length; i++) { object? value2 = cachedPlayerTriggerFields[i].GetValue(player); InteractTrigger val2 = (InteractTrigger)((value2 is InteractTrigger) ? value2 : null); if ((Object)(object)val2 != (Object)null) { trigger = val2; return true; } } PropertyInfo[] cachedPlayerTriggerProperties = _cachedPlayerTriggerProperties; foreach (PropertyInfo propertyInfo in cachedPlayerTriggerProperties) { try { object? value3 = propertyInfo.GetValue(player); InteractTrigger val3 = (InteractTrigger)((value3 is InteractTrigger) ? value3 : null); if ((Object)(object)val3 != (Object)null) { trigger = val3; return true; } } catch { } } return false; } private static void CachePlayerTriggerMembers() { if (_cachedPlayerTriggerFields == null || _cachedPlayerTriggerProperties == null) { _cachedPlayerTriggerFields = (from f in typeof(PlayerControllerB).GetFields(InstanceFlags) where typeof(InteractTrigger).IsAssignableFrom(f.FieldType) select f).ToArray(); _cachedPlayerTriggerProperties = (from p in typeof(PlayerControllerB).GetProperties(InstanceFlags) where p.GetIndexParameters().Length == 0 && p.CanRead && typeof(InteractTrigger).IsAssignableFrom(p.PropertyType) select p).ToArray(); } } private static bool HasUsableInteractCollider(GameObject hostObject) { if ((Object)(object)hostObject == (Object)null) { return false; } Collider[] components = hostObject.GetComponents(); foreach (Collider val in components) { if ((Object)(object)val != (Object)null && val.enabled) { return true; } } return false; } } public static class ReviveLogic { [CompilerGenerated] private sealed class d__10 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: { <>1__state = -1; PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || !val.isPlayerDead || (Object)(object)HUDManager.Instance == (Object)null) { return false; } HUDManager.Instance.UpdateBoxesSpectateUI(); return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static ManualLogSource _log; public static void SetLogSource(ManualLogSource logSource) { _log = logSource; } public static void ApplyRevive(int playerClientId, int health, int remainingRevives, Vector3 revivePosition, bool isInsideFactory, ulong maskedNetworkObjectId = 0uL) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(playerClientId); if ((Object)(object)playerByClientId == (Object)null) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)$"Cannot revive player {playerClientId}: player not found."); } return; } bool isPlayerDead = playerByClientId.isPlayerDead; ModState.RemainingRevives = remainingRevives; if (!isPlayerDead) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)$"Ignoring revive for {playerClientId}: already alive."); } return; } PlayerDeathType playerLastDeathType = GeneralUtil.GetPlayerLastDeathType(playerClientId); ulong playerLastDeathNetworkObjectId = GeneralUtil.GetPlayerLastDeathNetworkObjectId(playerClientId); RagdollGrabbableObject val = null; MaskedPlayerEnemy val2 = null; switch (playerLastDeathType) { case PlayerDeathType.Body: val = GeneralUtil.GetBodyByNetworkObjectId(playerLastDeathNetworkObjectId); if ((Object)(object)val == (Object)null) { val = GeneralUtil.GetBodyForPlayer(playerClientId); } break; case PlayerDeathType.Masked: val2 = GeneralUtil.GetMaskedByNetworkObjectId(playerLastDeathNetworkObjectId); if ((Object)(object)val2 == (Object)null) { val2 = GeneralUtil.GetConvertedMaskedCorpseForPlayer(playerClientId); } break; } try { RevivePlayerState(playerByClientId, health, revivePosition, isInsideFactory); RemoveBody(val); if ((Object)(object)val2 != (Object)null) { MethodInfo method = typeof(ReviveInteractTriggerManager).GetMethod("RemoveEntry", BindingFlags.Static | BindingFlags.NonPublic); if (method != null) { method.Invoke(null, new object[1] { playerClientId }); } } DeathMarkerManager.ClearMarker(playerClientId); GeneralUtil.ClearPlayerDeathState(playerClientId); MaskedConversionTracker.ForgetPlayer(playerClientId); ShowReviveTip(playerByClientId, remainingRevives); RefreshSpectatorListForDeadPlayers(); } catch (Exception arg) { ManualLogSource log3 = _log; if (log3 != null) { log3.LogError((object)$"Error while reviving player {playerClientId}: {arg}"); } } } private static void RevivePlayerState(PlayerControllerB player, int health, Vector3 revivePosition, bool isInsideFactory) { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) int num = (int)player.playerClientId; player.ResetPlayerBloodObjects(player.isPlayerDead); player.isClimbingLadder = false; player.ResetZAndXRotation(); if ((Object)(object)player.thisController != (Object)null) { ((Collider)player.thisController).enabled = true; } player.health = health; player.disableLookInput = false; player.isPlayerDead = false; player.isPlayerControlled = true; player.isInElevator = !isInsideFactory; player.isInHangarShipRoom = !isInsideFactory; player.isInsideFactory = isInsideFactory; player.setPositionOfDeadPlayer = false; player.deadBody = null; player.redirectToEnemy = null; if ((Object)(object)StartOfRound.Instance != (Object)null) { StartOfRound instance = StartOfRound.Instance; instance.livingPlayers++; StartOfRound.Instance.allPlayersDead = false; StartOfRound.Instance.UpdatePlayerVoiceEffects(); if (StartOfRound.Instance.allPlayerObjects != null && num >= 0 && num < StartOfRound.Instance.allPlayerObjects.Length) { player.DisablePlayerModel(StartOfRound.Instance.allPlayerObjects[num], true, true); } } player.TeleportPlayer(revivePosition, false, 0f, false, true); if ((Object)(object)player.helmetLight != (Object)null) { ((Behaviour)player.helmetLight).enabled = false; } player.Crouch(false); player.criticallyInjured = false; if ((Object)(object)player.playerBodyAnimator != (Object)null) { player.playerBodyAnimator.SetBool("Limp", false); } player.bleedingHeavily = false; player.activatingItem = false; player.twoHanded = false; player.inSpecialInteractAnimation = false; player.disableSyncInAnimation = false; player.inAnimationWithEnemy = null; player.holdingWalkieTalkie = false; player.speakingToWalkieTalkie = false; player.isSinking = false; player.isUnderwater = false; player.sinkingValue = 0f; player.voiceMuffledByEnemy = false; player.hasBegunSpectating = false; player.hinderedMultiplier = 1f; player.isMovementHindered = 0; player.sourcesCausingSinking = 0; if ((Object)(object)player.statusEffectAudio != (Object)null) { player.statusEffectAudio.Stop(); } player.DisableJetpackControlsLocally(); if ((Object)(object)player.mapRadarDotAnimator != (Object)null) { player.mapRadarDotAnimator.SetBool("dead", false); } if ((Object)(object)StartOfRound.Instance != (Object)null) { player.reverbPreset = StartOfRound.Instance.shipReverb; } FixVoiceState(player, num); FixLocalPlayerUiIfNeeded(player, health); } private static void FixVoiceState(PlayerControllerB player, int playerIndex) { try { if ((Object)(object)SoundManager.Instance != (Object)null) { SoundManager.Instance.earsRingingTimer = 0f; if (SoundManager.Instance.playerVoicePitchTargets != null && playerIndex >= 0 && playerIndex < SoundManager.Instance.playerVoicePitchTargets.Length) { SoundManager.Instance.playerVoicePitchTargets[playerIndex] = 1f; SoundManager.Instance.SetPlayerPitch(1f, playerIndex); } } if ((Object)(object)player.currentVoiceChatIngameSettings == (Object)null && (Object)(object)StartOfRound.Instance != (Object)null) { StartOfRound.Instance.RefreshPlayerVoicePlaybackObjects(); } if (!((Object)(object)player.currentVoiceChatIngameSettings != (Object)null)) { return; } if ((Object)(object)player.currentVoiceChatIngameSettings.voiceAudio == (Object)null) { player.currentVoiceChatIngameSettings.InitializeComponents(); } if ((Object)(object)player.currentVoiceChatIngameSettings.voiceAudio != (Object)null) { OccludeAudio component = ((Component)player.currentVoiceChatIngameSettings.voiceAudio).GetComponent(); if ((Object)(object)component != (Object)null) { component.overridingLowPass = false; } } } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Voice reset skipped: " + ex.Message)); } } } private static void FixLocalPlayerUiIfNeeded(PlayerControllerB revivedPlayer, int health) { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || val.playerClientId != revivedPlayer.playerClientId) { return; } val.bleedingHeavily = false; val.criticallyInjured = false; val.isPlayerDead = false; val.isPlayerControlled = true; val.disableLookInput = false; val.hasBegunSpectating = false; val.health = health; val.spectatedPlayerScript = null; if ((Object)(object)val.playerBodyAnimator != (Object)null) { val.playerBodyAnimator.SetBool("Limp", false); } if ((Object)(object)HUDManager.Instance != (Object)null) { if ((Object)(object)HUDManager.Instance.audioListenerLowPass != (Object)null) { ((Behaviour)HUDManager.Instance.audioListenerLowPass).enabled = false; } HUDManager.Instance.UpdateHealthUI(health, true); HUDManager.Instance.RemoveSpectateUI(); if ((Object)(object)HUDManager.Instance.gasHelmetAnimator != (Object)null) { HUDManager.Instance.gasHelmetAnimator.SetBool("gasEmitting", false); } if ((Object)(object)HUDManager.Instance.gameOverAnimator != (Object)null) { HUDManager.Instance.gameOverAnimator.SetTrigger("revive"); } } if ((Object)(object)StartOfRound.Instance != (Object)null) { StartOfRound.Instance.SetSpectateCameraToGameOverMode(false, val); StartOfRound.Instance.SetPlayerObjectExtrapolate(false); } } private static void RemoveBody(RagdollGrabbableObject body) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0047: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)body == (Object)null) { return; } try { if ((Object)(object)body != (Object)null && ((GrabbableObject)body).isHeld && (Object)(object)((GrabbableObject)body).playerHeldBy != (Object)null) { ((GrabbableObject)body).playerHeldBy.DropAllHeldItems(true, false, false, false, default(Vector3), default(Vector3), default(Vector3), default(Vector3), default(Vector3)); } NetworkObject networkObject = ((NetworkBehaviour)body).NetworkObject; if ((Object)(object)networkObject != (Object)null && networkObject.IsSpawned) { if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer) { networkObject.Despawn(true); } return; } if ((Object)(object)body.ragdoll != (Object)null) { Object.Destroy((Object)(object)((Component)body.ragdoll).gameObject); } if ((Object)(object)((Component)body).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)body).gameObject); } } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Body removal skipped: " + ex.Message)); } } } private static void RemoveMaskedCorpse(MaskedPlayerEnemy masked) { if ((Object)(object)masked == (Object)null) { return; } MaskedOriginInfo component = ((Component)masked).GetComponent(); if ((Object)(object)component != (Object)null && (component.Origin == MaskedOrigin.ConvertedByMaskedEnemy || component.Origin == MaskedOrigin.ConvertedByMaskItem)) { MethodInfo method = typeof(ReviveInteractTriggerManager).GetMethod("RemoveEntry", BindingFlags.Static | BindingFlags.NonPublic); if (method != null) { method.Invoke(null, new object[1] { component.FormerPlayerClientId }); } return; } try { NetworkObject val = ((masked != null) ? ((NetworkBehaviour)masked).NetworkObject : null); if ((Object)(object)val != (Object)null && val.IsSpawned) { if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer) { val.Despawn(true); } } else if ((Object)(object)((Component)masked).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)masked).gameObject); } } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Masked corpse removal skipped: " + ex.Message)); } } } private static void ShowReviveTip(PlayerControllerB player, int remainingRevives) { if (!((Object)(object)HUDManager.Instance == (Object)null)) { string text = (ModConfig.LimitedRevives ? $"{remainingRevives} revives left." : "Unlimited revives."); HUDManager.Instance.DisplayTip("Revive", player.playerUsername + " was revived. " + text, false, false, "LC_Tip1"); PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val != (Object)null && val.isPlayerDead) { HUDManager.Instance.UpdateBoxesSpectateUI(); } } } private static void RefreshSpectatorListForDeadPlayers() { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (!((Object)(object)val == (Object)null) && val.isPlayerDead && !((Object)(object)HUDManager.Instance == (Object)null)) { HUDManager.Instance.UpdateBoxesSpectateUI(); if ((Object)(object)StartOfRound.Instance != (Object)null) { ((MonoBehaviour)StartOfRound.Instance).StartCoroutine(RefreshSpectatorListDelayed()); } } } [IteratorStateMachine(typeof(d__10))] private static IEnumerator RefreshSpectatorListDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__10(0); } } public static class ReviveNetwork { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnRequestRevive; public static HandleNamedMessageDelegate <1>__OnPerformRevive; public static HandleNamedMessageDelegate <2>__OnRejectRevive; public static HandleNamedMessageDelegate <3>__OnSyncConfig; } private const string RequestReviveMessage = "UltimateRevive.RequestRevive.v2"; private const string PerformReviveMessage = "UltimateRevive.PerformRevive.v2"; private const string RejectReviveMessage = "UltimateRevive.RejectRevive.v2"; private const string SyncConfigMessage = "UltimateRevive.SyncConfig.v1"; private static ManualLogSource _log; private static bool _registered; private static readonly HashSet _configSyncedClientIds = new HashSet(); public static void SetLogSource(ManualLogSource logSource) { _log = logSource; } public static void TryRegisterHandlers() { //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_004c: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown if (!_registered && !((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.CustomMessagingManager != null) { CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager; object obj = <>O.<0>__OnRequestRevive; if (obj == null) { HandleNamedMessageDelegate val = OnRequestRevive; <>O.<0>__OnRequestRevive = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("UltimateRevive.RequestRevive.v2", (HandleNamedMessageDelegate)obj); object obj2 = <>O.<1>__OnPerformRevive; if (obj2 == null) { HandleNamedMessageDelegate val2 = OnPerformRevive; <>O.<1>__OnPerformRevive = val2; obj2 = (object)val2; } customMessagingManager.RegisterNamedMessageHandler("UltimateRevive.PerformRevive.v2", (HandleNamedMessageDelegate)obj2); object obj3 = <>O.<2>__OnRejectRevive; if (obj3 == null) { HandleNamedMessageDelegate val3 = OnRejectRevive; <>O.<2>__OnRejectRevive = val3; obj3 = (object)val3; } customMessagingManager.RegisterNamedMessageHandler("UltimateRevive.RejectRevive.v2", (HandleNamedMessageDelegate)obj3); object obj4 = <>O.<3>__OnSyncConfig; if (obj4 == null) { HandleNamedMessageDelegate val4 = OnSyncConfig; <>O.<3>__OnSyncConfig = val4; obj4 = (object)val4; } customMessagingManager.RegisterNamedMessageHandler("UltimateRevive.SyncConfig.v1", (HandleNamedMessageDelegate)obj4); _registered = true; ModState.Active = true; _configSyncedClientIds.Clear(); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)"Custom networking registered."); } } } public static void UnregisterHandlers() { if (_registered && !((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.CustomMessagingManager != null) { CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager; customMessagingManager.UnregisterNamedMessageHandler("UltimateRevive.RequestRevive.v2"); customMessagingManager.UnregisterNamedMessageHandler("UltimateRevive.PerformRevive.v2"); customMessagingManager.UnregisterNamedMessageHandler("UltimateRevive.RejectRevive.v2"); customMessagingManager.UnregisterNamedMessageHandler("UltimateRevive.SyncConfig.v1"); _registered = false; ModState.Active = false; _configSyncedClientIds.Clear(); } } public static void SendConfigToClients() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (!GeneralUtil.IsNetworkReady() || !NetworkManager.Singleton.IsServer) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(128, (Allocator)2, -1); try { WriteConfigPayload(val); List list = new List(); foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != 0L) { list.Add(connectedClientsId); } } if (list.Count <= 0) { return; } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("UltimateRevive.SyncConfig.v1", (IReadOnlyList)list, val, (NetworkDelivery)3); foreach (ulong item in list) { _configSyncedClientIds.Add(item); } ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"Config synchronized to {list.Count} client(s)."); } } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } public static void SyncConfigForNewClients() { //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) if (!GeneralUtil.IsNetworkReady() || !NetworkManager.Singleton.IsServer || NetworkManager.Singleton.CustomMessagingManager == null) { return; } HashSet connectedClientIds = new HashSet(); foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { connectedClientIds.Add(connectedClientsId); } _configSyncedClientIds.RemoveWhere((ulong id) => !connectedClientIds.Contains(id)); List list = new List(); foreach (ulong connectedClientsId2 in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId2 != 0L && !_configSyncedClientIds.Contains(connectedClientsId2)) { list.Add(connectedClientsId2); } } if (list.Count == 0) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(128, (Allocator)2, -1); try { WriteConfigPayload(val); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("UltimateRevive.SyncConfig.v1", (IReadOnlyList)list, val, (NetworkDelivery)3); foreach (ulong item in list) { _configSyncedClientIds.Add(item); } ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"Config synchronized to {list.Count} new client(s)."); } } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } public static void RequestRevive(int targetPlayerClientId) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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) TryRegisterHandlers(); if (!GeneralUtil.IsNetworkReady()) { ShowLocalTip("Revive failed", "Network is not ready.", warning: true); return; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return; } int reviverPlayerClientId = (int)val.playerClientId; if (NetworkManager.Singleton.IsServer) { ProcessReviveRequest(reviverPlayerClientId, targetPlayerClientId, NetworkManager.Singleton.LocalClientId); return; } FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(8, (Allocator)2, -1); try { ((FastBufferWriter)(ref val2)).WriteValueSafe(ref reviverPlayerClientId, default(ForPrimitives)); ((FastBufferWriter)(ref val2)).WriteValueSafe(ref targetPlayerClientId, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("UltimateRevive.RequestRevive.v2", 0uL, val2, (NetworkDelivery)3); } finally { ((IDisposable)(FastBufferWriter)(ref val2)).Dispose(); } } private static void OnRequestRevive(ulong senderClientId, FastBufferReader reader) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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) if (NetworkManager.Singleton.IsServer) { int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); int targetPlayerClientId = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref targetPlayerClientId, default(ForPrimitives)); ProcessReviveRequest(((Object)(object)GeneralUtil.GetPlayerByClientId((int)senderClientId) != (Object)null) ? ((int)senderClientId) : num, targetPlayerClientId, senderClientId); } } private static void ProcessReviveRequest(int reviverPlayerClientId, int targetPlayerClientId, ulong requestingNetworkClientId) { //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: 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_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_0429: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(reviverPlayerClientId); GeneralUtil.GetPlayerByClientId(targetPlayerClientId); PlayerDeathType playerLastDeathType = GeneralUtil.GetPlayerLastDeathType(targetPlayerClientId); ulong playerLastDeathNetworkObjectId = GeneralUtil.GetPlayerLastDeathNetworkObjectId(targetPlayerClientId); RagdollGrabbableObject val = null; MaskedPlayerEnemy val2 = null; bool flag; int targetPlayerClientId2; string reason2; if (playerLastDeathType == PlayerDeathType.Masked) { if (!ModConfig.EnableMaskedPlayerRevive) { SendReject(requestingNetworkClientId, "masked revive disabled"); return; } val2 = ((playerLastDeathNetworkObjectId != 0L) ? GeneralUtil.GetMaskedByNetworkObjectId(playerLastDeathNetworkObjectId) : null); if ((Object)(object)val2 == (Object)null) { val2 = GeneralUtil.GetConvertedMaskedCorpseForPlayer(targetPlayerClientId); } if ((Object)(object)val2 == (Object)null) { string reason = null; if (!TryResolveTombValidationPosition(targetPlayerClientId, out var position, out var method) || !GeneralUtil.IsReviverCloseEnoughToTomb(playerByClientId, position) || !ReviveRules.CanReviveAtTomb(playerByClientId, targetPlayerClientId, out reason)) { Plugin.DebugLog(string.Format("[ReviveMethod] tombValidation player={0} death=Masked method={1} result=reject reason={2}", targetPlayerClientId, method ?? "none", string.IsNullOrEmpty(reason) ? "monitor target source missing" : reason)); SendReject(requestingNetworkClientId, string.IsNullOrEmpty(reason) ? "monitor target source missing" : reason); } else { Plugin.DebugLog($"[ReviveMethod] tombValidation player={targetPlayerClientId} death=Masked method={method} result=ok"); CompleteTombRevive(targetPlayerClientId, position); } return; } if (!GeneralUtil.TryResolveConvertedMaskedPlayer(val2, out var playerClientId, out var _) || playerClientId != targetPlayerClientId) { SendReject(requestingNetworkClientId, "monitor target source mismatch"); return; } flag = ReviveRules.CanReviveMasked(playerByClientId, val2, out targetPlayerClientId2, out reason2); } else { val = ((playerLastDeathNetworkObjectId != 0L) ? GeneralUtil.GetBodyByNetworkObjectId(playerLastDeathNetworkObjectId) : GeneralUtil.GetBodyForPlayer(targetPlayerClientId)); if ((Object)(object)val == (Object)null) { string reason3 = null; if (!TryResolveTombValidationPosition(targetPlayerClientId, out var position2, out var method2) || !GeneralUtil.IsReviverCloseEnoughToTomb(playerByClientId, position2) || !ReviveRules.CanReviveAtTomb(playerByClientId, targetPlayerClientId, out reason3)) { Plugin.DebugLog(string.Format("[ReviveMethod] tombValidation player={0} death=Body method={1} result=reject reason={2}", targetPlayerClientId, method2 ?? "none", string.IsNullOrEmpty(reason3) ? "monitor target source missing" : reason3)); SendReject(requestingNetworkClientId, string.IsNullOrEmpty(reason3) ? "monitor target source missing" : reason3); } else { Plugin.DebugLog($"[ReviveMethod] tombValidation player={targetPlayerClientId} death=Body method={method2} result=ok"); CompleteTombRevive(targetPlayerClientId, position2); } return; } if (!GeneralUtil.TryGetBodyOwner(val, out var targetPlayerClientId3, out var _) || targetPlayerClientId3 != targetPlayerClientId) { string reason4 = null; if (!DeathMarkerManager.TryGetMarkerPosition(targetPlayerClientId, out var position3)) { Plugin.DebugLog($"[ReviveMethod] tombValidation player={targetPlayerClientId} death=BodyOwnerMismatch method=marker-only result=reject reason=tomb marker missing"); SendReject(requestingNetworkClientId, "tomb marker missing"); } else if (!GeneralUtil.IsReviverCloseEnoughToTomb(playerByClientId, position3) || !ReviveRules.CanReviveAtTomb(playerByClientId, targetPlayerClientId, out reason4)) { Plugin.DebugLog(string.Format("[ReviveMethod] tombValidation player={0} death=BodyOwnerMismatch method=marker-only result=reject reason={1}", targetPlayerClientId, string.IsNullOrEmpty(reason4) ? "monitor target source mismatch" : reason4)); SendReject(requestingNetworkClientId, string.IsNullOrEmpty(reason4) ? "monitor target source mismatch" : reason4); } else { Plugin.DebugLog($"[ReviveMethod] tombValidation player={targetPlayerClientId} death=BodyOwnerMismatch method=marker-only result=ok"); CompleteTombRevive(targetPlayerClientId, position3); } return; } flag = ReviveRules.CanRevive(playerByClientId, val, out targetPlayerClientId2, out reason2); } if (!flag) { SendReject(requestingNetworkClientId, reason2); return; } PlayerControllerB playerByClientId2 = GeneralUtil.GetPlayerByClientId(targetPlayerClientId2); if ((Object)(object)playerByClientId2 == (Object)null) { SendReject(requestingNetworkClientId, "target missing"); return; } Vector3 val3 = (((Object)(object)val != (Object)null && (Object)(object)((Component)val).transform != (Object)null) ? ((Component)val).transform.position : ((Component)val2).transform.position); if (!GeneralUtil.IsReviverCloseEnough(playerByClientId, val3)) { SendReject(requestingNetworkClientId, "too far from body"); return; } bool isInsideFactory = playerByClientId2.isInsideFactory; ulong maskedNetworkObjectId = (((Object)(object)val2 != (Object)null) ? MaskedConversionTracker.GetNetworkObjectId(val2) : 0); PlayerControllerB closestAlivePlayer = GeneralUtil.GetClosestAlivePlayer(val3); if ((Object)(object)closestAlivePlayer != (Object)null) { isInsideFactory = closestAlivePlayer.isInsideFactory; if (Vector3.Distance(val3, ((Component)closestAlivePlayer).transform.position) > 7f) { val3 = ((Component)closestAlivePlayer).transform.position; } } int health = GeneralUtil.IncrementReviveCountAndGetHealth(targetPlayerClientId2); if (ModConfig.LimitedRevives) { ModState.RemainingRevives = Mathf.Max(0, ModState.RemainingRevives - 1); } if ((Object)(object)val2 != (Object)null) { ulong networkObjectId = MaskedConversionTracker.GetNetworkObjectId(val2); Vector3 deathPosition = (((Object)(object)((Component)val2).transform != (Object)null) ? ((Component)val2).transform.position : val3); GeneralUtil.SetPlayerDeathState(targetPlayerClientId2, PlayerDeathType.Masked, networkObjectId, deathPosition, "ReviveNetwork:FinalizeSourceMasked"); } else if ((Object)(object)val != (Object)null) { ulong networkObjectId2 = (((Object)(object)((NetworkBehaviour)val).NetworkObject != (Object)null) ? ((NetworkBehaviour)val).NetworkObject.NetworkObjectId : 0); Vector3 deathPosition2 = (((Object)(object)((Component)val).transform != (Object)null) ? ((Component)val).transform.position : val3); GeneralUtil.SetPlayerDeathState(targetPlayerClientId2, PlayerDeathType.Body, networkObjectId2, deathPosition2, "ReviveNetwork:FinalizeSourceBody"); } BroadcastRevive(targetPlayerClientId2, health, ModState.RemainingRevives, val3, isInsideFactory, maskedNetworkObjectId); } private static void CompleteTombRevive(int targetPlayerClientId, Vector3 tombPos) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_006d: 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) PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(targetPlayerClientId); if ((Object)(object)playerByClientId == (Object)null) { return; } int health = GeneralUtil.IncrementReviveCountAndGetHealth(targetPlayerClientId); if (ModConfig.LimitedRevives) { ModState.RemainingRevives = Mathf.Max(0, ModState.RemainingRevives - 1); } bool isInsideFactory = playerByClientId.isInsideFactory; PlayerControllerB closestAlivePlayer = GeneralUtil.GetClosestAlivePlayer(tombPos); if ((Object)(object)closestAlivePlayer != (Object)null) { isInsideFactory = closestAlivePlayer.isInsideFactory; if (Vector3.Distance(tombPos, ((Component)closestAlivePlayer).transform.position) > 7f) { tombPos = ((Component)closestAlivePlayer).transform.position; } } BroadcastRevive(targetPlayerClientId, health, ModState.RemainingRevives, tombPos, isInsideFactory, 0uL); } private static void BroadcastRevive(int targetPlayerClientId, int health, int remainingRevives, Vector3 position, bool insideFactory, ulong maskedNetworkObjectId) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) ReviveLogic.ApplyRevive(targetPlayerClientId, health, remainingRevives, position, insideFactory, maskedNetworkObjectId); if (!GeneralUtil.IsNetworkReady()) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(96, (Allocator)2, -1); try { WriteRevivePayload(val, targetPlayerClientId, health, remainingRevives, position, insideFactory, maskedNetworkObjectId); List list = new List(); foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != 0L) { list.Add(connectedClientsId); } } if (list.Count > 0) { NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("UltimateRevive.PerformRevive.v2", (IReadOnlyList)list, val, (NetworkDelivery)3); } } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private static void OnPerformRevive(ulong senderClientId, FastBufferReader reader) { //IL_0000: 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) ReadRevivePayload(reader, out var targetPlayerClientId, out var health, out var remainingRevives, out var position, out var insideFactory, out var maskedNetworkObjectId); ReviveLogic.ApplyRevive(targetPlayerClientId, health, remainingRevives, position, insideFactory, maskedNetworkObjectId); } private static void SendReject(ulong networkClientId, string reason) { //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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.CustomMessagingManager == null) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(256, (Allocator)2, -1); try { FixedString128Bytes val2 = new FixedString128Bytes(reason ?? "unknown reason"); ((FastBufferWriter)(ref val)).WriteValueSafe(ref val2, default(ForFixedStrings)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("UltimateRevive.RejectRevive.v2", networkClientId, val, (NetworkDelivery)3); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private static void OnRejectRevive(ulong senderClientId, FastBufferReader reader) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) FixedString128Bytes val = default(FixedString128Bytes); ((FastBufferReader)(ref reader)).ReadValueSafe(ref val, default(ForFixedStrings)); ShowLocalTip("Cannot revive", ((object)(FixedString128Bytes)(ref val)).ToString(), warning: true); } private static void WriteRevivePayload(FastBufferWriter writer, int targetPlayerClientId, int health, int remainingRevives, Vector3 position, bool insideFactory, ulong maskedNetworkObjectId) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_001e: 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_0030: 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_0047: 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_005e: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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) ((FastBufferWriter)(ref writer)).WriteValueSafe(ref targetPlayerClientId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref health, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref remainingRevives, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref position.x, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref position.y, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref position.z, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref insideFactory, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref maskedNetworkObjectId, default(ForPrimitives)); } private static void ReadRevivePayload(FastBufferReader reader, out int targetPlayerClientId, out int health, out int remainingRevives, out Vector3 position, out bool insideFactory, out ulong maskedNetworkObjectId) { //IL_0005: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0051: 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_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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) ((FastBufferReader)(ref reader)).ReadValueSafe(ref targetPlayerClientId, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref health, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref remainingRevives, default(ForPrimitives)); float num = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); float num2 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num2, default(ForPrimitives)); float num3 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num3, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref insideFactory, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref maskedNetworkObjectId, default(ForPrimitives)); position = new Vector3(num, num2, num3); } private static void ShowLocalTip(string title, string body, bool warning) { if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip(title, body, warning, false, "LC_Tip1"); } } private static void WriteConfigPayload(FastBufferWriter writer) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_0072: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.ReviveTime, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.CanPickUpBodies, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.DeadBodyWeight, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.CanReviveTeleportedBodies, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.ReviveHealth, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.ExtraHealthLostPerRevive, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.LimitedRevives, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.RevivesPerLevelMultiplier, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.FixedRevivesPerLevel, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.InfiniteReviveTime, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.TimeUntilCannotBeRevived, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.MaxReviveDistance, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.MaxReviveDistanceTomb, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.EnableMaskedPlayerRevive, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.EnableDeathTombFallback, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.EnableDeathTombCollider, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.DeathTombGroundOffset, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ModConfig.DeathTombSpawnHeight, default(ForPrimitives)); } private static void ReadConfigPayload(FastBufferReader reader, out float reviveTime, out bool canPickUpBodies, out float deadBodyWeight, out bool canReviveTeleportedBodies, out int reviveHealth, out int extraHealthLostPerRevive, out bool limitedRevives, out float revivesPerLevelMultiplier, out int fixedRevivesPerLevel, out bool infiniteReviveTime, out int timeUntilCannotBeRevived, out float maxReviveDistance, out float maxReviveDistanceTomb, out bool enableMaskedPlayerRevive, out bool enableDeathTombFallback, out bool enableDeathTombCollider, out string deathTombAssetBundlePath, out string deathTombPrefabName, out float deathTombGroundOffset, out float deathTombSpawnHeight) { //IL_0005: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0051: 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_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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_0117: 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_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) ((FastBufferReader)(ref reader)).ReadValueSafe(ref reviveTime, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref canPickUpBodies, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref deadBodyWeight, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref canReviveTeleportedBodies, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref reviveHealth, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref extraHealthLostPerRevive, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref limitedRevives, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref revivesPerLevelMultiplier, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref fixedRevivesPerLevel, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref infiniteReviveTime, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref timeUntilCannotBeRevived, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref maxReviveDistance, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref maxReviveDistanceTomb, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref enableMaskedPlayerRevive, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref enableDeathTombFallback, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref enableDeathTombCollider, default(ForPrimitives)); FixedString512Bytes val = default(FixedString512Bytes); ((FastBufferReader)(ref reader)).ReadValueSafe(ref val, default(ForFixedStrings)); deathTombAssetBundlePath = ((object)(FixedString512Bytes)(ref val)).ToString(); FixedString128Bytes val2 = default(FixedString128Bytes); ((FastBufferReader)(ref reader)).ReadValueSafe(ref val2, default(ForFixedStrings)); deathTombPrefabName = ((object)(FixedString128Bytes)(ref val2)).ToString(); ((FastBufferReader)(ref reader)).ReadValueSafe(ref deathTombGroundOffset, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref deathTombSpawnHeight, default(ForPrimitives)); } private static void OnSyncConfig(ulong senderClientId, FastBufferReader reader) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsServer && senderClientId == 0L) { ReadConfigPayload(reader, out var reviveTime, out var canPickUpBodies, out var deadBodyWeight, out var canReviveTeleportedBodies, out var reviveHealth, out var extraHealthLostPerRevive, out var limitedRevives, out var revivesPerLevelMultiplier, out var fixedRevivesPerLevel, out var infiniteReviveTime, out var timeUntilCannotBeRevived, out var maxReviveDistance, out var maxReviveDistanceTomb, out var enableMaskedPlayerRevive, out var enableDeathTombFallback, out var enableDeathTombCollider, out var deathTombAssetBundlePath, out var deathTombPrefabName, out var deathTombGroundOffset, out var deathTombSpawnHeight); ModConfig.ApplySyncedConfig(reviveTime, canPickUpBodies, deadBodyWeight, canReviveTeleportedBodies, reviveHealth, extraHealthLostPerRevive, limitedRevives, revivesPerLevelMultiplier, fixedRevivesPerLevel, infiniteReviveTime, timeUntilCannotBeRevived, maxReviveDistance, maxReviveDistanceTomb, enableMaskedPlayerRevive, enableDeathTombFallback, enableDeathTombCollider, deathTombAssetBundlePath, deathTombPrefabName, deathTombGroundOffset, deathTombSpawnHeight); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)"Received config synchronization from host."); } } } private static bool TryResolveTombValidationPosition(int playerClientId, out Vector3 position, out string method) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (DeathMarkerManager.TryGetMarkerPosition(playerClientId, out position)) { method = "active-marker"; return true; } if (!ModConfig.EnableDeathTombFallback && GeneralUtil.TryGetPlayerLastDeathPosition(playerClientId, out position)) { method = "death-position-exception"; return true; } method = "none"; position = default(Vector3); return false; } } public static class ReviveRules { public static bool CanRevive(PlayerControllerB reviver, RagdollGrabbableObject body, out int targetPlayerClientId, out string reason) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) targetPlayerClientId = -1; reason = string.Empty; if (!ModState.Active) { return false; } if ((Object)(object)reviver == (Object)null || reviver.isPlayerDead) { return false; } if (!GeneralUtil.TryGetBodyOwner(body, out targetPlayerClientId, out var targetPlayer)) { return false; } if (!targetPlayer.isPlayerDead) { return false; } if ((int)reviver.playerClientId == targetPlayerClientId) { return false; } if ((Object)(object)body == (Object)null || (Object)(object)((Component)body).transform == (Object)null || !GeneralUtil.IsReviverCloseEnough(reviver, ((Component)body).transform.position)) { return false; } if (ModConfig.LimitedRevives && ModState.RemainingRevives <= 0) { reason = "no revives left"; return false; } if (!ModConfig.CanReviveTeleportedBodies && (Object)(object)body != (Object)null && (Object)(object)((Component)body).gameObject.GetComponent() != (Object)null) { reason = "body was teleported"; return false; } if (!ModConfig.InfiniteReviveTime && Time.time - GeneralUtil.GetPlayerDiedAtTime(targetPlayerClientId) > (float)ModConfig.TimeUntilCannotBeRevived) { reason = "time expired"; return false; } return true; } public static float SecondsLeft(int targetPlayerClientId) { if (ModConfig.InfiniteReviveTime) { return float.PositiveInfinity; } float num = Time.time - GeneralUtil.GetPlayerDiedAtTime(targetPlayerClientId); return Mathf.Max(0f, (float)ModConfig.TimeUntilCannotBeRevived - num); } public static bool CanReviveMasked(PlayerControllerB reviver, MaskedPlayerEnemy masked, out int targetPlayerClientId, out string reason) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) targetPlayerClientId = -1; reason = string.Empty; if (!ModState.Active) { return false; } if (!ModConfig.EnableMaskedPlayerRevive) { return false; } if ((Object)(object)reviver == (Object)null || reviver.isPlayerDead) { return false; } if ((Object)(object)masked == (Object)null) { return false; } if (!MaskedConversionTracker.IsMaskedDead(masked)) { reason = "kill masked first"; return false; } if (!GeneralUtil.TryResolveConvertedMaskedPlayer(masked, out targetPlayerClientId, out var _)) { return false; } PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(targetPlayerClientId); if ((Object)(object)playerByClientId == (Object)null) { return false; } if (!playerByClientId.isPlayerDead) { return false; } if ((int)reviver.playerClientId == targetPlayerClientId) { return false; } if ((Object)(object)masked == (Object)null || (Object)(object)((Component)masked).transform == (Object)null || !GeneralUtil.IsReviverCloseEnough(reviver, ((Component)masked).transform.position)) { return false; } if (ModConfig.LimitedRevives && ModState.RemainingRevives <= 0) { reason = "no revives left"; return false; } if (!ModConfig.InfiniteReviveTime && Time.time - GeneralUtil.GetPlayerDiedAtTime(targetPlayerClientId) > (float)ModConfig.TimeUntilCannotBeRevived) { reason = "time expired"; return false; } return true; } public static bool CanReviveAtTomb(PlayerControllerB reviver, int targetPlayerClientId, out string reason) { reason = string.Empty; if (!ModState.Active) { return false; } if ((Object)(object)reviver == (Object)null || reviver.isPlayerDead) { reason = "reviver invalid"; return false; } PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(targetPlayerClientId); if ((Object)(object)playerByClientId == (Object)null || !playerByClientId.isPlayerDead) { return false; } if ((int)reviver.playerClientId == targetPlayerClientId) { return false; } if (ModConfig.LimitedRevives && ModState.RemainingRevives <= 0) { reason = "no revives left"; return false; } if (!ModConfig.InfiniteReviveTime && Time.time - GeneralUtil.GetPlayerDiedAtTime(targetPlayerClientId) > (float)ModConfig.TimeUntilCannotBeRevived) { reason = "time expired"; return false; } return true; } } public static class TombDeadBodySetup { public sealed class UltimateReviveTombMarker : MonoBehaviour { public int playerId; } [CompilerGenerated] private sealed class d__8 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public PlayerControllerB player; public DeadBodyInfo body; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__8(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; EnsurePlayerIsRadarTarget(player); SyncDeadPlayerToTomb(player, body); <>2__current = (object)new WaitForSeconds(0.25f); <>1__state = 2; return true; case 2: <>1__state = -1; EnsurePlayerIsRadarTarget(player); SyncDeadPlayerToTomb(player, body); <>2__current = (object)new WaitForSeconds(1f); <>1__state = 3; return true; case 3: <>1__state = -1; EnsurePlayerIsRadarTarget(player); SyncDeadPlayerToTomb(player, body); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly Dictionary ActiveTombBodies = new Dictionary(); private static readonly Dictionary NextRadarCheck = new Dictionary(); public static DeadBodyInfo SetupTombAsDeadBody(PlayerControllerB player, GameObject tombObject, Vector3 position) { //IL_0024: 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) DeadBodyInfo val = tombObject.GetComponent(); if ((Object)(object)val == (Object)null) { val = tombObject.AddComponent(); } int playerIndex = GetPlayerIndex(player); tombObject.transform.position = position; val.playerObjectId = playerIndex; val.playerScript = player; val.setMaterialToPlayerSuit = false; val.bodyBleedingHeavily = false; val.detachedHead = false; val.overrideSpawnPosition = true; val.causeOfDeath = (CauseOfDeath)0; val.attachedLimb = null; val.attachedTo = null; val.secondaryAttachedLimb = null; val.secondaryAttachedTo = null; val.grabBodyObject = null; val.bloodSplashParticle = null; val.beamUpParticle = null; val.beamOutParticle = null; val.playAudioOnDeath = null; val.bodyBloodDecals = Array.Empty(); val.canBeGrabbedBackByPlayers = false; val.deactivated = false; val.radarDot = EnsureRadarDot(tombObject.transform); val.nightVisionRadar = EnsureNightVisionRadar(tombObject.transform); val.bodyParts = EnsureBodyParts(tombObject.transform, player); SanitizeTombPhysics(tombObject); player.isPlayerDead = true; player.redirectToEnemy = null; player.deadBody = val; EnsurePlayerIsRadarTarget(player); SyncDeadPlayerToTomb(player, val); RegisterActiveTomb(player, val); ForceMonitorTargetToPlayer(player); UltimateReviveTombMarker ultimateReviveTombMarker = tombObject.GetComponent(); if ((Object)(object)ultimateReviveTombMarker == (Object)null) { ultimateReviveTombMarker = tombObject.AddComponent(); } ultimateReviveTombMarker.playerId = playerIndex; Debug.LogWarning((object)("[UltimateRevive][TombSetupOK] " + $"player={player.playerClientId} " + "body=" + ((Object)val).name + " " + $"deadBodyAssigned={(Object)(object)player.deadBody == (Object)(object)val} " + "radarDot=" + (((Object)(object)val.radarDot == (Object)null) ? "NULL" : ((object)val.radarDot).GetType().Name) + " nightVisionRadar=" + (((Object)(object)val.nightVisionRadar == (Object)null) ? "NULL" : "ok") + " parts=" + ((val.bodyParts == null) ? "NULL" : val.bodyParts.Length.ToString()))); return val; } public static void RegisterActiveTomb(PlayerControllerB player, DeadBodyInfo body) { if (!((Object)(object)player == (Object)null) && !((Object)(object)body == (Object)null)) { int playerIndex = GetPlayerIndex(player); ActiveTombBodies[playerIndex] = body; NextRadarCheck[playerIndex] = 0f; EnsurePlayerIsRadarTarget(player); SyncDeadPlayerToTomb(player, body); } } public static void ForceMonitorTargetToPlayer(PlayerControllerB player) { if ((Object)(object)player == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return; } ManualCameraRenderer mapScreen = StartOfRound.Instance.mapScreen; if ((Object)(object)mapScreen == (Object)null || mapScreen.radarTargets == null) { return; } int num = -1; for (int i = 0; i < mapScreen.radarTargets.Count; i++) { if ((Object)(object)mapScreen.radarTargets[i].transform == (Object)(object)((Component)player).transform) { num = i; break; } } if (num < 0) { Debug.LogWarning((object)$"[UltimateRevive][RadarTarget] player={player.playerClientId} not found in radarTargets"); return; } mapScreen.targetTransformIndex = num; mapScreen.targetedPlayer = player; Debug.LogWarning((object)("[UltimateRevive][RadarTarget] forced monitor target " + $"player={player.playerClientId} index={num} " + "deadBody=" + (((Object)(object)player.deadBody == (Object)null) ? "NULL" : ((Object)player.deadBody).name))); } public static void UnregisterActiveTomb(PlayerControllerB player) { if (!((Object)(object)player == (Object)null)) { int playerIndex = GetPlayerIndex(player); ActiveTombBodies.Remove(playerIndex); NextRadarCheck.Remove(playerIndex); } } public static void TickActiveTombs() { if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null) { return; } List list = new List(); foreach (KeyValuePair activeTombBody in ActiveTombBodies) { int key = activeTombBody.Key; DeadBodyInfo value = activeTombBody.Value; if ((Object)(object)value == (Object)null || key < 0 || key >= StartOfRound.Instance.allPlayerScripts.Length) { list.Add(key); continue; } PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[key]; if ((Object)(object)val == (Object)null || !val.isPlayerDead || (Object)(object)val.deadBody != (Object)(object)value) { list.Add(key); continue; } SyncDeadPlayerToTomb(val, value); if (!NextRadarCheck.TryGetValue(key, out var value2) || Time.time >= value2) { NextRadarCheck[key] = Time.time + 1f; EnsurePlayerIsRadarTarget(val); } } for (int i = 0; i < list.Count; i++) { ActiveTombBodies.Remove(list[i]); NextRadarCheck.Remove(list[i]); } } [IteratorStateMachine(typeof(d__8))] private static IEnumerator DelayedTombSync(PlayerControllerB player, DeadBodyInfo body) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__8(0) { player = player, body = body }; } private static void SanitizeTombPhysics(GameObject tombObject) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) Rigidbody component = tombObject.GetComponent(); if ((Object)(object)component != (Object)null) { if (!component.isKinematic) { component.velocity = Vector3.zero; component.angularVelocity = Vector3.zero; } component.useGravity = false; component.isKinematic = true; } MeshCollider[] componentsInChildren = tombObject.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Collider)componentsInChildren[i]).enabled = false; } Transform val = tombObject.transform.Find("TombCollision"); if ((Object)(object)val == (Object)null) { GameObject val2 = new GameObject("TombCollision"); val2.transform.SetParent(tombObject.transform, false); val = val2.transform; } BoxCollider val3 = ((Component)val).GetComponent(); if ((Object)(object)val3 == (Object)null) { val3 = ((Component)val).gameObject.AddComponent(); } val3.size = new Vector3(0.6f, 1.35f, 0.35f); val3.center = new Vector3(0f, 0.675f, 0f); ((Collider)val3).isTrigger = false; ((Collider)val3).enabled = true; } public static void EnsurePlayerIsRadarTarget(PlayerControllerB player) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown if ((Object)(object)player == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return; } ManualCameraRenderer mapScreen = StartOfRound.Instance.mapScreen; if ((Object)(object)mapScreen == (Object)null || mapScreen.radarTargets == null) { return; } for (int i = 0; i < mapScreen.radarTargets.Count; i++) { if ((Object)(object)mapScreen.radarTargets[i].transform == (Object)(object)((Component)player).transform) { Debug.LogWarning((object)$"[UltimateRevive][RadarFix] player={player.playerClientId} already in radarTargets index={i}"); return; } } mapScreen.radarTargets.Add(new TransformAndName(((Component)player).transform, player.playerUsername, false)); Debug.LogWarning((object)$"[UltimateRevive][RadarFix] added dead player={player.playerClientId} to radarTargets index={mapScreen.radarTargets.Count - 1}"); } private static void SyncDeadPlayerToTomb(PlayerControllerB player, DeadBodyInfo body) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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) if ((Object)(object)player == (Object)null || (Object)(object)body == (Object)null) { return; } Vector3 position = ((Component)body).transform.position; ((Component)player).transform.position = position; if ((Object)(object)body.radarDot != (Object)null) { body.radarDot.position = position; ((Component)body.radarDot).gameObject.SetActive(true); } if ((Object)(object)body.nightVisionRadar != (Object)null) { ((Component)body.nightVisionRadar).transform.position = position; } if (body.bodyParts == null) { return; } for (int i = 0; i < body.bodyParts.Length; i++) { Rigidbody val = body.bodyParts[i]; if (!((Object)(object)val == (Object)null)) { ((Component)val).transform.position = position; if (!val.isKinematic) { val.velocity = Vector3.zero; val.angularVelocity = Vector3.zero; } } } } private static Light EnsureNightVisionRadar(Transform root) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_003c: 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) Transform val = root.Find("NightVisionRadar"); GameObject val2; if ((Object)(object)val != (Object)null) { val2 = ((Component)val).gameObject; } else { val2 = new GameObject("NightVisionRadar"); val2.transform.SetParent(root, false); val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; } Light val3 = val2.GetComponent(); if ((Object)(object)val3 == (Object)null) { val3 = val2.AddComponent(); } val3.type = (LightType)2; val3.range = 2f; val3.intensity = 0f; ((Behaviour)val3).enabled = false; return val3; } private static int GetPlayerIndex(PlayerControllerB player) { if ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.allPlayerScripts != null) { for (int i = 0; i < StartOfRound.Instance.allPlayerScripts.Length; i++) { if ((Object)(object)StartOfRound.Instance.allPlayerScripts[i] == (Object)(object)player) { return i; } } } return (int)player.playerClientId; } private static Transform EnsureRadarDot(Transform root) { //IL_002a: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) Transform val = root.Find("RadarDot_World"); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(true); val.SetParent(root, false); val.localPosition = Vector3.zero; val.localRotation = Quaternion.identity; return val; } Transform val2 = root.Find("RadarDot"); if ((Object)(object)val2 != (Object)null && !(val2 is RectTransform)) { ((Component)val2).gameObject.SetActive(true); val2.SetParent(root, false); val2.localPosition = Vector3.zero; val2.localRotation = Quaternion.identity; return val2; } GameObject val3 = new GameObject("RadarDot_World"); val3.transform.SetParent(root, false); val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.identity; val3.SetActive(true); return val3.transform; } private static Rigidbody[] EnsureBodyParts(Transform root, PlayerControllerB player) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) int num = 0; if ((Object)(object)player != (Object)null && player.bodyParts != null) { num = player.bodyParts.Length; } int num2 = Mathf.Max(num, 6); Rigidbody[] array = (Rigidbody[])(object)new Rigidbody[num2]; for (int i = 0; i < num2; i++) { string text = $"TombBodyPart_{i}"; Transform val = root.Find(text); GameObject val2; if ((Object)(object)val != (Object)null) { val2 = ((Component)val).gameObject; } else { val2 = new GameObject(text); val2.transform.SetParent(root, false); } val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.transform.localScale = Vector3.one; Rigidbody val3 = val2.GetComponent(); if ((Object)(object)val3 == (Object)null) { val3 = val2.AddComponent(); } BoxCollider val4 = val2.GetComponent(); if ((Object)(object)val4 == (Object)null) { val4 = val2.AddComponent(); } val4.size = new Vector3(0.2f, 0.2f, 0.2f); val4.center = Vector3.zero; ((Collider)val4).isTrigger = false; ((Collider)val4).enabled = true; val3.isKinematic = false; val3.useGravity = false; val3.constraints = (RigidbodyConstraints)126; val3.detectCollisions = true; val3.velocity = Vector3.zero; val3.angularVelocity = Vector3.zero; array[i] = val3; } return array; } } public class UltimateReviveTeleportedTag : MonoBehaviour { } public class UltimateReviveTombPhysicsStopper : MonoBehaviour { } } namespace UltimateRevive.Patches { internal static class InteractTriggerPatch { private static readonly HashSet LoggedLifecycleEvents = new HashSet(); private static void AwakePostfix(InteractTrigger __instance) { LogLifecycle("awake", __instance); } private static void StartPostfix(InteractTrigger __instance) { LogLifecycle("start", __instance); TryRefreshBodyOwner(__instance); } private static void OnEnablePostfix(InteractTrigger __instance) { LogLifecycle("enable", __instance); TryRefreshBodyOwner(__instance); } private static void TryRefreshBodyOwner(InteractTrigger trigger) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) if (!ModState.Active || (Object)(object)trigger == (Object)null) { return; } RagdollGrabbableObject val = ((Component)trigger).GetComponent() ?? ((Component)trigger).GetComponentInParent(); if ((Object)(object)val == (Object)null || DeathMarkerManager.IsTombRagdollGrabbable(val)) { return; } ulong num = (((Object)(object)((NetworkBehaviour)val).NetworkObject != (Object)null) ? ((NetworkBehaviour)val).NetworkObject.NetworkObjectId : 0); Vector3 deathPosition = (((Object)(object)((Component)val).transform != (Object)null) ? ((Component)val).transform.position : Vector3.zero); DeadBodyInfo componentInParent = ((Component)trigger).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { int playerObjectId = componentInParent.playerObjectId; PlayerControllerB val2 = ((StartOfRound.Instance?.allPlayerScripts != null && playerObjectId >= 0 && playerObjectId < StartOfRound.Instance.allPlayerScripts.Length) ? StartOfRound.Instance.allPlayerScripts[playerObjectId] : null); if ((Object)(object)val2 != (Object)null && val2.isPlayerDead) { GeneralUtil.SetPlayerDeathState(playerObjectId, PlayerDeathType.Body, num, deathPosition, "Trigger.Active:DeadBodyInfo"); ReviveInteractTriggerManager.ForceRefreshPlayer(playerObjectId, "Trigger.Active:DeadBodyInfo"); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[TriggerLifecycle] bodyOwnerRefresh player={playerObjectId} trigger={((Object)trigger).name} body={((Object)val).name} obj={num} via DeadBodyInfo"); } return; } } MaskedPlayerEnemy componentInParent2 = ((Component)trigger).GetComponentInParent(); if (!((Object)(object)componentInParent2 != (Object)null)) { return; } int? playerIdForMasked = MaskedConversionTracker.GetPlayerIdForMasked(componentInParent2); if (!playerIdForMasked.HasValue) { return; } PlayerControllerB val3 = ((StartOfRound.Instance?.allPlayerScripts != null && playerIdForMasked.Value >= 0 && playerIdForMasked.Value < StartOfRound.Instance.allPlayerScripts.Length) ? StartOfRound.Instance.allPlayerScripts[playerIdForMasked.Value] : null); if ((Object)(object)val3 != (Object)null && val3.isPlayerDead) { GeneralUtil.SetPlayerDeathState(playerIdForMasked.Value, PlayerDeathType.Masked, num, deathPosition, "Trigger.Active:MaskedPlayerEnemy"); ReviveInteractTriggerManager.ForceRefreshPlayer(playerIdForMasked.Value, "Trigger.Active:MaskedPlayerEnemy"); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[TriggerLifecycle] bodyOwnerRefresh player={playerIdForMasked.Value} trigger={((Object)trigger).name} body={((Object)val).name} obj={num} via MaskedPlayerEnemy"); } } } private static void OnDestroyPostfix(InteractTrigger __instance) { if (!((Object)(object)__instance == (Object)null)) { int instanceId = ((Object)__instance).GetInstanceID(); LoggedLifecycleEvents.RemoveWhere((string key) => key.StartsWith(instanceId + ":")); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[TriggerLifecycle] phase=destroy id={instanceId} name={((Object)__instance).name}"); } } } public static void TryPatch(Harmony harmony) { Type typeFromHandle = typeof(InteractTriggerPatch); Type typeFromHandle2 = typeof(InteractTrigger); TryPatchMethod(harmony, typeFromHandle2, "Awake", typeFromHandle.GetMethod("AwakePostfix", BindingFlags.Static | BindingFlags.NonPublic)); TryPatchMethod(harmony, typeFromHandle2, "Start", typeFromHandle.GetMethod("StartPostfix", BindingFlags.Static | BindingFlags.NonPublic)); TryPatchMethod(harmony, typeFromHandle2, "OnEnable", typeFromHandle.GetMethod("OnEnablePostfix", BindingFlags.Static | BindingFlags.NonPublic)); TryPatchMethod(harmony, typeFromHandle2, "OnDestroy", typeFromHandle.GetMethod("OnDestroyPostfix", BindingFlags.Static | BindingFlags.NonPublic)); } private static void TryPatchMethod(Harmony harmony, Type targetType, string methodName, MethodInfo postfix) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown if (postfix == null) { return; } MethodInfo method = targetType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[TriggerLifecycle] skip patch: " + targetType.Name + "." + methodName + " not found")); } return; } try { harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[TriggerLifecycle] patched: " + targetType.Name + "." + methodName)); } } catch (Exception ex) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[TriggerLifecycle] patch failed: " + targetType.Name + "." + methodName + " — " + ex.Message)); } } } private static void LogLifecycle(string phase, InteractTrigger trigger) { if ((Object)(object)trigger == (Object)null) { return; } int instanceID = ((Object)trigger).GetInstanceID(); string item = $"{instanceID}:{phase}"; if (LoggedLifecycleEvents.Add(item)) { string text = (((Object)(object)((Component)trigger).gameObject != (Object)null) ? ((Object)((Component)trigger).gameObject).name : "none"); string text2 = (((Object)(object)((Component)trigger).transform != (Object)null) ? BuildTransformPath(((Component)trigger).transform) : "none"); int num = (((Object)(object)((Component)trigger).gameObject != (Object)null) ? ((Component)trigger).gameObject.layer : (-1)); Collider component = ((Component)trigger).GetComponent(); string text3 = (((Object)(object)component == (Object)null) ? "none" : $"{((object)component).GetType().Name}:{component.enabled}:trigger={component.isTrigger}"); RagdollGrabbableObject componentInParent = ((Component)trigger).GetComponentInParent(); string text4 = (((Object)(object)componentInParent != (Object)null) ? ((Object)componentInParent).name : "none"); ulong num2 = (((Object)(object)((componentInParent != null) ? ((NetworkBehaviour)componentInParent).NetworkObject : null) != (Object)null) ? ((NetworkBehaviour)componentInParent).NetworkObject.NetworkObjectId : 0); DeadBodyInfo componentInParent2 = ((Component)trigger).GetComponentInParent(); string text5 = (((Object)(object)componentInParent2 != (Object)null) ? ((Object)componentInParent2).name : "none"); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[TriggerLifecycle] phase={phase} id={instanceID} name={((Object)trigger).name} obj={text} enabled={((Behaviour)trigger).enabled} interactable={trigger.interactable} layer={num} collider={text3} ragdoll={text4}/obj:{num2} deadBody={text5} path={text2}"); } } } private static string BuildTransformPath(Transform transform) { if ((Object)(object)transform == (Object)null) { return "none"; } List list = new List(); Transform val = transform; while ((Object)(object)val != (Object)null) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list); } } [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] internal static class KillPlayerPatch { [CompilerGenerated] private sealed class d__1 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public PlayerControllerB player; public Vector3 deathPosition; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; if (TryResolveNoBodyDeath(player, deathPosition, allowTomb: false, "KillPlayer:noBody:nextFrame")) { return false; } <>2__current = (object)new WaitForSeconds(0.35f); <>1__state = 2; return true; case 2: <>1__state = -1; if (TryResolveNoBodyDeath(player, deathPosition, allowTomb: false, "KillPlayer:noBody:0.35s")) { return false; } <>2__current = (object)new WaitForSeconds(1.15f); <>1__state = 3; return true; case 3: <>1__state = -1; TryResolveNoBodyDeath(player, deathPosition, allowTomb: true, "KillPlayer:noBody:fallbackTomb"); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static void Postfix(PlayerControllerB __instance, Vector3 bodyVelocity, bool spawnBody, CauseOfDeath causeOfDeath, int deathAnimation, Vector3 positionOffset, bool setOverrideDropItems) { //IL_0031: 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_0038: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (!ModState.Active || (Object)(object)__instance == (Object)null) { return; } int playerClientId = (int)__instance.playerClientId; Vector3 deathPosition = (((Object)(object)((Component)__instance).transform != (Object)null) ? (((Component)__instance).transform.position + positionOffset) : positionOffset); if (spawnBody) { if (GeneralUtil.GetPlayerLastDeathType(playerClientId) != PlayerDeathType.Masked) { GeneralUtil.SetPlayerDeathState(playerClientId, PlayerDeathType.Body, 0uL, deathPosition, "KillPlayer:spawnBody"); } return; } if (GeneralUtil.GetPlayerLastDeathType(playerClientId) != PlayerDeathType.Masked) { GeneralUtil.SetPlayerDeathState(playerClientId, PlayerDeathType.Body, 0uL, deathPosition, "KillPlayer:noBody"); } Plugin.RunCoroutineSafe(ResolveNoBodyDeathCoroutine(__instance, deathPosition)); } [IteratorStateMachine(typeof(d__1))] private static IEnumerator ResolveNoBodyDeathCoroutine(PlayerControllerB player, Vector3 deathPosition) { //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 decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(0) { player = player, deathPosition = deathPosition }; } private static bool TryResolveNoBodyDeath(PlayerControllerB player, Vector3 deathPosition, bool allowTomb, string reason) { //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0162: 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_0071: 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_0179: 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) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) if (!ModState.Active || (Object)(object)player == (Object)null || !player.isPlayerDead) { return true; } int num = (int)player.playerClientId; if (GeneralUtil.GetPlayerLastDeathType(num) == PlayerDeathType.Masked && ModConfig.EnableMaskedPlayerRevive) { MaskedPlayerEnemy maskedForPlayer = MaskedConversionTracker.GetMaskedForPlayer(num); if ((Object)(object)maskedForPlayer != (Object)null) { ulong networkObjectId = MaskedConversionTracker.GetNetworkObjectId(maskedForPlayer); Vector3 deathPosition2 = (((Object)(object)((Component)maskedForPlayer).transform != (Object)null) ? ((Component)maskedForPlayer).transform.position : deathPosition); GeneralUtil.SetPlayerDeathState(num, PlayerDeathType.Masked, networkObjectId, deathPosition2, reason + ":maskedResolved"); ReviveInteractTriggerManager.ForceRefreshPlayer(num, reason + ":maskedResolved"); return true; } if (!allowTomb && MaskedConversionTracker.HasPendingForPlayer(num)) { return false; } } if ((Object)(object)player.deadBody != (Object)null && !DeathMarkerManager.IsTombDeadBody(num, player.deadBody)) { ReviveInteractTriggerManager.ForceRefreshPlayer(num, reason + ":deadBodyResolved"); return true; } RagdollGrabbableObject bodyForPlayer = GeneralUtil.GetBodyForPlayer(num); if ((Object)(object)bodyForPlayer != (Object)null && !DeathMarkerManager.IsTombRagdollGrabbable(bodyForPlayer)) { ulong networkObjectId2 = (((Object)(object)((NetworkBehaviour)bodyForPlayer).NetworkObject != (Object)null) ? ((NetworkBehaviour)bodyForPlayer).NetworkObject.NetworkObjectId : 0); Vector3 deathPosition3 = (((Object)(object)((Component)bodyForPlayer).transform != (Object)null) ? ((Component)bodyForPlayer).transform.position : deathPosition); GeneralUtil.SetPlayerDeathState(num, PlayerDeathType.Body, networkObjectId2, deathPosition3, reason + ":bodyResolved"); ReviveInteractTriggerManager.ForceRefreshPlayer(num, reason + ":bodyResolved"); return true; } if (!allowTomb) { return false; } Vector3 position = deathPosition; if (GeneralUtil.TryGetPlayerLastDeathPosition(num, out var position2)) { position = position2; } else if ((Object)(object)((Component)player).transform != (Object)null) { position = ((Component)player).transform.position; } if (DeathMarkerManager.TrySpawnTombForPlayer(player, position, reason)) { ReviveInteractTriggerManager.ForceRefreshPlayer(num, reason + ":tombSpawned"); return true; } return false; } } [HarmonyPatch(typeof(MaskedPlayerEnemy), "CreateMimicClientRpc")] internal static class MaskedCreateMimicPatch { private static void Postfix(MaskedPlayerEnemy __instance, NetworkObjectReference netObjectRef, bool inFactory, int playerKilled) { NetworkObject val = default(NetworkObject); if (!ModState.Active || !ModConfig.EnableMaskedPlayerRevive || !((NetworkObjectReference)(ref netObjectRef)).TryGet(ref val, (NetworkManager)null) || (Object)(object)val == (Object)null) { return; } MaskedPlayerEnemy val2 = ((Component)val).GetComponent() ?? ((Component)val).GetComponentInChildren(true); if (!((Object)(object)val2 == (Object)null)) { if (playerKilled >= 0) { MaskedConversionTracker.TagMaskedAsConverted(val2, playerKilled, MaskedOrigin.ConvertedByMaskedEnemy, "CreateMimicClientRpc:playerKilled"); } else { MaskedConversionTracker.TagMaskedOnSpawn(val2); } } } } [HarmonyPatch] internal static class MaskedConversionPatch { [HarmonyPatch(typeof(MaskedPlayerEnemy), "Start")] [HarmonyPostfix] private static void MaskedStartPostfix(MaskedPlayerEnemy __instance) { if (ModState.Active && ModConfig.EnableMaskedPlayerRevive) { MaskedConversionTracker.TagMaskedOnSpawn(__instance); } } [HarmonyPatch(typeof(HauntedMaskItem), "CreateMimicServerRpc")] [HarmonyPrefix] private static void CreateMimicServerRpcPrefix(HauntedMaskItem __instance) { if (ModState.Active && ModConfig.EnableMaskedPlayerRevive && !((Object)(object)__instance == (Object)null)) { if ((Object)(object)((GrabbableObject)(__instance?)).playerHeldBy != (Object)null) { MaskedConversionTracker.RegisterPending(((GrabbableObject)__instance).playerHeldBy, MaskedOrigin.ConvertedByMaskItem); } } } [HarmonyPatch(typeof(HauntedMaskItem), "FinishAttaching")] [HarmonyPostfix] private static void FinishAttachingPostfix(HauntedMaskItem __instance) { if (ModState.Active && ModConfig.EnableMaskedPlayerRevive && !((Object)(object)__instance == (Object)null)) { PlayerControllerB val = null; try { val = Traverse.Create((object)__instance).Field("previousPlayerHeldBy").GetValue(); } catch { } if ((Object)(object)val != (Object)null && val.isPlayerDead) { MaskedConversionTracker.RegisterPending(val, MaskedOrigin.ConvertedByMaskItem); } } } [HarmonyPatch(typeof(MaskedPlayerEnemy), "killAnimation")] [HarmonyPostfix] private static void KillAnimationPostfix(MaskedPlayerEnemy __instance) { if (!ModState.Active || !ModConfig.EnableMaskedPlayerRevive || (Object)(object)__instance == (Object)null) { return; } PlayerControllerB val = ((EnemyAI)(__instance?)).inSpecialAnimationWithPlayer; if (!((Object)(object)val == (Object)null)) { int num = (int)val.playerClientId; MaskedConversionTracker.RegisterPending(val, MaskedOrigin.ConvertedByMaskedEnemy); if ((Object)(object)MaskedConversionTracker.GetMaskedForPlayer(num) != (Object)null) { ReviveInteractTriggerManager.ForceRefreshPlayer(num, "Masked.killAnimation"); } } } [HarmonyPatch(typeof(MaskedPlayerEnemy), "FinishKillAnimation")] [HarmonyPostfix] private static void FinishKillAnimationPostfix(MaskedPlayerEnemy __instance) { if (!ModState.Active || !ModConfig.EnableMaskedPlayerRevive || (Object)(object)__instance == (Object)null) { return; } PlayerControllerB val = null; try { val = Traverse.Create((object)__instance).Field("lastPlayerKilled").GetValue(); } catch { } if (!((Object)(object)val == (Object)null)) { int num = (int)val.playerClientId; MaskedConversionTracker.RegisterPending(val, MaskedOrigin.ConvertedByMaskedEnemy); if ((Object)(object)MaskedConversionTracker.GetMaskedForPlayer(num) != (Object)null) { ReviveInteractTriggerManager.ForceRefreshPlayer(num, "Masked.FinishKillAnimation"); } } } [HarmonyPatch(typeof(MaskedPlayerEnemy), "KillEnemy")] [HarmonyPostfix] private static void KillEnemyPostfix(MaskedPlayerEnemy __instance) { if (ModState.Active && ModConfig.EnableMaskedPlayerRevive && !((Object)(object)__instance == (Object)null)) { ReviveInteractTriggerManager.OnMaskedKilled(__instance); } } } [HarmonyPatch(typeof(PlayerControllerB))] internal static class PlayerControllerBPatch { private const string ReviveOverlayPrefix = "Revive:"; private static float _startedReviveAt; private static bool _startedRevive; private static int _revivingPlayerId = -1; [HarmonyPatch("KillPlayerClientRpc")] [HarmonyPrefix] private static void KillPlayerClientRpcPrefix(PlayerControllerB __instance, ref int playerId) { //IL_0017: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_019f: 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) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_00ee: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) try { Vector3 val = (((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).transform != (Object)null) ? ((Component)__instance).transform.position : Vector3.zero); if (ModConfig.EnableMaskedPlayerRevive) { EnemyAI obj = (((Object)(object)__instance != (Object)null) ? __instance.redirectToEnemy : null); MaskedPlayerEnemy val2 = (MaskedPlayerEnemy)(object)((obj is MaskedPlayerEnemy) ? obj : null); if ((Object)(object)val2 != (Object)null) { ulong networkObjectId = MaskedConversionTracker.GetNetworkObjectId(val2); Vector3 deathPosition = (((Object)(object)((Component)val2).transform != (Object)null) ? ((Component)val2).transform.position : val); GeneralUtil.SetPlayerDeathState(playerId, PlayerDeathType.Masked, networkObjectId, deathPosition, "KillPlayerClientRpc:redirectToEnemy"); ReviveInteractTriggerManager.ForceRefreshPlayer(playerId, "KillPlayerClientRpc:redirectToEnemy"); return; } if (GeneralUtil.GetPlayerLastDeathType(playerId) == PlayerDeathType.Masked) { ulong playerLastDeathNetworkObjectId = GeneralUtil.GetPlayerLastDeathNetworkObjectId(playerId); MaskedPlayerEnemy val3 = ((playerLastDeathNetworkObjectId != 0L) ? GeneralUtil.GetMaskedByNetworkObjectId(playerLastDeathNetworkObjectId) : GeneralUtil.GetConvertedMaskedCorpseForPlayer(playerId)); if ((Object)(object)val3 != (Object)null) { ulong networkObjectId2 = MaskedConversionTracker.GetNetworkObjectId(val3); Vector3 deathPosition2 = (((Object)(object)((Component)val3).transform != (Object)null) ? ((Component)val3).transform.position : val); GeneralUtil.SetPlayerDeathState(playerId, PlayerDeathType.Masked, networkObjectId2, deathPosition2, "KillPlayerClientRpc:preserveMasked"); ReviveInteractTriggerManager.ForceRefreshPlayer(playerId, "KillPlayerClientRpc:preserveMasked"); return; } } } GeneralUtil.SetPlayerDeathState(playerId, PlayerDeathType.Body, 0uL, val, "KillPlayerClientRpc"); ReviveInteractTriggerManager.ForceRefreshPlayer(playerId, "KillPlayerClientRpc:body"); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("KillPlayerClientRpcPrefix fallback after exception: " + ex.Message + ex.GetType().FullName + ": " + ex.Message + "\n" + ex.StackTrace)); } GeneralUtil.SetPlayerDeathState(playerId, PlayerDeathType.Body, 0uL, Vector3.zero, "KillPlayerClientRpc:exceptionFallback"); ReviveInteractTriggerManager.ForceRefreshPlayer(playerId, "KillPlayerClientRpc:exceptionFallback"); } } [HarmonyPatch("Interact_performed")] [HarmonyPrefix] private static bool InteractPerformedPrefix(PlayerControllerB __instance) { if (ModConfig.CanPickUpBodies) { return true; } if (IsLocalAlivePlayer(__instance) && ReviveInteractTriggerManager.IsHoveringReviveTrigger(__instance)) { return false; } if (!IsLocalAlivePlayer(__instance)) { return true; } return !ReviveInteractTriggerManager.IsHoveringReviveTrigger(__instance); } [HarmonyPatch("SetHoverTipAndCurrentInteractTrigger")] [HarmonyPostfix] private static void SetHoverTipAndCurrentInteractTriggerPostfix(PlayerControllerB __instance) { HandleReviveUiAndInput(__instance); } [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePostfix(PlayerControllerB __instance) { HandleReviveUiAndInput(__instance); } internal static void TickFromPlugin() { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (!((Object)(object)val == (Object)null)) { HandleReviveUiAndInput(val); } } private static void HandleReviveUiAndInput(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { ResetProgress(); } else { if ((uint)player.playerClientId != (uint)val.playerClientId) { return; } if (player.isPlayerDead) { ResetProgress(); return; } TMP_Text cursorTip = (TMP_Text)(object)player.cursorTip; if ((Object)(object)cursorTip == (Object)null) { ResetProgress(); return; } if (!TryGetReviveTarget(player, out var targetPlayerId, out var reason, out var canRevive)) { ResetProgress(); return; } if (!canRevive) { if (reason == "kill masked first" && (!ModConfig.LimitedRevives || ModState.RemainingRevives > 0)) { SetReviveOverlay(cursorTip, "Revive: Kill the masked to revive your teammate"); } else if (!string.IsNullOrWhiteSpace(reason) && reason != "too far from body" && reason != "source missing") { SetReviveOverlay(cursorTip, BuildBlockedTip(reason)); } ResetProgress(); return; } InputAction reviveAction = Plugin.ReviveAction; if (reviveAction == null) { SetReviveOverlay(cursorTip, "Revive: key unavailable"); ResetProgress(); return; } if (!reviveAction.IsPressed()) { SetReviveOverlay(cursorTip, BuildIdleTip(targetPlayerId)); ResetProgress(); return; } if (!_startedRevive || _revivingPlayerId != targetPlayerId) { _startedRevive = true; _revivingPlayerId = targetPlayerId; _startedReviveAt = Time.time; } float num = Time.time - _startedReviveAt; if (num >= ModConfig.ReviveTime) { ReviveNetwork.RequestRevive(targetPlayerId); SetReviveOverlay(cursorTip, "Revive: requested"); ResetProgress(); } else { SetReviveOverlay(cursorTip, string.Format("{0} {1}/{2:0}s", "Revive:", Mathf.CeilToInt(num), ModConfig.ReviveTime)); } } } private static bool TryGetReviveTarget(PlayerControllerB reviver, out int targetPlayerId, out string reason, out bool canRevive) { targetPlayerId = -1; reason = string.Empty; canRevive = false; if (ReviveInteractTriggerManager.TryGetHoveredReviveTarget(reviver, out targetPlayerId, out reason, out canRevive)) { return true; } reason = "no revive trigger"; return false; } private static bool IsLookingAtLatestSourceForTarget(PlayerControllerB reviver, int targetPlayerId) { if ((Object)(object)reviver != (Object)null && targetPlayerId >= 0) { return ReviveInteractTriggerManager.IsHoveringTriggerForTarget(reviver, targetPlayerId); } return false; } private static bool IsLocalAlivePlayer(PlayerControllerB player) { if ((Object)(object)player == (Object)null || player.isPlayerDead) { return false; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return false; } return (uint)player.playerClientId == (uint)val.playerClientId; } private static string BuildIdleTip(int targetPlayerId) { string reviveBindingLabel = Plugin.GetReviveBindingLabel(); if (ModConfig.InfiniteReviveTime) { return "Revive: hold " + reviveBindingLabel; } float num = ReviveRules.SecondsLeft(targetPlayerId); if (num <= 0f) { return "Revive: 0s left"; } return string.Format("{0} hold {1} ({2}s)", "Revive:", reviveBindingLabel, Mathf.CeilToInt(num)); } private static string BuildBlockedTip(string reason) { if (string.IsNullOrWhiteSpace(reason)) { return string.Empty; } string text = reason.Trim().ToLowerInvariant(); if (text == "source missing" || text == "too far from body") { return string.Empty; } if (text.Contains("outside") || text.Contains("line of sight")) { return "Revive: keep target in sight"; } return "Revive: " + reason; } private static void SetReviveOverlay(TMP_Text cursorTip, string reviveLine) { if (!((Object)(object)cursorTip == (Object)null)) { string text = StripReviveOverlay(cursorTip.text); if (string.IsNullOrWhiteSpace(text)) { cursorTip.text = reviveLine; } else { cursorTip.text = reviveLine + "\n" + text; } } } private static string StripReviveOverlay(string text) { if (string.IsNullOrWhiteSpace(text)) { return string.Empty; } string[] array = text.Split('\n'); StringBuilder stringBuilder = new StringBuilder(); string[] array2 = array; foreach (string text2 in array2) { string text3 = text2?.Trim() ?? string.Empty; if (!string.IsNullOrWhiteSpace(text3) && !text3.StartsWith("Revive:", StringComparison.OrdinalIgnoreCase)) { if (stringBuilder.Length > 0) { stringBuilder.Append('\n'); } stringBuilder.Append(text2); } } return stringBuilder.ToString(); } private static void ResetProgress() { _startedRevive = false; _revivingPlayerId = -1; _startedReviveAt = 0f; } } [HarmonyPatch(typeof(RagdollGrabbableObject))] internal static class RagdollGrabbableObjectPatch { [CompilerGenerated] private sealed class d__2 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public RagdollGrabbableObject body; private float[] 5__2; private int 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__2(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = new float[5] { 0.2f, 0.5f, 1f, 2f, 4f }; 5__3 = 0; break; case 1: <>1__state = -1; if (!ModState.Active || (Object)(object)body == (Object)null) { return false; } TryRefreshBodySource(body, $"Ragdoll.Delayed:{5__2[5__3]:0.0}s"); 5__3++; break; } if (5__3 < 5__2.Length) { <>2__current = (object)new WaitForSeconds(5__2[5__3]); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly Dictionary LastRefreshSignatureByBody = new Dictionary(); [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPostfix(RagdollGrabbableObject __instance) { if (ModState.Active && !((Object)(object)__instance == (Object)null)) { if ((Object)(object)((GrabbableObject)(__instance?)).itemProperties != (Object)null) { ((GrabbableObject)__instance).itemProperties.weight = ModConfig.DeadBodyWeight; } TryRefreshBodySource(__instance, "Ragdoll.Start"); ((MonoBehaviour)__instance).StartCoroutine(LateRefreshCoroutine(__instance)); } } [IteratorStateMachine(typeof(d__2))] private static IEnumerator LateRefreshCoroutine(RagdollGrabbableObject body) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__2(0) { body = body }; } private static void TryRefreshBodySource(RagdollGrabbableObject body, string reason) { //IL_0033: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) if (!ModState.Active || (Object)(object)body == (Object)null) { return; } int instanceID = ((Object)body).GetInstanceID(); Vector3 val = (((Object)(object)((Component)body).transform != (Object)null) ? ((Component)body).transform.position : Vector3.zero); ulong num = (((Object)(object)((NetworkBehaviour)body).NetworkObject != (Object)null) ? ((NetworkBehaviour)body).NetworkObject.NetworkObjectId : 0); DeadBodyInfo componentInParent = ((Component)body).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { int playerObjectId = componentInParent.playerObjectId; PlayerControllerB val2 = ((StartOfRound.Instance?.allPlayerScripts != null && playerObjectId >= 0 && playerObjectId < StartOfRound.Instance.allPlayerScripts.Length) ? StartOfRound.Instance.allPlayerScripts[playerObjectId] : null); if ((Object)(object)val2 != (Object)null && val2.isPlayerDead && GeneralUtil.GetPlayerLastDeathType(playerObjectId) != PlayerDeathType.Masked) { string signature = $"deadBodyInfo:{playerObjectId}:{num}"; if (ShouldApplyRefresh(instanceID, signature)) { GeneralUtil.SetPlayerDeathState(playerObjectId, PlayerDeathType.Body, num, val, reason + ":DeadBodyInfo"); ReviveInteractTriggerManager.ForceRefreshPlayer(playerObjectId, reason + ":DeadBodyInfo"); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[ReviveTrigger] bodyRefresh player={playerObjectId} body={((Object)body).name} obj={num} via DeadBodyInfo reason={reason}"); } } return; } } if (GeneralUtil.TryGetBodyOwner(body, out var targetPlayerClientId, out var _) && GeneralUtil.GetPlayerLastDeathType(targetPlayerClientId) != PlayerDeathType.Masked) { string signature2 = $"owner:{targetPlayerClientId}:{num}"; if (ShouldApplyRefresh(instanceID, signature2)) { GeneralUtil.SetPlayerDeathState(targetPlayerClientId, PlayerDeathType.Body, num, val, reason + ":ownerResolved"); ReviveInteractTriggerManager.ForceRefreshPlayer(targetPlayerClientId, reason + ":ownerResolved"); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[ReviveTrigger] bodyRefresh player={targetPlayerClientId} body={((Object)body).name} obj={num} reason={reason}"); } } return; } PlayerReviveInfo playerReviveInfo = null; float num2 = 49f; foreach (PlayerReviveInfo playerInfo in ModState.PlayerInfos) { if (playerInfo != null && playerInfo.LastDeathType == PlayerDeathType.Body && playerInfo.HasLastDeathPosition) { Vector3 val3 = playerInfo.LastDeathPosition - val; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude < num2) { num2 = sqrMagnitude; playerReviveInfo = playerInfo; } } } if (playerReviveInfo == null) { return; } string signature3 = $"deathPos:{playerReviveInfo.PlayerClientId}:{num}"; if (ShouldApplyRefresh(instanceID, signature3)) { GeneralUtil.SetPlayerDeathState(playerReviveInfo.PlayerClientId, PlayerDeathType.Body, num, val, reason + ":matchedByDeathPos"); ReviveInteractTriggerManager.ForceRefreshPlayer(playerReviveInfo.PlayerClientId, reason + ":matchedByDeathPos"); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[ReviveTrigger] bodyRefresh player={playerReviveInfo.PlayerClientId} body={((Object)body).name} obj={num} mode=deathPos reason={reason}"); } } } private static bool ShouldApplyRefresh(int bodyInstanceId, string signature) { if (string.IsNullOrWhiteSpace(signature)) { return true; } if (LastRefreshSignatureByBody.TryGetValue(bodyInstanceId, out var value) && value == signature) { return false; } LastRefreshSignatureByBody[bodyInstanceId] = signature; return true; } [HarmonyPatch("OnDestroy")] [HarmonyPostfix] private static void OnDestroyPostfix(RagdollGrabbableObject __instance) { if (!((Object)(object)__instance == (Object)null)) { LastRefreshSignatureByBody.Remove(((Object)__instance).GetInstanceID()); } } } [HarmonyPatch(typeof(StartOfRound))] internal static class StartOfRoundPatch { [CompilerGenerated] private sealed class d__5 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; ReviveNetwork.TryRegisterHandlers(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPostfix(StartOfRound __instance) { ModState.Active = true; ReviveNetwork.TryRegisterHandlers(); ReviveInteractTriggerManager.WarmUpCache(); if ((Object)(object)__instance != (Object)null) { ((MonoBehaviour)__instance).StartCoroutine(RegisterNetworkDelayed()); } } [HarmonyPatch("OnClientConnect")] [HarmonyPostfix] private static void OnClientConnectPostfix(StartOfRound __instance) { ModState.Active = true; if ((Object)(object)__instance != (Object)null) { ((MonoBehaviour)__instance).StartCoroutine(RegisterNetworkDelayed()); } } [HarmonyPatch("OnLocalDisconnect")] [HarmonyPostfix] private static void OnLocalDisconnectPostfix() { ReviveNetwork.UnregisterHandlers(); ModState.Reset(); } [HarmonyPatch("openingDoorsSequence")] [HarmonyPrefix] private static void OpeningDoorsSequencePrefix() { if (ModState.Active) { GeneralUtil.ResetAllPlayerInfos(); MaskedConversionTracker.Reset(); DeathMarkerManager.Reset(); ReviveInteractTriggerManager.Reset(); GeneralUtil.SetRemainingRevivesFromPlayerCount(); ReviveNetwork.SyncConfigForNewClients(); } } [HarmonyPatch("EndOfGame")] [HarmonyPrefix] private static void EndOfGamePrefix() { if (ModState.Active) { GeneralUtil.ResetAllPlayerInfos(); MaskedConversionTracker.Reset(); DeathMarkerManager.Reset(); ReviveInteractTriggerManager.Reset(); } } [IteratorStateMachine(typeof(d__5))] private static IEnumerator RegisterNetworkDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__5(0); } } }