using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TerminalAliases")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+37c6543cb4b656ea651197164928e3c0efe80b33")]
[assembly: AssemblyProduct("TerminalAliases")]
[assembly: AssemblyTitle("TerminalAliases")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace TerminalAliases
{
public class AliasManager
{
private readonly string _filePath;
private Dictionary<string, string> _aliases = new Dictionary<string, string>();
public IReadOnlyDictionary<string, string> Aliases => _aliases;
public AliasManager(string configDirectory)
{
_filePath = Path.Combine(configDirectory, "TerminalAliases.cfg");
Load();
}
public void Load()
{
_aliases.Clear();
if (!File.Exists(_filePath))
{
Plugin.Log.LogInfo((object)("No alias file found at " + _filePath + ", starting fresh."));
return;
}
try
{
string[] array = File.ReadAllLines(_filePath);
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim();
if (string.IsNullOrEmpty(text) || text.StartsWith("#"))
{
continue;
}
int num = text.IndexOf('=');
if (num > 0 && num < text.Length - 1)
{
string text2 = text.Substring(0, num).Trim().ToLowerInvariant();
string value = text.Substring(num + 1).Trim();
if (!string.IsNullOrEmpty(text2) && !string.IsNullOrEmpty(value))
{
_aliases[text2] = value;
}
}
}
Plugin.Log.LogInfo((object)$"Loaded {_aliases.Count} alias(es) from {_filePath}");
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to load aliases: " + ex.Message));
}
}
public void Save()
{
try
{
List<string> list = new List<string>();
foreach (KeyValuePair<string, string> alias in _aliases)
{
list.Add(alias.Key + "=" + alias.Value);
}
File.WriteAllLines(_filePath, list);
Plugin.Log.LogDebug((object)$"Saved {_aliases.Count} alias(es) to {_filePath}");
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to save aliases: " + ex.Message));
}
}
public bool Add(string alias, string command)
{
if (string.IsNullOrWhiteSpace(alias) || string.IsNullOrWhiteSpace(command))
{
return false;
}
alias = alias.ToLowerInvariant();
_aliases[alias] = command;
Save();
return true;
}
public bool Remove(string alias)
{
if (string.IsNullOrWhiteSpace(alias))
{
return false;
}
alias = alias.ToLowerInvariant();
if (_aliases.Remove(alias))
{
Save();
return true;
}
return false;
}
public bool TryGet(string alias, out string command)
{
return _aliases.TryGetValue(alias.ToLowerInvariant(), out command);
}
}
[BepInPlugin("TerminalAliases", "TerminalAliases", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Log { get; private set; }
internal static AliasManager AliasManager { get; private set; }
internal static Harmony Harmony { get; private set; }
private void Awake()
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
AliasManager = new AliasManager(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath));
Harmony = new Harmony("TerminalAliases");
Harmony.PatchAll(Assembly.GetExecutingAssembly());
Log.LogInfo((object)"TerminalAliases v1.0.0 loaded.");
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "TerminalAliases";
public const string PLUGIN_NAME = "TerminalAliases";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace TerminalAliases.Patches
{
[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
internal static class AliasCommandsPatch
{
[HarmonyPrefix]
private static bool HandleAliasCommands(Terminal __instance, ref TerminalNode __result)
{
if (__instance.textAdded <= 0)
{
return true;
}
string text = __instance.screenText.text;
int startIndex = text.Length - __instance.textAdded;
string text2 = text.Substring(startIndex).Trim().ToLowerInvariant();
if (string.IsNullOrEmpty(text2))
{
return true;
}
string[] array = text2.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (array.Length == 0)
{
return true;
}
string text3 = array[0];
if (text3 == "alias")
{
__result = HandleAliasCommand(array, __instance);
return false;
}
if (text3 == "removealias")
{
__result = HandleRemoveAliasCommand(array, __instance);
return false;
}
return true;
}
private static TerminalNode HandleAliasCommand(string[] parts, Terminal terminal)
{
if (parts.Length == 1)
{
IReadOnlyDictionary<string, string> aliases = Plugin.AliasManager.Aliases;
if (aliases.Count == 0)
{
return CreateNode("No aliases defined.\n\nUse 'alias [name] [command]' to create one.\n\n");
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Defined aliases:");
stringBuilder.AppendLine();
foreach (KeyValuePair<string, string> item in aliases)
{
stringBuilder.AppendLine(" " + item.Key + " = " + item.Value);
}
stringBuilder.AppendLine();
return CreateNode(stringBuilder.ToString());
}
if (parts.Length == 2)
{
return CreateNode("Usage: alias [name] [command]\n\nExample: alias vm view monitor\n\n");
}
string text = parts[1];
string text2 = string.Join(" ", parts, 2, parts.Length - 2);
if (Plugin.AliasManager.Add(text, text2))
{
return CreateNode("Alias '" + text + "' set to '" + text2 + "'\n\n");
}
return CreateNode("Failed to add alias.\n\n");
}
private static TerminalNode HandleRemoveAliasCommand(string[] parts, Terminal terminal)
{
if (parts.Length < 2)
{
return CreateNode("Usage: removealias [name]\n\n");
}
string text = parts[1];
if (Plugin.AliasManager.Remove(text))
{
return CreateNode("Alias '" + text + "' removed.\n\n");
}
return CreateNode("Alias '" + text + "' not found.\n\n");
}
private static TerminalNode CreateNode(string text)
{
TerminalNode obj = ScriptableObject.CreateInstance<TerminalNode>();
obj.displayText = text;
obj.clearPreviousText = true;
return obj;
}
}
[HarmonyPatch(typeof(Terminal))]
internal static class TerminalInputPatch
{
private static bool _pendingConfirm;
[HarmonyPatch("Update")]
[HarmonyPostfix]
private static void HandleCtrlEnter(Terminal __instance)
{
if (__instance.terminalInUse)
{
Keyboard current = Keyboard.current;
if (current != null && (((ButtonControl)current.leftCtrlKey).isPressed || ((ButtonControl)current.rightCtrlKey).isPressed) && ((ButtonControl)current.enterKey).wasPressedThisFrame)
{
_pendingConfirm = true;
__instance.OnSubmit();
}
}
}
[HarmonyPatch("OnSubmit")]
[HarmonyPostfix]
private static void AutoConfirm(Terminal __instance)
{
if (_pendingConfirm)
{
_pendingConfirm = false;
((MonoBehaviour)__instance).StartCoroutine(ConfirmCoroutine(__instance));
}
}
private static IEnumerator ConfirmCoroutine(Terminal terminal)
{
yield return null;
if (!terminal.terminalInUse)
{
yield break;
}
TerminalNode currentNode = terminal.currentNode;
if ((Object)(object)currentNode == (Object)null || currentNode.terminalOptions == null || currentNode.terminalOptions.Length == 0)
{
yield break;
}
CompatibleNoun[] terminalOptions = currentNode.terminalOptions;
foreach (CompatibleNoun val in terminalOptions)
{
if (!((Object)(object)val.noun == (Object)null))
{
string word = val.noun.word;
if (word != null && word.ToLowerInvariant() == "confirm")
{
terminal.LoadNewNode(val.result);
Plugin.Log.LogDebug((object)"Auto-confirmed via Ctrl+Enter.");
break;
}
}
}
}
}
[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
internal static class TerminalPatch
{
private static FieldInfo? _modifyingTextField;
private const int MaxChainDepth = 10;
private static FieldInfo ModifyingTextField => _modifyingTextField ?? (_modifyingTextField = typeof(Terminal).GetField("modifyingText", BindingFlags.Instance | BindingFlags.NonPublic));
[HarmonyPrefix]
private static void ExpandAliases(Terminal __instance)
{
if (__instance.textAdded <= 0)
{
return;
}
string text = __instance.screenText.text;
int num = text.Length - __instance.textAdded;
string text2 = text.Substring(num);
if (!string.IsNullOrWhiteSpace(text2))
{
string text3 = ExpandInput(text2);
if (!(text3 == text2))
{
bool flag = (bool)ModifyingTextField.GetValue(__instance);
ModifyingTextField.SetValue(__instance, true);
int num2 = text3.Length - text2.Length;
__instance.screenText.text = text.Substring(0, num) + text3;
__instance.textAdded += num2;
ModifyingTextField.SetValue(__instance, flag);
Plugin.Log.LogDebug((object)("Expanded: '" + text2.Trim() + "' -> '" + text3.Trim() + "'"));
}
}
}
private static string ExpandInput(string input)
{
IReadOnlyDictionary<string, string> aliases = Plugin.AliasManager.Aliases;
if (aliases.Count == 0)
{
return input;
}
string text = input;
for (int i = 0; i < 10; i++)
{
string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.None);
bool flag = false;
for (int j = 0; j < array.Length; j++)
{
string text2 = array[j];
string key = text2.ToLowerInvariant();
if (aliases.TryGetValue(key, out var value))
{
array[j] = PreserveCase(text2, value);
flag = true;
}
}
if (!flag)
{
break;
}
text = string.Join(" ", array);
}
return text;
}
private static string PreserveCase(string original, string replacement)
{
if (string.IsNullOrEmpty(original) || string.IsNullOrEmpty(replacement))
{
return replacement;
}
if (original == original.ToUpperInvariant())
{
return replacement.ToUpperInvariant();
}
if (char.IsUpper(original[0]))
{
StringBuilder stringBuilder = new StringBuilder(replacement.Length);
stringBuilder.Append(char.ToUpperInvariant(replacement[0]));
if (replacement.Length > 1)
{
stringBuilder.Append(replacement.Substring(1));
}
return stringBuilder.ToString();
}
return replacement;
}
}
}