Decompiled source of Signs v0.7.0

jcdcdev.Valheim.Signs/jcdcdev.Valheim.Signs.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using SimpleJson;
using TMPro;
using UnityEngine;
using jcdcdev.Valheim.Core;
using jcdcdev.Valheim.Core.Extensions;
using jcdcdev.Valheim.Core.RPC;
using jcdcdev.Valheim.Signs.Converters;
using jcdcdev.Valheim.Signs.Extensions;
using jcdcdev.Valheim.Signs.Models;
using jcdcdev.Valheim.Signs.RPC;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: ComVisible(false)]
[assembly: Guid("915F70BA-D5B8-46C3-9D78-BCD7472FBE25")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("jcdcdev.Valheim.Signs")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © James Carter 2024")]
[assembly: AssemblyFileVersion("0.7.0")]
[assembly: AssemblyInformationalVersion("0.7.0+ca83a42626dd27c7da924134035d8f111320012c")]
[assembly: AssemblyProduct("jcdcdev.Valheim.Signs")]
[assembly: AssemblyTitle("jcdcdev.Valheim.Signs")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.7.0.0")]
[module: UnverifiableCode]
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 jcdcdev.Valheim.Core
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public abstract class BasePlugin<TPlugin> : BaseUnityPlugin where TPlugin : class
	{
		private static TPlugin? _instance;

		private readonly IDictionary<string, object?> _cache = new Dictionary<string, object>();

		public readonly ISimpleRPC BadRequest = new BadRequest();

		public readonly ManualLogSource Logger = Logger.CreateLogSource("Signs");

		private Harmony? _harmony;

		protected abstract string PluginId { get; }

		protected string ConfigBasePath => $"{Paths.ConfigPath}{Path.DirectorySeparatorChar}{PluginId}{Path.DirectorySeparatorChar}";

		public static TPlugin Instance => _instance ?? throw new InvalidOperationException("Plugin is not loaded");

		[UsedImplicitly]
		private void Awake()
		{
			try
			{
				_instance = (this as TPlugin) ?? throw new InvalidOperationException("Plugin " + PluginId + " is not initialised correctly");
				EnsureConfigDirectoryExists();
				BadRequest.Initialise(NetworkManager.Instance);
				OnAwake();
				_harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), PluginId);
			}
			catch (Exception ex)
			{
				Logger.LogIssue(ex, "Error during plugin initialisation");
				throw;
			}
		}

		[UsedImplicitly]
		private void OnDestroy()
		{
			_instance = null;
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void EnsureConfigDirectoryExists()
		{
			if (!Directory.Exists(ConfigBasePath))
			{
				Directory.CreateDirectory(ConfigBasePath);
			}
		}

		public void AddCacheItem(string key, object? value)
		{
			_cache[key] = value;
		}

		protected TItem? GetCacheItem<TItem>(string key) where TItem : class
		{
			if (!_cache.TryGetValue(key, out object value))
			{
				return null;
			}
			if (value is TItem result)
			{
				return result;
			}
			return null;
		}

		protected virtual void OnAwake()
		{
		}

		protected T? ReadJsonFromFile<T>(string path) where T : class
		{
			try
			{
				return JsonHelper.FromJson<T>(File.ReadAllText(path));
			}
			catch (Exception ex)
			{
				Logger.LogIssue(ex, "Error reading " + typeof(T).Name + " from file");
				return null;
			}
		}

		protected void WriteJsonToFile(object model, string path)
		{
			try
			{
				string contents = JsonHelper.ToJson(model);
				File.WriteAllText(path, contents);
				throw new Exception("Test Error");
			}
			catch (Exception ex)
			{
				Logger.LogIssue(ex, "Error writing " + model.GetType().Name + " to file");
			}
		}
	}
	public static class JsonHelper
	{
		public static string? ToJson(object? obj)
		{
			if (obj == null)
			{
				return null;
			}
			return SimpleJson.SerializeObject(obj);
		}

		public static T? FromJson<T>(string? json) where T : class
		{
			if (json == null || string.IsNullOrWhiteSpace(json))
			{
				return null;
			}
			return SimpleJson.DeserializeObject<T>(json);
		}
	}
}
namespace jcdcdev.Valheim.Core.RPC
{
	public class BadRequest : SimpleRPC
	{
		public override IEnumerator Client(long sender, ZPackage? pkg)
		{
			if (sender != ZRoutedRpc.instance.GetServerPeerID())
			{
				Logger.LogWarning((object)"BadRequest called with invalid sender.");
				yield break;
			}
			if (pkg == null || pkg.Size() <= 0)
			{
				Logger.LogWarning((object)"BadRequest called with no payload.");
				yield break;
			}
			string text = pkg.ReadString();
			if (text == "")
			{
				Logger.LogWarning((object)"BadRequest called with empty payload.");
				yield break;
			}
			Logger.LogWarning((object)("BadRequest called: " + text));
			((Terminal)Chat.instance).AddString("Server", "<color=\"red\">" + text + "</color>", (Type)1, false);
		}

		public override IEnumerator Server(long sender, ZPackage? pkg)
		{
			return SimpleRPC.Noop(sender, pkg);
		}
	}
	public interface ISimpleRPC
	{
		void Send(long peerId, ZPackage pkg);

		void Send(long peerId, string? message);

		void Send(long peerId, object? model);

		void SendAll(ZPackage pkg);

		void SendAll(string? message);

		void SendAll(object? model);

		void SendToServer(ZPackage pkg);

		void SendToServer(string? message);

		void SendToServer(object? model);

		IEnumerator ClientInternal(long sender, ZPackage? pkg);

		IEnumerator ServerInternal(long sender, ZPackage? pkg);

		void Initialise(NetworkManager instance);
	}
	public abstract class SimpleRPC : ISimpleRPC
	{
		private CustomRPC _rpc;

		public void Send(long peerId, ZPackage pkg)
		{
			try
			{
				Logger.LogDebug((object)$"\n\nRPC SENT - {_rpc.Name}\n\nRecipient: {peerId}\n");
				_rpc.SendPackage(peerId, pkg);
			}
			catch (Exception ex)
			{
				LoggerExtensions.LogIssue(ex, "Error sending RPC " + _rpc.Name);
			}
		}

		public void Send(long peerId, string? message)
		{
			Send(peerId, CreatePackage(message));
		}

		public void Send(long peerId, object? model)
		{
			Send(peerId, JsonHelper.ToJson(model));
		}

		public void SendAll(ZPackage pkg)
		{
			Send(ZRoutedRpc.Everybody, pkg);
		}

		public void SendAll(string? message)
		{
			Send(ZRoutedRpc.Everybody, message);
		}

		public void SendAll(object? model)
		{
			Send(ZRoutedRpc.Everybody, model);
		}

		public void SendToServer(ZPackage pkg)
		{
			Send(ZRoutedRpc.instance.GetServerPeerID(), pkg);
		}

		public void SendToServer(string? message)
		{
			SendToServer(CreatePackage(message));
		}

		public void SendToServer(object? model)
		{
			SendToServer(JsonHelper.ToJson(model));
		}

		public IEnumerator ClientInternal(long sender, ZPackage? pkg)
		{
			Logger.LogDebug((object)$"\n\nRPC RECEIVED - {_rpc.Name}\n\nRecipient Type: CLIENT\nSender: {sender}\n");
			yield return Client(sender, pkg);
		}

		public IEnumerator ServerInternal(long sender, ZPackage? pkg)
		{
			Logger.LogDebug((object)$"\n\nRPC RECEIVED - {_rpc.Name}\n\nRecipient Type: SERVER\nSender: {sender}\n");
			yield return Server(sender, pkg);
		}

		public void Initialise(NetworkManager instance)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0042: Expected O, but got Unknown
			string name = GetType().Name;
			Logger.LogInfo((object)("Initialising RPC for " + name));
			_rpc = NetworkManager.Instance.AddRPC(name, new CoroutineHandler(Server), new CoroutineHandler(Client));
		}

		protected static IEnumerator Noop(long sender, ZPackage? pkg)
		{
			yield break;
		}

		private static ZPackage CreatePackage(string? message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(message);
			return val;
		}

		public abstract IEnumerator Client(long sender, ZPackage? pkg);

		public abstract IEnumerator Server(long sender, ZPackage? pkg);
	}
	public static class ZNetHelper
	{
		public static bool IsLocalOrServer(this ZNet znet)
		{
			if (!znet.IsLocal())
			{
				return ZNetExtension.IsServerInstance(znet);
			}
			return true;
		}

		public static bool IsLocalOrClient(this ZNet znet)
		{
			if (!znet.IsLocal())
			{
				return ZNetExtension.IsClientInstance(znet);
			}
			return true;
		}

		public static bool IsLocal(this ZNet znet)
		{
			return ZNetExtension.IsLocalInstance(znet);
		}
	}
}
namespace jcdcdev.Valheim.Core.Extensions
{
	public static class LoggerExtensions
	{
		private const string GitHubUrl = "https://github.com/jcdcdev/jcdcdev.Valheim.Signs";

		public static void LogIssue(Exception ex, string? title = null)
		{
			Logger.LogError((object)GetReportText(ex, title));
		}

		public static void LogIssue(this ManualLogSource logger, Exception ex, string? title = null)
		{
			logger.LogError((object)GetReportText(ex, title));
		}

		private static string GetReportText(Exception ex, string? titleText = null)
		{
			string text = ex.Message ?? "An error occurred";
			if (!string.IsNullOrWhiteSpace(titleText) && titleText != null)
			{
				text = titleText;
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(text);
			stringBuilder.AppendLine();
			stringBuilder.AppendHeader("EXCEPTION");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine(ex.ToString());
			string value = stringBuilder.ToString();
			string searchIssueUrl = GetSearchIssueUrl(text);
			string createIssueUrl = GetCreateIssueUrl(text);
			StringBuilder stringBuilder2 = new StringBuilder();
			stringBuilder2.AppendLine();
			stringBuilder2.AppendHeader("ERROR REPORT", bold: true);
			stringBuilder2.AppendLine();
			stringBuilder2.AppendLine(value);
			stringBuilder2.AppendLine();
			stringBuilder2.AppendHeader("HELP & SUPPORT", bold: true);
			stringBuilder2.AppendLine();
			stringBuilder2.AppendLine("Please check for existing issues or create a new issue on GitHub.");
			stringBuilder2.AppendLine();
			stringBuilder2.AppendHeader("SEARCH FOR EXISTING ISSUES");
			stringBuilder2.AppendLine("\n" + searchIssueUrl + "\n");
			stringBuilder2.AppendHeader("CREATE A NEW ISSUE");
			stringBuilder2.AppendLine("\n" + createIssueUrl + "\n");
			return stringBuilder2.ToString();
		}

		private static string GetSearchIssueUrl(string? title)
		{
			return new UriBuilder("https://github.com/jcdcdev/jcdcdev.Valheim.Signs/issues").AddQuery("q", Uri.EscapeUriString("is:issue+is:open+" + title)).ToUriString();
		}

		private static string GetCreateIssueUrl(string title = "An error occurred")
		{
			Dictionary<string, string> query = new Dictionary<string, string>
			{
				{
					"title",
					Uri.EscapeUriString(title)
				},
				{
					"PackageVersion",
					Uri.EscapeUriString("0.7.0")
				},
				{ "labels", "bug" },
				{ "template", "bug.yml" }
			};
			return new UriBuilder("https://github.com/jcdcdev/jcdcdev.Valheim.Signs/issues/new").AddQuery(query).ToUriString();
		}
	}
	public static class PlayerExtensions
	{
		private const string CustomDataKeyPrefix = "jcdcdev-";

		public static T GetCustomData<T>(this Player player, string key, T defaultValue = default(T))
		{
			key = "jcdcdev-" + key;
			try
			{
				if (player.m_customData.TryGetValue(key, out var value))
				{
					Logger.LogDebug((object)("Getting custom data for player: " + player.GetPlayerName() + " with key: " + key + " and value: " + value));
					T val = (T)Convert.ChangeType(value, typeof(T));
					return (T)((val != null) ? ((object)val) : ((object)defaultValue));
				}
				return defaultValue;
			}
			catch (Exception ex)
			{
				Logger.LogError((object)ex);
				return defaultValue;
			}
		}

		public static void SetCustomData(this Player player, string key, string value)
		{
			Logger.LogDebug((object)("Setting custom data for player: " + player.GetPlayerName() + " with key: " + key + " and value: " + value));
			key = "jcdcdev-" + key;
			player.m_customData[key] = value;
		}
	}
	public static class SkillExtensions
	{
		public static string? ToEmoji(this SkillType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected I4, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected I4, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Invalid comparison between Unknown and I4
			switch ((int)type)
			{
			default:
				switch (type - 100)
				{
				default:
					if ((int)type != 999)
					{
						break;
					}
					return string.Empty;
				case 0:
					return "\ud83e\udd98";
				case 1:
					return "\ud83e\udda5";
				case 2:
					return "\ud83c\udfc3";
				case 3:
					return "\ud83c\udfca";
				case 4:
					return "\ud83c\udfa3";
				case 10:
					return "\ud83c\udfc7";
				case 5:
				case 6:
				case 7:
				case 8:
				case 9:
					break;
				}
				return string.Empty;
			case 0:
				return null;
			case 1:
				return "⚔\ufe0f";
			case 2:
				return "\ud83d\udd2a";
			case 3:
				return "\ud83c\udfcf";
			case 4:
				return "\ud83d\udd31";
			case 5:
				return "\ud83d\udde1\ufe0f";
			case 6:
				return "\ud83d\udee1\ufe0f";
			case 7:
				return "\ud83e\ude93";
			case 8:
				return "\ud83c\udff9";
			case 9:
				return "\ud83d\udd25";
			case 10:
				return "\ud83e\ude78";
			case 11:
				return "\ud83e\udd4a";
			case 12:
				return "⛏\ufe0f";
			case 13:
				return "\ud83e\ude93";
			case 14:
				return "\ud83c\udff9";
			}
		}
	}
	public static class StringBuilderExtensions
	{
		public static StringBuilder AppendHeader(this StringBuilder sb, string header, bool bold = false)
		{
			if (bold)
			{
				sb.AppendLine(new string('=', header.Length));
			}
			sb.AppendLine(header ?? "");
			if (bold)
			{
				sb.AppendLine(new string('=', header.Length));
			}
			else
			{
				sb.AppendLine(new string('-', header.Length));
			}
			return sb;
		}
	}
	public static class StringExtensions
	{
		public static bool InvariantEquals(this string value, string compare)
		{
			return value.Equals(compare, StringComparison.InvariantCultureIgnoreCase);
		}

		public static bool StartsWithInvariant(this string value, string compare)
		{
			return value.StartsWith(compare, StringComparison.InvariantCultureIgnoreCase);
		}
	}
	public static class TimeExtensions
	{
		private static readonly TimeSpan DayStartTime = new TimeSpan(6, 0, 0);

		private static readonly TimeSpan NightStartTime = new TimeSpan(18, 0, 0);

		public static float SmoothDayFraction => EnvMan.instance.m_smoothDayFraction;

		public static int CurrentDay => EnvMan.instance.GetCurrentDay();

		public static TimeSpan CalculateTimeLeftInDay()
		{
			TimeSpan timeOfDay = ServerTimeNow().TimeOfDay;
			Logger.LogDebug((object)$"Game Time:\n\n{timeOfDay}\nServer Time:\n\n{LocalNow().TimeOfDay}");
			if (timeOfDay < DayStartTime || timeOfDay >= NightStartTime)
			{
				return TimeSpan.Zero;
			}
			return NightStartTime - timeOfDay;
		}

		public static string GetTimeFormat(string? originalText)
		{
			if (originalText == null || string.IsNullOrWhiteSpace(originalText))
			{
				return "HH:mm";
			}
			List<string> source = originalText.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).ToList();
			bool flag = source.Any((string x) => x == "12");
			return source.LastOrDefault((string x) => x != "12") switch
			{
				"s" => flag ? "h:mm:ss tt" : "HH:mm:ss", 
				"f" => "f", 
				"F" => "F", 
				"g" => "g", 
				"G" => "G", 
				"r" => "r", 
				"R" => "R", 
				"U" => "U", 
				_ => flag ? "h:mm tt" : "HH:mm", 
			};
		}

		public static string GetFuzzyTime()
		{
			string[] array = new string[24]
			{
				"Midnight", "Early Morning", "Early Morning", "Before Dawn", "Before Dawn", "Dawn", "Dawn", "Morning", "Morning", "Late Morning",
				"Late Morning", "Midday", "Midday", "Early Afternoon", "Early Afternoon", "Afternoon", "Afternoon", "Evening", "Evening", "Night",
				"Night", "Late Night", "Late Night", "Midnight"
			};
			int num = Math.Min((int)((float)array.Length * SmoothDayFraction), array.Length - 1);
			return array[num] ?? "";
		}

		public static DateTime ServerTimeNow()
		{
			int num = (int)(SmoothDayFraction * 24f);
			int num2 = (int)((SmoothDayFraction * 24f - (float)num) * 60f);
			int seconds = (int)(((SmoothDayFraction * 24f - (float)num) * 60f - (float)num2) * 60f);
			TimeSpan value = new TimeSpan(num, num2, seconds);
			DateTime minValue = DateTime.MinValue;
			return minValue.AddDays(EnvMan.instance.GetCurrentDay()).Add(value);
		}

		public static DateTime LocalNow(TimeZoneInfo? timeZone = null)
		{
			if (timeZone == null)
			{
				timeZone = TimeZoneInfo.Local;
			}
			return TimeZoneInfo.ConvertTime(DateTime.UtcNow, timeZone);
		}

		public static string ToEmojiClock(this DateTime? time)
		{
			int num = time?.Hour ?? 0;
			int num2 = time?.Minute ?? 0;
			if (num2 >= 0 && num2 < 30)
			{
				return num switch
				{
					0 => "\ud83d\udd5b", 
					1 => "\ud83d\udd50", 
					2 => "\ud83d\udd51", 
					3 => "\ud83d\udd52", 
					4 => "\ud83d\udd53", 
					5 => "\ud83d\udd54", 
					6 => "\ud83d\udd55", 
					7 => "\ud83d\udd56", 
					8 => "\ud83d\udd57", 
					9 => "\ud83d\udd58", 
					10 => "\ud83d\udd59", 
					11 => "\ud83d\udd5a", 
					12 => "\ud83d\udd5b", 
					13 => "\ud83d\udd50", 
					14 => "\ud83d\udd51", 
					15 => "\ud83d\udd52", 
					16 => "\ud83d\udd53", 
					17 => "\ud83d\udd54", 
					18 => "\ud83d\udd55", 
					19 => "\ud83d\udd56", 
					20 => "\ud83d\udd57", 
					21 => "\ud83d\udd58", 
					22 => "\ud83d\udd59", 
					23 => "\ud83d\udd5a", 
					_ => "\ud83d\udd5b", 
				};
			}
			return num switch
			{
				0 => "\ud83d\udd67", 
				1 => "\ud83d\udd5c", 
				2 => "\ud83d\udd5d", 
				3 => "\ud83d\udd5e", 
				4 => "\ud83d\udd5f", 
				5 => "\ud83d\udd60", 
				6 => "\ud83d\udd61", 
				7 => "\ud83d\udd62", 
				8 => "\ud83d\udd63", 
				9 => "\ud83d\udd64", 
				10 => "\ud83d\udd65", 
				11 => "\ud83d\udd66", 
				12 => "\ud83d\udd67", 
				13 => "\ud83d\udd5c", 
				14 => "\ud83d\udd5d", 
				15 => "\ud83d\udd5e", 
				16 => "\ud83d\udd5f", 
				17 => "\ud83d\udd60", 
				18 => "\ud83d\udd61", 
				19 => "\ud83d\udd62", 
				20 => "\ud83d\udd63", 
				21 => "\ud83d\udd64", 
				22 => "\ud83d\udd65", 
				23 => "\ud83d\udd66", 
				_ => "\ud83d\udd67", 
			};
		}
	}
	public static class UriBuilderExtensions
	{
		public static UriBuilder AddQuery(this UriBuilder uriBuilder, string key, string value)
		{
			string query = uriBuilder.Query;
			if (query.Length > 1)
			{
				query = query.Substring(1);
				query = query + "&" + key + "=" + value;
			}
			else
			{
				query = key + "=" + value;
			}
			uriBuilder.Query = query;
			return uriBuilder;
		}

		public static UriBuilder AddQuery(this UriBuilder uriBuilder, Dictionary<string, string> query)
		{
			uriBuilder.Query = string.Join("&", query.Select<KeyValuePair<string, string>, string>((KeyValuePair<string, string> x) => x.Key + "=" + x.Value));
			return uriBuilder;
		}

		public static string ToUriString(this UriBuilder uriBuilder)
		{
			if (uriBuilder.Port == 443)
			{
				uriBuilder.Port = -1;
			}
			return uriBuilder.ToString();
		}
	}
}
namespace jcdcdev.Valheim.Signs
{
	public static class Constants
	{
		public static class CacheKeys
		{
			public static string DeathLeaderboard => "DeathLeaderboard";
		}

		public const string PluginId = "jcdcdev.Valheim.Signs";

		public const string PluginName = "jcdcdev - Signs";

		public static readonly Regex HandlebarRegexPattern = new Regex("{{([^}}]+)}}", RegexOptions.Compiled);

		public static readonly Regex HoverTextRegexPattern = new Regex("\"([^\"]*)\"", RegexOptions.Compiled);

		public const string DefaultHoverError = "Invalid sign";

		public static string ErrorMessage(string error)
		{
			return "<color=\"red\">ERROR</color>\n" + error;
		}
	}
	[BepInPlugin("jcdcdev.Valheim.Signs", "jcdcdev - Signs", "0.7.0")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class SignsPlugin : BasePlugin<SignsPlugin>
	{
		public static readonly bool IsAzuSignsInstalled = Chainloader.PluginInfos.ContainsKey("Azumatt.AzuSigns");

		private static readonly List<IAmADynamicSign> DynamicSigns = new List<IAmADynamicSign>();

		public readonly ISimpleRPC DeathLeaderboardUpdateRequest = new DeathLeaderboardUpdateRequest();

		public readonly ISimpleRPC DeathLeaderboardUpdateResponse = new DeathLeaderboardUpdateResponse();

		public readonly ISimpleRPC DeathUpdate = new DeathUpdate();

		private readonly Dictionary<int, SmelterDto> _smelters = new Dictionary<int, SmelterDto>();

		public ConfigEntry<int> SmelterRadius;

		private string LeaderboardPath => base.ConfigBasePath + "death-leaderboard.json";

		protected override string PluginId => "jcdcdev.Valheim.Signs";

		protected override void OnAwake()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			DeathUpdate.Initialise(NetworkManager.Instance);
			DeathLeaderboardUpdateRequest.Initialise(NetworkManager.Instance);
			DeathLeaderboardUpdateResponse.Initialise(NetworkManager.Instance);
			SmelterRadius = ((BaseUnityPlugin)this).Config.Bind<int>("Smelter", "Radius", 10, new ConfigDescription("The radius to search for smelters", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			AddSigns();
			EnsureLeaderboardFileExists();
		}

		private void EnsureLeaderboardFileExists()
		{
			if (!File.Exists(LeaderboardPath))
			{
				WriteJsonToFile(PlayerDeathLeaderBoard.Empty, LeaderboardPath);
			}
		}

		private void AddSigns()
		{
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			foreach (Type type in types)
			{
				if (!type.IsAbstract && !type.IsInterface && typeof(IAmADynamicSign).IsAssignableFrom(type) && Activator.CreateInstance(type) is IAmADynamicSign sign)
				{
					AddSign(sign);
				}
			}
		}

		private void AddSign(IAmADynamicSign sign)
		{
			DynamicSigns.Add(sign);
		}

		public bool TryGetSignText(Sign sign, string? input, out string? output)
		{
			Sign sign2 = sign;
			string input2 = input;
			output = null;
			if (input2 == null)
			{
				Logger.LogDebug((object)"No token found.");
				return false;
			}
			IAmADynamicSign amADynamicSign = DynamicSigns.FirstOrDefault((IAmADynamicSign x) => x.CanConvert(sign2, input2));
			if (amADynamicSign == null)
			{
				Logger.LogDebug((object)("No converter found for " + input2));
				return false;
			}
			string signText = amADynamicSign.GetSignText(sign2, input2);
			if (signText == null || Utility.IsNullOrWhiteSpace(signText))
			{
				Logger.LogDebug((object)"No result found.");
				return false;
			}
			output = signText;
			return true;
		}

		public bool Client_GetSignText(Sign sign, string signText, out string output)
		{
			output = signText;
			try
			{
				foreach (string item in Client_GetTokenValue(signText))
				{
					if (TryGetSignText(sign, item, out string output2) && output2 != null)
					{
						output = output.Replace("{{" + item + "}}", output2);
					}
				}
				return output != signText;
			}
			catch (Exception ex)
			{
				Logger.LogIssue(ex, "Error getting sign text");
				return false;
			}
		}

		private IEnumerable<string> Client_GetTokenValue(string originalText)
		{
			try
			{
				MatchCollection matchCollection = Constants.HandlebarRegexPattern.Matches(originalText);
				if (matchCollection.Count == 0)
				{
					return new List<string>();
				}
				List<string> list = new List<string>();
				foreach (Match item in matchCollection)
				{
					list.Add(item.Groups[1].Value);
				}
				return list;
			}
			catch (Exception ex)
			{
				Logger.LogIssue(ex, "Error getting sign token values");
				return new List<string>();
			}
		}

		public bool Client_GetSignHoverText(Sign sign, string originalText, out string output)
		{
			Logger.LogDebug((object)("Sign Hover: " + originalText));
			output = string.Empty;
			IEnumerable<string> enumerable = Client_GetTokenValue(originalText);
			List<string> list = new List<string>();
			foreach (string item in enumerable)
			{
				if (TryGetSignHoverText(sign, item, out string hover) && hover != null)
				{
					list.Add(hover);
				}
			}
			if (list.Count == 0)
			{
				return false;
			}
			string text = "[<color=\"yellow\">DYNAMIC</color>] " + string.Join(" ", list);
			output = Constants.HoverTextRegexPattern.Replace(originalText, text ?? "");
			Logger.LogDebug((object)("Sign Hover: " + output));
			return output != originalText;
		}

		private bool TryGetSignHoverText(Sign sign, string? originalValue, out string? hover)
		{
			Sign sign2 = sign;
			string originalValue2 = originalValue;
			hover = null;
			if (originalValue2 == null)
			{
				Logger.LogDebug((object)"No token found.");
				return false;
			}
			IAmADynamicSign amADynamicSign = DynamicSigns.FirstOrDefault((IAmADynamicSign x) => x.CanConvert(sign2, originalValue2));
			if (amADynamicSign == null)
			{
				Logger.LogDebug((object)"No converter found.");
				return false;
			}
			string signHoverText = amADynamicSign.GetSignHoverText(sign2, originalValue2);
			if (signHoverText == null || Utility.IsNullOrWhiteSpace(signHoverText))
			{
				Logger.LogDebug((object)"No hover text found.");
				return false;
			}
			hover = signHoverText;
			return true;
		}

		public PlayerDeathLeaderBoard? Server_GetDeathLeaderboard()
		{
			if (!ZNet.instance.IsLocalOrServer())
			{
				Logger.LogWarning((object)"GetServerDeathLeaderBoardModel called on client.");
				return null;
			}
			try
			{
				string leaderboardPath = LeaderboardPath;
				if (!File.Exists(leaderboardPath))
				{
					Logger.LogWarning((object)"Death Leaderboard file not found.");
					return null;
				}
				PlayerDeathLeaderBoard playerDeathLeaderBoard = ReadJsonFromFile<PlayerDeathLeaderBoard>(leaderboardPath);
				if (playerDeathLeaderBoard == null)
				{
					Logger.LogWarning((object)"Death Leaderboard file is empty.");
					return null;
				}
				Logger.LogDebug((object)("File Based Death Leaderboard:\n\n" + playerDeathLeaderBoard.GetSignText()));
				return playerDeathLeaderBoard;
			}
			catch (Exception ex)
			{
				Logger.LogIssue(ex, "Error getting death leaderboard");
				return null;
			}
		}

		public PlayerDeathLeaderBoard? Client_GetOrRequestDeathLeaderboard()
		{
			if (!ZNet.instance.IsLocalOrClient())
			{
				Logger.LogWarning((object)"Client method called on server: Client_GetOrRequestDeathLeaderboard");
				return null;
			}
			PlayerDeathLeaderBoard cacheItem = GetCacheItem<PlayerDeathLeaderBoard>(Constants.CacheKeys.DeathLeaderboard);
			if (cacheItem != null)
			{
				Logger.LogDebug((object)"Using cached death leaderboard.");
				return cacheItem;
			}
			ISimpleRPC deathLeaderboardUpdateRequest = DeathLeaderboardUpdateRequest;
			DateTime minValue = DateTime.MinValue;
			deathLeaderboardUpdateRequest.SendToServer((object?)minValue.Ticks);
			return null;
		}

		public void Server_UpdateDeath(PlayerDeathInfo data)
		{
			PlayerDeathInfo data2 = data;
			try
			{
				string leaderboardPath = LeaderboardPath;
				PlayerDeathLeaderBoard playerDeathLeaderBoard = ReadJsonFromFile<PlayerDeathLeaderBoard>(leaderboardPath);
				if (playerDeathLeaderBoard == null)
				{
					Logger.LogWarning((object)"Death Leaderboard file not found.");
					return;
				}
				PlayerDeathInfo playerDeathInfo = playerDeathLeaderBoard.Players.FirstOrDefault((PlayerDeathInfo x) => x.Id == data2.Id);
				if (playerDeathInfo == null)
				{
					Logger.LogWarning((object)"Player not found in leaderboard.");
					playerDeathLeaderBoard.Players.Add(data2);
				}
				else
				{
					if (playerDeathInfo.Deaths == data2.Deaths)
					{
						Logger.LogDebug((object)"Player death count is the same. No update needed.");
						return;
					}
					Logger.LogInfo((object)$"Updating Death Count - {playerDeathInfo.Name}: {playerDeathInfo.Deaths} => {data2.Deaths}");
					playerDeathInfo.Deaths = data2.Deaths;
				}
				playerDeathLeaderBoard.Players = playerDeathLeaderBoard.Players.OrderByDescending((PlayerDeathInfo x) => x.Deaths).ToList();
				playerDeathLeaderBoard.Updated = DateTime.UtcNow;
				DeathLeaderboardUpdateResponse.SendAll((object?)playerDeathLeaderBoard);
				WriteJsonToFile(playerDeathLeaderBoard, leaderboardPath);
			}
			catch (Exception ex)
			{
				Logger.LogIssue(ex, "Error updating death leaderboard");
			}
		}

		public void Client_SendDeathUpdateRequest(Player player)
		{
			if (!ZNet.instance.IsLocalOrClient())
			{
				Logger.LogWarning((object)"InvokeDeathUpdateRequest called on server.");
			}
			else
			{
				DeathUpdate.SendToServer((object?)player.GetDeathInfo());
			}
		}

		public SmelterDto? Client_GetClosestSmelter(Vector3 position)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!ZNet.instance.IsLocalOrClient())
			{
				Logger.LogError((object)"GetClosestSmelter called on server.");
				return null;
			}
			SmelterDto smelterDto = _smelters.Values.OrderBy((SmelterDto x) => Vector3.Distance(position, x.Position)).FirstOrDefault();
			if (smelterDto == null)
			{
				Logger.LogDebug((object)"Smelter not found.");
				return null;
			}
			float num = Vector3.Distance(position, smelterDto.Position);
			Logger.LogDebug((object)$"Closest Smelter: {num} - {smelterDto.Id}");
			if (num > (float)SmelterRadius.Value)
			{
				Logger.LogDebug((object)"Smelter is too far away.");
				return null;
			}
			return smelterDto;
		}

		public List<SmelterDto> Client_GetAllSmelters()
		{
			if (!ZNet.instance.IsLocalOrClient())
			{
				Logger.LogWarning((object)"GetSmelters called on server.");
				return new List<SmelterDto>();
			}
			return _smelters.Values.ToList();
		}

		public void Client_AddSmelter(Smelter smelter)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if (!ZNet.instance.IsLocalOrClient())
			{
				Logger.LogWarning((object)"AddSmelter called on server.");
				return;
			}
			int instanceID = ((Object)smelter).GetInstanceID();
			if (_smelters.ContainsKey(instanceID))
			{
				Logger.LogWarning((object)"Smelter already exists.");
				return;
			}
			SmelterDto value = new SmelterDto
			{
				Id = instanceID,
				X = ((Component)smelter).transform.position.x,
				Y = ((Component)smelter).transform.position.y,
				Z = ((Component)smelter).transform.position.z
			};
			_smelters.Add(instanceID, value);
		}
	}
	public class SmelterDto
	{
		public int Id { get; set; }

		public float X { get; set; }

		public float Y { get; set; }

		public float Z { get; set; }

		public Vector3 Position => new Vector3(X, Y, Z);
	}
	public static class VersionInfo
	{
		public const string Version = "0.7.0";
	}
}
namespace jcdcdev.Valheim.Signs.RPC
{
	public class DeathLeaderboardUpdateRequest : SimpleRPC
	{
		public override IEnumerator Client(long sender, ZPackage? pkg)
		{
			return SimpleRPC.Noop(sender, pkg);
		}

		public override IEnumerator Server(long sender, ZPackage? pkg)
		{
			if (pkg == null)
			{
				Logger.LogWarning((object)"No payload received for DeathUpdate");
				BasePlugin<SignsPlugin>.Instance.BadRequest.Send(sender, "No payload received for DeathUpdate");
				yield break;
			}
			string s = pkg.ReadString();
			DateTime dateTime = DateTime.MinValue;
			if (long.TryParse(s, out var result))
			{
				dateTime = new DateTime(result);
			}
			try
			{
				PlayerDeathLeaderBoard playerDeathLeaderBoard = BasePlugin<SignsPlugin>.Instance.Server_GetDeathLeaderboard();
				if (playerDeathLeaderBoard == null)
				{
					yield break;
				}
				if (playerDeathLeaderBoard.Updated <= dateTime)
				{
					Logger.LogDebug((object)$"DeathLeaderboard is up to date. Server Last Updated: {playerDeathLeaderBoard.Updated} Client Last Updated: {dateTime}");
					yield break;
				}
				BasePlugin<SignsPlugin>.Instance.DeathLeaderboardUpdateResponse.Send(sender, (object?)playerDeathLeaderBoard);
			}
			catch (Exception ex)
			{
				Logger.LogError((object)ex);
			}
			yield return null;
		}
	}
	public class DeathLeaderboardUpdateResponse : SimpleRPC
	{
		public override IEnumerator Client(long sender, ZPackage? pkg)
		{
			if (pkg == null || pkg.Size() <= 0)
			{
				Logger.LogWarning((object)"DeathLeaderboardResponse called with no payload.");
				yield break;
			}
			string text = pkg.ReadString();
			if (text == "")
			{
				Logger.LogWarning((object)"DeathLeaderboardResponse called with empty payload.");
				yield break;
			}
			try
			{
				PlayerDeathLeaderBoard playerDeathLeaderBoard = JsonHelper.FromJson<PlayerDeathLeaderBoard>(text);
				if (playerDeathLeaderBoard == null || playerDeathLeaderBoard.Updated == DateTime.MinValue)
				{
					Logger.LogWarning((object)"DeathLeaderboardResponse called with invalid payload.");
				}
				else
				{
					BasePlugin<SignsPlugin>.Instance.AddCacheItem(Constants.CacheKeys.DeathLeaderboard, playerDeathLeaderBoard);
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)ex);
			}
		}

		public override IEnumerator Server(long sender, ZPackage? pkg)
		{
			if (!ZNet.instance.IsLocal())
			{
				return SimpleRPC.Noop(sender, pkg);
			}
			return Client(sender, pkg);
		}
	}
	public class DeathUpdate : SimpleRPC
	{
		public override IEnumerator Client(long sender, ZPackage? pkg)
		{
			return SimpleRPC.Noop(sender, pkg);
		}

		public override IEnumerator Server(long sender, ZPackage? pkg)
		{
			if (pkg == null)
			{
				Logger.LogWarning((object)"No payload received for DeathUpdate");
				BasePlugin<SignsPlugin>.Instance.BadRequest.Send(sender, "Failed to update death count.");
				yield break;
			}
			Logger.LogDebug((object)"DeathUpdate called.");
			PlayerDeathInfo playerDeathInfo = JsonHelper.FromJson<PlayerDeathInfo>(pkg.ReadString());
			if (playerDeathInfo == null)
			{
				Logger.LogWarning((object)"Failed to parse payload for DeathUpdate");
				BasePlugin<SignsPlugin>.Instance.BadRequest.Send(sender, "Failed to update death count.");
			}
			else
			{
				BasePlugin<SignsPlugin>.Instance.Server_UpdateDeath(playerDeathInfo);
			}
		}
	}
}
namespace jcdcdev.Valheim.Signs.Patches
{
	[HarmonyPatch(typeof(Player), "OnDeath")]
	public static class PlayerOnDeath
	{
		public static void Postfix(Player __instance)
		{
			Logger.LogDebug((object)"PlayerOnDeath.Postfix");
			__instance.IncrementDeathCount();
			BasePlugin<SignsPlugin>.Instance.Client_SendDeathUpdateRequest(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	public class PlayerOnSpawned
	{
		public static void Postfix(Player __instance)
		{
			Logger.LogDebug((object)"PlayerOnSpawned.Postfix");
			BasePlugin<SignsPlugin>.Instance.Client_SendDeathUpdateRequest(__instance);
		}
	}
	[HarmonyPatch(typeof(Sign), "GetHoverText")]
	public static class SignGetHoverText
	{
		public static void Postfix(Sign __instance, ref string __result)
		{
			Logger.LogDebug((object)"SignGetHoverText.Postfix");
			try
			{
				string originalText = __result;
				if (!BasePlugin<SignsPlugin>.Instance.Client_GetSignHoverText(__instance, originalText, out string output))
				{
					Logger.LogDebug((object)"SignGetHoverText.Postfix: No output");
				}
				else
				{
					__result = output;
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(Sign), "UpdateText")]
	[HarmonyPriority(0)]
	public static class SignUpdateText
	{
		public static void Postfix(Sign __instance)
		{
			Logger.LogDebug((object)"SignUpdateText.Postfix");
			ZNetView nview = __instance.m_nview;
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				Logger.LogWarning((object)"SignUpdateText.Postfix: view is null or invalid");
				return;
			}
			try
			{
				nview.ClaimOwnership();
				ZDO zDO = nview.GetZDO();
				string signText = GetSignText(__instance, zDO);
				if (!BasePlugin<SignsPlugin>.Instance.Client_GetSignText(__instance, signText, out string output))
				{
					Logger.LogDebug((object)"SignUpdateText.Postfix: No output");
				}
				else
				{
					SetSignText(__instance, zDO, output);
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)ex);
			}
		}

		private static void SetSignText(Sign __instance, ZDO zdo, string output)
		{
			if (SignsPlugin.IsAzuSignsInstalled)
			{
				zdo.Set("newText", output);
			}
			((TMP_Text)__instance.m_textWidget).text = output;
		}

		private static string GetSignText(Sign __instance, ZDO zdo)
		{
			string @string = zdo.GetString("newText", "");
			string string2 = zdo.GetString("text", "");
			string defaultText = __instance.m_defaultText;
			string text = ((!SignsPlugin.IsAzuSignsInstalled) ? (Utility.IsNullOrWhiteSpace(string2) ? defaultText : string2) : (Utility.IsNullOrWhiteSpace(@string) ? string2 : @string));
			Logger.LogDebug((object)("SignUpdateText.Postfix: NEW TEXT: " + @string));
			Logger.LogDebug((object)("SignUpdateText.Postfix: TEXT: " + string2));
			Logger.LogDebug((object)("SignUpdateText.Postfix: DEFAULT: " + defaultText));
			Logger.LogDebug((object)("SignUpdateText.Postfix: RESULT OUTPUT: " + text));
			return text;
		}
	}
	[HarmonyPatch(typeof(Smelter), "Awake")]
	public static class SmelterAwakePatch
	{
		private static void Postfix(Smelter __instance)
		{
			BasePlugin<SignsPlugin>.Instance.Client_AddSmelter(__instance);
		}
	}
}
namespace jcdcdev.Valheim.Signs.Models
{
	public class PlayerDeathInfo
	{
		public int Deaths { get; set; }

		public long Id { get; set; }

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

	}
	public class PlayerDeathLeaderBoard
	{
		public static PlayerDeathLeaderBoard Empty => new PlayerDeathLeaderBoard
		{
			Updated = DateTime.MinValue,
			Players = new List<PlayerDeathInfo>()
		};

		public List<PlayerDeathInfo> Players { get; set; } = new List<PlayerDeathInfo>();


		public DateTime Updated { get; set; }

		public string GetSignText(int take = int.MaxValue)
		{
			List<PlayerDeathInfo> list = Players.OrderByDescending((PlayerDeathInfo x) => x.Deaths).Take(take).ToList();
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < list.Count; i++)
			{
				PlayerDeathInfo playerDeathInfo = list[i];
				stringBuilder.AppendLine($"{i + 1}. {playerDeathInfo.Name}: {playerDeathInfo.Deaths}");
			}
			return stringBuilder.ToString();
		}
	}
}
namespace jcdcdev.Valheim.Signs.Extensions
{
	public static class PlayerExtensions
	{
		public static PlayerDeathInfo GetDeathInfo(this Player player)
		{
			return new PlayerDeathInfo
			{
				Deaths = player.GetDeathCount(),
				Id = player.GetPlayerID(),
				Name = player.GetPlayerName()
			};
		}

		public static int GetDeathCount(this Player player)
		{
			string key = DeathsWorldKey(ZNet.m_world.m_uid);
			return player.GetCustomData(key, 0);
		}

		public static int IncrementDeathCount(this Player player)
		{
			Logger.LogDebug((object)"Incrementing death count.");
			string key = DeathsWorldKey(ZNet.m_world.m_uid);
			int customData = player.GetCustomData(key, 0);
			customData++;
			player.SetCustomData(key, $"{customData}");
			Logger.LogDebug((object)$"Deaths: {customData}");
			return customData;
		}

		private static string DeathsWorldKey(long worldUid)
		{
			return $"deaths-world-{worldUid}";
		}
	}
}
namespace jcdcdev.Valheim.Signs.Converters
{
	public class ActualTimeSign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.StartsWithInvariant("actualTime");
		}

		public string? GetSignText(Sign sign, string input)
		{
			DateTime value = TimeExtensions.LocalNow(TimeZoneInfo.Local);
			if (input.Contains("emoji"))
			{
				return TimeExtensions.ToEmojiClock(value);
			}
			string timeFormat = TimeExtensions.GetTimeFormat(input);
			return value.ToString(timeFormat);
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Actual Time";
		}
	}
	public class ComfortSign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				return input.InvariantEquals("comfort");
			}
			return false;
		}

		public string? GetSignText(Sign sign, string input)
		{
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer == null)
			{
				return null;
			}
			return localPlayer.GetComfortLevel().ToString();
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Comfort";
		}
	}
	public class CurrentDaySign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.StartsWith("currentDay", StringComparison.InvariantCultureIgnoreCase);
		}

		public string? GetSignText(Sign sign, string input)
		{
			return TimeExtensions.CurrentDay.ToString();
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Current Day";
		}
	}
	public class DayPercentSign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.StartsWithInvariant("dayPercent");
		}

		public string? GetSignText(Sign sign, string input)
		{
			float smoothDayFraction = TimeExtensions.SmoothDayFraction;
			if ((smoothDayFraction <= 0.25f || smoothDayFraction >= 0.75f) ? true : false)
			{
				return "-";
			}
			float num = (smoothDayFraction - 0.25f) * 100f / 0.5f;
			return $"{num:F0}%";
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Day percentage";
		}
	}
	public class DeathCountSign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.StartsWithInvariant("deathCount");
		}

		public string? GetSignText(Sign sign, string input)
		{
			string playerId = input.ToLowerInvariant().Replace("deathcount", string.Empty).Trim();
			if (Utility.IsNullOrWhiteSpace(playerId))
			{
				return Player.m_localPlayer?.GetDeathCount().ToString();
			}
			PlayerDeathLeaderBoard playerDeathLeaderBoard = BasePlugin<SignsPlugin>.Instance.Client_GetOrRequestDeathLeaderboard();
			if (playerDeathLeaderBoard == null)
			{
				return Constants.ErrorMessage("Leaderboard not available");
			}
			long id;
			PlayerDeathInfo playerDeathInfo = ((!long.TryParse(playerId, out id)) ? playerDeathLeaderBoard.Players.FirstOrDefault((PlayerDeathInfo x) => x.Name.InvariantEquals(playerId)) : playerDeathLeaderBoard.Players.FirstOrDefault((PlayerDeathInfo x) => x.Id == id));
			if (playerDeathInfo != null)
			{
				return playerDeathInfo.Deaths.ToString();
			}
			return Constants.ErrorMessage("Player not found");
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Deaths Count";
		}
	}
	public class DeathLeaderboardSign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.StartsWithInvariant("deathBoard");
		}

		public string? GetSignText(Sign sign, string input)
		{
			int take = 3;
			string[] array = input.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				if (int.TryParse(array[i], out var result))
				{
					take = result;
					break;
				}
			}
			return BasePlugin<SignsPlugin>.Instance.Client_GetOrRequestDeathLeaderboard()?.GetSignText(take);
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Deaths Leaderboard";
		}
	}
	public class FuzzyTime : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.StartsWithInvariant("fuzzyTime");
		}

		public string? GetSignText(Sign sign, string input)
		{
			return TimeExtensions.GetFuzzyTime();
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Fuzzy Time";
		}
	}
	public class GameTimeSign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.StartsWith("gameTime", StringComparison.InvariantCultureIgnoreCase);
		}

		public string? GetSignText(Sign sign, string input)
		{
			DateTime value = TimeExtensions.ServerTimeNow();
			if (input.Contains("emoji"))
			{
				return TimeExtensions.ToEmojiClock(value);
			}
			string timeFormat = TimeExtensions.GetTimeFormat(input);
			return value.ToString(timeFormat);
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Game Time";
		}
	}
	public interface IAmADynamicSign
	{
		bool CanConvert(Sign sign, string input);

		string? GetSignText(Sign sign, string input);

		string? GetSignHoverText(Sign sign, string input);
	}
	public class NightCountdownSign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.StartsWithInvariant("nightCountdown");
		}

		public string? GetSignText(Sign sign, string input)
		{
			bool flag = input.ToLowerInvariant().Replace("nightCountdown", string.Empty).Contains("s");
			TimeSpan timeSpan = TimeExtensions.CalculateTimeLeftInDay();
			TimeSpan zero = TimeSpan.Zero;
			if (timeSpan == zero)
			{
				return "-";
			}
			TimeSpan timeSpan2 = ConvertToRealTime(timeSpan, zero);
			if (!flag)
			{
				return timeSpan2.ToString("mm");
			}
			return timeSpan2.ToString("mm\\:ss");
		}

		private static TimeSpan ConvertToRealTime(TimeSpan current, TimeSpan end)
		{
			double num = (end - current).TotalHours / 24.0;
			return TimeSpan.FromSeconds(2700.0 * num);
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Time left until night";
		}
	}
	public class OnlineCountSign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.Equals("onlineCount", StringComparison.InvariantCultureIgnoreCase);
		}

		public string? GetSignText(Sign sign, string input)
		{
			return $"{ZNet.instance.GetPlayerList().Count}";
		}

		public string GetSignHoverText(Sign sign, string input)
		{
			return "Online Players";
		}
	}
	public class PlayerHealthSign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.InvariantEquals("health");
		}

		public string? GetSignText(Sign sign, string input)
		{
			float health = ((Character)Player.m_localPlayer).GetHealth();
			float maxHealth = ((Character)Player.m_localPlayer).GetMaxHealth();
			return $"{health:F0}/{maxHealth:F0}";
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Health";
		}
	}
	public class PlayerStaminaSign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.InvariantEquals("stamina");
		}

		public string? GetSignText(Sign sign, string input)
		{
			float stamina = Player.m_localPlayer.m_stamina;
			float maxStamina = Player.m_localPlayer.m_maxStamina;
			return $"{stamina:F0}/{maxStamina:F0}";
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Stamina";
		}
	}
	public class SkillSign : IAmADynamicSign
	{
		public bool CanConvert(Sign sign, string input)
		{
			return input.StartsWithInvariant("skill");
		}

		public string? GetSignText(Sign sign, string input)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return Constants.ErrorMessage("Player not found");
			}
			bool flag = input.Contains("emoji");
			bool flag2 = input.Contains("label");
			SkillType skill = GetSkill(input);
			if ((int)skill == 0)
			{
				return Constants.ErrorMessage("Invalid skill");
			}
			float skillLevel = ((Character)localPlayer).GetSkillLevel(skill);
			string text = string.Empty;
			if (flag)
			{
				text = skill.ToEmoji() + " ";
			}
			if (flag2)
			{
				text += $"{skill} ";
			}
			return text + $"{skillLevel:F0}";
		}

		private static SkillType GetSkill(string input)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (!Enum.TryParse<SkillType>(input.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).FirstOrDefault(), ignoreCase: true, out SkillType result))
			{
				return (SkillType)0;
			}
			return result;
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			SkillType skill = GetSkill(input);
			if ((int)skill != 0)
			{
				return ((object)(SkillType)(ref skill)).ToString();
			}
			return "Invalid sign";
		}
	}
	public class SmelterContentSign : IAmADynamicSign
	{
		private const string Tag = "smelterContent";

		public bool CanConvert(Sign sign, string input)
		{
			return input.StartsWithInvariant("smelterContent");
		}

		public string? GetSignText(Sign sign, string input)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			List<string> source = input.ToLowerInvariant().Replace("smelterContent".ToLowerInvariant(), "").Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
				.ToList();
			bool flag = source.All((string x) => x != "l");
			bool flag2 = source.Any((string x) => x == "f");
			bool flag3 = source.Any((string x) => x == "o");
			if (!flag2 && !flag3)
			{
				flag2 = true;
				flag3 = true;
				flag = true;
			}
			SmelterDto dto = BasePlugin<SignsPlugin>.Instance.Client_GetClosestSmelter(((Component)sign).transform.position);
			if (dto == null)
			{
				return Constants.ErrorMessage($"No smelter found within {BasePlugin<SignsPlugin>.Instance.SmelterRadius.Value} blocks");
			}
			Smelter val = ((IEnumerable<Smelter>)(Object.FindObjectsByType<Smelter>((FindObjectsSortMode)1) ?? Array.Empty<Smelter>())).FirstOrDefault((Func<Smelter, bool>)((Smelter x) => ((Object)x).GetInstanceID() == dto.Id));
			if ((Object)(object)val == (Object)null)
			{
				return Constants.ErrorMessage("Smelter Component not found with id: " + dto.Id);
			}
			int queueSize = val.GetQueueSize();
			float fuel = val.GetFuel();
			string queuedOre = val.GetQueuedOre();
			string name = ((Object)val.m_fuelItem).name;
			StringBuilder stringBuilder = new StringBuilder();
			if (flag2)
			{
				if (flag)
				{
					stringBuilder.Append(name + ": ");
				}
				stringBuilder.Append($"{fuel}\n");
			}
			if (flag3)
			{
				if (flag)
				{
					stringBuilder.Append(queuedOre + ": ");
				}
				stringBuilder.Append($"{queueSize}\n");
			}
			return stringBuilder.ToString();
		}

		public string? GetSignHoverText(Sign sign, string input)
		{
			return "Smelter Content";
		}
	}
}