Implement command completion suggestions.

This commit is contained in:
BruceChen 2022-12-06 15:50:17 +08:00
parent 5d2589b10f
commit 84cf749344
115 changed files with 4684 additions and 2695 deletions

View file

@ -1,18 +1,24 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Brigadier.NET;
using Brigadier.NET.Builder;
using ImageMagick;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Mapping;
using MinecraftClient.Scripting;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
public class Map : ChatBot
{
public const string CommandName = "maps";
public static Configs Config = new();
public struct QueuedMap
@ -63,25 +69,89 @@ namespace MinecraftClient.ChatBots
private readonly string baseDirectory = @"Rendered_Maps";
private readonly Dictionary<int, McMap> cachedMaps = new();
internal readonly Dictionary<int, McMap> cachedMaps = new();
private readonly Queue<QueuedMap> discordQueue = new();
public override void Initialize()
public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{
if (!Directory.Exists(baseDirectory))
Directory.CreateDirectory(baseDirectory);
DeleteRenderedMaps();
RegisterChatBotCommand("maps", "bot.map.cmd.desc", "maps list|render <id> or maps l|r <id>", OnMapCommand);
dispatcher.Register(l => l.Literal("help")
.Then(l => l.Literal(CommandName)
.Executes(r => OnCommandHelp(r.Source, string.Empty))
)
);
dispatcher.Register(l => l.Literal(CommandName)
.Executes(r => OnCommandList(r.Source))
.Then(l => l.Literal("list")
.Executes(r => OnCommandList(r.Source)))
.Then(l => l.Literal("render")
.Then(l => l.Argument("MapID", MccArguments.MapBotMapId())
.Executes(r => OnCommandRender(r.Source, Arguments.GetInteger(r, "MapID")))))
.Then(l => l.Literal("_help")
.Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CommandName)))
);
}
public override void OnUnload()
public override void OnUnload(CommandDispatcher<CmdResult> dispatcher)
{
dispatcher.Unregister(CommandName);
dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName);
DeleteRenderedMaps();
}
private int OnCommandHelp(CmdResult r, string? cmd)
{
return r.SetAndReturn(cmd switch
{
#pragma warning disable format // @formatter:off
_ => Translations.error_usage + ": /maps <list/render <id>>"
+ '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false),
#pragma warning restore format // @formatter:on
});
}
private int OnCommandList(CmdResult r)
{
if (cachedMaps.Count == 0)
return r.SetAndReturn(CmdResult.Status.Fail, Translations.bot_map_no_maps);
LogToConsole(Translations.bot_map_received);
foreach (var (key, value) in new SortedDictionary<int, McMap>(cachedMaps))
LogToConsole(string.Format(Translations.bot_map_list_item, key, value.LastUpdated));
return r.SetAndReturn(CmdResult.Status.Done);
}
private int OnCommandRender(CmdResult r, int mapId)
{
if (!cachedMaps.ContainsKey(mapId))
return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.bot_map_cmd_not_found, mapId));
try
{
McMap map = cachedMaps[mapId];
if (Config.Save_To_File)
SaveToFile(map);
if (Config.Render_In_Console)
RenderInConsole(map);
return r.SetAndReturn(CmdResult.Status.Done);
}
catch (Exception e)
{
LogDebugToConsole(e.StackTrace!);
return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.bot_map_failed_to_render, mapId));
}
}
private void DeleteRenderedMaps()
{
if (Config.Delete_All_On_Unload)
@ -94,56 +164,6 @@ namespace MinecraftClient.ChatBots
}
}
public string OnMapCommand(string command, string[] args)
{
if (args.Length == 0 || (args.Length == 1 && (args[0].ToLower().Equals("list") || args[0].ToLower().Equals("l"))))
{
if (cachedMaps.Count == 0)
return Translations.bot_map_no_maps;
LogToConsole(Translations.bot_map_received);
foreach (var (key, value) in new SortedDictionary<int, McMap>(cachedMaps))
LogToConsole(string.Format(Translations.bot_map_list_item, key, value.LastUpdated));
return "";
}
if (args.Length > 1)
{
if (args[0].ToLower().Equals("render") || args[0].ToLower().Equals("r"))
{
if (args.Length < 2)
return "maps <list/render <id>> | maps <l/r <id>>";
if (int.TryParse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture, out int mapId))
{
if (!cachedMaps.ContainsKey(mapId))
return string.Format(Translations.bot_map_cmd_not_found, mapId);
try
{
McMap map = cachedMaps[mapId];
if (Config.Save_To_File)
SaveToFile(map);
if (Config.Render_In_Console)
RenderInConsole(map);
return "";
}
catch (Exception e)
{
LogDebugToConsole(e.StackTrace!);
return string.Format(Translations.bot_map_failed_to_render, mapId);
}
}
return Translations.bot_map_cmd_invalid_id;
}
}
return "";
}
public override void OnMapData(int mapid, byte scale, bool trackingPosition, bool locked, List<MapIcon> icons, byte columnsUpdated, byte rowsUpdated, byte mapCoulmnX, byte mapRowZ, byte[]? colors)
{
if (columnsUpdated == 0 && cachedMaps.ContainsKey(mapid))
@ -320,7 +340,7 @@ namespace MinecraftClient.ChatBots
}
}
private void RenderInConsole(McMap map)
private static void RenderInConsole(McMap map)
{
StringBuilder sb = new();
@ -406,7 +426,7 @@ namespace MinecraftClient.ChatBots
public DateTime LastUpdated { get; set; }
}
class MapColors
internal class MapColors
{
// When colors are updated in a new update, you can get them using the game code: net\minecraft\world\level\material\MaterialColor.java
public static Dictionary<byte, byte[]> Colors = new()