Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BunkbedRevive v1.0.2
BunkbedRevive.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using 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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("0.0.0.0")] [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; private static float nextReviveTime; private static readonly FieldInfo ThrowingObjectField = typeof(PlayerControllerB).GetField("throwingObject", BindingFlags.Instance | BindingFlags.NonPublic); 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_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Expected O, but got Unknown //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected O, but got Unknown //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: 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.oneHandedItemAllowed = true; 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 val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || !val.isHoldingObject || (Object)(object)val.currentlyHeldObjectServer == (Object)null) { return null; } GrabbableObject currentlyHeldObjectServer = val.currentlyHeldObjectServer; return (RagdollGrabbableObject)(object)((currentlyHeldObjectServer is RagdollGrabbableObject) ? currentlyHeldObjectServer : null); } private static bool IsHeldBodyRevivable(RagdollGrabbableObject body) { if ((Object)(object)body == (Object)null || body.bodyID < 0) { return false; } PlayerControllerB[] array = StartOfRound.Instance?.allPlayerScripts; if (array == null || body.bodyID >= array.Length) { return false; } PlayerControllerB val = array[body.bodyID]; if ((Object)(object)val != (Object)null) { return val.isPlayerDead; } return false; } private void Awake() { Instance = this; GetIcons(); CreateTrigger(); } private void Update() { if (!((Object)(object)interactTrigger == (Object)null) && !((Object)(object)StartOfRound.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)) { RagdollGrabbableObject heldBody = GetHeldBody(); bool flag = (Object)(object)heldBody != (Object)null && IsHeldBodyRevivable(heldBody); interactTrigger.interactable = flag; if (flag) { 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() { if (Time.unscaledTime < nextReviveTime) { return; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; RagdollGrabbableObject heldBody = GetHeldBody(); if ((Object)(object)val == (Object)null || !IsHeldBodyRevivable(heldBody)) { return; } int reviveCost = GetReviveCost(); Terminal val2 = Object.FindObjectOfType<Terminal>(); if ((Object)(object)val2 != (Object)null && val2.groupCredits < reviveCost) { BunkbedRevivePlugin.Log.LogMessage((object)"Not enough credits for revive"); interactTrigger.StopInteraction(); return; } nextReviveTime = Time.unscaledTime + 0.5f; if ((Object)(object)val2 != (Object)null) { val2.groupCredits -= reviveCost; val2.SyncGroupCreditsServerRpc(val2.groupCredits, val2.numberOfItemsInDropship); } int bodyID = heldBody.bodyID; string text = (((Object)(object)heldBody.ragdoll != (Object)null) ? heldBody.ragdoll.playerScript.playerUsername : "Player"); BunkbedNetworking.RevivePlayerServerRpc(bodyID); GrabbableObject currentlyHeldObjectServer = val.currentlyHeldObjectServer; if ((Object)(object)currentlyHeldObjectServer != (Object)null && (Object)(object)((NetworkBehaviour)currentlyHeldObjectServer).NetworkObject != (Object)null && ((NetworkBehaviour)currentlyHeldObjectServer).NetworkObject.IsSpawned) { val.DespawnHeldObject(); } if ((Object)(object)BunkbedRevivePlugin.Instance != (Object)null) { ((MonoBehaviour)BunkbedRevivePlugin.Instance).StartCoroutine(ClearStuckCarryState(val)); } 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]"; } private static IEnumerator ClearStuckCarryState(PlayerControllerB player) { yield return (object)new WaitForSeconds(0.4f); if ((Object)(object)player == (Object)null) { yield break; } GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer; if ((Object)(object)currentlyHeldObjectServer != (Object)null && (Object)(object)((NetworkBehaviour)currentlyHeldObjectServer).NetworkObject != (Object)null && ((NetworkBehaviour)currentlyHeldObjectServer).NetworkObject.IsSpawned) { yield break; } if ((Object)(object)currentlyHeldObjectServer != (Object)null) { for (int i = 0; i < player.ItemSlots.Length; i++) { if ((Object)(object)player.ItemSlots[i] == (Object)(object)currentlyHeldObjectServer) { player.ItemSlots[i] = null; } } if ((Object)(object)player.ItemOnlySlot == (Object)(object)currentlyHeldObjectServer) { player.ItemOnlySlot = null; } } bool flag = ThrowingObjectField != null && (bool)ThrowingObjectField.GetValue(player); player.currentlyHeldObjectServer = null; player.twoHanded = false; player.twoHandedAnimation = false; player.isHoldingObject = false; player.isGrabbingObjectAnimation = false; player.activatingItem = false; player.carryWeight = 1f; ResetThrowingFlag(player); BunkbedRevivePlugin.Log.LogInfo((object)$"Cleared carry state for {player.playerUsername} (throwingObject was {flag})"); if ((Object)(object)HUDManager.Instance != (Object)null) { ((Behaviour)HUDManager.Instance.holdingTwoHandedItem).enabled = false; HUDManager.Instance.ClearControlTips(); } } private static void ResetThrowingFlag(PlayerControllerB player) { if (ThrowingObjectField != null && (bool)ThrowingObjectField.GetValue(player)) { ThrowingObjectField.SetValue(player, false); } } public static void RevivePlayer(int playerId) { //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null || playerId < 0 || playerId >= instance.allPlayerScripts.Length) { return; } PlayerControllerB val = 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.inSpecialInteractAnimation = false; val.freeRotationInInteractAnimation = false; val.disableSyncInAnimation = false; val.inAnimationWithEnemy = null; val.holdingWalkieTalkie = false; val.speakingToWalkieTalkie = false; val.parentedToElevatorLastFrame = false; val.overrideGameOverSpectatePivot = null; val.enemyWaitingForBodyRagdoll = null; val.hasBeenCriticallyInjured = false; ((Behaviour)val.nightVisionRadar).enabled = false; val.disableMoveInput = false; val.disableLookInput = false; val.disableInteract = false; val.ResetZAndXRotation(); ((Collider)val.thisController).enabled = true; instance.SetPlayerObjectExtrapolate(false); Vector3 position = instance.playerSpawnPositions[playerId].position; val.TeleportPlayer(position, false, 0f, false, true); if ((Object)(object)val.playerBodyAnimator != (Object)null) { val.playerBodyAnimator.SetBool("Limp", false); } if (instance.livingPlayers < instance.connectedPlayersAmount + 1) { instance.livingPlayers++; } } instance.allPlayersDead = false; ((Renderer)val.thisPlayerModel).enabled = true; ((Renderer)val.thisPlayerModelLOD1).enabled = true; ((Renderer)val.thisPlayerModelLOD2).enabled = true; if ((Object)(object)val.currentlyHeldObjectServer == (Object)null) { val.twoHanded = false; val.twoHandedAnimation = false; val.isHoldingObject = false; val.isGrabbingObjectAnimation = false; val.activatingItem = false; val.carryWeight = 1f; if (((NetworkBehaviour)val).IsOwner) { ResetThrowingFlag(val); } } 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(); if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.gasHelmetAnimator.SetBool("gasEmitting", false); HUDManager.Instance.RemoveSpectateUI(); HUDManager.Instance.gameOverAnimator.SetTrigger("revive"); HUDManager.Instance.HideHUD(false); HUDManager.Instance.UpdateHealthUI(100, false); ((Behaviour)HUDManager.Instance.audioListenerLowPass).enabled = false; } val.spectatedPlayerScript = null; instance.SetSpectateCameraToGameOverMode(false, val); TimeOfDay.Instance.DisableAllWeather(false); instance.UpdatePlayerVoiceEffects(); val.reverbPreset = instance.shipReverb; if ((Object)(object)SoundManager.Instance != (Object)null) { 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.CustomMessagingManager != null) { CustomMessagingManager customMessagingManager = 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 = 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() { NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.CustomMessagingManager != null) { singleton.CustomMessagingManager.UnregisterNamedMessageHandler("BunkbedRevive.ReviveServer"); singleton.CustomMessagingManager.UnregisterNamedMessageHandler("BunkbedRevive.ReviveClient"); } } public unsafe static void RevivePlayerServerRpc(int playerId) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.CustomMessagingManager == null) { return; } if (singleton.IsServer) { BroadcastRevive(playerId); return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref playerId, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("BunkbedRevive.ReviveServer", 0uL, val, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void HandleReviveRequest(ulong clientId, FastBufferReader reader) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsServer) { int playerId = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref playerId, default(ForPrimitives)); BroadcastRevive(playerId); } } private unsafe static void BroadcastRevive(int playerId) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.CustomMessagingManager == null) { return; } BunkbedController.RevivePlayer(playerId); List<ulong> remoteClientIds = GetRemoteClientIds(); if (remoteClientIds.Count == 0) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref playerId, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("BunkbedRevive.ReviveClient", (IReadOnlyList<ulong>)remoteClientIds, val, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static List<ulong> GetRemoteClientIds() { List<ulong> list = new List<ulong>(); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.ConnectedClientsList == null) { return list; } foreach (NetworkClient connectedClients in singleton.ConnectedClientsList) { if (connectedClients.ClientId != singleton.LocalClientId) { list.Add(connectedClients.ClientId); } } return list; } private static void HandleReviveBroadcast(ulong clientId, FastBufferReader reader) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && !singleton.IsServer) { int playerId = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref playerId, default(ForPrimitives)); BunkbedController.RevivePlayer(playerId); } } } [BepInPlugin("com.user.BunkbedRevive", "BunkbedRevive", "1.0.2")] public sealed class BunkbedRevivePlugin : BaseUnityPlugin { public const string PluginGuid = "com.user.BunkbedRevive"; public const string PluginName = "BunkbedRevive"; public const string PluginVersion = "1.0.2"; 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.2 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 unlockable) => unlockable.unlockableName.IndexOf("bunkbeds", StringComparison.CurrentCultureIgnoreCase) >= 0); if (bunkBedId >= 0) { PlaceableShipObject val = ((IEnumerable<PlaceableShipObject>)Object.FindObjectsOfType<PlaceableShipObject>()).FirstOrDefault((Func<PlaceableShipObject, bool>)((PlaceableShipObject placeable) => placeable.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() { ReviveCost = ((BaseUnityPlugin)BunkbedRevivePlugin.Instance).Config.Bind<int>("Revive", "Cost", 25, "Number of credits to revive a dead player at the bunk beds"); BodyWeight = ((BaseUnityPlugin)BunkbedRevivePlugin.Instance).Config.Bind<float>("Revive", "Body Weight", 1.1f, "Weight of dead bodies when carried"); } } }