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 d__10 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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(d__10))] private static IEnumerator RegisterSignVariantsWhenReady() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new 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 _signCache = new Dictionary(); [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(); _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(); 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() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } 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 PrefabTemplates = new HashSet(); 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(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(); if ((Object)(object)component != (Object)null) { component.m_name = signVariantDef.DisplayName; component.m_description = signVariantDef.Description; } Sign component2 = val.GetComponent(); if ((Object)(object)component2 != (Object)null) { Traverse.Create((object)component2).Field("m_maxTextLength").SetValue((object)signVariantDef.MaxTextLength); } scene.m_prefabs.Add(val); Dictionary value = Traverse.Create((object)scene).Field>("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()?.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() : null); GameObject itemPrefab3 = ObjectDB.instance.GetItemPrefab("FineWood"); ItemDrop val3 = ((itemPrefab3 != null) ? itemPrefab3.GetComponent() : 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 list = new List(); 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(); 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()).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(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(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(false); if (componentsInChildren.Length == 0) { Plugin.Log.LogWarning((object)"[GlowHelper] No MeshRenderers found on sign — 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(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 d__13 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public SignController <>4__this; public float intensityMult; public Color glowColor; private int 5__2; private MeshRenderer[] 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 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; 5__2 = Shader.PropertyToID("_EmissionColor"); 5__3 = ((Component)signController._sign).GetComponentsInChildren(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 = 5__3; foreach (MeshRenderer val2 in array) { if (!((Object)(object)val2 == (Object)null)) { ((Renderer)val2).material.SetColor(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 d__12 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public SignController <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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 InternalSetSuppressed = new HashSet(); private Sign _sign; private TMP_Text _textField; private SignEffects? _effects; private Coroutine? _rainbowCo; private Coroutine? _pulsateCo; private void Awake() { Sign component = ((Component)this).GetComponent(); 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(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(d__12))] private IEnumerator RainbowCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__12(0) { <>4__this = this }; } [IteratorStateMachine(typeof(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 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("(.*?)", RegexOptions.Compiled | RegexOptions.Singleline); private static readonly Regex RxBg = new Regex("(.*?)", RegexOptions.Compiled | RegexOptions.Singleline); private static readonly Regex RxBgClose = new Regex("", RegexOptions.Compiled); private static readonly Regex RxRainbow = new Regex("(.*?)", 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 += $""; text3 = "" + text3; } string text4 = ColorPresets.ExpandAliases(ModConfig.DefaultTextColor.Value ?? "").Trim(); if (!string.IsNullOrEmpty(text4) && text4.StartsWith("#") && !text.TrimStart().StartsWith(""; text3 = "" + text3; } if (!string.IsNullOrEmpty(text2)) { return text2 + text + text3; } return text; } } } namespace BetterSigns.Config { public static class ColorPresets { private static readonly Dictionary _map = new Dictionary(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# Welcome!\n# DANGER\n# \n# Spring is here!\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 DefaultFontSize { get; private set; } public static ConfigEntry DefaultTextColor { get; private set; } public static ConfigEntry MaxGlowIntensity { get; private set; } public static ConfigEntry GlowPulsate { get; private set; } public static ConfigEntry GlowPulsateSpeed { get; private set; } public static ConfigEntry GlowPulsateMinMultiplier { get; private set; } public static ConfigEntry EnableRainbow { get; private set; } public static ConfigEntry RainbowSpeed { get; private set; } public static ConfigEntry RainbowSaturation { get; private set; } public static ConfigEntry 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("Text", "DefaultFontSize", 0f, new ConfigDescription("Default font size for all signs. 0 = leave TMP default unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); DefaultTextColor = config.Bind("Text", "DefaultTextColor", "", "Default text color for signs without a tag. Accepts #RRGGBB or a named preset. Empty = use TMP default."); MaxGlowIntensity = config.Bind("Glow", "MaxGlowIntensity", 1.5f, new ConfigDescription("Maximum emission intensity for tags (0 = glow disabled server-wide, 10 = very bright). Individual signs can scale this with e.g. .", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10f), Array.Empty())); GlowPulsate = config.Bind("Glow", "GlowPulsate", false, "When true, glow intensity oscillates between GlowPulsateMinMultiplier and MaxGlowIntensity."); GlowPulsateSpeed = config.Bind("Glow", "GlowPulsateSpeed", 1f, new ConfigDescription("Oscillation cycles per second while pulsating.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), Array.Empty())); GlowPulsateMinMultiplier = config.Bind("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(0f, 1f), Array.Empty())); EnableRainbow = config.Bind("Rainbow", "EnableRainbow", true, "When false, tags are stripped. Disable on low-end servers to save CPU."); RainbowSpeed = config.Bind("Rainbow", "RainbowSpeed", 1f, new ConfigDescription("Full hue rotations per second.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), Array.Empty())); RainbowSaturation = config.Bind("Rainbow", "RainbowSaturation", 1f, new ConfigDescription("Color saturation of the rainbow (0 = grey, 1 = fully saturated).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); RainbowBrightness = config.Bind("Rainbow", "RainbowBrightness", 1f, new ConfigDescription("Color brightness of the rainbow (0 = black, 1 = full brightness).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); } } }