Decompiled source of Glitnir Fader Ending v0.2.2

GlitnirFaderEnding.dll

Decompiled 2 months 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 BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("GlitnirFaderEnding")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GlitnirFaderEnding")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("3e8757f3-4e74-4e03-9abb-82f3a0280cc2")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Glitnir.FaderEnding;

[BepInPlugin("glitnir.faderending", "Glitnir Fader Ending", "0.2.2")]
[BepInDependency("com.jotunn.jotunn", "2.29.0")]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
[SynchronizationMode(/*Could not decode attribute arguments.*/)]
public class GlitnirFaderEndingPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Character), "OnDeath")]
	private static class Character_OnDeath_Patch
	{
		[HarmonyPrefix]
		private static void Prefix(Character __instance)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				Instance.TryHandleBossDeath(__instance);
			}
		}
	}

	[HarmonyPatch(typeof(Player), "TakeInput")]
	private static class Player_TakeInput_Patch
	{
		[HarmonyPrefix]
		private static bool Prefix(Player __instance, ref bool __result)
		{
			if (!LockPlayerInput.Value || !EndingOverlay.IsActive)
			{
				return true;
			}
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				__result = false;
				return false;
			}
			return true;
		}
	}

	[CompilerGenerated]
	private sealed class <HandleVictoryAuthoritativeLocal>d__64 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public long killerPlayerId;

		public string killerName;

		public Vector3 bossDeathPosition;

		public List<KeyValuePair<GameObject, int>> drops;

		public GlitnirFaderEndingPlugin <>4__this;

		private Player <targetPlayer>5__1;

		private float <delay>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <HandleVictoryAuthoritativeLocal>d__64(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<targetPlayer>5__1 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_00bb: 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_011a: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(Mathf.Max(0f, TeleportDelaySeconds.Value));
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				<targetPlayer>5__1 = Player.m_localPlayer;
				if ((Object)(object)<targetPlayer>5__1 == (Object)null)
				{
					return false;
				}
				if (killerPlayerId != 0L && <targetPlayer>5__1.GetPlayerID() != killerPlayerId)
				{
					LogDebug("Instância local não é o jogador vencedor.");
					return false;
				}
				<>4__this.ApplyAuthoritativeVictoryToPlayer(<targetPlayer>5__1, bossDeathPosition, drops);
				if (!EndingEnabled.Value)
				{
					break;
				}
				<delay>5__2 = Mathf.Max(0f, DelayBeforeEndingVideoSeconds.Value);
				if (<delay>5__2 > 0f)
				{
					<>2__current = (object)new WaitForSeconds(<delay>5__2);
					<>1__state = 2;
					return true;
				}
				goto IL_012b;
			case 2:
				{
					<>1__state = -1;
					goto IL_012b;
				}
				IL_012b:
				<>4__this.BroadcastVictoryToClients(<targetPlayer>5__1.GetPlayerID());
				break;
			}
			LogDebug($"Vitória aplicada localmente para {killerName} ({killerPlayerId}) com teleporte em ({TeleportX.Value}, {TeleportY.Value}, {TeleportZ.Value}).");
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <HandleVictoryAuthoritativeServer>d__63 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public long killerPlayerId;

		public string killerName;

		public Vector3 bossDeathPosition;

		public List<KeyValuePair<GameObject, int>> drops;

		public GlitnirFaderEndingPlugin <>4__this;

		private Player <targetPlayer>5__1;

		private float <delay>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <HandleVictoryAuthoritativeServer>d__63(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<targetPlayer>5__1 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(Mathf.Max(0f, TeleportDelaySeconds.Value));
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				<targetPlayer>5__1 = FindPlayerById(killerPlayerId);
				if ((Object)(object)<targetPlayer>5__1 == (Object)null)
				{
					LogWarning($"Não foi possível encontrar o jogador vencedor no servidor. PlayerID={killerPlayerId}");
					return false;
				}
				<>4__this.ApplyAuthoritativeVictoryToPlayer(<targetPlayer>5__1, bossDeathPosition, drops);
				if (!EndingEnabled.Value)
				{
					break;
				}
				<delay>5__2 = Mathf.Max(0f, DelayBeforeEndingVideoSeconds.Value);
				if (<delay>5__2 > 0f)
				{
					<>2__current = (object)new WaitForSeconds(<delay>5__2);
					<>1__state = 2;
					return true;
				}
				goto IL_0117;
			case 2:
				{
					<>1__state = -1;
					goto IL_0117;
				}
				IL_0117:
				<>4__this.BroadcastVictoryToClients(killerPlayerId);
				break;
			}
			LogDebug($"Vitória aplicada no servidor para {killerName} ({killerPlayerId}) com teleporte em ({TeleportX.Value}, {TeleportY.Value}, {TeleportZ.Value}).");
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	public const string PluginGuid = "glitnir.faderending";

	public const string PluginName = "Glitnir Fader Ending";

	public const string PluginVersion = "0.2.2";

	internal const string RpcVictory = "glitnir.faderending.victory";

	internal static GlitnirFaderEndingPlugin Instance;

	internal static Harmony HarmonyInstance;

	private bool _rpcRegistered;

	private const string SectionGeneral = "General";

	private const string SectionTrigger = "Trigger";

	private const string SectionTeleport = "Teleport";

	private const string SectionLoot = "Loot";

	private const string SectionEnding = "Ending";

	private const string SectionVideo = "Video";

	private const string SectionFinalize = "Finalize";

	internal static ConfigEntry<bool> ModEnabled;

	internal static ConfigEntry<bool> DebugLogging;

	internal static ConfigEntry<string> BossPrefabName;

	internal static ConfigEntry<bool> MatchPrefabNameExactly;

	internal static ConfigEntry<bool> RequirePlayerAsKiller;

	internal static ConfigEntry<bool> TeleportEnabled;

	internal static ConfigEntry<float> TeleportX;

	internal static ConfigEntry<float> TeleportY;

	internal static ConfigEntry<float> TeleportZ;

	internal static ConfigEntry<float> TeleportYaw;

	internal static ConfigEntry<float> TeleportDelaySeconds;

	internal static ConfigEntry<bool> ResetVelocityAfterTeleport;

	internal static ConfigEntry<bool> LootToInventoryEnabled;

	internal static ConfigEntry<string> OverflowModeConfig;

	internal static ConfigEntry<bool> DisableVanillaWorldDrops;

	internal static ConfigEntry<bool> ShowLootDebugLog;

	internal static ConfigEntry<bool> EndingEnabled;

	internal static ConfigEntry<bool> LockPlayerInput;

	internal static ConfigEntry<bool> AllowSkip;

	internal static ConfigEntry<string> SkipKey;

	internal static ConfigEntry<float> FadeInSeconds;

	internal static ConfigEntry<float> FadeOutSeconds;

	internal static ConfigEntry<bool> MuteGameAudioWhileEnding;

	internal static ConfigEntry<float> DelayBeforeEndingVideoSeconds;

	internal static ConfigEntry<float> MinimumSkipDelaySeconds;

	internal static ConfigEntry<bool> VideoEnabled;

	internal static ConfigEntry<bool> UseEmbeddedVideo;

	internal static ConfigEntry<string> EmbeddedVideoResourceName;

	internal static ConfigEntry<string> EmbeddedVideoOutputFileName;

	internal static ConfigEntry<string> VideoPath;

	internal static ConfigEntry<bool> LoopVideo;

	internal static ConfigEntry<float> VideoVolume;

	internal static ConfigEntry<bool> MuteVideoAudio;

	internal static ConfigEntry<float> HoldOnLastFrameSeconds;

	internal static ConfigEntry<float> MaxVideoDurationSeconds;

	internal static ConfigEntry<bool> AutoCloseEnding;

	internal static ConfigEntry<bool> KeepPlayerLockedUntilEnd;

	internal static ConfigEntry<bool> IgnoreDuplicateVictoryEvents;

	private static readonly FieldInfo LastHitField = AccessTools.Field(typeof(Character), "m_lastHit");

	private static readonly FieldInfo DropsEnabledField = AccessTools.Field(typeof(CharacterDrop), "m_dropsEnabled");

	private void Awake()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		Instance = this;
		BindConfig();
		HarmonyInstance = new Harmony("glitnir.faderending");
		HarmonyInstance.PatchAll(Assembly.GetExecutingAssembly());
		SynchronizationManager.OnConfigurationSynchronized += delegate(object _, ConfigurationSynchronizationEventArgs args)
		{
			if (DebugLogging != null && DebugLogging.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[DEBUG] Config sync recebido. Initial={args.InitialSynchronization} | Teleport=({TeleportX.Value}, {TeleportY.Value}, {TeleportZ.Value})");
			}
		};
		LogInfo("Glitnir Fader Ending 0.2.2 carregado.");
	}

	private void Update()
	{
		EnsureRpcRegistered();
	}

	private void OnDestroy()
	{
		if (HarmonyInstance != null)
		{
			HarmonyInstance.UnpatchSelf();
		}
	}

	private ConfigEntry<T> BindSynced<T>(string section, string key, T defaultValue, string description, AcceptableValueBase acceptable = null)
	{
		return ConfigFileExtensions.BindConfigInOrder<T>(((BaseUnityPlugin)this).Config, section, key, defaultValue, description, true, true, true, acceptable, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
	}

	private ConfigEntry<T> BindLocal<T>(string section, string key, T defaultValue, string description, AcceptableValueBase acceptable = null)
	{
		return ConfigFileExtensions.BindConfigInOrder<T>(((BaseUnityPlugin)this).Config, section, key, defaultValue, description, false, true, true, acceptable, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
	}

	private void BindConfig()
	{
		ModEnabled = BindSynced("General", "ModEnabled", defaultValue: true, "Liga ou desliga completamente o mod.");
		DebugLogging = BindLocal("General", "DebugLogging", defaultValue: false, "Ativa logs extras no console local.");
		BossPrefabName = BindSynced("Trigger", "BossPrefabName", "Fader", "Nome do prefab do boss que dispara a sequência.");
		MatchPrefabNameExactly = BindSynced("Trigger", "MatchPrefabNameExactly", defaultValue: true, "Se true, compara o nome do prefab exatamente. Se false, usa Contains.");
		RequirePlayerAsKiller = BindSynced("Trigger", "RequirePlayerAsKiller", defaultValue: true, "Se true, a sequência só dispara se o golpe final vier de um Player.");
		TeleportEnabled = BindSynced("Teleport", "TeleportEnabled", defaultValue: true, "Teleporta o jogador vencedor para um ponto seguro.");
		TeleportX = BindSynced("Teleport", "TeleportX", 0f, "Coordenada X do teleporte.");
		TeleportY = BindSynced("Teleport", "TeleportY", 100f, "Coordenada Y do teleporte.");
		TeleportZ = BindSynced("Teleport", "TeleportZ", 0f, "Coordenada Z do teleporte.");
		TeleportYaw = BindSynced("Teleport", "TeleportYaw", 180f, "Rotação Y do jogador após o teleporte.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 360f));
		TeleportDelaySeconds = BindSynced("Teleport", "TeleportDelaySeconds", 0.25f, "Delay entre a morte do boss e o teleporte.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f));
		ResetVelocityAfterTeleport = BindSynced("Teleport", "ResetVelocityAfterTeleport", defaultValue: true, "Zera a velocidade do rigidbody do jogador depois do teleporte.");
		LootToInventoryEnabled = BindSynced("Loot", "LootToInventoryEnabled", defaultValue: true, "Envia os drops do Fader direto para o inventário do vencedor.");
		OverflowModeConfig = BindSynced("Loot", "OverflowModeConfig", "SpawnAtTeleportLocation", "Quando não couber no inventário: SpawnAtTeleportLocation | SpawnAtPlayer | SpawnAtBossDeath | Discard");
		DisableVanillaWorldDrops = BindSynced("Loot", "DisableVanillaWorldDrops", defaultValue: true, "Desliga o drop vanilla no chão para evitar duplicação.");
		ShowLootDebugLog = BindLocal("Loot", "ShowLootDebugLog", defaultValue: false, "Log local detalhado do processamento dos drops.");
		EndingEnabled = BindSynced("Ending", "EndingEnabled", defaultValue: true, "Mostra a sequência final após matar o boss.");
		LockPlayerInput = BindSynced("Ending", "LockPlayerInput", defaultValue: true, "Bloqueia input do jogador enquanto a sequência final estiver ativa.");
		AllowSkip = BindLocal("Ending", "AllowSkip", defaultValue: true, "Permite pular a sequência final no cliente local.");
		SkipKey = BindLocal("Ending", "SkipKey", "Escape", "Tecla local para pular a sequência final.");
		FadeInSeconds = BindSynced("Ending", "FadeInSeconds", 1.5f, "Tempo de fade-in da tela.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 10f));
		FadeOutSeconds = BindSynced("Ending", "FadeOutSeconds", 1.25f, "Tempo de fade-out da tela.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 10f));
		MuteGameAudioWhileEnding = BindSynced("Ending", "MuteGameAudioWhileEnding", defaultValue: true, "Zera o áudio do jogo enquanto o vídeo final estiver rodando.");
		DelayBeforeEndingVideoSeconds = BindSynced("Ending", "DelayBeforeEndingVideoSeconds", 2f, "Tempo de espera após o teleporte antes de abrir o vídeo.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 15f));
		MinimumSkipDelaySeconds = BindSynced("Ending", "MinimumSkipDelaySeconds", 3f, "Tempo mínimo antes de permitir pular o vídeo com Esc.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f));
		VideoEnabled = BindSynced("Video", "VideoEnabled", defaultValue: true, "Liga o vídeo final.");
		UseEmbeddedVideo = BindSynced("Video", "UseEmbeddedVideo", defaultValue: true, "Se true, usa o vídeo embutido dentro da DLL.");
		EmbeddedVideoResourceName = BindSynced("Video", "EmbeddedVideoResourceName", "", "Nome exato do recurso embutido. Pode ficar vazio para autodetectar.");
		EmbeddedVideoOutputFileName = BindSynced("Video", "EmbeddedVideoOutputFileName", "glitnir_fader_video_embedded.mp4", "Nome do arquivo temporário extraído do recurso embutido.");
		VideoPath = BindSynced("Video", "VideoPath", "glitnir_fader_video.mp4", "Caminho do vídeo externo. Só é usado quando UseEmbeddedVideo = false.");
		LoopVideo = BindSynced("Video", "LoopVideo", defaultValue: false, "Se true, o vídeo fica em loop até o jogador pular.");
		VideoVolume = BindLocal("Video", "VideoVolume", 1f, "Volume local do vídeo.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f));
		MuteVideoAudio = BindSynced("Video", "MuteVideoAudio", defaultValue: false, "Se true, o vídeo toca sem áudio.");
		HoldOnLastFrameSeconds = BindSynced("Video", "HoldOnLastFrameSeconds", 1f, "Quanto tempo segura o último frame antes de fechar.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f));
		MaxVideoDurationSeconds = BindSynced("Video", "MaxVideoDurationSeconds", 600f, "Proteção para não ficar preso se o vídeo não reportar o fim corretamente.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 7200f));
		AutoCloseEnding = BindSynced("Finalize", "AutoCloseEnding", defaultValue: true, "Fecha a UI ao fim do vídeo.");
		KeepPlayerLockedUntilEnd = BindSynced("Finalize", "KeepPlayerLockedUntilEnd", defaultValue: true, "Mantém input bloqueado até o fim total da sequência.");
		IgnoreDuplicateVictoryEvents = BindSynced("Finalize", "IgnoreDuplicateVictoryEvents", defaultValue: true, "Ignora RPCs duplicados do mesmo evento.");
	}

	private void EnsureRpcRegistered()
	{
		if (!_rpcRegistered && ZRoutedRpc.instance != null)
		{
			ZRoutedRpc.instance.Register<ZPackage>("glitnir.faderending.victory", (Action<long, ZPackage>)OnVictoryRpc);
			_rpcRegistered = true;
			LogDebug("ZRoutedRpc registrado.");
		}
	}

	private void OnVictoryRpc(long sender, ZPackage pkg)
	{
		try
		{
			if (!EndingEnabled.Value || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			long num = pkg.ReadLong();
			if (Player.m_localPlayer.GetPlayerID() == num)
			{
				if (IgnoreDuplicateVictoryEvents.Value && EndingOverlay.IsActive)
				{
					LogDebug("RPC duplicado ignorado porque a sequência final já está ativa.");
				}
				else
				{
					EndingOverlay.Show();
				}
			}
		}
		catch (Exception arg)
		{
			LogError($"Falha ao processar RPC de vitória: {arg}");
		}
	}

	internal void TryHandleBossDeath(Character victim)
	{
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!ModEnabled.Value || (Object)(object)victim == (Object)null || victim.IsPlayer() || !IsConfiguredBoss(victim))
			{
				return;
			}
			if (!IsAuthoritativeForDeathHandling(victim))
			{
				LogDebug("Instância não autoritativa para tratar morte do boss. Ignorando.");
				return;
			}
			CharacterDrop component = ((Component)victim).GetComponent<CharacterDrop>();
			if ((Object)(object)component == (Object)null)
			{
				LogWarning("Fader morreu, mas CharacterDrop não foi encontrado.");
				return;
			}
			string killerName;
			long num = TryGetKillerPlayerId(victim, out killerName);
			if (RequirePlayerAsKiller.Value && num == 0)
			{
				LogWarning("Fader morreu, mas não foi possível identificar um Player como golpe final.");
				return;
			}
			List<KeyValuePair<GameObject, int>> drops = new List<KeyValuePair<GameObject, int>>();
			if (LootToInventoryEnabled.Value)
			{
				drops = component.GenerateDropList();
				if (DisableVanillaWorldDrops.Value && DropsEnabledField != null)
				{
					DropsEnabledField.SetValue(component, false);
				}
			}
			Vector3 position = ((Component)victim).transform.position;
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				((MonoBehaviour)this).StartCoroutine(HandleVictoryAuthoritativeServer(num, killerName, position, drops));
			}
			else
			{
				((MonoBehaviour)this).StartCoroutine(HandleVictoryAuthoritativeLocal(num, killerName, position, drops));
			}
		}
		catch (Exception arg)
		{
			LogError($"Erro ao tratar morte do boss: {arg}");
		}
	}

	[IteratorStateMachine(typeof(<HandleVictoryAuthoritativeServer>d__63))]
	private IEnumerator HandleVictoryAuthoritativeServer(long killerPlayerId, string killerName, Vector3 bossDeathPosition, List<KeyValuePair<GameObject, int>> drops)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <HandleVictoryAuthoritativeServer>d__63(0)
		{
			<>4__this = this,
			killerPlayerId = killerPlayerId,
			killerName = killerName,
			bossDeathPosition = bossDeathPosition,
			drops = drops
		};
	}

	[IteratorStateMachine(typeof(<HandleVictoryAuthoritativeLocal>d__64))]
	private IEnumerator HandleVictoryAuthoritativeLocal(long killerPlayerId, string killerName, Vector3 bossDeathPosition, List<KeyValuePair<GameObject, int>> drops)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <HandleVictoryAuthoritativeLocal>d__64(0)
		{
			<>4__this = this,
			killerPlayerId = killerPlayerId,
			killerName = killerName,
			bossDeathPosition = bossDeathPosition,
			drops = drops
		};
	}

	private void ApplyAuthoritativeVictoryToPlayer(Player targetPlayer, Vector3 bossDeathPosition, List<KeyValuePair<GameObject, int>> drops)
	{
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: 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_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)targetPlayer == (Object)null)
		{
			return;
		}
		if (TeleportEnabled.Value)
		{
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(TeleportX.Value, TeleportY.Value, TeleportZ.Value);
			Quaternion val2 = Quaternion.Euler(0f, TeleportYaw.Value, 0f);
			((Character)targetPlayer).TeleportTo(val, val2, true);
			if (ResetVelocityAfterTeleport.Value)
			{
				Rigidbody component = ((Component)targetPlayer).GetComponent<Rigidbody>();
				if ((Object)(object)component != (Object)null)
				{
					component.velocity = Vector3.zero;
					component.angularVelocity = Vector3.zero;
				}
			}
			LogDebug($"Teleport aplicado para {targetPlayer.GetPlayerName()} em {val}");
		}
		if (LootToInventoryEnabled.Value && drops != null && drops.Count > 0)
		{
			GiveDropsToInventory(targetPlayer, drops, bossDeathPosition);
		}
	}

	private void GiveDropsToInventory(Player player, List<KeyValuePair<GameObject, int>> drops, Vector3 bossDeathPosition)
	{
		//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)player == (Object)null)
		{
			return;
		}
		Inventory inventory = ((Humanoid)player).GetInventory();
		if (inventory == null)
		{
			return;
		}
		List<KeyValuePair<GameObject, int>> list = new List<KeyValuePair<GameObject, int>>();
		foreach (KeyValuePair<GameObject, int> drop in drops)
		{
			GameObject key = drop.Key;
			int value = drop.Value;
			if ((Object)(object)key == (Object)null || value <= 0)
			{
				continue;
			}
			ItemDrop component = key.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				LogWarning("Prefab sem ItemDrop: " + NormalizePrefabName(key));
				continue;
			}
			int num = Mathf.Max(1, component.m_itemData.m_shared.m_maxStackSize);
			int num2 = value;
			while (num2 > 0)
			{
				int num3 = Mathf.Min(num, num2);
				GameObject val = Object.Instantiate<GameObject>(key);
				((Object)val).hideFlags = (HideFlags)61;
				ItemDrop component2 = val.GetComponent<ItemDrop>();
				if ((Object)(object)component2 == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					break;
				}
				component2.m_itemData.m_stack = num3;
				if (!inventory.AddItem(component2.m_itemData))
				{
					list.Add(new KeyValuePair<GameObject, int>(key, num3));
				}
				Object.Destroy((Object)(object)val);
				num2 -= num3;
			}
			if (ShowLootDebugLog.Value)
			{
				LogDebug($"Drop processado: {NormalizePrefabName(key)} x{value}");
			}
		}
		if (list.Count > 0)
		{
			HandleOverflowDrops(list, player, bossDeathPosition);
		}
	}

	private void HandleOverflowDrops(List<KeyValuePair<GameObject, int>> overflow, Player player, Vector3 bossDeathPosition)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		string text = (OverflowModeConfig.Value ?? "SpawnAtTeleportLocation").Trim();
		Vector3 val = bossDeathPosition;
		if (text.Equals("Discard", StringComparison.OrdinalIgnoreCase))
		{
			LogWarning("Drops excedentes foram descartados por configuração.");
			return;
		}
		if (text.Equals("SpawnAtPlayer", StringComparison.OrdinalIgnoreCase))
		{
			val = ((Component)player).transform.position;
		}
		else if (text.Equals("SpawnAtTeleportLocation", StringComparison.OrdinalIgnoreCase))
		{
			((Vector3)(ref val))..ctor(TeleportX.Value, TeleportY.Value, TeleportZ.Value);
		}
		SpawnOverflowDrops(overflow, val);
		LogWarning($"Alguns drops não couberam no inventário e foram spawnados em {val}.");
	}

	private void SpawnOverflowDrops(List<KeyValuePair<GameObject, int>> overflow, Vector3 spawnPosition)
	{
		//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_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		foreach (KeyValuePair<GameObject, int> item in overflow)
		{
			GameObject key = item.Key;
			int value = item.Value;
			if ((Object)(object)key == (Object)null || value <= 0)
			{
				continue;
			}
			ItemDrop component = key.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				continue;
			}
			int num = Mathf.Max(1, component.m_itemData.m_shared.m_maxStackSize);
			int num2 = value;
			while (num2 > 0)
			{
				int num3 = Mathf.Min(num, num2);
				Vector3 val = Random.insideUnitSphere * 0.5f;
				val.y = Mathf.Abs(val.y);
				GameObject val2 = Object.Instantiate<GameObject>(key, spawnPosition + Vector3.up + val, Quaternion.identity);
				ItemDrop component2 = val2.GetComponent<ItemDrop>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.m_itemData.m_stack = num3;
				}
				num2 -= num3;
			}
		}
	}

	private void BroadcastVictoryToClients(long winnerPlayerId)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		if (ZRoutedRpc.instance == null)
		{
			LogWarning("ZRoutedRpc.instance ainda não está pronto. Vitória não foi transmitida.");
			return;
		}
		ZPackage val = new ZPackage();
		val.Write(winnerPlayerId);
		ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "glitnir.faderending.victory", new object[1] { val });
		LogDebug($"RPC de vitória enviado para o player {winnerPlayerId}.");
	}

	private static long TryGetKillerPlayerId(Character victim, out string killerName)
	{
		killerName = string.Empty;
		try
		{
			HitData val = (HitData)((LastHitField != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if (val == null)
			{
				return 0L;
			}
			Character attacker = val.GetAttacker();
			Player val2 = (Player)(object)((attacker is Player) ? attacker : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return 0L;
			}
			killerName = val2.GetPlayerName();
			return val2.GetPlayerID();
		}
		catch (Exception ex)
		{
			LogWarning("Falha ao obter killer via m_lastHit: " + ex.Message);
			return 0L;
		}
	}

	private static bool IsAuthoritativeForDeathHandling(Character victim)
	{
		ZNetView component = ((Component)victim).GetComponent<ZNetView>();
		if ((Object)(object)component == (Object)null)
		{
			return true;
		}
		if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
		{
			return true;
		}
		return component.IsOwner();
	}

	private static bool IsConfiguredBoss(Character victim)
	{
		string text = (BossPrefabName.Value ?? "Fader").Trim();
		string text2 = NormalizePrefabName(((Component)victim).gameObject);
		if (MatchPrefabNameExactly.Value)
		{
			return string.Equals(text2, text, StringComparison.OrdinalIgnoreCase);
		}
		return text2.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0;
	}

	private static Player FindPlayerById(long playerId)
	{
		if (playerId == 0)
		{
			return null;
		}
		try
		{
			MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			MethodInfo[] array = methods;
			foreach (MethodInfo methodInfo in array)
			{
				if (methodInfo.Name != "GetAllPlayers")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 0)
				{
					object obj = methodInfo.Invoke(null, null);
					if (!(obj is IEnumerable enumerable))
					{
						continue;
					}
					foreach (object item in enumerable)
					{
						Player val = (Player)((item is Player) ? item : null);
						if ((Object)(object)val != (Object)null && val.GetPlayerID() == playerId)
						{
							return val;
						}
					}
				}
				else
				{
					if (parameters.Length != 1 || !typeof(List<Player>).IsAssignableFrom(parameters[0].ParameterType))
					{
						continue;
					}
					List<Player> list = new List<Player>();
					methodInfo.Invoke(null, new object[1] { list });
					foreach (Player item2 in list)
					{
						if ((Object)(object)item2 != (Object)null && item2.GetPlayerID() == playerId)
						{
							return item2;
						}
					}
				}
			}
		}
		catch (Exception ex)
		{
			LogWarning("Falha ao localizar jogador por ID: " + ex.Message);
		}
		return null;
	}

	internal static string NormalizePrefabName(GameObject go)
	{
		if ((Object)(object)go == (Object)null)
		{
			return string.Empty;
		}
		return NormalizePrefabName(((Object)go).name);
	}

	internal static string NormalizePrefabName(string name)
	{
		if (string.IsNullOrWhiteSpace(name))
		{
			return string.Empty;
		}
		string text = name.Trim();
		if (text.EndsWith("(Clone)", StringComparison.Ordinal))
		{
			text = text.Substring(0, text.Length - "(Clone)".Length).Trim();
		}
		return text;
	}

	internal static string GetPreparedVideoPath()
	{
		if (UseEmbeddedVideo.Value)
		{
			return ExtractEmbeddedVideoToCache();
		}
		return GetResolvedExternalVideoPath();
	}

	internal static string GetResolvedExternalVideoPath()
	{
		string text = ((VideoPath.Value != null) ? VideoPath.Value.Trim() : string.Empty);
		if (string.IsNullOrWhiteSpace(text))
		{
			return string.Empty;
		}
		if (Path.IsPathRooted(text))
		{
			return text;
		}
		return Path.Combine(Paths.ConfigPath, text);
	}

	internal static string ExtractEmbeddedVideoToCache()
	{
		try
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string text = ResolveEmbeddedVideoResourceName(executingAssembly);
			if (string.IsNullOrWhiteSpace(text))
			{
				LogWarning("Nenhum vídeo embutido foi encontrado no assembly.");
				return string.Empty;
			}
			string text2 = Path.Combine(Paths.PluginPath, "GlitnirFaderEndingCache");
			Directory.CreateDirectory(text2);
			string text3 = ((EmbeddedVideoOutputFileName.Value != null) ? EmbeddedVideoOutputFileName.Value.Trim() : string.Empty);
			if (string.IsNullOrWhiteSpace(text3))
			{
				string text4 = Path.GetExtension(text);
				if (string.IsNullOrWhiteSpace(text4))
				{
					text4 = ".mp4";
				}
				text3 = "glitnir_fader_video_embedded" + text4;
			}
			text3 = SanitizeFileName(text3);
			string text5 = Path.Combine(text2, text3);
			using (Stream stream = executingAssembly.GetManifestResourceStream(text))
			{
				if (stream == null)
				{
					LogWarning("Não foi possível abrir o recurso embutido: " + text);
					return string.Empty;
				}
				bool flag = true;
				if (File.Exists(text5))
				{
					FileInfo fileInfo = new FileInfo(text5);
					if (stream.CanSeek && fileInfo.Length == stream.Length)
					{
						flag = false;
					}
				}
				if (flag)
				{
					if (stream.CanSeek)
					{
						stream.Position = 0L;
					}
					using (FileStream destination = new FileStream(text5, FileMode.Create, FileAccess.Write, FileShare.Read))
					{
						stream.CopyTo(destination);
					}
					LogDebug("Vídeo embutido extraído para: " + text5);
				}
			}
			return text5;
		}
		catch (Exception arg)
		{
			LogError($"Falha ao extrair vídeo embutido: {arg}");
			return string.Empty;
		}
	}

	private static string ResolveEmbeddedVideoResourceName(Assembly asm)
	{
		string configured = ((EmbeddedVideoResourceName.Value != null) ? EmbeddedVideoResourceName.Value.Trim() : string.Empty);
		string[] manifestResourceNames = asm.GetManifestResourceNames();
		if (!string.IsNullOrWhiteSpace(configured))
		{
			string text = manifestResourceNames.FirstOrDefault((string n) => string.Equals(n, configured, StringComparison.Ordinal));
			if (!string.IsNullOrWhiteSpace(text))
			{
				return text;
			}
			string text2 = manifestResourceNames.FirstOrDefault((string n) => n.EndsWith(configured, StringComparison.OrdinalIgnoreCase));
			if (!string.IsNullOrWhiteSpace(text2))
			{
				return text2;
			}
		}
		string text3 = manifestResourceNames.FirstOrDefault((string n) => n.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase) || n.EndsWith(".webm", StringComparison.OrdinalIgnoreCase) || n.EndsWith(".mov", StringComparison.OrdinalIgnoreCase));
		return text3 ?? string.Empty;
	}

	private static string SanitizeFileName(string fileName)
	{
		char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
		foreach (char oldChar in invalidFileNameChars)
		{
			fileName = fileName.Replace(oldChar, '_');
		}
		return fileName;
	}

	internal static void LogInfo(string msg)
	{
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg);
		}
	}

	internal static void LogWarning(string msg)
	{
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogWarning((object)msg);
		}
	}

	internal static void LogError(string msg)
	{
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogError((object)msg);
		}
	}

	internal static void LogDebug(string msg)
	{
		if ((Object)(object)Instance != (Object)null && DebugLogging != null && DebugLogging.Value)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[DEBUG] " + msg));
		}
	}
}
internal sealed class EndingOverlay : MonoBehaviour
{
	[CompilerGenerated]
	private sealed class <FadeCanvas>d__22 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public float from;

		public float to;

		public float duration;

		public EndingOverlay <>4__this;

		private float <elapsed>5__1;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <FadeCanvas>d__22(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<elapsed>5__1 = 0f;
				<>4__this._canvasGroup.alpha = from;
				break;
			case 1:
				<>1__state = -1;
				break;
			}
			if (<elapsed>5__1 < duration)
			{
				<elapsed>5__1 += Time.unscaledDeltaTime;
				<>4__this._canvasGroup.alpha = Mathf.Lerp(from, to, <elapsed>5__1 / duration);
				<>2__current = null;
				<>1__state = 1;
				return true;
			}
			<>4__this._canvasGroup.alpha = to;
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <RunSequence>d__19 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public EndingOverlay <>4__this;

		private float <prepareTimeout>5__1;

		private float <watchdog>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <RunSequence>d__19(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Expected O, but got Unknown
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.FadeCanvas(0f, 1f, Mathf.Max(0.01f, GlitnirFaderEndingPlugin.FadeInSeconds.Value)));
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				if (GlitnirFaderEndingPlugin.VideoEnabled.Value && (Object)(object)<>4__this._videoPlayer != (Object)null && !string.IsNullOrWhiteSpace(<>4__this._videoPlayer.url))
				{
					<prepareTimeout>5__1 = 10f;
					goto IL_0116;
				}
				goto IL_0189;
			case 2:
				<>1__state = -1;
				goto IL_0116;
			case 3:
				<>1__state = -1;
				goto IL_0253;
			case 4:
				<>1__state = -1;
				goto IL_029e;
			case 5:
				<>1__state = -1;
				<>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.FadeCanvas(1f, 0f, Mathf.Max(0.01f, GlitnirFaderEndingPlugin.FadeOutSeconds.Value)));
				<>1__state = 6;
				return true;
			case 6:
				{
					<>1__state = -1;
					<>4__this.RestoreGameAudioMute();
					<>4__this._isActive = false;
					<>4__this.SetOverlayState(visible: false, instantAlphaReset: true);
					return false;
				}
				IL_0189:
				if (<>4__this._videoPreparedSuccessfully)
				{
					<watchdog>5__2 = Mathf.Max(1f, GlitnirFaderEndingPlugin.MaxVideoDurationSeconds.Value);
					goto IL_0253;
				}
				<>2__current = (object)new WaitForSecondsRealtime(Mathf.Max(0.1f, GlitnirFaderEndingPlugin.HoldOnLastFrameSeconds.Value));
				<>1__state = 4;
				return true;
				IL_029e:
				if ((Object)(object)<>4__this._videoPlayer != (Object)null && <>4__this._videoPlayer.isPlaying)
				{
					<>4__this._videoPlayer.Stop();
				}
				<>2__current = (object)new WaitForSecondsRealtime(Mathf.Max(0f, GlitnirFaderEndingPlugin.HoldOnLastFrameSeconds.Value));
				<>1__state = 5;
				return true;
				IL_0116:
				if (!<>4__this._videoPlayer.isPrepared && <prepareTimeout>5__1 > 0f)
				{
					<prepareTimeout>5__1 -= Time.unscaledDeltaTime;
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				<>4__this._videoPreparedSuccessfully = <>4__this._videoPlayer.isPrepared;
				if (<>4__this._videoPreparedSuccessfully)
				{
					<>4__this._videoPlayer.Play();
				}
				else
				{
					GlitnirFaderEndingPlugin.LogWarning("O vídeo não ficou pronto a tempo. Encerrando sequência com fade.");
				}
				goto IL_0189;
				IL_0253:
				if (!<>4__this._skipRequested)
				{
					<watchdog>5__2 -= Time.unscaledDeltaTime;
					if (<watchdog>5__2 <= 0f)
					{
						GlitnirFaderEndingPlugin.LogWarning("Tempo máximo do vídeo atingido. Encerrando sequência.");
					}
					else if (GlitnirFaderEndingPlugin.LoopVideo.Value || <>4__this._videoPlayer.isPlaying || <>4__this._videoPlayer.frame <= 0)
					{
						<>2__current = null;
						<>1__state = 3;
						return true;
					}
				}
				goto IL_029e;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	internal static EndingOverlay Instance;

	private bool _isActive;

	private bool _skipRequested;

	private bool _videoPreparedSuccessfully;

	private bool _audioMutedByOverlay;

	private float _previousGameAudioVolume = 1f;

	private float _sequenceStartTime;

	private Canvas _canvas;

	private CanvasGroup _canvasGroup;

	private RawImage _background;

	private VideoPlayer _videoPlayer;

	private RenderTexture _renderTexture;

	internal static bool IsActive => (Object)(object)Instance != (Object)null && Instance._isActive;

	internal static void EnsureRuntimeObject()
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Expected O, but got Unknown
		if (!((Object)(object)Instance != (Object)null))
		{
			GameObject val = new GameObject("GlitnirFaderEndingOverlay");
			Object.DontDestroyOnLoad((Object)(object)val);
			Instance = val.AddComponent<EndingOverlay>();
			Instance.BuildUi();
			Instance.SetOverlayState(visible: false, instantAlphaReset: true);
		}
	}

	internal static void Show()
	{
		EnsureRuntimeObject();
		Instance.Begin();
	}

	private void BuildUi()
	{
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Expected O, but got Unknown
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		_canvas = ((Component)this).gameObject.AddComponent<Canvas>();
		_canvas.renderMode = (RenderMode)0;
		_canvas.sortingOrder = 9999;
		((Behaviour)_canvas).enabled = false;
		((Component)this).gameObject.AddComponent<GraphicRaycaster>();
		_canvasGroup = ((Component)this).gameObject.AddComponent<CanvasGroup>();
		_canvasGroup.alpha = 0f;
		_canvasGroup.interactable = false;
		_canvasGroup.blocksRaycasts = false;
		GameObject val = new GameObject("Background");
		val.transform.SetParent(((Component)this).transform, false);
		RectTransform val2 = val.AddComponent<RectTransform>();
		val2.anchorMin = Vector2.zero;
		val2.anchorMax = Vector2.one;
		val2.offsetMin = Vector2.zero;
		val2.offsetMax = Vector2.zero;
		_background = val.AddComponent<RawImage>();
		((Graphic)_background).color = Color.black;
		_videoPlayer = ((Component)this).gameObject.AddComponent<VideoPlayer>();
		_videoPlayer.playOnAwake = false;
		_videoPlayer.isLooping = false;
		_videoPlayer.renderMode = (VideoRenderMode)2;
		_videoPlayer.audioOutputMode = (VideoAudioOutputMode)2;
		_videoPlayer.skipOnDrop = true;
	}

	private void Begin()
	{
		((MonoBehaviour)this).StopAllCoroutines();
		_skipRequested = false;
		_isActive = true;
		_videoPreparedSuccessfully = false;
		_sequenceStartTime = Time.unscaledTime;
		SetOverlayState(visible: true, instantAlphaReset: false);
		ApplyGameAudioMute();
		ConfigureVideo();
		((MonoBehaviour)this).StartCoroutine(RunSequence());
	}

	private void ConfigureVideo()
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: 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_00d7: Expected O, but got Unknown
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		if (!GlitnirFaderEndingPlugin.VideoEnabled.Value)
		{
			_background.texture = null;
			((Graphic)_background).color = Color.black;
			_videoPreparedSuccessfully = false;
			return;
		}
		string preparedVideoPath = GlitnirFaderEndingPlugin.GetPreparedVideoPath();
		if (string.IsNullOrWhiteSpace(preparedVideoPath) || !File.Exists(preparedVideoPath))
		{
			GlitnirFaderEndingPlugin.LogWarning("Vídeo não encontrado: " + preparedVideoPath);
			_background.texture = null;
			((Graphic)_background).color = Color.black;
			_videoPreparedSuccessfully = false;
			return;
		}
		if ((Object)(object)_renderTexture != (Object)null)
		{
			_renderTexture.Release();
			Object.Destroy((Object)(object)_renderTexture);
		}
		_renderTexture = new RenderTexture(1920, 1080, 0);
		_videoPlayer.targetTexture = _renderTexture;
		_background.texture = (Texture)(object)_renderTexture;
		((Graphic)_background).color = Color.white;
		_videoPlayer.url = preparedVideoPath;
		_videoPlayer.isLooping = GlitnirFaderEndingPlugin.LoopVideo.Value;
		_videoPlayer.SetDirectAudioMute((ushort)0, GlitnirFaderEndingPlugin.MuteVideoAudio.Value);
		_videoPlayer.SetDirectAudioVolume((ushort)0, Mathf.Clamp01(GlitnirFaderEndingPlugin.VideoVolume.Value));
		_videoPlayer.Prepare();
	}

	[IteratorStateMachine(typeof(<RunSequence>d__19))]
	private IEnumerator RunSequence()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <RunSequence>d__19(0)
		{
			<>4__this = this
		};
	}

	private void ApplyGameAudioMute()
	{
		if (GlitnirFaderEndingPlugin.MuteGameAudioWhileEnding.Value)
		{
			_previousGameAudioVolume = AudioListener.volume;
			AudioListener.volume = 0f;
			_audioMutedByOverlay = true;
		}
	}

	private void RestoreGameAudioMute()
	{
		if (_audioMutedByOverlay)
		{
			AudioListener.volume = _previousGameAudioVolume;
			_audioMutedByOverlay = false;
		}
	}

	[IteratorStateMachine(typeof(<FadeCanvas>d__22))]
	private IEnumerator FadeCanvas(float from, float to, float duration)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <FadeCanvas>d__22(0)
		{
			<>4__this = this,
			from = from,
			to = to,
			duration = duration
		};
	}

	private void SetOverlayState(bool visible, bool instantAlphaReset)
	{
		if ((Object)(object)_canvas != (Object)null)
		{
			((Behaviour)_canvas).enabled = visible;
		}
		if ((Object)(object)_canvasGroup != (Object)null)
		{
			_canvasGroup.interactable = visible;
			_canvasGroup.blocksRaycasts = visible;
			if (instantAlphaReset)
			{
				_canvasGroup.alpha = (visible ? 1f : 0f);
			}
		}
	}

	private void Update()
	{
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		if (_isActive && GlitnirFaderEndingPlugin.AllowSkip.Value)
		{
			float num = Time.unscaledTime - _sequenceStartTime;
			if (!(num < Mathf.Max(0f, GlitnirFaderEndingPlugin.MinimumSkipDelaySeconds.Value)) && TryGetSkipKey(out var key) && Input.GetKeyDown(key))
			{
				_skipRequested = true;
			}
		}
	}

	private bool TryGetSkipKey(out KeyCode key)
	{
		return Enum.TryParse<KeyCode>(GlitnirFaderEndingPlugin.SkipKey.Value, ignoreCase: true, out key);
	}

	private void OnDestroy()
	{
		RestoreGameAudioMute();
	}
}