Decompiled source of DeadManWalking v1.0.2

DeadManWalking.dll

Decompiled 10 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace DeadManWalking;

[BepInPlugin("DeadManWalking", "DeadManWalking", "1.0.2")]
public class Plugin : BaseUnityPlugin
{
	private const string modGUID = "Eltyo.DeadManWalking";

	private const string modName = "DeadManWalking";

	private const string modVersion = "1.0.2";

	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_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Expected O, but got Unknown
		Instance = this;
		LOGGER = Logger.CreateLogSource("Eltyo.DeadManWalking");
		Harmony = new Harmony("DeadManWalking");
		MaxRevives = ((BaseUnityPlugin)Instance).Config.Bind<int>("General", "Max Revives", 3, "The number of times a player can be revived in a single match.");
		ReviveTimeSeconds = ((BaseUnityPlugin)Instance).Config.Bind<float>("General", "Revive Timer Seconds", 30f, "The number of times a player can be revived in a single match.");
		ReviveOnBodyCollected = ((BaseUnityPlugin)Instance).Config.Bind<bool>("General", "Revive on body collected", true, "If true the player is revived when their body is collected.");
		ReviveAfterDeathOnTimer = ((BaseUnityPlugin)Instance).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)
		{
			LOGGER.LogError((object)("Failed to patch Revive System; '" + ex.Message + "'\n" + ex.StackTrace));
		}
		LOGGER.LogInfo((object)"Plugin DeadManWalking is loaded!");
	}

	private void OnDestroy()
	{
		Harmony harmony = Harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}
}
internal abstract class IReviveCondition
{
	public abstract void Reset();

	public abstract bool ShouldRevivePlayer(RevivePlayerMetric metric);
}
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 void Revive(Vector3 revive_pos)
	{
		//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
		if (!CanRevive())
		{
			return;
		}
		int revivesLeft = RevivesLeft - 1;
		RevivesLeft = revivesLeft;
		Player.ResetPlayerBloodObjects(Player.isPlayerDead);
		if (Player.isPlayerDead || Player.isPlayerControlled)
		{
			Player.isClimbingLadder = false;
			Player.ResetZAndXRotation();
			((Collider)Player.thisController).enabled = true;
			Player.health = 100;
			Player.disableLookInput = false;
			if (Player.isPlayerDead)
			{
				Player.isPlayerDead = false;
				Player.isPlayerControlled = true;
				Player.isInElevator = false;
				Player.isInHangarShipRoom = false;
				Player.isInsideFactory = true;
				Player.wasInElevatorLastFrame = false;
				StartOfRound.Instance.SetPlayerObjectExtrapolate(false);
				Player.setPositionOfDeadPlayer = false;
				((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);
				Player.deadBody = null;
				if ((Object)(object)Player == (Object)(object)GameNetworkManager.Instance.localPlayerController)
				{
					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;
					HUDManager.Instance.HideHUD(false);
				}
			}
			SoundManager.Instance.earsRingingTimer = 0f;
			Player.voiceMuffledByEnemy = false;
			if ((Object)(object)Player.currentVoiceChatIngameSettings == (Object)null)
			{
				StartOfRound.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)
				{
					return;
				}
				((Component)Player.currentVoiceChatIngameSettings.voiceAudio).GetComponent<OccludeAudio>().overridingLowPass = false;
			}
		}
		StartOfRound instance = StartOfRound.Instance;
		instance.livingPlayers++;
		if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)(object)Player)
		{
			Player.bleedingHeavily = false;
			Player.criticallyInjured = false;
			Player.playerBodyAnimator.SetBool("Limp", false);
			Player.health = 100;
			HUDManager.Instance.UpdateHealthUI(100, false);
			Player.spectatedPlayerScript = null;
			((Behaviour)HUDManager.Instance.audioListenerLowPass).enabled = false;
			StartOfRound.Instance.SetSpectateCameraToGameOverMode(false, Player);
			TimeOfDay.Instance.DisableAllWeather(false);
			StartOfRound.Instance.UpdatePlayerVoiceEffects();
			((Renderer)Player.thisPlayerModel).enabled = true;
		}
		else
		{
			((Renderer)Player.thisPlayerModel).enabled = true;
			((Renderer)Player.thisPlayerModelLOD1).enabled = true;
			((Renderer)Player.thisPlayerModelLOD2).enabled = true;
		}
		Player.TeleportPlayer(revive_pos, false, 0f, false, true);
	}
}
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;
		PlayerControllerB[] array = allPlayerScripts;
		foreach (PlayerControllerB val in array)
		{
			ulong actualClientId = val.actualClientId;
			string playerUsername = val.playerUsername;
			if (actualClientId != 0L || val.isHostPlayerObject)
			{
				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_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: 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)
		{
			ulong key = s_PlayerMetric.Key;
			RevivePlayerMetric value = s_PlayerMetric.Value;
			PlayerControllerB player = value.Player;
			if (!player.isPlayerDead || (player.actualClientId == 0L && !player.isHostPlayerObject))
			{
				continue;
			}
			foreach (IReviveCondition s_ReviveAction in s_ReviveActions)
			{
				if (value.CanRevive() && s_ReviveAction.ShouldRevivePlayer(value))
				{
					value.Revive(StartOfRound.Instance.middleOfShipNode.position + new Vector3(0f, -1.5f, 0f));
				}
			}
		}
	}
}
internal class ReviveOnBodyCollected : IReviveCondition
{
	public override void Reset()
	{
	}

	public override 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 override void Reset()
	{
		m_Timers.Clear();
	}

	public override 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 = "DeadManWalking";

	public const string PLUGIN_NAME = "DeadManWalking";

	public const string PLUGIN_VERSION = "1.0.2";
}