Decompiled source of RedactedNotification v1.0.1

BepInEx/plugins/RedactedNotification.dll

Decompiled 2 weeks ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon;
using Pigeon.Math;
using Pigeon.Movement;
using Sparroh.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[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("RedactedNotification")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RedactedNotification")]
[assembly: AssemblyTitle("RedactedNotification")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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;
		}
	}
}
public static class HudRepositionClient
{
	private const string ApiTypeName = "HudRepositionAPI";

	private static Type _apiType;

	private static MethodInfo _register;

	private static MethodInfo _unregister;

	private static bool _available;

	public static bool IsAvailable
	{
		get
		{
			EnsureResolved();
			return _available;
		}
	}

	public static void Register(string id, string displayName, RectTransform rect, ConfigEntry<float> anchorX, ConfigEntry<float> anchorY)
	{
		if (!_available)
		{
			EnsureResolved(force: true);
		}
		if (!_available || (Object)(object)rect == (Object)null || anchorX == null || anchorY == null)
		{
			return;
		}
		try
		{
			_register.Invoke(null, new object[5] { id, displayName, rect, anchorX, anchorY });
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("[HudRepositionClient] Register failed: " + (ex.InnerException?.Message ?? ex.Message)));
		}
	}

	public static void Unregister(string id)
	{
		if (!_available)
		{
			EnsureResolved(force: true);
		}
		if (!_available || string.IsNullOrEmpty(id))
		{
			return;
		}
		try
		{
			_unregister.Invoke(null, new object[1] { id });
		}
		catch (Exception)
		{
		}
	}

	private static void EnsureResolved(bool force = false)
	{
		if (_available && !force)
		{
			return;
		}
		_apiType = null;
		_register = null;
		_unregister = null;
		_available = false;
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			try
			{
				Type type = assembly.GetType("HudRepositionAPI", throwOnError: false);
				if (type != null)
				{
					_apiType = type;
					break;
				}
			}
			catch
			{
			}
		}
		if (_apiType == null)
		{
			return;
		}
		MethodInfo[] methods = _apiType.GetMethods(BindingFlags.Static | BindingFlags.Public);
		foreach (MethodInfo methodInfo in methods)
		{
			ParameterInfo[] parameters = methodInfo.GetParameters();
			if (methodInfo.Name == "Register" && parameters.Length == 5 && parameters[0].ParameterType == typeof(string) && parameters[1].ParameterType == typeof(string) && typeof(RectTransform).IsAssignableFrom(parameters[2].ParameterType))
			{
				_register = methodInfo;
			}
			else if (methodInfo.Name == "Unregister" && parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
			{
				_unregister = methodInfo;
			}
		}
		_available = _register != null && _unregister != null;
	}
}
[HarmonyPatch]
public static class RedactedPatches
{
	[HarmonyPatch(typeof(MissionSelectButton), "Setup", new Type[]
	{
		typeof(MissionData),
		typeof(MissionSelectWindow),
		typeof(bool),
		typeof(bool),
		typeof(bool)
	})]
	[HarmonyPostfix]
	private static void MissionSelectButton_Setup_Postfix(MissionSelectButton __instance)
	{
		try
		{
			if (SparrohPlugin.Scanner != null && !((Object)(object)__instance == (Object)null))
			{
				ref MissionData mission = ref __instance.Mission;
				SparrohPlugin.Scanner.ObserveMission(ref mission);
			}
		}
		catch
		{
		}
	}

	[HarmonyPatch(typeof(MissionSelectWindow), "Setup")]
	[HarmonyPostfix]
	private static void MissionSelectWindow_Setup_Postfix()
	{
		try
		{
			SparrohPlugin.Scanner?.ForceRescan();
		}
		catch
		{
		}
	}
}
[BepInPlugin("sparroh.redactednotification", "RedactedNotification", "1.0.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class SparrohPlugin : BaseUnityPlugin
{
	public const string PluginGUID = "sparroh.redactednotification";

	public const string PluginName = "RedactedNotification";

	public const string PluginVersion = "1.0.1";

	internal static ManualLogSource Logger;

	private Harmony _harmony;

	private RedactedHUD _hud;

	internal static RedactedBoardScanner Scanner { get; private set; }

	private void Awake()
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		Logger = ((BaseUnityPlugin)this).Logger;
		try
		{
			_harmony = new Harmony("sparroh.redactednotification");
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Failed to create Harmony instance: " + ex.Message));
			return;
		}
		ConfigFile configFile = ((BaseUnityPlugin)this).Config;
		try
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.redactednotification.cfg");
			fileSystemWatcher.Changed += delegate
			{
				try
				{
					configFile.Reload();
				}
				catch
				{
				}
			};
			fileSystemWatcher.EnableRaisingEvents = true;
		}
		catch (Exception ex2)
		{
			Logger.LogWarning((object)("Failed to set up config watcher: " + ex2.Message));
		}
		try
		{
			Scanner = new RedactedBoardScanner();
			_hud = new RedactedHUD(configFile, Scanner);
		}
		catch (Exception ex3)
		{
			Logger.LogError((object)("Failed to initialize RedactedNotification: " + ex3.Message));
		}
		try
		{
			_harmony.PatchAll();
		}
		catch (Exception ex4)
		{
			Logger.LogError((object)("Failed to apply Harmony patches: " + ex4.Message));
		}
		Logger.LogInfo((object)"RedactedNotification v1.0.1 loaded.");
	}

	private void Update()
	{
		try
		{
			Scanner?.Update();
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Error in RedactedBoardScanner.Update(): " + ex.Message));
		}
		try
		{
			_hud?.UpdateHudVisibility();
		}
		catch (Exception ex2)
		{
			Logger.LogError((object)("Error in RedactedHUD.UpdateHudVisibility(): " + ex2.Message));
		}
		try
		{
			_hud?.Update();
		}
		catch (Exception ex3)
		{
			Logger.LogError((object)("Error in RedactedHUD.Update(): " + ex3.Message));
		}
	}

	private void OnDestroy()
	{
		try
		{
			_hud?.OnDestroy();
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Error in RedactedHUD.OnDestroy(): " + ex.Message));
		}
		try
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
		catch (Exception ex2)
		{
			Logger.LogError((object)("Error unpatching Harmony: " + ex2.Message));
		}
	}
}
public sealed class RedactedBoardScanner
{
	private int _cachedSeed = int.MinValue;

	private bool _hasRedactedOnBoard;

	private int _redactedIndex = -1;

	private MissionModifier _redactedModifier;

	private bool _resolveAttempted;

	private int _matchCount;

	public bool HasRedactedOnBoard => _hasRedactedOnBoard;

	public int MatchCount => _matchCount;

	public MissionModifier RedactedModifier => _redactedModifier;

	public int RedactedIndex => _redactedIndex;

	public int LastScannedSeed => _cachedSeed;

	public bool IsResolved
	{
		get
		{
			if (_redactedIndex >= 0)
			{
				return (Object)(object)_redactedModifier != (Object)null;
			}
			return false;
		}
	}

	public void Update()
	{
		try
		{
			if (!((Object)(object)Global.Instance == (Object)null) && (IsResolved || TryResolveRedacted()))
			{
				int missionSelectSeed = Global.MissionSelectSeed;
				if (missionSelectSeed != _cachedSeed)
				{
					_cachedSeed = missionSelectSeed;
					RescanBoard(missionSelectSeed);
				}
			}
		}
		catch (Exception ex)
		{
			SparrohPlugin.Logger.LogError((object)("RedactedBoardScanner.Update failed: " + ex.Message));
		}
	}

	public void ForceRescan()
	{
		if (!((Object)(object)Global.Instance == (Object)null) && (IsResolved || TryResolveRedacted()))
		{
			_cachedSeed = Global.MissionSelectSeed;
			RescanBoard(_cachedSeed);
		}
	}

	public void ObserveMission(ref MissionData mission)
	{
		if ((IsResolved || TryResolveRedacted()) && MissionHasRedacted(ref mission) && !_hasRedactedOnBoard)
		{
			_hasRedactedOnBoard = true;
			SparrohPlugin.Logger.LogInfo((object)"ERROR REDACTED observed on mission select board.");
		}
	}

	public bool TryResolveRedacted()
	{
		if (IsResolved)
		{
			return true;
		}
		if ((Object)(object)Global.Instance == (Object)null || Global.Instance.MissionModifiers == null)
		{
			return false;
		}
		if (_resolveAttempted)
		{
			_ = _redactedIndex;
			_ = 0;
		}
		_resolveAttempted = true;
		WeightedArray<MissionModifier> missionModifiers = Global.Instance.MissionModifiers;
		int length = missionModifiers.Length;
		for (int i = 0; i < length; i++)
		{
			MissionModifier val = missionModifiers[i];
			if (!((Object)(object)val == (Object)null) && IsErrorRedacted(val))
			{
				_redactedIndex = i;
				_redactedModifier = val;
				SparrohPlugin.Logger.LogInfo((object)$"Resolved ERROR REDACTED modifier at index {i} (APIName='{val.APIName}', Name='{SafeName(val)}').");
				return true;
			}
		}
		for (int j = 0; j < length; j++)
		{
			MissionModifier val2 = missionModifiers[j];
			if (!((Object)(object)val2 == (Object)null))
			{
				string text = val2.APIName ?? string.Empty;
				string text2 = SafeName(val2);
				string text3 = (text + " " + text2).ToLowerInvariant();
				if (text3.Contains("redact") || text3.Contains("error redacted") || text3.Contains("error_redacted"))
				{
					_redactedIndex = j;
					_redactedModifier = val2;
					SparrohPlugin.Logger.LogInfo((object)$"Resolved ERROR REDACTED modifier (fallback) at index {j} (APIName='{text}').");
					return true;
				}
			}
		}
		return false;
	}

	private static string SafeName(MissionModifier mod)
	{
		try
		{
			return ((mod != null) ? mod.Name : null) ?? string.Empty;
		}
		catch
		{
			return string.Empty;
		}
	}

	private static bool IsErrorRedacted(MissionModifier mod)
	{
		if ((Object)(object)mod == (Object)null)
		{
			return false;
		}
		string text = (mod.APIName ?? string.Empty).ToLowerInvariant();
		if ((text.Contains("error_redacted") || text.Contains("error-redacted") || text == "redacted" || text.Contains("redacted")) && text.Contains("redact"))
		{
			return true;
		}
		try
		{
			string text2 = (mod.Name ?? string.Empty).ToLowerInvariant();
			if (text2.Contains("error") && text2.Contains("redact"))
			{
				return true;
			}
			if (text2 == "error redacted" || text2.Contains("error redacted"))
			{
				return true;
			}
		}
		catch
		{
		}
		return false;
	}

	private void RescanBoard(int currentSeed)
	{
		_hasRedactedOnBoard = false;
		_matchCount = 0;
		if ((Object)(object)Global.Instance == (Object)null || Global.Instance.Regions == null)
		{
			return;
		}
		try
		{
			Mission mission = Global.GetMission("intro");
			if ((Object)(object)mission != (Object)null && PlayerData.Instance != null && !PlayerData.Instance.HasCompletedMission(mission))
			{
				SparrohPlugin.Logger.LogDebug((object)"Board scan skipped: intro mission not completed.");
				return;
			}
		}
		catch
		{
		}
		WorldRegion[] regions = Global.Instance.Regions;
		foreach (WorldRegion val in regions)
		{
			if (!((Object)(object)val == (Object)null) && !val.LockRegion)
			{
				ScanRegion(val, currentSeed);
			}
		}
		if (_hasRedactedOnBoard)
		{
			SparrohPlugin.Logger.LogInfo((object)$"ERROR REDACTED present on mission board (seed={currentSeed}, matches={_matchCount}).");
		}
		else
		{
			SparrohPlugin.Logger.LogDebug((object)$"Board scan complete (seed={currentSeed}): no ERROR REDACTED.");
		}
	}

	private void ScanRegion(WorldRegion region, int currentSeed)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: 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_00a5: 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_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: 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_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b1: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_023d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: 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_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)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		int[] array = new int[Global.Instance.Missions.Length];
		int num = FillValidMissions(region.Flags, array);
		Random val = default(Random);
		((Random)(ref val))..ctor(MathUtil.Squirrel3Hash((region.ID + 3173412) * 71239192, currentSeed));
		bool[] array2 = new bool[Global.Instance.Missions.Length];
		Random val2 = default(Random);
		MissionData data = default(MissionData);
		for (int i = 0; i < 8; i++)
		{
			if (num == 0)
			{
				num = FillValidMissions(region.Flags, array);
			}
			if (num == 0)
			{
				break;
			}
			int num2 = ((Random)(ref val)).Next() + 1;
			((Random)(ref val2))..ctor(MathUtil.Squirrel3Hash(num2, currentSeed));
			LevelFlags val3 = region.Flags;
			bool flag = false;
			if (i >= 7 && (region.Flags & 0x8000) != 0)
			{
				SceneData[] legacyScenes = region.LegacyScenes;
				if (legacyScenes != null && legacyScenes.Length != 0)
				{
					flag = true;
					val3 = (LevelFlags)(val3 & -32769);
					for (int num3 = num - 1; num3 >= 0; num3--)
					{
						if ((Global.Instance.Missions[array[num3]].MissionFlags & 0x400) == 0)
						{
							array[num3] = array[num - 1];
							num--;
						}
					}
				}
			}
			if (num == 0)
			{
				num = FillValidMissions(val3, array);
			}
			if (num == 0)
			{
				break;
			}
			int num4 = ((Random)(ref val2)).Next(num);
			int num5 = array[num4];
			array[num4] = array[num - 1];
			num--;
			array2[num5] = true;
			Mission val4 = Global.Instance.Missions[num5];
			if (!((Object)(object)val4 == (Object)null))
			{
				SceneData[] array3 = ((flag && region.LegacyScenes != null && region.LegacyScenes.Length != 0) ? region.LegacyScenes : region.Scenes);
				if (array3 != null && array3.Length != 0)
				{
					SceneData val5 = array3[((Random)(ref val2)).Next(array3.Length)];
					((MissionData)(ref data))..ctor(num2, val4, region, val5, Global.Instance.DefaultMissionContainer, val4.GetAdditionalData());
					CheckAndCount(ref data);
				}
			}
		}
		for (int j = 0; j < Global.Instance.Missions.Length; j++)
		{
			Mission val6 = Global.Instance.Missions[j];
			if (!((Object)(object)val6 == (Object)null))
			{
				if ((val6.MissionFlags & 1) == 0 && val6.ShowHiddenMissionInSelectScreen(region))
				{
					int missionSeed = ((Random)(ref val)).Next() + 1;
					AddSpecialMission(val6, missionSeed, region, currentSeed, spawnInDesignedScene: false);
				}
				else if ((val6.MissionFlags & 0x20) != 0 && !array2[j])
				{
					array2[j] = true;
					int missionSeed2 = ((Random)(ref val)).Next() + 1;
					bool spawnInDesignedScene = (val6.MissionFlags & 0x400) != 0 && ((Random)(ref val)).NextFloat() <= 0.35f;
					AddSpecialMission(val6, missionSeed2, region, currentSeed, spawnInDesignedScene);
				}
			}
		}
		for (int k = 0; k < Global.Instance.Missions.Length; k++)
		{
			Mission val7 = Global.Instance.Missions[k];
			if (!((Object)(object)val7 == (Object)null) && (val7.MissionFlags & 0x80) != 0)
			{
				float rareSpawnChance = val7.GetRareSpawnChance();
				if (((Random)(ref val)).NextFloat() < rareSpawnChance)
				{
					int missionSeed3 = ((Random)(ref val)).Next() + 1;
					AddSpecialMission(val7, missionSeed3, region, currentSeed, spawnInDesignedScene: false);
				}
			}
		}
	}

	private void AddSpecialMission(Mission mission, int missionSeed, WorldRegion region, int currentSeed, bool spawnInDesignedScene)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: 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)
		Random val = default(Random);
		((Random)(ref val))..ctor(MathUtil.Squirrel3Hash(missionSeed, currentSeed));
		SceneData[] array = region.Scenes;
		if (spawnInDesignedScene && (region.Flags & 0x8000) != 0)
		{
			SceneData[] legacyScenes = region.LegacyScenes;
			if (legacyScenes != null && legacyScenes.Length != 0)
			{
				array = legacyScenes;
			}
		}
		if (array != null && array.Length != 0)
		{
			SceneData val2 = array[((Random)(ref val)).Next(array.Length)];
			MissionData data = default(MissionData);
			((MissionData)(ref data))..ctor(missionSeed, mission, region, val2, Global.Instance.DefaultMissionContainer, mission.GetAdditionalData());
			CheckAndCount(ref data);
		}
	}

	private void CheckAndCount(ref MissionData data)
	{
		if (MissionHasRedacted(ref data))
		{
			_hasRedactedOnBoard = true;
			_matchCount++;
		}
	}

	public bool MissionHasRedacted(ref MissionData data)
	{
		if (!IsResolved)
		{
			return false;
		}
		int modifierCount = ((MissionData)(ref data)).GetModifierCount();
		if (modifierCount <= 0)
		{
			return false;
		}
		for (int i = 0; i < modifierCount; i++)
		{
			if (((MissionData)(ref data)).GetModifier(i) == _redactedIndex)
			{
				return true;
			}
		}
		return false;
	}

	private static int FillValidMissions(LevelFlags compatibleLevels, int[] indexBuffer, int onlyThisIndex = -1)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: 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_0058: 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_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: 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_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: 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_009c: Unknown result type (might be due to invalid IL or missing references)
		Mission[] missions = Global.Instance.Missions;
		int result = 0;
		for (int i = 0; i < missions.Length; i++)
		{
			if (onlyThisIndex >= 0)
			{
				indexBuffer[result++] = onlyThisIndex;
			}
			else if ((missions[i].MissionFlags & 0x80) == 0)
			{
				bool flag = false;
				if ((missions[i].MissionFlags & 0x200) != 0 && (compatibleLevels & 0x8000) != 0)
				{
					flag = true;
				}
				bool flag2 = false;
				if ((missions[i].MissionFlags & 0x400) != 0 && (compatibleLevels & 0x8000) == 0)
				{
					flag2 = true;
				}
				if ((flag || flag2) && missions[i].CanBeSelected() && (missions[i].CompatibleLevels & 0x40F0 & compatibleLevels) != 0 && (missions[i].MissionFlags & 2) == 0)
				{
					indexBuffer[result++] = i;
				}
			}
		}
		return result;
	}
}
public sealed class RedactedHUD
{
	private readonly ConfigFile _configFile;

	private readonly RedactedBoardScanner _scanner;

	private ConfigEntry<bool> _enableHud;

	private ConfigEntry<bool> _showWhenNotDetected;

	private ConfigEntry<bool> _enableBlink;

	private ConfigEntry<float> _blinkSpeed;

	private ConfigEntry<float> _blinkMinAlpha;

	private ConfigEntry<float> _anchorX;

	private ConfigEntry<float> _anchorY;

	private ConfigEntry<string> _alertText;

	private ConfigEntry<string> _idleText;

	private HudHandle _hud;

	private Image _iconImage;

	private Sprite _fallbackTriangle;

	private bool _lastDetected;

	private bool _lastShowIdle;

	private Color _baseAlertColor = UIColors.Orchid;

	private Color _baseIdleColor = UIColors.TextMuted;

	public static RedactedHUD Instance { get; private set; }

	private bool IsHudAlive
	{
		get
		{
			if (HudHandle.IsValid(_hud))
			{
				return _hud.Primary != null;
			}
			return false;
		}
	}

	public RedactedHUD(ConfigFile configFile, RedactedBoardScanner scanner)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		_configFile = configFile;
		_scanner = scanner;
		Instance = this;
		try
		{
			_enableHud = configFile.Bind<bool>("General", "EnableHUD", true, "Show the ERROR REDACTED board notification on the player HUD.");
			_showWhenNotDetected = configFile.Bind<bool>("General", "ShowWhenNotDetected", false, "When enabled, always show a grey idle indicator (\"no ERROR detected.\") when ERROR REDACTED is not on the board. When disabled, the HUD is hidden until the modifier appears.");
			_alertText = configFile.Bind<string>("General", "AlertText", "ERROR REDACTED has appeared!", "Text shown when ERROR REDACTED is on the current mission board.");
			_idleText = configFile.Bind<string>("General", "IdleText", "no ERROR detected.", "Text shown in idle mode when ERROR REDACTED is not on the board.");
			_enableBlink = configFile.Bind<bool>("General", "EnableBlink", true, "Pulse the alert HUD when ERROR REDACTED is on the board so it is easier to notice.");
			_blinkSpeed = configFile.Bind<float>("General", "BlinkSpeed", 2f, "Blink rate in full cycles per second (soft alpha pulse). Reasonable range: 1–3.");
			_blinkMinAlpha = configFile.Bind<float>("General", "BlinkMinAlpha", 0.35f, "Minimum alpha during the dim phase of the blink (0–1). Higher = subtler blink.");
			_anchorX = configFile.Bind<float>("HUD Positioning", "AnchorX", 0.5f, "X anchor position for the notification (0-1).");
			_anchorY = configFile.Bind<float>("HUD Positioning", "AnchorY", 0.12f, "Y anchor position for the notification (0-1).");
			_enableHud.SettingChanged += delegate
			{
				OnEnableChanged();
			};
			_showWhenNotDetected.SettingChanged += delegate
			{
				RefreshVisual(force: true);
			};
			_alertText.SettingChanged += delegate
			{
				RefreshVisual(force: true);
			};
			_idleText.SettingChanged += delegate
			{
				RefreshVisual(force: true);
			};
			_enableBlink.SettingChanged += delegate
			{
				ApplyBlinkAlpha(1f);
			};
			_blinkMinAlpha.SettingChanged += delegate
			{
			};
			_anchorX.SettingChanged += delegate
			{
				OnAnchorChanged();
			};
			_anchorY.SettingChanged += delegate
			{
				OnAnchorChanged();
			};
		}
		catch (Exception ex)
		{
			SparrohPlugin.Logger.LogError((object)("Failed to initialize RedactedHUD config: " + ex.Message));
		}
	}

	public void Update()
	{
		try
		{
			if (_enableHud == null || !_enableHud.Value)
			{
				if (IsHudAlive && _hud.IsActive)
				{
					_hud.SetActive(false);
				}
				return;
			}
			if (_hud != null && !IsHudAlive)
			{
				ClearDestroyedHud();
			}
			if ((Object)(object)Player.LocalPlayer == (Object)null || (Object)(object)Player.LocalPlayer.PlayerLook == (Object)null || (Object)(object)Player.LocalPlayer.PlayerLook.Reticle == (Object)null)
			{
				return;
			}
			bool flag = _scanner != null && _scanner.HasRedactedOnBoard;
			if (!flag && (_showWhenNotDetected == null || !_showWhenNotDetected.Value))
			{
				if (IsHudAlive)
				{
					_hud.SetActive(false);
				}
				return;
			}
			if (!IsHudAlive)
			{
				CreateHud();
				if (!IsHudAlive)
				{
					return;
				}
			}
			_hud.SetActive(true);
			RefreshVisual(force: false);
			UpdateBlink(flag);
		}
		catch (Exception ex)
		{
			SparrohPlugin.Logger.LogError((object)("Error in RedactedHUD.Update(): " + ex.Message));
		}
	}

	private void UpdateBlink(bool detected)
	{
		if (IsHudAlive)
		{
			if (!detected || _enableBlink == null || !_enableBlink.Value)
			{
				ApplyBlinkAlpha(1f);
				return;
			}
			float num = ((_blinkSpeed != null) ? Mathf.Max(0.1f, _blinkSpeed.Value) : 2f);
			float num2 = ((_blinkMinAlpha != null) ? Mathf.Clamp01(_blinkMinAlpha.Value) : 0.35f);
			float num3 = Mathf.PingPong(Time.unscaledTime * num, 1f);
			float alpha = Mathf.Lerp(num2, 1f, num3);
			ApplyBlinkAlpha(alpha);
		}
	}

	private void ApplyBlinkAlpha(float alpha)
	{
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: 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)
		if (IsHudAlive)
		{
			alpha = Mathf.Clamp01(alpha);
			if (_hud.Primary != null && (Object)(object)_hud.Primary.Tmp != (Object)null)
			{
				Color color = (_lastDetected ? _baseAlertColor : _baseIdleColor);
				color.a = alpha;
				((Graphic)_hud.Primary.Tmp).color = color;
			}
			if ((Object)(object)_iconImage != (Object)null)
			{
				Color color2 = ((Graphic)_iconImage).color;
				float num = (_lastDetected ? 1f : 0.85f);
				color2.a = num * alpha;
				((Graphic)_iconImage).color = color2;
			}
		}
	}

	public void UpdateHudVisibility()
	{
		if (!IsHudAlive)
		{
			ClearDestroyedHud();
			return;
		}
		if (_enableHud == null || !_enableHud.Value)
		{
			_hud.SetActive(false);
			return;
		}
		bool active = (_scanner != null && _scanner.HasRedactedOnBoard) || (_showWhenNotDetected != null && _showWhenNotDetected.Value);
		_hud.SetActive(active);
	}

	private void OnEnableChanged()
	{
		if (_enableHud != null && !_enableHud.Value && _hud != null)
		{
			DestroyHud();
		}
		UpdateHudVisibility();
	}

	private void OnAnchorChanged()
	{
		if (IsHudAlive)
		{
			_hud.SetAnchor(_anchorX.Value, _anchorY.Value);
		}
	}

	private void ClearDestroyedHud()
	{
		if (_hud == null)
		{
			return;
		}
		try
		{
			if ((Object)(object)_hud.Rect != (Object)null)
			{
				HudRepositionClient.Unregister("sparroh.redactednotification");
			}
		}
		catch
		{
		}
		_hud = null;
		_iconImage = null;
	}

	private void CreateHud()
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: 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_00d2: 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_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		if (IsHudAlive)
		{
			return;
		}
		ClearDestroyedHud();
		_hud = HudBuilder.Create("RedactedNotificationHUD").ParentToReticle(true).Anchor(_anchorX.Value, _anchorY.Value)
			.Pivot(new Vector2(0.5f, 0.5f))
			.Size(420f, 32f, true)
			.AddText("StatusText", 18f, (TextAlignmentOptions)514)
			.Build();
		if (!IsHudAlive)
		{
			return;
		}
		try
		{
			RectTransform val = UIFactory.CreateRect("RedactedIcon", (Transform)(object)_hud.Rect);
			val.anchorMin = new Vector2(0f, 0.5f);
			val.anchorMax = new Vector2(0f, 0.5f);
			val.pivot = new Vector2(0f, 0.5f);
			val.sizeDelta = UITheme.ScaledSize(28f, 28f);
			val.anchoredPosition = new Vector2(UITheme.S(4f), 0f);
			_iconImage = ((Component)val).gameObject.AddComponent<Image>();
			((Graphic)_iconImage).raycastTarget = false;
			_iconImage.preserveAspect = true;
			if (_hud.Primary != null && (Object)(object)_hud.Primary.Rect != (Object)null)
			{
				RectTransform rect = _hud.Primary.Rect;
				rect.offsetMin = new Vector2(UITheme.S(34f), rect.offsetMin.y);
			}
		}
		catch (Exception ex)
		{
			SparrohPlugin.Logger.LogWarning((object)("Could not create redacted icon: " + ex.Message));
			_iconImage = null;
		}
		HudRepositionClient.Register("sparroh.redactednotification", "ERROR REDACTED Alert", _hud.Rect, _anchorX, _anchorY);
		_lastDetected = false;
		_lastShowIdle = false;
		RefreshVisual(force: true);
	}

	private void DestroyHud()
	{
		HudRepositionClient.Unregister("sparroh.redactednotification");
		if (_hud != null)
		{
			if (_hud.IsAlive)
			{
				_hud.Destroy();
			}
			_hud = null;
		}
		_iconImage = null;
	}

	private void RefreshVisual(bool force)
	{
		//IL_007b: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: 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_010f: Unknown result type (might be due to invalid IL or missing references)
		if (!IsHudAlive)
		{
			return;
		}
		bool flag = _scanner != null && _scanner.HasRedactedOnBoard;
		bool flag2 = _showWhenNotDetected != null && _showWhenNotDetected.Value;
		if (force || flag != _lastDetected || flag2 != _lastShowIdle)
		{
			_lastDetected = flag;
			_lastShowIdle = flag2;
			if (flag)
			{
				string text = ((_alertText != null) ? _alertText.Value : "ERROR REDACTED has appeared!");
				_baseAlertColor = GetAlertColor();
				_hud.Primary.Text = text;
				((Graphic)_hud.Primary.Tmp).color = _baseAlertColor;
				ApplyIcon(alert: true);
				ApplyBlinkAlpha(1f);
			}
			else if (flag2)
			{
				string text2 = ((_idleText != null) ? _idleText.Value : "no ERROR detected.");
				_baseIdleColor = UIColors.TextMuted;
				_hud.Primary.Text = text2;
				((Graphic)_hud.Primary.Tmp).color = _baseIdleColor;
				ApplyIcon(alert: false);
				ApplyBlinkAlpha(1f);
			}
		}
	}

	private Color GetAlertColor()
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: 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_0039: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (_scanner != null && (Object)(object)_scanner.RedactedModifier != (Object)null)
			{
				return _scanner.RedactedModifier.IconColor;
			}
		}
		catch
		{
		}
		return UIColors.Orchid;
	}

	private void ApplyIcon(bool alert)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: 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)
		if ((Object)(object)_iconImage == (Object)null)
		{
			return;
		}
		Sprite val = null;
		Color alertColor = default(Color);
		if (alert)
		{
			alertColor = GetAlertColor();
			try
			{
				if (_scanner != null && (Object)(object)_scanner.RedactedModifier != (Object)null)
				{
					val = _scanner.RedactedModifier.Icon;
				}
			}
			catch
			{
			}
		}
		else
		{
			((Color)(ref alertColor))..ctor(0.45f, 0.45f, 0.48f, 0.85f);
			try
			{
				if (_scanner != null && (Object)(object)_scanner.RedactedModifier != (Object)null)
				{
					val = _scanner.RedactedModifier.Icon;
				}
			}
			catch
			{
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			val = GetFallbackTriangle();
		}
		_iconImage.sprite = val;
		((Graphic)_iconImage).color = alertColor;
		((Behaviour)_iconImage).enabled = (Object)(object)val != (Object)null;
	}

	private Sprite GetFallbackTriangle()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: 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_010e: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_fallbackTriangle != (Object)null)
		{
			return _fallbackTriangle;
		}
		Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false);
		((Texture)val).filterMode = (FilterMode)1;
		((Texture)val).wrapMode = (TextureWrapMode)1;
		Color val2 = default(Color);
		((Color)(ref val2))..ctor(0f, 0f, 0f, 0f);
		Color white = Color.white;
		for (int i = 0; i < 32; i++)
		{
			for (int j = 0; j < 32; j++)
			{
				float num = ((float)j + 0.5f) / 32f;
				float num2 = ((float)i + 0.5f) / 32f;
				float num3 = num2 * 0.5f;
				bool flag = num2 >= 0.12f && num2 <= 0.92f && Mathf.Abs(num - 0.5f) <= num3 * 0.9f;
				val.SetPixel(j, i, flag ? white : val2);
			}
		}
		val.Apply(false, true);
		_fallbackTriangle = Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 100f);
		return _fallbackTriangle;
	}

	public void OnDestroy()
	{
		try
		{
			DestroyHud();
		}
		catch (Exception ex)
		{
			SparrohPlugin.Logger.LogError((object)("Error in RedactedHUD.OnDestroy(): " + ex.Message));
		}
	}
}
namespace RedactedNotification
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "RedactedNotification";

		public const string PLUGIN_NAME = "RedactedNotification";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}