Please disclose if your mod was created primarily 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 BunkbedRevive LegitsFork v2.0.2
BunkbedRevive.dll
Decompiled a month agousing System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BunkbedRevive.Configuration; using GameNetcodeStuff; using HarmonyLib; using LethalConfig; using LethalConfig.ConfigItems; using LethalConfig.ConfigItems.Options; using Microsoft.CodeAnalysis; using StaticNetcodeLib; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Events; [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: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("BunkbedRevive")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Revive dead players at the bunkbeds")] [assembly: AssemblyFileVersion("2.0.0.0")] [assembly: AssemblyInformationalVersion("2.0.0")] [assembly: AssemblyProduct("BunkbedRevive")] [assembly: AssemblyTitle("BunkbedRevive")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BunkbedRevive { public class BunkbedController : MonoBehaviour { private static InteractTrigger interactTrigger; private static Sprite defaultIcon; private static Sprite disabledIcon; public static BunkbedController Instance; public static int remainingOverallRevives = 0; public static List<int> teleportedBodies = new List<int>(); public static Dictionary<int, int> remainingPlayerRevives = new Dictionary<int, int>(); public static int GetReviveCost() { CostMethods reviveCostMethod = NetworkSync.Config.ReviveCostMethod; int reviveCostPercent = NetworkSync.Config.ReviveCostPercent; int reviveCostAmount = NetworkSync.Config.ReviveCostAmount; BunkbedRevive.Logger.LogDebug((object)$"GetReviveCost called - Method: {reviveCostMethod}, Percent: {reviveCostPercent}%, Amount: {reviveCostAmount}"); if (reviveCostMethod == CostMethods.SetAmount) { int num = ((reviveCostAmount > 0) ? reviveCostAmount : 0); BunkbedRevive.Logger.LogDebug((object)$"Using SetAmount method - Cost: {num}"); return num; } if (reviveCostPercent <= 0) { BunkbedRevive.Logger.LogDebug((object)"Using Percentage method but percent is 0 - Cost: 0"); return 0; } int num2 = (int)Math.Floor((float)TimeOfDay.Instance.profitQuota * ((float)reviveCostPercent / 100f)); BunkbedRevive.Logger.LogDebug((object)$"Using Percentage method - Quota: {TimeOfDay.Instance.profitQuota}, Calculated Cost: {num2}"); return num2; } public static bool CanRevive(int id, bool logStuff = false) { ReviveLimits reviveLimitMethod = NetworkSync.Config.ReviveLimitMethod; bool reviveTeleported = NetworkSync.Config.ReviveTeleported; BunkbedRevive.Logger.LogDebug((object)$"CanRevive called - PlayerID: {id}, ReviveLimit: {reviveLimitMethod}, CanReviveTeleported: {reviveTeleported}"); if (!reviveTeleported && teleportedBodies.Contains(id)) { BunkbedRevive.Logger.LogDebug((object)$"Player {id} cannot be revived - body was teleported"); return false; } switch (reviveLimitMethod) { case ReviveLimits.None: BunkbedRevive.Logger.LogDebug((object)$"Player {id} can be revived - no revive limits"); return true; case ReviveLimits.Overall: { bool flag2 = remainingOverallRevives > 0; BunkbedRevive.Logger.LogDebug((object)$"Overall revive limit - Remaining: {remainingOverallRevives}, Can Revive: {flag2}"); return flag2; } case ReviveLimits.PerPlayer: if (remainingPlayerRevives.ContainsKey(id)) { bool flag = remainingPlayerRevives[id] > 0; BunkbedRevive.Logger.LogDebug((object)$"Per-player revive limit for {id} - Remaining: {remainingPlayerRevives[id]}, Can Revive: {flag}"); return flag; } BunkbedRevive.Logger.LogDebug((object)$"Player {id} not in revive dictionary - adding with limit {NetworkSync.Config.ReviveLimitPer}"); remainingPlayerRevives.Add(id, NetworkSync.Config.ReviveLimitPer); return true; default: BunkbedRevive.Logger.LogDebug((object)$"Player {id} can be revived - default true"); return true; } } public static void UpdateReviveCount(int id) { ReviveLimits reviveLimitMethod = NetworkSync.Config.ReviveLimitMethod; BunkbedRevive.Logger.LogDebug((object)$"UpdateReviveCount called - PlayerID: {id}, ReviveLimit: {reviveLimitMethod}"); switch (reviveLimitMethod) { case ReviveLimits.None: BunkbedRevive.Logger.LogDebug((object)"No revive limits - not updating count"); return; case ReviveLimits.Overall: { int num = remainingOverallRevives; remainingOverallRevives--; BunkbedRevive.Logger.LogDebug((object)$"Overall revive count updated - Before: {num}, After: {remainingOverallRevives}"); break; } } if (reviveLimitMethod == ReviveLimits.PerPlayer) { if (!remainingPlayerRevives.ContainsKey(id)) { BunkbedRevive.Logger.LogDebug((object)$"Player {id} not in revive dictionary - adding with limit {NetworkSync.Config.ReviveLimitPer}"); remainingPlayerRevives.Add(id, NetworkSync.Config.ReviveLimitPer); } int num2 = remainingPlayerRevives[id]; remainingPlayerRevives[id]--; BunkbedRevive.Logger.LogDebug((object)$"Per-player revive count updated for {id} - Before: {num2}, After: {remainingPlayerRevives[id]}"); } } private static void CreateTrigger() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_004a: 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_0093: 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_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Expected O, but got Unknown //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Expected O, but got Unknown //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Expected O, but got Unknown //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Expected O, but got Unknown //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Expected O, but got Unknown GameObject val = new GameObject("Bed", new Type[2] { typeof(BoxCollider), typeof(InteractTrigger) }); Transform transform = ((Component)Instance).transform; val.transform.SetParent(transform); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.layer = LayerMask.NameToLayer("InteractableObject"); val.tag = "InteractTrigger"; BoxCollider component = val.GetComponent<BoxCollider>(); ((Collider)component).isTrigger = true; component.center = Vector3.zero; component.size = new Vector3(2.5f, 3f, 1f); ((Collider)component).enabled = true; int reviveCost = GetReviveCost(); interactTrigger = val.GetComponent<InteractTrigger>(); interactTrigger.twoHandedItemAllowed = true; interactTrigger.interactable = true; interactTrigger.holdInteraction = false; interactTrigger.timeToHold = 0.4f; interactTrigger.cooldownTime = 0.25f; interactTrigger.timeToHoldSpeedMultiplier = 1f; interactTrigger.hoverTip = "Revive for " + ((reviveCost <= 0) ? "free" : (reviveCost + " scrap")) + " : [E]"; interactTrigger.hoverIcon = defaultIcon; interactTrigger.disabledHoverIcon = disabledIcon; interactTrigger.disabledHoverTip = "No dead players"; interactTrigger.onCancelAnimation = new InteractEvent(); interactTrigger.holdingInteractEvent = new InteractEventFloat(); interactTrigger.onInteractEarly = new InteractEvent(); interactTrigger.onInteract = new InteractEvent(); interactTrigger.onStopInteract = new InteractEvent(); ((UnityEvent<PlayerControllerB>)(object)interactTrigger.onInteract).AddListener((UnityAction<PlayerControllerB>)delegate { OnInteract(); }); ((UnityEvent<PlayerControllerB>)(object)interactTrigger.onStopInteract).AddListener((UnityAction<PlayerControllerB>)delegate { OnStopInteract(); }); } public static void ResetValues() { BunkbedRevive.Logger.LogDebug((object)$"ResetValues called - Setting overall revives to {NetworkSync.Config.ReviveLimitOverall}"); remainingOverallRevives = NetworkSync.Config.ReviveLimitOverall; remainingPlayerRevives.Clear(); teleportedBodies.Clear(); BunkbedRevive.Logger.LogDebug((object)"Player revive counters and teleported bodies cleared"); } private void Awake() { BunkbedRevive.Logger.LogDebug((object)"BunkbedController Awake called"); Instance = this; GetIcons(); CreateTrigger(); ResetValues(); BunkbedRevive.Logger.LogInfo((object)"BunkbedController initialized successfully"); } private void Update() { if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return; } bool flag = StartOfRound.Instance.connectedPlayersAmount + 1 - StartOfRound.Instance.livingPlayers > 0; RagdollGrabbableObject heldBody = GetHeldBody(); interactTrigger.interactable = flag && Object.op_Implicit((Object)(object)heldBody); if (!Object.op_Implicit((Object)(object)heldBody)) { return; } string text = (Object.op_Implicit((Object)(object)heldBody.ragdoll) ? heldBody.ragdoll.playerScript.playerUsername : "Player"); int num = heldBody.bodyID.Value; if ((Object)(object)heldBody.ragdoll != (Object)null && (Object)(object)heldBody.ragdoll.playerScript != (Object)null) { int num2 = (int)heldBody.ragdoll.playerScript.playerClientId; if (num != num2) { num = num2; } } if (!CanRevive(num)) { interactTrigger.hoverTip = "Can't revive " + text; return; } int reviveCost = GetReviveCost(); interactTrigger.hoverTip = "Revive " + text + " for " + ((reviveCost <= 0) ? "free" : (reviveCost + " scrap")) + " : [E]"; } private static void GetIcons() { StartMatchLever val = Object.FindObjectOfType<StartMatchLever>(); defaultIcon = val.triggerScript.hoverIcon; disabledIcon = val.triggerScript.disabledHoverIcon; } private static RagdollGrabbableObject? GetHeldBody() { PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; GrabbableObject currentlyHeldObjectServer = GameNetworkManager.Instance.localPlayerController.currentlyHeldObjectServer; if (!localPlayerController.isHoldingObject || (Object)(object)currentlyHeldObjectServer == (Object)null || !Object.op_Implicit((Object)(object)currentlyHeldObjectServer) || !(currentlyHeldObjectServer is RagdollGrabbableObject)) { return null; } return (RagdollGrabbableObject?)(object)((currentlyHeldObjectServer is RagdollGrabbableObject) ? currentlyHeldObjectServer : null); } private static PlayerControllerB GetLocalPlayer() { return GameNetworkManager.Instance.localPlayerController; } public static void RevivePlayer(int playerId) { //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) BunkbedRevive.Logger.LogDebug((object)$"RevivePlayer called for PlayerID: {playerId}"); PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerId]; if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val == (Object)null) { BunkbedRevive.Logger.LogError((object)$"Cannot revive player {playerId} - player script is null or invalid"); return; } string playerUsername = val.playerUsername; bool isPlayerDead = val.isPlayerDead; BunkbedRevive.Logger.LogDebug((object)$"Reviving {playerUsername} (ID: {playerId}) - Was Dead: {isPlayerDead}, Is Controlled: {val.isPlayerControlled}"); UpdateReviveCount(playerId); if (val.isPlayerDead || val.isPlayerControlled) { BunkbedRevive.Logger.LogDebug((object)("Resetting player state for " + playerUsername)); val.ResetPlayerBloodObjects(val.isPlayerDead); val.isClimbingLadder = false; val.clampLooking = false; val.inVehicleAnimation = false; val.disableMoveInput = false; val.ResetZAndXRotation(); ((Collider)val.thisController).enabled = true; val.health = 100; val.disableLookInput = false; val.disableInteract = false; if (val.isPlayerDead) { BunkbedRevive.Logger.LogDebug((object)("Player " + playerUsername + " was dead - performing full revival")); val.isPlayerDead = false; val.isPlayerControlled = true; val.isInElevator = true; val.isInHangarShipRoom = true; val.isInsideFactory = false; val.parentedToElevatorLastFrame = false; val.overrideGameOverSpectatePivot = null; StartOfRound.Instance.SetPlayerObjectExtrapolate(false); val.TeleportPlayer(StartOfRound.Instance.GetPlayerSpawnPosition(playerId, false), false, 0f, false, true); BunkbedRevive.Logger.LogDebug((object)("Teleported " + playerUsername + " to spawn position")); val.setPositionOfDeadPlayer = false; val.DisablePlayerModel(StartOfRound.Instance.allPlayerObjects[playerId], true, true); ((Behaviour)val.helmetLight).enabled = false; val.Crouch(false); val.criticallyInjured = false; if ((Object)(object)val.playerBodyAnimator != (Object)null) { val.playerBodyAnimator.SetBool("Limp", false); } val.bleedingHeavily = false; val.activatingItem = false; val.twoHanded = false; val.inShockingMinigame = false; val.inSpecialInteractAnimation = false; val.freeRotationInInteractAnimation = false; val.disableSyncInAnimation = false; val.inAnimationWithEnemy = null; val.holdingWalkieTalkie = false; val.speakingToWalkieTalkie = false; val.isSinking = false; val.isUnderwater = false; val.sinkingValue = 0f; val.statusEffectAudio.Stop(); val.DisableJetpackControlsLocally(); val.health = 100; val.mapRadarDotAnimator.SetBool("dead", false); val.deadBody = null; val.externalForceAutoFade = Vector3.zero; if ((Object)(object)val == (Object)(object)GameNetworkManager.Instance.localPlayerController) { BunkbedRevive.Logger.LogDebug((object)(playerUsername + " is local player - updating local UI")); HUDManager.Instance.gasHelmetAnimator.SetBool("gasEmitting", false); val.hasBegunSpectating = false; HUDManager.Instance.RemoveSpectateUI(); HUDManager.Instance.gameOverAnimator.SetTrigger("revive"); val.hinderedMultiplier = 1f; val.isMovementHindered = 0; val.sourcesCausingSinking = 0; val.reverbPreset = StartOfRound.Instance.shipReverb; } } BunkbedRevive.Logger.LogDebug((object)("Resetting audio and voice settings for " + playerUsername)); SoundManager.Instance.earsRingingTimer = 0f; val.voiceMuffledByEnemy = false; SoundManager.Instance.playerVoicePitchTargets[playerId] = 1f; SoundManager.Instance.SetPlayerPitch(1f, playerId); if ((Object)(object)val.currentVoiceChatIngameSettings == (Object)null) { StartOfRound.Instance.RefreshPlayerVoicePlaybackObjects(); } if ((Object)(object)val.currentVoiceChatIngameSettings != (Object)null) { if ((Object)(object)val.currentVoiceChatIngameSettings.voiceAudio == (Object)null) { val.currentVoiceChatIngameSettings.InitializeComponents(); } if ((Object)(object)val.currentVoiceChatIngameSettings.voiceAudio == (Object)null) { return; } ((Component)val.currentVoiceChatIngameSettings.voiceAudio).GetComponent<OccludeAudio>().overridingLowPass = false; } } BunkbedRevive.Logger.LogDebug((object)$"Updating game state - Living players before: {StartOfRound.Instance.livingPlayers}"); StartOfRound instance = StartOfRound.Instance; instance.livingPlayers++; StartOfRound.Instance.allPlayersDead = false; BunkbedRevive.Logger.LogDebug((object)$"Living players after: {StartOfRound.Instance.livingPlayers}, All players dead: {StartOfRound.Instance.allPlayersDead}"); if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)(object)val) { BunkbedRevive.Logger.LogDebug((object)(playerUsername + " is local player - updating local player state")); val.bleedingHeavily = false; val.criticallyInjured = false; val.playerBodyAnimator.SetBool("Limp", false); val.health = 100; HUDManager.Instance.UpdateHealthUI(100, false); val.spectatedPlayerScript = null; ((Behaviour)HUDManager.Instance.audioListenerLowPass).enabled = false; StartOfRound.Instance.SetSpectateCameraToGameOverMode(false, val); TimeOfDay.Instance.DisableAllWeather(false); StartOfRound.Instance.UpdatePlayerVoiceEffects(); ((Renderer)val.thisPlayerModel).enabled = true; HUDManager.Instance.HideHUD(false); } else { BunkbedRevive.Logger.LogDebug((object)(playerUsername + " is remote player - enabling player models")); ((Renderer)val.thisPlayerModel).enabled = true; ((Renderer)val.thisPlayerModelLOD1).enabled = true; ((Renderer)val.thisPlayerModelLOD2).enabled = true; } BunkbedRevive.Logger.LogInfo((object)$"Successfully revived {playerUsername} (ID: {playerId})"); } public static void OnInteract() { BunkbedRevive.Logger.LogDebug((object)"OnInteract called - bunkbed interaction started"); PlayerControllerB localPlayer = GetLocalPlayer(); RagdollGrabbableObject heldBody = GetHeldBody(); if (!Object.op_Implicit((Object)(object)heldBody)) { BunkbedRevive.Logger.LogWarning((object)"OnInteract called but player is not holding a body"); return; } int num = heldBody.bodyID.Value; string text = "Unknown"; if ((Object)(object)heldBody.ragdoll != (Object)null && (Object)(object)heldBody.ragdoll.playerScript != (Object)null) { text = heldBody.ragdoll.playerScript.playerUsername; int num2 = (int)heldBody.ragdoll.playerScript.playerClientId; BunkbedRevive.Logger.LogDebug((object)$"[CLIENT] Body Info - BodyID from NetworkVar: {num}, Actual PlayerClientId from ragdoll: {num2}, Player Name: {text}"); if (num != num2) { BunkbedRevive.Logger.LogWarning((object)$"[CLIENT] BODY ID MISMATCH! BodyID ({num}) != PlayerClientId ({num2}) for player {text}"); BunkbedRevive.Logger.LogWarning((object)"[CLIENT] This is likely a desync issue. Using actual PlayerClientId instead."); num = num2; } } else { BunkbedRevive.Logger.LogWarning((object)$"[CLIENT] Could not get ragdoll player info! Using bodyID: {num}"); } int reviveCost = GetReviveCost(); BunkbedRevive.Logger.LogDebug((object)$"[CLIENT] Attempting revive - PlayerID: {num}, Player Name: {text}, Cost: {reviveCost}, Current Credits: {HUDManager.Instance.terminalScript.groupCredits}"); if (HUDManager.Instance.terminalScript.groupCredits < reviveCost) { BunkbedRevive.Logger.LogDebug((object)$"Not enough credits - Need: {reviveCost}, Have: {HUDManager.Instance.terminalScript.groupCredits}"); HUDManager.Instance.DisplayGlobalNotification("Not enough credits"); interactTrigger.StopInteraction(); return; } if (!CanRevive(num, logStuff: true)) { BunkbedRevive.Logger.LogDebug((object)$"Cannot revive player {num} ({text}) - revive limit or teleportation rule"); HUDManager.Instance.DisplayGlobalNotification("Can't Revive"); interactTrigger.StopInteraction(); return; } BunkbedRevive.Logger.LogDebug((object)$"[CLIENT] Sending RevivePlayerServerRpc for player {num} ({text})"); BunkbedNetworking.RevivePlayerServerRpc(num, reviveCost); if (Object.op_Implicit((Object)(object)localPlayer)) { BunkbedRevive.Logger.LogDebug((object)"Despawning held body object"); localPlayer.DespawnHeldObject(); } } private static void OnStopInteract() { int reviveCost = GetReviveCost(); interactTrigger.hoverTip = "Revive for " + ((reviveCost <= 0) ? "free" : (reviveCost + " scrap")) + " : [E]"; } } [StaticNetcode] internal class BunkbedNetworking { [ServerRpc(RequireOwnership = false)] public static void RevivePlayerServerRpc(int id, int reviveCost) { BunkbedRevive.Logger.LogDebug((object)$"[SERVER] RevivePlayerServerRpc called - PlayerID: {id}, Cost: {reviveCost}"); if ((Object)(object)StartOfRound.Instance == (Object)null || id < 0 || id >= StartOfRound.Instance.allPlayerScripts.Length) { ManualLogSource logger = BunkbedRevive.Logger; object arg = id; StartOfRound instance = StartOfRound.Instance; logger.LogError((object)$"[SERVER] Invalid player ID: {arg}. Valid range: 0-{((instance != null) ? (instance.allPlayerScripts.Length - 1) : (-1))}"); NotifyClientRpc("Invalid player ID", success: false); return; } PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[id]; if ((Object)(object)val == (Object)null) { BunkbedRevive.Logger.LogError((object)$"[SERVER] Player script is null for ID: {id}"); NotifyClientRpc("Player not found", success: false); return; } if (!val.isPlayerDead) { BunkbedRevive.Logger.LogWarning((object)$"[SERVER] Attempted to revive player {val.playerUsername} (ID: {id}) who is not dead!"); NotifyClientRpc(val.playerUsername + " is not dead", success: false); return; } BunkbedRevive.Logger.LogDebug((object)$"[SERVER] Validated player {val.playerUsername} (ID: {id}) is dead and ready for revival"); Terminal val2 = Object.FindObjectOfType<Terminal>(); if ((Object)(object)val2 == (Object)null) { BunkbedRevive.Logger.LogError((object)"[SERVER] Terminal not found! Cannot process revive."); return; } BunkbedRevive.Logger.LogDebug((object)$"[SERVER] Current credits before revive: {val2.groupCredits}"); if (val2.groupCredits < reviveCost) { BunkbedRevive.Logger.LogWarning((object)$"[SERVER] Not enough credits to revive player {id}. Required: {reviveCost}, Available: {val2.groupCredits}"); NotifyClientRpc("Not enough credits", success: false); return; } if (!BunkbedController.CanRevive(id)) { BunkbedRevive.Logger.LogWarning((object)$"[SERVER] Cannot revive player {id} due to revive limits or teleportation rules"); NotifyClientRpc("Can't Revive", success: false); return; } val2.groupCredits -= reviveCost; BunkbedRevive.Logger.LogDebug((object)$"[SERVER] Credits after deduction: {val2.groupCredits}"); BunkbedRevive.Logger.LogDebug((object)"[SERVER] Syncing credits to all clients..."); val2.SyncGroupCreditsServerRpc(val2.groupCredits, val2.numberOfItemsInDropship); string text = "Player"; if ((Object)(object)StartOfRound.Instance != (Object)null && id >= 0 && id < StartOfRound.Instance.allPlayerScripts.Length) { PlayerControllerB val3 = StartOfRound.Instance.allPlayerScripts[id]; if ((Object)(object)val3 != (Object)null) { text = val3.playerUsername; BunkbedRevive.Logger.LogDebug((object)$"[SERVER] Reviving player: {text} (ID: {id})"); } else { BunkbedRevive.Logger.LogWarning((object)$"[SERVER] Player script is null for ID: {id}"); } } else { BunkbedRevive.Logger.LogWarning((object)$"[SERVER] Invalid player ID: {id} or StartOfRound instance not found"); } BunkbedRevive.Logger.LogInfo((object)$"[SERVER] Broadcasting revive for {text} (ID: {id})"); RevivePlayerClientRpc(id, text); } [ClientRpc] public static void RevivePlayerClientRpc(int id, string playerName) { BunkbedRevive.Logger.LogDebug((object)$"[CLIENT] RevivePlayerClientRpc received - PlayerID: {id}, PlayerName: {playerName}"); try { BunkbedController.RevivePlayer(id); HUDManager.Instance.DisplayGlobalNotification(playerName + " has been revived"); BunkbedRevive.Logger.LogDebug((object)("[CLIENT] Successfully revived " + playerName)); } catch (Exception ex) { BunkbedRevive.Logger.LogError((object)$"[CLIENT] Error reviving player {playerName} (ID: {id}): {ex.Message}"); BunkbedRevive.Logger.LogError((object)("[CLIENT] Stack trace: " + ex.StackTrace)); } } [ClientRpc] public static void NotifyClientRpc(string message, bool success) { BunkbedRevive.Logger.LogDebug((object)$"[CLIENT] NotifyClientRpc received - Message: '{message}', Success: {success}"); HUDManager.Instance.DisplayGlobalNotification(message); } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("viviko.BunkbedRevive", "BunkbedRevive", "2.0.0")] public sealed class BunkbedRevive : BaseUnityPlugin { [CompilerGenerated] private static class <>O { public static CanModifyDelegate <0>__CanModifyCallback; } private readonly Harmony harmony = new Harmony("viviko.BunkbedRevive"); public static BunkbedRevive Instance; internal static ManualLogSource Logger { get; private set; } private void Awake() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_003d: 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_0048: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //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_0089: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected O, but got Unknown //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_010b: Expected O, but got Unknown //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Expected O, but got Unknown //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_0141: 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) //IL_014c: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Expected O, but got Unknown //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Expected O, but got Unknown //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Expected O, but got Unknown //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Expected O, but got Unknown //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) //IL_01ce: Expected O, but got Unknown //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Expected O, but got Unknown //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; CustomConfig.Init(); ConfigEntry<CostMethods> reviveCostMethod = CustomConfig.ReviveCostMethod; EnumDropDownOptions val = new EnumDropDownOptions(); ((BaseOptions)val).RequiresRestart = false; EnumDropDownOptions obj = val; object obj2 = <>O.<0>__CanModifyCallback; if (obj2 == null) { CanModifyDelegate val2 = CanModifyCallback; <>O.<0>__CanModifyCallback = val2; obj2 = (object)val2; } ((BaseOptions)obj).CanModifyCallback = (CanModifyDelegate)obj2; LethalConfigManager.AddConfigItem((BaseConfigItem)(object)new EnumDropDownConfigItem<CostMethods>(reviveCostMethod, val)); ConfigEntry<int> reviveCostPercent = CustomConfig.ReviveCostPercent; IntSliderOptions val3 = new IntSliderOptions(); ((BaseOptions)val3).RequiresRestart = false; IntSliderOptions obj3 = val3; object obj4 = <>O.<0>__CanModifyCallback; if (obj4 == null) { CanModifyDelegate val4 = CanModifyCallback; <>O.<0>__CanModifyCallback = val4; obj4 = (object)val4; } ((BaseOptions)obj3).CanModifyCallback = (CanModifyDelegate)obj4; LethalConfigManager.AddConfigItem((BaseConfigItem)new IntSliderConfigItem(reviveCostPercent, val3)); ConfigEntry<int> reviveCostAmount = CustomConfig.ReviveCostAmount; val3 = new IntSliderOptions(); ((BaseOptions)val3).RequiresRestart = false; IntSliderOptions obj5 = val3; object obj6 = <>O.<0>__CanModifyCallback; if (obj6 == null) { CanModifyDelegate val5 = CanModifyCallback; <>O.<0>__CanModifyCallback = val5; obj6 = (object)val5; } ((BaseOptions)obj5).CanModifyCallback = (CanModifyDelegate)obj6; LethalConfigManager.AddConfigItem((BaseConfigItem)new IntSliderConfigItem(reviveCostAmount, val3)); ConfigEntry<ReviveLimits> reviveLimitMethod = CustomConfig.ReviveLimitMethod; val = new EnumDropDownOptions(); ((BaseOptions)val).RequiresRestart = false; EnumDropDownOptions obj7 = val; object obj8 = <>O.<0>__CanModifyCallback; if (obj8 == null) { CanModifyDelegate val6 = CanModifyCallback; <>O.<0>__CanModifyCallback = val6; obj8 = (object)val6; } ((BaseOptions)obj7).CanModifyCallback = (CanModifyDelegate)obj8; LethalConfigManager.AddConfigItem((BaseConfigItem)(object)new EnumDropDownConfigItem<ReviveLimits>(reviveLimitMethod, val)); ConfigEntry<int> reviveLimitPer = CustomConfig.ReviveLimitPer; val3 = new IntSliderOptions(); ((BaseOptions)val3).RequiresRestart = false; IntSliderOptions obj9 = val3; object obj10 = <>O.<0>__CanModifyCallback; if (obj10 == null) { CanModifyDelegate val7 = CanModifyCallback; <>O.<0>__CanModifyCallback = val7; obj10 = (object)val7; } ((BaseOptions)obj9).CanModifyCallback = (CanModifyDelegate)obj10; LethalConfigManager.AddConfigItem((BaseConfigItem)new IntSliderConfigItem(reviveLimitPer, val3)); ConfigEntry<int> reviveLimitOverall = CustomConfig.ReviveLimitOverall; val3 = new IntSliderOptions(); ((BaseOptions)val3).RequiresRestart = false; IntSliderOptions obj11 = val3; object obj12 = <>O.<0>__CanModifyCallback; if (obj12 == null) { CanModifyDelegate val8 = CanModifyCallback; <>O.<0>__CanModifyCallback = val8; obj12 = (object)val8; } ((BaseOptions)obj11).CanModifyCallback = (CanModifyDelegate)obj12; LethalConfigManager.AddConfigItem((BaseConfigItem)new IntSliderConfigItem(reviveLimitOverall, val3)); ConfigEntry<bool> reviveTeleported = CustomConfig.ReviveTeleported; BoolCheckBoxOptions val9 = new BoolCheckBoxOptions(); ((BaseOptions)val9).RequiresRestart = false; object obj13 = <>O.<0>__CanModifyCallback; if (obj13 == null) { CanModifyDelegate val10 = CanModifyCallback; <>O.<0>__CanModifyCallback = val10; obj13 = (object)val10; } ((BaseOptions)val9).CanModifyCallback = (CanModifyDelegate)obj13; LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(reviveTeleported, val9)); ConfigEntry<float> reviveBodyWeight = CustomConfig.ReviveBodyWeight; FloatSliderOptions val11 = new FloatSliderOptions(); ((BaseOptions)val11).RequiresRestart = false; object obj14 = <>O.<0>__CanModifyCallback; if (obj14 == null) { CanModifyDelegate val12 = CanModifyCallback; <>O.<0>__CanModifyCallback = val12; obj14 = (object)val12; } ((BaseOptions)val11).CanModifyCallback = (CanModifyDelegate)obj14; LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(reviveBodyWeight, val11)); harmony.PatchAll(); Logger.LogInfo((object)"Plugin BunkbedRevive v2.0.0 is loaded!"); } private static CanModifyResult CanModifyCallback() { //IL_0034: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)GameNetworkManager.Instance) && GameNetworkManager.Instance.gameHasStarted) { return CanModifyResult.op_Implicit((false, "This setting cant be changed while in a game")); } return CanModifyResult.True(); } } internal static class GeneratedPluginInfo { public const string Identifier = "viviko.BunkbedRevive"; public const string Name = "BunkbedRevive"; public const string Version = "2.0.0"; } } namespace BunkbedRevive.Patches { [HarmonyPatch(typeof(RagdollGrabbableObject))] public class RagdollGrabbableObjectPatch { [HarmonyPatch("Start")] [HarmonyPrefix] private static void StartPatch(RagdollGrabbableObject __instance) { ((GrabbableObject)__instance).itemProperties.weight = NetworkSync.Config.ReviveBodyWeight; } } [HarmonyPatch(typeof(RoundManager))] public class RoundManagerPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePatch() { NetworkSync.Init(); } [HarmonyPatch("OnDestroy")] [HarmonyPostfix] private static void DestroyPatch() { NetworkSync.Cleanup(); } [HarmonyPatch("FinishGeneratingNewLevelClientRpc")] [HarmonyPostfix] private static void FinishGeneratingNewLevelClientRpcPatch() { NetworkSync.FinishSync(hostSynced: false); } } [HarmonyPatch(typeof(ShipTeleporter))] public class ShipTeleporterPatch { [HarmonyPatch("SetPlayerTeleporterId")] [HarmonyPrefix] private static void SetPlayerTeleporterIdPatch(PlayerControllerB playerScript, int teleporterId) { if (teleporterId == 1) { int num = (int)playerScript.playerClientId; BunkbedRevive.Logger.LogDebug((object)$"Player {playerScript.playerUsername} (ID: {num}) was teleported (inverse teleporter)"); if (!BunkbedController.teleportedBodies.Contains(num)) { BunkbedController.teleportedBodies.Add(num); BunkbedRevive.Logger.LogDebug((object)$"Added player {num} to teleported bodies list"); } else { BunkbedRevive.Logger.LogDebug((object)$"Player {num} already in teleported bodies list"); } } } } [HarmonyPatch(typeof(StartOfRound))] public class StartOfRoundPatch { [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch(StartOfRound __instance) { BunkbedRevive.Logger.LogDebug((object)"StartOfRound.Start called - attaching BunkbedController to bunkbeds"); int bunkBedId = __instance.unlockablesList.unlockables.FindIndex((UnlockableItem un) => un.unlockableName.Contains("bunkbeds", StringComparison.CurrentCultureIgnoreCase)); if (bunkBedId == -1) { BunkbedRevive.Logger.LogError((object)"Could not find bunkbeds in unlockables list!"); return; } BunkbedRevive.Logger.LogDebug((object)$"Found bunkbeds at index {bunkBedId}"); PlaceableShipObject val = Object.FindObjectsOfType<PlaceableShipObject>().First((PlaceableShipObject pc) => pc.unlockableID == bunkBedId); if ((Object)(object)val == (Object)null) { BunkbedRevive.Logger.LogError((object)"Could not find bunkbeds PlaceableShipObject!"); return; } ((Component)val).gameObject.AddComponent<BunkbedController>(); BunkbedRevive.Logger.LogInfo((object)"BunkbedController component attached to bunkbeds successfully"); } [HarmonyPatch("EndOfGame")] [HarmonyPrefix] private static void EndOfGamePatch() { BunkbedRevive.Logger.LogDebug((object)"EndOfGame called - resetting revive values"); BunkbedController.ResetValues(); } [HarmonyPatch("openingDoorsSequence")] [HarmonyPrefix] private static void openingDoorsSequencePatch() { BunkbedRevive.Logger.LogDebug((object)"openingDoorsSequence called - resetting revive values"); BunkbedController.ResetValues(); } } } namespace BunkbedRevive.Configuration { internal class CustomConfig { internal static ConfigEntry<CostMethods> ReviveCostMethod; internal static ConfigEntry<int> ReviveCostPercent; internal static ConfigEntry<int> ReviveCostAmount; internal static ConfigEntry<ReviveLimits> ReviveLimitMethod; internal static ConfigEntry<int> ReviveLimitPer; internal static ConfigEntry<int> ReviveLimitOverall; internal static ConfigEntry<bool> ReviveTeleported; internal static ConfigEntry<float> ReviveBodyWeight; internal static void Init() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Expected O, but got Unknown //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown ConfigFile config = ((BaseUnityPlugin)BunkbedRevive.Instance).Config; config.SaveOnConfigSet = false; ReviveCostMethod = config.Bind<CostMethods>("Cost", "Cost Method", CostMethods.PercentOfQuota, "Which method to use for revive cost"); ReviveCostPercent = config.Bind<int>("Cost", "Percent Of Quota", 30, new ConfigDescription("Adjust the percent of quota a revive will cost", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); ReviveCostAmount = config.Bind<int>("Cost", "Set Amount", 50, new ConfigDescription("Adjust the amount a revive will cost", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>())); ReviveLimitMethod = config.Bind<ReviveLimits>("Limits", "Revive Limit Method", ReviveLimits.None, "Which method to use for revive limits"); ReviveLimitPer = config.Bind<int>("Limits", "Revives per Player", 2, new ConfigDescription("Adjust the amount of revives per player", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); ReviveLimitOverall = config.Bind<int>("Limits", "Overall Revives", 4, new ConfigDescription("Adjust the amount of overall revives", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); ReviveTeleported = config.Bind<bool>("Limits", "Can Revive Teleported bodies", true, (ConfigDescription)null); ReviveBodyWeight = config.Bind<float>("Other", "Dead Body Weight", 1.1f, new ConfigDescription("Adjust the weight of dead bodies\n Default is 1.1 as of v56", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); PropertyInfo property = ((object)config).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic); Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)property.GetValue(config, null); dictionary.Clear(); config.Save(); config.SaveOnConfigSet = true; } } public enum CostMethods { PercentOfQuota, SetAmount } public enum ReviveLimits { None, PerPlayer, Overall } internal class NetworkConfig : INetworkSerializable { public CostMethods ReviveCostMethod = CostMethods.PercentOfQuota; public int ReviveCostPercent = 30; public int ReviveCostAmount = 50; public ReviveLimits ReviveLimitMethod = ReviveLimits.None; public int ReviveLimitPer = 2; public int ReviveLimitOverall = 4; public bool ReviveTeleported = false; public float ReviveBodyWeight = 1.1f; public void CopyLocalConfig() { ReviveCostMethod = CustomConfig.ReviveCostMethod.Value; ReviveCostPercent = CustomConfig.ReviveCostPercent.Value; ReviveCostAmount = CustomConfig.ReviveCostAmount.Value; ReviveLimitMethod = CustomConfig.ReviveLimitMethod.Value; ReviveLimitPer = CustomConfig.ReviveLimitPer.Value; ReviveLimitOverall = CustomConfig.ReviveLimitOverall.Value; ReviveTeleported = CustomConfig.ReviveTeleported.Value; ReviveBodyWeight = CustomConfig.ReviveBodyWeight.Value; } public unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter { //IL_000b: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_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_0067: 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_007e: 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_0095: 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_00ac: 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) ((BufferSerializer<CostMethods>*)(&serializer))->SerializeValue<CostMethods>(ref ReviveCostMethod, default(ForEnums)); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref ReviveCostPercent, default(ForPrimitives)); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref ReviveCostAmount, default(ForPrimitives)); ((BufferSerializer<ReviveLimits>*)(&serializer))->SerializeValue<ReviveLimits>(ref ReviveLimitMethod, default(ForEnums)); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref ReviveLimitPer, default(ForPrimitives)); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref ReviveLimitOverall, default(ForPrimitives)); ((BufferSerializer<bool>*)(&serializer))->SerializeValue<bool>(ref ReviveTeleported, default(ForPrimitives)); ((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref ReviveBodyWeight, default(ForPrimitives)); } } internal static class NetworkSync { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__ContactServerRpc; public static Action<ulong> <1>__OnClientDisconnect; public static HandleNamedMessageDelegate <2>__SendConfigClientRpc; } public static NetworkConfig Config; public static bool SyncedWithHost; public static bool FinishedSync; public static List<ulong> HostSyncedList; public static void Init() { //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_0148: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: 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_00fc: Expected O, but got Unknown BunkbedRevive.Logger.LogDebug((object)"NetworkSync.Init called"); Config = new NetworkConfig(); Config.CopyLocalConfig(); SyncedWithHost = false; FinishedSync = false; if (NetworkManager.Singleton.IsHost) { BunkbedRevive.Logger.LogInfo((object)"Setup as host - initializing host-specific handlers"); HostSyncedList = new List<ulong>(); SyncedWithHost = true; object obj = <>O.<0>__ContactServerRpc; if (obj == null) { HandleNamedMessageDelegate val = ContactServerRpc; <>O.<0>__ContactServerRpc = val; obj = (object)val; } SetupMessageHandler("ContactServerRpc", (HandleNamedMessageDelegate)obj); FinishSync(hostSynced: true); NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnect; } else if (NetworkManager.Singleton.IsClient) { BunkbedRevive.Logger.LogInfo((object)"Setup as client - registering with host"); object obj2 = <>O.<2>__SendConfigClientRpc; if (obj2 == null) { HandleNamedMessageDelegate val2 = SendConfigClientRpc; <>O.<2>__SendConfigClientRpc = val2; obj2 = (object)val2; } SetupMessageHandler("SendConfigClientRpc", (HandleNamedMessageDelegate)obj2); string text = "2.0.0".ToString(); BunkbedRevive.Logger.LogDebug((object)("Sending version " + text + " to host")); FastBufferWriter buffer = default(FastBufferWriter); ((FastBufferWriter)(ref buffer))..ctor(text.Length * 2, (Allocator)2, -1); ((FastBufferWriter)(ref buffer)).WriteValue(text, false); SendToHost("ContactServerRpc", buffer, forceSend: true); } } public static void Cleanup() { Config = null; SyncedWithHost = false; HostSyncedList = null; FinishedSync = false; NetworkManager.Singleton.OnClientDisconnectCallback -= OnClientDisconnect; } public static void OnClientDisconnect(ulong clientId) { if (HostSyncedList.Remove(clientId)) { BunkbedRevive.Logger.LogInfo((object)("BunkbedRevive client " + clientId + " disconnected.")); } } public static void SetupMessageHandler(string name, HandleNamedMessageDelegate del) { NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("BunkbedRevive." + name, del); } public static void DeleteMessageHandler(string name) { NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("BunkbedRevive." + name); } public static void SendToClients(string name, IReadOnlyList<ulong> clients, ref FastBufferWriter buffer) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsHost) { BunkbedRevive.Logger.LogError((object)"SendToClients called from client!"); } else { NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("BunkbedRevive." + name, clients, buffer, (NetworkDelivery)3); } } public static void SendToClients(string name, ref FastBufferWriter buffer) { SendToClients(name, HostSyncedList, ref buffer); } public static void SendToHost(string name, FastBufferWriter buffer, bool forceSend = false) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (forceSend || SyncedWithHost) { NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("BunkbedRevive." + name, 0uL, buffer, (NetworkDelivery)3); } } public static void ContactServerRpc(ulong clientId, FastBufferReader reader) { string text = default(string); ((FastBufferReader)(ref reader)).ReadValue(ref text, false); BunkbedRevive.Logger.LogInfo((object)("Client " + clientId + " connected with BunkbedRevive version " + text)); BunkbedRevive.Logger.LogDebug((object)$"Sending config to client {clientId}"); HostSyncedList.Add(clientId); FastBufferWriter buffer = default(FastBufferWriter); ((FastBufferWriter)(ref buffer))..ctor(128, (Allocator)2, 1024); ((FastBufferWriter)(ref buffer)).WriteNetworkSerializable<NetworkConfig>(ref Config); SendToClients("SendConfigClientRpc", new <>z__ReadOnlySingleElementList<ulong>(clientId), ref buffer); } public static void SendConfigClientRpc(ulong clientId, FastBufferReader reader) { ((FastBufferReader)(ref reader)).ReadNetworkSerializableInPlace<NetworkConfig>(ref Config); BunkbedRevive.Logger.LogInfo((object)"Successfully synced config with host"); BunkbedRevive.Logger.LogDebug((object)$"Config values - CostMethod: {Config.ReviveCostMethod}, CostPercent: {Config.ReviveCostPercent}, CostAmount: {Config.ReviveCostAmount}"); BunkbedRevive.Logger.LogDebug((object)$"Config values - LimitMethod: {Config.ReviveLimitMethod}, LimitPer: {Config.ReviveLimitPer}, LimitOverall: {Config.ReviveLimitOverall}"); FinishSync(hostSynced: true); } public static void FinishSync(bool hostSynced) { if (FinishedSync) { BunkbedRevive.Logger.LogDebug((object)"FinishSync called but already finished"); return; } SyncedWithHost = hostSynced; FinishedSync = true; if (!SyncedWithHost) { BunkbedRevive.Logger.LogWarning((object)"Could not sync with host BunkbedRevive instance. Only client-side effects will apply."); } else { BunkbedRevive.Logger.LogInfo((object)"Successfully finished sync with host"); } } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class UnscopedRefAttribute : Attribute { } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SkipLocalsInitAttribute : Attribute { } } [CompilerGenerated] internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T> { object IEnumerator.Current => _item; T IEnumerator<T>.Current => _item; public Enumerator(T item) { _item = item; } bool IEnumerator.MoveNext() { return !_moveNextCalled && (_moveNextCalled = true); } void IEnumerator.Reset() { _moveNextCalled = false; } void IDisposable.Dispose() { } } int ICollection.Count => 1; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => 1; T IReadOnlyList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } } int ICollection<T>.Count => 1; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } public <>z__ReadOnlySingleElementList(T item) { _item = item; } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.CopyTo(Array array, int index) { array.SetValue(_item, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return EqualityComparer<T>.Default.Equals(_item, (T)value); } int IList.IndexOf(object value) { return (!EqualityComparer<T>.Default.Equals(_item, (T)value)) ? (-1) : 0; } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return new Enumerator(_item); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return EqualityComparer<T>.Default.Equals(_item, item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { array[arrayIndex] = _item; } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { return (!EqualityComparer<T>.Default.Equals(_item, item)) ? (-1) : 0; } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } }