Decompiled source of Unfaded v1.0.8

Unfaded.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unfaded.Configuration;
using Unfaded.Core;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Unfaded")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.8.0")]
[assembly: AssemblyInformationalVersion("1.0.8+7e46e9bf7956adb6ebdb15af98c735f0a1f80358")]
[assembly: AssemblyProduct("Unfaded")]
[assembly: AssemblyTitle("Unfaded")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.8.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 Unfaded
{
	[BepInPlugin("djc.valheim.unfaded", "Unfaded", "1.0.8")]
	public sealed class UnfadedPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "djc.valheim.unfaded";

		public const string PluginName = "Unfaded";

		public const string PluginVersion = "1.0.8";

		private Harmony? _harmony;

		public static UnfadedPlugin? Instance { get; private set; }

		private void Awake()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			PluginConfig.BindConfig(((BaseUnityPlugin)this).Config);
			_harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "djc.valheim.unfaded");
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} v{1} loaded successfully. Blackout: {2}, Respawn: {3}s ([{4}]), KillerCam: {5}, FreeFly: {6}, SlowMo: {7}, RecordHotkey: {8}.", "Unfaded", "1.0.8", PluginConfig.DisableDeathFade.Value ? "Disabled" : "Enabled", PluginConfig.RespawnDelay.Value, PluginConfig.ManualRespawnKey.Value, PluginConfig.EnableKillerCam.Value, PluginConfig.EnableFreeFly.Value, PluginConfig.EnableSlowMotion.Value, PluginConfig.RecordHotkey?.Value));
		}

		private void Update()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (PluginConfig.EnableRecordingHotkey == null || !PluginConfig.EnableRecordingHotkey.Value || PluginConfig.RecordHotkey == null || !Input.GetKeyDown(PluginConfig.RecordHotkey.Value))
			{
				return;
			}
			if (RecordingManager.IsRecording)
			{
				RecordingManager.StopRecording(out string message);
				((BaseUnityPlugin)this).Logger.LogInfo((object)message);
				if ((Object)(object)Console.instance != (Object)null)
				{
					((Terminal)Console.instance).AddString(message);
				}
			}
			else
			{
				RecordingManager.StartRecording(out string message2);
				((BaseUnityPlugin)this).Logger.LogInfo((object)message2);
				if ((Object)(object)Console.instance != (Object)null)
				{
					((Terminal)Console.instance).AddString(message2);
				}
			}
		}

		private void OnDestroy()
		{
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Instance = null;
		}
	}
}
namespace Unfaded.Patches
{
	[HarmonyPatch(typeof(GameCamera))]
	public static class GameCameraDeathPatch
	{
		private static bool s_wasDead = false;

		private static float s_orbitYaw = 0f;

		private static float s_orbitPitch = 25f;

		[HarmonyPostfix]
		[HarmonyPatch("UpdateCamera")]
		public static void UpdateCameraPostfix(GameCamera __instance, float dt)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			bool flag = (Object)(object)localPlayer != (Object)null && ((Character)localPlayer).IsDead();
			bool flag2 = DeathStateManager.IsTestSimActive && Time.time < DeathStateManager.TestSimEndTime;
			if (!flag && !flag2)
			{
				if (s_wasDead)
				{
					DeathStateManager.ResetOnRespawn();
					s_wasDead = false;
				}
			}
			else
			{
				if (!PluginConfig.IsModEnabled.Value)
				{
					return;
				}
				HandleModeSwitchKeys();
				if (DeathStateManager.CurrentMode == DeathCameraMode.FreeFly && PluginConfig.EnableFreeFly.Value)
				{
					UpdateFreeFlyMode(__instance, dt);
					return;
				}
				Vector3 val = Vector3.zero;
				if (DeathStateManager.CurrentMode == DeathCameraMode.KillerFocus && PluginConfig.EnableKillerCam.Value)
				{
					if ((Object)(object)DeathStateManager.LastKiller != (Object)null && (Object)(object)((Component)DeathStateManager.LastKiller).gameObject != (Object)null)
					{
						val = DeathStateManager.LastKiller.GetCenterPoint();
					}
					else
					{
						DeathStateManager.CurrentMode = DeathCameraMode.RagdollOrbit;
					}
				}
				if (DeathStateManager.CurrentMode == DeathCameraMode.RagdollOrbit)
				{
					if (flag)
					{
						Ragdoll ragdoll = localPlayer.GetRagdoll();
						val = ((!((Object)(object)ragdoll != (Object)null)) ? (((Component)localPlayer).transform.position + Vector3.up * 1.5f) : ragdoll.GetAverageBodyPosition());
					}
					else if (flag2)
					{
						val = ((Component)localPlayer).transform.position + Vector3.up * 1.5f;
					}
				}
				if (PluginConfig.EnableCameraOrbit.Value)
				{
					if (!s_wasDead)
					{
						s_wasDead = true;
						s_orbitYaw = ((Component)__instance).transform.eulerAngles.y;
						s_orbitPitch = Mathf.Clamp(((Component)__instance).transform.eulerAngles.x, 5f, 75f);
					}
					Vector2 mouseDelta = ZInput.GetMouseDelta();
					s_orbitYaw += mouseDelta.x * PluginConfig.CameraOrbitSensitivity.Value;
					s_orbitPitch -= mouseDelta.y * PluginConfig.CameraOrbitSensitivity.Value;
					s_orbitPitch = Mathf.Clamp(s_orbitPitch, -10f, 85f);
					Vector3 val2 = -(Quaternion.Euler(s_orbitPitch, s_orbitYaw, 0f) * Vector3.forward);
					float num = Mathf.Clamp(__instance.m_distance, __instance.m_minDistance, __instance.m_maxDistance);
					Vector3 position = val + val2 * num;
					RaycastHit val3 = default(RaycastHit);
					if (Physics.SphereCast(val, 0.25f, val2, ref val3, num, LayerMask.op_Implicit(__instance.m_blockCameraMask)))
					{
						position = val + val2 * Mathf.Max(0.5f, ((RaycastHit)(ref val3)).distance - 0.15f);
					}
					((Component)__instance).transform.position = position;
					((Component)__instance).transform.LookAt(val);
				}
				else
				{
					((Component)__instance).transform.LookAt(val);
				}
			}
		}

		private static void HandleModeSwitchKeys()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (PluginConfig.EnableFreeFly.Value && Input.GetKeyDown(PluginConfig.FreeFlyKey.Value))
			{
				if (DeathStateManager.CurrentMode == DeathCameraMode.FreeFly)
				{
					DeathStateManager.CurrentMode = DeathCameraMode.RagdollOrbit;
					Player localPlayer = Player.m_localPlayer;
					if (localPlayer != null)
					{
						((Character)localPlayer).Message((MessageType)1, "Spectator: Ragdoll Orbit", 0, (Sprite)null, false);
					}
				}
				else
				{
					DeathStateManager.CurrentMode = DeathCameraMode.FreeFly;
					Player localPlayer2 = Player.m_localPlayer;
					if (localPlayer2 != null)
					{
						((Character)localPlayer2).Message((MessageType)1, "Spectator: Free-Fly Drone (WASD to Move)", 0, (Sprite)null, false);
					}
				}
			}
			if (!PluginConfig.EnableKillerCam.Value || !Input.GetKeyDown(PluginConfig.KillerCamKey.Value))
			{
				return;
			}
			if (DeathStateManager.CurrentMode == DeathCameraMode.KillerFocus)
			{
				DeathStateManager.CurrentMode = DeathCameraMode.RagdollOrbit;
				Player localPlayer3 = Player.m_localPlayer;
				if (localPlayer3 != null)
				{
					((Character)localPlayer3).Message((MessageType)1, "Spectator: Ragdoll Orbit", 0, (Sprite)null, false);
				}
			}
			else if ((Object)(object)DeathStateManager.LastKiller != (Object)null)
			{
				DeathStateManager.CurrentMode = DeathCameraMode.KillerFocus;
				Player localPlayer4 = Player.m_localPlayer;
				if (localPlayer4 != null)
				{
					((Character)localPlayer4).Message((MessageType)1, "Spectator: Killer Focus (" + DeathStateManager.LastKillerName + ")", 0, (Sprite)null, false);
				}
			}
			else
			{
				Player localPlayer5 = Player.m_localPlayer;
				if (localPlayer5 != null)
				{
					((Character)localPlayer5).Message((MessageType)1, "No enemy killer to spectate (environmental death)", 0, (Sprite)null, false);
				}
			}
		}

		private static void UpdateFreeFlyMode(GameCamera cam, float dt)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//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_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			Vector2 mouseDelta = ZInput.GetMouseDelta();
			DeathStateManager.FreeFlyYaw += mouseDelta.x * PluginConfig.CameraOrbitSensitivity.Value;
			DeathStateManager.FreeFlyPitch -= mouseDelta.y * PluginConfig.CameraOrbitSensitivity.Value;
			DeathStateManager.FreeFlyPitch = Mathf.Clamp(DeathStateManager.FreeFlyPitch, -85f, 85f);
			Quaternion val = Quaternion.Euler(DeathStateManager.FreeFlyPitch, DeathStateManager.FreeFlyYaw, 0f);
			Vector3 val2 = Vector3.zero;
			if (Input.GetKey((KeyCode)119))
			{
				val2 += val * Vector3.forward;
			}
			if (Input.GetKey((KeyCode)115))
			{
				val2 -= val * Vector3.forward;
			}
			if (Input.GetKey((KeyCode)100))
			{
				val2 += val * Vector3.right;
			}
			if (Input.GetKey((KeyCode)97))
			{
				val2 -= val * Vector3.right;
			}
			if (Input.GetKey((KeyCode)32))
			{
				val2 += Vector3.up;
			}
			if (Input.GetKey((KeyCode)306))
			{
				val2 -= Vector3.up;
			}
			float num = PluginConfig.FreeFlySpeed.Value;
			if (Input.GetKey((KeyCode)304))
			{
				num *= 2f;
			}
			Vector3 val3 = DeathStateManager.FreeFlyPosition + val2 * num * dt;
			Vector3 deathPosition = DeathStateManager.DeathPosition;
			if (deathPosition != Vector3.zero)
			{
				float value = PluginConfig.FreeFlyRadius.Value;
				Vector3 val4 = val3 - deathPosition;
				if (((Vector3)(ref val4)).magnitude > value)
				{
					val3 = deathPosition + ((Vector3)(ref val4)).normalized * value;
				}
			}
			DeathStateManager.FreeFlyPosition = val3;
			((Component)cam).transform.position = val3;
			((Component)cam).transform.rotation = val;
		}
	}
	public static class GameRespawnPatch
	{
		[HarmonyPatch(typeof(Game), "RequestRespawn")]
		public static class RequestRespawnPatch
		{
			[HarmonyPrefix]
			public static void Prefix(ref float delay, bool afterDeath)
			{
				if (PluginConfig.IsModEnabled.Value && afterDeath && delay > 0f)
				{
					delay = Mathf.Max(0f, PluginConfig.RespawnDelay.Value);
				}
			}
		}

		[HarmonyPatch(typeof(Hud), "Update")]
		public static class HudUpdateInputPatch
		{
			private static float s_lastPromptTime;

			[HarmonyPostfix]
			public static void Postfix(Hud __instance)
			{
				//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				if (!PluginConfig.IsModEnabled.Value)
				{
					return;
				}
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && ((Character)localPlayer).IsDead() && !((Object)(object)Game.instance == (Object)null) && !Game.instance.WaitingForRespawn() && !Game.instance.IsShuttingDown())
				{
					if (PluginConfig.ShowRespawnPrompt.Value && Time.time - s_lastPromptTime > 4.5f)
					{
						s_lastPromptTime = Time.time;
						string arg = ((object)PluginConfig.ManualRespawnKey.Value/*cast due to .constrained prefix*/).ToString();
						string text = string.Format(PluginConfig.RespawnPromptText.Value, arg);
						((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
					}
					if (PluginConfig.EnableManualRespawn.Value && Input.GetKeyDown(PluginConfig.ManualRespawnKey.Value))
					{
						DeathStateManager.ResetOnRespawn();
						Game.instance.RequestRespawn(0f, true);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "OnDeath")]
		public static class PlayerOnDeathPatch
		{
			[HarmonyPostfix]
			public static void Postfix(Player __instance)
			{
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: Unknown result type (might be due to invalid IL or missing references)
				if (PluginConfig.IsModEnabled.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					DeathStateManager.RecordLethalHit(__instance, ((Character)__instance).m_lastHit);
					if (PluginConfig.EnableSlowMotion.Value && (Object)(object)UnfadedPlugin.Instance != (Object)null)
					{
						((MonoBehaviour)UnfadedPlugin.Instance).StartCoroutine(DeathStateManager.SlowMotionRoutine((MonoBehaviour)(object)UnfadedPlugin.Instance));
					}
					if (PluginConfig.EnableDeathRecap.Value)
					{
						string text = DeathStateManager.FormatDeathRecap();
						((Character)__instance).Message((MessageType)2, text, 0, (Sprite)null, false);
					}
					if (PluginConfig.ShowRespawnPrompt.Value)
					{
						string arg = ((object)PluginConfig.ManualRespawnKey.Value/*cast due to .constrained prefix*/).ToString();
						string text2 = string.Format(PluginConfig.RespawnPromptText.Value, arg);
						((Character)__instance).Message((MessageType)1, text2, 0, (Sprite)null, false);
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(Hud))]
	public static class HudBlackScreenPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch("UpdateBlackScreen")]
		public static bool UpdateBlackScreenPrefix(Hud __instance, Player player, float dt)
		{
			if (!PluginConfig.IsModEnabled.Value || !PluginConfig.DisableDeathFade.Value)
			{
				return true;
			}
			if ((Object)(object)player != (Object)null && ((Character)player).IsDead() && ((Object)(object)Game.instance == (Object)null || !Game.instance.WaitingForRespawn()))
			{
				if ((Object)(object)Game.instance != (Object)null && Game.instance.IsShuttingDown())
				{
					return true;
				}
				if (player.IsSleeping() || ((Character)player).IsTeleporting())
				{
					return true;
				}
				if ((Object)(object)__instance.m_loadingScreen != (Object)null)
				{
					__instance.m_loadingScreen.alpha = 0f;
					((Component)__instance.m_loadingScreen).gameObject.SetActive(false);
				}
				if ((Object)(object)__instance.m_loadingProgress != (Object)null)
				{
					__instance.m_loadingProgress.SetActive(false);
				}
				if ((Object)(object)__instance.m_sleepingProgress != (Object)null)
				{
					__instance.m_sleepingProgress.SetActive(false);
				}
				if ((Object)(object)__instance.m_teleportingProgress != (Object)null)
				{
					__instance.m_teleportingProgress.SetActive(false);
				}
				return false;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch("GetFadeDuration")]
		public static bool GetFadeDurationPrefix(Player player, ref float __result)
		{
			if (!PluginConfig.IsModEnabled.Value || (Object)(object)player == (Object)null || !((Character)player).IsDead())
			{
				return true;
			}
			if (PluginConfig.DisableDeathFade.Value)
			{
				__result = 999999f;
				return false;
			}
			if (PluginConfig.CustomDeathFadeDuration.Value > 0f)
			{
				__result = Mathf.Max(0.01f, PluginConfig.CustomDeathFadeDuration.Value);
				return false;
			}
			return true;
		}
	}
}
namespace Unfaded.Core
{
	public enum DeathCameraMode
	{
		RagdollOrbit,
		KillerFocus,
		FreeFly
	}
	public static class DeathStateManager
	{
		public static DeathCameraMode CurrentMode { get; set; } = DeathCameraMode.RagdollOrbit;

		public static Character? LastKiller { get; set; }

		public static string LastKillerName { get; set; } = "";

		public static int LastKillerStars { get; set; } = 0;

		public static float LastLethalDamage { get; set; } = 0f;

		public static string LastDamageType { get; set; } = "";

		public static Vector3 DeathPosition { get; set; } = Vector3.zero;

		public static Vector3 FreeFlyPosition { get; set; } = Vector3.zero;

		public static float FreeFlyYaw { get; set; } = 0f;

		public static float FreeFlyPitch { get; set; } = 20f;

		public static bool IsTestSimActive { get; set; } = false;

		public static float TestSimEndTime { get; set; } = 0f;

		public static void RecordLethalHit(Player player, HitData hit)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Invalid comparison between Unknown and I4
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Invalid comparison between Unknown and I4
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Invalid comparison between Unknown and I4
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Invalid comparison between Unknown and I4
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Invalid comparison between Unknown and I4
			CurrentMode = DeathCameraMode.RagdollOrbit;
			DeathPosition = ((Component)player).transform.position;
			FreeFlyPosition = ((Component)player).transform.position + Vector3.up * 3f - ((Component)player).transform.forward * 4f;
			FreeFlyYaw = ((Component)player).transform.eulerAngles.y;
			FreeFlyPitch = 25f;
			LastLethalDamage = hit.GetTotalDamage();
			Character attacker = hit.GetAttacker();
			if ((Object)(object)attacker != (Object)null)
			{
				LastKiller = attacker;
				LastKillerName = attacker.GetHoverName();
				if (string.IsNullOrEmpty(LastKillerName))
				{
					LastKillerName = attacker.m_name;
				}
				LastKillerStars = attacker.GetLevel() - 1;
			}
			else
			{
				LastKiller = null;
				LastKillerStars = 0;
				HitType hitType = hit.m_hitType;
				if ((int)hitType <= 8)
				{
					if ((int)hitType != 3)
					{
						if ((int)hitType != 8)
						{
							goto IL_0122;
						}
						LastKillerName = "Drowning / Water";
					}
					else
					{
						LastKillerName = "Gravity / Fall Damage";
					}
				}
				else if ((int)hitType != 9)
				{
					if ((int)hitType != 13)
					{
						goto IL_0122;
					}
					LastKillerName = "Falling Tree / Timber";
				}
				else
				{
					LastKillerName = "Smoke Inhalation";
				}
			}
			goto IL_012c;
			IL_0122:
			LastKillerName = "The Harsh Environment";
			goto IL_012c;
			IL_012c:
			if (hit.m_damage.m_fire > 0f)
			{
				LastDamageType = "Fire";
			}
			else if (hit.m_damage.m_frost > 0f)
			{
				LastDamageType = "Frost";
			}
			else if (hit.m_damage.m_lightning > 0f)
			{
				LastDamageType = "Lightning";
			}
			else if (hit.m_damage.m_poison > 0f)
			{
				LastDamageType = "Poison";
			}
			else if (hit.m_damage.m_spirit > 0f)
			{
				LastDamageType = "Spirit";
			}
			else if (hit.m_damage.m_slash > 0f)
			{
				LastDamageType = "Slash";
			}
			else if (hit.m_damage.m_pierce > 0f)
			{
				LastDamageType = "Pierce";
			}
			else if (hit.m_damage.m_blunt > 0f)
			{
				LastDamageType = "Blunt";
			}
			else
			{
				LastDamageType = "Physical";
			}
		}

		public static string FormatDeathRecap()
		{
			string text = ((LastKillerStars > 0) ? $" ({LastKillerStars}★)" : "");
			string text2 = ((LastLethalDamage > 0f) ? $" [{LastLethalDamage:F0} {LastDamageType}]" : "");
			return "\ud83d\udc80 Slain by: <color=#FF6B6B><b>" + LastKillerName + text + "</b></color>" + text2;
		}

		public static IEnumerator SlowMotionRoutine(MonoBehaviour runner)
		{
			if (!((Object)(object)ZNet.instance != (Object)null) || ZNet.instance.IsServer() || ZNet.instance.GetNrOfPlayers() <= 1)
			{
				float targetScale = Mathf.Clamp(PluginConfig.SlowMotionScale.Value, 0.05f, 1f);
				float duration = Mathf.Max(0.1f, PluginConfig.SlowMotionDuration.Value);
				Time.timeScale = targetScale;
				Time.fixedDeltaTime = 0.02f * targetScale;
				float elapsed = 0f;
				while (elapsed < duration)
				{
					elapsed += Time.unscaledDeltaTime;
					yield return null;
				}
				float restoreDuration = 0.5f;
				float restoreElapsed = 0f;
				while (restoreElapsed < restoreDuration)
				{
					restoreElapsed += Time.unscaledDeltaTime;
					float num = restoreElapsed / restoreDuration;
					Time.timeScale = Mathf.Lerp(targetScale, 1f, num);
					Time.fixedDeltaTime = 0.02f * Time.timeScale;
					yield return null;
				}
				Time.timeScale = 1f;
				Time.fixedDeltaTime = 0.02f;
			}
		}

		public static void ResetOnRespawn()
		{
			Time.timeScale = 1f;
			Time.fixedDeltaTime = 0.02f;
			CurrentMode = DeathCameraMode.RagdollOrbit;
			LastKiller = null;
			IsTestSimActive = false;
		}
	}
	public static class RecordingManager
	{
		private const byte VK_LWIN = 91;

		private const byte VK_LMENU = 18;

		private const byte VK_R = 82;

		private const uint KEYEVENTF_KEYUP = 2u;

		public static bool IsRecording { get; private set; }

		public static DateTime RecordingStartTime { get; private set; }

		public static DateTime RecordingStopTime { get; private set; }

		public static string LastRecordedFile { get; private set; } = string.Empty;

		public static string LastRecordedDirectory { get; private set; } = string.Empty;

		public static double LastDurationSeconds { get; private set; }

		public static long LastFileSizeBytes { get; private set; }

		[DllImport("user32.dll")]
		private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

		public static string GetActiveOutputDirectory()
		{
			string text = PluginConfig.RecordOutputDirectory?.Value;
			if (!string.IsNullOrWhiteSpace(text) && Directory.Exists(text))
			{
				return text;
			}
			string text2 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyVideos), "Captures");
			if (Directory.Exists(text2))
			{
				return text2;
			}
			string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos);
			if (Directory.Exists(folderPath))
			{
				return folderPath;
			}
			if (Directory.Exists("E:\\BF6-Highlights\\raw"))
			{
				return "E:\\BF6-Highlights\\raw";
			}
			return Directory.GetCurrentDirectory();
		}

		public static List<string> GetCandidateDirectories()
		{
			List<string> list = new List<string>();
			string text = PluginConfig.RecordOutputDirectory?.Value;
			if (!string.IsNullOrWhiteSpace(text) && Directory.Exists(text))
			{
				list.Add(text);
			}
			string text2 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyVideos), "Captures");
			if (Directory.Exists(text2) && !list.Contains(text2))
			{
				list.Add(text2);
			}
			string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos);
			if (Directory.Exists(folderPath) && !list.Contains(folderPath))
			{
				list.Add(folderPath);
			}
			if (Directory.Exists("E:\\BF6-Highlights\\raw") && !list.Contains("E:\\BF6-Highlights\\raw"))
			{
				list.Add("E:\\BF6-Highlights\\raw");
			}
			return list;
		}

		public static void TriggerHardwareCaptureShortcut()
		{
			ConfigEntry<bool> enableGameBarTrigger = PluginConfig.EnableGameBarTrigger;
			if (enableGameBarTrigger == null || !enableGameBarTrigger.Value)
			{
				return;
			}
			try
			{
				keybd_event(91, 0, 0u, UIntPtr.Zero);
				keybd_event(18, 0, 0u, UIntPtr.Zero);
				keybd_event(82, 0, 0u, UIntPtr.Zero);
				keybd_event(82, 0, 2u, UIntPtr.Zero);
				keybd_event(18, 0, 2u, UIntPtr.Zero);
				keybd_event(91, 0, 2u, UIntPtr.Zero);
			}
			catch (Exception ex)
			{
				ZLog.LogWarning((object)("[Unfaded.RecordingManager] Failed to dispatch capture shortcut: " + ex.Message));
			}
		}

		public static bool StartRecording(out string message)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if (IsRecording)
			{
				double totalSeconds = (DateTime.Now - RecordingStartTime).TotalSeconds;
				message = $"<color=#FFAA00>[Record]</color> Already recording since <b>{RecordingStartTime:HH:mm:ss}</b> ({totalSeconds:F0}s elapsed).\nType <color=#00FFAA>'record stop'</color> to complete.";
				return false;
			}
			RecordingStartTime = DateTime.Now;
			IsRecording = true;
			TriggerHardwareCaptureShortcut();
			string activeOutputDirectory = GetActiveOutputDirectory();
			ShowHudMessage($"<color=#FF4444>\ud83d\udd34 REC</color> Started at {RecordingStartTime:HH:mm:ss}");
			message = $"<color=#00FFAA>[Record]</color> <b>RECORDING STARTED</b> at <b>{RecordingStartTime:HH:mm:ss}</b>\n" + " • Target Directory : <b>" + activeOutputDirectory + "</b>\n • Hotkey Dispatched : <b>[Win + Alt + R]</b> (Windows Game Bar / OBS)\n" + $" • Finish Command   : Type <color=#00FFAA>'record stop'</color> (or press {PluginConfig.RecordHotkey?.Value})";
			return true;
		}

		public static bool StopRecording(out string message)
		{
			if (!IsRecording)
			{
				message = "<color=#FFAA00>[Record]</color> No active recording in progress. Type <color=#00FFAA>'record start'</color> to begin.";
				return false;
			}
			RecordingStopTime = DateTime.Now;
			IsRecording = false;
			TriggerHardwareCaptureShortcut();
			double num = (LastDurationSeconds = (RecordingStopTime - RecordingStartTime).TotalSeconds);
			FileInfo fileInfo = FindNewestVideoFile(RecordingStartTime.AddSeconds(-3.0));
			if (fileInfo != null)
			{
				LastRecordedFile = fileInfo.FullName;
				LastRecordedDirectory = fileInfo.DirectoryName ?? string.Empty;
				LastFileSizeBytes = fileInfo.Length;
				double num2 = (double)LastFileSizeBytes / 1048576.0;
				string arg = FormatDuration(num);
				ShowHudMessage($"<color=#00FFAA>⏹ REC SAVED</color> [{arg}] ({num2:F1} MB)");
				message = "==================================================\n   <b><color=#00FFAA>Unfaded :: Recording Completed & Saved</color></b>\n==================================================\n" + $" • Start Time : <b>{RecordingStartTime:HH:mm:ss}</b>\n" + $" • Stop Time  : <b>{RecordingStopTime:HH:mm:ss}</b>\n" + $" • Duration   : <b>{arg}</b> ({num:F1}s)\n" + " • File Name  : <b><color=#00FFAA>" + fileInfo.Name + "</color></b>\n" + $" • File Size  : <b>{num2:F2} MB</b>\n" + " • Directory  : <b>" + LastRecordedDirectory + "</b>\n==================================================";
				return true;
			}
			string activeOutputDirectory = GetActiveOutputDirectory();
			string text = FormatDuration(num);
			ShowHudMessage("<color=#00FFAA>⏹ REC STOPPED</color> [" + text + "]");
			message = "==================================================\n   <b><color=#00FFAA>Unfaded :: Recording Stopped</color></b>\n==================================================\n" + $" • Start Time : <b>{RecordingStartTime:HH:mm:ss}</b>\n" + $" • Stop Time  : <b>{RecordingStopTime:HH:mm:ss}</b>\n" + $" • Duration   : <b>{text}</b> ({num:F1}s)\n" + " • Directory  : <b>" + activeOutputDirectory + "</b>\n • Status     : Finalizing write buffer in capture folder.\n==================================================";
			return true;
		}

		public static string GetStatus()
		{
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			if (IsRecording)
			{
				double totalSeconds = (DateTime.Now - RecordingStartTime).TotalSeconds;
				return $"<color=#00FFAA>[Record]</color> State: <b><color=#FF4444>● RECORDING ACTIVE</color></b> ({FormatDuration(totalSeconds)} elapsed, started {RecordingStartTime:HH:mm:ss})\n" + " • Target Directory: " + GetActiveOutputDirectory() + "\n • Finish Command  : Type <color=#00FFAA>'record stop'</color>";
			}
			string arg = ((!string.IsNullOrEmpty(LastRecordedFile)) ? $"\n • Last File : {Path.GetFileName(LastRecordedFile)} ({FormatDuration(LastDurationSeconds)}, {(double)LastFileSizeBytes / 1048576.0:F1} MB)\n • Directory : {LastRecordedDirectory}" : "");
			return "<color=#00FFAA>[Record]</color> State: <b>IDLE</b>\n • Capture Directory : " + GetActiveOutputDirectory() + "\n" + $" • Hotkey            : [{PluginConfig.RecordHotkey?.Value}] (toggle start/stop){arg}\n" + " • Usage             : 'record start' | 'record stop' | 'record status' | 'record dir <path>'";
		}

		private static FileInfo? FindNewestVideoFile(DateTime sinceTime)
		{
			HashSet<string> validExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".mp4", ".mkv", ".mov", ".avi", ".webm" };
			FileInfo fileInfo = null;
			foreach (string candidateDirectory in GetCandidateDirectories())
			{
				if (!Directory.Exists(candidateDirectory))
				{
					continue;
				}
				try
				{
					FileInfo fileInfo2 = (from f in new DirectoryInfo(candidateDirectory).GetFiles("*.*", SearchOption.TopDirectoryOnly)
						where validExtensions.Contains(f.Extension) && f.LastWriteTime >= sinceTime
						orderby f.LastWriteTime descending
						select f).FirstOrDefault();
					if (fileInfo2 != null && (fileInfo == null || fileInfo2.LastWriteTime > fileInfo.LastWriteTime))
					{
						fileInfo = fileInfo2;
					}
				}
				catch (Exception ex)
				{
					ZLog.LogWarning((object)("[Unfaded.RecordingManager] Error scanning " + candidateDirectory + ": " + ex.Message));
				}
			}
			return fileInfo;
		}

		public static string FormatDuration(double totalSeconds)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(totalSeconds);
			if (!(timeSpan.TotalHours >= 1.0))
			{
				return $"{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}";
			}
			return $"{(int)timeSpan.TotalHours:D2}:{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}";
		}

		private static void ShowHudMessage(string text)
		{
			try
			{
				if ((Object)(object)MessageHud.instance != (Object)null)
				{
					MessageHud.instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true);
				}
				else if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					((Character)Player.m_localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
				}
			}
			catch
			{
			}
		}
	}
}
namespace Unfaded.Configuration
{
	public static class PluginConfig
	{
		public static ConfigEntry<bool> IsModEnabled;

		public static ConfigEntry<bool> DisableDeathFade;

		public static ConfigEntry<float> CustomDeathFadeDuration;

		public static ConfigEntry<float> RespawnDelay;

		public static ConfigEntry<bool> EnableManualRespawn;

		public static ConfigEntry<KeyCode> ManualRespawnKey;

		public static ConfigEntry<bool> ShowRespawnPrompt;

		public static ConfigEntry<string> RespawnPromptText;

		public static ConfigEntry<bool> EnableCameraOrbit;

		public static ConfigEntry<float> CameraOrbitSensitivity;

		public static ConfigEntry<bool> EnableDeathRecap;

		public static ConfigEntry<bool> EnableKillerCam;

		public static ConfigEntry<KeyCode> KillerCamKey;

		public static ConfigEntry<bool> EnableSlowMotion;

		public static ConfigEntry<float> SlowMotionScale;

		public static ConfigEntry<float> SlowMotionDuration;

		public static ConfigEntry<bool> EnableFreeFly;

		public static ConfigEntry<KeyCode> FreeFlyKey;

		public static ConfigEntry<float> FreeFlyRadius;

		public static ConfigEntry<float> FreeFlySpeed;

		public static ConfigEntry<string> RecordOutputDirectory;

		public static ConfigEntry<bool> EnableRecordingHotkey;

		public static ConfigEntry<KeyCode> RecordHotkey;

		public static ConfigEntry<bool> EnableGameBarTrigger;

		public static void BindConfig(ConfigFile config)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Expected O, but got Unknown
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Expected O, but got Unknown
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Expected O, but got Unknown
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Expected O, but got Unknown
			IsModEnabled = config.Bind<bool>("1 - General", "Enabled", true, "Master toggle for Unfaded mod.");
			DisableDeathFade = config.Bind<bool>("2 - Visuals", "DisableDeathFade", true, "Completely eliminate the 9.5-second black screen fadeout on death, keeping the viewport fully visible.");
			CustomDeathFadeDuration = config.Bind<float>("2 - Visuals", "CustomDeathFadeDuration", 0f, "Custom death fade duration in seconds. Set to 0 for no fade. Vanilla Valheim is 9.5 seconds.");
			RespawnDelay = config.Bind<float>("3 - Respawn", "RespawnDelay", 10f, new ConfigDescription("Seconds to wait before automatic respawn after death. Vanilla Valheim is 10.0 seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>()));
			EnableManualRespawn = config.Bind<bool>("3 - Respawn", "EnableManualRespawn", true, "Allow pressing a key while dead to immediately trigger respawn at your bed/spawnpoint.");
			ManualRespawnKey = config.Bind<KeyCode>("3 - Respawn", "ManualRespawnKey", (KeyCode)32, "Key that triggers early respawn while dead.");
			ShowRespawnPrompt = config.Bind<bool>("3 - Respawn", "ShowRespawnPrompt", true, "Show an on-screen HUD prompt indicating spectator controls and the manual respawn hotkey while dead.");
			RespawnPromptText = config.Bind<string>("3 - Respawn", "RespawnPromptText", "[{0}] Respawn • [K] Killer Cam • [F] Free Fly", "Status bar text displayed during death spectator mode.");
			EnableCameraOrbit = config.Bind<bool>("4 - Spectator Camera", "EnableCameraOrbit", true, "Allow orbiting the camera around your ragdoll using mouse look while dead.");
			CameraOrbitSensitivity = config.Bind<float>("4 - Spectator Camera", "CameraOrbitSensitivity", 2f, new ConfigDescription("Mouse look sensitivity multiplier while spectating your corpse.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			EnableDeathRecap = config.Bind<bool>("5 - Killer & Recap", "EnableDeathRecap", true, "Display an on-screen Death Recap banner showing the killer's name, star rank, and lethal damage amount.");
			EnableKillerCam = config.Bind<bool>("5 - Killer & Recap", "EnableKillerCam", true, "Allow toggling the camera focus to the creature that dealt the fatal blow.");
			KillerCamKey = config.Bind<KeyCode>("5 - Killer & Recap", "KillerCamKey", (KeyCode)107, "Key to toggle camera focus between your ragdoll and your killer.");
			EnableSlowMotion = config.Bind<bool>("6 - Cinematic Slow-Mo", "EnableSlowMotion", true, "Briefly enter cinematic bullet-time slow motion upon receiving lethal damage so you can watch your Viking ragdoll launch in epic slow-mo.");
			SlowMotionScale = config.Bind<float>("6 - Cinematic Slow-Mo", "SlowMotionScale", 0.35f, new ConfigDescription("Time scale during the lethal impact (0.1 = super slow, 1.0 = normal speed).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
			SlowMotionDuration = config.Bind<float>("6 - Cinematic Slow-Mo", "SlowMotionDuration", 1.5f, new ConfigDescription("Real-time seconds of slow motion before returning to regular game speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 5f), Array.Empty<object>()));
			EnableFreeFly = config.Bind<bool>("7 - Free-Fly Spectator", "EnableFreeFly", true, "Allow untethering the camera to fly freely around the death site for tactical corpse recovery scouting.");
			FreeFlyKey = config.Bind<KeyCode>("7 - Free-Fly Spectator", "FreeFlyKey", (KeyCode)102, "Key to toggle free-fly drone mode on and off while dead.");
			FreeFlyRadius = config.Bind<float>("7 - Free-Fly Spectator", "FreeFlyRadius", 60f, new ConfigDescription("Maximum flight distance in meters from your death location.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 200f), Array.Empty<object>()));
			FreeFlySpeed = config.Bind<float>("7 - Free-Fly Spectator", "FreeFlySpeed", 15f, new ConfigDescription("Movement speed in meters per second while in free-fly drone mode.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 50f), Array.Empty<object>()));
			RecordOutputDirectory = config.Bind<string>("8 - Video Recording", "RecordOutputDirectory", "", "Optional custom directory to scan for recorded video files. If blank, auto-detects Captures and OBS directories.");
			EnableRecordingHotkey = config.Bind<bool>("8 - Video Recording", "EnableRecordingHotkey", true, "Enable hotkey toggle to start and stop video recording without opening console.");
			RecordHotkey = config.Bind<KeyCode>("8 - Video Recording", "RecordHotkey", (KeyCode)290, "Hotkey to toggle video recording on/off (starts recording on first press, stops and logs summary on second press).");
			EnableGameBarTrigger = config.Bind<bool>("8 - Video Recording", "EnableGameBarTrigger", true, "Automatically dispatch Windows Game Bar capture shortcut (Win + Alt + R) on record start/stop.");
		}
	}
}
namespace Unfaded.Commands
{
	[HarmonyPatch(typeof(Terminal), "Awake")]
	public static class UnfadedCommand
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__0_0;

			public static ConsoleEvent <>9__0_1;

			public static Func<string, string> <>9__1_0;

			internal void <Postfix>b__0_0(ConsoleEventArgs args)
			{
				HandleRecordCommand(args);
			}

			internal void <Postfix>b__0_1(ConsoleEventArgs args)
			{
				if (args.Length < 2 || args[1].Equals("status", StringComparison.OrdinalIgnoreCase) || args[1].Equals("help", StringComparison.OrdinalIgnoreCase))
				{
					PrintStatus(args.Context);
					return;
				}
				string text = args[1].ToLower();
				switch (text)
				{
				case "record":
				case "rec":
					HandleRecordSubcommand(args);
					break;
				case "die":
				case "smite":
				case "tree":
					ExecuteSmite(args, text == "tree");
					break;
				case "test":
				{
					DeathStateManager.IsTestSimActive = true;
					DeathStateManager.TestSimEndTime = Time.time + 6f;
					Terminal context2 = args.Context;
					if (context2 != null)
					{
						context2.AddString("<color=#00FFAA>[Unfaded]</color> <b>Spectator Test Mode Active (6s)</b>! Orbit with mouse, press [K] Killer, [F] Free Fly.");
					}
					break;
				}
				case "delay":
				{
					if (args.Length >= 3 && float.TryParse(args[2], out var result))
					{
						PluginConfig.RespawnDelay.Value = Mathf.Clamp(result, 0f, 120f);
						Terminal context6 = args.Context;
						if (context6 != null)
						{
							context6.AddString($"<color=#00FFAA>[Unfaded]</color> Respawn delay set to: <b>{PluginConfig.RespawnDelay.Value:F1}s</b>");
						}
					}
					else
					{
						Terminal context7 = args.Context;
						if (context7 != null)
						{
							context7.AddString("<color=#FF6B6B>[Unfaded]</color> Usage: unfaded delay <seconds> (e.g. unfaded delay 5)");
						}
					}
					break;
				}
				case "slowmo":
				{
					PluginConfig.EnableSlowMotion.Value = !PluginConfig.EnableSlowMotion.Value;
					Terminal context4 = args.Context;
					if (context4 != null)
					{
						context4.AddString("<color=#00FFAA>[Unfaded]</color> Cinematic Slow-Mo on lethal hit: <b>" + (PluginConfig.EnableSlowMotion.Value ? "<color=#00FFAA>ENABLED</color>" : "<color=#FF6B6B>DISABLED</color>") + "</b>");
					}
					break;
				}
				case "orbit":
				{
					PluginConfig.EnableCameraOrbit.Value = !PluginConfig.EnableCameraOrbit.Value;
					Terminal context5 = args.Context;
					if (context5 != null)
					{
						context5.AddString("<color=#00FFAA>[Unfaded]</color> 360° Corpse Orbit: <b>" + (PluginConfig.EnableCameraOrbit.Value ? "<color=#00FFAA>ENABLED</color>" : "<color=#FF6B6B>DISABLED</color>") + "</b>");
					}
					break;
				}
				case "killer":
				{
					PluginConfig.EnableKillerCam.Value = !PluginConfig.EnableKillerCam.Value;
					Terminal context8 = args.Context;
					if (context8 != null)
					{
						context8.AddString("<color=#00FFAA>[Unfaded]</color> Killer Focus Cam: <b>" + (PluginConfig.EnableKillerCam.Value ? "<color=#00FFAA>ENABLED</color>" : "<color=#FF6B6B>DISABLED</color>") + "</b>");
					}
					break;
				}
				case "freefly":
				{
					PluginConfig.EnableFreeFly.Value = !PluginConfig.EnableFreeFly.Value;
					Terminal context3 = args.Context;
					if (context3 != null)
					{
						context3.AddString("<color=#00FFAA>[Unfaded]</color> Free-Fly Drone Spectator: <b>" + (PluginConfig.EnableFreeFly.Value ? "<color=#00FFAA>ENABLED</color>" : "<color=#FF6B6B>DISABLED</color>") + "</b>");
					}
					break;
				}
				default:
				{
					Terminal context = args.Context;
					if (context != null)
					{
						context.AddString("<color=#FF6B6B>[Unfaded]</color> Unknown subcommand. Options: status, record, test, delay <sec>, slowmo, orbit, killer, freefly");
					}
					break;
				}
				}
			}

			internal string <HandleRecordCommand>b__1_0(string d)
			{
				return "  • " + d;
			}
		}

		[HarmonyPostfix]
		public static void Postfix()
		{
			//IL_0035: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					HandleRecordCommand(args);
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			ConsoleEvent val2 = (ConsoleEvent)obj;
			new ConsoleCommand("record", "Video recording devcommands (start, stop, status, dir)", val2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			new ConsoleCommand("rec", "Shorthand alias for record (start, stop, status, dir)", val2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj2 = <>c.<>9__0_1;
			if (obj2 == null)
			{
				ConsoleEvent val3 = delegate(ConsoleEventArgs args)
				{
					if (args.Length < 2 || args[1].Equals("status", StringComparison.OrdinalIgnoreCase) || args[1].Equals("help", StringComparison.OrdinalIgnoreCase))
					{
						PrintStatus(args.Context);
					}
					else
					{
						string text = args[1].ToLower();
						switch (text)
						{
						case "record":
						case "rec":
							HandleRecordSubcommand(args);
							break;
						case "die":
						case "smite":
						case "tree":
							ExecuteSmite(args, text == "tree");
							break;
						case "test":
						{
							DeathStateManager.IsTestSimActive = true;
							DeathStateManager.TestSimEndTime = Time.time + 6f;
							Terminal context2 = args.Context;
							if (context2 != null)
							{
								context2.AddString("<color=#00FFAA>[Unfaded]</color> <b>Spectator Test Mode Active (6s)</b>! Orbit with mouse, press [K] Killer, [F] Free Fly.");
							}
							break;
						}
						case "delay":
						{
							if (args.Length >= 3 && float.TryParse(args[2], out var result))
							{
								PluginConfig.RespawnDelay.Value = Mathf.Clamp(result, 0f, 120f);
								Terminal context6 = args.Context;
								if (context6 != null)
								{
									context6.AddString($"<color=#00FFAA>[Unfaded]</color> Respawn delay set to: <b>{PluginConfig.RespawnDelay.Value:F1}s</b>");
								}
							}
							else
							{
								Terminal context7 = args.Context;
								if (context7 != null)
								{
									context7.AddString("<color=#FF6B6B>[Unfaded]</color> Usage: unfaded delay <seconds> (e.g. unfaded delay 5)");
								}
							}
							break;
						}
						case "slowmo":
						{
							PluginConfig.EnableSlowMotion.Value = !PluginConfig.EnableSlowMotion.Value;
							Terminal context4 = args.Context;
							if (context4 != null)
							{
								context4.AddString("<color=#00FFAA>[Unfaded]</color> Cinematic Slow-Mo on lethal hit: <b>" + (PluginConfig.EnableSlowMotion.Value ? "<color=#00FFAA>ENABLED</color>" : "<color=#FF6B6B>DISABLED</color>") + "</b>");
							}
							break;
						}
						case "orbit":
						{
							PluginConfig.EnableCameraOrbit.Value = !PluginConfig.EnableCameraOrbit.Value;
							Terminal context5 = args.Context;
							if (context5 != null)
							{
								context5.AddString("<color=#00FFAA>[Unfaded]</color> 360° Corpse Orbit: <b>" + (PluginConfig.EnableCameraOrbit.Value ? "<color=#00FFAA>ENABLED</color>" : "<color=#FF6B6B>DISABLED</color>") + "</b>");
							}
							break;
						}
						case "killer":
						{
							PluginConfig.EnableKillerCam.Value = !PluginConfig.EnableKillerCam.Value;
							Terminal context8 = args.Context;
							if (context8 != null)
							{
								context8.AddString("<color=#00FFAA>[Unfaded]</color> Killer Focus Cam: <b>" + (PluginConfig.EnableKillerCam.Value ? "<color=#00FFAA>ENABLED</color>" : "<color=#FF6B6B>DISABLED</color>") + "</b>");
							}
							break;
						}
						case "freefly":
						{
							PluginConfig.EnableFreeFly.Value = !PluginConfig.EnableFreeFly.Value;
							Terminal context3 = args.Context;
							if (context3 != null)
							{
								context3.AddString("<color=#00FFAA>[Unfaded]</color> Free-Fly Drone Spectator: <b>" + (PluginConfig.EnableFreeFly.Value ? "<color=#00FFAA>ENABLED</color>" : "<color=#FF6B6B>DISABLED</color>") + "</b>");
							}
							break;
						}
						default:
						{
							Terminal context = args.Context;
							if (context != null)
							{
								context.AddString("<color=#FF6B6B>[Unfaded]</color> Unknown subcommand. Options: status, record, test, delay <sec>, slowmo, orbit, killer, freefly");
							}
							break;
						}
						}
					}
				};
				<>c.<>9__0_1 = val3;
				obj2 = (object)val3;
			}
			new ConsoleCommand("unfaded", "Unfaded death spectator & recording commands (status, record, test, delay, slowmo, orbit, killer, freefly)", (ConsoleEvent)obj2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		public static void HandleRecordCommand(ConsoleEventArgs args)
		{
			if (args.Length < 2 || args[1].Equals("status", StringComparison.OrdinalIgnoreCase))
			{
				string status = RecordingManager.GetStatus();
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString(status);
				}
				return;
			}
			string text = args[1].ToLower();
			switch (text)
			{
			case "begin":
			case "start":
			case "on":
			{
				RecordingManager.StartRecording(out string message4);
				Terminal context9 = args.Context;
				if (context9 != null)
				{
					context9.AddString(message4);
				}
				break;
			}
			case "stop":
			case "end":
			case "off":
			{
				RecordingManager.StopRecording(out string message);
				Terminal context3 = args.Context;
				if (context3 != null)
				{
					context3.AddString(message);
				}
				break;
			}
			case "toggle":
				if (RecordingManager.IsRecording)
				{
					RecordingManager.StopRecording(out string message2);
					Terminal context7 = args.Context;
					if (context7 != null)
					{
						context7.AddString(message2);
					}
				}
				else
				{
					RecordingManager.StartRecording(out string message3);
					Terminal context8 = args.Context;
					if (context8 != null)
					{
						context8.AddString(message3);
					}
				}
				break;
			case "path":
			case "dir":
			case "directory":
			{
				if (args.Length >= 3)
				{
					string text2 = args.FullLine.Substring(args.FullLine.IndexOf(args[2], StringComparison.Ordinal)).Trim();
					if (Directory.Exists(text2))
					{
						PluginConfig.RecordOutputDirectory.Value = text2;
						Terminal context4 = args.Context;
						if (context4 != null)
						{
							context4.AddString("<color=#00FFAA>[Record]</color> Capture directory updated: <b>" + text2 + "</b>");
						}
					}
					else
					{
						Terminal context5 = args.Context;
						if (context5 != null)
						{
							context5.AddString("<color=#FF6B6B>[Record]</color> Directory not found: " + text2);
						}
					}
					break;
				}
				Terminal context6 = args.Context;
				if (context6 != null)
				{
					context6.AddString("<color=#00FFAA>[Record]</color> Active capture directory: <b>" + RecordingManager.GetActiveOutputDirectory() + "</b>\n Candidate folders searched:\n" + string.Join("\n", from d in RecordingManager.GetCandidateDirectories()
						select "  • " + d));
				}
				break;
			}
			case "smite":
			case "tree":
				ExecuteSmite(args, text == "tree");
				break;
			default:
			{
				Terminal context2 = args.Context;
				if (context2 != null)
				{
					context2.AddString("<color=#FF6B6B>[Record]</color> Usage:\n • <color=#00FFAA>record start</color>  - Start recording (echos start time, sends Win+Alt+R)\n • <color=#00FFAA>record stop</color>   - Stop recording (echos duration, filename, path, size)\n • <color=#00FFAA>record status</color> - View recording status\n • <color=#00FFAA>record dir [path]</color> - Show or set output directory");
				}
				break;
			}
			}
		}

		private static void HandleRecordSubcommand(ConsoleEventArgs args)
		{
			if (args.Length < 3)
			{
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString(RecordingManager.GetStatus());
				}
				return;
			}
			switch (args[2].ToLower())
			{
			case "begin":
			case "start":
			case "on":
			{
				RecordingManager.StartRecording(out string message2);
				Terminal context8 = args.Context;
				if (context8 != null)
				{
					context8.AddString(message2);
				}
				break;
			}
			case "stop":
			case "end":
			case "off":
			{
				RecordingManager.StopRecording(out string message);
				Terminal context7 = args.Context;
				if (context7 != null)
				{
					context7.AddString(message);
				}
				break;
			}
			case "status":
			{
				Terminal context3 = args.Context;
				if (context3 != null)
				{
					context3.AddString(RecordingManager.GetStatus());
				}
				break;
			}
			case "path":
			case "dir":
			case "directory":
				if (args.Length >= 4)
				{
					string text = args.FullLine.Substring(args.FullLine.IndexOf(args[3], StringComparison.Ordinal)).Trim();
					if (Directory.Exists(text))
					{
						PluginConfig.RecordOutputDirectory.Value = text;
						Terminal context4 = args.Context;
						if (context4 != null)
						{
							context4.AddString("<color=#00FFAA>[Record]</color> Capture directory updated: <b>" + text + "</b>");
						}
					}
					else
					{
						Terminal context5 = args.Context;
						if (context5 != null)
						{
							context5.AddString("<color=#FF6B6B>[Record]</color> Directory not found: " + text);
						}
					}
				}
				else
				{
					Terminal context6 = args.Context;
					if (context6 != null)
					{
						context6.AddString("<color=#00FFAA>[Record]</color> Active capture directory: <b>" + RecordingManager.GetActiveOutputDirectory() + "</b>");
					}
				}
				break;
			default:
			{
				Terminal context2 = args.Context;
				if (context2 != null)
				{
					context2.AddString("<color=#FF6B6B>[Record]</color> Usage: unfaded record start | stop | status | dir [path]");
				}
				break;
			}
			}
		}

		private static void ExecuteSmite(ConsoleEventArgs args, bool asTree)
		{
			//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_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_0044: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString("<color=#FF6B6B>[Unfaded]</color> Local player not found. Load into a world first.");
				}
				return;
			}
			HitData val = new HitData
			{
				m_hitType = (HitType)(asTree ? 13 : 14),
				m_pushForce = 120f
			};
			Vector3 val2 = ((Component)localPlayer).transform.forward * -1f + Vector3.up * 0.45f;
			val.m_dir = ((Vector3)(ref val2)).normalized;
			val.m_point = ((Component)localPlayer).transform.position;
			HitData val3 = val;
			val3.m_damage.m_damage = 9999f;
			((Character)localPlayer).Damage(val3);
			string text = (asTree ? "Falling Tree / Timber" : "Cinematic Smite");
			Terminal context2 = args.Context;
			if (context2 != null)
			{
				context2.AddString("<color=#00FFAA>[Unfaded]</color> ⚡ Lethal hit dealt (" + text + ")! Ragdoll launched, spectator active.");
			}
		}

		private static void PrintStatus(Terminal context)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)context == (Object)null))
			{
				context.AddString("==================================================");
				context.AddString("   <b><color=#00FFAA>Unfaded :: Death Spectator & Recording</color></b>");
				context.AddString("==================================================");
				context.AddString(" • Blackout Override : <b>" + (PluginConfig.DisableDeathFade.Value ? "<color=#00FFAA>SUPPRESSED (Clear View)</color>" : "<color=#FF6B6B>ACTIVE (Vanilla)</color>") + "</b>");
				context.AddString($" • Respawn Delay     : <b>{PluginConfig.RespawnDelay.Value:F1}s</b> (Instant on [{PluginConfig.ManualRespawnKey.Value}])");
				context.AddString(string.Format(" • 360° Corpse Orbit : <b>{0}</b> (Sensitivity: {1:F1}x)", PluginConfig.EnableCameraOrbit.Value ? "ENABLED" : "DISABLED", PluginConfig.CameraOrbitSensitivity.Value));
				context.AddString(" • Killer Cam [K]    : <b>" + (PluginConfig.EnableKillerCam.Value ? "ENABLED" : "DISABLED") + "</b>");
				context.AddString(string.Format(" • Free-Fly Drone [F]: <b>{0}</b> (Radius: {1:F0}m)", PluginConfig.EnableFreeFly.Value ? "ENABLED" : "DISABLED", PluginConfig.FreeFlyRadius.Value));
				context.AddString(" • Bullet-Time SlowMo: <b>" + (PluginConfig.EnableSlowMotion.Value ? $"ENABLED ({PluginConfig.SlowMotionScale.Value:F2}x for {PluginConfig.SlowMotionDuration.Value:F1}s)" : "DISABLED") + "</b>");
				context.AddString(string.Format(" • Video Recording   : <b>{0}</b> (Hotkey: [{1}])", RecordingManager.IsRecording ? "<color=#FF4444>ACTIVE</color>" : "<color=#00FFAA>IDLE</color>", PluginConfig.RecordHotkey?.Value));
				context.AddString(" • Capture Directory : <b>" + RecordingManager.GetActiveOutputDirectory() + "</b>");
				context.AddString(" Recording Commands  : record start | record stop | record status | record dir");
				context.AddString(" Spectator Commands  : unfaded test | unfaded delay <sec> | unfaded slowmo | unfaded killer");
				context.AddString("==================================================");
			}
		}
	}
}