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>()));
}
}
}