Decompiled source of PrideHUD v1.0.0

BepInEx/plugins/PrideHUD/PrideHUD.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon.Movement;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("coruscnium")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Replaces every image in the player HUD with a pride flag")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0.0")]
[assembly: AssemblyProduct("PrideHUD")]
[assembly: AssemblyTitle("PrideHUD")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PrideHUD
{
	internal static class FlagLibrary
	{
		private const string PreferredDefault = "Rainbow";

		private static readonly string[] SupportedExtensions = new string[3] { ".png", ".jpg", ".jpeg" };

		private static readonly Dictionary<string, string> PathsByName = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, Sprite> SpriteCache = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);

		private static string[] _names = new string[0];

		public static string[] Names => _names;

		private static string FlagFolder
		{
			get
			{
				string location = Assembly.GetExecutingAssembly().Location;
				if (!string.IsNullOrEmpty(location))
				{
					return Path.Combine(Path.GetDirectoryName(location), "flags");
				}
				return null;
			}
		}

		public static void Scan()
		{
			PathsByName.Clear();
			string flagFolder = FlagFolder;
			string[] array;
			try
			{
				array = (Directory.Exists(flagFolder) ? Directory.GetFiles(flagFolder) : new string[0]);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Could not read '" + flagFolder + "': " + ex.Message));
				array = new string[0];
			}
			string[] array2 = array;
			foreach (string text in array2)
			{
				string fileName = Path.GetFileName(text);
				if (Array.IndexOf(SupportedExtensions, Path.GetExtension(fileName).ToLowerInvariant()) < 0)
				{
					continue;
				}
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
				if (fileNameWithoutExtension.Length != 0)
				{
					if (fileNameWithoutExtension.IndexOf(',') >= 0)
					{
						Plugin.Logger.LogWarning((object)("Skipping '" + fileName + "': commas break ModSettingsMenu's dropdown."));
					}
					else
					{
						PathsByName[fileNameWithoutExtension] = text;
					}
				}
			}
			List<string> list = new List<string>(PathsByName.Keys);
			list.Sort(StringComparer.OrdinalIgnoreCase);
			int num = list.FindIndex((string n) => string.Equals(n, "Rainbow", StringComparison.OrdinalIgnoreCase));
			if (num > 0)
			{
				string item = list[num];
				list.RemoveAt(num);
				list.Insert(0, item);
			}
			_names = list.ToArray();
			if (_names.Length == 0)
			{
				Plugin.Logger.LogWarning((object)("No flag images found in '" + flagFolder + "' — the HUD is left alone."));
			}
		}

		public static Sprite Get(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			if (SpriteCache.TryGetValue(name, out var value))
			{
				if ((Object)(object)value != (Object)null)
				{
					return value;
				}
				SpriteCache.Remove(name);
			}
			if (!PathsByName.TryGetValue(name, out var value2))
			{
				return null;
			}
			Sprite val = Load(value2);
			SpriteCache[name] = val;
			return val;
		}

		private static Sprite Load(string path)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
				if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path)))
				{
					Plugin.Logger.LogWarning((object)("Could not decode '" + Path.GetFileName(path) + "' as an image."));
					Object.Destroy((Object)(object)val);
					return null;
				}
				((Texture)val).wrapMode = (TextureWrapMode)0;
				((Texture)val).filterMode = (FilterMode)1;
				((Object)val).hideFlags = (HideFlags)61;
				Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
				((Object)obj).hideFlags = (HideFlags)61;
				((Object)obj).name = "PrideHUD:" + Path.GetFileNameWithoutExtension(path);
				return obj;
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Could not load '" + path + "': " + ex.Message));
				return null;
			}
		}
	}
	internal static class HudPainter
	{
		private sealed class Claim
		{
			public Sprite OriginalSprite;

			public Sprite OriginalOverride;

			public Color OriginalColor;

			public Sprite Applied;
		}

		private static readonly Dictionary<Image, Claim> Claims = new Dictionary<Image, Claim>();

		private static readonly List<Image> ImageBuffer = new List<Image>();

		private static readonly List<Transform> Roots = new List<Transform>();

		private static readonly List<Image> Stale = new List<Image>();

		private static bool _loggedSweepError;

		private static bool _loggedTintError;

		public static string Selection = "Rainbow";

		public static int ClaimCount => Claims.Count;

		public static void Sweep()
		{
			try
			{
				CollectRoots();
				if (Roots.Count == 0)
				{
					if (Claims.Count > 0)
					{
						DropDestroyedClaims();
					}
					return;
				}
				Sprite val = FlagLibrary.Get(Selection);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				foreach (Transform root in Roots)
				{
					((Component)root).GetComponentsInChildren<Image>(true, ImageBuffer);
					foreach (Image item in ImageBuffer)
					{
						Apply(item, val);
					}
				}
				DropDestroyedClaims();
			}
			catch (Exception arg)
			{
				if (!_loggedSweepError)
				{
					_loggedSweepError = true;
					Plugin.Logger.LogError((object)$"HUD sweep failed, skipping this pass: {arg}");
				}
			}
		}

		private static void CollectRoots()
		{
			Roots.Clear();
			PlayerLook instance = PlayerLook.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				Add((Transform)(object)instance.DefaultHUDParent);
				Add((Transform)(object)instance.StaticReticle);
				Add((Transform)(object)instance.GearHUDParent);
				Add((Transform)(object)instance.Reticle);
			}
			if ((Object)(object)MissionHUD.Instance != (Object)null)
			{
				Add(((Component)MissionHUD.Instance).transform);
			}
			static void Add(Transform t)
			{
				if ((Object)(object)t != (Object)null)
				{
					Roots.Add(t);
				}
			}
		}

		private static void Apply(Image image, Sprite flag)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)image == (Object)null)
			{
				return;
			}
			Claim value;
			bool flag2 = Claims.TryGetValue(image, out value);
			if ((flag2 || !((Object)(object)image.sprite == (Object)null)) && (flag2 || !((Object)(object)((Component)image).GetComponent<Mask>() != (Object)null)))
			{
				if (!flag2)
				{
					value = new Claim
					{
						OriginalSprite = image.sprite,
						OriginalOverride = image.overrideSprite,
						OriginalColor = ((Graphic)image).color
					};
					Claims[image] = value;
				}
				else if (image.sprite != value.Applied)
				{
					value.OriginalSprite = image.sprite;
				}
				if (image.sprite != flag)
				{
					image.sprite = flag;
					value.Applied = flag;
				}
				if ((Object)(object)image.overrideSprite != (Object)null)
				{
					value.OriginalOverride = image.overrideSprite;
					image.overrideSprite = null;
				}
				NeutraliseTint(image, value);
			}
		}

		private static void NeutraliseTint(Image image, Claim claim)
		{
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			Color color = ((Graphic)image).color;
			if (color.r != 1f || color.g != 1f || color.b != 1f)
			{
				claim.OriginalColor = new Color(color.r, color.g, color.b, claim.OriginalColor.a);
				((Graphic)image).color = new Color(1f, 1f, 1f, color.a);
			}
		}

		public static void OnGraphicRetinted(Graphic graphic)
		{
			try
			{
				Image val = (Image)(object)((graphic is Image) ? graphic : null);
				if (val != null && Claims.TryGetValue(val, out var value))
				{
					NeutraliseTint(val, value);
				}
			}
			catch (Exception arg)
			{
				if (!_loggedTintError)
				{
					_loggedTintError = true;
					Plugin.Logger.LogError((object)$"Failed to keep a HUD image untinted: {arg}");
				}
			}
		}

		private static void DropDestroyedClaims()
		{
			Stale.Clear();
			foreach (KeyValuePair<Image, Claim> claim in Claims)
			{
				if ((Object)(object)claim.Key == (Object)null)
				{
					Stale.Add(claim.Key);
				}
			}
			foreach (Image item in Stale)
			{
				Claims.Remove(item);
			}
			Stale.Clear();
		}

		public static void Restore()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<Image, Claim> claim in Claims)
			{
				Image key = claim.Key;
				Claim value = claim.Value;
				if (!((Object)(object)key == (Object)null))
				{
					try
					{
						key.sprite = value.OriginalSprite;
						key.overrideSprite = value.OriginalOverride;
						((Graphic)key).color = new Color(value.OriginalColor.r, value.OriginalColor.g, value.OriginalColor.b, ((Graphic)key).color.a);
					}
					catch (Exception ex)
					{
						Plugin.Logger.LogWarning((object)("Could not restore a HUD image: " + ex.Message));
					}
				}
			}
			Claims.Clear();
		}
	}
	[HarmonyPatch(typeof(CharacterGraphic), "UpdateGraphicColor")]
	internal static class CharacterGraphicPatch
	{
		[HarmonyPostfix]
		private static void Postfix(CharacterGraphic __instance)
		{
			HudPainter.OnGraphicRetinted(((Component)__instance).GetComponent<Graphic>());
		}
	}
	[MycoMod(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("coruscnium.pridehud", "PrideHUD", "1.0.0.0")]
	[BepInProcess("Mycopunk.exe")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "coruscnium.pridehud";

		public const string PluginName = "PrideHUD";

		public const string PluginVersion = "1.0.0.0";

		internal static ManualLogSource Logger;

		private const float SweepInterval = 0.25f;

		private static ConfigEntry<string> _flagConfig;

		private static FileSystemWatcher _configWatcher;

		private static volatile bool _pendingConfigReload;

		private Harmony _harmony;

		private float _sinceSweep;

		private void Awake()
		{
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			FlagLibrary.Scan();
			string[] names = FlagLibrary.Names;
			_flagConfig = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Flag", (names.Length != 0) ? names[0] : "Rainbow", new ConfigDescription("Which pride flag replaces every image in the HUD.\nDrop more images into the mod's 'flags' folder to add options here.", (AcceptableValueBase)(object)((names.Length != 0) ? new AcceptableValueList<string>(names) : null), Array.Empty<object>()));
			HudPainter.Selection = _flagConfig.Value;
			_flagConfig.SettingChanged += delegate
			{
				HudPainter.Selection = _flagConfig.Value;
			};
			((BaseUnityPlugin)this).Config.Save();
			try
			{
				_configWatcher = new FileSystemWatcher(Paths.ConfigPath, "coruscnium.pridehud.cfg")
				{
					NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
					EnableRaisingEvents = true
				};
				_configWatcher.Changed += OnConfigFileChanged;
				_configWatcher.Created += OnConfigFileChanged;
				_configWatcher.Renamed += OnConfigFileChanged;
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Could not start config file watcher: " + ex.Message));
			}
			_harmony = new Harmony("coruscnium.pridehud");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			Logger.LogInfo((object)string.Format("{0} loaded. {1} flag(s) available, showing {2}.", "PrideHUD", names.Length, _flagConfig.Value));
		}

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

		private void Update()
		{
			if (_pendingConfigReload)
			{
				_pendingConfigReload = false;
				((BaseUnityPlugin)this).Config.Reload();
			}
			_sinceSweep += Time.unscaledDeltaTime;
			if (!(_sinceSweep < 0.25f))
			{
				_sinceSweep = 0f;
				HudPainter.Sweep();
			}
		}

		private void OnDestroy()
		{
			HudPainter.Restore();
			if (_configWatcher != null)
			{
				_configWatcher.EnableRaisingEvents = false;
				_configWatcher.Changed -= OnConfigFileChanged;
				_configWatcher.Created -= OnConfigFileChanged;
				_configWatcher.Renamed -= OnConfigFileChanged;
				_configWatcher.Dispose();
				_configWatcher = null;
			}
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}