Decompiled source of BunkbedRevive LegitsFork v2.0.1

BunkbedRevive.dll

Decompiled 3 hours ago
using 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_007a: 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_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Expected O, but got Unknown
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: 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.layer = LayerMask.NameToLayer("InteractableObject");
			val.tag = "InteractTrigger";
			BoxCollider component = val.GetComponent<BoxCollider>();
			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();
	}
}