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
{
}
}