Decompiled source of NullscapeOperator v1.3.6

plugins/NullscapeOperator/NullscapeOperator.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace NullscapeOperator
{
	internal sealed class OperatorEncounter : IDisposable
	{
		private enum Phase
		{
			Intro,
			Waiting,
			Leaving,
			Warning,
			Attacking,
			Finished
		}

		private const float IntroDuration = 0.65f;

		private const float YellowDuration = 5f;

		private const float ReleaseGracePeriod = 0.1f;

		private const float LeaveDuration = 0.55f;

		private const float RedWarningDuration = 1f;

		private const float AttackFrameDuration = 0.14f;

		private const float StickDeadZone = 0.26f;

		private readonly Component player;

		private readonly Texture2D[] textures;

		private readonly Action dealFatalDamage;

		private readonly ManualLogSource logger;

		private readonly OperatorSounds sounds;

		private readonly float screenHeightFraction;

		private readonly float leftCenterFraction;

		private readonly float swayAngle;

		private Phase phase;

		private float elapsedInPhase;

		private float releasedFor;

		private float alpha = 1f;

		private static bool horizontalAxisAvailable = true;

		private static bool verticalAxisAvailable = true;

		public bool Finished => phase == Phase.Finished;

		public OperatorEncounter(Component player, Texture2D[] textures, float height, float left, float sway, Action dealFatalDamage, OperatorSounds sounds, ManualLogSource logger)
		{
			this.player = player;
			this.textures = textures;
			this.dealFatalDamage = dealFatalDamage;
			this.sounds = sounds;
			this.logger = logger;
			screenHeightFraction = Mathf.Clamp(height, 0.2f, 0.75f);
			leftCenterFraction = Mathf.Clamp(left, 0.12f, 0.36f);
			swayAngle = Mathf.Clamp(sway, 0f, 14f);
			sounds?.Play(0);
		}

		public void Update(float deltaTime)
		{
			if (Finished)
			{
				return;
			}
			if ((Object)(object)player == (Object)null || !player.gameObject.activeInHierarchy)
			{
				Finish();
			}
			else
			{
				if (Time.timeScale <= 0.001f)
				{
					return;
				}
				float num = Mathf.Max(0f, deltaTime);
				elapsedInPhase += num;
				switch (phase)
				{
				case Phase.Intro:
					if (elapsedInPhase >= 0.65f)
					{
						Enter(Phase.Waiting);
					}
					break;
				case Phase.Waiting:
					if (!AnyControlsHeld())
					{
						releasedFor += num;
						if (releasedFor >= 0.1f || elapsedInPhase >= 5f)
						{
							Enter(Phase.Leaving);
							break;
						}
					}
					else
					{
						releasedFor = 0f;
					}
					if (elapsedInPhase >= 5f)
					{
						Enter(Phase.Warning);
					}
					break;
				case Phase.Leaving:
					alpha = 1f - Mathf.Clamp01(elapsedInPhase / 0.55f);
					if (elapsedInPhase >= 0.55f)
					{
						Finish();
					}
					break;
				case Phase.Warning:
					if (elapsedInPhase >= 1f)
					{
						Enter(Phase.Attacking);
					}
					break;
				case Phase.Attacking:
					if (elapsedInPhase >= 0.14f)
					{
						try
						{
							dealFatalDamage();
						}
						catch (Exception ex)
						{
							logger.LogError((object)("Operator could not damage player: " + ex));
						}
						Finish();
					}
					break;
				}
			}
		}

		private static bool AnyControlsHeld()
		{
			if (Input.anyKey)
			{
				return true;
			}
			if (!StickMoved("Horizontal", ref horizontalAxisAvailable))
			{
				return StickMoved("Vertical", ref verticalAxisAvailable);
			}
			return true;
		}

		private static bool StickMoved(string axis, ref bool available)
		{
			if (!available)
			{
				return false;
			}
			try
			{
				return Mathf.Abs(Input.GetAxisRaw(axis)) > 0.26f;
			}
			catch (ArgumentException)
			{
				available = false;
				return false;
			}
			catch (UnityException)
			{
				available = false;
				return false;
			}
		}

		public void Draw()
		{
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: 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_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			if (Finished)
			{
				return;
			}
			int num;
			switch (phase)
			{
			default:
				return;
			case Phase.Intro:
			case Phase.Leaving:
				num = 0;
				break;
			case Phase.Waiting:
				num = 1;
				break;
			case Phase.Warning:
				num = 2;
				break;
			case Phase.Attacking:
				num = 3;
				break;
			}
			Texture2D val = textures[num];
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			float num2 = (float)Screen.height * screenHeightFraction;
			float num3 = num2 * (float)((Texture)val).width / (float)((Texture)val).height;
			bool flag = phase == Phase.Waiting;
			float num4 = elapsedInPhase;
			float num5 = swayAngle * Mathf.Sin(num4 * (flag ? 5.1f : 2.7f)) * (flag ? 1f : 0.45f);
			float num6 = (float)Screen.width * (flag ? 0.04f : 0.008f) * Mathf.Sin(num4 * (flag ? 3.3f : 1.6f));
			float num7 = (float)Screen.height * (flag ? 0.054f : 0.012f) * Mathf.Sin(num4 * (flag ? 3.3f : 2f) + 0.6f);
			float num8 = Mathf.Clamp(Mathf.Max(num3 / 2f + 12f, (float)Screen.width * leftCenterFraction) + num6 - num3 / 2f, 0f, Mathf.Max(0f, (float)Screen.width - num3));
			float num9 = Mathf.Clamp((float)Screen.height * 0.52f - num2 / 2f - num7, 0f, Mathf.Max(0f, (float)Screen.height - num2));
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(num8, num9, num3, num2);
			Matrix4x4 matrix = GUI.matrix;
			Color color = GUI.color;
			int depth = GUI.depth;
			try
			{
				GUI.depth = -500;
				GUI.color = new Color(1f, 1f, 1f, alpha);
				GUIUtility.RotateAroundPivot(num5, ((Rect)(ref val2)).center);
				GUI.DrawTexture(val2, (Texture)(object)val, (ScaleMode)2, true);
			}
			finally
			{
				GUI.matrix = matrix;
				GUI.color = color;
				GUI.depth = depth;
			}
		}

		private void Enter(Phase next)
		{
			phase = next;
			elapsedInPhase = 0f;
			releasedFor = 0f;
			alpha = 1f;
			if (sounds != null)
			{
				sounds.StopWaitingLoop();
			}
			if (sounds != null)
			{
				switch (next)
				{
				case Phase.Waiting:
					sounds.StartWaitingLoop();
					break;
				case Phase.Leaving:
					sounds.Play(2);
					break;
				case Phase.Attacking:
					sounds.Play(3);
					break;
				case Phase.Warning:
					break;
				}
			}
		}

		private void Finish()
		{
			if (!Finished)
			{
				phase = Phase.Finished;
				if (sounds != null)
				{
					sounds.StopWaitingLoop();
				}
			}
		}

		public void Dispose()
		{
			Finish();
		}
	}
	internal sealed class OperatorSounds : IDisposable
	{
		internal const int Spawn = 0;

		internal const int Waiting = 1;

		internal const int Vanish = 2;

		internal const int Kill = 3;

		private static readonly string[] Names = new string[4] { "spawn.wav", "waiting.wav", "vanish.wav", "kill.wav" };

		private readonly AudioClip[] clips = (AudioClip[])(object)new AudioClip[4];

		private readonly ManualLogSource log;

		private readonly GameObject host;

		private readonly AudioSource effects;

		private readonly AudioSource waiting;

		private bool disposed;

		private float volume;

		internal float Volume
		{
			get
			{
				return volume;
			}
			set
			{
				volume = Mathf.Clamp01(value);
				if ((Object)(object)effects != (Object)null)
				{
					effects.volume = volume;
				}
				if ((Object)(object)waiting != (Object)null)
				{
					waiting.volume = volume;
				}
			}
		}

		internal OperatorSounds(string directory, float initialVolume, ManualLogSource logger)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			log = logger;
			host = new GameObject("NullscapeOperator_Audio");
			Object.DontDestroyOnLoad((Object)(object)host);
			effects = host.AddComponent<AudioSource>();
			waiting = host.AddComponent<AudioSource>();
			Configure(effects, looping: false);
			Configure(waiting, looping: true);
			Volume = initialVolume;
			for (int i = 0; i < Names.Length; i++)
			{
				try
				{
					clips[i] = LoadPcm16Wav(Path.Combine(directory, Names[i]));
				}
				catch (Exception ex)
				{
					log.LogWarning((object)("Audio indisponivel (" + Names[i] + "): " + ex.Message));
				}
			}
		}

		private static void Configure(AudioSource source, bool looping)
		{
			source.playOnAwake = false;
			source.spatialBlend = 0f;
			source.loop = looping;
			source.dopplerLevel = 0f;
		}

		internal void Play(int index)
		{
			if (!disposed && index >= 0 && index < clips.Length && !((Object)(object)clips[index] == (Object)null) && !(volume <= 0f))
			{
				effects.PlayOneShot(clips[index], 1f);
			}
		}

		internal void StartWaitingLoop()
		{
			if (!disposed && !((Object)(object)clips[1] == (Object)null) && !(volume <= 0f))
			{
				waiting.Stop();
				waiting.clip = clips[1];
				waiting.Play();
			}
		}

		internal void StopWaitingLoop()
		{
			if (!disposed)
			{
				waiting.Stop();
				waiting.clip = null;
			}
		}

		private static AudioClip LoadPcm16Wav(string filename)
		{
			using FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
			using BinaryReader binaryReader = new BinaryReader(fileStream);
			if (new string(binaryReader.ReadChars(4)) != "RIFF")
			{
				throw new InvalidDataException("RIFF ausente");
			}
			binaryReader.ReadUInt32();
			if (new string(binaryReader.ReadChars(4)) != "WAVE")
			{
				throw new InvalidDataException("WAVE ausente");
			}
			ushort num = 0;
			ushort num2 = 0;
			ushort num3 = 0;
			int num4 = 0;
			byte[] array = null;
			while (fileStream.Position + 8 <= fileStream.Length)
			{
				string text = new string(binaryReader.ReadChars(4));
				uint num5 = binaryReader.ReadUInt32();
				long num6 = fileStream.Position + num5 + (num5 & 1);
				if (num6 > fileStream.Length + 1)
				{
					throw new InvalidDataException("Chunk WAV invalido");
				}
				if (text == "fmt " && num5 >= 16)
				{
					num = binaryReader.ReadUInt16();
					num2 = binaryReader.ReadUInt16();
					num4 = binaryReader.ReadInt32();
					binaryReader.ReadUInt32();
					binaryReader.ReadUInt16();
					num3 = binaryReader.ReadUInt16();
				}
				else if (text == "data")
				{
					if (num5 > 2205000)
					{
						throw new InvalidDataException("Audio muito grande");
					}
					array = binaryReader.ReadBytes((int)num5);
				}
				fileStream.Position = Math.Min(num6, fileStream.Length);
			}
			if (num != 1 || num2 != 1 || num3 != 16 || num4 < 8000 || num4 > 96000 || array == null || array.Length < 2 || array.Length % 2 != 0)
			{
				throw new InvalidDataException("Esperado audio WAV mono PCM16");
			}
			float[] array2 = new float[array.Length / 2];
			for (int i = 0; i < array2.Length; i++)
			{
				short num7 = (short)(array[i * 2] | (array[i * 2 + 1] << 8));
				array2[i] = (float)num7 / 32768f;
			}
			AudioClip val = AudioClip.Create(Path.GetFileNameWithoutExtension(filename), array2.Length, 1, num4, false);
			if (!val.SetData(array2, 0))
			{
				Object.Destroy((Object)(object)val);
				throw new IOException("AudioClip.SetData falhou");
			}
			return val;
		}

		public void Dispose()
		{
			if (disposed)
			{
				return;
			}
			StopWaitingLoop();
			disposed = true;
			if ((Object)(object)effects != (Object)null)
			{
				effects.Stop();
			}
			AudioClip[] array = clips;
			foreach (AudioClip val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
			}
			if ((Object)(object)host != (Object)null)
			{
				Object.Destroy((Object)(object)host);
			}
		}
	}
	[BepInPlugin("gooin.ultrakill.nullscapeoperator", "Nullscape Operator", "1.3.6")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private static readonly Dictionary<string, string> KnownScenes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "241a6a8caec7a13438a5ee786040de32", "Intro" },
			{ "b3e7f2f8052488a45b35549efb98d902", "Main Menu" },
			{ "4f8ecffaa98c2614f89922daf31fa22d", "Bootstrap" },
			{ "eb57c9574cb2e624799753de0f8ffcad", "Level 0-1" },
			{ "7927c42db92e4164cae682a55e6b7725", "Level 0-2" },
			{ "5bcb2e0461e7fce408badfcb6778c271", "Level 0-3" },
			{ "3e978dea8d12a0146b46cb0c302d66e2", "Level 0-4" },
			{ "5541f073d290f4348884fa3f76072afd", "Level 0-5" },
			{ "bed42b2b2baee8e4e91e0dce20965c80", "Level 1-1" },
			{ "8038b251ea4683b4db4ef432205184f6", "Level 1-2" },
			{ "8bb7c995619939c449fa474a046a0e10", "Level 1-3" },
			{ "36abcaae9708abc4d9e89e6ec73a2846", "Level 1-4" },
			{ "55e17289238a28d488af367454267a0d", "Level 2-1" },
			{ "6440445a799e22842babe18edf7da792", "Level 2-2" },
			{ "4e039f071c1fba04a82a7b6b44feadc2", "Level 2-3" },
			{ "e33f259a6c8241e46a5cbe4869cf059f", "Level 2-4" },
			{ "eedb12c9580191843af569e5c1f747d0", "Level 3-1" },
			{ "f1aa2efdf8dccae45b1396aef397ed79", "Level 3-2" },
			{ "35e79ad18419eb54c99acadb947ec056", "Level 4-1" },
			{ "3ccffeb3aeb6d3848be2264c18b62a52", "Level 4-2" },
			{ "38748a67bc9e67a43956a92f87d1e742", "Level 4-3" },
			{ "ac1675e648695a343bd064c6d0c56e57", "Level 4-4" },
			{ "fba3bcfce7b99ae4d90356c81c5586b3", "Level 5-1" },
			{ "e964cf0ffaa9e0e4e940b5c738983796", "Level 5-2" },
			{ "05467c3b58b659d488c34adf5963fd5e", "Level 5-3" },
			{ "37e4fc7501da6c44a9d2154603fdcad5", "Level 5-4" },
			{ "e6c1048e72392b94ab51eadc3d5bb481", "Level 6-1" },
			{ "28553bdf5ebfbd94a848afd933e0dfb1", "Level 6-2" },
			{ "401a07bc9536abc4d88d37641bf1d12c", "Level 7-1" },
			{ "aa55551f768b5224997a4b5e0ef315ea", "Level 7-2" },
			{ "a952d42adc8d6724887c991e5376f170", "Level 7-3" },
			{ "6e981b1865c649749a610aafc471e198", "Level 7-4" },
			{ "07b47256f0da7f941947e74905ad16b4", "Level 0-S" },
			{ "5d90a7ae80eab2244b5bd784a77d3724", "Level 1-S" },
			{ "9dcce8702f56e7349ba1ecc71ba5f42a", "Level 2-S" },
			{ "388594c020ef7c240afc673f062e6425", "Level 4-S" },
			{ "1567f75bc4488644684d7a25471dbe95", "Level 5-S" },
			{ "aa8b84f8b1443ef4783afbc6b1db1e30", "Level 7-S" },
			{ "005a4f2ce549277458596ee0f0d6e88c", "Level P-1" },
			{ "1f290c2101e628540bf9c6d1d2140750", "Level P-2" },
			{ "36c5b4853d1d63d4686ea9a23ca61f8c", "Level E-0" },
			{ "920eb5e368b1f154a800f39c4c78c41c", "Level E-1" },
			{ "4c18368dae54f154da2ae65baf0e630e", "Intermission1" },
			{ "d8e7c3bbb0c2f3940aa7c51dc5849781", "Intermission2" },
			{ "9240e656c89994d44b21940f65ab57da", "Cybergrind" },
			{ "7b3cb6a0a342eb54dafe5552d4820eeb", "Sandbox" },
			{ "e92f893de47503a4f959f7d5bca84261", "Museum" }
		};

		private ConfigEntry<bool> enabled;

		private ConfigEntry<bool> runOnSecrets;

		private ConfigEntry<float> uiHeight;

		private ConfigEntry<float> leftPosition;

		private ConfigEntry<float> swayAngle;

		private ConfigEntry<float> soundVolume;

		private OperatorSounds soundEffects;

		private readonly Texture2D[] textures = (Texture2D[])(object)new Texture2D[4];

		private Type playerType;

		private Component player;

		private OperatorEncounter encounter;

		private int currentSceneHandle = int.MinValue;

		private bool spawnedThisLevel;

		private float elapsed;

		private float nextLookup;

		private float spawnDelay;

		private bool texturesReady;

		private string sceneLabel;

		private bool gameplayScene;

		private bool stoppedForSafety;

		private float nextSceneCheck;

		private FieldInfo cachedHp;

		private FieldInfo cachedDead;

		private Type cachedFieldsForType;

		private void Awake()
		{
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Operator encounters.");
			runOnSecrets = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IncludeSecretAndPrimeLevels", true, "Enable on secret/prime levels too.");
			uiHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "ScreenHeightFraction", 0.52f, "Operator UI height relative to screen height (0.20 to 0.75).");
			leftPosition = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "LeftScreenCenter", 0.2f, "Horizontal center position as fraction of screen width (0.12 to 0.36). Left side by default.");
			swayAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SwayAngleDegrees", 7.5f, "Rocking tilt in degrees while yellow; green/red use softer tilt (0 to 14).");
			soundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Volume", 1f, "Volume of the Operator sound effects, 0 to 1.");
			soundEffects = new OperatorSounds(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "sounds"), soundVolume.Value, ((BaseUnityPlugin)this).Logger);
			texturesReady = LoadTextures();
			SceneManager.activeSceneChanged += OnSceneChanged;
			ResetForScene(SceneManager.GetActiveScene());
		}

		private void OnSceneChanged(Scene oldScene, Scene newScene)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (stoppedForSafety)
			{
				return;
			}
			try
			{
				ResetForScene(newScene);
			}
			catch (Exception ex)
			{
				StopSafely("mudanca de fase", ex);
			}
		}

		private void ResetForScene(Scene scene)
		{
			DisposeEncounter();
			currentSceneHandle = ((Scene)(ref scene)).handle;
			spawnedThisLevel = false;
			elapsed = 0f;
			nextLookup = 0f;
			player = null;
			sceneLabel = (KnownScenes.TryGetValue(((Scene)(ref scene)).name ?? string.Empty, out var value) ? value : (((Scene)(ref scene)).name ?? string.Empty));
			spawnDelay = DetermineDelay();
			gameplayScene = IsGameplayScene();
			nextSceneCheck = Time.unscaledTime + 1f;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Scene: " + sceneLabel + " / Operator spawn scheduled in " + spawnDelay.ToString("0") + " seconds of active gameplay."));
		}

		private static float DetermineDelay()
		{
			return Random.Range(1.01f, 119.99f);
		}

		private bool IsGameplayScene()
		{
			string text = sceneLabel;
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			if (text.Equals("Intro", StringComparison.OrdinalIgnoreCase) || text.Equals("Main Menu", StringComparison.OrdinalIgnoreCase) || text.Equals("Bootstrap", StringComparison.OrdinalIgnoreCase) || text.Equals("Sandbox", StringComparison.OrdinalIgnoreCase) || text.Equals("Museum", StringComparison.OrdinalIgnoreCase) || text.Equals("uk_construct", StringComparison.OrdinalIgnoreCase) || text.Equals("Endless", StringComparison.OrdinalIgnoreCase) || text.Equals("Cybergrind", StringComparison.OrdinalIgnoreCase) || text.StartsWith("Intermission", StringComparison.OrdinalIgnoreCase) || text.IndexOf("credit", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return false;
			}
			if (text.StartsWith("Level ", StringComparison.OrdinalIgnoreCase))
			{
				if (!runOnSecrets.Value)
				{
					if (!text.Contains("-S"))
					{
						return !text.Contains("P-");
					}
					return false;
				}
				return true;
			}
			if (text.Length == 32)
			{
				return IsHex(text);
			}
			return false;
		}

		private static bool IsHex(string value)
		{
			for (int i = 0; i < value.Length; i++)
			{
				if (!Uri.IsHexDigit(value[i]))
				{
					return false;
				}
			}
			return true;
		}

		private Component FindPlayer()
		{
			if (playerType == null)
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					playerType = assembly.GetType("NewMovement", throwOnError: false);
					if (playerType != null)
					{
						break;
					}
				}
			}
			if (playerType == null)
			{
				return null;
			}
			Object obj = Object.FindObjectOfType(playerType);
			return (Component)(object)((obj is Component) ? obj : null);
		}

		private void Update()
		{
			if (stoppedForSafety)
			{
				return;
			}
			try
			{
				UpdateCore();
			}
			catch (Exception ex)
			{
				StopSafely("Update", ex);
			}
		}

		private void StopSafely(string stage, Exception ex)
		{
			stoppedForSafety = true;
			((BaseUnityPlugin)this).Logger.LogError((object)("NullscapeOperator interrompido para evitar novos erros em " + stage + ": " + ex));
			try
			{
				DisposeEncounter();
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Falha na limpeza do evento: " + ex2.Message));
			}
		}

		private void UpdateCore()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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)
			if (Time.unscaledTime >= nextSceneCheck)
			{
				nextSceneCheck = Time.unscaledTime + 1f;
				Scene activeScene = SceneManager.GetActiveScene();
				if (((Scene)(ref activeScene)).handle != currentSceneHandle)
				{
					ResetForScene(activeScene);
				}
			}
			if (!enabled.Value || !texturesReady || !gameplayScene)
			{
				DisposeEncounter();
				return;
			}
			if ((Object)(object)player == (Object)null || !player.gameObject.activeInHierarchy)
			{
				if (Time.unscaledTime < nextLookup)
				{
					return;
				}
				nextLookup = Time.unscaledTime + 1f;
				player = FindPlayer();
				if ((Object)(object)player == (Object)null)
				{
					return;
				}
				CacheHealthFields(((object)player).GetType());
			}
			if (encounter != null)
			{
				encounter.Update(Mathf.Max(0f, Time.deltaTime));
				if (encounter.Finished)
				{
					DisposeEncounter();
				}
			}
			else if (!spawnedThisLevel && !(Time.timeScale <= 0.01f) && !IsDead(player))
			{
				elapsed += Mathf.Max(0f, Time.deltaTime);
				if (!(elapsed < spawnDelay))
				{
					soundEffects.Volume = Mathf.Clamp01(soundVolume.Value);
					encounter = new OperatorEncounter(player, textures, uiHeight.Value, leftPosition.Value, swayAngle.Value, ApplyFatalHit, soundEffects, ((BaseUnityPlugin)this).Logger);
					spawnedThisLevel = true;
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Operator apparition spawned on " + sceneLabel));
				}
			}
		}

		private void OnGUI()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			if (stoppedForSafety || Event.current == null || (int)Event.current.type != 7 || enabled == null || !enabled.Value || encounter == null || encounter.Finished)
			{
				return;
			}
			try
			{
				encounter.Draw();
			}
			catch (Exception ex)
			{
				StopSafely("OnGUI", ex);
			}
		}

		private void CacheHealthFields(Type type)
		{
			if (!(type == cachedFieldsForType))
			{
				cachedFieldsForType = type;
				cachedHp = type.GetField("hp", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				cachedDead = type.GetField("dead", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
		}

		private bool IsDead(Component target)
		{
			if ((Object)(object)target == (Object)null)
			{
				return true;
			}
			try
			{
				CacheHealthFields(((object)target).GetType());
				if (cachedHp != null && Convert.ToDouble(cachedHp.GetValue(target)) <= 0.0)
				{
					return true;
				}
				if (cachedDead != null && cachedDead.FieldType == typeof(bool) && (bool)cachedDead.GetValue(target))
				{
					return true;
				}
			}
			catch (Exception ex)
			{
				cachedHp = null;
				cachedDead = null;
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Nao foi possivel ler vida do jogador: " + ex.Message));
			}
			return false;
		}

		private void ApplyFatalHit()
		{
			if ((Object)(object)player == (Object)null || IsDead(player))
			{
				return;
			}
			try
			{
				MethodInfo[] methods = ((object)player).GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name != "GetHurt")
					{
						continue;
					}
					ParameterInfo[] parameters = methodInfo.GetParameters();
					object[] parameters2;
					if (parameters.Length == 7 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == typeof(bool) && parameters[2].ParameterType == typeof(float) && parameters[3].ParameterType == typeof(bool) && parameters[4].ParameterType == typeof(bool) && parameters[5].ParameterType == typeof(float) && parameters[6].ParameterType == typeof(bool))
					{
						parameters2 = new object[7] { 99999, false, 1f, true, true, 0.35f, false };
					}
					else
					{
						if (parameters.Length != 3 || !(parameters[0].ParameterType == typeof(int)) || !(parameters[1].ParameterType == typeof(bool)) || !(parameters[2].ParameterType == typeof(float)))
						{
							continue;
						}
						parameters2 = new object[3] { 99999, false, 1f };
					}
					methodInfo.Invoke(player, parameters2);
					return;
				}
				((BaseUnityPlugin)this).Logger.LogError((object)"Could not find a supported NewMovement fatal damage method.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Fatal hit call failed: " + ex));
			}
		}

		private bool LoadTextures()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "assets");
			string[] array = new string[4] { "idle.png", "waiting.png", "danger.png", "killing.png" };
			try
			{
				for (int i = 0; i < array.Length; i++)
				{
					string text = Path.Combine(path, array[i]);
					byte[] array2 = File.ReadAllBytes(text);
					Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
					if (!ImageConversion.LoadImage(val, array2, true))
					{
						Object.Destroy((Object)(object)val);
						throw new IOException("Imagem invalida: " + text);
					}
					((Texture)val).filterMode = (FilterMode)0;
					((Texture)val).wrapMode = (TextureWrapMode)1;
					textures[i] = val;
				}
				return true;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not load Operator textures: " + ex));
				return false;
			}
		}

		private void DisposeEncounter()
		{
			if (encounter != null)
			{
				encounter.Dispose();
				encounter = null;
			}
		}

		private void OnDestroy()
		{
			SceneManager.activeSceneChanged -= OnSceneChanged;
			DisposeEncounter();
			if (soundEffects != null)
			{
				soundEffects.Dispose();
			}
			Texture2D[] array = textures;
			foreach (Texture2D val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}
	}
}