Decompiled source of BetterSigns v1.1.1

BetterSigns.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterSigns.Config;
using BetterSigns.Helpers;
using BetterSigns.Items;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace BetterSigns
{
	[BepInPlugin("com.yourname.bettersigns", "BetterSigns", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private sealed class <RegisterSignVariantsWhenReady>d__10 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RegisterSignVariantsWhenReady>d__10(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					Log.LogInfo((object)"[Plugin] Waiting for ZNetScene + 'sign' prefab...");
					goto IL_004a;
				case 1:
					<>1__state = -1;
					goto IL_004a;
				case 2:
					{
						<>1__state = -1;
						break;
					}
					IL_004a:
					if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZNetScene.instance.GetPrefab("sign") == (Object)null)
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					Log.LogInfo((object)"[Plugin] ZNetScene ready — registering sign variant prefabs.");
					SignVariants.RegisterPrefabs(ZNetScene.instance);
					Log.LogInfo((object)"[Plugin] Waiting for ObjectDB + Hammer item...");
					break;
				}
				if ((Object)(object)ObjectDB.instance == (Object)null || (Object)(object)ObjectDB.instance.GetItemPrefab("Hammer") == (Object)null)
				{
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				Log.LogInfo((object)"[Plugin] ObjectDB ready — registering sign variants in piece table.");
				SignVariants.RegisterInPieceTable(ZNetScene.instance);
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string PluginGuid = "com.yourname.bettersigns";

		public const string PluginName = "BetterSigns";

		public const string PluginVersion = "1.1.0";

		private Harmony _harmony;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Initialize(((BaseUnityPlugin)this).Config);
			ColorPresets.Load(Paths.ConfigPath);
			_harmony = new Harmony("com.yourname.bettersigns");
			_harmony.PatchAll();
			Log.LogInfo((object)"[BetterSigns] v1.1.0 loaded successfully.");
		}

		private void Start()
		{
			Log.LogInfo((object)"[BetterSigns] Starting sign variant registration coroutine.");
			((MonoBehaviour)this).StartCoroutine(RegisterSignVariantsWhenReady());
		}

		[IteratorStateMachine(typeof(<RegisterSignVariantsWhenReady>d__10))]
		private static IEnumerator RegisterSignVariantsWhenReady()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RegisterSignVariantsWhenReady>d__10(0);
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace BetterSigns.Patches
{
	[HarmonyPatch(typeof(TMP_Text), "set_text")]
	internal static class TmpTextSetterPatch
	{
		private static readonly Dictionary<TMP_Text, Sign?> _signCache = new Dictionary<TMP_Text, Sign>();

		[HarmonyPrefix]
		public static void Prefix(TMP_Text __instance, ref string value)
		{
			try
			{
				if (SignController.InternalSetSuppressed.Contains(__instance))
				{
					return;
				}
				if (!_signCache.TryGetValue(__instance, out Sign value2))
				{
					value2 = ((Component)__instance).GetComponentInParent<Sign>();
					_signCache[__instance] = value2;
				}
				if (!((Object)(object)value2 == (Object)null) && !string.IsNullOrEmpty(value))
				{
					string cleanText;
					SignEffects signEffects = SignTextParser.Parse(ColorPresets.ExpandAliases(value), out cleanText);
					Plugin.Log.LogDebug((object)("[TmpPatch] '" + value + "' → '" + cleanText + "' " + $"glow={signEffects.GlowColor.HasValue} rainbow={signEffects.HasRainbow} " + $"bg={signEffects.BackgroundColor.HasValue}"));
					SignController component = ((Component)value2).GetComponent<SignController>();
					if ((Object)(object)component != (Object)null)
					{
						component.ApplyEffects(value2, signEffects);
					}
					value = cleanText;
					__instance.richText = true;
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[TmpPatch] {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(Sign), "Awake")]
	internal static class SignAwakePatch
	{
		[HarmonyPostfix]
		public static void Postfix(Sign __instance)
		{
			try
			{
				if ((Object)(object)((Component)__instance).GetComponent<SignController>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<SignController>();
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[SignAwakePatch] {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(Sign), "SetText")]
	internal static class SignSetTextPatch
	{
		[HarmonyPrefix]
		public static void Prefix(ref string text)
		{
			try
			{
				text = ColorPresets.ExpandAliases(text);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[SetText.Prefix] {arg}");
			}
		}
	}
}
namespace BetterSigns.Items
{
	internal struct SignVariantDef
	{
		public string Id;

		public string DisplayName;

		public string Description;

		public float Scale;

		public int MaxTextLength;

		public int WoodCost;

		public int FineWoodCost;
	}
	internal static class SignVariants
	{
		internal static readonly HashSet<GameObject> PrefabTemplates = new HashSet<GameObject>();

		private static readonly SignVariantDef[] Defs = new SignVariantDef[4]
		{
			new SignVariantDef
			{
				Id = "sign_small_bs",
				DisplayName = "Small Sign",
				Description = "A compact sign for labeling chests and containers.",
				Scale = 0.5f,
				MaxTextLength = 40,
				WoodCost = 1,
				FineWoodCost = 0
			},
			new SignVariantDef
			{
				Id = "sign_large_bs",
				DisplayName = "Large Sign",
				Description = "An oversized sign visible from across the room.",
				Scale = 2f,
				MaxTextLength = 120,
				WoodCost = 4,
				FineWoodCost = 1
			},
			new SignVariantDef
			{
				Id = "sign_huge_bs",
				DisplayName = "Huge Sign",
				Description = "A massive sign for landmarks and grand announcements.",
				Scale = 3f,
				MaxTextLength = 200,
				WoodCost = 6,
				FineWoodCost = 2
			},
			new SignVariantDef
			{
				Id = "sign_colossal_bs",
				DisplayName = "Colossal Sign",
				Description = "An enormous sign visible from the far end of any hall.",
				Scale = 5f,
				MaxTextLength = 300,
				WoodCost = 10,
				FineWoodCost = 4
			}
		};

		internal static void RegisterPrefabs(ZNetScene scene)
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Log.LogInfo((object)"[SignVariants] RegisterPrefabs called.");
			GameObject prefab = scene.GetPrefab("sign");
			if ((Object)(object)prefab == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[SignVariants] Base 'sign' prefab not found.");
				return;
			}
			SignVariantDef[] defs = Defs;
			for (int i = 0; i < defs.Length; i++)
			{
				SignVariantDef signVariantDef = defs[i];
				if ((Object)(object)scene.GetPrefab(signVariantDef.Id) != (Object)null)
				{
					Plugin.Log.LogInfo((object)("[SignVariants] '" + signVariantDef.Id + "' already registered, skipping."));
					continue;
				}
				bool activeSelf = prefab.activeSelf;
				prefab.SetActive(false);
				GameObject val = Object.Instantiate<GameObject>(prefab);
				prefab.SetActive(activeSelf);
				((Object)val).name = signVariantDef.Id;
				Object.DontDestroyOnLoad((Object)(object)val);
				val.transform.localScale = Vector3.one * signVariantDef.Scale;
				Piece component = val.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null)
				{
					component.m_name = signVariantDef.DisplayName;
					component.m_description = signVariantDef.Description;
				}
				Sign component2 = val.GetComponent<Sign>();
				if ((Object)(object)component2 != (Object)null)
				{
					Traverse.Create((object)component2).Field("m_maxTextLength").SetValue((object)signVariantDef.MaxTextLength);
				}
				scene.m_prefabs.Add(val);
				Dictionary<int, GameObject> value = Traverse.Create((object)scene).Field<Dictionary<int, GameObject>>("m_namedPrefabs").Value;
				if (value != null)
				{
					value[StableHash(signVariantDef.Id)] = val;
				}
				PrefabTemplates.Add(val);
				val.SetActive(true);
				Plugin.Log.LogInfo((object)$"[SignVariants] Registered '{signVariantDef.Id}' (scale={signVariantDef.Scale}x)");
			}
		}

		internal static void RegisterInPieceTable(ZNetScene scene)
		{
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Expected O, but got Unknown
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Expected O, but got Unknown
			Plugin.Log.LogInfo((object)"[SignVariants] RegisterInPieceTable called.");
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[SignVariants] ObjectDB.instance is null — skipping.");
				return;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer");
			if ((Object)(object)itemPrefab == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[SignVariants] Hammer prefab not found.");
				return;
			}
			PieceTable val = itemPrefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces;
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[SignVariants] Hammer piece table not found.");
				return;
			}
			GameObject itemPrefab2 = ObjectDB.instance.GetItemPrefab("Wood");
			ItemDrop val2 = ((itemPrefab2 != null) ? itemPrefab2.GetComponent<ItemDrop>() : null);
			GameObject itemPrefab3 = ObjectDB.instance.GetItemPrefab("FineWood");
			ItemDrop val3 = ((itemPrefab3 != null) ? itemPrefab3.GetComponent<ItemDrop>() : null);
			SignVariantDef[] defs = Defs;
			for (int i = 0; i < defs.Length; i++)
			{
				SignVariantDef signVariantDef = defs[i];
				GameObject prefab = scene.GetPrefab(signVariantDef.Id);
				if ((Object)(object)prefab == (Object)null)
				{
					Plugin.Log.LogWarning((object)("[SignVariants] Prefab '" + signVariantDef.Id + "' not in ZNetScene — piece skipped."));
					continue;
				}
				if (val.m_pieces.Contains(prefab))
				{
					Plugin.Log.LogInfo((object)("[SignVariants] '" + signVariantDef.Id + "' already in piece table."));
					continue;
				}
				List<Requirement> list = new List<Requirement>();
				if ((Object)(object)val2 != (Object)null && signVariantDef.WoodCost > 0)
				{
					list.Add(new Requirement
					{
						m_resItem = val2,
						m_amount = signVariantDef.WoodCost,
						m_recover = true
					});
				}
				if ((Object)(object)val3 != (Object)null && signVariantDef.FineWoodCost > 0)
				{
					list.Add(new Requirement
					{
						m_resItem = val3,
						m_amount = signVariantDef.FineWoodCost,
						m_recover = true
					});
				}
				Piece component = prefab.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null)
				{
					component.m_resources = list.ToArray();
				}
				val.m_pieces.Add(prefab);
				Plugin.Log.LogInfo((object)("[SignVariants] '" + signVariantDef.Id + "' added to Hammer " + $"(Wood×{signVariantDef.WoodCost} FineWood×{signVariantDef.FineWoodCost})"));
			}
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				Traverse.Create((object)Player.m_localPlayer).Method("UpdateKnownRecipesList", Array.Empty<object>()).GetValue();
				Plugin.Log.LogInfo((object)"[SignVariants] Player.UpdateKnownRecipesList() refreshed.");
			}
		}

		private static int StableHash(string str)
		{
			int num = 5381;
			int num2 = num;
			for (int i = 0; i < str.Length && str[i] != 0; i += 2)
			{
				num = ((num << 5) + num) ^ str[i];
				if (i + 1 < str.Length && str[i + 1] != 0)
				{
					num2 = ((num2 << 5) + num2) ^ str[i + 1];
				}
			}
			return num + num2 * 1566083941;
		}
	}
	[HarmonyPatch(typeof(ZNetView), "Awake")]
	internal static class ZNetViewPrefabPatch
	{
		[HarmonyPrefix]
		public static bool Prefix(ZNetView __instance)
		{
			if (SignVariants.PrefabTemplates.Contains(((Component)__instance).gameObject))
			{
				Plugin.Log.LogDebug((object)("[ZNetViewPatch] Skipping ZDO registration for prefab template '" + ((Object)((Component)__instance).gameObject).name + "'"));
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class PlayerOnSpawnedPatch
	{
		[HarmonyPostfix]
		public static void Postfix(Player __instance)
		{
			try
			{
				Plugin.Log.LogInfo((object)"[SignVariants] Player.OnSpawned — re-registering piece table.");
				if ((Object)(object)ZNetScene.instance != (Object)null)
				{
					SignVariants.RegisterInPieceTable(ZNetScene.instance);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[PlayerOnSpawnedPatch] {arg}");
			}
		}
	}
}
namespace BetterSigns.Helpers
{
	public static class GlowHelper
	{
		private static readonly int PropEmission = Shader.PropertyToID("_EmissionColor");

		private static readonly int PropColor = Shader.PropertyToID("_Color");

		private static readonly int PropMainColor = Shader.PropertyToID("_MainColor");

		public static void ApplyGlow(Sign sign, SignEffects effects)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (effects.GlowColor.HasValue && !ModConfig.GlowPulsate.Value)
			{
				SetGlow(sign, effects.GlowColor.Value, effects.GlowIntensity);
			}
			else if (!effects.GlowColor.HasValue)
			{
				RemoveGlow(sign);
			}
			if (effects.BackgroundColor.HasValue)
			{
				SetBackground(sign, effects.BackgroundColor.Value);
			}
			else
			{
				ResetBackground(sign);
			}
		}

		private static void SetGlow(Sign sign, Color color, float intensityMult = 1f)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(0f, ModConfig.MaxGlowIntensity.Value) * intensityMult;
			Color val = color * num;
			MeshRenderer[] componentsInChildren = ((Component)sign).GetComponentsInChildren<MeshRenderer>(false);
			foreach (MeshRenderer obj in componentsInChildren)
			{
				Material material = ((Renderer)obj).material;
				material.EnableKeyword("_EMISSION");
				material.SetColor(PropEmission, val);
				DynamicGI.SetEmissive((Renderer)(object)obj, val);
			}
		}

		private static void RemoveGlow(Sign sign)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			MeshRenderer[] componentsInChildren = ((Component)sign).GetComponentsInChildren<MeshRenderer>(false);
			foreach (MeshRenderer obj in componentsInChildren)
			{
				Material material = ((Renderer)obj).material;
				material.DisableKeyword("_EMISSION");
				material.SetColor(PropEmission, Color.black);
				DynamicGI.SetEmissive((Renderer)(object)obj, Color.black);
			}
		}

		private static void SetBackground(Sign sign, Color bgColor)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			MeshRenderer[] componentsInChildren = ((Component)sign).GetComponentsInChildren<MeshRenderer>(false);
			if (componentsInChildren.Length == 0)
			{
				Plugin.Log.LogWarning((object)"[GlowHelper] No MeshRenderers found on sign — <bg> has no effect.");
				return;
			}
			MeshRenderer[] array = componentsInChildren;
			foreach (MeshRenderer val in array)
			{
				Material material = ((Renderer)val).material;
				Plugin.Log.LogDebug((object)("[GlowHelper] Renderer '" + ((Object)((Component)val).gameObject).name + "' shader='" + ((Object)material.shader).name + "' " + $"hasColor={material.HasProperty(PropColor)} hasMainColor={material.HasProperty(PropMainColor)}"));
				if (material.HasProperty(PropColor))
				{
					material.SetColor(PropColor, bgColor);
					Plugin.Log.LogDebug((object)("[GlowHelper] Set _Color on '" + ((Object)((Component)val).gameObject).name + "'"));
					continue;
				}
				if (material.HasProperty(PropMainColor))
				{
					material.SetColor(PropMainColor, bgColor);
					Plugin.Log.LogDebug((object)("[GlowHelper] Set _MainColor on '" + ((Object)((Component)val).gameObject).name + "'"));
					continue;
				}
				try
				{
					material.color = bgColor;
				}
				catch
				{
				}
			}
		}

		private static void ResetBackground(Sign sign)
		{
			//IL_0028: 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)
			MeshRenderer[] componentsInChildren = ((Component)sign).GetComponentsInChildren<MeshRenderer>(false);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material material = ((Renderer)componentsInChildren[i]).material;
				if (material.HasProperty(PropColor))
				{
					material.SetColor(PropColor, Color.white);
				}
				else if (material.HasProperty(PropMainColor))
				{
					material.SetColor(PropMainColor, Color.white);
				}
			}
		}
	}
	[DefaultExecutionOrder(500)]
	public class SignController : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <GlowPulsateCoroutine>d__13 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public SignController <>4__this;

			public float intensityMult;

			public Color glowColor;

			private int <propEmission>5__2;

			private MeshRenderer[] <renderers>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GlowPulsateCoroutine>d__13(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<renderers>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0096: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				SignController signController = <>4__this;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
				}
				else
				{
					<>1__state = -1;
					<propEmission>5__2 = Shader.PropertyToID("_EmissionColor");
					<renderers>5__3 = ((Component)signController._sign).GetComponentsInChildren<MeshRenderer>(false);
				}
				float num2 = ModConfig.MaxGlowIntensity.Value * intensityMult;
				float num3 = num2 * ModConfig.GlowPulsateMinMultiplier.Value;
				float value = ModConfig.GlowPulsateSpeed.Value;
				float num4 = (Mathf.Sin(Time.time * value * MathF.PI * 2f) + 1f) * 0.5f;
				Color val = glowColor * Mathf.Lerp(num3, num2, num4);
				MeshRenderer[] array = <renderers>5__3;
				foreach (MeshRenderer val2 in array)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						((Renderer)val2).material.SetColor(<propEmission>5__2, val);
						DynamicGI.SetEmissive((Renderer)(object)val2, val);
					}
				}
				<>2__current = null;
				<>1__state = 1;
				return true;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <RainbowCoroutine>d__12 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public SignController <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RainbowCoroutine>d__12(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a6: 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_00cd: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d9: 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_011f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0121: 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_0124: Unknown result type (might be due to invalid IL or missing references)
				//IL_0129: 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_012c: Unknown result type (might be due to invalid IL or missing references)
				//IL_012e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0133: Unknown result type (might be due to invalid IL or missing references)
				//IL_0135: Unknown result type (might be due to invalid IL or missing references)
				//IL_0136: 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_013f: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				SignController signController = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				case 2:
					<>1__state = -1;
					break;
				}
				signController._textField.ForceMeshUpdate(false, false);
				TMP_TextInfo textInfo = signController._textField.textInfo;
				if (textInfo == null || textInfo.characterCount == 0)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				float value = ModConfig.RainbowSpeed.Value;
				float value2 = ModConfig.RainbowSaturation.Value;
				float value3 = ModConfig.RainbowBrightness.Value;
				int characterCount = textInfo.characterCount;
				for (int i = 0; i < characterCount; i++)
				{
					TMP_CharacterInfo val = textInfo.characterInfo[i];
					if (val.isVisible)
					{
						Color32 val2 = Color32.op_Implicit(Color.HSVToRGB((Time.time * value + (float)i / (float)characterCount) % 1f, value2, value3));
						int materialReferenceIndex = val.materialReferenceIndex;
						int vertexIndex = val.vertexIndex;
						Color32[] colors = textInfo.meshInfo[materialReferenceIndex].colors32;
						if (vertexIndex + 3 < colors.Length)
						{
							colors[vertexIndex] = (colors[vertexIndex + 1] = (colors[vertexIndex + 2] = (colors[vertexIndex + 3] = val2)));
						}
					}
				}
				for (int j = 0; j < textInfo.meshInfo.Length; j++)
				{
					textInfo.meshInfo[j].mesh.colors32 = textInfo.meshInfo[j].colors32;
					signController._textField.UpdateGeometry(textInfo.meshInfo[j].mesh, j);
				}
				<>2__current = null;
				<>1__state = 2;
				return true;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal static readonly HashSet<TMP_Text> InternalSetSuppressed = new HashSet<TMP_Text>();

		private Sign _sign;

		private TMP_Text _textField;

		private SignEffects? _effects;

		private Coroutine? _rainbowCo;

		private Coroutine? _pulsateCo;

		private void Awake()
		{
			Sign component = ((Component)this).GetComponent<Sign>();
			if ((Object)(object)component != (Object)null)
			{
				Setup(component);
			}
			else
			{
				Plugin.Log.LogWarning((object)"[SignController] Awake: no Sign on same GameObject.");
			}
		}

		public void Setup(Sign sign)
		{
			_sign = sign;
			_textField = ((Component)sign).GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)_textField == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[SignController] No TMP_Text found — controller inactive.");
			}
			else
			{
				Plugin.Log.LogDebug((object)"[SignController] Ready — TMP found.");
			}
		}

		private void LateUpdate()
		{
			if ((Object)(object)_sign == (Object)null || (Object)(object)_textField == (Object)null || _effects == null || !(_textField.text != _effects.CleanText))
			{
				return;
			}
			Plugin.Log.LogDebug((object)"[SignController] TMP reverted — restoring clean text.");
			InternalSetSuppressed.Add(_textField);
			try
			{
				_textField.richText = true;
				_textField.text = _effects.CleanText;
			}
			finally
			{
				InternalSetSuppressed.Remove(_textField);
			}
		}

		public void ApplyEffects(Sign sign, SignEffects effects)
		{
			try
			{
				_effects = effects;
				GlowHelper.ApplyGlow(sign, effects);
				RefreshAnimations();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[SignController.ApplyEffects] {arg}");
			}
		}

		private void RefreshAnimations()
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			if (_effects != null)
			{
				StopSafe(ref _rainbowCo);
				if (_effects.HasRainbow && ModConfig.EnableRainbow.Value)
				{
					_rainbowCo = ((MonoBehaviour)this).StartCoroutine(RainbowCoroutine());
				}
				StopSafe(ref _pulsateCo);
				if (_effects.GlowColor.HasValue && ModConfig.GlowPulsate.Value && ModConfig.MaxGlowIntensity.Value > 0f)
				{
					_pulsateCo = ((MonoBehaviour)this).StartCoroutine(GlowPulsateCoroutine(_effects.GlowColor.Value, _effects.GlowIntensity));
				}
			}
		}

		private void StopSafe(ref Coroutine? co)
		{
			if (co != null)
			{
				((MonoBehaviour)this).StopCoroutine(co);
				co = null;
			}
		}

		[IteratorStateMachine(typeof(<RainbowCoroutine>d__12))]
		private IEnumerator RainbowCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RainbowCoroutine>d__12(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<GlowPulsateCoroutine>d__13))]
		private IEnumerator GlowPulsateCoroutine(Color glowColor, float intensityMult = 1f)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GlowPulsateCoroutine>d__13(0)
			{
				<>4__this = this,
				glowColor = glowColor,
				intensityMult = intensityMult
			};
		}
	}
	public sealed class SignEffects
	{
		public Color? GlowColor { get; set; }

		public float GlowIntensity { get; set; } = 0.3f;


		public Color? BackgroundColor { get; set; }

		public bool HasRainbow { get; set; }

		public string CleanText { get; set; } = string.Empty;

	}
	public static class SignTextParser
	{
		private static readonly Regex RxGlow = new Regex("<glow=(#[0-9A-Fa-f]{6,8})(?:,([0-9]*\\.?[0-9]+))?>(.*?)</glow>", RegexOptions.Compiled | RegexOptions.Singleline);

		private static readonly Regex RxBg = new Regex("<bg=(#[0-9A-Fa-f]{6,8})>(.*?)</bg>", RegexOptions.Compiled | RegexOptions.Singleline);

		private static readonly Regex RxBgClose = new Regex("</bg>", RegexOptions.Compiled);

		private static readonly Regex RxRainbow = new Regex("<rainbow>(.*?)</rainbow>", RegexOptions.Compiled | RegexOptions.Singleline);

		private static readonly Regex RxAnyTag = new Regex("<[^>]+>", RegexOptions.Compiled);

		public static SignEffects Parse(string rawText, out string cleanText)
		{
			SignEffects effects = new SignEffects();
			string text = rawText ?? string.Empty;
			text = ColorPresets.ExpandAliases(text);
			text = ApplyDefaults(text);
			text = RxGlow.Replace(text, delegate(Match match)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				Color value2 = default(Color);
				if (ColorUtility.TryParseHtmlString(match.Groups[1].Value, ref value2))
				{
					effects.GlowColor = value2;
					if (match.Groups[2].Success && float.TryParse(match.Groups[2].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && result >= 0f)
					{
						effects.GlowIntensity = result;
					}
				}
				return match.Groups[3].Value;
			});
			text = RxBg.Replace(text, delegate(Match match)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				Color value = default(Color);
				if (ColorUtility.TryParseHtmlString(match.Groups[1].Value, ref value))
				{
					effects.BackgroundColor = value;
				}
				return match.Groups[2].Value;
			});
			text = RxBgClose.Replace(text, string.Empty);
			text = (cleanText = RxRainbow.Replace(text, delegate(Match match)
			{
				effects.HasRainbow = true;
				return match.Groups[1].Value;
			}));
			effects.CleanText = text;
			return effects;
		}

		public static string StripAllTags(string text)
		{
			return RxAnyTag.Replace(text ?? string.Empty, string.Empty);
		}

		private static string ApplyDefaults(string text)
		{
			string text2 = string.Empty;
			string text3 = string.Empty;
			float value = ModConfig.DefaultFontSize.Value;
			if (value > 0f)
			{
				text2 += $"<size={value}>";
				text3 = "</size>" + text3;
			}
			string text4 = ColorPresets.ExpandAliases(ModConfig.DefaultTextColor.Value ?? "").Trim();
			if (!string.IsNullOrEmpty(text4) && text4.StartsWith("#") && !text.TrimStart().StartsWith("<color"))
			{
				text2 = text2 + "<color=" + text4 + ">";
				text3 = "</color>" + text3;
			}
			if (!string.IsNullOrEmpty(text2))
			{
				return text2 + text + text3;
			}
			return text;
		}
	}
}
namespace BetterSigns.Config
{
	public static class ColorPresets
	{
		private static readonly Dictionary<string, string> _map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private static readonly Regex AliasPattern = new Regex("<(color|glow|bg)=([^#>][^>]*)>", RegexOptions.IgnoreCase | RegexOptions.Compiled);

		public static void Load(string configFolderPath)
		{
			string text = Path.Combine(configFolderPath, "BetterSigns.colors.cfg");
			if (!File.Exists(text))
			{
				WriteDefaultsTo(text);
			}
			_map.Clear();
			string[] array = File.ReadAllLines(text);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (string.IsNullOrEmpty(text2) || text2.StartsWith("#"))
				{
					continue;
				}
				int num = text2.IndexOf('=');
				if (num > 0)
				{
					string text3 = text2.Substring(0, num).Trim();
					string value = text2.Substring(num + 1).Trim();
					if (!string.IsNullOrEmpty(text3) && !string.IsNullOrEmpty(value))
					{
						_map[text3] = value;
					}
				}
			}
			Plugin.Log.LogInfo((object)$"[ColorPresets] {_map.Count} preset(s) loaded from BetterSigns.colors.cfg");
		}

		public static string ExpandAliases(string text)
		{
			if (string.IsNullOrEmpty(text) || _map.Count == 0)
			{
				return text;
			}
			return AliasPattern.Replace(text, delegate(Match match)
			{
				string value = match.Groups[1].Value;
				string text2 = match.Groups[2].Value.Trim();
				string key = text2;
				string text3 = string.Empty;
				int num = text2.IndexOf(',');
				if (num >= 0)
				{
					key = text2.Substring(0, num).TrimEnd();
					text3 = text2.Substring(num);
				}
				string value2;
				return _map.TryGetValue(key, out value2) ? ("<" + value + "=" + value2 + text3 + ">") : match.Value;
			});
		}

		private static void WriteDefaultsTo(string filePath)
		{
			File.WriteAllText(filePath, "# BetterSigns — Color Presets\n# ─────────────────────────────────────────────────────────────────────────────\n# Define named color aliases here so you don't have to type hex codes on signs.\n#\n# Usage examples on a sign:\n#   <color=gold>Welcome!</color>\n#   <glow=fire>DANGER</glow>\n#   <bg=dark>\n#   <color=meadows><rainbow>Spring is here!</rainbow></color>\n#\n# Format:  name = #RRGGBB   or   name = #RRGGBBAA   (alpha optional)\n# Names are case-insensitive.  Lines starting with # are comments.\n# ─────────────────────────────────────────────────────────────────────────────\n\n# ── Primary colors ────────────────────────────────────────────────────────────\nred     = #FF0000\ngreen   = #00CC00\nblue    = #0055FF\nyellow  = #FFFF00\ncyan    = #00FFFF\nmagenta = #FF00FF\norange  = #FF8800\npink    = #FF69B4\npurple  = #8800FF\n\n# ── Neutrals ─────────────────────────────────────────────────────────────────\nwhite   = #FFFFFF\nblack   = #000000\ngrey    = #888888\ngray    = #888888\ndark    = #1A0A00\nlight   = #F0F0F0\n\n# ── Metals ───────────────────────────────────────────────────────────────────\ngold    = #FFD700\nsilver  = #C0C0C0\nbronze  = #CD7F32\ncopper  = #B87333\niron    = #434B4D\n\n# ── Valheim biomes ───────────────────────────────────────────────────────────\nmeadows     = #7CFC00\nblackforest = #1A3300\nswamp       = #4A5240\nmountain    = #D0E8FF\nplains      = #C8A850\nocean       = #006994\nmistlands   = #7788AA\nashlands    = #CC4400\ndeephorth   = #8855AA\n\n# ── Elements / magic ─────────────────────────────────────────────────────────\nfire    = #FF4400\nice     = #88CCFF\npoison  = #44FF44\nblood   = #880000\nspirit  = #AACCFF\nshadow  = #222244\nmist    = #AABBCC\nthunder = #FFEE00\nnature  = #55AA00\n\n# ── UI / status ───────────────────────────────────────────────────────────────\ndanger  = #FF3300\nwarning = #FFAA00\nsafe    = #00CC44\ninfo    = #00AAFF\n");
			Plugin.Log.LogInfo((object)"[ColorPresets] Generated default BetterSigns.colors.cfg");
		}
	}
	public static class ModConfig
	{
		public static ConfigEntry<float> DefaultFontSize { get; private set; }

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

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

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

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

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

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

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

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

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

		public static void Initialize(ConfigFile config)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Expected O, but got Unknown
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Expected O, but got Unknown
			DefaultFontSize = config.Bind<float>("Text", "DefaultFontSize", 0f, new ConfigDescription("Default font size for all signs. 0 = leave TMP default unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			DefaultTextColor = config.Bind<string>("Text", "DefaultTextColor", "", "Default text color for signs without a <color> tag. Accepts #RRGGBB or a named preset. Empty = use TMP default.");
			MaxGlowIntensity = config.Bind<float>("Glow", "MaxGlowIntensity", 1.5f, new ConfigDescription("Maximum emission intensity for <glow> tags (0 = glow disabled server-wide, 10 = very bright). Individual signs can scale this with <glow=#color,multiplier> e.g. <glow=#FF0000,2.0>.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			GlowPulsate = config.Bind<bool>("Glow", "GlowPulsate", false, "When true, glow intensity oscillates between GlowPulsateMinMultiplier and MaxGlowIntensity.");
			GlowPulsateSpeed = config.Bind<float>("Glow", "GlowPulsateSpeed", 1f, new ConfigDescription("Oscillation cycles per second while pulsating.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			GlowPulsateMinMultiplier = config.Bind<float>("Glow", "GlowPulsateMinMultiplier", 0.1f, new ConfigDescription("Fraction of MaxGlowIntensity used at the dim end of the pulse (0 = full fade-out, 1 = no pulse).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			EnableRainbow = config.Bind<bool>("Rainbow", "EnableRainbow", true, "When false, <rainbow> tags are stripped. Disable on low-end servers to save CPU.");
			RainbowSpeed = config.Bind<float>("Rainbow", "RainbowSpeed", 1f, new ConfigDescription("Full hue rotations per second.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			RainbowSaturation = config.Bind<float>("Rainbow", "RainbowSaturation", 1f, new ConfigDescription("Color saturation of the rainbow (0 = grey, 1 = fully saturated).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			RainbowBrightness = config.Bind<float>("Rainbow", "RainbowBrightness", 1f, new ConfigDescription("Color brightness of the rainbow (0 = black, 1 = full brightness).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		}
	}
}