Decompiled source of ConsoleLibrary v1.1.0

plugins/LuckyShotConsoleLibrary.dll

Decompiled 18 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Shooterlatro.DebugTools;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("LuckyShotConsoleLibrary")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+4135dd1490a61fe647f2a0e54287f36471f5cf7f")]
[assembly: AssemblyProduct("LuckyShotConsoleLibrary")]
[assembly: AssemblyTitle("LuckyShotConsoleLibrary")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LuckyShot.ConsoleLibrary
{
	public sealed class ConsoleCommand
	{
		public string Name { get; set; }

		public string Description { get; set; }

		public string Usage { get; set; }

		public string OwnerModId { get; set; }

		public Func<IReadOnlyList<string>, DeveloperConsoleCommandResult> Handler { get; set; }

		public bool IsRegistered { get; internal set; }

		public override string ToString()
		{
			return Name;
		}
	}
	public static class ConsoleCommands
	{
		private static readonly object Sync = new object();

		private static readonly Dictionary<string, ConsoleCommand> Commands = new Dictionary<string, ConsoleCommand>(StringComparer.OrdinalIgnoreCase);

		public static IReadOnlyCollection<ConsoleCommand> All
		{
			get
			{
				lock (Sync)
				{
					return new List<ConsoleCommand>(Commands.Values).AsReadOnly();
				}
			}
		}

		public static event Action<ConsoleCommand> Registered;

		public static event Action<ConsoleCommand> Unregistered;

		public static ConsoleCommand Register(string name, Func<IReadOnlyList<string>, DeveloperConsoleCommandResult> handler, string description = null, string usage = null, string ownerModId = null)
		{
			if (!IsValidName(name) || handler == null)
			{
				return null;
			}
			ConsoleCommand consoleCommand = new ConsoleCommand
			{
				Name = name.ToLowerInvariant(),
				Description = description,
				Usage = usage,
				OwnerModId = (ownerModId ?? InferOwner()),
				Handler = handler
			};
			lock (Sync)
			{
				if (Commands.ContainsKey(consoleCommand.Name))
				{
					return null;
				}
				Commands[consoleCommand.Name] = consoleCommand;
				consoleCommand.IsRegistered = true;
			}
			try
			{
				ConsoleCommands.Registered?.Invoke(consoleCommand);
			}
			catch
			{
			}
			return consoleCommand;
		}

		public static ConsoleCommand Register(ConsoleCommand cmd, string ownerModId = null)
		{
			if (cmd == null || !IsValidName(cmd.Name) || cmd.Handler == null)
			{
				return null;
			}
			lock (Sync)
			{
				string text = cmd.Name.ToLowerInvariant();
				if (Commands.ContainsKey(text))
				{
					return null;
				}
				cmd.Name = text;
				if (string.IsNullOrWhiteSpace(cmd.OwnerModId))
				{
					cmd.OwnerModId = ownerModId ?? InferOwner();
				}
				Commands[text] = cmd;
				cmd.IsRegistered = true;
			}
			try
			{
				ConsoleCommands.Registered?.Invoke(cmd);
			}
			catch
			{
			}
			return cmd;
		}

		public static bool Unregister(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return false;
			}
			ConsoleCommand value;
			lock (Sync)
			{
				if (!Commands.TryGetValue(name, out value))
				{
					return false;
				}
				Commands.Remove(name);
				value.IsRegistered = false;
			}
			try
			{
				ConsoleCommands.Unregistered?.Invoke(value);
			}
			catch
			{
			}
			return true;
		}

		public static ConsoleCommand Get(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return null;
			}
			lock (Sync)
			{
				ConsoleCommand value;
				return Commands.TryGetValue(name, out value) ? value : null;
			}
		}

		public static bool IsRegistered(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return false;
			}
			lock (Sync)
			{
				return Commands.ContainsKey(name);
			}
		}

		internal static bool TryExecute(string commandName, IReadOnlyList<string> args, out DeveloperConsoleCommandResult result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			result = default(DeveloperConsoleCommandResult);
			if (string.IsNullOrWhiteSpace(commandName))
			{
				return false;
			}
			ConsoleCommand value;
			lock (Sync)
			{
				if (!Commands.TryGetValue(commandName, out value))
				{
					return false;
				}
			}
			try
			{
				DeveloperConsoleCommandResult val = value.Handler(args);
				result = val;
				return true;
			}
			catch (Exception ex)
			{
				result = new DeveloperConsoleCommandResult(false, value.Name + " failed: " + ex.Message, (IReadOnlyList<DeveloperConsoleHoloEntry>)null, false);
				return true;
			}
		}

		internal static string HelpAppendix()
		{
			List<ConsoleCommand> list;
			lock (Sync)
			{
				list = new List<ConsoleCommand>(Commands.Values);
			}
			if (list.Count == 0)
			{
				return string.Empty;
			}
			list.Sort((ConsoleCommand a, ConsoleCommand b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
			List<string> list2 = new List<string>();
			foreach (ConsoleCommand item in list)
			{
				string text = item.Name + "()";
				if (!string.IsNullOrWhiteSpace(item.Usage))
				{
					text = item.Usage;
				}
				else if (!string.IsNullOrWhiteSpace(item.Description))
				{
					text = text + " - " + item.Description;
				}
				list2.Add(text);
			}
			return "\n" + string.Join("\n", list2.ToArray());
		}

		public static bool IsValidName(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return false;
			}
			foreach (char c in name)
			{
				if (!char.IsLetterOrDigit(c) && c != '_')
				{
					return false;
				}
			}
			return true;
		}

		private static string InferOwner()
		{
			try
			{
				string text = Assembly.GetCallingAssembly()?.GetName()?.Name;
				return string.IsNullOrEmpty(text) ? "unknown" : text;
			}
			catch
			{
				return "unknown";
			}
		}
	}
	public static class ConsoleMarkup
	{
		public const string Prefix = "\u200bmd:";

		public const string Green = "#50FA7B";

		public const string Red = "#FF5555";

		public const string Cyan = "#8BE9FD";

		public const string Yellow = "#F1FA8C";

		public const string Grey = "#AAAAAA";

		public static string Format(string markdown)
		{
			return "\u200bmd:" + (markdown ?? string.Empty);
		}

		public static string Ok(string title, string body = null)
		{
			return Format(string.IsNullOrEmpty(body) ? ("**" + title + "**") : ("**" + title + "**\n" + body));
		}

		public static string Fail(string title, string body = null)
		{
			return Format("**" + title + "**" + (string.IsNullOrEmpty(body) ? string.Empty : ("\n" + body)));
		}

		public static string Title(string text)
		{
			return "# " + text;
		}

		public static string Bullet(string text)
		{
			return "- " + text;
		}

		public static string Code(string text)
		{
			return "`" + text + "`";
		}

		public static string Bold(string text)
		{
			return "**" + text + "**";
		}

		public static string Italic(string text)
		{
			return "*" + text + "*";
		}

		public static string Color(string hex, string text)
		{
			return "[c=" + hex + "]" + text + "[/c]";
		}

		internal static bool TryStrip(string text, out string markdown)
		{
			markdown = null;
			if (string.IsNullOrEmpty(text) || !text.StartsWith("\u200bmd:", StringComparison.Ordinal))
			{
				return false;
			}
			markdown = text.Substring("\u200bmd:".Length);
			return true;
		}

		internal static string ToRichText(string markdown)
		{
			if (markdown == null)
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder();
			string[] array = markdown.Replace("\r\n", "\n").Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append('\n');
				}
				stringBuilder.Append(ConvertLine(array[i]));
			}
			return stringBuilder.ToString();
		}

		private static string ConvertLine(string line)
		{
			if (string.IsNullOrEmpty(line))
			{
				return string.Empty;
			}
			int i;
			for (i = 0; i < line.Length && line[i] == '#'; i++)
			{
			}
			if (i >= 1 && i <= 3 && i < line.Length && line[i] == ' ')
			{
				string text = ConvertInline(line.Substring(i + 1).Trim());
				string text2 = i switch
				{
					2 => "115%", 
					1 => "130%", 
					_ => "105%", 
				};
				return "<size=" + text2 + "><b>" + text + "</b></size>";
			}
			string text3 = line.TrimStart(Array.Empty<char>());
			if ((text3.StartsWith("- ") || text3.StartsWith("* ")) && text3.Length > 2)
			{
				return "• " + ConvertInline(text3.Substring(2));
			}
			return ConvertInline(line);
		}

		private static string ConvertInline(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return string.Empty;
			}
			List<Tuple<string, bool>> list = new List<Tuple<string, bool>>();
			StringBuilder stringBuilder = new StringBuilder();
			bool flag = false;
			for (int i = 0; i < s.Length; i++)
			{
				if (s[i] == '`')
				{
					list.Add(Tuple.Create(stringBuilder.ToString(), flag));
					stringBuilder.Length = 0;
					flag = !flag;
				}
				else
				{
					stringBuilder.Append(s[i]);
				}
			}
			list.Add(Tuple.Create(stringBuilder.ToString(), flag));
			StringBuilder stringBuilder2 = new StringBuilder();
			foreach (Tuple<string, bool> item in list)
			{
				if (item.Item2)
				{
					stringBuilder2.Append("<color=#F1FA8C><b>" + Escape(item.Item1) + "</b></color>");
				}
				else
				{
					stringBuilder2.Append(ConvertSpans(Escape(item.Item1)));
				}
			}
			return stringBuilder2.ToString();
		}

		private static string ConvertSpans(string escaped)
		{
			return Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(escaped, "\\[c=([#A-Za-z0-9]+)\\](.+?)\\[/c\\]", (Match m) => (!IsHexColor(m.Groups[1].Value)) ? m.Value : ("<color=" + m.Groups[1].Value + ">" + m.Groups[2].Value + "</color>")), "\\*\\*(.+?)\\*\\*", "<b>$1</b>"), "__(.+?)__", "<u>$1</u>"), "~~(.+?)~~", "<s>$1</s>"), "(?<!\\w)\\*(?!\\s)(.+?)(?<!\\s)\\*(?!\\w)", "<i>$1</i>"), "(?<!\\w)_(?!\\s)(.+?)(?<!\\s)_(?!\\w)", "<i>$1</i>");
		}

		private static bool IsHexColor(string v)
		{
			if (string.IsNullOrEmpty(v) || !v.StartsWith("#"))
			{
				return false;
			}
			string text = v.Substring(1);
			if (text.Length != 3 && text.Length != 6 && text.Length != 8)
			{
				return false;
			}
			string text2 = text;
			for (int i = 0; i < text2.Length; i++)
			{
				if (!Uri.IsHexDigit(text2[i]))
				{
					return false;
				}
			}
			return true;
		}

		private static string Escape(string text)
		{
			return (text ?? string.Empty).Replace("<", "&lt;").Replace(">", "&gt;");
		}
	}
	[HarmonyPatch]
	internal static class MarkupRenderPatch
	{
		private static MethodBase TargetMethod()
		{
			try
			{
				Type type = AccessTools.TypeByName("Shooterlatro.DebugTools.DeveloperConsole");
				if (type == null)
				{
					return null;
				}
				return AccessTools.Method(type, "AppendSingleTextLine", new Type[2]
				{
					typeof(string),
					typeof(string)
				}, (Type[])null);
			}
			catch
			{
				return null;
			}
		}

		private static bool Prefix(object __instance, string text, string color)
		{
			try
			{
				if (!ConsoleMarkup.TryStrip(text, out var markdown))
				{
					return true;
				}
				string richText = ConsoleMarkup.ToRichText(markdown);
				AppendRichLine(__instance, richText, color);
				return false;
			}
			catch
			{
				return true;
			}
		}

		private static void AppendRichLine(object console, string richText, string color)
		{
			Type? obj = console.GetType().Assembly.GetType("TMPro.TMP_Text") ?? Type.GetType("TMPro.TMP_Text");
			Type type = FindType("UnityEngine.UI.LayoutElement");
			Type type2 = FindType("UnityEngine.GameObject");
			if (obj == null || type == null || type2 == null || GetField(console, "_outputContainer") == null)
			{
				return;
			}
			object obj2 = CallInst(console, "CreateOutputRow", new object[1] { "TextLine" });
			if (obj2 == null)
			{
				return;
			}
			object prop = GetProp(obj2, "transform");
			object obj3 = CallInst(console, "CreateRowText", new object[2] { prop, 0 });
			if (obj3 != null)
			{
				SetProp(obj3, "text", "<color=" + color + ">" + richText + "</color>");
				object obj4 = obj2.GetType().GetMethod("GetComponent", new Type[1] { typeof(Type) })?.Invoke(obj2, new object[1] { type });
				if (obj4 != null)
				{
					SetProp(obj4, "minHeight", 28f);
					SetProp(obj4, "preferredHeight", 28f);
				}
				object prop2 = GetProp(obj3, "rectTransform");
				prop2?.GetType().GetMethod("SetSizeWithCurrentAnchors")?.Invoke(prop2, new object[2] { 1, 28f });
			}
		}

		private static Type FindType(string full)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(full);
					if (type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return Type.GetType(full);
		}

		private static object GetField(object o, string n)
		{
			return o.GetType().GetField(n, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(o);
		}

		private static object GetProp(object o, string n)
		{
			return o.GetType().GetProperty(n, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(o);
		}

		private static void SetProp(object o, string n, object v)
		{
			try
			{
				o.GetType().GetProperty(n, BindingFlags.Instance | BindingFlags.Public)?.SetValue(o, v);
			}
			catch
			{
			}
		}

		private static object CallInst(object instance, string n, object[] args)
		{
			try
			{
				MethodInfo[] methods = instance.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name != n || methodInfo.GetParameters().Length != args.Length)
					{
						continue;
					}
					ParameterInfo[] parameters = methodInfo.GetParameters();
					object[] array = new object[args.Length];
					for (int j = 0; j < args.Length; j++)
					{
						if (args[j] != null && parameters[j].ParameterType.IsEnum && args[j] is int)
						{
							array[j] = Enum.ToObject(parameters[j].ParameterType, (int)args[j]);
						}
						else
						{
							array[j] = args[j];
						}
					}
					return methodInfo.Invoke(instance, array);
				}
			}
			catch
			{
			}
			return null;
		}

		private static object CallMethod(object o, string n, Type[] sig, object[] args)
		{
			try
			{
				return o.GetType().GetMethod(n, sig)?.Invoke(o, args);
			}
			catch
			{
				return null;
			}
		}
	}
	[HarmonyPatch(typeof(DeveloperConsoleCommandExecutor), "Execute")]
	internal static class ExecutorPatch
	{
		private const string UnknownPrefix = "Unknown command '";

		private static void Postfix(string input, ref DeveloperConsoleCommandResult __result)
		{
			//IL_003f: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (((DeveloperConsoleCommandResult)(ref __result)).Success)
				{
					return;
				}
				string text = ((DeveloperConsoleCommandResult)(ref __result)).Message ?? string.Empty;
				if (IsHelpResult(input, text))
				{
					string text2 = ConsoleCommands.HelpAppendix();
					if (!string.IsNullOrEmpty(text2))
					{
						__result = new DeveloperConsoleCommandResult(true, text + text2, (IReadOnlyList<DeveloperConsoleHoloEntry>)null, false);
					}
				}
				else if (text.StartsWith("Unknown command '", StringComparison.Ordinal))
				{
					ParseName(input, out var name, out var args);
					if (!string.IsNullOrEmpty(name) && ConsoleCommands.TryExecute(name, args, out var result))
					{
						__result = result;
					}
				}
			}
			catch
			{
			}
		}

		private static bool IsHelpResult(string input, string msg)
		{
			if (string.IsNullOrWhiteSpace(input) || string.IsNullOrEmpty(msg))
			{
				return false;
			}
			ParseName(input, out var name, out var _);
			if (string.Equals(name, "help", StringComparison.OrdinalIgnoreCase))
			{
				return msg.IndexOf("Available commands:", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static void ParseName(string input, out string name, out List<string> args)
		{
			name = null;
			args = new List<string>();
			try
			{
				string text = (input ?? string.Empty).Trim();
				if (text.Length == 0)
				{
					return;
				}
				int num = text.IndexOf('(');
				if (num < 0)
				{
					name = text.Trim();
					return;
				}
				name = text.Substring(0, num).Trim();
				int num2 = text.LastIndexOf(')');
				if (num2 < num)
				{
					return;
				}
				string text2 = text.Substring(num + 1, num2 - num - 1);
				if (string.IsNullOrWhiteSpace(text2))
				{
					return;
				}
				StringBuilder stringBuilder = new StringBuilder();
				char c = '\0';
				bool flag = false;
				string text3 = text2;
				foreach (char c2 in text3)
				{
					if (flag)
					{
						stringBuilder.Append(c2);
						flag = false;
						continue;
					}
					if (c != 0)
					{
						if (c2 == '\\')
						{
							flag = true;
						}
						else if (c2 == c)
						{
							c = '\0';
						}
						else
						{
							stringBuilder.Append(c2);
						}
						continue;
					}
					switch (c2)
					{
					case '"':
					case '\'':
						c = c2;
						break;
					case ',':
						args.Add(stringBuilder.ToString().Trim());
						stringBuilder.Clear();
						break;
					default:
						stringBuilder.Append(c2);
						break;
					}
				}
				args.Add(stringBuilder.ToString().Trim());
			}
			catch
			{
			}
		}
	}
	public static class Results
	{
		public static DeveloperConsoleCommandResult Ok(string message)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			return new DeveloperConsoleCommandResult(true, message, (IReadOnlyList<DeveloperConsoleHoloEntry>)null, false);
		}

		public static DeveloperConsoleCommandResult Err(string message)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			return new DeveloperConsoleCommandResult(false, message, (IReadOnlyList<DeveloperConsoleHoloEntry>)null, false);
		}

		public static DeveloperConsoleCommandResult Md(string markdown)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			return new DeveloperConsoleCommandResult(true, ConsoleMarkup.Format(markdown), (IReadOnlyList<DeveloperConsoleHoloEntry>)null, false);
		}

		public static DeveloperConsoleCommandResult MdErr(string markdown)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			return new DeveloperConsoleCommandResult(false, ConsoleMarkup.Format(markdown), (IReadOnlyList<DeveloperConsoleHoloEntry>)null, false);
		}

		public static DeveloperConsoleCommandResult OkMd(string title, string body = null)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return new DeveloperConsoleCommandResult(true, ConsoleMarkup.Ok(title, body), (IReadOnlyList<DeveloperConsoleHoloEntry>)null, false);
		}

		public static DeveloperConsoleCommandResult ErrMd(string title, string body = null)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return new DeveloperConsoleCommandResult(false, ConsoleMarkup.Fail(title, body), (IReadOnlyList<DeveloperConsoleHoloEntry>)null, false);
		}
	}
	[BepInPlugin("com.luckyshot.wiki.consolelibrary", "LuckyShot Console Library", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		private void Awake()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			new Harmony("com.luckyshot.wiki.consolelibrary").PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LuckyShot Console Library loaded (library only, no commands built in).");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Mods: use ConsoleCommands.Register(name, handler, description, usage);");
		}
	}
	internal static class PluginInfo
	{
		public const string GUID = "com.luckyshot.wiki.consolelibrary";

		public const string NAME = "LuckyShot Console Library";

		public const string VERSION = "1.1.0";
	}
}