Decompiled source of AdvancedTerminalAPI v5.1.0

BepInEx/plugins/AdvancedTerminalAPI.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using AdvancedTerminalAPI.NetcodePatcher;
using BepInEx;
using BepInEx.Logging;
using Computerdores.AdvancedTerminalAPI.Vanillin;
using Computerdores.AdvancedTerminalAPI.Vanillin.Commands;
using Computerdores.AdvancedTerminalAPI.patch;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("Computerdores")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("A Lethal Company Mod to provide a more advanced API for the Terminal.")]
[assembly: AssemblyFileVersion("5.1.0.0")]
[assembly: AssemblyInformationalVersion("5.1.0+33f6424e733f41848c95eec6180e9665bb94cecc")]
[assembly: AssemblyProduct("AdvancedTerminalAPI")]
[assembly: AssemblyTitle("AdvancedTerminalAPI")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Computerdores/AdvancedTerminalAPI")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("5.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
internal class <Module>
{
	static <Module>()
	{
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 Computerdores
{
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "AdvancedTerminalAPI";

		public const string PLUGIN_NAME = "AdvancedTerminalAPI";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace Computerdores.AdvancedTerminalAPI
{
	public struct CommandResult
	{
		public string output;

		public bool clearScreen;

		public bool success;

		public bool wantsMoreInput;

		public static readonly CommandResult IgnoreInput = new CommandResult(null, clearScreen: false, success: true, wantsMoreInput: true);

		public static readonly CommandResult GenericError = new CommandResult(null, clearScreen: true, success: false);

		public CommandResult(string output = null, bool clearScreen = true, bool success = true, bool wantsMoreInput = false)
		{
			this.output = output;
			this.clearScreen = clearScreen;
			this.success = success;
			this.wantsMoreInput = wantsMoreInput;
		}
	}
	public delegate void Consumer<in T>(T value);
	public interface IAliasable
	{
		IEnumerable<ICommand> GetAll(ITerminal term);
	}
	public interface ICommand
	{
		string GetName();

		CommandResult Execute(string input, ITerminal terminal);

		ICommand CloneStateless();
	}
	public interface IDescribable
	{
		string GetUsage();

		string GetDescription();
	}
	public class InputFieldDriver
	{
		private int _maxInputLength = 40;

		private readonly TMP_InputField _inputField;

		private string _displayedText = "\n\n\n";

		private string _input = "";

		public int MaxInputLength
		{
			get
			{
				return _maxInputLength;
			}
			set
			{
				_maxInputLength = value;
				if (_input.Length > _maxInputLength)
				{
					OnInputFieldChangedHandler(_inputField.text);
				}
			}
		}

		public string Input
		{
			get
			{
				return _input;
			}
			set
			{
				_input = value;
				_renderToInputField();
			}
		}

		public Terminal VanillaTerminal { get; }

		public event Consumer<string> OnSubmit;

		public event Consumer<string> OnInputChange;

		public InputFieldDriver(Terminal __instance)
		{
			VanillaTerminal = __instance;
			_inputField = __instance.screenText;
			((UnityEvent<string>)(object)_inputField.onValueChanged).AddListener((UnityAction<string>)OnInputFieldChangedHandler);
			((UnityEvent<string>)(object)_inputField.onSubmit).AddListener((UnityAction<string>)OnInputFieldSubmitHandler);
			TerminalWrapper.Get(__instance).EnterTerminal += OnEnterTerminalHandler;
		}

		public void DisplayText([CanBeNull] string text, bool clearScreen)
		{
			if (clearScreen)
			{
				_displayedText = "\n";
			}
			if (!Utility.IsNullOrWhiteSpace(text))
			{
				if (!clearScreen)
				{
					_displayedText += Input;
				}
				_displayedText = _displayedText + "\n\n" + text;
			}
			Input = "";
			_renderToInputField();
		}

		public string GetDisplayedText()
		{
			return _displayedText;
		}

		private void _renderToInputField()
		{
			_inputField.text = _displayedText + Input;
			_inputField.caretPosition = _inputField.text.Length;
		}

		private void OnInputFieldChangedHandler(string newText)
		{
			if (newText.Length < _displayedText.Length)
			{
				Input = "";
			}
			else
			{
				int length = Math.Min(_maxInputLength, newText.Length - _displayedText.Length);
				Input = newText.Substring(_displayedText.Length, length);
			}
			_renderToInputField();
			this.OnInputChange?.Invoke(Input);
		}

		private void OnInputFieldSubmitHandler(string text)
		{
			this.OnSubmit?.Invoke(Input);
			_inputField.ActivateInputField();
			((Selectable)_inputField).Select();
		}

		private void OnEnterTerminalHandler(bool firstTime)
		{
			Input = "";
		}
	}
	public interface IPredictable
	{
		string PredictInput(string partialInput, ITerminal terminal);
	}
	public interface ITerminal
	{
		InputFieldDriver GetDriver();

		void AddCommand(ICommand command);

		IEnumerable<ICommand> GetCommands(bool includeBuiltins);
	}
	public delegate T Method<out T, in T2>(T2 input);
	[BepInPlugin("AdvancedTerminalAPI", "AdvancedTerminalAPI", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		private readonly Harmony _harmony = new Harmony("AdvancedTerminalAPI");

		private static Method<ITerminal, InputFieldDriver> _terminalConstructor;

		private static readonly List<ICommand> Commands = new List<ICommand>();

		private static Plugin Instance { get; set; }

		internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger;

		private static InputFieldDriver Driver { get; set; }

		private static ITerminal CustomTerminal { get; set; }

		public Plugin()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			Instance = this;
			ReplaceITerminal((InputFieldDriver d) => new VanillinTerminal(d));
		}

		public static void ReplaceITerminal(Method<ITerminal, InputFieldDriver> terminalConstructor)
		{
			_terminalConstructor = terminalConstructor;
			if (Driver != null)
			{
				ReplaceITerminalInstance();
			}
		}

		public static void AddCommand(ICommand command)
		{
			Commands.Add(command);
			CustomTerminal.AddCommand(command);
		}

		internal static void RegisterTerminal(Terminal terminal)
		{
			Driver = new InputFieldDriver(terminal);
			ReplaceITerminalInstance();
		}

		private static void ReplaceITerminalInstance()
		{
			CustomTerminal = _terminalConstructor(Driver);
			foreach (ICommand command in Commands)
			{
				CustomTerminal.AddCommand(command);
			}
		}

		private void Awake()
		{
			ApplyPatches();
		}

		private void ApplyPatches()
		{
			_harmony.PatchAll(typeof(TerminalPatch));
		}
	}
	public delegate void SimpleEvent();
	public class TerminalWrapper
	{
		private readonly Terminal _terminal;

		private TerminalNode _lastLoadedNode;

		internal bool redirectLoadNewNode;

		private static readonly Dictionary<Terminal, TerminalWrapper> WrapperMap = new Dictionary<Terminal, TerminalWrapper>();

		public bool TerminalInUse => _terminal.terminalInUse;

		public event Consumer<bool> EnterTerminal;

		public event SimpleEvent ExitTerminal;

		public event SimpleEvent PreAwake;

		public event SimpleEvent PostAwake;

		public event SimpleEvent PreStart;

		public event SimpleEvent PostStart;

		public event SimpleEvent PreUpdate;

		public event SimpleEvent PostUpdate;

		private TerminalWrapper(Terminal terminal)
		{
			_terminal = terminal;
			TerminalPatch.OnEnterTerminal += OnEnterTerminal;
			TerminalPatch.OnExitTerminal += OnExitTerminal;
			TerminalPatch.PreAwake += OnPreAwake;
			TerminalPatch.PostAwake += OnPostAwake;
			TerminalPatch.PreStart += OnPreStart;
			TerminalPatch.PostStart += OnPostStart;
			TerminalPatch.PreUpdate += OnPreUpdate;
			TerminalPatch.PostUpdate += OnPostUpdate;
		}

		public TerminalNode LoadNode(TerminalNode node)
		{
			if (node.itemCost != 0 || node.buyRerouteToMoon == -2)
			{
				_terminal.totalCostOfItems = node.itemCost * _terminal.playerDefinedAmount;
			}
			TerminalNode result = node;
			if (node.buyItemIndex != -1 || (node.buyRerouteToMoon != -1 && node.buyRerouteToMoon != -2) || node.shipUnlockableID != -1)
			{
				result = VanillaLoad(node, (Consumer<TerminalNode>)_terminal.LoadNewNodeIfAffordable);
			}
			else if (node.creatureFileID != -1)
			{
				result = VanillaLoad(node, (Consumer<TerminalNode>)_terminal.AttemptLoadCreatureFileNode);
			}
			else if (node.storyLogFileID != -1)
			{
				result = VanillaLoad(node, (Consumer<TerminalNode>)_terminal.AttemptLoadStoryLogFileNode);
			}
			else
			{
				LoadNewNode(node);
			}
			return result;
		}

		private TerminalNode VanillaLoad(TerminalNode node, Consumer<TerminalNode> loadMethod)
		{
			_lastLoadedNode = null;
			redirectLoadNewNode = true;
			loadMethod(node);
			redirectLoadNewNode = false;
			return _lastLoadedNode;
		}

		internal void LoadNewNode(TerminalNode node)
		{
			_terminal.RunTerminalEvents(node);
			((Selectable)_terminal.screenText).interactable = true;
			_lastLoadedNode = node;
			if (node.playSyncedClip != -1)
			{
				_terminal.PlayTerminalAudioServerRpc(node.playSyncedClip);
			}
			else if ((Object)(object)node.playClip != (Object)null)
			{
				_terminal.terminalAudio.PlayOneShot(node.playClip);
			}
			_terminal.LoadTerminalImage(node);
		}

		private void OnEnterTerminal((bool firstTime, Terminal terminal) t)
		{
			if ((Object)(object)t.terminal == (Object)(object)_terminal)
			{
				this.EnterTerminal?.Invoke(t.firstTime);
			}
		}

		private void OnExitTerminal(Terminal terminal)
		{
			if ((Object)(object)terminal == (Object)(object)_terminal)
			{
				this.ExitTerminal?.Invoke();
			}
		}

		private void OnPreAwake(Terminal terminal)
		{
			if ((Object)(object)terminal == (Object)(object)_terminal)
			{
				this.PreAwake?.Invoke();
			}
		}

		private void OnPostAwake(Terminal terminal)
		{
			if ((Object)(object)terminal == (Object)(object)_terminal)
			{
				this.PostAwake?.Invoke();
			}
		}

		private void OnPreStart(Terminal terminal)
		{
			if ((Object)(object)terminal == (Object)(object)_terminal)
			{
				this.PreStart?.Invoke();
			}
		}

		private void OnPostStart(Terminal terminal)
		{
			if ((Object)(object)terminal == (Object)(object)_terminal)
			{
				this.PostStart?.Invoke();
			}
		}

		private void OnPreUpdate(Terminal terminal)
		{
			if ((Object)(object)terminal == (Object)(object)_terminal)
			{
				this.PreUpdate?.Invoke();
			}
		}

		private void OnPostUpdate(Terminal terminal)
		{
			if ((Object)(object)terminal == (Object)(object)_terminal)
			{
				this.PostUpdate?.Invoke();
			}
		}

		public static TerminalWrapper Get(Terminal terminal)
		{
			if (WrapperMap.TryGetValue(terminal, out var value))
			{
				return value;
			}
			WrapperMap[terminal] = new TerminalWrapper(terminal);
			return WrapperMap[terminal];
		}
	}
}
namespace Computerdores.AdvancedTerminalAPI.Vanillin
{
	public static class Util
	{
		public static TerminalNode GetSpecialNode(ITerminal terminal, int nodeIndex)
		{
			return GetSpecialNode(terminal.GetDriver().VanillaTerminal, nodeIndex);
		}

		public static TerminalNode GetSpecialNode(Terminal vanillaTerminal, int nodeIndex)
		{
			return vanillaTerminal.terminalNodes.specialNodes[nodeIndex];
		}

		public static T VanillaStringMatch<T>(this IEnumerable<T> enumerable, string word, Converter<T, string> stringConverter, Predicate<T> predicate = null, int specificity = 3)
		{
			IEnumerable<T> source = (enumerable as T[]) ?? enumerable.ToArray();
			T val = source.FirstOrDefault((T n) => string.Equals(stringConverter(n), word, StringComparison.CurrentCultureIgnoreCase) && (predicate?.Invoke(n) ?? true));
			if (val != null || word.Length < specificity)
			{
				return val;
			}
			int spec;
			for (spec = word.Length; spec >= specificity; spec--)
			{
				if (val != null)
				{
					break;
				}
				val = source.FirstOrDefault((T n) => stringConverter(n).StartsWith(word.Substring(0, spec), StringComparison.CurrentCultureIgnoreCase) && (predicate?.Invoke(n) ?? true));
			}
			return val;
		}

		public static CompatibleNoun FindTerminalOption(this TerminalNode node, string word, Predicate<CompatibleNoun> predicate = null)
		{
			return node.terminalOptions.VanillaStringMatch(word, (CompatibleNoun compatibleNoun) => compatibleNoun.noun.word, predicate, 1);
		}

		public static CompatibleNoun FindNoun(this TerminalKeyword keyword, string word, Predicate<CompatibleNoun> predicate = null)
		{
			return keyword.compatibleNouns.VanillaStringMatch(word, (CompatibleNoun compatibleNoun) => compatibleNoun.noun.word, predicate);
		}

		public static TerminalKeyword FindKeyword(Terminal vanillaTerm, string word, Predicate<TerminalKeyword> predicate = null)
		{
			return vanillaTerm.terminalNodes.allKeywords.VanillaStringMatch(word, (TerminalKeyword keyword) => keyword.word, predicate);
		}

		public static TerminalKeyword FindKeyword(ITerminal terminal, string word, Predicate<TerminalKeyword> predicate = null)
		{
			return FindKeyword(terminal.GetDriver().VanillaTerminal, word, predicate);
		}

		public static TerminalNode FindByKeyword(Terminal vanillaTerm, string word, Predicate<TerminalKeyword> predicate = null)
		{
			TerminalKeyword val = FindKeyword(vanillaTerm, word, predicate);
			return ((Object)(object)val != (Object)null) ? val.specialKeywordResult : null;
		}

		public static string TextPostProcess(this TerminalNode node, Terminal vanillaTerm)
		{
			return vanillaTerm.TextPostProcess(node.displayText, node);
		}

		public static int GetPlayerIndexByName(string name, int specificity = 3)
		{
			TransformAndName val = StartOfRound.Instance.mapScreen.radarTargets.VanillaStringMatch(name, (TransformAndName input) => input.name, null, specificity);
			if (val == null)
			{
				return -1;
			}
			return StartOfRound.Instance.mapScreen.radarTargets.IndexOf(val);
		}

		public static string PredictMoonName(Terminal terminal, string partialInput)
		{
			return ((Object)(object)terminal == (Object)null) ? partialInput : FindKeyword(terminal, "route").FindNoun(partialInput).noun.word;
		}

		public static string PredictConfirmation(string partialInput)
		{
			return new List<string> { "CONFIRM", "DENY" }.VanillaStringMatch(partialInput, (string s) => s, null, 1);
		}

		public static string PredictPlayerName(string partialInput)
		{
			int playerIndexByName = GetPlayerIndexByName(partialInput);
			return (playerIndexByName != -1) ? StartOfRound.Instance.mapScreen.radarTargets[playerIndexByName].name : partialInput;
		}

		public static string PredictBuyable(Terminal terminal, string partialInput)
		{
			return FindKeyword(terminal, "buy").compatibleNouns.VanillaStringMatch(partialInput, (CompatibleNoun cn) => cn.noun.word, (CompatibleNoun cn) => cn.result.shipUnlockableID != -1 || cn.result.buyItemIndex != -1)?.noun?.word;
		}
	}
	public class VanillinTerminal : ITerminal
	{
		protected readonly InputFieldDriver driver;

		protected readonly TerminalWrapper wrapper;

		protected ICommand currentCommand;

		protected List<ICommand> Commands { get; } = new List<ICommand>();


		protected List<ICommand> BuiltinCommands { get; } = new List<ICommand>();


		private static ManualLogSource Log => Plugin.Log;

		public VanillinTerminal(InputFieldDriver driver)
		{
			this.driver = driver;
			wrapper = TerminalWrapper.Get(driver.VanillaTerminal);
			this.driver.OnSubmit += OnSubmit;
			wrapper.EnterTerminal += OnEnterTerminal;
			AddBuiltinCommands(GetBuiltinCommands(GetDriver()));
		}

		public InputFieldDriver GetDriver()
		{
			return driver;
		}

		public virtual IEnumerable<ICommand> GetCommands(bool includeBuiltins)
		{
			IEnumerable<ICommand> result;
			if (!includeBuiltins)
			{
				IEnumerable<ICommand> commands = Commands;
				result = commands;
			}
			else
			{
				result = BuiltinCommands.Concat(Commands);
			}
			return result;
		}

		public void AddCommand(ICommand command)
		{
			AddCommand(Commands, command);
		}

		protected virtual void AddCommand(ICollection<ICommand> commands, ICommand command)
		{
			commands.Add(command);
			if (command is IAliasable aliasable)
			{
				CollectionExtensions.Do<ICommand>(aliasable.GetAll(this), (Action<ICommand>)delegate(ICommand cmd)
				{
					AddCommand(commands, cmd);
				});
			}
		}

		public static IEnumerable<ICommand> GetBuiltinCommands(InputFieldDriver driver)
		{
			List<ICommand> list = new List<ICommand>
			{
				new SpecialNodeCommand("welcome", 1),
				new ViewCommand(),
				new SwitchCommand(),
				new PingCommand(),
				new TransmitCommand(),
				new ScanCommand(),
				new BuyCommand(),
				new RouteCommand(),
				new InfoCommand(),
				new EjectCommand(),
				new FlashCommand(),
				new OtherCommand()
			};
			list.AddRange(SimpleCommand.GetAll());
			list.AddRange(AccessibleObjectCommand.GetAll(driver));
			return list;
		}

		private void AddBuiltinCommands(IEnumerable<ICommand> commands)
		{
			foreach (ICommand command in commands)
			{
				AddCommand(BuiltinCommands, command);
			}
		}

		protected virtual void OnSubmit(string text)
		{
			string input = text;
			if (currentCommand == null)
			{
				string[] array = text.Split(' ');
				input = ((array.Length == 1) ? "" : GeneralExtensions.Join<string>(array.Skip(1), (Func<string, string>)null, " "));
				currentCommand = FindCommand(array[0])?.CloneStateless();
			}
			ICommand command = currentCommand;
			if (command != null)
			{
				Log.LogInfo((object)("Executing Command (" + currentCommand.GetName() + ") for input : '" + text + "'"));
				CommandResult commandResult;
				try
				{
					commandResult = command.Execute(input, this);
				}
				catch (Exception arg)
				{
					commandResult = new CommandResult("An Error occured while executing the command.\nPlease contact the author of the mod that the command is from.\n\n");
					Log.LogInfo((object)$"An error occurred during execution of '{currentCommand.GetName()}': {arg}");
				}
				if (commandResult.success)
				{
					driver.DisplayText(commandResult.output, commandResult.clearScreen);
				}
				else
				{
					Log.LogInfo((object)("Command execution was not successful for input (" + currentCommand.GetName() + "): '" + text + "'"));
					driver.DisplayText(Utility.IsNullOrWhiteSpace(commandResult.output) ? SpecialText(11) : commandResult.output, commandResult.clearScreen);
				}
				if (!commandResult.wantsMoreInput)
				{
					currentCommand = null;
				}
			}
			else if (text != "")
			{
				Log.LogInfo((object)("Did not find Command for input: '" + text + "'"));
				driver.DisplayText(SpecialText(10), clearScreen: true);
			}
		}

		protected virtual void OnEnterTerminal(bool firstTime)
		{
			ICommand command = (firstTime ? FindCommand("welcome") : FindCommand("help"));
			Log.LogInfo((object)("Entering Terminal" + (firstTime ? " for the first time" : "") + "."));
			driver.DisplayText(command?.Execute("", this).output, clearScreen: true);
		}

		protected virtual ICommand FindCommand(string command)
		{
			return FindCommand(Commands, command) ?? FindCommand(BuiltinCommands, command);
		}

		protected static ICommand FindCommand(IEnumerable<ICommand> commands, string command)
		{
			return commands.VanillaStringMatch(command, (ICommand s) => s.GetName());
		}

		protected string SpecialText(int i)
		{
			return Util.GetSpecialNode(driver.VanillaTerminal, i).displayText;
		}

		private void DebugLogNodeInfo()
		{
			for (int i = 0; i < driver.VanillaTerminal.terminalNodes.specialNodes.Count; i++)
			{
				Log.LogDebug((object)($"Special Node ({i}): '" + driver.VanillaTerminal.terminalNodes.specialNodes[i].displayText.Replace("\n", "\\n") + "'"));
			}
			for (int j = 0; j < driver.VanillaTerminal.terminalNodes.allKeywords.Length; j++)
			{
				TerminalKeyword val = driver.VanillaTerminal.terminalNodes.allKeywords[j];
				string text = (((Object)(object)val.specialKeywordResult == (Object)null) ? null : val.specialKeywordResult.displayText?.Replace("\n", "\\n"));
				Log.LogDebug((object)($"Keyword ({j}), " + (val.isVerb ? "Verb" : "Noun") + " '" + val.word + "'" + ((text != null) ? (": '" + text + "' ") : "")));
			}
		}
	}
}
namespace Computerdores.AdvancedTerminalAPI.Vanillin.Commands
{
	public class AccessibleObjectCommand : ICommand
	{
		private readonly string _name;

		public AccessibleObjectCommand(string name)
		{
			_name = name;
		}

		public string GetName()
		{
			return _name;
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			Terminal vanillaTerminal = terminal.GetDriver().VanillaTerminal;
			vanillaTerminal.CallFunctionInAccessibleTerminalObject(_name);
			vanillaTerminal.PlayBroadcastCodeEffect();
			return new CommandResult(Util.GetSpecialNode(vanillaTerminal, 19).displayText);
		}

		public ICommand CloneStateless()
		{
			return new AccessibleObjectCommand(_name);
		}

		public static IEnumerable<AccessibleObjectCommand> GetAll(InputFieldDriver driver)
		{
			return from keyword in driver.VanillaTerminal.terminalNodes.allKeywords
				where keyword.accessTerminalObjects
				select new AccessibleObjectCommand(keyword.word);
		}
	}
	public class BuyCommand : ICommand, IAliasable, IPredictable
	{
		private bool _awaitingConfirmation;

		private ICommand _command;

		public string GetName()
		{
			return "buy";
		}

		public string PredictInput(string partialInput, ITerminal terminal)
		{
			return _awaitingConfirmation ? Util.PredictConfirmation(partialInput) : FromPlayerInput(terminal.GetDriver().VanillaTerminal, partialInput).GetName();
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			if (_awaitingConfirmation)
			{
				return _command.Execute(input, terminal);
			}
			_awaitingConfirmation = true;
			string[] source = input.Split(' ');
			_command = FromPlayerInput(terminal.GetDriver().VanillaTerminal, source.First());
			return _command?.Execute(GeneralExtensions.Join<string>(source.Skip(1), (Func<string, string>)null, " "), terminal) ?? CommandResult.IgnoreInput;
		}

		public ICommand CloneStateless()
		{
			return new BuyCommand();
		}

		public IEnumerable<ICommand> GetAll(ITerminal term)
		{
			return from cn in Util.FindKeyword(term, "buy").compatibleNouns
				where cn.result.shipUnlockableID != -1 || cn.result.buyItemIndex != -1
				select FromCompatibleNoun(cn);
		}

		private static ICommand FromPlayerInput(Terminal term, string input)
		{
			CompatibleNoun cn2 = Util.FindKeyword(term, "buy").FindNoun(input, (CompatibleNoun cn) => cn.result.shipUnlockableID != -1 || cn.result.buyItemIndex != -1);
			return FromCompatibleNoun(cn2);
		}

		private static ICommand FromCompatibleNoun(CompatibleNoun cn)
		{
			if (cn.result.buyItemIndex != -1)
			{
				return new BuyItemCommand(cn.noun.word);
			}
			return new BuyUnlockableCommand(cn.noun.word);
		}
	}
	public class BuyItemCommand : ICommand, IPredictable
	{
		private readonly string _itemName;

		private bool _awaitingConfirmation;

		private CompatibleNoun _item;

		public BuyItemCommand(string itemName)
		{
			_itemName = itemName;
		}

		public string GetName()
		{
			return _itemName;
		}

		public string PredictInput(string partialInput, ITerminal terminal)
		{
			return _awaitingConfirmation ? Util.PredictConfirmation(partialInput) : partialInput;
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			Terminal vanillaTerminal = terminal.GetDriver().VanillaTerminal;
			TerminalNode val;
			if (!_awaitingConfirmation)
			{
				_item = Util.FindKeyword(terminal, "buy").FindNoun(_itemName);
				string value = Regex.Match(input, "\\d+").Value;
				vanillaTerminal.playerDefinedAmount = (Utility.IsNullOrWhiteSpace(value) ? 1 : Mathf.Clamp(int.Parse(value), 0, 10));
				val = TerminalWrapper.Get(vanillaTerminal).LoadNode(_item.result);
				_awaitingConfirmation = val.isConfirmationNode;
				return new CommandResult(val.TextPostProcess(vanillaTerminal), val.clearPreviousText, success: true, _awaitingConfirmation);
			}
			CompatibleNoun val2 = _item.result.FindTerminalOption(input);
			if (val2 == null)
			{
				return CommandResult.IgnoreInput;
			}
			val = TerminalWrapper.Get(vanillaTerminal).LoadNode(val2.result);
			return new CommandResult(val.TextPostProcess(vanillaTerminal), val.clearPreviousText);
		}

		public ICommand CloneStateless()
		{
			return new BuyItemCommand(_itemName);
		}
	}
	public class BuyUnlockableCommand : ICommand, IPredictable
	{
		private readonly string _itemName;

		private bool _awaitingConfirmation;

		private CompatibleNoun _item;

		public BuyUnlockableCommand(string itemName)
		{
			_itemName = itemName;
		}

		public string GetName()
		{
			return _itemName;
		}

		public string PredictInput(string partialInput, ITerminal terminal)
		{
			return _awaitingConfirmation ? Util.PredictConfirmation(partialInput) : partialInput;
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			Terminal vanillaTerminal = terminal.GetDriver().VanillaTerminal;
			TerminalNode val;
			if (!_awaitingConfirmation)
			{
				_item = Util.FindKeyword(terminal, "buy").FindNoun(_itemName);
				val = TerminalWrapper.Get(vanillaTerminal).LoadNode(_item.result);
				CompatibleNoun[] terminalOptions = val.terminalOptions;
				_awaitingConfirmation = ((terminalOptions != null && terminalOptions.Length != 0) ? 1 : 0) > (false ? 1 : 0);
				return new CommandResult(val.TextPostProcess(vanillaTerminal), val.clearPreviousText, success: true, _awaitingConfirmation);
			}
			CompatibleNoun val2 = _item.result.FindTerminalOption(input);
			if (val2 == null)
			{
				return CommandResult.IgnoreInput;
			}
			val = TerminalWrapper.Get(vanillaTerminal).LoadNode(val2.result);
			return new CommandResult(val.TextPostProcess(vanillaTerminal), val.clearPreviousText);
		}

		public ICommand CloneStateless()
		{
			return new BuyUnlockableCommand(_itemName);
		}
	}
	public class EjectCommand : ICommand, IPredictable
	{
		private bool _awaitingConfirmation;

		public string GetName()
		{
			return "eject";
		}

		public string PredictInput(string partialInput, ITerminal terminal)
		{
			return _awaitingConfirmation ? Util.PredictConfirmation(partialInput) : partialInput;
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			Terminal vanillaTerminal = terminal.GetDriver().VanillaTerminal;
			if (!_awaitingConfirmation)
			{
				_awaitingConfirmation = true;
				return new CommandResult(Util.FindByKeyword(vanillaTerminal, "eject").displayText, clearScreen: true, success: true, wantsMoreInput: true);
			}
			TerminalNode val = Util.FindByKeyword(vanillaTerminal, "eject").FindTerminalOption(input)?.result;
			if ((Object)(object)val == (Object)null)
			{
				return CommandResult.IgnoreInput;
			}
			val = TerminalWrapper.Get(vanillaTerminal).LoadNode(val);
			return new CommandResult(val.TextPostProcess(vanillaTerminal));
		}

		public ICommand CloneStateless()
		{
			return new EjectCommand();
		}
	}
	public class FlashCommand : ICommand, IPredictable
	{
		public string GetName()
		{
			return "flash";
		}

		public string PredictInput(string partialInput, ITerminal terminal)
		{
			return Util.PredictPlayerName(partialInput);
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			int num = Util.GetPlayerIndexByName(input);
			if (num == -1)
			{
				num = StartOfRound.Instance.mapScreen.targetTransformIndex;
				if (!StartOfRound.Instance.mapScreen.radarTargets[num].isNonPlayer)
				{
					return CommandResult.GenericError;
				}
			}
			StartOfRound.Instance.mapScreen.FlashRadarBooster(num);
			return new CommandResult(Util.GetSpecialNode(terminal, 23).displayText);
		}

		public ICommand CloneStateless()
		{
			return new FlashCommand();
		}
	}
	public class InfoCommand : ICommand, IAliasable, IPredictable
	{
		public string GetName()
		{
			return "info";
		}

		public string PredictInput(string partialInput, ITerminal terminal)
		{
			TerminalKeyword val = Util.FindKeyword(terminal.GetDriver().VanillaTerminal, "info");
			TerminalKeyword val2 = val.compatibleNouns.VanillaStringMatch(partialInput, (CompatibleNoun cn) => cn.noun.word)?.noun;
			if (val2 != null)
			{
				return val2.word;
			}
			return partialInput;
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			string[] array = input.Split(' ');
			return new InfoThingCommand(array[0]).Execute(GeneralExtensions.Join<string>(array.Skip(1), (Func<string, string>)null, " "), terminal);
		}

		public ICommand CloneStateless()
		{
			return new InfoCommand();
		}

		public IEnumerable<ICommand> GetAll(ITerminal term)
		{
			TerminalKeyword kw = Util.FindKeyword(term.GetDriver().VanillaTerminal, "info");
			return from a in kw.compatibleNouns
				where (Object)(object)a.noun.defaultVerb == (Object)(object)kw
				select new InfoThingCommand(a.noun.word);
		}
	}
	public class InfoThingCommand : ICommand
	{
		private readonly string _name;

		public InfoThingCommand(string name)
		{
			_name = name;
		}

		public string GetName()
		{
			return _name;
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			Terminal vanillaTerminal = terminal.GetDriver().VanillaTerminal;
			TerminalNode val = Util.FindKeyword(vanillaTerminal, "info").FindNoun(_name).result;
			if (val.creatureFileID != -1)
			{
				val = TerminalWrapper.Get(vanillaTerminal).LoadNode(val);
			}
			return ((Object)(object)val == (Object)null) ? CommandResult.GenericError : new CommandResult(val.TextPostProcess(vanillaTerminal), val.clearPreviousText);
		}

		public ICommand CloneStateless()
		{
			return new InfoThingCommand(_name);
		}
	}
	public class OtherCommand : ICommand
	{
		public string GetName()
		{
			return "other";
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			string text = "Other commands:\n\n";
			foreach (ICommand command in terminal.GetCommands(includeBuiltins: true))
			{
				if (command is IDescribable describable)
				{
					text = text + ">" + describable.GetUsage() + "\n" + describable.GetDescription() + "\n\n";
				}
			}
			text += "\n";
			return new CommandResult(text);
		}

		public ICommand CloneStateless()
		{
			return new OtherCommand();
		}
	}
	public class PingCommand : ICommand, IPredictable, IDescribable
	{
		public string GetName()
		{
			return "ping";
		}

		public string PredictInput(string partialInput, ITerminal terminal)
		{
			return Util.PredictPlayerName(partialInput);
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			int playerIndexByName = Util.GetPlayerIndexByName(input);
			if (playerIndexByName == -1)
			{
				return CommandResult.GenericError;
			}
			StartOfRound.Instance.mapScreen.PingRadarBooster(playerIndexByName);
			return new CommandResult(Util.GetSpecialNode(terminal, 21).displayText);
		}

		public ICommand CloneStateless()
		{
			return new PingCommand();
		}

		public string GetUsage()
		{
			return "PING [Radar booster name]";
		}

		public string GetDescription()
		{
			return "To make a radar booster play a noise.";
		}
	}
	public class RouteCommand : ICommand, IPredictable, IAliasable
	{
		private RouteMoonCommand _command;

		private bool _awaitingConfirmation;

		public string GetName()
		{
			return "route";
		}

		public string PredictInput(string partialInput, ITerminal terminal)
		{
			return _awaitingConfirmation ? Util.PredictConfirmation(partialInput) : Util.PredictMoonName(terminal.GetDriver().VanillaTerminal, partialInput);
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			if (_awaitingConfirmation)
			{
				return _command.Execute(input, terminal);
			}
			_awaitingConfirmation = true;
			string[] source = input.Split(' ');
			_command = RouteMoonCommand.FromPlayerInput(terminal.GetDriver().VanillaTerminal, source.First());
			return _command?.Execute(GeneralExtensions.Join<string>(source.Skip(1), (Func<string, string>)null, " "), terminal) ?? CommandResult.IgnoreInput;
		}

		public IEnumerable<ICommand> GetAll(ITerminal term)
		{
			return Util.FindKeyword(term, "route").compatibleNouns.Select((CompatibleNoun noun) => new RouteMoonCommand(noun.noun.word));
		}

		public ICommand CloneStateless()
		{
			return new RouteCommand();
		}
	}
	public class RouteMoonCommand : ICommand, IPredictable
	{
		private readonly string _moonName;

		private bool _awaitingConfirmation;

		private CompatibleNoun _moon;

		public RouteMoonCommand(string moonName)
		{
			_moonName = moonName;
		}

		public string PredictInput(string partialInput, ITerminal terminal)
		{
			return _awaitingConfirmation ? Util.PredictConfirmation(partialInput) : partialInput;
		}

		public string GetName()
		{
			return _moonName;
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			Terminal vanillaTerminal = terminal.GetDriver().VanillaTerminal;
			TerminalNode val;
			if (!_awaitingConfirmation)
			{
				_moon = Util.FindKeyword(terminal, "route").FindNoun(_moonName);
				if (_moon.result.itemCost != 0 || _moon.result.buyRerouteToMoon == -2)
				{
					vanillaTerminal.totalCostOfItems = _moon.result.itemCost;
				}
				val = TerminalWrapper.Get(vanillaTerminal).LoadNode(_moon.result);
				CompatibleNoun[] terminalOptions = val.terminalOptions;
				_awaitingConfirmation = ((terminalOptions != null && terminalOptions.Length != 0) ? 1 : 0) > (false ? 1 : 0);
				return new CommandResult(val.TextPostProcess(vanillaTerminal), val.clearPreviousText, success: true, _awaitingConfirmation);
			}
			CompatibleNoun val2 = _moon.result.FindTerminalOption(input);
			if (val2 == null)
			{
				return CommandResult.IgnoreInput;
			}
			val = TerminalWrapper.Get(vanillaTerminal).LoadNode(val2.result);
			return new CommandResult(val.TextPostProcess(vanillaTerminal), val.clearPreviousText);
		}

		public ICommand CloneStateless()
		{
			return new RouteMoonCommand(_moonName);
		}

		public static RouteMoonCommand FromPlayerInput(Terminal term, string input)
		{
			return new RouteMoonCommand(Util.FindKeyword(term, "route").FindNoun(input).noun.word);
		}
	}
	public class ScanCommand : ICommand, IDescribable
	{
		public string GetName()
		{
			return "scan";
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			Terminal vanillaTerminal = terminal.GetDriver().VanillaTerminal;
			TerminalNode val = Util.FindByKeyword(terminal.GetDriver().VanillaTerminal, "scan");
			return new CommandResult(vanillaTerminal.TextPostProcess(val.displayText, val));
		}

		public ICommand CloneStateless()
		{
			return new ScanCommand();
		}

		public string GetUsage()
		{
			return "SCAN";
		}

		public string GetDescription()
		{
			return "To scan for the number of items left on the current planet.";
		}
	}
	public class SimpleCommand : ICommand
	{
		private string _name;

		public SimpleCommand(string name)
		{
			_name = name;
		}

		public string GetName()
		{
			return _name;
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			Terminal vanillaTerminal = terminal.GetDriver().VanillaTerminal;
			TerminalNode specialKeywordResult = Util.FindKeyword(vanillaTerminal, _name).specialKeywordResult;
			return ((Object)(object)specialKeywordResult == (Object)null) ? CommandResult.GenericError : new CommandResult(specialKeywordResult.TextPostProcess(vanillaTerminal), specialKeywordResult.clearPreviousText);
		}

		public ICommand CloneStateless()
		{
			return new SimpleCommand(_name);
		}

		public static IEnumerable<SimpleCommand> GetAll()
		{
			return new string[8] { "help", "moons", "store", "upgrades", "decor", "storage", "sigurd", "bestiary" }.Select((string s) => new SimpleCommand(s));
		}
	}
	public class SpecialNodeCommand : ICommand
	{
		private readonly string _name;

		private readonly int _index;

		public SpecialNodeCommand(string name, int index)
		{
			_name = name;
			_index = index;
		}

		public string GetName()
		{
			return _name;
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			Terminal vanillaTerminal = terminal.GetDriver().VanillaTerminal;
			return new CommandResult(Util.GetSpecialNode(vanillaTerminal, _index).TextPostProcess(vanillaTerminal));
		}

		public ICommand CloneStateless()
		{
			return new SpecialNodeCommand(_name, _index);
		}
	}
	public class SwitchCommand : ICommand, IPredictable, IDescribable
	{
		public string GetName()
		{
			return "switch";
		}

		public string PredictInput(string partialInput, ITerminal terminal)
		{
			return Util.PredictPlayerName(partialInput);
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			int playerIndexByName = Util.GetPlayerIndexByName(input);
			if (playerIndexByName == -1 && Utility.IsNullOrWhiteSpace(input))
			{
				return CommandResult.GenericError;
			}
			if (playerIndexByName != -1)
			{
				StartOfRound.Instance.mapScreen.SwitchRadarTargetAndSync(playerIndexByName);
			}
			else
			{
				StartOfRound.Instance.mapScreen.SwitchRadarTargetForward(true);
			}
			return new CommandResult(Util.FindByKeyword(terminal.GetDriver().VanillaTerminal, "switch").displayText);
		}

		public ICommand CloneStateless()
		{
			return new SwitchCommand();
		}

		public string GetUsage()
		{
			return "SWITCH [Player name]";
		}

		public string GetDescription()
		{
			return "To switch view to a player on the main monitor.";
		}
	}
	public class TransmitCommand : ICommand, IDescribable
	{
		public string GetName()
		{
			return "transmit";
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			Terminal vanillaTerminal = terminal.GetDriver().VanillaTerminal;
			SignalTranslator val = Object.FindObjectOfType<SignalTranslator>();
			if ((Object)(object)val == (Object)null || !((double)Time.realtimeSinceStartup - (double)val.timeLastUsingSignalTranslator > 8.0) || string.IsNullOrEmpty(input))
			{
				return CommandResult.GenericError;
			}
			if (!((NetworkBehaviour)vanillaTerminal).IsServer)
			{
				val.timeLastUsingSignalTranslator = Time.realtimeSinceStartup;
			}
			HUDManager.Instance.UseSignalTranslatorServerRpc(input.Substring(0, Mathf.Min(input.Length, 10)));
			TerminalNode specialNode = Util.GetSpecialNode(terminal, 22);
			return new CommandResult(specialNode.displayText, specialNode.clearPreviousText);
		}

		public ICommand CloneStateless()
		{
			return new TransmitCommand();
		}

		public string GetUsage()
		{
			return "TRANSMIT [message]";
		}

		public string GetDescription()
		{
			return "To transmit a message with the signal translator.";
		}
	}
	public class ViewCommand : ICommand, IAliasable, IDescribable, IPredictable
	{
		public string GetName()
		{
			return "view";
		}

		public string PredictInput(string partialInput, ITerminal terminal)
		{
			return Util.FindKeyword(terminal, "view").compatibleNouns.VanillaStringMatch(partialInput, (CompatibleNoun cn) => cn.noun.word, (CompatibleNoun cn) => (Object)(object)cn.noun.defaultVerb != (Object)null).noun.word;
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			string[] array = input.Split(' ');
			ViewThingCommand viewThingCommand = new ViewThingCommand(array[0]);
			return viewThingCommand.Execute(GeneralExtensions.Join<string>(array.Skip(1), (Func<string, string>)null, " "), terminal);
		}

		public ICommand CloneStateless()
		{
			return new ViewCommand();
		}

		public IEnumerable<ICommand> GetAll(ITerminal term)
		{
			return from noun in Util.FindKeyword(term, "view").compatibleNouns
				where (Object)(object)noun.noun.defaultVerb != (Object)null
				select new ViewThingCommand(noun.noun.word);
		}

		public string GetUsage()
		{
			return "VIEW MONITOR";
		}

		public string GetDescription()
		{
			return "To toggle on AND off the main monitor's map cam.";
		}
	}
	public class ViewThingCommand : ICommand
	{
		private readonly string _name;

		public ViewThingCommand(string name)
		{
			_name = name;
		}

		public string GetName()
		{
			return _name;
		}

		public CommandResult Execute(string input, ITerminal terminal)
		{
			Terminal vanillaTerminal = terminal.GetDriver().VanillaTerminal;
			TerminalNode result = Util.FindKeyword(terminal, "view").FindNoun(_name).result;
			result = TerminalWrapper.Get(vanillaTerminal).LoadNode(result);
			return new CommandResult(result.TextPostProcess(vanillaTerminal), result.clearPreviousText);
		}

		public ICommand CloneStateless()
		{
			return new ViewThingCommand(_name);
		}
	}
}
namespace Computerdores.AdvancedTerminalAPI.patch
{
	[HarmonyPatch(typeof(Terminal))]
	public static class TerminalPatch
	{
		internal static event Consumer<(bool, Terminal)> OnEnterTerminal;

		internal static event Consumer<Terminal> OnExitTerminal;

		internal static event Consumer<Terminal> PreAwake;

		internal static event Consumer<Terminal> PostAwake;

		internal static event Consumer<Terminal> PreStart;

		internal static event Consumer<Terminal> PostStart;

		internal static event Consumer<Terminal> PreUpdate;

		internal static event Consumer<Terminal> PostUpdate;

		[HarmonyPrefix]
		[HarmonyPatch("LoadNewNode")]
		private static bool InterceptLoadNewNode(this Terminal __instance, TerminalNode node)
		{
			TerminalWrapper terminalWrapper = TerminalWrapper.Get(__instance);
			if (!terminalWrapper.redirectLoadNewNode)
			{
				return true;
			}
			terminalWrapper.LoadNewNode(node);
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch("OnSubmit")]
		private static bool OnSubmitPrefix()
		{
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch("TextChanged")]
		private static bool TextChangedPrefix()
		{
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch("BeginUsingTerminal")]
		private static void BeginUsingTerminalPostfix(Terminal __instance)
		{
			TerminalPatch.OnEnterTerminal?.Invoke((!__instance.usedTerminalThisSession, __instance));
		}

		[HarmonyPrefix]
		[HarmonyPatch("QuitTerminal")]
		private static void QuitTerminalPrefix(Terminal __instance)
		{
			TerminalPatch.OnExitTerminal?.Invoke(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch("Awake")]
		private static void AwakePrefix(Terminal __instance)
		{
			Plugin.RegisterTerminal(__instance);
			TerminalPatch.PreAwake?.Invoke(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("Awake")]
		private static void AwakePostfix(Terminal __instance)
		{
			TerminalPatch.PostAwake?.Invoke(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch("Start")]
		private static void StartPrefix(Terminal __instance)
		{
			TerminalPatch.PreStart?.Invoke(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix(Terminal __instance)
		{
			TerminalPatch.PostStart?.Invoke(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch("Update")]
		private static void UpdatePrefix(Terminal __instance)
		{
			TerminalPatch.PreUpdate?.Invoke(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void UpdatePostfix(Terminal __instance)
		{
			TerminalPatch.PostUpdate?.Invoke(__instance);
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace AdvancedTerminalAPI.NetcodePatcher
{
	[AttributeUsage(AttributeTargets.Module)]
	internal class NetcodePatchedAssemblyAttribute : Attribute
	{
	}
}