diff --git a/ConsoleImprovements/ConsoleImprovements.csproj b/ConsoleImprovements/ConsoleImprovements.csproj
index 5a92203..7a624b5 100644
--- a/ConsoleImprovements/ConsoleImprovements.csproj
+++ b/ConsoleImprovements/ConsoleImprovements.csproj
@@ -44,5 +44,8 @@
$(LogicWorldGameLocation)\Logic_World_Data\Managed\UnityEngine.UI.dll
+
+ $(LogicWorldGameLocation)\Logic_World_Data\Managed\LICC.dll
+
diff --git a/ConsoleImprovements/ConsoleImprovements/manifest.jecs b/ConsoleImprovements/ConsoleImprovements/manifest.jecs
index 1c8938e..1f43c4e 100644
--- a/ConsoleImprovements/ConsoleImprovements/manifest.jecs
+++ b/ConsoleImprovements/ConsoleImprovements/manifest.jecs
@@ -1,8 +1,8 @@
ID: D4VID_ConsoleImprovements
Name: ConsoleImprovements
Author: D4VID
-Version: 1.1.2
-Priority: 0
+Version: 1.2.0
+Priority: -90
ClientOnly: true
Dependencies:
- HarmonyForLogicWorld
diff --git a/ConsoleImprovements/ConsoleImprovements/src/client/CommandHistoryPatch.cs b/ConsoleImprovements/ConsoleImprovements/src/client/CommandHistoryPatch.cs
index ac9945b..62803aa 100644
--- a/ConsoleImprovements/ConsoleImprovements/src/client/CommandHistoryPatch.cs
+++ b/ConsoleImprovements/ConsoleImprovements/src/client/CommandHistoryPatch.cs
@@ -1,9 +1,11 @@
+using System.Collections;
using System.Reflection;
using System.Collections.Generic;
using EccsLogicWorldAPI.Shared.AccessHelper;
using FancyInput;
using HarmonyLib;
using JimmysUnityUtilities;
+using LICC;
using LogicLog;
using TMPro;
using Console = FancyPantsConsole.Console;
@@ -17,6 +19,7 @@ namespace ConsoleImprovements.Client {
private static LinkedList _history = new LinkedList();
private static LinkedListNode? _command;
+ private static Trie _commandRegistry = new Trie();
public static bool Prepare(ILogicLogger logger) {
_logger = logger;
@@ -24,6 +27,21 @@ namespace ConsoleImprovements.Client {
// Get access to the rich text string inside the MessageData class
_commandInputFieldField = Fields.getPrivate(typeof(Console), "CommandInputField");
+ CommandConsole commandConsole = CommandConsole.Current;
+ // ICommandRegistryInternal
+ var registry = Fields.getPrivate(typeof(CommandConsole), "CommandRegistry").GetValue(commandConsole);
+ // CommandRegistry.CommandCollectionByName
+ var commandCollection = Properties.get(registry, "AllRegisteredCommands").GetValue(registry);
+ // IEnumerable
+ var commands = (IEnumerable) Methods.getPublic(commandCollection, "EnumerateAllCommands").Invoke(commandCollection, null)!;
+
+ foreach (var command in commands) {
+ var nameProperty = Properties.getPublic(command, "Name");
+ var hiddenProperty = Properties.getPublic(command, "Hidden");
+ if ((bool) hiddenProperty.GetValue(command)!) continue;
+ _commandRegistry.AddEntry((string) nameProperty.GetValue(command)!);
+ }
+
return true;
}
@@ -65,6 +83,27 @@ namespace ConsoleImprovements.Client {
}
}
+ if (RawInput.Tab.DownThisFrame()) {
+ TMP_InputField? commandInputField = _commandInputFieldField!.GetValue(__instance) as TMP_InputField;
+ if (commandInputField == null) {
+ _logger.Error("Cannot get CommandInputField value");
+ return true;
+ }
+
+ string current = commandInputField.text;
+ string? completed = _commandRegistry.LookupNext(current, out Trie.Node? node);
+ if (completed != null) {
+ if (completed == current) {
+ List commands = node?.CollectChildren(completed)!;
+ if (commands.Count > 0) {
+ _logger.Info($"Available commands: {string.Join(", ", commands)}");
+ }
+ } else {
+ UpdateCommandTextField(__instance, completed);
+ }
+ }
+ }
+
return true; // Resume original functionality
}
diff --git a/ConsoleImprovements/ConsoleImprovements/src/client/Trie.cs b/ConsoleImprovements/ConsoleImprovements/src/client/Trie.cs
new file mode 100644
index 0000000..be60748
--- /dev/null
+++ b/ConsoleImprovements/ConsoleImprovements/src/client/Trie.cs
@@ -0,0 +1,87 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace ConsoleImprovements.Client {
+
+ ///
+ /// A crude implementation of the trie data structure for fast lookups
+ ///
+ public class Trie {
+ private readonly Node _root = new Node() {
+ Children = new Dictionary()
+ };
+
+ ///
+ /// Add a new string entry to the structure
+ ///
+ public void AddEntry(string str) {
+ Node current = _root;
+ foreach (char ch in str.ToLower()) {
+ if (!current.Children.TryGetValue(ch, out Node? next)) {
+ next = new Node();
+ current.Children[ch] = next;
+ }
+
+ current = next;
+ }
+
+ current.End = true;
+ }
+
+ ///
+ /// Look up how the given string may continue
+ ///
+ /// The string to base the search on
+ /// outputs the reached node which is either an end node or has multiple children
+ /// Continuation of the prefix (including the prefix)
+ public string? LookupNext(string prefix, out Node? node) {
+ string lowercase = prefix.ToLower();
+ Node current = _root;
+ foreach (char ch in lowercase) {
+ if (!current.Children.TryGetValue(ch, out Node? next)) {
+ node = null;
+ return null;
+ }
+
+ current = next;
+ }
+
+ var commonBuilder = new StringBuilder(lowercase);
+ while (current.Children.Count == 1) {
+ if (current.End) {
+ break;
+ }
+
+ KeyValuePair single = current.Children.First();
+ commonBuilder.Append(single.Key);
+ current = single.Value;
+ }
+
+ node = current;
+ return commonBuilder.ToString();
+ }
+
+ public class Node {
+ public bool End;
+ public Dictionary Children = new Dictionary();
+
+ ///
+ /// Get all possible strings that can be made from the children of this node
+ ///
+ /// Pass in the previously obtained string path to this node
+ public List CollectChildren(string prefix) {
+ var collected = new List();
+ if (End) {
+ collected.Add(prefix.ToLower());
+ }
+
+ foreach ((char ch, Node node) in Children) {
+ collected.AddRange(node.CollectChildren(prefix + ch));
+ }
+
+ return collected;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 7be4be0..36dc6f4 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,9 @@
# Console Improvements Mod
-This mod does 2 things:
+This mod does 3 things:
1. It removes the `> ` prefix from copied commands
2. Adds a command history that can be cycled using up and down arrow keys
+3. Adds tab completion
## Dependencies