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)
{
}
}
}