Decompiled source of Cano Signs v1.1.0

Cano.Signs.dll

Decompiled 4 days 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 System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
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("Cano")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Enhanced signs: per-sign neon light switch, bigger character limit, rich-text codes kept in the editor, custom colour, neon, render distance.")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("Cano.Signs")]
[assembly: AssemblyTitle("Cano.Signs")]
[assembly: AssemblyVersion("1.1.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 Cano.Signs
{
	internal sealed class ConfigurationManagerAttributes
	{
		public int? Order;
	}
	internal static class Cfg
	{
		private const string General = "1 - General";

		private const string Editor = "2 - Editor";

		private const string Text = "3 - Text";

		private const string Neon = "4 - Neon";

		private const string Marks = "5 - Marks";

		private static ConfigFile _file;

		private static int _order = 100;

		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<int> CharLimit;

		public static ConfigEntry<bool> KeepRichText;

		public static ConfigEntry<bool> UseCustomColor;

		public static ConfigEntry<string> CustomColor;

		public static ConfigEntry<float> RenderDistance;

		public static ConfigEntry<bool> NeonEnabled;

		public static ConfigEntry<string> NeonColor;

		public static ConfigEntry<float> NeonBrightness;

		public static ConfigEntry<bool> NeonLight;

		public static ConfigEntry<KeyboardShortcut> MarkKey;

		public static ConfigEntry<bool> ShowIcons;

		public static ConfigEntry<string> MsgLightOn;

		public static ConfigEntry<string> MsgLightOff;

		public static ConfigEntry<string> MsgLookAtSign;

		public static void Bind(ConfigFile file)
		{
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			_file = file;
			Enabled = B("1 - General", "Enabled", def: true, "Master switch. Off = signs behave exactly like vanilla.");
			CharLimit = B("2 - Editor", "Character Limit", 999, "Maximum characters per sign (vanilla is 50).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 999));
			KeepRichText = B("2 - Editor", "Keep Rich Text Codes Visible", def: true, "Keeps tags like <color=red> visible and editable in the sign editor instead of hiding them.");
			UseCustomColor = B("3 - Text", "Use Custom Colour", def: false, "Use the colour below as the default sign text colour.");
			CustomColor = B("3 - Text", "Custom Colour (Hex)", "#FFFFFF", "Hex colour, e.g. #FFD27F.");
			RenderDistance = B("3 - Text", "Render Distance (m)", 192f, "Sign text further away than this is not rendered. 192 = always on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 192f));
			NeonEnabled = B("4 - Neon", "Neon Signs", def: false, "Glowing sign text (HDR boost, shader glow and optional light).");
			NeonColor = B("4 - Neon", "Neon Colour (Hex)", "#FFFFFF", "Neon colour for text without colour codes, e.g. #00FFFF.");
			NeonBrightness = B("4 - Neon", "Neon Brightness", 2f, "Text and glow strength. 1 = normal.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f));
			NeonLight = B("4 - Neon", "Neon Light", def: true, "Neon signs with text, within 40 m, cast a light mixed from their text colours. Individual signs can be switched off with the Marks shortcut. Disable for max performance.");
			MarkKey = B<KeyboardShortcut>("5 - Marks", "Toggle Light Shortcut", new KeyboardShortcut((KeyCode)112, (KeyCode[])(object)new KeyCode[2]
			{
				(KeyCode)304,
				(KeyCode)308
			}), "Flips the sign you look at between tick (glow and light) and X (glow only). Needs Neon Signs and Neon Light on.");
			ShowIcons = B("5 - Marks", "Show Hover Icon", def: true, "Show '[shortcut] tick / X' under the name of the sign you look at. Off = no icon (the shortcut still works).");
			MsgLightOn = B("5 - Marks", "Light On Message", "Sign light on", "Message when a sign's light is switched on (tick). Empty = no message.");
			MsgLightOff = B("5 - Marks", "Light Off Message", "Sign light off", "Message when a sign's light is switched off (X). Empty = no message.");
			MsgLookAtSign = B("5 - Marks", "Look At Sign Message", "Look at a sign to toggle its light", "Message when you press the shortcut without looking at a sign. Empty = no message.");
		}

		private static ConfigEntry<T> B<T>(string section, string key, T def, string desc, AcceptableValueBase range = null)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			return _file.Bind<T>(section, key, def, new ConfigDescription(desc, range, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = _order--
				}
			}));
		}

		public static bool TryHex(string hex, out Color c)
		{
			//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)
			c = Color.white;
			if (string.IsNullOrWhiteSpace(hex))
			{
				return false;
			}
			hex = hex.Trim();
			return ColorUtility.TryParseHtmlString(hex.StartsWith("#") ? hex : ("#" + hex), ref c);
		}
	}
	internal static class SignMarks
	{
		public const string Key = "Cano.Signs_LightOff";

		public static bool IsLightOff(ZNetView v)
		{
			if ((Object)(object)v != (Object)null && v.IsValid())
			{
				return v.GetZDO().GetInt("Cano.Signs_LightOff", 0) == 1;
			}
			return false;
		}

		public static void Poll()
		{
			//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)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (!Input.anyKeyDown)
			{
				return;
			}
			KeyboardShortcut value = Cfg.MarkKey.Value;
			if (!((KeyboardShortcut)(ref value)).IsDown() || Typing())
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
			Sign val = (((Object)(object)hoverObject != (Object)null) ? hoverObject.GetComponentInParent<Sign>() : null);
			if ((Object)(object)val == (Object)null)
			{
				Say(Cfg.MsgLookAtSign.Value);
				return;
			}
			ZNetView component = ((Component)val).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid() && PrivateArea.CheckAccess(((Component)val).transform.position, 0f, true, false))
			{
				bool flag = !IsLightOff(component);
				if (!component.IsOwner())
				{
					component.ClaimOwnership();
				}
				component.GetZDO().Set("Cano.Signs_LightOff", flag ? 1 : 0);
				SignVisual component2 = ((Component)val).GetComponent<SignVisual>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.Apply();
				}
				Say(flag ? Cfg.MsgLightOff.Value : Cfg.MsgLightOn.Value);
			}
		}

		private static void Say(string text)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && !string.IsNullOrEmpty(text))
			{
				((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		private static bool Typing()
		{
			if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible())
			{
				return Menu.IsVisible();
			}
			return true;
		}

		public static string Label(KeyboardShortcut s)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref s)).Modifiers)
			{
				stringBuilder.Append(((object)modifier/*cast due to .constrained prefix*/).ToString().Replace("Left", "").Replace("Right", "")).Append('+');
			}
			return stringBuilder.Append(((KeyboardShortcut)(ref s)).MainKey).ToString();
		}
	}
	internal static class MarkHint
	{
		private const string Reserve = "   ";

		private static int _frame = -10;

		private static bool _off;

		private static bool _shown;

		private static string _label;

		private static string _hint;

		private static string _placedText;

		private static Image _icon;

		private static Sprite _tick;

		private static Sprite _cross;

		public static void Invalidate()
		{
			_label = null;
			_hint = null;
		}

		public static string Request(bool lightOff)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			_frame = Time.frameCount;
			_off = lightOff;
			if (_hint == null)
			{
				_label = "[" + SignMarks.Label(Cfg.MarkKey.Value) + "]";
				_hint = "\n" + _label + "   ";
			}
			return _hint;
		}

		public static void Tick()
		{
			if (Time.frameCount - _frame > 1)
			{
				if (_shown)
				{
					Hide();
				}
				return;
			}
			TMP_Text val = (TMP_Text)(object)(((Object)(object)Hud.instance != (Object)null) ? Hud.instance.m_hoverName : null);
			if (((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy || !Place(val)) && _shown)
			{
				Hide();
			}
		}

		public static void Reset()
		{
			_frame = -10;
			Hide();
		}

		private static void Hide()
		{
			_shown = false;
			_placedText = null;
			if ((Object)(object)_icon != (Object)null)
			{
				((Component)_icon).gameObject.SetActive(false);
			}
		}

		private static bool Place(TMP_Text text)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00a4: 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 (!EnsureIcon(text))
			{
				return false;
			}
			if (!string.Equals(text.text, _placedText, StringComparison.Ordinal))
			{
				text.ForceMeshUpdate(false, false);
				TMP_TextInfo textInfo = text.textInfo;
				int num = FindLabelEnd(textInfo);
				if (num < 0)
				{
					return false;
				}
				TMP_CharacterInfo val = textInfo.characterInfo[num];
				float num2 = text.fontSize * 0.85f;
				_placedText = text.text;
				((Graphic)_icon).rectTransform.sizeDelta = new Vector2(num2, num2);
				((Transform)((Graphic)_icon).rectTransform).localPosition = new Vector3(val.topRight.x + num2 * 0.6f, (val.topRight.y + val.bottomRight.y) * 0.5f, 0f);
			}
			Sprite val2 = (_off ? _cross : _tick);
			if ((Object)(object)_icon.sprite != (Object)(object)val2)
			{
				_icon.sprite = val2;
			}
			if (!_shown)
			{
				((Component)_icon).gameObject.SetActive(true);
				_shown = true;
			}
			return true;
		}

		private static int FindLabelEnd(TMP_TextInfo info)
		{
			int characterCount = info.characterCount;
			for (int i = 0; i + _label.Length <= characterCount; i++)
			{
				bool flag = true;
				for (int j = 0; j < _label.Length && flag; j++)
				{
					flag = info.characterInfo[i + j].character == _label[j];
				}
				if (flag)
				{
					return i + _label.Length - 1;
				}
			}
			return -1;
		}

		private static bool EnsureIcon(TMP_Text text)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_icon != (Object)null)
			{
				return true;
			}
			_tick = Load("Mark_tick.png");
			_cross = Load("Mark_cross.png");
			if ((Object)(object)_tick == (Object)null || (Object)(object)_cross == (Object)null)
			{
				return false;
			}
			GameObject val = new GameObject("Cano.Signs.MarkIcon", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(text.transform, false);
			_icon = val.GetComponent<Image>();
			((Graphic)_icon).raycastTarget = false;
			_icon.preserveAspect = true;
			return true;
		}

		private static Sprite Load(string resource)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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)
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource);
			if (stream == null)
			{
				SignsPlugin.Log.LogWarning((object)("Embedded image missing: " + resource));
				return null;
			}
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, array.Length);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)1
			};
			ImageConversion.LoadImage(val, array);
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		}
	}
	[BepInPlugin("Cano.Signs", "Cano.Signs", "1.1.0")]
	public class SignsPlugin : BaseUnityPlugin
	{
		[HarmonyPatch]
		private static class Patches
		{
			private static bool _richCaptured;

			private static bool _vanillaRich;

			[HarmonyPostfix]
			[HarmonyPatch(typeof(Sign), "Awake")]
			private static void SignAwake(Sign __instance)
			{
				if (VisualOn)
				{
					SignVisual.Attach(__instance);
				}
			}

			[HarmonyPostfix]
			[HarmonyPatch(typeof(Sign), "GetHoverText")]
			private static void SignHover(Sign __instance, ref string __result)
			{
				if (MarksOn && Cfg.ShowIcons.Value && !string.IsNullOrEmpty(__result))
				{
					__result += MarkHint.Request(SignMarks.IsLightOff(((Component)__instance).GetComponent<ZNetView>()));
				}
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(TextInput), "RequestText")]
			private static void RequestText(TextInput __instance, TextReceiver sign, ref int charLimit)
			{
				if (!(sign is Sign))
				{
					return;
				}
				bool value = Cfg.Enabled.Value;
				if (value && Cfg.CharLimit.Value > charLimit)
				{
					charLimit = Cfg.CharLimit.Value;
				}
				TMP_InputField inputField = (TMP_InputField)(object)__instance.m_inputField;
				if (!((Object)(object)inputField == (Object)null))
				{
					if (!_richCaptured)
					{
						_vanillaRich = inputField.richText;
						_richCaptured = true;
					}
					inputField.richText = (!value || !Cfg.KeepRichText.Value) && _vanillaRich;
				}
			}
		}

		public const string Guid = "Cano.Signs";

		public const string Version = "1.1.0";

		internal const float MaxDistance = 192f;

		internal static bool VisualOn;

		internal static bool TickOn;

		internal static bool MarksOn;

		internal static bool LimitDistance;

		internal static bool CustomOn;

		internal static bool NeonOn;

		internal static bool NeonLight;

		internal static float Distance;

		internal static float Brightness;

		internal static Color Custom;

		internal static Color Neon;

		internal static ManualLogSource Log;

		private static bool _wasVisual;

		private static bool _wasMarks;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg.Bind(((BaseUnityPlugin)this).Config);
			((BaseUnityPlugin)this).Config.SettingChanged += delegate
			{
				Refresh();
			};
			Refresh();
			_harmony = new Harmony("Cano.Signs");
			_harmony.PatchAll(typeof(Patches));
		}

		private void Update()
		{
			SignVisual.TickSlice();
			if (MarksOn)
			{
				SignMarks.Poll();
			}
		}

		private void LateUpdate()
		{
			if (MarksOn)
			{
				MarkHint.Tick();
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			SignVisual.DetachAll();
		}

		private void Refresh()
		{
			//IL_00a3: 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)
			bool value = Cfg.Enabled.Value;
			Distance = Cfg.RenderDistance.Value;
			LimitDistance = value && Distance < 191.99f;
			CustomOn = value && Cfg.UseCustomColor.Value && Cfg.TryHex(Cfg.CustomColor.Value, out Custom);
			NeonOn = value && Cfg.NeonEnabled.Value;
			NeonLight = Cfg.NeonLight.Value;
			Brightness = Cfg.NeonBrightness.Value;
			if (!Cfg.TryHex(Cfg.NeonColor.Value, out Neon))
			{
				Neon = Color.white;
			}
			MarksOn = NeonOn && NeonLight;
			if (_wasMarks && !MarksOn)
			{
				MarkHint.Reset();
			}
			_wasMarks = MarksOn;
			MarkHint.Invalidate();
			TickOn = NeonOn || LimitDistance;
			VisualOn = CustomOn || TickOn;
			((Behaviour)this).enabled = TickOn;
			if (VisualOn)
			{
				if (!_wasVisual)
				{
					SignVisual.AttachAll();
				}
				SignVisual.ApplyAll();
			}
			else if (_wasVisual)
			{
				SignVisual.DetachAll();
			}
			_wasVisual = VisualOn;
		}
	}
	internal static class SignColors
	{
		public static bool HasVisibleText(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			for (int i = 0; i < text.Length; i++)
			{
				if (text[i] == '<')
				{
					int num = text.IndexOf('>', i + 1);
					if (num >= 0)
					{
						i = num;
						continue;
					}
				}
				if (!char.IsWhiteSpace(text[i]))
				{
					return true;
				}
			}
			return false;
		}

		public static Color Blended(string text, Color baseColor)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: 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)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: 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)
			if (string.IsNullOrEmpty(text) || text.IndexOf('<') < 0)
			{
				return baseColor;
			}
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			Dictionary<int, Color> dictionary2 = new Dictionary<int, Color>();
			List<Color> stack = new List<Color>();
			int num = 0;
			while (num < text.Length)
			{
				int num2 = text.IndexOf('<', num);
				int num3 = ((num2 < 0) ? (-1) : text.IndexOf('>', num2 + 1));
				if (num3 < 0)
				{
					Vote(text, num, text.Length, stack, baseColor, dictionary, dictionary2);
					break;
				}
				Vote(text, num, num2, stack, baseColor, dictionary, dictionary2);
				HandleTag(text.Substring(num2 + 1, num3 - num2 - 1).Trim(), stack, baseColor);
				num = num3 + 1;
			}
			if (dictionary.Count == 0)
			{
				return baseColor;
			}
			if (dictionary.Count == 1)
			{
				using Dictionary<int, Color>.ValueCollection.Enumerator enumerator = dictionary2.Values.GetEnumerator();
				if (enumerator.MoveNext())
				{
					return enumerator.Current;
				}
			}
			float num4 = 0f;
			float num5 = 0f;
			float num6 = 0f;
			Color val;
			foreach (KeyValuePair<int, int> item in dictionary)
			{
				val = dictionary2[item.Key];
				Color linear = ((Color)(ref val)).linear;
				num4 += linear.r * (float)item.Value;
				num5 += linear.g * (float)item.Value;
				num6 += linear.b * (float)item.Value;
			}
			float num7 = Mathf.Max(num4, Mathf.Max(num5, num6));
			if (num7 <= 1E-05f)
			{
				return baseColor;
			}
			val = new Color(num4 / num7, num5 / num7, num6 / num7, 1f);
			return ((Color)(ref val)).gamma;
		}

		private static void HandleTag(string tag, List<Color> stack, Color baseColor)
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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)
			if (tag.Length == 0)
			{
				return;
			}
			string text = tag.ToLowerInvariant();
			if (text == "/color")
			{
				if (stack.Count > 0)
				{
					stack.RemoveAt(stack.Count - 1);
				}
				return;
			}
			string text2 = (text.StartsWith("color=") ? tag.Substring(6) : (text.StartsWith("#") ? tag : null));
			if (text2 != null)
			{
				text2 = text2.Trim().Trim('"', '\'').Trim();
				Color val = default(Color);
				stack.Add(ColorUtility.TryParseHtmlString(text2, ref val) ? val : ((stack.Count > 0) ? stack[stack.Count - 1] : baseColor));
			}
		}

		private static void Vote(string text, int from, int to, List<Color> stack, Color baseColor, Dictionary<int, int> weights, Dictionary<int, Color> colors)
		{
			//IL_003f: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			for (int i = from; i < to; i++)
			{
				if (!char.IsWhiteSpace(text[i]))
				{
					num++;
				}
			}
			if (num != 0)
			{
				Color val = ((stack.Count > 0) ? stack[stack.Count - 1] : baseColor);
				int key = (Mathf.RoundToInt(val.r * 255f) << 16) | (Mathf.RoundToInt(val.g * 255f) << 8) | Mathf.RoundToInt(val.b * 255f);
				weights.TryGetValue(key, out var value);
				weights[key] = value + num;
				colors[key] = val;
			}
		}

		public static Color ForLight(Color c)
		{
			//IL_0000: 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)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			float num = default(float);
			float num2 = default(float);
			float num3 = default(float);
			Color.RGBToHSV(c, ref num, ref num2, ref num3);
			if (!(num3 < 0.05f))
			{
				return Color.HSVToRGB(num, num2, 1f);
			}
			return Color.white;
		}
	}
	internal sealed class SignVisual : MonoBehaviour
	{
		private const float LightRange = 40f;

		private static readonly List<SignVisual> All = new List<SignVisual>();

		private static int _cursor;

		private TMP_Text _text;

		private ZNetView _view;

		private Color _origColor;

		private Color _glowColor;

		private Material _origMaterial;

		private Material _neonMaterial;

		private string _lastText;

		private bool _known;

		private bool _hasText;

		private bool _glowing;

		private Light _light;

		public static void Attach(Sign sign)
		{
			if ((Object)(object)sign != (Object)null && (Object)(object)((Component)sign).GetComponent<SignVisual>() == (Object)null)
			{
				((Component)sign).gameObject.AddComponent<SignVisual>();
			}
		}

		public static void AttachAll()
		{
			Sign[] array = Object.FindObjectsByType<Sign>((FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				Attach(array[i]);
			}
		}

		public static void ApplyAll()
		{
			for (int num = All.Count - 1; num >= 0; num--)
			{
				All[num].Apply();
			}
		}

		public static void DetachAll()
		{
			SignVisual[] array = All.ToArray();
			foreach (SignVisual obj in array)
			{
				obj.Restore();
				Object.Destroy((Object)(object)obj);
			}
			All.Clear();
		}

		public static void TickSlice()
		{
			if (All.Count == 0)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			int num = Mathf.Max(1, All.Count / 30);
			while (num > 0 && All.Count > 0)
			{
				if (_cursor >= All.Count)
				{
					_cursor = 0;
				}
				All[_cursor++].Tick(localPlayer);
				num--;
			}
		}

		private void Awake()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			Sign component = ((Component)this).GetComponent<Sign>();
			_text = (TMP_Text)(object)(((Object)(object)component != (Object)null) ? component.m_textWidget : null);
			_view = ((Component)this).GetComponent<ZNetView>();
			if (!((Object)(object)_text == (Object)null))
			{
				_origColor = ((Graphic)_text).color;
				_origMaterial = _text.fontSharedMaterial;
			}
		}

		private void OnEnable()
		{
			All.Add(this);
			Apply();
		}

		private void OnDisable()
		{
			All.Remove(this);
			if ((Object)(object)_light != (Object)null)
			{
				((Behaviour)_light).enabled = false;
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_neonMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_neonMaterial);
			}
			if ((Object)(object)_light != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_light).gameObject);
			}
		}

		public void Apply()
		{
			//IL_0032: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_text == (Object)null))
			{
				((Graphic)_text).color = (SignsPlugin.NeonOn ? SignsPlugin.Neon : (SignsPlugin.CustomOn ? SignsPlugin.Custom : _origColor));
				if (!SignsPlugin.LimitDistance)
				{
					((Behaviour)_text).enabled = true;
				}
				_known = false;
				Player localPlayer = Player.m_localPlayer;
				SyncNeon();
				UpdateLight(((Behaviour)_text).enabled, DistanceTo(localPlayer), localPlayer);
			}
		}

		private void Tick(Player player)
		{
			if (!((Object)(object)_text == (Object)null))
			{
				float num = DistanceTo(player);
				bool flag = !SignsPlugin.LimitDistance || (Object)(object)player == (Object)null || num <= SignsPlugin.Distance;
				if (((Behaviour)_text).enabled != flag)
				{
					((Behaviour)_text).enabled = flag;
				}
				SyncNeon();
				UpdateLight(flag, num, player);
			}
		}

		private float DistanceTo(Player p)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)p != (Object)null))
			{
				return 0f;
			}
			return Vector3.Distance(((Component)p).transform.position, ((Component)this).transform.position);
		}

		private void Restore()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_text != (Object)null)
			{
				((Graphic)_text).color = _origColor;
				RestoreMaterial();
				((Behaviour)_text).enabled = true;
			}
			_glowing = false;
			if ((Object)(object)_light != (Object)null)
			{
				((Behaviour)_light).enabled = false;
			}
		}

		private void SyncNeon()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			string text = _text.text;
			bool flag = !_known || text != _lastText;
			if (flag)
			{
				_known = true;
				_lastText = text;
				_hasText = HasText(text);
				_glowColor = SignColors.Blended(text, SignsPlugin.Neon);
			}
			bool flag2 = SignsPlugin.NeonOn && _hasText;
			if (flag2)
			{
				if (flag || !_glowing)
				{
					ApplyNeonMaterial();
				}
			}
			else if (_glowing)
			{
				RestoreMaterial();
			}
			_glowing = flag2;
		}

		private bool HasText(string text)
		{
			if ((Object)(object)_view != (Object)null && _view.IsValid() && _view.GetZDO().GetString(ZDOVars.s_text, (string)null) == null)
			{
				return false;
			}
			return SignColors.HasVisibleText(text);
		}

		private void ApplyNeonMaterial()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			if (!((Object)(object)_origMaterial == (Object)null))
			{
				if ((Object)(object)_neonMaterial == (Object)null)
				{
					_neonMaterial = new Material(_origMaterial);
				}
				float brightness = SignsPlugin.Brightness;
				SetColor("_FaceColor", new Color(brightness, brightness, brightness, 1f));
				_neonMaterial.EnableKeyword("GLOW_ON");
				_neonMaterial.EnableKeyword("UNDERLAY_ON");
				float num = Mathf.Clamp01((brightness - 0.5f) / 9.5f);
				Color c = default(Color);
				((Color)(ref c))..ctor(_glowColor.r, _glowColor.g, _glowColor.b, 1f);
				SetColor("_GlowColor", c);
				SetFloat("_GlowPower", Mathf.Lerp(0.3f, 1f, num));
				SetFloat("_GlowOuter", Mathf.Lerp(0.4f, 1f, num));
				SetFloat("_GlowInner", 0.1f);
				SetFloat("_GlowOffset", 0f);
				c.a = Mathf.Lerp(0.55f, 1f, num);
				SetColor("_UnderlayColor", c);
				SetFloat("_UnderlayOffsetX", 0f);
				SetFloat("_UnderlayOffsetY", 0f);
				SetFloat("_UnderlayDilate", Mathf.Lerp(0.3f, 1f, num));
				SetFloat("_UnderlaySoftness", Mathf.Lerp(0.4f, 1f, num));
				_text.fontSharedMaterial = _neonMaterial;
			}
		}

		private void RestoreMaterial()
		{
			if ((Object)(object)_origMaterial != (Object)null && (Object)(object)_text.fontSharedMaterial != (Object)(object)_origMaterial)
			{
				_text.fontSharedMaterial = _origMaterial;
			}
		}

		private void SetColor(string prop, Color c)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (_neonMaterial.HasProperty(prop))
			{
				_neonMaterial.SetColor(prop, c);
			}
		}

		private void SetFloat(string prop, float v)
		{
			if (_neonMaterial.HasProperty(prop))
			{
				_neonMaterial.SetFloat(prop, v);
			}
		}

		private void UpdateLight(bool shown, float dist, Player player)
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			if (!(_glowing && SignsPlugin.NeonLight && shown) || !(dist <= 40f) || SignMarks.IsLightOff(_view))
			{
				if ((Object)(object)_light != (Object)null && ((Behaviour)_light).enabled)
				{
					((Behaviour)_light).enabled = false;
				}
				return;
			}
			if ((Object)(object)_light == (Object)null)
			{
				GameObject val = new GameObject("Cano_NeonLight");
				val.transform.SetParent(((Component)this).transform, false);
				_light = val.AddComponent<Light>();
				_light.type = (LightType)2;
				_light.shadows = (LightShadows)0;
			}
			float brightness = SignsPlugin.Brightness;
			_light.color = SignColors.ForLight(_glowColor);
			_light.intensity = Mathf.Clamp(0.4f + brightness * 0.5f, 0.5f, 5.5f);
			_light.range = Mathf.Clamp(3f + brightness * 0.8f, 3f, 11f);
			Transform transform = _text.transform;
			Vector3 val2 = transform.forward;
			if ((Object)(object)player != (Object)null && Vector3.Dot(((Component)player).transform.position - transform.position, val2) < 0f)
			{
				val2 = -val2;
			}
			((Component)_light).transform.position = transform.position + val2 * 0.35f;
			((Behaviour)_light).enabled = true;
		}
	}
}