Decompiled source of LC ReviveDeadPlayers v1.0.0

LC_ReviveDeadPlayers.dll

Decompiled 9 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LC_ReviveDeadPlayers")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A template for Lethal Company")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LC_ReviveDeadPlayers")]
[assembly: AssemblyTitle("LC_ReviveDeadPlayers")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LC_ReviveDeadPlayers
{
	[BepInPlugin("LC_ReviveDeadPlayers", "LC_ReviveDeadPlayers", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public static ManualLogSource LOGGER;

		public static Plugin Instance { get; private set; }

		public Harmony Harmony { get; private set; }

		public ConfigEntry<int> MaxRevives { get; private set; }

		public ConfigEntry<float> ReviveTimeSeconds { get; private set; }

		public ConfigEntry<bool> ReviveOnBodyCollected { get; private set; }

		public ConfigEntry<bool> ReviveAfterDeathOnTimer { get; private set; }

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Instance = this;
			LOGGER = ((BaseUnityPlugin)this).Logger;
			Harmony = new Harmony("LC_ReviveDeadPlayers");
			MaxRevives = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Max Revives", 3, "The number of times a player can be revived in a single match.");
			ReviveTimeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Revive Timer Seconds", 30f, "The number of times a player can be revived in a single match.");
			ReviveOnBodyCollected = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Revive on body collected", true, "If true the player is revived when their body is collected.");
			ReviveAfterDeathOnTimer = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Revive on timer after death", true, "If true the player is revived based on a timer after they die.");
			if (ReviveOnBodyCollected.Value)
			{
				RevivePlayerSystem.AddReviveCondition(new ReviveOnBodyCollected());
			}
			if (ReviveAfterDeathOnTimer.Value)
			{
				RevivePlayerSystem.AddReviveCondition(new ReviveOnTimer());
			}
			try
			{
				Harmony.PatchAll(typeof(RevivePlayerSystem));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Failed to patch Revive System; '" + ex.Message + "'\n" + ex.StackTrace));
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin LC_ReviveDeadPlayers is loaded!");
		}
	}
	internal interface IReviveCondition
	{
		void Reset();

		bool ShouldRevivePlayer(RevivePlayerMetric metric);

		Vector3 GetRevivePosition(RevivePlayerMetric _)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return StartOfRound.Instance.middleOfShipNode.position;
		}
	}
	internal class RevivePlayerMetric
	{
		public PlayerControllerB Player { get; }

		public int RevivesLeft { get; set; }

		public int ResetRevives { get; set; }

		public RevivePlayerMetric(PlayerControllerB player, int revives)
		{
			Player = player;
			RevivesLeft = revives;
			ResetRevives = revives;
		}

		public void Reset()
		{
			RevivesLeft = ResetRevives;
		}

		public bool CanRevive()
		{
			return RevivesLeft > 0;
		}

		public int GetPlayerIndex()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				throw new NullReferenceException("Start of round is null");
			}
			for (int i = 0; i < instance.allPlayerScripts.Length; i++)
			{
				PlayerControllerB val = instance.allPlayerScripts[i];
				if (val.actualClientId == Player.actualClientId && (val.actualClientId != 0L || val.isHostPlayerObject))
				{
					return i;
				}
			}
			throw new ArgumentException("Unknown Player Index: " + (object)Player);
		}

		public void Revive(Vector3 revive_pos)
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if (!CanRevive())
			{
				return;
			}
			int revivesLeft = RevivesLeft - 1;
			RevivesLeft = revivesLeft;
			StartOfRound instance = StartOfRound.Instance;
			int playerIndex = GetPlayerIndex();
			instance.livingPlayers++;
			Player.isClimbingLadder = false;
			Player.ResetZAndXRotation();
			((Collider)Player.thisController).enabled = true;
			Player.health = 100;
			Player.disableLookInput = false;
			Player.isPlayerDead = false;
			Player.isPlayerControlled = true;
			Player.isInElevator = true;
			Player.isInHangarShipRoom = true;
			Player.isInsideFactory = false;
			Player.wasInElevatorLastFrame = false;
			instance.SetPlayerObjectExtrapolate(false);
			Player.TeleportPlayer(revive_pos, false, 0f, false, true);
			Player.setPositionOfDeadPlayer = false;
			Player.DisablePlayerModel(instance.allPlayerObjects[GetPlayerIndex()], true, true);
			((Behaviour)Player.helmetLight).enabled = false;
			Player.Crouch(false);
			Player.criticallyInjured = false;
			if ((Object)(object)Player.playerBodyAnimator != (Object)null)
			{
				Player.playerBodyAnimator.SetBool("Limp", false);
			}
			Player.bleedingHeavily = false;
			Player.activatingItem = false;
			Player.twoHanded = false;
			Player.inSpecialInteractAnimation = false;
			Player.disableSyncInAnimation = false;
			Player.inAnimationWithEnemy = null;
			Player.holdingWalkieTalkie = false;
			Player.speakingToWalkieTalkie = false;
			Player.isSinking = false;
			Player.isUnderwater = false;
			Player.sinkingValue = 0f;
			Player.statusEffectAudio.Stop();
			Player.DisableJetpackControlsLocally();
			Player.health = 100;
			Player.mapRadarDotAnimator.SetBool("dead", false);
			if (((NetworkBehaviour)Player).IsOwner)
			{
				HUDManager.Instance.gasHelmetAnimator.SetBool("gasEmitting", false);
				Player.hasBegunSpectating = false;
				HUDManager.Instance.RemoveSpectateUI();
				HUDManager.Instance.gameOverAnimator.SetTrigger("revive");
				Player.hinderedMultiplier = 1f;
				Player.isMovementHindered = 0;
				Player.sourcesCausingSinking = 0;
				Player.reverbPreset = instance.shipReverb;
			}
			SoundManager.Instance.earsRingingTimer = 0f;
			Player.voiceMuffledByEnemy = false;
			SoundManager.Instance.playerVoicePitchTargets[playerIndex] = 1f;
			SoundManager.Instance.SetPlayerPitch(1f, playerIndex);
			if ((Object)(object)Player.currentVoiceChatIngameSettings == (Object)null)
			{
				instance.RefreshPlayerVoicePlaybackObjects();
			}
			if ((Object)(object)Player.currentVoiceChatIngameSettings != (Object)null)
			{
				if ((Object)(object)Player.currentVoiceChatIngameSettings.voiceAudio == (Object)null)
				{
					Player.currentVoiceChatIngameSettings.InitializeComponents();
				}
				if (!((Object)(object)Player.currentVoiceChatIngameSettings.voiceAudio == (Object)null))
				{
					((Component)Player.currentVoiceChatIngameSettings.voiceAudio).GetComponent<OccludeAudio>().overridingLowPass = false;
				}
			}
		}
	}
	internal static class RevivePlayerSystem
	{
		private static readonly List<IReviveCondition> s_ReviveActions = new List<IReviveCondition>();

		private static readonly Dictionary<ulong, RevivePlayerMetric> s_PlayerMetrics = new Dictionary<ulong, RevivePlayerMetric>();

		public static void AddReviveCondition(IReviveCondition condition)
		{
			s_ReviveActions.Add(condition);
		}

		public static void ClearReviveActions()
		{
			s_ReviveActions.Clear();
		}

		[HarmonyPatch(typeof(RoundManager), "FinishGeneratingNewLevelClientRpc")]
		[HarmonyPrefix]
		private static void ResetMetricsOnRoundStart()
		{
			Plugin.LOGGER.LogError((object)"Round Manager Finished Level Generation!");
			StartOfRound instance = StartOfRound.Instance;
			s_PlayerMetrics.Clear();
			if ((Object)(object)instance == (Object)null)
			{
				Plugin.LOGGER.LogError((object)"Start of Round is null at 'FinishGeneratingNewLevelClientRpc'");
				return;
			}
			s_ReviveActions.ForEach(delegate(IReviveCondition x)
			{
				x.Reset();
			});
			int value = Plugin.Instance.MaxRevives.Value;
			PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				ulong actualClientId = val.actualClientId;
				string playerUsername = val.playerUsername;
				if (actualClientId == 0L && !val.isHostPlayerObject)
				{
					break;
				}
				Plugin.LOGGER.LogInfo((object)$"Starting Revive Tracking for: '{actualClientId}' => '{playerUsername}'");
				s_PlayerMetrics.Add(val.actualClientId, new RevivePlayerMetric(val, value));
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "Update")]
		[HarmonyPrefix]
		private static void TryRevivePlayers(ref StartOfRound __instance)
		{
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			if (!__instance.shipHasLanded || __instance.inShipPhase)
			{
				return;
			}
			if (s_PlayerMetrics.Count <= 0 || s_ReviveActions.Count <= 0)
			{
				Plugin.LOGGER.LogInfo((object)"No revive actions or players available to revive");
				return;
			}
			foreach (KeyValuePair<ulong, RevivePlayerMetric> s_PlayerMetric in s_PlayerMetrics)
			{
				s_PlayerMetric.Deconstruct(out var key, out var value);
				ulong num = key;
				RevivePlayerMetric revivePlayerMetric = value;
				PlayerControllerB player = revivePlayerMetric.Player;
				if (!player.isPlayerDead || (player.actualClientId == 0L && !player.isHostPlayerObject))
				{
					continue;
				}
				foreach (IReviveCondition s_ReviveAction in s_ReviveActions)
				{
					if (!revivePlayerMetric.CanRevive() || s_ReviveAction.ShouldRevivePlayer(revivePlayerMetric))
					{
						Plugin.LOGGER.LogInfo((object)$"Reviving Player '{num}' => '{player.playerUsername}'");
						revivePlayerMetric.Revive(s_ReviveAction.GetRevivePosition(revivePlayerMetric));
					}
				}
			}
		}
	}
	internal class ReviveOnBodyCollected : IReviveCondition
	{
		public void Reset()
		{
		}

		public bool ShouldRevivePlayer(RevivePlayerMetric metric)
		{
			if (Plugin.Instance.ReviveOnBodyCollected.Value)
			{
				return metric.Player.deadBody.isInShip;
			}
			return false;
		}
	}
	internal class ReviveOnTimer : IReviveCondition
	{
		private readonly Dictionary<ulong, float> m_Timers = new Dictionary<ulong, float>();

		public void Reset()
		{
			m_Timers.Clear();
		}

		public bool ShouldRevivePlayer(RevivePlayerMetric metric)
		{
			if (!Plugin.Instance.ReviveAfterDeathOnTimer.Value || !metric.CanRevive())
			{
				return false;
			}
			ulong actualClientId = metric.Player.actualClientId;
			float value = Plugin.Instance.ReviveTimeSeconds.Value;
			if (!m_Timers.TryGetValue(actualClientId, out var value2))
			{
				m_Timers.Add(actualClientId, 0f);
				return false;
			}
			m_Timers[actualClientId] = value2 + Time.deltaTime;
			value2 = m_Timers[actualClientId];
			if (value2 > value)
			{
				m_Timers[actualClientId] = 0f;
				return true;
			}
			return false;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "LC_ReviveDeadPlayers";

		public const string PLUGIN_NAME = "LC_ReviveDeadPlayers";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}