Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ReviveCompanyRemake v1.0.0
ReviveCompanyRemake.dll
Decompiled 3 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; 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 ReviveCompanyRemake.Patches; using TMPro; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ReviveCompanyRemake")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ReviveCompanyRemake")] [assembly: AssemblyTitle("ReviveCompanyRemake")] [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 ReviveCompanyRemake { public static class GeneralUtil { private static ManualLogSource _log; 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_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) 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[] array = Object.FindObjectsOfType<RagdollGrabbableObject>(); RagdollGrabbableObject[] array2 = array; foreach (RagdollGrabbableObject val in array2) { if (TryGetBodyOwner(val, out var targetPlayerClientId, out var _) && targetPlayerClientId == playerClientId) { return val; } } return null; } public static RagdollGrabbableObject GetLookedAtBody(PlayerControllerB player) { //IL_003b: 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_0055: 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_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) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)player.gameplayCamera == (Object)null) { return null; } float clientDetectionDistance = GetClientDetectionDistance(player); Ray val = default(Ray); ((Ray)(ref val))..ctor(((Component)player.gameplayCamera).transform.position, ((Component)player.gameplayCamera).transform.forward); RaycastHit[] array = Physics.RaycastAll(val, clientDetectionDistance, -1, (QueryTriggerInteraction)2); if (array.Length != 0) { 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]; RagdollGrabbableObject val3 = ResolveBodyFromCollider(((RaycastHit)(ref val2)).collider); if ((Object)(object)val3 != (Object)null) { return val3; } } } RaycastHit[] array3 = Physics.SphereCastAll(val, 0.55f, clientDetectionDistance, -1, (QueryTriggerInteraction)2); if (array3.Length != 0) { Array.Sort(array3, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array4 = array3; for (int j = 0; j < array4.Length; j++) { RaycastHit val4 = array4[j]; RagdollGrabbableObject val5 = ResolveBodyFromCollider(((RaycastHit)(ref val4)).collider); if ((Object)(object)val5 != (Object)null) { return val5; } } } return FindClosestBodyInView(player, clientDetectionDistance); } 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 = AccessTools.Field(((object)body).GetType(), "playerScript")?.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; } private static RagdollGrabbableObject ResolveBodyFromCollider(Collider collider) { if ((Object)(object)collider == (Object)null) { return null; } RagdollGrabbableObject val = ((Component)collider).GetComponent<RagdollGrabbableObject>() ?? ((Component)collider).GetComponentInParent<RagdollGrabbableObject>(); if ((Object)(object)val != (Object)null) { return val; } GrabbableObject val2 = ((Component)collider).GetComponent<GrabbableObject>() ?? ((Component)collider).GetComponentInParent<GrabbableObject>(); return (RagdollGrabbableObject)(object)((val2 is RagdollGrabbableObject) ? val2 : null); } public static PlayerReviveInfo GetOrCreateInfo(int playerClientId) { PlayerReviveInfo playerReviveInfo = ModState.PlayerInfos.FirstOrDefault((PlayerReviveInfo x) => x.PlayerClientId == playerClientId); if (playerReviveInfo != null) { return playerReviveInfo; } playerReviveInfo = new PlayerReviveInfo { PlayerClientId = playerClientId, TimeDiedAt = Time.time }; ModState.PlayerInfos.Add(playerReviveInfo); return playerReviveInfo; } public static void ResetAllPlayerInfos() { 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 }); } } } public static void SetPlayerDiedAt(int playerClientId) { GetOrCreateInfo(playerClientId).TimeDiedAt = Time.time; } 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() { return (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.CustomMessagingManager != null && NetworkManager.Singleton.IsListening; } public static float GetReviveValidationDistance(PlayerControllerB reviver) { if ((Object)(object)reviver == (Object)null) { return 0f; } return Mathf.Max(reviver.grabDistance, ModConfig.MaxReviveDistance) + 1.5f; } public static bool IsReviverCloseEnough(PlayerControllerB reviver, Vector3 targetPosition) { //IL_003d: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)reviver == (Object)null) { return false; } float reviveValidationDistance = GetReviveValidationDistance(reviver); Vector3 val = (((Object)(object)reviver.gameplayCamera != (Object)null) ? ((Component)reviver.gameplayCamera).transform.position : ((Component)reviver).transform.position); return Vector3.Distance(val, targetPosition) <= reviveValidationDistance; } public static MaskedPlayerEnemy GetLookedAtConvertedMaskedCorpse(PlayerControllerB player) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_00e1: 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_012f: 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) if (!ModConfig.EnableMaskedPlayerRevive || (Object)(object)player == (Object)null || (Object)(object)player.gameplayCamera == (Object)null) { return null; } float clientDetectionDistance = GetClientDetectionDistance(player); Ray val = default(Ray); ((Ray)(ref val))..ctor(((Component)player.gameplayCamera).transform.position, ((Component)player.gameplayCamera).transform.forward); RaycastHit[] array = Physics.RaycastAll(val, clientDetectionDistance, -1, (QueryTriggerInteraction)2); if (array.Length != 0) { 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]; MaskedPlayerEnemy val3 = ResolveMaskedFromCollider(((RaycastHit)(ref val2)).collider); if (IsReviveableConvertedMaskedCorpse(val3)) { return val3; } } } RaycastHit[] array3 = Physics.SphereCastAll(val, 0.55f, clientDetectionDistance, -1, (QueryTriggerInteraction)2); if (array3.Length != 0) { Array.Sort(array3, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array4 = array3; for (int j = 0; j < array4.Length; j++) { RaycastHit val4 = array4[j]; MaskedPlayerEnemy val5 = ResolveMaskedFromCollider(((RaycastHit)(ref val4)).collider); if (IsReviveableConvertedMaskedCorpse(val5)) { return val5; } } } return FindClosestMaskedCorpseInView(player, clientDetectionDistance); } public static MaskedPlayerEnemy GetConvertedMaskedCorpseForPlayer(int playerClientId) { if (!ModConfig.EnableMaskedPlayerRevive) { return null; } MaskedPlayerEnemy[] array = Object.FindObjectsOfType<MaskedPlayerEnemy>(); foreach (MaskedPlayerEnemy val in array) { if (IsReviveableConvertedMaskedCorpse(val) && TryResolveConvertedMaskedPlayer(val, out var playerClientId2, out var _) && playerClientId2 == playerClientId) { return val; } } return null; } 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) { return MaskedConversionTracker.GetMaskedByNetworkObjectId(networkObjectId); } private static MaskedPlayerEnemy ResolveMaskedFromCollider(Collider collider) { return ((collider != null) ? ((Component)collider).GetComponent<MaskedPlayerEnemy>() : null) ?? ((collider != null) ? ((Component)collider).GetComponentInParent<MaskedPlayerEnemy>() : null); } private static RagdollGrabbableObject FindClosestBodyInView(PlayerControllerB player, float maxDistance) { //IL_0069: 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_00a1: Unknown result type (might be due to invalid IL or missing references) Camera val = player?.gameplayCamera; if ((Object)(object)val == (Object)null) { return null; } RagdollGrabbableObject result = null; float num = float.MaxValue; RagdollGrabbableObject[] array = Object.FindObjectsOfType<RagdollGrabbableObject>(); foreach (RagdollGrabbableObject val2 in array) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).transform == (Object)null)) { float num2 = Vector3.Distance(((Component)val).transform.position, ((Component)val2).transform.position); if (!(num2 > maxDistance) && !(num2 >= num) && IsInViewWindow(val, ((Component)val2).transform.position)) { result = val2; num = num2; } } } return result; } private static MaskedPlayerEnemy FindClosestMaskedCorpseInView(PlayerControllerB player, float maxDistance) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) Camera val = player?.gameplayCamera; if ((Object)(object)val == (Object)null) { return null; } MaskedPlayerEnemy result = null; float num = float.MaxValue; MaskedPlayerEnemy[] array = Object.FindObjectsOfType<MaskedPlayerEnemy>(); foreach (MaskedPlayerEnemy val2 in array) { if (IsReviveableConvertedMaskedCorpse(val2) && !((Object)(object)((Component)val2).transform == (Object)null)) { float num2 = Vector3.Distance(((Component)val).transform.position, ((Component)val2).transform.position); if (!(num2 > maxDistance) && !(num2 >= num) && IsInViewWindow(val, ((Component)val2).transform.position)) { result = val2; num = num2; } } } return result; } private static bool IsInViewWindow(Camera camera, Vector3 worldPosition) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0039: Unknown result type (might be due to invalid IL or missing references) Vector3 val = camera.WorldToViewportPoint(worldPosition); if (val.z <= 0f) { return false; } return Mathf.Abs(val.x - 0.5f) <= 0.4f && Mathf.Abs(val.y - 0.5f) <= 0.45f; } private static float GetClientDetectionDistance(PlayerControllerB player) { return GetReviveValidationDistance(player); } private static bool IsReviveableConvertedMaskedCorpse(MaskedPlayerEnemy masked) { int playerClientId; string source; return (Object)(object)masked != (Object)null && MaskedConversionTracker.IsMaskedDead(masked) && TryResolveConvertedMaskedPlayer(masked, out playerClientId, out source); } } public static class MaskedConversionTracker { private sealed class PendingConversion { public int PlayerClientId; public MaskedOrigin Origin; public Vector3 Position; public float TimeRegistered; } private const float PendingLifetimeSeconds = 20f; private const float FallbackMatchDistance = 35f; private static readonly List<PendingConversion> PendingConversions = new List<PendingConversion>(); private static ManualLogSource _log; public static void SetLogSource(ManualLogSource logSource) { _log = logSource; } public static void Reset() { PendingConversions.Clear(); } public static void RegisterPending(PlayerControllerB player, MaskedOrigin origin) { //IL_0060: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_009b: 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) if (ModConfig.EnableMaskedPlayerRevive && !((Object)(object)player == (Object)null) && (origin == MaskedOrigin.ConvertedByMaskItem || origin == MaskedOrigin.ConvertedByMaskedEnemy)) { int playerClientId = (int)player.playerClientId; Vector3 position = (((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 = position, TimeRegistered = Time.time }); GeneralUtil.SetPlayerDiedAt(playerClientId); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"Registered pending Masked conversion: player={playerClientId}, origin={origin}."); } TryAssignPendingToExistingMasked(playerClientId); } } public static void TagMaskedOnSpawn(MaskedPlayerEnemy masked) { if (!((Object)(object)masked == (Object)null) && ModConfig.EnableMaskedPlayerRevive) { MaskedOriginInfo orAddInfo = GetOrAddInfo(masked); if (TryConsumePendingFor(masked, out var pending)) { ApplyConvertedTag(masked, orAddInfo, pending); } else if (orAddInfo.Origin == MaskedOrigin.Unknown) { orAddInfo.Origin = MaskedOrigin.NaturalSpawn; orAddInfo.FormerPlayerClientId = -1; orAddInfo.TaggedAt = Time.time; } } } 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<MaskedOriginInfo>(); if ((Object)(object)component == (Object)null) { TagMaskedOnSpawn(masked); component = ((Component)masked).GetComponent<MaskedOriginInfo>(); } 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) { return (Object)(object)masked != (Object)null && ((EnemyAI)masked).isEnemyDead; } 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 MaskedPlayerEnemy GetConvertedMaskedCorpseForPlayer(int playerClientId) { if (!ModConfig.EnableMaskedPlayerRevive) { return null; } MaskedPlayerEnemy[] array = Object.FindObjectsOfType<MaskedPlayerEnemy>(); foreach (MaskedPlayerEnemy val in array) { if (!((Object)(object)val == (Object)null)) { TagMaskedOnSpawn(val); if (IsMaskedDead(val) && IsConvertedMasked(val, out var playerClientId2) && playerClientId2 == playerClientId) { return val; } } } return null; } public static MaskedPlayerEnemy GetMaskedByNetworkObjectId(ulong networkObjectId) { if (networkObjectId == 0) { 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<MaskedPlayerEnemy>(); if ((Object)(object)component != (Object)null) { return component; } component = ((Component)value).GetComponentInChildren<MaskedPlayerEnemy>(); if ((Object)(object)component != (Object)null) { return component; } } MaskedPlayerEnemy[] array = Object.FindObjectsOfType<MaskedPlayerEnemy>(); foreach (MaskedPlayerEnemy val in array) { if (GetNetworkObjectId(val) == networkObjectId) { return val; } } return null; } public static void ForgetPlayer(int playerClientId) { PendingConversions.RemoveAll((PendingConversion x) => x.PlayerClientId == playerClientId); MaskedPlayerEnemy[] array = Object.FindObjectsOfType<MaskedPlayerEnemy>(); foreach (MaskedPlayerEnemy val in array) { MaskedOriginInfo maskedOriginInfo = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<MaskedOriginInfo>() : null); if ((Object)(object)maskedOriginInfo != (Object)null && maskedOriginInfo.FormerPlayerClientId == playerClientId) { maskedOriginInfo.Origin = MaskedOrigin.Unknown; maskedOriginInfo.FormerPlayerClientId = -1; } } } private static void TryAssignPendingToExistingMasked(int playerClientId) { CleanupExpiredPending(); MaskedPlayerEnemy[] array = Object.FindObjectsOfType<MaskedPlayerEnemy>(); foreach (MaskedPlayerEnemy val in array) { if ((Object)(object)val == (Object)null) { continue; } int mimickingPlayerClientId = GetMimickingPlayerClientId(val); if (mimickingPlayerClientId == playerClientId) { PendingConversion pendingConversion = PendingConversions.FirstOrDefault((PendingConversion x) => x.PlayerClientId == playerClientId); if (pendingConversion != null) { ApplyConvertedTag(val, GetOrAddInfo(val), pendingConversion); PendingConversions.Remove(pendingConversion); } break; } } } private static bool TryConsumePendingFor(MaskedPlayerEnemy masked, out PendingConversion pending) { //IL_009c: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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) pending = null; CleanupExpiredPending(); int mimicId = GetMimickingPlayerClientId(masked); if (mimicId >= 0) { pending = PendingConversions.FirstOrDefault((PendingConversion x) => x.PlayerClientId == mimicId); if (pending != null) { PendingConversions.Remove(pending); return true; } } if (PendingConversions.Count == 0) { return false; } Vector3 maskedPosition = (((Object)(object)((Component)masked).transform != (Object)null) ? ((Component)masked).transform.position : Vector3.zero); pending = PendingConversions.OrderBy((PendingConversion x) => Vector3.Distance(x.Position, maskedPosition)).FirstOrDefault(); if (pending == null) { return false; } float num = Vector3.Distance(pending.Position, maskedPosition); if (num > 35f) { pending = null; return false; } PendingConversions.Remove(pending); return true; } private static void ApplyConvertedTag(MaskedPlayerEnemy masked, MaskedOriginInfo info, PendingConversion pending) { info.Origin = pending.Origin; info.FormerPlayerClientId = pending.PlayerClientId; info.TaggedAt = Time.time; ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"Tagged Masked {GetNetworkObjectId(masked)} as {pending.Origin} from player {pending.PlayerClientId}."); } } private static MaskedOriginInfo GetOrAddInfo(MaskedPlayerEnemy masked) { MaskedOriginInfo maskedOriginInfo = ((Component)masked).GetComponent<MaskedOriginInfo>(); if ((Object)(object)maskedOriginInfo == (Object)null) { maskedOriginInfo = ((Component)masked).gameObject.AddComponent<MaskedOriginInfo>(); } return maskedOriginInfo; } private static int GetMimickingPlayerClientId(MaskedPlayerEnemy masked) { try { PlayerControllerB value = Traverse.Create((object)masked).Field("mimickingPlayer").GetValue<PlayerControllerB>(); 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 = MaskedOrigin.Unknown; public int FormerPlayerClientId = -1; public float TaggedAt; } public static class ModConfig { 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 bool EnableMaskedPlayerRevive; public static void Bind(ConfigFile config) { ReviveTime = config.Bind<float>("Revive", "ReviveTime", 5f, "How long, in seconds, the revive button must be held.").Value; CanPickUpBodies = config.Bind<bool>("Bodies", "CanPickUpBodies", true, "If false, pressing interact on bodies is blocked so the revive prompt is easier to use.").Value; DeadBodyWeight = config.Bind<float>("Bodies", "DeadBodyWeight", 1.35f, "Weight multiplier applied to dead bodies.").Value; CanReviveTeleportedBodies = config.Bind<bool>("Rules", "CanReviveTeleportedBodies", true, "If false, bodies teleported back to the ship cannot be revived.").Value; ReviveHealth = config.Bind<int>("Rules", "HealthYouReviveWith", 35, "Base health after revive.").Value; ExtraHealthLostPerRevive = config.Bind<int>("Rules", "ExtraHealthLostPerRevive", 5, "Additional health penalty each time the same player is revived in the same round.").Value; LimitedRevives = config.Bind<bool>("Rules", "LimitAmountOfRevives", true, "If true, revives are limited per level.").Value; RevivesPerLevelMultiplier = config.Bind<float>("Rules", "RevivesPerLevelMultiplier", 1.25f, "Revives per level = controlled players * this value, unless FixedRevivesPerLevel is above 0.").Value; FixedRevivesPerLevel = config.Bind<int>("Rules", "FixedRevivesPerLevel", 0, "Overrides RevivesPerLevelMultiplier when above 0.").Value; InfiniteReviveTime = config.Bind<bool>("Rules", "InfiniteReviveTime", false, "If true, players can be revived no matter how long they have been dead.").Value; TimeUntilCannotBeRevived = config.Bind<int>("Rules", "TimeUntilCannotBeRevived", 120, "How long someone can be dead and still be revived, in seconds.").Value; MaxReviveDistance = config.Bind<float>("Revive", "MaxReviveDistance", 3f, "Maximum distance from reviver camera to body.").Value; EnableMaskedPlayerRevive = config.Bind<bool>("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; } 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, bool enableMaskedPlayerRevive) { ReviveTime = reviveTime; CanPickUpBodies = canPickUpBodies; DeadBodyWeight = deadBodyWeight; CanReviveTeleportedBodies = canReviveTeleportedBodies; ReviveHealth = reviveHealth; ExtraHealthLostPerRevive = extraHealthLostPerRevive; LimitedRevives = limitedRevives; RevivesPerLevelMultiplier = revivesPerLevelMultiplier; FixedRevivesPerLevel = fixedRevivesPerLevel; InfiniteReviveTime = infiniteReviveTime; TimeUntilCannotBeRevived = timeUntilCannotBeRevived; MaxReviveDistance = maxReviveDistance; EnableMaskedPlayerRevive = enableMaskedPlayerRevive; } } public static class ModState { public static bool Active; public static int RemainingRevives = int.MaxValue; public static readonly List<PlayerReviveInfo> PlayerInfos = new List<PlayerReviveInfo>(); public static void Reset() { Active = false; RemainingRevives = int.MaxValue; PlayerInfos.Clear(); MaskedConversionTracker.Reset(); } } public sealed class PlayerReviveInfo { public int PlayerClientId; public bool HasBeenTeleported; public float TimeDiedAt; public int TimesRevivedThisLevel; } [BepInPlugin("chaps.ReviveCompanyRemake", "ReviveCompanyRemake", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { private sealed class RuntimeDriver : MonoBehaviour { private void Update() { try { ReviveNetwork.TryRegisterHandlers(); ReviveNetwork.SyncConfigForNewClients(); PlayerControllerBPatch.TickFromPlugin(); } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"Runtime driver update failed: {arg}"); } } } } public const string ModGuid = "chaps.ReviveCompanyRemake"; public const string ModName = "ReviveCompanyRemake"; public const string ModVersion = "1.0.0"; internal static ManualLogSource Log; internal static ReviveInputActions InputActions; private Harmony _harmony; private bool _isQuitting; private static RuntimeDriver _runtimeDriver; internal static InputAction ReviveAction => InputActions?.Revive; private void Awake() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown 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); _harmony = new Harmony("chaps.ReviveCompanyRemake"); try { _harmony.PatchAll(); VerifyHarmonyHooks(); } catch (Exception arg) { Log.LogError((object)$"Harmony patching failed: {arg}"); } Log.LogInfo((object)"ReviveCompanyRemake 1.0.0 loaded."); EnsureRuntimeDriver(); } private void Update() { try { ReviveNetwork.TryRegisterHandlers(); ReviveNetwork.SyncConfigForNewClients(); PlayerControllerBPatch.TickFromPlugin(); } catch (Exception arg) { Log.LogError((object)$"Runtime Update failed: {arg}"); } } private void OnDestroy() { if (!_isQuitting) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"Plugin OnDestroy called before application quit. Keeping Harmony patches active."); } return; } ReviveNetwork.UnregisterHandlers(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void OnApplicationQuit() { _isQuitting = true; } internal static string GetReviveBindingLabel() { InputAction reviveAction = ReviveAction; if (reviveAction == null) { return "key"; } string bindingDisplayString = InputActionRebindingExtensions.GetBindingDisplayString(reviveAction, (DisplayStringOptions)0, (string)null); return string.IsNullOrWhiteSpace(bindingDisplayString) ? "key" : bindingDisplayString; } 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.ReviveCompanyRemake")) || (patchInfo.Postfixes != null && patchInfo.Postfixes.Any((Patch p) => p.owner == "chaps.ReviveCompanyRemake")) || (patchInfo.Transpilers != null && patchInfo.Transpilers.Any((Patch p) => p.owner == "chaps.ReviveCompanyRemake")) || (patchInfo.Finalizers != null && patchInfo.Finalizers.Any((Patch p) => p.owner == "chaps.ReviveCompanyRemake")))) { Log.LogInfo((object)("Harmony hook active: " + type.Name + "." + methodName)); } else { Log.LogWarning((object)("Harmony hook NOT active: " + type.Name + "." + methodName)); } } private void EnsureRuntimeDriver() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!((Object)(object)_runtimeDriver != (Object)null)) { GameObject val = new GameObject("ReviveCompanyRemake.RuntimeDriver"); Object.DontDestroyOnLoad((Object)(object)val); _runtimeDriver = val.AddComponent<RuntimeDriver>(); } } } public sealed class ReviveInputActions : LcInputActions { [InputAction(/*Could not decode attribute arguments.*/)] public InputAction Revive { get; set; } } public static class ReviveLogic { 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_00e6: 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; } RagdollGrabbableObject val = null; if ((Object)(object)playerByClientId.deadBody != (Object)null) { val = ((Component)playerByClientId.deadBody).GetComponentInParent<RagdollGrabbableObject>(); } if ((Object)(object)val == (Object)null) { val = GeneralUtil.GetBodyForPlayer(playerClientId); } MaskedPlayerEnemy val2 = (((Object)(object)val == (Object)null) ? GeneralUtil.GetMaskedByNetworkObjectId(maskedNetworkObjectId) : null); if ((Object)(object)val2 == (Object)null && (Object)(object)val == (Object)null) { val2 = GeneralUtil.GetConvertedMaskedCorpseForPlayer(playerClientId); } try { RevivePlayerState(playerByClientId, health, revivePosition, isInsideFactory); RemoveBody(val); RemoveMaskedCorpse(val2); MaskedConversionTracker.ForgetPlayer(playerClientId); ShowReviveTip(playerByClientId, remainingRevives); } 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_00fb: 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; 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<OccludeAudio>(); 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.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_0045: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_0063: 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_006d: 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) 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; } 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(); } } } } 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 = "ReviveCompanyRemake.RequestRevive.v2"; private const string PerformReviveMessage = "ReviveCompanyRemake.PerformRevive.v2"; private const string RejectReviveMessage = "ReviveCompanyRemake.RejectRevive.v2"; private const string SyncConfigMessage = "ReviveCompanyRemake.SyncConfig.v1"; private static ManualLogSource _log; private static bool _registered; private static readonly HashSet<ulong> _configSyncedClientIds = new HashSet<ulong>(); public static void SetLogSource(ManualLogSource logSource) { _log = logSource; } public static void TryRegisterHandlers() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0076: 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_0081: Expected O, but got Unknown //IL_009d: 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_00a8: Expected O, but got Unknown //IL_00c4: 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: 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("ReviveCompanyRemake.RequestRevive.v2", (HandleNamedMessageDelegate)obj); object obj2 = <>O.<1>__OnPerformRevive; if (obj2 == null) { HandleNamedMessageDelegate val2 = OnPerformRevive; <>O.<1>__OnPerformRevive = val2; obj2 = (object)val2; } customMessagingManager.RegisterNamedMessageHandler("ReviveCompanyRemake.PerformRevive.v2", (HandleNamedMessageDelegate)obj2); object obj3 = <>O.<2>__OnRejectRevive; if (obj3 == null) { HandleNamedMessageDelegate val3 = OnRejectRevive; <>O.<2>__OnRejectRevive = val3; obj3 = (object)val3; } customMessagingManager.RegisterNamedMessageHandler("ReviveCompanyRemake.RejectRevive.v2", (HandleNamedMessageDelegate)obj3); object obj4 = <>O.<3>__OnSyncConfig; if (obj4 == null) { HandleNamedMessageDelegate val4 = OnSyncConfig; <>O.<3>__OnSyncConfig = val4; obj4 = (object)val4; } customMessagingManager.RegisterNamedMessageHandler("ReviveCompanyRemake.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("ReviveCompanyRemake.RequestRevive.v2"); customMessagingManager.UnregisterNamedMessageHandler("ReviveCompanyRemake.PerformRevive.v2"); customMessagingManager.UnregisterNamedMessageHandler("ReviveCompanyRemake.RejectRevive.v2"); customMessagingManager.UnregisterNamedMessageHandler("ReviveCompanyRemake.SyncConfig.v1"); _registered = false; ModState.Active = false; _configSyncedClientIds.Clear(); } } public static void SendConfigToClients() { //IL_002f: 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 (!GeneralUtil.IsNetworkReady() || !NetworkManager.Singleton.IsServer) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(128, (Allocator)2, -1); try { WriteConfigPayload(val); List<ulong> list = new List<ulong>(); foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != 0) { list.Add(connectedClientsId); } } if (list.Count <= 0) { return; } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReviveCompanyRemake.SyncConfig.v1", (IReadOnlyList<ulong>)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_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) if (!GeneralUtil.IsNetworkReady() || !NetworkManager.Singleton.IsServer || NetworkManager.Singleton.CustomMessagingManager == null) { return; } HashSet<ulong> connectedClientIds = new HashSet<ulong>(); foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { connectedClientIds.Add(connectedClientsId); } _configSyncedClientIds.RemoveWhere((ulong id) => !connectedClientIds.Contains(id)); List<ulong> list = new List<ulong>(); foreach (ulong connectedClientsId2 in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId2 != 0 && !_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("ReviveCompanyRemake.SyncConfig.v1", (IReadOnlyList<ulong>)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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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_00be: 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<int>(ref reviverPlayerClientId, default(ForPrimitives)); ((FastBufferWriter)(ref val2)).WriteValueSafe<int>(ref targetPlayerClientId, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReviveCompanyRemake.RequestRevive.v2", 0uL, val2, (NetworkDelivery)3); } finally { ((IDisposable)(FastBufferWriter)(ref val2)).Dispose(); } } private static void OnRequestRevive(ulong senderClientId, FastBufferReader reader) { //IL_001a: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsServer) { int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); int targetPlayerClientId = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref targetPlayerClientId, default(ForPrimitives)); int reviverPlayerClientId = (((Object)(object)GeneralUtil.GetPlayerByClientId((int)senderClientId) != (Object)null) ? ((int)senderClientId) : num); ProcessReviveRequest(reviverPlayerClientId, targetPlayerClientId, senderClientId); } } private static void ProcessReviveRequest(int reviverPlayerClientId, int targetPlayerClientId, ulong requestingNetworkClientId) { //IL_00a1: 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_00a6: 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_00e9: 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_0113: 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_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(reviverPlayerClientId); RagdollGrabbableObject bodyForPlayer = GeneralUtil.GetBodyForPlayer(targetPlayerClientId); MaskedPlayerEnemy val = null; bool flag; int targetPlayerClientId2; string reason; if ((Object)(object)bodyForPlayer != (Object)null) { flag = ReviveRules.CanRevive(playerByClientId, bodyForPlayer, out targetPlayerClientId2, out reason); } else { val = GeneralUtil.GetConvertedMaskedCorpseForPlayer(targetPlayerClientId); flag = ReviveRules.CanReviveMasked(playerByClientId, val, out targetPlayerClientId2, out reason); } if (!flag) { SendReject(requestingNetworkClientId, reason); return; } PlayerControllerB playerByClientId2 = GeneralUtil.GetPlayerByClientId(targetPlayerClientId2); if ((Object)(object)playerByClientId2 == (Object)null) { SendReject(requestingNetworkClientId, "target missing"); return; } Vector3 val2 = (((Object)(object)bodyForPlayer != (Object)null) ? ((Component)bodyForPlayer).transform.position : ((Component)val).transform.position); if (!GeneralUtil.IsReviverCloseEnough(playerByClientId, val2)) { SendReject(requestingNetworkClientId, "too far from body"); return; } bool isInsideFactory = playerByClientId2.isInsideFactory; ulong maskedNetworkObjectId = (((Object)(object)val != (Object)null) ? MaskedConversionTracker.GetNetworkObjectId(val) : 0); PlayerControllerB closestAlivePlayer = GeneralUtil.GetClosestAlivePlayer(val2); if ((Object)(object)closestAlivePlayer != (Object)null) { isInsideFactory = closestAlivePlayer.isInsideFactory; if (Vector3.Distance(val2, ((Component)closestAlivePlayer).transform.position) > 7f) { val2 = ((Component)closestAlivePlayer).transform.position; } } int health = GeneralUtil.IncrementReviveCountAndGetHealth(targetPlayerClientId2); if (ModConfig.LimitedRevives) { ModState.RemainingRevives = Mathf.Max(0, ModState.RemainingRevives - 1); } BroadcastRevive(targetPlayerClientId2, health, ModState.RemainingRevives, val2, isInsideFactory, maskedNetworkObjectId); } private static void BroadcastRevive(int targetPlayerClientId, int health, int remainingRevives, Vector3 position, bool insideFactory, ulong maskedNetworkObjectId) { //IL_0004: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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<ulong> list = new List<ulong>(); foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != 0) { list.Add(connectedClientsId); } } if (list.Count > 0) { NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReviveCompanyRemake.PerformRevive.v2", (IReadOnlyList<ulong>)list, val, (NetworkDelivery)3); } } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private static void OnPerformRevive(ulong senderClientId, FastBufferReader reader) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_003c: 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_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_0065: 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<FixedString128Bytes>(ref val2, default(ForFixedStrings)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReviveCompanyRemake.RejectRevive.v2", networkClientId, val, (NetworkDelivery)3); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private static void OnRejectRevive(ulong senderClientId, FastBufferReader reader) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) FixedString128Bytes val = default(FixedString128Bytes); ((FastBufferReader)(ref reader)).ReadValueSafe<FixedString128Bytes>(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_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_002d: 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_0045: 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_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_0075: 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_0088: 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_009b: 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) ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref targetPlayerClientId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref health, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref remainingRevives, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref position.x, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref position.y, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref position.z, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref insideFactory, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<ulong>(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_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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0063: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref targetPlayerClientId, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref health, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref remainingRevives, default(ForPrimitives)); float num = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num, default(ForPrimitives)); float num2 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num2, default(ForPrimitives)); float num3 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num3, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref insideFactory, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(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_000a: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0052: 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_0068: 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_007e: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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) ((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref ModConfig.ReviveTime, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref ModConfig.CanPickUpBodies, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref ModConfig.DeadBodyWeight, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref ModConfig.CanReviveTeleportedBodies, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref ModConfig.ReviveHealth, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref ModConfig.ExtraHealthLostPerRevive, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref ModConfig.LimitedRevives, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref ModConfig.RevivesPerLevelMultiplier, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref ModConfig.FixedRevivesPerLevel, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref ModConfig.InfiniteReviveTime, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref ModConfig.TimeUntilCannotBeRevived, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref ModConfig.MaxReviveDistance, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref ModConfig.EnableMaskedPlayerRevive, 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 bool enableMaskedPlayerRevive) { //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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0063: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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) //IL_008f: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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_00e8: 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) ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref reviveTime, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref canPickUpBodies, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref deadBodyWeight, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref canReviveTeleportedBodies, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref reviveHealth, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref extraHealthLostPerRevive, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref limitedRevives, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref revivesPerLevelMultiplier, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref fixedRevivesPerLevel, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref infiniteReviveTime, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref timeUntilCannotBeRevived, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref maxReviveDistance, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref enableMaskedPlayerRevive, default(ForPrimitives)); } private static void OnSyncConfig(ulong senderClientId, FastBufferReader reader) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsServer && senderClientId == 0) { 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 enableMaskedPlayerRevive); ModConfig.ApplySyncedConfig(reviveTime, canPickUpBodies, deadBodyWeight, canReviveTeleportedBodies, reviveHealth, extraHealthLostPerRevive, limitedRevives, revivesPerLevelMultiplier, fixedRevivesPerLevel, infiniteReviveTime, timeUntilCannotBeRevived, maxReviveDistance, enableMaskedPlayerRevive); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)"Received config synchronization from host."); } } } } public static class ReviveRules { public static bool CanRevive(PlayerControllerB reviver, RagdollGrabbableObject body, out int targetPlayerClientId, out string reason) { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) targetPlayerClientId = -1; reason = string.Empty; if (!ModState.Active) { reason = "mod inactive"; return false; } if ((Object)(object)reviver == (Object)null || reviver.isPlayerDead) { reason = "reviver invalid"; return false; } if (!GeneralUtil.TryGetBodyOwner(body, out targetPlayerClientId, out var targetPlayer)) { reason = "no body"; return false; } if (!targetPlayer.isPlayerDead) { reason = "player already alive"; return false; } if ((int)reviver.playerClientId == targetPlayerClientId) { reason = "cannot revive yourself"; return false; } if ((Object)(object)body == (Object)null || (Object)(object)((Component)body).transform == (Object)null || !GeneralUtil.IsReviverCloseEnough(reviver, ((Component)body).transform.position)) { reason = "too far from body"; return false; } if (ModConfig.LimitedRevives && ModState.RemainingRevives <= 0) { reason = "no revives left"; return false; } if (!ModConfig.CanReviveTeleportedBodies && GeneralUtil.HasPlayerTeleported(targetPlayerClientId)) { reason = "body was teleported"; return false; } if (!ModConfig.InfiniteReviveTime) { float num = Time.time - GeneralUtil.GetPlayerDiedAtTime(targetPlayerClientId); if (num > (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_0145: Unknown result type (might be due to invalid IL or missing references) targetPlayerClientId = -1; reason = string.Empty; if (!ModState.Active) { reason = "mod inactive"; return false; } if (!ModConfig.EnableMaskedPlayerRevive) { reason = "masked revive disabled"; return false; } if ((Object)(object)reviver == (Object)null || reviver.isPlayerDead) { reason = "reviver invalid"; return false; } if ((Object)(object)masked == (Object)null) { reason = "no masked body"; return false; } if (!MaskedConversionTracker.IsMaskedDead(masked)) { reason = "kill masked first"; return false; } if (!GeneralUtil.TryResolveConvertedMaskedPlayer(masked, out targetPlayerClientId, out var _)) { reason = "not a converted player"; return false; } PlayerControllerB playerByClientId = GeneralUtil.GetPlayerByClientId(targetPlayerClientId); if ((Object)(object)playerByClientId == (Object)null) { reason = "target missing"; return false; } if (!playerByClientId.isPlayerDead) { reason = "player already alive"; return false; } if ((int)reviver.playerClientId == targetPlayerClientId) { reason = "cannot revive yourself"; return false; } if ((Object)(object)masked == (Object)null || (Object)(object)((Component)masked).transform == (Object)null || !GeneralUtil.IsReviverCloseEnough(reviver, ((Component)masked).transform.position)) { reason = "too far from body"; return false; } if (ModConfig.LimitedRevives && ModState.RemainingRevives <= 0) { reason = "no revives left"; return false; } if (!ModConfig.InfiniteReviveTime) { float num = Time.time - GeneralUtil.GetPlayerDiedAtTime(targetPlayerClientId); if (num > (float)ModConfig.TimeUntilCannotBeRevived) { reason = "time expired"; return false; } } return true; } } } namespace ReviveCompanyRemake.Patches { [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<PlayerControllerB>(); } 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)) { PlayerControllerB val = ((EnemyAI)(__instance?)).inSpecialAnimationWithPlayer; if ((Object)(object)val != (Object)null) { MaskedConversionTracker.RegisterPending(val, MaskedOrigin.ConvertedByMaskedEnemy); } } } [HarmonyPatch(typeof(MaskedPlayerEnemy), "FinishKillAnimation")] [HarmonyPostfix] private static void FinishKillAnimationPostfix(MaskedPlayerEnemy __instance) { if (ModState.Active && ModConfig.EnableMaskedPlayerRevive && !((Object)(object)__instance == (Object)null)) { PlayerControllerB val = null; try { val = Traverse.Create((object)__instance).Field("lastPlayerKilled").GetValue<PlayerControllerB>(); } catch { } if ((Object)(object)val != (Object)null) { MaskedConversionTracker.RegisterPending(val, MaskedOrigin.ConvertedByMaskedEnemy); } } } } [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; private static int _lastHandledUpdateFrame = -1; private static int _lastHandledLateFrame = -1; [HarmonyPatch("KillPlayerClientRpc")] [HarmonyPrefix] private static void KillPlayerClientRpcPrefix(ref int playerId) { GeneralUtil.SetPlayerDiedAt(playerId); } [HarmonyPatch("Interact_performed")] [HarmonyPrefix] private static bool InteractPerformedPrefix(PlayerControllerB __instance) { if (ModConfig.CanPickUpBodies) { return true; } if (!IsLocalAlivePlayer(__instance)) { return true; } return (Object)(object)GeneralUtil.GetLookedAtBody(__instance) == (Object)null; } [HarmonyPatch("SetHoverTipAndCurrentInteractTrigger")] [HarmonyPostfix] private static void SetHoverTipAndCurrentInteractTriggerPostfix(PlayerControllerB __instance) { HandleReviveUiAndInput(__instance, latePass: false); } [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePostfix(PlayerControllerB __instance) { HandleReviveUiAndInput(__instance, latePass: false); } [HarmonyPatch("LateUpdate")] [HarmonyPostfix] private static void LateUpdatePostfix(PlayerControllerB __instance) { HandleReviveUiAndInput(__instance, latePass: true); } internal static void TickFromPlugin() { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (!((Object)(object)val == (Object)null)) { HandleReviveUiAndInput(val, latePass: false); } } private static void HandleReviveUiAndInput(PlayerControllerB player, bool latePass) { 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; } int frameCount = Time.frameCount; if (latePass) { if (frameCount == _lastHandledLateFrame) { return; } _lastHandledLateFrame = frameCount; } else { if (frameCount == _lastHandledUpdateFrame) { return; } _lastHandledUpdateFrame = frameCount; } 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) { SetReviveOverlay(cursorTip, "Revive: can't revive (" + 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; RagdollGrabbableObject lookedAtBody = GeneralUtil.GetLookedAtBody(reviver); if ((Object)(object)lookedAtBody != (Object)null) { canRevive = ReviveRules.CanRevive(reviver, lookedAtBody, out targetPlayerId, out reason); return true; } if (!ModConfig.EnableMaskedPlayerRevive) { reason = "no body detected and masked revive disabled"; return false; } MaskedPlayerEnemy lookedAtConvertedMaskedCorpse = GeneralUtil.GetLookedAtConvertedMaskedCorpse(reviver); if ((Object)(object)lookedAtConvertedMaskedCorpse == (Object)null) { reason = "no body or converted masked corpse under crosshair"; return false; } canRevive = ReviveRules.CanReviveMasked(reviver, lookedAtConvertedMaskedCorpse, out targetPlayerId, out reason); return true; } 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 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 { [HarmonyPatch("Start")] [HarmonyPrefix] private static void StartPrefix(RagdollGrabbableObject __instance) { if (ModState.Active && !((Object)(object)__instance == (Object)null)) { if ((Object)(object)((GrabbableObject)(__instance?)).itemProperties != (Object)null) { ((GrabbableObject)__instance).itemProperties.weight = ModConfig.DeadBodyWeight; } } } } [HarmonyPatch(typeof(ShipTeleporter))] internal static class ShipTeleporterPatch { [HarmonyPatch("beamUpPlayer")] [HarmonyPrefix] private static void BeamUpPlayerPrefix() { if (ModState.Active && !((Object)(object)StartOfRound.Instance == (Object)null)) { PlayerControllerB val = StartOfRound.Instance.mapScreen?.targetedPlayer; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.redirectToEnemy != (Object)null) && !((Object)(object)val.deadBody == (Object)null) && val.isPlayerDead) { GeneralUtil.MarkTeleported((int)val.playerClientId); } } } } [HarmonyPatch(typeof(StartOfRound))] internal static class StartOfRoundPatch { [CompilerGenerated] private sealed class <RegisterNetworkDelayed>d__5 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RegisterNetworkDelayed>d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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(); 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(); GeneralUtil.SetRemainingRevivesFromPlayerCount(); } } [HarmonyPatch("EndOfGame")] [HarmonyPrefix] private static void EndOfGamePrefix() { if (ModState.Active) { GeneralUtil.ResetAllPlayerInfos(); MaskedConversionTracker.Reset(); } } [IteratorStateMachine(typeof(<RegisterNetworkDelayed>d__5))] private static IEnumerator RegisterNetworkDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RegisterNetworkDelayed>d__5(0); } } }