Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LethalAutocomplete v0.4.5
LethalAutocomplete.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using LethalCompanyInputUtils.Api; using Newtonsoft.Json; using TerminalApi; using TerminalApi.Events; using UnityEngine; using UnityEngine.InputSystem; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("LethalAutocomplete")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("LethalAutocomplete")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("B5A3A159-6BFF-43BE-840B-173ABE0E1D7F")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace LethalAutocomplete; public class WordNode { public string Word { get; set; } public List<WordNode> Children { get; set; } public int Weight { get; set; } public WordNode(string word, int weight) { Word = word; Weight = weight; Children = new List<WordNode>(); } public List<WordNode> FindMatchingWords(string[] inputs) { List<WordNode> list = new List<WordNode>(); if (inputs.Length == 0 || Word.ToLower().StartsWith(inputs[0].ToLower())) { if (inputs.Length == 1) { list.Add(this); } else { foreach (WordNode child in Children) { list.AddRange(child.FindMatchingWords(inputs.Skip(1).ToArray())); } } } return list; } } public class Autocomplete { private List<WordNode> _words; public List<string> blacklist; public static ManualLogSource Logger; private readonly int _defaultWeight = 10; public Autocomplete() { _words = new List<WordNode>(); blacklist = new List<string>(); } public void Insert(TerminalKeyword terminalKeyword) { try { if ((Object)(object)terminalKeyword == (Object)null) { Logger.LogWarning((object)"Tried to add null keyword"); return; } string word = ((Object)terminalKeyword).name; Logger.LogInfo((object)"blacklist"); if (blacklist == null) { blacklist = new List<string>(); } bool flag = blacklist.Contains(word); if (ListContainsWord(word, _words)) { if (flag) { _words = _words.Where((WordNode x) => x.Word != word).ToList(); } } else { if (flag) { return; } Logger.LogInfo((object)"create WordNode node"); WordNode wordNode = new WordNode(word, _defaultWeight); Logger.LogInfo((object)"terminalKeyword.compatibleNouns"); if (terminalKeyword.compatibleNouns != null) { for (int i = 0; i < terminalKeyword.compatibleNouns.Length; i++) { string text = ""; text = ((!new string[2] { "route", "info" }.Any(word.ToLower().Contains)) ? ((object)terminalKeyword.compatibleNouns[i].noun).ToString().Split(new char[1] { ' ' })[0] : terminalKeyword.compatibleNouns[i].noun.word); WordNode wordNode2 = new WordNode(text, _defaultWeight); if (word.ToLower() == "buy") { for (int j = 1; j < 10; j++) { wordNode2.Children.Add(new WordNode(j.ToString(), 10 - j)); } } wordNode.Children.Add(wordNode2); } } Logger.LogInfo((object)"_words.Add"); _words.Add(wordNode); } } catch (Exception arg2) { string arg = "None"; if (Object.op_Implicit((Object)(object)terminalKeyword) && ((Object)terminalKeyword).name != "") { arg = ((Object)terminalKeyword).name; } Logger.LogError((object)$"Failed to add terminal keyword '{arg}' in to autocomplete dictionary! Exception: {arg2}"); } } private bool ListContainsWord(string word, List<WordNode> list) { return list.Any((WordNode node) => node.Word == word); } public List<string> GetAutocomplete(string input) { try { string[] array = input.Split(new char[1] { ' ' }); List<WordNode> list = new List<WordNode>(); string matching_start = ""; for (int i = 0; i < array.Length - 1; i++) { matching_start = matching_start + array[i] + " "; } foreach (WordNode word in _words) { list.AddRange(word.FindMatchingWords(array)); } list = (from n in list.Distinct() where n.Weight > 0 orderby n.Weight descending select n).ToList(); return list.Select((WordNode n) => matching_start + n.Word).ToList(); } catch (Exception arg) { Logger.LogError((object)$"Failed on autocomplete search. Error: {arg}"); return null; } } public List<WordNode> GetWords() { return _words; } public void SetWords(List<WordNode> words) { _words = new List<WordNode>(words); } } internal class AutocompleteManager { private class SaveData { public List<WordNode> Words { get; set; } public Dictionary<string, List<string>> History { get; set; } public List<string> CommandsBlacklist { get; set; } public List<string> HistoryBlacklist { get; set; } } public static Keybinds keybinds; public static string saveFilePath = ""; public static string autocompleteKey = "<Keyboard>/tab"; public static string historyNextKey = "<Keyboard>/upArrow"; public static string historyPrevKey = "<Keyboard>/downArrow"; public static bool saveHistory = true; public static int historyMaxCount = 20; public bool exited; private Terminal _terminal; private string _input; private List<string> _terminalCommands; private List<string> _commandsHistory; private List<string> _historyBlacklist; private int _historyIndex; private string _lastAutocomplete = ""; private bool _startedAutocomplete; private List<string> _autocompleteOptions; private int _autocompleteOptionIndex; public static ManualLogSource Logger; private Autocomplete _autocomplete; public void Awake() { if (Plugin.IsDebug) { Logger.LogInfo((object)("Lethal Autocomplete Plugin is loaded! Autocomplete Key: " + autocompleteKey)); } _terminalCommands = new List<string>(); _commandsHistory = new List<string>(); _historyBlacklist = new List<string>(); _autocomplete = new Autocomplete(); Autocomplete.Logger = Logger; LoadFromJson(); SetupTerminalCallbacks(); } private void OnTerminalTextChanged(object sender, TerminalTextChangedEventArgs e) { try { _input = TerminalApi.GetTerminalInput(); _input = _input.Replace("\n", ""); if (Plugin.IsDebug) { Logger.LogMessage((object)("OnTerminalTextChanged: " + _input)); } if (_input != _lastAutocomplete) { ResetAutocomplete(); } } catch (Exception arg) { Logger.LogError((object)$"On terminal text changed event. Error: {arg}"); } } private void OnTerminalExit(object sender, TerminalEventArgs e) { if (Plugin.IsDebug) { Logger.LogMessage((object)"Terminal Exited"); } if (!saveHistory) { _commandsHistory = new List<string>(); } try { RemoveKeybindCallbacks(); SaveToJson(); } catch (Exception arg) { Logger.LogError((object)$"On terminal exit. Error: {arg}"); } } private void TerminalIsStarting(object sender, TerminalEventArgs e) { try { if (Plugin.IsDebug) { Logger.LogMessage((object)"Terminal is starting"); } _terminal = TerminalApi.Terminal; if (autocompleteKey.Contains("tab")) { RemoveTerminalExitBinding(); } } catch (Exception arg) { Logger.LogError((object)$"On terminal starting. Error: {arg}"); } } private void RemoveTerminalExitBinding() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) try { MovementActions movement = _terminal.playerActions.Movement; InputAction openMenu = ((MovementActions)(ref movement)).OpenMenu; if (Plugin.IsDebug) { Logger.LogMessage((object)(openMenu.name + " " + InputActionRebindingExtensions.GetBindingDisplayString(openMenu, (DisplayStringOptions)0, (string)null))); } openMenu.Disable(); InputBinding val = default(InputBinding); ((InputBinding)(ref val)).path = "<Keyboard>/tab"; ((InputBinding)(ref val)).overridePath = ""; InputActionRebindingExtensions.ApplyBindingOverride(openMenu, val); openMenu.Enable(); if (Plugin.IsDebug) { Logger.LogMessage((object)(openMenu.name + " " + InputActionRebindingExtensions.GetBindingDisplayString(openMenu, (DisplayStringOptions)0, (string)null))); } } catch (Exception ex) { Logger.LogWarning((object)"Remove terminal tab exit binded key"); Logger.LogError((object)ex); throw; } } private void TerminalIsStarted(object sender, TerminalEventArgs e) { try { if (Plugin.IsDebug) { Logger.LogMessage((object)"Terminal is started"); } _terminalCommands.Clear(); for (int i = 0; i < _terminal.terminalNodes.allKeywords.Length; i++) { Logger.LogWarning((object)$"Add: {_terminal.terminalNodes.allKeywords[i]}"); _autocomplete.Insert(_terminal.terminalNodes.allKeywords[i]); } } catch (Exception ex) { Logger.LogWarning((object)"Terminal is started"); Logger.LogError((object)ex); throw; } } private void TextSubmitted(object sender, TerminalParseSentenceEventArgs e) { if (Plugin.IsDebug) { Logger.LogMessage((object)("TextSubmitted: " + _input)); } try { if (e.SubmittedText != "" && !_historyBlacklist.Contains(e.SubmittedText)) { if (_commandsHistory.Count + 1 > historyMaxCount) { _commandsHistory.RemoveAt(0); } if (_commandsHistory.Contains(e.SubmittedText)) { _commandsHistory.Remove(e.SubmittedText); } _commandsHistory.Add(e.SubmittedText); _historyIndex = _commandsHistory.Count; } _input = ""; ResetAutocomplete(); } catch (Exception ex) { Logger.LogWarning((object)$"Text submitted: {e.SubmittedText} Node Returned: {e.ReturnedNode}"); Logger.LogError((object)ex); } } private void OnBeginUsing(object sender, TerminalEventArgs e) { Logger.LogMessage((object)"Player has just started using the terminal"); SetupKeybindCallbacks(); } private void OnBeganUsing(object sender, TerminalEventArgs e) { if (autocompleteKey.Contains("tab")) { HUDManager.Instance.ChangeControlTip(0, "Quit terminal : [Esc]", true); } } private void SetupTerminalCallbacks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown Events.TerminalStarting += new TerminalEventHandler(TerminalIsStarting); Events.TerminalStarted += new TerminalEventHandler(TerminalIsStarted); Events.TerminalParsedSentence += new TerminalParseSentenceEventHandler(TextSubmitted); Events.TerminalBeginUsing += new TerminalEventHandler(OnBeginUsing); Events.TerminalBeganUsing += new TerminalEventHandler(OnBeganUsing); Events.TerminalExited += new TerminalEventHandler(OnTerminalExit); Events.TerminalTextChanged += new TerminalTextChangedEventHandler(OnTerminalTextChanged); } private void SetupKeybindCallbacks() { Logger.LogMessage((object)"Setup Keybind Callbacks"); keybinds.AutocompleteAction.performed += OnAutocompleteKey; keybinds.HistoryNextAction.performed += OnHistoryNextKey; keybinds.HistoryPrevAction.performed += OnHistoryPrevKey; } private void RemoveKeybindCallbacks() { Logger.LogMessage((object)"Remove Keybind Callbacks"); keybinds.AutocompleteAction.performed -= OnAutocompleteKey; keybinds.HistoryNextAction.performed -= OnHistoryNextKey; keybinds.HistoryPrevAction.performed -= OnHistoryPrevKey; } private void OnHistoryNextKey(CallbackContext ctx) { try { if (_commandsHistory.Count >= 1 && _historyIndex >= 1) { _historyIndex--; Logger.LogInfo((object)("Set input to '" + _commandsHistory[_historyIndex] + "'.")); TerminalApi.SetTerminalInput(_commandsHistory[_historyIndex]); } } catch (Exception arg) { Logger.LogError((object)$"Failed on history next key performed. Error: {arg}"); Logger.LogInfo((object)$"_commandsHistory.Count={_commandsHistory.Count}"); Logger.LogInfo((object)$"historyIndex={_historyIndex}"); } } private void OnHistoryPrevKey(CallbackContext ctx) { TerminalApi.SetTerminalInput(""); try { if (_commandsHistory.Count >= 1) { if (_historyIndex + 1 >= _commandsHistory.Count) { _historyIndex = _commandsHistory.Count; TerminalApi.SetTerminalInput(""); Logger.LogInfo((object)"Set input to ''."); Logger.LogInfo((object)("INPUT: " + TerminalApi.GetTerminalInput())); } else { _historyIndex++; Logger.LogInfo((object)("Set input to '" + _commandsHistory[_historyIndex] + "'.")); TerminalApi.SetTerminalInput(_commandsHistory[_historyIndex]); } } } catch (Exception arg) { Logger.LogError((object)$"Failed on history prev key performed. Error: {arg}"); Logger.LogInfo((object)$"_commandsHistory.Count={_commandsHistory.Count}"); Logger.LogInfo((object)$"historyIndex={_historyIndex}"); } } private void OnAutocompleteKey(CallbackContext ctx) { try { if (_startedAutocomplete) { NextAutocomplete(); } else { StartAutocomplete(); } } catch (Exception arg) { Logger.LogError((object)$"Failed on autocomplete key performed. Error: {arg}"); Logger.LogInfo((object)$"_startedAutocomplete={_startedAutocomplete}"); } } private void StartAutocomplete() { try { List<string> autocomplete = _autocomplete.GetAutocomplete(_input); if (Plugin.IsDebug) { Logger.LogInfo((object)"Autocomplete options:"); foreach (string item in autocomplete) { Logger.LogInfo((object)(item ?? "")); } } if (autocomplete != null && autocomplete.Count > 0) { _autocompleteOptions = new List<string>(autocomplete); _startedAutocomplete = true; _lastAutocomplete = _autocompleteOptions.First(); Logger.LogMessage((object)("Set Autocomplete " + _lastAutocomplete)); TerminalApi.SetTerminalInput(_lastAutocomplete); } } catch (Exception arg) { Logger.LogError((object)$"Failed on autocomplete new options search. Error: {arg}"); } } private void NextAutocomplete() { try { if (Plugin.IsDebug) { Logger.LogInfo((object)"Autocomplete Options:"); for (int i = 0; i < _autocompleteOptions.Count; i++) { Logger.LogInfo((object)_autocompleteOptions[i]); } Logger.LogInfo((object)$"Autocomplete Index: {_autocompleteOptionIndex + 1}"); } _autocompleteOptionIndex++; if (_autocompleteOptionIndex >= _autocompleteOptions.Count) { _autocompleteOptionIndex = 0; } _lastAutocomplete = _autocompleteOptions[_autocompleteOptionIndex]; TerminalApi.SetTerminalInput(_lastAutocomplete); } catch (Exception arg) { Logger.LogError((object)$"Failed on autocomplete next options search. Error: {arg}"); } } private void ResetAutocomplete() { try { if (Plugin.IsDebug) { Logger.LogInfo((object)"Reset autocomplete state"); } _startedAutocomplete = false; _autocompleteOptionIndex = 0; } catch (Exception arg) { Logger.LogError((object)$"Failed on autocomplete reset. Error: {arg}"); } } public void SaveToJson() { List<WordNode> words = _autocomplete.GetWords(); Dictionary<string, List<string>> history = new Dictionary<string, List<string>> { ["value"] = _commandsHistory }; List<string> list = new List<string>(); list = _autocomplete.blacklist; List<string> list2 = new List<string>(); list2 = _historyBlacklist; string contents = JsonConvert.SerializeObject((object)new { Words = words, History = history, CommandsBlacklist = list, HistoryBlacklist = list2 }, (Formatting)1); File.WriteAllText(saveFilePath, contents); } private void LoadFromJson() { try { if (File.Exists(saveFilePath)) { string text = File.ReadAllText(saveFilePath); if (!string.IsNullOrEmpty(text)) { SaveData saveData = JsonConvert.DeserializeObject<SaveData>(text); _autocomplete.blacklist = saveData.CommandsBlacklist; _historyBlacklist = saveData.HistoryBlacklist; List<string> first = saveData.History["value"]; _commandsHistory = new List<string>(first.Except(_historyBlacklist)); _historyIndex = _commandsHistory.Count; _autocomplete.SetWords(saveData.Words); Logger.LogMessage((object)"Loaded save from JSON!"); } } } catch (Exception arg) { Logger.LogError((object)$"Failed on loading json save file. Error: {arg}"); } } } internal class Keybinds : LcInputActions { public InputAction AutocompleteAction => ((LcInputActions)this).Asset["Autocomplete"]; public InputAction HistoryNextAction => ((LcInputActions)this).Asset["HistoryNext"]; public InputAction HistoryPrevAction => ((LcInputActions)this).Asset["HistoryPrev"]; public override void CreateInputActions(in InputActionMapBuilder builder) { ((LcInputActions)this).CreateInputActions(ref builder); builder.NewActionBinding().WithActionId("Autocomplete").WithActionType((InputActionType)1) .WithKbmPath(AutocompleteManager.autocompleteKey) .WithBindingName("Autocomplete Key") .Finish(); builder.NewActionBinding().WithActionId("HistoryNext").WithActionType((InputActionType)1) .WithKbmPath(AutocompleteManager.historyNextKey) .WithBindingName("HistoryNext Key") .Finish(); builder.NewActionBinding().WithActionId("HistoryPrev").WithActionType((InputActionType)1) .WithKbmPath(AutocompleteManager.historyPrevKey) .WithBindingName("HistoryPrev Key") .Finish(); } } [BepInPlugin("redeye.lethalautocomplete", "Lethal Autocomplete", "0.4.5")] [BepInDependency("atomic.terminalapi", "1.3.0")] [BepInDependency("com.rune580.LethalCompanyInputUtils", "0.4.2")] public class Plugin : BaseUnityPlugin { private const string _GUID = "redeye.lethalautocomplete"; private const string _Name = "Lethal Autocomplete"; private const string _Version = "0.4.5"; public static bool IsDebug; private AutocompleteManager _autocomplete; public string PluginPath = ""; private void Awake() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Lethal Autocomplete Plugin is loaded!"); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null); try { PluginPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)ex); } try { _autocomplete = new AutocompleteManager(); AutocompleteManager.Logger = ((BaseUnityPlugin)this).Logger; ConfigFile(); AutocompleteManager.keybinds = new Keybinds(); _autocomplete.Awake(); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)ex2); } } private void OnApplicationQuit() { _autocomplete.SaveToJson(); } private void ConfigFile() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown string path = "save.json"; string text = Path.Combine(PluginPath, path); string text2 = ((BaseUnityPlugin)this).Config.Bind<string>("Basic", "Save Data Path", "", "Absolute path to the json file with autocomplete words and commands history. By default save.json generated in plugins/red_eye-LethalAutocomplete folder.").Value; if (!File.Exists(text2) && text2 != "") { text2 = text; ((BaseUnityPlugin)this).Config.Remove(new ConfigDefinition("Basic", "Save Data Path")); ((BaseUnityPlugin)this).Config.Bind<string>("Basic", "Save Data Path", text, "Absolute path to the json file with autocomplete words and commands history. By default save.json generated in plugins/red_eye-LethalAutocomplete folder."); ((BaseUnityPlugin)this).Logger.LogWarning((object)"The save file wasn't found in the directory specified by the configuration file! Using default path."); } AutocompleteManager.saveFilePath = ((text2 == "") ? text : text2); ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("Keyboard Bindings", "Autocomplete", "<Keyboard>/tab", "Get autocomplete for current input"); AutocompleteManager.autocompleteKey = (val.Value.ToLower().StartsWith("<keyboard>") ? val.Value : ("<Keyboard>/" + val.Value)); ConfigEntry<string> val2 = ((BaseUnityPlugin)this).Config.Bind<string>("Keyboard Bindings", "History Next", "<Keyboard>/upArrow", "Get current terminal session next command"); AutocompleteManager.historyNextKey = (val2.Value.ToLower().StartsWith("<keyboard>") ? val2.Value : ("<Keyboard>/" + val2.Value)); ConfigEntry<string> val3 = ((BaseUnityPlugin)this).Config.Bind<string>("Keyboard Bindings", "History Prev", "<Keyboard>/downArrow", "Get current terminal session prev command"); AutocompleteManager.historyPrevKey = (val3.Value.ToLower().StartsWith("<keyboard>") ? val3.Value : ("<Keyboard>/" + val3.Value)); AutocompleteManager.saveHistory = ((BaseUnityPlugin)this).Config.Bind<bool>("History", "Save History", true, "Regulates if the history be saved after the re-entry").Value; AutocompleteManager.historyMaxCount = ((BaseUnityPlugin)this).Config.Bind<int>("History", "Buffer Length", 20, "Max amount of commands to remember during terminal session").Value; IsDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("Other", "Enable Debug", false, "").Value; } }