Decompiled source of RedactedNotification v1.0.2

BepInEx/plugins/RedactedNotification.dll

Decompiled 2 months 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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Sparroh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyProduct("RedactedNotification")]
[assembly: AssemblyTitle("RedactedNotification")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.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 ConfigManager
{
	private const float DebounceSeconds = 0.25f;

	private static ConfigFile config;

	private static ManualLogSource logger;

	private static FileSystemWatcher configWatcher;

	private static volatile bool pendingRefresh;

	private static volatile bool reloadPending;

	private static float lastReloadTime;

	public static ConfigEntry<bool> EnableHud { get; private set; }

	public static ConfigEntry<bool> ShowWhenNotDetected { get; private set; }

	public static ConfigEntry<string> AlertText { get; private set; }

	public static ConfigEntry<string> IdleText { get; private set; }

	public static ConfigEntry<bool> EnableBlink { get; private set; }

	public static ConfigEntry<float> BlinkSpeed { get; private set; }

	public static ConfigEntry<float> BlinkMinAlpha { get; private set; }

	public static HudAnchors Anchors { get; private set; }

	public static void Initialize(ConfigFile configFile, ManualLogSource log)
	{
		config = configFile;
		logger = log;
		EnableHud = config.Bind<bool>("General", "Enable Notification", true, "Show the ERROR REDACTED board notification on the player HUD.");
		ShowWhenNotDetected = config.Bind<bool>("General", "Show When Not Detected", 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 = config.Bind<string>("General", "Alert Text", "ERROR REDACTED has appeared!", "Text shown when ERROR REDACTED is on the current mission board.");
		IdleText = config.Bind<string>("General", "Idle Text", "no ERROR detected.", "Text shown in idle mode when ERROR REDACTED is not on the board.");
		EnableBlink = config.Bind<bool>("General", "Enable Blink", true, "Pulse the alert HUD when ERROR REDACTED is on the board so it is easier to notice.");
		BlinkSpeed = config.Bind<float>("General", "Blink Speed", 2f, "Blink rate in full cycles per second (soft alpha pulse). Reasonable range: 1–3.");
		BlinkMinAlpha = config.Bind<float>("General", "Blink Min Alpha", 0.35f, "Minimum alpha during the dim phase of the blink (0–1). Higher = subtler blink.");
		Anchors = HudAnchors.Bind(config, "Notification", 0.5f, 0.12f, "HUD Positioning");
		EnableHud.SettingChanged += OnSettingChanged;
		ShowWhenNotDetected.SettingChanged += OnSettingChanged;
		AlertText.SettingChanged += OnSettingChanged;
		IdleText.SettingChanged += OnSettingChanged;
		EnableBlink.SettingChanged += OnSettingChanged;
		BlinkSpeed.SettingChanged += OnSettingChanged;
		BlinkMinAlpha.SettingChanged += OnSettingChanged;
		try
		{
			SetupFileWatcher();
		}
		catch (Exception ex)
		{
			logger.LogError((object)("Error setting up config file watcher: " + ex.Message));
		}
	}

	public static void Tick()
	{
		if (!reloadPending || Time.unscaledTime - lastReloadTime < 0.25f)
		{
			return;
		}
		reloadPending = false;
		lastReloadTime = Time.unscaledTime;
		try
		{
			config.Reload();
			pendingRefresh = true;
			logger.LogInfo((object)"Config reloaded from disk.");
		}
		catch (Exception ex)
		{
			logger.LogError((object)("Error reloading config: " + ex.Message));
		}
	}

	public static bool ConsumePendingRefresh()
	{
		if (!pendingRefresh)
		{
			return false;
		}
		pendingRefresh = false;
		return true;
	}

	public static void Dispose()
	{
		if (EnableHud != null)
		{
			EnableHud.SettingChanged -= OnSettingChanged;
		}
		if (ShowWhenNotDetected != null)
		{
			ShowWhenNotDetected.SettingChanged -= OnSettingChanged;
		}
		if (AlertText != null)
		{
			AlertText.SettingChanged -= OnSettingChanged;
		}
		if (IdleText != null)
		{
			IdleText.SettingChanged -= OnSettingChanged;
		}
		if (EnableBlink != null)
		{
			EnableBlink.SettingChanged -= OnSettingChanged;
		}
		if (BlinkSpeed != null)
		{
			BlinkSpeed.SettingChanged -= OnSettingChanged;
		}
		if (BlinkMinAlpha != null)
		{
			BlinkMinAlpha.SettingChanged -= OnSettingChanged;
		}
		if (configWatcher != null)
		{
			configWatcher.EnableRaisingEvents = false;
			configWatcher.Changed -= OnConfigFileChanged;
			configWatcher.Created -= OnConfigFileChanged;
			configWatcher.Renamed -= OnConfigFileChanged;
			configWatcher.Dispose();
			configWatcher = null;
		}
	}

	private static void SetupFileWatcher()
	{
		configWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.redactednotification.cfg");
		configWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite;
		configWatcher.Changed += OnConfigFileChanged;
		configWatcher.Created += OnConfigFileChanged;
		configWatcher.Renamed += OnConfigFileChanged;
		configWatcher.EnableRaisingEvents = true;
	}

	private static void OnConfigFileChanged(object sender, FileSystemEventArgs e)
	{
		reloadPending = true;
	}

	private static void OnSettingChanged(object sender, EventArgs e)
	{
		pendingRefresh = true;
	}
}
[BepInPlugin("sparroh.redactednotification", "RedactedNotification", "1.0.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class RedactedNotificationPlugin : BaseUnityPlugin
{
	public const string PluginGUID = "sparroh.redactednotification";

	public const string PluginName = "RedactedNotification";

	public const string PluginVersion = "1.0.2";

	internal static ManualLogSource Logger;

	private Harmony _harmony;

	private RedactedHUD _hud;

	internal static RedactedBoardScanner Scanner { get; private set; }

	private void Awake()
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		Logger = ((BaseUnityPlugin)this).Logger;
		ConfigManager.Initialize(((BaseUnityPlugin)this).Config, Logger);
		try
		{
			_harmony = new Harmony("sparroh.redactednotification");
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Failed to create Harmony instance: " + ex.Message));
			return;
		}
		try
		{
			Scanner = new RedactedBoardScanner();
			_hud = new RedactedHUD(Scanner);
		}
		catch (Exception ex2)
		{
			Logger.LogError((object)("Failed to initialize RedactedNotification: " + ex2.Message));
		}
		try
		{
			_harmony.PatchAll();
		}
		catch (Exception ex3)
		{
			Logger.LogError((object)("Failed to apply Harmony patches: " + ex3.Message));
		}
		Logger.LogInfo((object)"RedactedNotification v1.0.2 loaded.");
	}

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

	private void OnDestroy()
	{
		try
		{
			_hud?.OnDestroy();
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Error in RedactedHUD.OnDestroy(): " + ex.Message));
		}
		ConfigManager.Dispose();
		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 bool _resolveAttempted;

	public bool HasRedactedOnBoard { get; private set; }

	public int MatchCount { get; private set; }

	public MissionModifier RedactedModifier { get; private set; }

	public int RedactedIndex { get; private set; } = -1;

	public int LastScannedSeed { get; private set; } = int.MinValue;

	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 != LastScannedSeed)
				{
					LastScannedSeed = missionSelectSeed;
					RescanBoard(missionSelectSeed);
				}
			}
		}
		catch (Exception ex)
		{
			RedactedNotificationPlugin.Logger.LogError((object)("RedactedBoardScanner.Update failed: " + ex.Message));
		}
	}

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

	public void ObserveMission(ref MissionData mission)
	{
		if ((IsResolved || TryResolveRedacted()) && MissionHasRedacted(ref mission) && !HasRedactedOnBoard)
		{
			HasRedactedOnBoard = true;
			RedactedNotificationPlugin.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;
				RedactedNotificationPlugin.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;
					RedactedNotificationPlugin.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))
			{
				RedactedNotificationPlugin.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)
		{
			RedactedNotificationPlugin.Logger.LogInfo((object)$"ERROR REDACTED present on mission board (seed={currentSeed}, matches={MatchCount}).");
		}
		else
		{
			RedactedNotificationPlugin.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 & 0x640F0 & compatibleLevels) != 0 && (missions[i].MissionFlags & 2) == 0)
				{
					indexBuffer[result++] = i;
				}
			}
		}
		return result;
	}
}
public sealed class RedactedHUD
{
	private readonly RedactedBoardScanner _scanner;

	private Color _baseAlertColor = UIColors.Orchid;

	private Color _baseIdleColor = UIColors.TextMuted;

	private Sprite _fallbackTriangle;

	private HudHandle _hud;

	private Image _iconImage;

	private bool _lastDetected;

	private bool _lastShowIdle;

	public static RedactedHUD Instance { get; private set; }

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

	public RedactedHUD(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)
		_scanner = scanner;
		Instance = this;
	}

	public void OnConfigChanged()
	{
		if (ConfigManager.EnableHud != null && !ConfigManager.EnableHud.Value && _hud != null)
		{
			DestroyHud();
		}
		UpdateHudVisibility();
		RefreshVisual(force: true);
		ApplyBlinkAlpha(1f);
	}

	public void Update()
	{
		try
		{
			if (ConfigManager.EnableHud == null || !ConfigManager.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 && (ConfigManager.ShowWhenNotDetected == null || !ConfigManager.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)
		{
			RedactedNotificationPlugin.Logger.LogError((object)("Error in RedactedHUD.Update(): " + ex.Message));
		}
	}

	private void UpdateBlink(bool detected)
	{
		if (IsHudAlive)
		{
			if (!detected || ConfigManager.EnableBlink == null || !ConfigManager.EnableBlink.Value)
			{
				ApplyBlinkAlpha(1f);
				return;
			}
			float num = ((ConfigManager.BlinkSpeed != null) ? Mathf.Max(0.1f, ConfigManager.BlinkSpeed.Value) : 2f);
			float num2 = ((ConfigManager.BlinkMinAlpha != null) ? Mathf.Clamp01(ConfigManager.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 (ConfigManager.EnableHud == null || !ConfigManager.EnableHud.Value)
		{
			_hud.SetActive(false);
			return;
		}
		bool active = (_scanner != null && _scanner.HasRedactedOnBoard) || (ConfigManager.ShowWhenNotDetected != null && ConfigManager.ShowWhenNotDetected.Value);
		_hud.SetActive(active);
	}

	private void ClearDestroyedHud()
	{
		_hud = null;
		_iconImage = null;
	}

	private void CreateHud()
	{
		//IL_0059: 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_00d1: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		if (IsHudAlive)
		{
			return;
		}
		ClearDestroyedHud();
		HudAnchors anchors = ConfigManager.Anchors;
		float num = ((anchors != null) ? anchors.XValue : 0.5f);
		float num2 = ((anchors != null) ? anchors.YValue : 0.12f);
		_hud = HudBuilder.Create("RedactedNotificationHUD").ParentToReticle(true).Anchor(num, num2)
			.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)
		{
			RedactedNotificationPlugin.Logger.LogWarning((object)("Could not create redacted icon: " + ex.Message));
			_iconImage = null;
		}
		if (anchors != null)
		{
			_hud.EnableReposition("sparroh.redactednotification", "ERROR REDACTED Alert", anchors);
		}
		_lastDetected = false;
		_lastShowIdle = false;
		RefreshVisual(force: true);
	}

	private void DestroyHud()
	{
		if (_hud != null)
		{
			if (_hud.IsAlive)
			{
				_hud.Destroy();
			}
			_hud = null;
		}
		_iconImage = null;
	}

	private void RefreshVisual(bool force)
	{
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		if (!IsHudAlive)
		{
			return;
		}
		bool flag = _scanner != null && _scanner.HasRedactedOnBoard;
		bool flag2 = ConfigManager.ShowWhenNotDetected != null && ConfigManager.ShowWhenNotDetected.Value;
		if (force || flag != _lastDetected || flag2 != _lastShowIdle)
		{
			_lastDetected = flag;
			_lastShowIdle = flag2;
			if (flag)
			{
				string text = ((ConfigManager.AlertText != null) ? ConfigManager.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 = ((ConfigManager.IdleText != null) ? ConfigManager.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)
		{
			RedactedNotificationPlugin.Logger.LogError((object)("Error in RedactedHUD.OnDestroy(): " + ex.Message));
		}
	}
}
[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 (RedactedNotificationPlugin.Scanner != null && !((Object)(object)__instance == (Object)null))
			{
				ref MissionData mission = ref __instance.Mission;
				RedactedNotificationPlugin.Scanner.ObserveMission(ref mission);
			}
		}
		catch
		{
		}
	}

	[HarmonyPatch(typeof(MissionSelectWindow), "Setup")]
	[HarmonyPostfix]
	private static void MissionSelectWindow_Setup_Postfix()
	{
		try
		{
			RedactedNotificationPlugin.Scanner?.ForceRescan();
		}
		catch
		{
		}
	}
}
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.2";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}