using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using InteractiveTerminalAPI.Compat;
using InteractiveTerminalAPI.Input;
using InteractiveTerminalAPI.Misc.Util;
using InteractiveTerminalAPI.NetcodePatcher;
using InteractiveTerminalAPI.Patches.TerminalComponents;
using InteractiveTerminalAPI.UI;
using InteractiveTerminalAPI.UI.Application;
using InteractiveTerminalAPI.UI.Cursor;
using InteractiveTerminalAPI.UI.Hierarchy;
using InteractiveTerminalAPI.UI.Page;
using InteractiveTerminalAPI.UI.Screen;
using InteractiveTerminalAPI.Util;
using LethalCompanyInputUtils.Api;
using Microsoft.CodeAnalysis;
using MoreShipUpgrades.Misc;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.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 MoreShipUpgrades.Misc
{
public class PluginConfig
{
public PluginConfig(ConfigFile file)
{
}
}
}
namespace InteractiveTerminalAPI
{
[BepInPlugin("WhiteSpike.InteractiveTerminalAPI", "Interactive Terminal API", "1.2.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
internal static readonly Harmony harmony = new Harmony("WhiteSpike.InteractiveTerminalAPI");
internal static readonly ManualLogSource mls = Logger.CreateLogSource("Interactive Terminal API");
public static PluginConfig Config;
private void Awake()
{
InputUtils_Compat.Init();
PatchMainVersion();
mls.LogInfo((object)"Interactive Terminal API 1.2.0 has been loaded successfully.");
}
internal static void PatchMainVersion()
{
PatchVitalComponents();
}
private static void PatchVitalComponents()
{
try
{
harmony.PatchAll(typeof(Keybinds));
harmony.PatchAll(typeof(TerminalPatcher));
mls.LogInfo((object)"Game managers have been patched");
}
catch (Exception ex)
{
mls.LogError((object)"An error has occurred patching the game managers...");
mls.LogError((object)ex);
}
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "InteractiveTerminalAPI";
public const string PLUGIN_NAME = "MoreShipUpgrades";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace InteractiveTerminalAPI.Util
{
internal static class TerminalNodeUtils
{
private static Terminal terminal;
private static readonly Dictionary<string, TerminalNode> retrievedTerminalNodes = new Dictionary<string, TerminalNode>();
private const string HELP_NOUN = "help";
private const string INFO_VERB = "info";
private const string SHOVEL_NOUN = "shovel";
public static Terminal GetTerminal()
{
if ((Object)(object)terminal == (Object)null)
{
terminal = GameObject.Find("TerminalScript").GetComponent<Terminal>();
}
return terminal;
}
internal static TerminalKeyword FindTerminalKeyword(string word)
{
TerminalKeyword obj = GetTerminal().CheckForExactSentences(word);
if ((Object)(object)obj == (Object)null)
{
Plugin.mls.LogError((object)("Couldn't find terminal node for the word \"" + word + "\""));
}
return obj;
}
internal static TerminalNode GetItemInfoTerminalNode(string word)
{
TerminalNode val = retrievedTerminalNodes.GetValueOrDefault(word, null);
if ((Object)(object)val != (Object)null)
{
return val;
}
TerminalKeyword val2 = GetTerminal().ParseWord("info", 2);
for (int i = 0; i < val2.compatibleNouns.Length; i++)
{
if (!((Object)(object)val == (Object)null))
{
break;
}
if (!(val2.compatibleNouns[i].noun.word != word))
{
val = val2.compatibleNouns[i].result;
}
}
if ((Object)(object)val == (Object)null)
{
Plugin.mls.LogError((object)("Couldn't find info terminal node for item \"" + word + "\""));
}
if (!retrievedTerminalNodes.ContainsKey(word))
{
retrievedTerminalNodes[word] = val;
}
return val;
}
internal static TerminalNode GetSpecialTerminalNodeByWord(string word)
{
TerminalNode valueOrDefault = retrievedTerminalNodes.GetValueOrDefault(word, null);
if ((Object)(object)valueOrDefault != (Object)null)
{
return valueOrDefault;
}
valueOrDefault = FindTerminalKeyword(word).specialKeywordResult;
if (!retrievedTerminalNodes.ContainsKey(word))
{
retrievedTerminalNodes[word] = valueOrDefault;
}
return valueOrDefault;
}
internal static void UpdateTextToNode(ref TerminalNode node, string insertText, bool enabled = true)
{
string displayText = node.displayText;
int num = displayText.IndexOf(insertText);
if (num != -1 && !enabled)
{
node.displayText = displayText.Remove(num, insertText.Length);
}
else if (num == -1 && enabled)
{
displayText += insertText;
node.displayText = displayText;
}
}
internal static TerminalNode GetHelpTerminalNode()
{
return GetSpecialTerminalNodeByWord("help");
}
internal static TerminalNode GetInfoShovelTerminalNode()
{
return GetItemInfoTerminalNode("shovel");
}
}
internal static class Tools
{
private static Terminal terminal;
public static void FindCodeInstruction(ref int index, ref List<CodeInstruction> codes, object findValue, MethodInfo addCode, bool skip = false, bool requireInstance = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, string errorMessage = "Not found")
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Expected O, but got Unknown
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Expected O, but got Unknown
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Expected O, but got Unknown
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Expected O, but got Unknown
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Expected O, but got Unknown
bool flag = false;
while (index < codes.Count)
{
if (CheckCodeInstruction(codes[index], findValue))
{
flag = true;
if (!skip)
{
if (andInstruction)
{
codes.Insert(index + 1, new CodeInstruction(OpCodes.And, (object)null));
}
if (!andInstruction && orInstruction)
{
codes.Insert(index + 1, new CodeInstruction(OpCodes.Or, (object)null));
}
if (notInstruction)
{
codes.Insert(index + 1, new CodeInstruction(OpCodes.Not, (object)null));
}
codes.Insert(index + 1, new CodeInstruction(OpCodes.Call, (object)addCode));
if (requireInstance)
{
codes.Insert(index + 1, new CodeInstruction(OpCodes.Ldarg_0, (object)null));
}
}
break;
}
index++;
}
if (!flag)
{
Plugin.mls.LogError((object)errorMessage);
}
index++;
}
public static int FindLocalField(int index, ref List<CodeInstruction> codes, int localIndex, object addCode, bool skip = false, bool store = false, bool requireInstance = false, string errorMessage = "Not found")
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Expected O, but got Unknown
bool flag = false;
while (index < codes.Count)
{
if (CheckCodeInstruction(codes[index], localIndex, store))
{
flag = true;
if (!skip)
{
codes.Insert(index + 1, new CodeInstruction(OpCodes.Call, addCode));
if (requireInstance)
{
codes.Insert(index + 1, new CodeInstruction(OpCodes.Ldarg_0, (object)null));
}
}
break;
}
index++;
}
if (!flag)
{
Plugin.mls.LogError((object)errorMessage);
}
return index + 1;
}
public static void FindString(ref int index, ref List<CodeInstruction> codes, string findValue, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
{
FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction, andInstruction, orInstruction, errorMessage);
}
public static void FindField(ref int index, ref List<CodeInstruction> codes, FieldInfo findField, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
{
FindCodeInstruction(ref index, ref codes, findField, addCode, skip, requireInstance, notInstruction, andInstruction, orInstruction, errorMessage);
}
public static void FindMethod(ref int index, ref List<CodeInstruction> codes, MethodInfo findMethod, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
{
FindCodeInstruction(ref index, ref codes, findMethod, addCode, skip, requireInstance, notInstruction, andInstruction, orInstruction, errorMessage);
}
public static void FindFloat(ref int index, ref List<CodeInstruction> codes, float findValue, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
{
FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction, andInstruction, orInstruction, errorMessage);
}
public static void FindInteger(ref int index, ref List<CodeInstruction> codes, sbyte findValue, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
{
FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction, andInstruction, orInstruction, errorMessage);
}
public static void FindSub(ref int index, ref List<CodeInstruction> codes, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
{
object findValue = OpCodes.Sub;
bool notInstruction2 = notInstruction;
bool andInstruction2 = andInstruction;
bool orInstruction2 = orInstruction;
FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction2, andInstruction2, orInstruction2, errorMessage);
}
public static void FindDiv(ref int index, ref List<CodeInstruction> codes, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
{
object findValue = OpCodes.Div;
bool notInstruction2 = notInstruction;
bool andInstruction2 = andInstruction;
bool orInstruction2 = orInstruction;
FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction2, andInstruction2, orInstruction2, errorMessage);
}
public static void FindAdd(ref int index, ref List<CodeInstruction> codes, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
{
object findValue = OpCodes.Add;
bool notInstruction2 = notInstruction;
bool andInstruction2 = andInstruction;
bool orInstruction2 = orInstruction;
FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction2, andInstruction2, orInstruction2, errorMessage);
}
public static void FindMul(ref int index, ref List<CodeInstruction> codes, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
{
object findValue = OpCodes.Mul;
bool notInstruction2 = notInstruction;
bool andInstruction2 = andInstruction;
bool orInstruction2 = orInstruction;
FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction2, andInstruction2, orInstruction2, errorMessage);
}
private static bool CheckCodeInstruction(CodeInstruction code, int localIndex, bool store = false)
{
if (!store)
{
switch (localIndex)
{
case 0:
return code.opcode == OpCodes.Ldloc_0;
case 1:
return code.opcode == OpCodes.Ldloc_1;
case 2:
return code.opcode == OpCodes.Ldloc_2;
case 3:
return code.opcode == OpCodes.Ldloc_3;
default:
if (code.opcode == OpCodes.Ldloc)
{
return (int)code.operand == localIndex;
}
return false;
}
}
switch (localIndex)
{
case 0:
return code.opcode == OpCodes.Stloc_0;
case 1:
return code.opcode == OpCodes.Stloc_1;
case 2:
return code.opcode == OpCodes.Stloc_2;
case 3:
return code.opcode == OpCodes.Stloc_3;
default:
if (code.opcode == OpCodes.Stloc)
{
return (int)code.operand == localIndex;
}
return false;
}
}
private static bool CheckCodeInstruction(CodeInstruction code, object findValue)
{
if (findValue is sbyte)
{
return CheckIntegerCodeInstruction(code, findValue);
}
if (findValue is float)
{
if (code.opcode == OpCodes.Ldc_R4)
{
return code.operand.Equals(findValue);
}
return false;
}
if (findValue is string)
{
if (code.opcode == OpCodes.Ldstr)
{
return code.operand.Equals(findValue);
}
return false;
}
if (findValue is MethodInfo)
{
if (code.opcode == OpCodes.Call || code.opcode == OpCodes.Callvirt)
{
return code.operand == findValue;
}
return false;
}
if (findValue is FieldInfo)
{
if (code.opcode == OpCodes.Ldfld || code.opcode == OpCodes.Stfld)
{
return code.operand == findValue;
}
return false;
}
if (findValue is OpCode)
{
return code.opcode == (OpCode)findValue;
}
return false;
}
private static bool CheckIntegerCodeInstruction(CodeInstruction code, object findValue)
{
switch ((sbyte)findValue)
{
case 0:
return code.opcode == OpCodes.Ldc_I4_0;
case 1:
return code.opcode == OpCodes.Ldc_I4_1;
case 2:
return code.opcode == OpCodes.Ldc_I4_2;
case 3:
return code.opcode == OpCodes.Ldc_I4_3;
case 4:
return code.opcode == OpCodes.Ldc_I4_4;
case 5:
return code.opcode == OpCodes.Ldc_I4_5;
case 6:
return code.opcode == OpCodes.Ldc_I4_6;
case 7:
return code.opcode == OpCodes.Ldc_I4_7;
case 8:
return code.opcode == OpCodes.Ldc_I4_8;
default:
if (code.opcode == OpCodes.Ldc_I4_S)
{
return code.operand.Equals(findValue);
}
return false;
}
}
public static void ShuffleList<T>(List<T> list)
{
if (list == null)
{
throw new ArgumentNullException("list");
}
Random random = new Random();
int num = list.Count;
while (num > 1)
{
num--;
int index = random.Next(num + 1);
T value = list[index];
list[index] = list[num];
list[num] = value;
}
}
public static bool SpawnMob(string mob, Vector3 position, int numToSpawn)
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
for (int i = 0; i < RoundManager.Instance.currentLevel.Enemies.Count; i++)
{
if (RoundManager.Instance.currentLevel.Enemies[i].enemyType.enemyName == mob)
{
for (int j = 0; j < numToSpawn; j++)
{
RoundManager.Instance.SpawnEnemyOnServer(position, 0f, i);
}
return true;
}
}
return false;
}
internal static string GenerateInfoForUpgrade(string infoFormat, int initialPrice, int[] incrementalPrices, Func<int, float> infoFunction)
{
string text = string.Format(infoFormat, 1, initialPrice, infoFunction(0));
for (int i = 0; i < incrementalPrices.Length; i++)
{
float num = infoFunction(i + 1);
text = ((num % 1f != 0f) ? (text + string.Format(infoFormat, i + 2, incrementalPrices[i], num)) : (text + string.Format(infoFormat, i + 2, incrementalPrices[i], Mathf.RoundToInt(num))));
}
return text;
}
public static Color ConvertValueToColor(string hex, Color defaultValue)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
Color result = default(Color);
if (hex == null || !ColorUtility.TryParseHtmlString("#" + hex.Trim('#', ' '), ref result))
{
return defaultValue;
}
return result;
}
internal static string WrapText(string text, int availableLength, string leftPadding = "", string rightPadding = "", bool padLeftFirst = true)
{
int num = availableLength - leftPadding.Length - rightPadding.Length;
string text2 = "";
string text3 = "";
int num2 = 0;
int num3 = -1;
bool flag = true;
bool flag2 = false;
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
if (c == '<')
{
flag2 = true;
}
if (c == ' ' && !flag2)
{
num3 = text3.Length;
}
if (c != '\n')
{
text3 += c;
if (!flag2)
{
num2++;
}
}
if (c == '>' && flag2)
{
flag2 = false;
}
if (num2 < num && c != '\n')
{
continue;
}
if (c != '\n' && c != ' ')
{
if (num3 != -1)
{
string text4 = ((padLeftFirst || !flag) ? leftPadding : "") + text3.Substring(0, num3) + new string(' ', Mathf.Max(0, num - num3)) + rightPadding;
text2 = text2 + text4 + "\n";
text3 = text3.Substring(num3 + 1);
}
else
{
string text5 = ((padLeftFirst || !flag) ? leftPadding : "") + text3 + rightPadding;
text2 = text2 + text5 + "\n";
text3 = "";
}
}
else
{
if (text3 != "")
{
text2 = text2 + ((padLeftFirst || !flag) ? leftPadding : "") + text3 + new string(' ', Mathf.Max(0, num - num2)) + rightPadding + "\n";
}
text3 = "";
}
num3 = -1;
flag = false;
num2 = text3.Length;
}
if (text3 != "")
{
text2 = text2 + ((padLeftFirst || !flag) ? leftPadding : "") + text3 + new string(' ', Mathf.Max(0, num - num2)) + rightPadding + "\n";
}
return text2;
}
internal static void SpawnExplosion(Vector3 explosionPosition, bool spawnExplosionEffect = false, float killRange = 1f, float damageRange = 1f, int nonLethalDamage = 50, float physicsForce = 0f, GameObject overridePrefab = null)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
Landmine.SpawnExplosion(explosionPosition, spawnExplosionEffect, killRange, damageRange, nonLethalDamage, physicsForce, overridePrefab, false);
}
internal static Terminal GetTerminal()
{
if ((Object)(object)terminal == (Object)null)
{
terminal = GameObject.Find("TerminalScript").GetComponent<Terminal>();
}
return terminal;
}
}
}
namespace InteractiveTerminalAPI.UI
{
public class InteractiveTerminalManager : MonoBehaviour
{
internal static Dictionary<string, Func<TerminalApplication>> registeredApplications = new Dictionary<string, Func<TerminalApplication>>();
internal static Dictionary<string, bool> commandSensitive = new Dictionary<string, bool>();
public static InteractiveTerminalManager Instance;
internal TerminalApplication mainApplication;
private Terminal terminalReference;
private TerminalNode lastTerminalNode;
private Color previousCaretColor;
private void Start()
{
Instance = this;
terminalReference = Tools.GetTerminal();
lastTerminalNode = terminalReference.currentNode;
UpdateInput(enable: false);
}
internal void Initialize(string command)
{
Func<TerminalApplication> func = registeredApplications.GetValueOrDefault(command, null);
if (commandSensitive.ContainsKey(command.ToLower()))
{
foreach (string key in registeredApplications.Keys)
{
if (string.Equals(key, command, StringComparison.OrdinalIgnoreCase))
{
func = registeredApplications[key];
break;
}
}
}
if (func == null)
{
Plugin.mls.LogError((object)"An application was not selected to change the terminal's text.");
return;
}
mainApplication = func();
if (mainApplication == null)
{
Plugin.mls.LogError((object)"The selected application doesn't have a valid constructor.");
return;
}
mainApplication.Initialization();
mainApplication.UpdateInputBindings(enable: true);
}
private void Update()
{
if (!((Object)(object)terminalReference == (Object)null) && mainApplication != null)
{
mainApplication.UpdateText();
}
}
private void OnDestroy()
{
mainApplication.UpdateInputBindings();
terminalReference.LoadNewNode(lastTerminalNode);
((Selectable)terminalReference.screenText).interactable = true;
terminalReference.screenText.ActivateInputField();
((Selectable)terminalReference.screenText).Select();
UpdateInput(enable: true);
Instance = null;
}
internal void UpdateInput(bool enable)
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
if (enable)
{
((Selectable)terminalReference.screenText).interactable = true;
terminalReference.screenText.ActivateInputField();
((Selectable)terminalReference.screenText).Select();
terminalReference.screenText.caretColor = previousCaretColor;
}
else
{
terminalReference.screenText.DeactivateInputField(false);
((Selectable)terminalReference.screenText).interactable = false;
previousCaretColor = terminalReference.screenText.caretColor;
terminalReference.screenText.caretColor = APIConstants.Invisible;
}
}
public static bool InteractiveTerminalBeingUsed()
{
return (Object)(object)Instance != (Object)null;
}
public static bool ContainsApplication(string command)
{
if (!commandSensitive.ContainsKey(command.ToLower()))
{
return registeredApplications.ContainsKey(command);
}
foreach (string key in registeredApplications.Keys)
{
if (string.Equals(key, command, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
public static void RegisterApplication<T>(string command) where T : TerminalApplication, new()
{
if (registeredApplications.ContainsKey(command))
{
Plugin.mls.LogError((object)("An application has already been registered under the command \"" + command + "\""));
return;
}
registeredApplications.Add(command, () => new T());
}
public static void RegisterApplication<T>(string command, bool caseSensitive) where T : TerminalApplication, new()
{
RegisterApplication<T>(command);
commandSensitive.Add(command.ToLower(), caseSensitive);
}
public static void RegisterApplication<T>(string[] commands) where T : TerminalApplication, new()
{
for (int i = 0; i < commands.Length; i++)
{
RegisterApplication<T>(commands[i]);
}
}
public static void RegisterApplication<T>(string[] commands, bool caseSensitive) where T : TerminalApplication, new()
{
for (int i = 0; i < commands.Length; i++)
{
RegisterApplication<T>(commands[i], caseSensitive);
}
}
}
public interface ITextElement
{
string GetText(int availableLength);
}
public class TextElement : ITextElement
{
public string Text { get; set; }
public string GetText(int availableLength)
{
return Tools.WrapText(Text, availableLength);
}
public static TextElement Create(string text = "")
{
return new TextElement
{
Text = text
};
}
}
}
namespace InteractiveTerminalAPI.UI.Screen
{
public class BoxedOutputScreen<K, V> : BoxedScreen
{
public Func<K> Input { get; set; }
public Func<K, V> Output { get; set; }
public V GetOutput()
{
if (Output == null || Input == null)
{
return default(V);
}
return Output(Input());
}
public override string GetText(int availableLength)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine().AppendLine();
stringBuilder.Append(new string(' ', 1)).Append('╔').Append(new string('═', Title.Length + 2))
.Append('╗')
.AppendLine();
stringBuilder.Append('╭').Append('╢').Append(' ')
.Append(Title)
.Append(' ')
.Append('╟')
.Append(new string('─', availableLength - 6 - Title.Length))
.Append('╮')
.AppendLine();
stringBuilder.Append('│').Append('╚').Append(new string('═', Title.Length + 2))
.Append('╝')
.Append(new string(' ', availableLength - 6 - Title.Length))
.Append('│')
.AppendLine();
for (int i = 0; i < elements.Length; i++)
{
stringBuilder.Append(Tools.WrapText(elements[i].GetText(availableLength - 4), availableLength, "│ ", " │"));
}
string text = GetOutput().ToString();
int num = availableLength - text.Length - 6;
stringBuilder.Append('│').Append(new string(' ', num - 3)).Append('╔');
stringBuilder.Append(new string('═', text.Length + 2)).Append('╗').Append(new string(' ', 3))
.Append('│')
.Append('\n');
stringBuilder.Append('╰').Append(new string('─', num - 3)).Append('╢')
.Append(' ')
.Append(text)
.Append(' ')
.Append('╟')
.Append(new string('─', 3))
.Append('╯')
.Append('\n');
stringBuilder.Append(new string(' ', num - 2)).Append('╚').Append(new string('═', text.Length + 2))
.Append('╝')
.Append('\n');
return stringBuilder.ToString();
}
public static BoxedOutputScreen<K, V> Create(string title = "", ITextElement[] elements = null, Func<K> input = null, Func<K, V> output = null)
{
return new BoxedOutputScreen<K, V>
{
Title = title,
elements = elements,
Input = input,
Output = output
};
}
}
public class BoxedScreen : IScreen, ITextElement
{
public string Title;
public ITextElement[] elements;
public virtual string GetText(int availableLength)
{
string text = Title;
if (Title.Length > availableLength - 6)
{
text = text.Substring(0, availableLength - 6);
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine().AppendLine();
stringBuilder.Append(new string(' ', 1)).Append('╔').Append(new string('═', text.Length + 2))
.Append('╗')
.AppendLine();
stringBuilder.Append('╭').Append('╢').Append(' ')
.Append(text)
.Append(' ')
.Append('╟')
.Append(new string('─', availableLength - 6 - text.Length))
.Append('╮')
.AppendLine();
stringBuilder.Append('│').Append('╚').Append(new string('═', text.Length + 2))
.Append('╝')
.Append(new string(' ', availableLength - 6 - text.Length))
.Append('│')
.AppendLine();
for (int i = 0; i < elements.Length; i++)
{
stringBuilder.Append(Tools.WrapText(elements[i].GetText(availableLength - 4), availableLength, "│ ", " │"));
}
stringBuilder.Append('╰').Append(new string('─', availableLength - 2)).Append('╯')
.AppendLine();
return stringBuilder.ToString();
}
public static BoxedScreen Create(string title = "", ITextElement[] elements = null)
{
return new BoxedScreen
{
Title = title,
elements = elements
};
}
}
public interface IScreen : ITextElement
{
}
}
namespace InteractiveTerminalAPI.UI.Page
{
public class PageCursorElement : PageElement
{
public CursorMenu[] cursorMenus;
public CursorMenu GetCurrentCursorMenu()
{
return cursorMenus[pageIndex];
}
public void ChangeSorting()
{
CollectionExtensions.Do<CursorMenu>((IEnumerable<CursorMenu>)cursorMenus, (Action<CursorMenu>)delegate(CursorMenu x)
{
x.ChangeSorting();
});
CursorElement[] array = cursorMenus.SelectMany((CursorMenu menu) => menu.elements).ToArray();
Func<CursorElement, CursorElement, int> sortFunction = cursorMenus[0].GetCurrentSorting();
Array.Sort(array, (CursorElement x, CursorElement y) => sortFunction(x, y));
int num = 0;
CursorMenu[] array2 = cursorMenus;
foreach (CursorMenu cursorMenu in array2)
{
int num2 = cursorMenu.elements.Length;
Array.Copy(array, num, cursorMenu.elements, 0, num2);
num += num2;
}
}
public static PageCursorElement Create(int startingPageIndex = 0, IScreen[] elements = null, CursorMenu[] cursorMenus = null)
{
return new PageCursorElement
{
pageIndex = startingPageIndex,
elements = elements,
cursorMenus = cursorMenus
};
}
}
public class PageElement : ITextElement
{
public int pageIndex;
public IScreen[] elements;
public string GetText(int availableLength)
{
IScreen screen = elements[pageIndex];
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(screen.GetText(availableLength));
if (elements.Length > 1)
{
stringBuilder.Append(new string(' ', availableLength - 30)).Append($"Page {pageIndex + 1}/{elements.Length}");
}
return stringBuilder.ToString();
}
public void PageUp()
{
pageIndex = (pageIndex + 1) % elements.Length;
}
public void PageDown()
{
pageIndex--;
if (pageIndex < 0)
{
pageIndex = elements.Length - 1;
}
}
public void ResetPage()
{
pageIndex = 0;
}
public IScreen GetCurrentScreen()
{
return elements[pageIndex];
}
public static PageElement Create(int startingPageIndex = 0, IScreen[] elements = null)
{
return new PageElement
{
pageIndex = startingPageIndex,
elements = elements
};
}
}
}
namespace InteractiveTerminalAPI.UI.Hierarchy
{
public class BaseCursorHierarchyElement : CursorElement
{
private CursorMenu previousCursorMenu;
public char IntersectionCharacter { get; set; } = '├';
public char LastIntersectionCharacter { get; set; } = '└';
public char SpacingCharacter { get; set; } = '─';
public int Spacing { get; set; } = 2;
public char VerticalSpacingCharacter { get; set; } = '│';
public int VerticalSpacing { get; set; } = 1;
public string Title { get; set; }
public CursorMenu innerCursorMenu { get; set; }
public bool Selected { get; set; }
public override void ExecuteAction()
{
base.ExecuteAction();
Selected = true;
if (InteractiveTerminalManager.Instance.mainApplication is InteractiveTerminalApplication interactiveTerminalApplication)
{
Keybinds.cursorExitAction.performed -= InteractiveTerminalManager.Instance.mainApplication.OnScreenExit;
Keybinds.cursorExitAction.performed += OnHierarchyExit;
previousCursorMenu = interactiveTerminalApplication.currentCursorMenu;
interactiveTerminalApplication.currentCursorMenu = innerCursorMenu;
}
}
public void OnHierarchyExit(CallbackContext context)
{
Keybinds.cursorExitAction.performed += InteractiveTerminalManager.Instance.mainApplication.OnScreenExit;
Keybinds.cursorExitAction.performed -= OnHierarchyExit;
if (InteractiveTerminalManager.Instance.mainApplication is InteractiveTerminalApplication interactiveTerminalApplication)
{
interactiveTerminalApplication.currentCursorMenu = previousCursorMenu;
previousCursorMenu = null;
}
Selected = false;
}
public override string GetText(int availableLength)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(Title);
if (!Selected)
{
return stringBuilder.ToString();
}
stringBuilder.Append("\n");
int num = 0;
CursorElement[] elements = innerCursorMenu.elements;
int num2 = 0;
while (num2 < elements.Length)
{
CursorElement cursorElement = elements[num2];
if (num != VerticalSpacing)
{
stringBuilder.Append(VerticalSpacingCharacter + "\n");
num++;
continue;
}
num = 0;
bool flag = num2 == elements.Length - 1;
if (flag)
{
stringBuilder.Append(LastIntersectionCharacter);
}
else
{
stringBuilder.Append(IntersectionCharacter);
}
stringBuilder.Append(new string(SpacingCharacter, Spacing));
stringBuilder.Append(' ');
string text = cursorElement.GetText(availableLength - 5 - Spacing);
string arg = (cursorElement.Active(cursorElement) ? "#00FF0066" : "#66666633");
text = ((num2 == innerCursorMenu.cursorIndex) ? string.Format("<mark={0}><color={1}>{2}</color></mark>", arg, "#FFFFFFFF", text) : text);
if (cursorElement is BaseCursorHierarchyElement)
{
stringBuilder.Append(Tools.WrapText(text, availableLength - 5 - Spacing, ((!flag) ? new string(VerticalSpacingCharacter, 1) : "") + new string(' ', Spacing + 1), "", padLeftFirst: false));
}
else if (flag)
{
stringBuilder.Append(Tools.WrapText(text, availableLength - 5 - Spacing));
}
else
{
stringBuilder.Append(Tools.WrapText(text, availableLength - 5 - Spacing, new string(VerticalSpacingCharacter, 1), "", padLeftFirst: false));
}
num2++;
}
return stringBuilder.ToString();
}
}
public abstract class BaseHierarchyElement<T> : ITextElement where T : ITextElement
{
public char IntersectionCharacter { get; set; } = '├';
public char LastIntersectionCharacter { get; set; } = '└';
public char SpacingCharacter { get; set; } = '─';
public int Spacing { get; set; } = 2;
public char VerticalSpacingCharacter { get; set; } = '│';
public int VerticalSpacing { get; set; } = 1;
public string Title { get; set; }
public T[] textElements { get; set; }
public string GetText(int availableLength)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(Title + "\n");
int num = 0;
int num2 = 0;
while (num2 < textElements.Length)
{
T val = textElements[num2];
if (num != VerticalSpacing)
{
stringBuilder.Append(VerticalSpacingCharacter + "\n");
num++;
continue;
}
num = 0;
bool flag = num2 == textElements.Length - 1;
if (flag)
{
stringBuilder.Append(LastIntersectionCharacter);
}
else
{
stringBuilder.Append(IntersectionCharacter);
}
stringBuilder.Append(new string(SpacingCharacter, Spacing));
stringBuilder.Append(' ');
T val2;
if (val is BaseHierarchyElement<T>)
{
ref T reference = ref val;
val2 = default(T);
if (val2 == null)
{
val2 = reference;
reference = ref val2;
}
stringBuilder.Append(Tools.WrapText(reference.GetText(availableLength - 5 - Spacing), availableLength - 5 - Spacing, ((!flag) ? new string(VerticalSpacingCharacter, 1) : "") + new string(' ', Spacing + 1), "", padLeftFirst: false));
}
else if (flag)
{
ref T reference2 = ref val;
val2 = default(T);
if (val2 == null)
{
val2 = reference2;
reference2 = ref val2;
}
stringBuilder.Append(Tools.WrapText(reference2.GetText(availableLength - 5 - Spacing), availableLength - 5 - Spacing));
}
else
{
ref T reference3 = ref val;
val2 = default(T);
if (val2 == null)
{
val2 = reference3;
reference3 = ref val2;
}
stringBuilder.Append(Tools.WrapText(reference3.GetText(availableLength - 5 - Spacing), availableLength - 5 - Spacing, new string(VerticalSpacingCharacter, 1), "", padLeftFirst: false));
}
num2++;
}
return stringBuilder.ToString();
}
}
internal class TextHierarchyElement : BaseHierarchyElement<ITextElement>
{
public static TextHierarchyElement Create(string title, ITextElement[] textElements, int spacing = 2, char intersectionCharacter = '├', char lastIntersectionCharacter = '└', char spacingCharacter = '─')
{
return new TextHierarchyElement
{
Title = title,
textElements = textElements,
Spacing = spacing,
IntersectionCharacter = intersectionCharacter,
LastIntersectionCharacter = lastIntersectionCharacter,
SpacingCharacter = spacingCharacter
};
}
}
}
namespace InteractiveTerminalAPI.UI.Cursor
{
public abstract class BaseCursorCounterMenu<T> : BaseCursorMenu<T> where T : CursorCounterElement
{
public void IncrementCounter()
{
elements[cursorIndex].IncrementCounter();
}
public void DecrementCounter()
{
elements[cursorIndex].DecrementCounter();
}
}
public abstract class BaseCursorMenu<T> : ITextElement where T : CursorElement
{
public char cursorCharacter = '>';
public int cursorIndex;
public int sortingIndex;
public T[] elements;
public Func<T, T, int>[] SortingFunctions { get; set; }
public void Execute()
{
elements[cursorIndex].ExecuteAction();
}
public Func<T, T, int> GetCurrentSorting()
{
return SortingFunctions[sortingIndex];
}
public void ChangeSorting()
{
sortingIndex = (sortingIndex + 1) % SortingFunctions.Length;
Array.Sort(elements, (T x, T y) => SortingFunctions[sortingIndex](x, y));
}
public void Forward()
{
cursorIndex = (cursorIndex + 1) % elements.Length;
while (elements[cursorIndex] == null || (!elements[cursorIndex].Active(elements[cursorIndex]) && !elements[cursorIndex].SelectInactive))
{
cursorIndex = (cursorIndex + 1) % elements.Length;
}
}
public void Backward()
{
cursorIndex--;
if (cursorIndex < 0)
{
cursorIndex = elements.Length - 1;
}
while (elements[cursorIndex] == null || (!elements[cursorIndex].Active(elements[cursorIndex]) && !elements[cursorIndex].SelectInactive))
{
cursorIndex--;
if (cursorIndex < 0)
{
cursorIndex = elements.Length - 1;
}
}
}
public void ResetCursor()
{
cursorIndex = 0;
}
public abstract string GetText(int availableLength);
}
public class CursorCounterElement : CursorElement
{
public int Counter { get; set; }
public bool ShowCounter { get; set; }
public void ToggleShow(bool showCounter)
{
ShowCounter = showCounter;
}
public void IncrementCounter()
{
Counter++;
}
public void DecrementCounter()
{
if (Counter > 0)
{
Counter--;
}
}
public override string GetText(int availableLength)
{
StringBuilder stringBuilder = new StringBuilder();
if (!base.Active(this))
{
stringBuilder.Append(string.Format("<color={0}>", "#666666"));
}
if (ShowCounter)
{
stringBuilder.Append('←').Append(Counter).Append('→')
.Append(' ');
}
stringBuilder.Append(base.GetText(availableLength));
if (!base.Active(this))
{
stringBuilder.Append("</color>");
}
return stringBuilder.ToString();
}
public static CursorCounterElement Create(string name = "", string description = "", Action action = null, int counter = 0, Func<CursorElement, bool> active = null, bool selectInactive = true, bool showCounter = true)
{
return new CursorCounterElement
{
Name = name,
Description = description,
Action = action,
Counter = counter,
Active = ((active == null) ? ((Func<CursorElement, bool>)((CursorElement _) => true)) : active),
SelectInactive = selectInactive,
ShowCounter = showCounter
};
}
}
public class CursorCounterMenu : BaseCursorCounterMenu<CursorCounterElement>
{
public override string GetText(int availableLength)
{
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < elements.Length; i++)
{
CursorCounterElement cursorCounterElement = elements[i];
if (cursorCounterElement != null)
{
if (i == cursorIndex)
{
stringBuilder.Append(cursorCharacter).Append(' ');
}
else
{
stringBuilder.Append(' ').Append(' ');
}
string text = cursorCounterElement.GetText(availableLength - 2);
string arg = (cursorCounterElement.Active(cursorCounterElement) ? "#00FF0066" : "#66666633");
text = ((i == cursorIndex) ? string.Format("<mark={0}><color={1}>{2}</color></mark>", arg, "#FFFFFFFF", text) : text);
stringBuilder.Append(Tools.WrapText(text, availableLength, " ", "", padLeftFirst: false));
}
}
return stringBuilder.ToString();
}
public static CursorCounterMenu Create<T>(int startingCursorIndex = 0, char cursorCharacter = '>', T[] elements = null, Func<CursorElement, CursorElement, int>[] sorting = null) where T : CursorCounterElement
{
if (sorting == null)
{
sorting = new Func<CursorElement, CursorElement, int>[1]
{
(CursorElement element1, CursorElement element2) => string.Compare(element2.Name, element1.Name)
};
}
CursorCounterMenu obj = new CursorCounterMenu
{
cursorIndex = startingCursorIndex,
cursorCharacter = cursorCharacter
};
obj.elements = elements;
Func<CursorCounterElement, CursorCounterElement, int>[] sortingFunctions = sorting;
obj.SortingFunctions = sortingFunctions;
return obj;
}
}
public class CursorElement : ITextElement
{
public string Name { get; set; }
public string Description { get; set; }
public Func<CursorElement, bool> Active { get; set; } = (CursorElement x) => true;
public bool SelectInactive { get; set; } = true;
public Action Action { get; set; }
public virtual string GetText(int availableLength)
{
StringBuilder stringBuilder = new StringBuilder();
if (!Active(this))
{
stringBuilder.Append(string.Format("<color={0}>", "#666666"));
}
stringBuilder.Append(Name);
if (!Active(this))
{
stringBuilder.Append("</color>");
}
if (!string.IsNullOrEmpty(Description))
{
stringBuilder.Append("\n" + Tools.WrapText(Description, availableLength));
}
return stringBuilder.ToString();
}
public virtual void ExecuteAction()
{
if (Action != null)
{
Action();
}
}
public static CursorElement Create(string name = "", string description = "", Action action = null, Func<CursorElement, bool> active = null, bool selectInactive = true)
{
return new CursorElement
{
Name = name,
Description = description,
Action = action,
Active = ((active == null) ? ((Func<CursorElement, bool>)((CursorElement _) => true)) : active),
SelectInactive = selectInactive
};
}
}
public class CursorMenu : BaseCursorMenu<CursorElement>
{
public override string GetText(int availableLength)
{
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < elements.Length; i++)
{
CursorElement cursorElement = elements[i];
if (cursorElement != null)
{
if (i == cursorIndex)
{
stringBuilder.Append(cursorCharacter).Append(' ');
}
else
{
stringBuilder.Append(' ').Append(' ');
}
string text = cursorElement.GetText(availableLength - 2);
string arg = (cursorElement.Active(cursorElement) ? "#00FF0066" : "#66666633");
if (!(cursorElement is BaseCursorHierarchyElement baseCursorHierarchyElement) || !baseCursorHierarchyElement.Selected)
{
text = ((i == cursorIndex) ? string.Format("<mark={0}><color={1}>{2}</color></mark>", arg, "#FFFFFFFF", text) : text);
}
stringBuilder.Append(Tools.WrapText(text, availableLength, " ", "", padLeftFirst: false));
}
}
return stringBuilder.ToString();
}
public static CursorMenu Create(int startingCursorIndex = 0, char cursorCharacter = '>', CursorElement[] elements = null, Func<CursorElement, CursorElement, int>[] sorting = null)
{
if (sorting == null)
{
sorting = new Func<CursorElement, CursorElement, int>[1]
{
(CursorElement element1, CursorElement element2) => string.Compare(element2.Name, element1.Name)
};
}
return new CursorMenu
{
cursorIndex = startingCursorIndex,
cursorCharacter = cursorCharacter,
elements = elements,
SortingFunctions = sorting
};
}
}
public class CursorOutputElement<T> : CursorCounterElement
{
public Func<int, T> Func { get; set; }
public T ApplyFunction()
{
return Func(base.Counter);
}
public override string GetText(int availableLength)
{
StringBuilder stringBuilder = new StringBuilder();
if (!base.Active(this))
{
stringBuilder.Append(string.Format("<color={0}>", "#666666"));
}
stringBuilder.Append(base.GetText(availableLength));
stringBuilder.Append(new string(' ', 10));
stringBuilder.Append(ApplyFunction());
if (!base.Active(this))
{
stringBuilder.Append("</color>");
}
return stringBuilder.ToString();
}
public static CursorOutputElement<T> Create(string name = "", string description = "", Action action = null, int counter = 0, Func<int, T> func = null, Func<CursorElement, bool> active = null, bool selectInactive = true, bool showCounter = true)
{
return new CursorOutputElement<T>
{
Name = name,
Description = description,
Action = action,
Counter = counter,
Func = func,
Active = ((active == null) ? ((Func<CursorElement, bool>)((CursorElement _) => true)) : active),
SelectInactive = selectInactive,
ShowCounter = showCounter
};
}
}
}
namespace InteractiveTerminalAPI.UI.Application
{
public abstract class BaseInteractiveApplication<K, V> : TerminalApplication where K : BaseCursorMenu<V> where V : CursorElement
{
public K currentCursorMenu;
public K previousCursorMenu;
public IScreen previousScreen;
protected override string GetApplicationText()
{
return currentScreen.GetText(51);
}
protected override Action PreviousScreen()
{
return delegate
{
SwitchScreen((previousScreen != null) ? previousScreen : currentScreen, (previousCursorMenu != null) ? previousCursorMenu : currentCursorMenu, previous: true);
};
}
protected override void AddInputBindings()
{
base.AddInputBindings();
Keybinds.changeSortingAction.performed += OnApplicationChangeSorting;
Keybinds.cursorUpAction.performed += OnApplicationCursorUp;
Keybinds.cursorDownAction.performed += OnApplicationCursorDown;
Keybinds.storeConfirmAction.performed += OnApplicationConfirm;
}
protected override void RemoveInputBindings()
{
base.RemoveInputBindings();
Keybinds.changeSortingAction.performed -= OnApplicationChangeSorting;
Keybinds.cursorUpAction.performed -= OnApplicationCursorUp;
Keybinds.cursorDownAction.performed -= OnApplicationCursorDown;
Keybinds.storeConfirmAction.performed -= OnApplicationConfirm;
}
internal void OnApplicationConfirm(CallbackContext context)
{
Submit();
}
internal void OnApplicationCursorUp(CallbackContext context)
{
MoveCursorUp();
}
internal void OnApplicationChangeSorting(CallbackContext context)
{
ChangeSorting();
}
internal void OnApplicationCursorDown(CallbackContext context)
{
MoveCursorDown();
}
protected virtual void ChangeSorting()
{
currentCursorMenu.ChangeSorting();
}
public virtual void MoveCursorUp()
{
currentCursorMenu.Backward();
}
public virtual void MoveCursorDown()
{
currentCursorMenu.Forward();
}
public void Submit()
{
currentCursorMenu.Execute();
}
protected virtual void SwitchScreen(IScreen screen, K cursorMenu, bool previous)
{
previousScreen = screen;
previousCursorMenu = currentCursorMenu;
currentScreen = screen;
currentCursorMenu = cursorMenu;
if (!previous)
{
cursorMenu.cursorIndex = 0;
}
}
}
public abstract class InteractiveCounterApplication<K, V> : BaseInteractiveApplication<K, V> where K : BaseCursorCounterMenu<V> where V : CursorCounterElement
{
protected override void AddInputBindings()
{
base.AddInputBindings();
Keybinds.pageUpAction.performed += OnApplicationCountUp;
Keybinds.pageDownAction.performed += OnApplicationCountDown;
}
protected override void RemoveInputBindings()
{
base.RemoveInputBindings();
Keybinds.pageUpAction.performed -= OnApplicationCountUp;
Keybinds.pageDownAction.performed -= OnApplicationCountDown;
}
private void IncrementSelectedCounter()
{
currentCursorMenu.IncrementCounter();
}
private void DecrementSelectedCounter()
{
currentCursorMenu.DecrementCounter();
}
internal void OnApplicationCountUp(CallbackContext context)
{
IncrementSelectedCounter();
}
internal void OnApplicationCountDown(CallbackContext context)
{
DecrementSelectedCounter();
}
}
public abstract class InteractiveTerminalApplication : BaseInteractiveApplication<CursorMenu, CursorElement>
{
protected void Confirm(string title, string description, Action confirmAction, Action declineAction, string additionalMessage = "")
{
CursorElement[] elements = new CursorElement[2]
{
CursorElement.Create("Confirm", "", confirmAction),
CursorElement.Create("Abort", "", declineAction)
};
CursorMenu cursorMenu = CursorMenu.Create(0, '>', elements);
ITextElement[] elements2 = new ITextElement[4]
{
TextElement.Create(description),
TextElement.Create(" "),
TextElement.Create(additionalMessage),
cursorMenu
};
IScreen screen = BoxedScreen.Create(title, elements2);
SwitchScreen(screen, cursorMenu, previous: false);
}
protected void ErrorMessage(string title, Action backAction, string error)
{
CursorElement[] elements = new CursorElement[1] { CursorElement.Create("Back", "", backAction) };
CursorMenu cursorMenu = CursorMenu.Create(0, '>', elements);
ITextElement[] elements2 = new ITextElement[3]
{
TextElement.Create(error),
TextElement.Create(" "),
cursorMenu
};
IScreen screen = BoxedScreen.Create(title, elements2);
SwitchScreen(screen, cursorMenu, previous: false);
}
protected void ErrorMessage(string title, string description, Action backAction, string error)
{
CursorElement[] elements = new CursorElement[1] { CursorElement.Create("Back", "", backAction) };
CursorMenu cursorMenu = CursorMenu.Create(0, '>', elements);
ITextElement[] elements2 = new ITextElement[5]
{
TextElement.Create(description),
TextElement.Create(" "),
TextElement.Create(error),
TextElement.Create(" "),
cursorMenu
};
IScreen screen = BoxedScreen.Create(title, elements2);
SwitchScreen(screen, cursorMenu, previous: false);
}
}
public abstract class PageApplication : InteractiveTerminalApplication
{
protected PageCursorElement initialPage;
protected PageCursorElement previousPage;
protected PageCursorElement currentPage;
protected override string GetApplicationText()
{
if (currentScreen != currentPage.GetCurrentScreen())
{
return currentScreen.GetText(51);
}
return currentPage.GetText(51);
}
protected virtual int GetEntriesPerPage<T>(T[] entries)
{
return Mathf.CeilToInt((float)entries.Length / 2f);
}
protected override Action PreviousScreen()
{
return delegate
{
if (previousPage != null)
{
SwitchScreen(previousPage, previous: true);
}
else
{
ResetScreen();
}
};
}
protected virtual int GetAmountPages<T>(T[] entries)
{
return Mathf.CeilToInt((float)entries.Length / (float)GetEntriesPerPage(entries));
}
protected override void ChangeSorting()
{
currentPage.ChangeSorting();
}
public override void MoveCursorUp()
{
int cursorIndex = currentCursorMenu.cursorIndex;
base.MoveCursorUp();
if (currentPage.GetCurrentCursorMenu() == currentCursorMenu && currentCursorMenu.cursorIndex > cursorIndex)
{
ChangeScreenBackward();
base.MoveCursorUp();
}
}
public override void MoveCursorDown()
{
int cursorIndex = currentCursorMenu.cursorIndex;
base.MoveCursorDown();
if (currentPage.GetCurrentCursorMenu() == currentCursorMenu && currentCursorMenu.cursorIndex < cursorIndex)
{
ChangeScreenForward();
currentCursorMenu.cursorIndex = 0;
}
}
protected void ResetScreen()
{
SwitchScreen(initialPage, previous: true);
}
protected void SwitchScreen(PageCursorElement pages, bool previous)
{
previousPage = currentPage;
currentPage = pages;
SwitchScreen(currentPage.GetCurrentScreen(), currentPage.GetCurrentCursorMenu(), previous);
}
protected override void SwitchScreen(IScreen screen, CursorMenu cursorMenu, bool previous)
{
base.SwitchScreen(screen, cursorMenu, previous);
if (screen == currentPage.GetCurrentScreen())
{
Keybinds.pageUpAction.performed += OnApplicationPageUp;
Keybinds.pageDownAction.performed += OnApplicationPageDown;
}
else
{
Keybinds.pageUpAction.performed -= OnApplicationPageUp;
Keybinds.pageDownAction.performed -= OnApplicationPageDown;
}
}
public void ChangeScreenForward()
{
currentPage.PageUp();
SwitchScreen(currentPage.GetCurrentScreen(), currentPage.GetCurrentCursorMenu(), previous: false);
}
public void ChangeScreenBackward()
{
currentPage.PageDown();
SwitchScreen(currentPage.GetCurrentScreen(), currentPage.GetCurrentCursorMenu(), previous: false);
}
protected override void AddInputBindings()
{
base.AddInputBindings();
Keybinds.pageUpAction.performed += OnApplicationPageUp;
Keybinds.pageDownAction.performed += OnApplicationPageDown;
}
protected override void RemoveInputBindings()
{
base.RemoveInputBindings();
Keybinds.pageUpAction.performed -= OnApplicationPageUp;
Keybinds.pageDownAction.performed -= OnApplicationPageDown;
}
protected (T[][], CursorMenu[], IScreen[]) GetPageEntries<T>(T[] entries)
{
int amountPages = GetAmountPages(entries);
int entriesPerPage = GetEntriesPerPage(entries);
T[][] array = new T[amountPages][];
for (int i = 0; i < amountPages; i++)
{
array[i] = new T[entriesPerPage];
}
for (int j = 0; j < entries.Length; j++)
{
int num = j / entriesPerPage;
int num2 = j % entriesPerPage;
array[num][num2] = entries[j];
}
CursorMenu[] array2 = new CursorMenu[array.Length];
IScreen[] array3 = new IScreen[array.Length];
CursorMenu[] cursorMenus = array2;
initialPage = PageCursorElement.Create(0, array3, cursorMenus);
return (array, array2, array3);
}
internal void OnApplicationPageUp(CallbackContext context)
{
ChangeScreenForward();
}
internal void OnApplicationPageDown(CallbackContext context)
{
ChangeScreenBackward();
}
}
public abstract class TerminalApplication
{
protected IScreen currentScreen;
protected readonly Terminal terminal = Tools.GetTerminal();
public abstract void Initialization();
protected abstract string GetApplicationText();
protected abstract Action PreviousScreen();
public void UpdateText()
{
string applicationText = GetApplicationText();
terminal.screenText.text = applicationText;
terminal.currentText = applicationText;
}
internal void UpdateInputBindings(bool enable = false)
{
if (enable)
{
AddInputBindings();
}
else
{
RemoveInputBindings();
}
}
protected virtual void AddInputBindings()
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
Keybinds.cursorExitAction.performed += OnScreenExit;
MovementActions movement = terminal.playerActions.Movement;
((MovementActions)(ref movement)).OpenMenu.performed -= terminal.PressESC;
}
protected virtual void RemoveInputBindings()
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
Keybinds.cursorExitAction.performed -= OnScreenExit;
MovementActions movement = terminal.playerActions.Movement;
((MovementActions)(ref movement)).OpenMenu.performed += terminal.PressESC;
}
public void OnScreenExit(CallbackContext context)
{
Object.Destroy((Object)(object)InteractiveTerminalManager.Instance);
}
}
}
namespace InteractiveTerminalAPI.Patches.TerminalComponents
{
[HarmonyPatch(typeof(Terminal))]
internal static class TerminalPatcher
{
[HarmonyTranspiler]
[HarmonyPatch("Update")]
private static IEnumerable<CodeInstruction> UpdateTranspiler(IEnumerable<CodeInstruction> instructions)
{
MethodInfo method = typeof(InteractiveTerminalManager).GetMethod("InteractiveTerminalBeingUsed");
MethodInfo method2 = typeof(ButtonControl).GetMethod("get_wasPressedThisFrame");
List<CodeInstruction> codes = new List<CodeInstruction>(instructions);
int index = 0;
Tools.FindMethod(ref index, ref codes, method2, method, skip: false, notInstruction: true, andInstruction: true, orInstruction: false, requireInstance: false, "Couldn't find field used to check if the terminal is being used");
return codes;
}
[HarmonyPostfix]
[HarmonyPatch("ParsePlayerSentence")]
private static void CustomParser(ref Terminal __instance, ref TerminalNode __result)
{
string command = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded);
if (InteractiveTerminalManager.ContainsApplication(command))
{
GameObject obj = Object.Instantiate<GameObject>(GameObject.CreatePrimitive((PrimitiveType)3));
((Object)obj).name = "InteractiveTerminal";
Object.Destroy((Object)(object)obj.GetComponent<MeshRenderer>());
Object.Destroy((Object)(object)obj.GetComponent<MeshFilter>());
Object.Destroy((Object)(object)obj.GetComponent<BoxCollider>());
obj.AddComponent<InteractiveTerminalManager>().Initialize(command);
__result = TerminalNodeUtils.GetHelpTerminalNode();
}
}
}
}
namespace InteractiveTerminalAPI.Misc
{
internal static class Metadata
{
public const string GUID = "WhiteSpike.InteractiveTerminalAPI";
public const string NAME = "Interactive Terminal API";
public const string VERSION = "1.2.0";
}
}
namespace InteractiveTerminalAPI.Misc.Util
{
internal static class APIConstants
{
internal const char WHITE_SPACE = ' ';
internal const string HEXADECIMAL_RED = "#FF0000";
internal const string HEXADECIMAL_WHITE = "#FFFFFF";
internal const string HEXADECIMAL_GREEN = "#00FF00";
internal const string HEXADECIMAL_GREY = "#666666";
internal const string MOVE_CURSOR_UP_KEYBIND_NAME = "Move Cursor Up in the current application";
internal const string MOVE_CURSOR_UP_DEFAULT_KEYBIND = "<Keyboard>/w";
internal const string MOVE_CURSOR_DOWN_KEYBIND_NAME = "Move Cursor Down in the current application";
internal const string MOVE_CURSOR_DOWN_DEFAULT_KEYBIND = "<Keyboard>/s";
internal const string EXIT_STORE_KEYBIND_NAME = "Exit application";
internal const string EXIT_STORE_DEFAULT_KEYBIND = "<Keyboard>/escape";
internal const string NEXT_PAGE_KEYBIND_NAME = "Next Page in the current application";
internal const string NEXT_PAGE_DEFAULT_KEYBIND = "<Keyboard>/d";
internal const string PREVIOUS_PAGE_KEYBIND_NAME = "Previous Page in the current application";
internal const string PREVIOUS_PAGE_DEFAULT_KEYBIND = "<Keyboard>/a";
internal const string SUBMIT_PROMPT_KEYBIND_NAME = "Submit Prompt in the current application";
internal const string SUBMIT_PROMPT_DEFAULT_KEYBIND = "<Keyboard>/enter";
internal const string CHANGE_SORTING_KEYBIND_NAME = "Change sorting in the current application";
internal const string CHANGE_SORTING_DEFAULT_KEYBIND = "<Keyboard>/f";
internal const char INTERSECTION = '├';
internal const char LAST_INTERSECTION = '└';
internal const char SPACING = '─';
internal const int SPACING_AMOUNT = 2;
internal const char VERTICAL_SPACING = '│';
internal const int VERTICAL_SPACING_AMOUNT = 1;
internal const char CURSOR = '>';
internal const string SELECTED_CURSOR_ELEMENT_FORMAT = "<mark={0}><color={1}>{2}</color></mark>";
internal const string COLOR_INITIAL_FORMAT = "<color={0}>";
internal const string COLOR_FINAL_FORMAT = "</color>";
internal const string DEFAULT_BACKGROUND_SELECTED_COLOR = "#00FF0066";
internal const string INACTIVE_BACKGROUND_SELECTED_COLOR = "#66666633";
internal const string DEFAULT_TEXT_SELECTED_COLOR = "#FFFFFFFF";
internal const string DEFAULT_DEACTIVATED_TEXT_COLOUR = "#66666655";
internal const string GO_BACK_PROMPT = "Back";
internal const string CONFIRM_PROMPT = "Confirm";
internal const string CANCEL_PROMPT = "Abort";
internal const int AVAILABLE_CHARACTERS_PER_LINE = 51;
internal const char TOP_LEFT_CORNER = '╭';
internal const char TOP_RIGHT_CORNER = '╮';
internal const char BOTTOM_LEFT_CORNER = '╰';
internal const char BOTTOM_RIGHT_CORNER = '╯';
internal const char VERTICAL_LINE = '│';
internal const char HORIZONTAL_LINE = '─';
internal const char CONNECTING_TITLE_LEFT = '╢';
internal const char CONNECTING_TITLE_RIGHT = '╟';
internal const char TOP_RIGHT_TITLE_CORNER = '╗';
internal const char TOP_LEFT_TITLE_CORNER = '╔';
internal const char BOTTOM_RIGHT_TITLE_CORNER = '╝';
internal const char BOTTOM_LEFT_TITLE_CORNER = '╚';
internal const char VERTICAL_TITLE_LINE = '║';
internal const char HORIZONTAL_TITLE_LINE = '═';
internal const char LEFT_ARROW = '←';
internal const char RIGHT_ARROW = '→';
internal const int START_PAGE_COUNTER = 30;
internal const int NAME_LENGTH = 17;
internal const int LEVEL_LENGTH = 7;
internal const char EMPTY_LEVEL = '○';
internal const char FILLED_LEVEL = '●';
internal static readonly Color Invisible = new Color(0f, 0f, 0f, 0f);
}
}
namespace InteractiveTerminalAPI.Input
{
internal class IngameKeybinds : LcInputActions
{
public static IngameKeybinds Instance;
[InputAction("<Keyboard>/w", Name = "Move Cursor Up in the current application")]
public InputAction UpgradeStoreCursorUpKey { get; set; }
[InputAction("<Keyboard>/s", Name = "Move Cursor Down in the current application")]
public InputAction UpgradeStoreCursorDownKey { get; set; }
[InputAction("<Keyboard>/escape", Name = "Exit application")]
public InputAction UpgradeStoreCursorExitKey { get; set; }
[InputAction("<Keyboard>/d", Name = "Next Page in the current application")]
public InputAction UpgradeStorePageUpKey { get; set; }
[InputAction("<Keyboard>/a", Name = "Previous Page in the current application")]
public InputAction UpgradeStorePageDownKey { get; set; }
[InputAction("<Keyboard>/enter", Name = "Submit Prompt in the current application")]
public InputAction LguStoreConfirmKey { get; set; }
[InputAction("<Keyboard>/f", Name = "Change sorting in the current application")]
public InputAction ApplicationChangeSorting { get; set; }
internal static InputActionAsset GetAsset()
{
return ((LcInputActions)Instance).Asset;
}
}
[HarmonyPatch]
internal static class Keybinds
{
public static InputActionAsset Asset;
public static InputActionMap ActionMap;
public static InputAction cursorUpAction;
public static InputAction cursorDownAction;
public static InputAction cursorExitAction;
public static InputAction pageUpAction;
public static InputAction pageDownAction;
public static InputAction storeConfirmAction;
public static InputAction changeSortingAction;
public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;
[HarmonyPatch(typeof(PreInitSceneScript), "Awake")]
[HarmonyPrefix]
public static void AddToKeybindMenu()
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
Asset = InputUtils_Compat.Asset;
ActionMap = Asset.actionMaps[0];
cursorUpAction = InputUtils_Compat.CursorUpKey;
cursorDownAction = InputUtils_Compat.CursorDownKey;
cursorExitAction = InputUtils_Compat.CursorExitKey;
pageUpAction = InputUtils_Compat.PageUpKey;
pageDownAction = InputUtils_Compat.PageDownKey;
storeConfirmAction = InputUtils_Compat.LguStoreConfirmKey;
changeSortingAction = InputUtils_Compat.ChangeApplicationSortingKey;
}
}
}
namespace InteractiveTerminalAPI.Compat
{
public static class InputUtils_Compat
{
internal static InputActionAsset Asset => IngameKeybinds.GetAsset();
public static InputAction CursorUpKey => IngameKeybinds.Instance.UpgradeStoreCursorUpKey;
public static InputAction CursorDownKey => IngameKeybinds.Instance.UpgradeStoreCursorDownKey;
public static InputAction CursorExitKey => IngameKeybinds.Instance.UpgradeStoreCursorExitKey;
public static InputAction PageUpKey => IngameKeybinds.Instance.UpgradeStorePageUpKey;
public static InputAction PageDownKey => IngameKeybinds.Instance.UpgradeStorePageDownKey;
public static InputAction LguStoreConfirmKey => IngameKeybinds.Instance.LguStoreConfirmKey;
public static InputAction ChangeApplicationSortingKey => IngameKeybinds.Instance.ApplicationChangeSorting;
internal static void Init()
{
IngameKeybinds.Instance = new IngameKeybinds();
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}
namespace InteractiveTerminalAPI.NetcodePatcher
{
[AttributeUsage(AttributeTargets.Module)]
internal class NetcodePatchedAssemblyAttribute : Attribute
{
}
}