Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BetterSigns v1.1.1
BetterSigns.dll
Decompiled 2 months agousing 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>())); } } }