Decompiled source of BunkbedRevive v1.0.1

BunkbedRevive.dll

Decompiled 13 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BunkbedRevive")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BunkbedRevive")]
[assembly: AssemblyTitle("BunkbedRevive")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 GetReviveCost()
		{
			return ModConfig.ReviveCost.Value;
		}

		public static bool HasDeadPlayers()
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null)
			{
				return false;
			}
			return StartOfRound.Instance.connectedPlayersAmount + 1 - StartOfRound.Instance.livingPlayers > 0;
		}

		private static void CreateTrigger()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Expected O, but got Unknown
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Expected O, but got Unknown
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Expected O, but got Unknown
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Expected O, but got Unknown
			GameObject val = new GameObject("ReviveBed", new Type[2]
			{
				typeof(BoxCollider),
				typeof(InteractTrigger)
			});
			val.transform.SetParent(((Component)Instance).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;
			interactTrigger = val.GetComponent<InteractTrigger>();
			interactTrigger.twoHandedItemAllowed = true;
			interactTrigger.interactable = true;
			interactTrigger.holdInteraction = false;
			interactTrigger.timeToHold = 0.4f;
			interactTrigger.cooldownTime = 0.25f;
			interactTrigger.timeToHoldSpeedMultiplier = 1f;
			int reviveCost = GetReviveCost();
			interactTrigger.hoverTip = "Revive for " + ((reviveCost <= 0) ? "free" : (reviveCost + " credits")) + " : [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();
			});
		}

		private static void GetIcons()
		{
			StartMatchLever val = Object.FindObjectOfType<StartMatchLever>();
			if ((Object)(object)val != (Object)null)
			{
				defaultIcon = val.triggerScript.hoverIcon;
				disabledIcon = val.triggerScript.disabledHoverIcon;
			}
		}

		private static RagdollGrabbableObject GetHeldBody()
		{
			PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
			if (!localPlayerController.isHoldingObject || (Object)(object)localPlayerController.currentlyHeldObjectServer == (Object)null)
			{
				return null;
			}
			GrabbableObject currentlyHeldObjectServer = localPlayerController.currentlyHeldObjectServer;
			RagdollGrabbableObject val = (RagdollGrabbableObject)(object)((currentlyHeldObjectServer is RagdollGrabbableObject) ? currentlyHeldObjectServer : null);
			if (val != null)
			{
				return val;
			}
			return null;
		}

		private void Awake()
		{
			Instance = this;
			GetIcons();
			CreateTrigger();
		}

		private void Update()
		{
			if (!((Object)(object)StartOfRound.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null))
			{
				bool flag = HasDeadPlayers();
				RagdollGrabbableObject heldBody = GetHeldBody();
				interactTrigger.interactable = flag && (Object)(object)heldBody != (Object)null;
				if ((Object)(object)heldBody != (Object)null)
				{
					string text = (((Object)(object)heldBody.ragdoll != (Object)null) ? heldBody.ragdoll.playerScript.playerUsername : "Player");
					int reviveCost = GetReviveCost();
					interactTrigger.hoverTip = "Revive " + text + " for " + ((reviveCost <= 0) ? "free" : (reviveCost + " credits")) + " : [E]";
				}
			}
		}

		public static void OnInteract()
		{
			PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
			RagdollGrabbableObject heldBody = GetHeldBody();
			if ((Object)(object)heldBody == (Object)null)
			{
				return;
			}
			int reviveCost = GetReviveCost();
			Terminal val = Object.FindObjectOfType<Terminal>();
			if ((Object)(object)val != (Object)null && val.groupCredits < reviveCost)
			{
				BunkbedRevivePlugin.Log.LogMessage((object)"Not enough credits for revive");
				interactTrigger.StopInteraction();
				return;
			}
			if ((Object)(object)val != (Object)null)
			{
				val.groupCredits -= reviveCost;
				val.SyncGroupCreditsServerRpc(val.groupCredits, val.numberOfItemsInDropship);
			}
			BunkbedNetworking.RevivePlayerServerRpc(heldBody.bodyID);
			if ((Object)(object)localPlayerController != (Object)null)
			{
				localPlayerController.DespawnHeldObject();
			}
			string text = (((Object)(object)heldBody.ragdoll != (Object)null) ? heldBody.ragdoll.playerScript.playerUsername : "Player");
			BunkbedRevivePlugin.Log.LogMessage((object)(text + " has been revived"));
		}

		private static void OnStopInteract()
		{
			int reviveCost = GetReviveCost();
			interactTrigger.hoverTip = "Revive for " + ((reviveCost <= 0) ? "free" : (reviveCost + " credits")) + " : [E]";
		}

		public static void RevivePlayer(int playerId)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerId];
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			bool isPlayerDead = val.isPlayerDead;
			val.ResetPlayerBloodObjects(isPlayerDead);
			if (isPlayerDead)
			{
				val.isPlayerDead = false;
				val.isPlayerControlled = true;
				val.isInElevator = true;
				val.isInHangarShipRoom = true;
				val.isInsideFactory = false;
				val.health = 100;
				val.criticallyInjured = false;
				val.bleedingHeavily = false;
				val.setPositionOfDeadPlayer = false;
				val.deadBody = null;
				val.isClimbingLadder = false;
				val.clampLooking = false;
				val.inVehicleAnimation = false;
				val.disableMoveInput = false;
				val.disableLookInput = false;
				val.disableInteract = false;
				val.ResetZAndXRotation();
				((Collider)val.thisController).enabled = true;
				StartOfRound.Instance.SetPlayerObjectExtrapolate(false);
				Vector3 position = StartOfRound.Instance.playerSpawnPositions[playerId].position;
				val.TeleportPlayer(position, false, 0f, false, true);
				if ((Object)(object)val.playerBodyAnimator != (Object)null)
				{
					val.playerBodyAnimator.SetBool("Limp", false);
				}
			}
			StartOfRound instance = StartOfRound.Instance;
			instance.livingPlayers++;
			StartOfRound.Instance.allPlayersDead = false;
			((Renderer)val.thisPlayerModel).enabled = true;
			((Renderer)val.thisPlayerModelLOD1).enabled = true;
			((Renderer)val.thisPlayerModelLOD2).enabled = true;
			if ((Object)(object)val == (Object)(object)GameNetworkManager.Instance.localPlayerController)
			{
				val.health = 100;
				val.hasBegunSpectating = false;
				val.hinderedMultiplier = 1f;
				val.isMovementHindered = 0;
				val.sourcesCausingSinking = 0;
				val.criticallyInjured = false;
				val.bleedingHeavily = false;
				val.isSinking = false;
				val.isUnderwater = false;
				val.sinkingValue = 0f;
				val.statusEffectAudio.Stop();
				val.DisableJetpackControlsLocally();
				HUDManager.Instance.gasHelmetAnimator.SetBool("gasEmitting", false);
				HUDManager.Instance.RemoveSpectateUI();
				HUDManager.Instance.gameOverAnimator.SetTrigger("revive");
				HUDManager.Instance.HideHUD(false);
				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();
				val.reverbPreset = StartOfRound.Instance.shipReverb;
				SoundManager.Instance.earsRingingTimer = 0f;
				SoundManager.Instance.playerVoicePitchTargets[playerId] = 1f;
				SoundManager.Instance.SetPlayerPitch(1f, playerId);
			}
		}
	}
	public static class BunkbedNetworking
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__HandleReviveRequest;

			public static HandleNamedMessageDelegate <1>__HandleReviveBroadcast;
		}

		private const string ReviveServerMsg = "BunkbedRevive.ReviveServer";

		private const string ReviveClientMsg = "BunkbedRevive.ReviveClient";

		public static void Init()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager;
			object obj = <>O.<0>__HandleReviveRequest;
			if (obj == null)
			{
				HandleNamedMessageDelegate val = HandleReviveRequest;
				<>O.<0>__HandleReviveRequest = val;
				obj = (object)val;
			}
			customMessagingManager.RegisterNamedMessageHandler("BunkbedRevive.ReviveServer", (HandleNamedMessageDelegate)obj);
			CustomMessagingManager customMessagingManager2 = NetworkManager.Singleton.CustomMessagingManager;
			object obj2 = <>O.<1>__HandleReviveBroadcast;
			if (obj2 == null)
			{
				HandleNamedMessageDelegate val2 = HandleReviveBroadcast;
				<>O.<1>__HandleReviveBroadcast = val2;
				obj2 = (object)val2;
			}
			customMessagingManager2.RegisterNamedMessageHandler("BunkbedRevive.ReviveClient", (HandleNamedMessageDelegate)obj2);
			BunkbedRevivePlugin.Log.LogInfo((object)"BunkbedRevive networking initialized");
		}

		public static void Cleanup()
		{
			if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.CustomMessagingManager != null)
			{
				NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("BunkbedRevive.ReviveServer");
				NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("BunkbedRevive.ReviveClient");
			}
		}

		public static void RevivePlayerServerRpc(int playerId)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer)
			{
				BroadcastRevive(playerId);
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1);
			((FastBufferWriter)(ref val)).WriteValue<int>(ref playerId, default(ForPrimitives));
			NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("BunkbedRevive.ReviveServer", 0uL, val, (NetworkDelivery)2);
		}

		private static void HandleReviveRequest(ulong clientId, FastBufferReader reader)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			int playerId = default(int);
			((FastBufferReader)(ref reader)).ReadValue<int>(ref playerId, default(ForPrimitives));
			BroadcastRevive(playerId);
		}

		private static void BroadcastRevive(int playerId)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			BunkbedController.RevivePlayer(playerId);
			PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
			if ((Object)(object)localPlayerController != (Object)null && localPlayerController.isHoldingObject && localPlayerController.currentlyHeldObjectServer is RagdollGrabbableObject)
			{
				localPlayerController.DespawnHeldObject();
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1);
			((FastBufferWriter)(ref val)).WriteValue<int>(ref playerId, default(ForPrimitives));
			NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("BunkbedRevive.ReviveClient", (IReadOnlyList<ulong>)GetClientIds(), val, (NetworkDelivery)2);
		}

		private static List<ulong> GetClientIds()
		{
			List<ulong> list = new List<ulong>();
			if (NetworkManager.Singleton.ConnectedClientsList != null)
			{
				foreach (NetworkClient connectedClients in NetworkManager.Singleton.ConnectedClientsList)
				{
					list.Add(connectedClients.ClientId);
				}
			}
			return list;
		}

		private static void HandleReviveBroadcast(ulong clientId, FastBufferReader reader)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			int playerId = default(int);
			((FastBufferReader)(ref reader)).ReadValue<int>(ref playerId, default(ForPrimitives));
			BunkbedController.RevivePlayer(playerId);
		}
	}
	[BepInPlugin("com.user.BunkbedRevive", "BunkbedRevive", "1.0.1")]
	public sealed class BunkbedRevivePlugin : BaseUnityPlugin
	{
		private readonly Harmony harmony = new Harmony("com.user.BunkbedRevive");

		public static BunkbedRevivePlugin Instance;

		public static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Init();
			harmony.PatchAll();
			Log.LogInfo((object)"BunkbedRevive v1.0.1 loaded!");
		}
	}
}
namespace BunkbedRevive.Patches
{
	[HarmonyPatch(typeof(RagdollGrabbableObject))]
	public class RagdollGrabbableObjectPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPrefix]
		private static void StartPatch(RagdollGrabbableObject __instance)
		{
			((GrabbableObject)__instance).itemProperties.weight = ModConfig.BodyWeight.Value;
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	public class StartOfRoundPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPatch(StartOfRound __instance)
		{
			BunkbedNetworking.Init();
			int bunkBedId = __instance.unlockablesList.unlockables.FindIndex((UnlockableItem un) => un.unlockableName.IndexOf("bunkbeds", StringComparison.CurrentCultureIgnoreCase) >= 0);
			if (bunkBedId >= 0)
			{
				PlaceableShipObject val = ((IEnumerable<PlaceableShipObject>)Object.FindObjectsOfType<PlaceableShipObject>()).FirstOrDefault((Func<PlaceableShipObject, bool>)((PlaceableShipObject pc) => pc.unlockableID == bunkBedId));
				if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject.GetComponent<BunkbedController>() == (Object)null)
				{
					((Component)val).gameObject.AddComponent<BunkbedController>();
					BunkbedRevivePlugin.Log.LogInfo((object)"BunkbedController added to bunk beds");
				}
			}
		}

		[HarmonyPatch("openingDoorsSequence")]
		[HarmonyPrefix]
		private static void openingDoorsSequencePatch()
		{
			BunkbedController.Instance = null;
		}

		[HarmonyPatch("EndOfGame")]
		[HarmonyPrefix]
		private static void EndOfGamePatch()
		{
			BunkbedNetworking.Cleanup();
			BunkbedController.Instance = null;
		}
	}
}
namespace BunkbedRevive.Configuration
{
	public static class ModConfig
	{
		public static ConfigEntry<int> ReviveCost;

		public static ConfigEntry<float> BodyWeight;

		public static void Init()
		{
			ConfigFile config = ((BaseUnityPlugin)BunkbedRevivePlugin.Instance).Config;
			ReviveCost = config.Bind<int>("Revive", "Cost", 25, "Number of credits to revive a dead player at the bunk beds");
			BodyWeight = config.Bind<float>("Revive", "Body Weight", 1.1f, "Weight of dead bodies when carried");
		}
	}
}