Decompiled source of TerminalAliases v1.0.0

TerminalAliases.dll

Decompiled 21 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TerminalAliases")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+37c6543cb4b656ea651197164928e3c0efe80b33")]
[assembly: AssemblyProduct("TerminalAliases")]
[assembly: AssemblyTitle("TerminalAliases")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 TerminalAliases
{
	public class AliasManager
	{
		private readonly string _filePath;

		private Dictionary<string, string> _aliases = new Dictionary<string, string>();

		public IReadOnlyDictionary<string, string> Aliases => _aliases;

		public AliasManager(string configDirectory)
		{
			_filePath = Path.Combine(configDirectory, "TerminalAliases.cfg");
			Load();
		}

		public void Load()
		{
			_aliases.Clear();
			if (!File.Exists(_filePath))
			{
				Plugin.Log.LogInfo((object)("No alias file found at " + _filePath + ", starting fresh."));
				return;
			}
			try
			{
				string[] array = File.ReadAllLines(_filePath);
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (string.IsNullOrEmpty(text) || text.StartsWith("#"))
					{
						continue;
					}
					int num = text.IndexOf('=');
					if (num > 0 && num < text.Length - 1)
					{
						string text2 = text.Substring(0, num).Trim().ToLowerInvariant();
						string value = text.Substring(num + 1).Trim();
						if (!string.IsNullOrEmpty(text2) && !string.IsNullOrEmpty(value))
						{
							_aliases[text2] = value;
						}
					}
				}
				Plugin.Log.LogInfo((object)$"Loaded {_aliases.Count} alias(es) from {_filePath}");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to load aliases: " + ex.Message));
			}
		}

		public void Save()
		{
			try
			{
				List<string> list = new List<string>();
				foreach (KeyValuePair<string, string> alias in _aliases)
				{
					list.Add(alias.Key + "=" + alias.Value);
				}
				File.WriteAllLines(_filePath, list);
				Plugin.Log.LogDebug((object)$"Saved {_aliases.Count} alias(es) to {_filePath}");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to save aliases: " + ex.Message));
			}
		}

		public bool Add(string alias, string command)
		{
			if (string.IsNullOrWhiteSpace(alias) || string.IsNullOrWhiteSpace(command))
			{
				return false;
			}
			alias = alias.ToLowerInvariant();
			_aliases[alias] = command;
			Save();
			return true;
		}

		public bool Remove(string alias)
		{
			if (string.IsNullOrWhiteSpace(alias))
			{
				return false;
			}
			alias = alias.ToLowerInvariant();
			if (_aliases.Remove(alias))
			{
				Save();
				return true;
			}
			return false;
		}

		public bool TryGet(string alias, out string command)
		{
			return _aliases.TryGetValue(alias.ToLowerInvariant(), out command);
		}
	}
	[BepInPlugin("TerminalAliases", "TerminalAliases", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log { get; private set; }

		internal static AliasManager AliasManager { get; private set; }

		internal static Harmony Harmony { get; private set; }

		private void Awake()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			AliasManager = new AliasManager(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath));
			Harmony = new Harmony("TerminalAliases");
			Harmony.PatchAll(Assembly.GetExecutingAssembly());
			Log.LogInfo((object)"TerminalAliases v1.0.0 loaded.");
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "TerminalAliases";

		public const string PLUGIN_NAME = "TerminalAliases";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace TerminalAliases.Patches
{
	[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
	internal static class AliasCommandsPatch
	{
		[HarmonyPrefix]
		private static bool HandleAliasCommands(Terminal __instance, ref TerminalNode __result)
		{
			if (__instance.textAdded <= 0)
			{
				return true;
			}
			string text = __instance.screenText.text;
			int startIndex = text.Length - __instance.textAdded;
			string text2 = text.Substring(startIndex).Trim().ToLowerInvariant();
			if (string.IsNullOrEmpty(text2))
			{
				return true;
			}
			string[] array = text2.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 0)
			{
				return true;
			}
			string text3 = array[0];
			if (text3 == "alias")
			{
				__result = HandleAliasCommand(array, __instance);
				return false;
			}
			if (text3 == "removealias")
			{
				__result = HandleRemoveAliasCommand(array, __instance);
				return false;
			}
			return true;
		}

		private static TerminalNode HandleAliasCommand(string[] parts, Terminal terminal)
		{
			if (parts.Length == 1)
			{
				IReadOnlyDictionary<string, string> aliases = Plugin.AliasManager.Aliases;
				if (aliases.Count == 0)
				{
					return CreateNode("No aliases defined.\n\nUse 'alias [name] [command]' to create one.\n\n");
				}
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("Defined aliases:");
				stringBuilder.AppendLine();
				foreach (KeyValuePair<string, string> item in aliases)
				{
					stringBuilder.AppendLine("  " + item.Key + " = " + item.Value);
				}
				stringBuilder.AppendLine();
				return CreateNode(stringBuilder.ToString());
			}
			if (parts.Length == 2)
			{
				return CreateNode("Usage: alias [name] [command]\n\nExample: alias vm view monitor\n\n");
			}
			string text = parts[1];
			string text2 = string.Join(" ", parts, 2, parts.Length - 2);
			if (Plugin.AliasManager.Add(text, text2))
			{
				return CreateNode("Alias '" + text + "' set to '" + text2 + "'\n\n");
			}
			return CreateNode("Failed to add alias.\n\n");
		}

		private static TerminalNode HandleRemoveAliasCommand(string[] parts, Terminal terminal)
		{
			if (parts.Length < 2)
			{
				return CreateNode("Usage: removealias [name]\n\n");
			}
			string text = parts[1];
			if (Plugin.AliasManager.Remove(text))
			{
				return CreateNode("Alias '" + text + "' removed.\n\n");
			}
			return CreateNode("Alias '" + text + "' not found.\n\n");
		}

		private static TerminalNode CreateNode(string text)
		{
			TerminalNode obj = ScriptableObject.CreateInstance<TerminalNode>();
			obj.displayText = text;
			obj.clearPreviousText = true;
			return obj;
		}
	}
	[HarmonyPatch(typeof(Terminal))]
	internal static class TerminalInputPatch
	{
		private static bool _pendingConfirm;

		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		private static void HandleCtrlEnter(Terminal __instance)
		{
			if (__instance.terminalInUse)
			{
				Keyboard current = Keyboard.current;
				if (current != null && (((ButtonControl)current.leftCtrlKey).isPressed || ((ButtonControl)current.rightCtrlKey).isPressed) && ((ButtonControl)current.enterKey).wasPressedThisFrame)
				{
					_pendingConfirm = true;
					__instance.OnSubmit();
				}
			}
		}

		[HarmonyPatch("OnSubmit")]
		[HarmonyPostfix]
		private static void AutoConfirm(Terminal __instance)
		{
			if (_pendingConfirm)
			{
				_pendingConfirm = false;
				((MonoBehaviour)__instance).StartCoroutine(ConfirmCoroutine(__instance));
			}
		}

		private static IEnumerator ConfirmCoroutine(Terminal terminal)
		{
			yield return null;
			if (!terminal.terminalInUse)
			{
				yield break;
			}
			TerminalNode currentNode = terminal.currentNode;
			if ((Object)(object)currentNode == (Object)null || currentNode.terminalOptions == null || currentNode.terminalOptions.Length == 0)
			{
				yield break;
			}
			CompatibleNoun[] terminalOptions = currentNode.terminalOptions;
			foreach (CompatibleNoun val in terminalOptions)
			{
				if (!((Object)(object)val.noun == (Object)null))
				{
					string word = val.noun.word;
					if (word != null && word.ToLowerInvariant() == "confirm")
					{
						terminal.LoadNewNode(val.result);
						Plugin.Log.LogDebug((object)"Auto-confirmed via Ctrl+Enter.");
						break;
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
	internal static class TerminalPatch
	{
		private static FieldInfo? _modifyingTextField;

		private const int MaxChainDepth = 10;

		private static FieldInfo ModifyingTextField => _modifyingTextField ?? (_modifyingTextField = typeof(Terminal).GetField("modifyingText", BindingFlags.Instance | BindingFlags.NonPublic));

		[HarmonyPrefix]
		private static void ExpandAliases(Terminal __instance)
		{
			if (__instance.textAdded <= 0)
			{
				return;
			}
			string text = __instance.screenText.text;
			int num = text.Length - __instance.textAdded;
			string text2 = text.Substring(num);
			if (!string.IsNullOrWhiteSpace(text2))
			{
				string text3 = ExpandInput(text2);
				if (!(text3 == text2))
				{
					bool flag = (bool)ModifyingTextField.GetValue(__instance);
					ModifyingTextField.SetValue(__instance, true);
					int num2 = text3.Length - text2.Length;
					__instance.screenText.text = text.Substring(0, num) + text3;
					__instance.textAdded += num2;
					ModifyingTextField.SetValue(__instance, flag);
					Plugin.Log.LogDebug((object)("Expanded: '" + text2.Trim() + "' -> '" + text3.Trim() + "'"));
				}
			}
		}

		private static string ExpandInput(string input)
		{
			IReadOnlyDictionary<string, string> aliases = Plugin.AliasManager.Aliases;
			if (aliases.Count == 0)
			{
				return input;
			}
			string text = input;
			for (int i = 0; i < 10; i++)
			{
				string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.None);
				bool flag = false;
				for (int j = 0; j < array.Length; j++)
				{
					string text2 = array[j];
					string key = text2.ToLowerInvariant();
					if (aliases.TryGetValue(key, out var value))
					{
						array[j] = PreserveCase(text2, value);
						flag = true;
					}
				}
				if (!flag)
				{
					break;
				}
				text = string.Join(" ", array);
			}
			return text;
		}

		private static string PreserveCase(string original, string replacement)
		{
			if (string.IsNullOrEmpty(original) || string.IsNullOrEmpty(replacement))
			{
				return replacement;
			}
			if (original == original.ToUpperInvariant())
			{
				return replacement.ToUpperInvariant();
			}
			if (char.IsUpper(original[0]))
			{
				StringBuilder stringBuilder = new StringBuilder(replacement.Length);
				stringBuilder.Append(char.ToUpperInvariant(replacement[0]));
				if (replacement.Length > 1)
				{
					stringBuilder.Append(replacement.Substring(1));
				}
				return stringBuilder.ToString();
			}
			return replacement;
		}
	}
}