From f8aefaf129bf97e57b84176f3eb22123bceb7389 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Wed, 26 Oct 2022 08:54:54 +0800 Subject: [PATCH 1/8] init --- MinecraftClient/Command.cs | 23 +++ MinecraftClient/Commands/Animation.cs | 47 ++++- MinecraftClient/Commands/Bed.cs | 5 + MinecraftClient/Commands/BlockInfo.cs | 5 + MinecraftClient/Commands/Bots.cs | 5 + MinecraftClient/Commands/ChangeSlot.cs | 5 + MinecraftClient/Commands/Chunk.cs | 5 + MinecraftClient/Commands/CommandSource.cs | 13 ++ MinecraftClient/Commands/Connect.cs | 5 + MinecraftClient/Commands/Debug.cs | 5 + MinecraftClient/Commands/Dig.cs | 5 + MinecraftClient/Commands/DropItem.cs | 5 + MinecraftClient/Commands/Enchant.cs | 5 + MinecraftClient/Commands/Entitycmd.cs | 5 + MinecraftClient/Commands/ExecIf.cs | 5 + MinecraftClient/Commands/ExecMulti.cs | 5 + MinecraftClient/Commands/Exit.cs | 5 + MinecraftClient/Commands/Health.cs | 5 + MinecraftClient/Commands/Inventory.cs | 5 + MinecraftClient/Commands/List.cs | 5 + MinecraftClient/Commands/Log.cs | 5 + MinecraftClient/Commands/Look.cs | 5 + MinecraftClient/Commands/Move.cs | 5 + MinecraftClient/Commands/Reco.cs | 5 + MinecraftClient/Commands/Reload.cs | 5 + MinecraftClient/Commands/Respawn.cs | 5 + MinecraftClient/Commands/Script.cs | 5 + MinecraftClient/Commands/Send.cs | 5 + MinecraftClient/Commands/Set.cs | 5 + MinecraftClient/Commands/SetRnd.cs | 5 + MinecraftClient/Commands/Sneak.cs | 5 + MinecraftClient/Commands/Tps.cs | 5 + MinecraftClient/Commands/UseItem.cs | 5 + MinecraftClient/Commands/Useblock.cs | 5 + MinecraftClient/ConsoleIO.cs | 1 + MinecraftClient/McClient.cs | 166 +++++++++++------- MinecraftClient/MinecraftClient.csproj | 1 + .../Protocol/Handlers/Protocol18.cs | 7 + MinecraftClient/Scripting/ChatBot.cs | 6 + 39 files changed, 353 insertions(+), 66 deletions(-) create mode 100644 MinecraftClient/Commands/CommandSource.cs diff --git a/MinecraftClient/Command.cs b/MinecraftClient/Command.cs index 627542c6..467e0cf8 100644 --- a/MinecraftClient/Command.cs +++ b/MinecraftClient/Command.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; using System.Text; +using Brigadier.NET; +using Microsoft.Extensions.Logging; +using MinecraftClient.Commands; namespace MinecraftClient { @@ -22,6 +25,8 @@ namespace MinecraftClient /// public abstract string CmdDesc { get; } + public abstract void RegisterCommand(McClient handler, CommandDispatcher dispatcher); + /// /// Get the translated version of command description. /// @@ -32,6 +37,24 @@ namespace MinecraftClient return CmdUsage + s + Translations.TryGet(CmdDesc); } + public void LogUsage(Logger.ILogger logger) + { + logger.Info($"{Translations.Get("error.usage")}: {Settings.Config.Main.Advanced.InternalCmdChar.ToChar()}{CmdUsage}"); + } + + + public static int LogExecuteResult(Logger.ILogger logger, bool result) + { + logger.Info(Translations.Get(result ? "general.done" : "general.fail")); + return result ? 1 : 0; + } + + public static int LogExecuteResult(Logger.ILogger logger, int result) + { + logger.Info(Translations.Get(result > 0 ? "general.done" : "general.fail")); + return result; + } + /// /// Usage message, eg: 'name [args]' /// diff --git a/MinecraftClient/Commands/Animation.cs b/MinecraftClient/Commands/Animation.cs index cdfa8ad7..a7caec2c 100644 --- a/MinecraftClient/Commands/Animation.cs +++ b/MinecraftClient/Commands/Animation.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using Brigadier.NET; +using Brigadier.NET.Builder; namespace MinecraftClient.Commands { @@ -8,6 +11,48 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "animation "; } } public override string CmdDesc { get { return "cmd.animation.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + dispatcher.Register(l => + l.Literal("help").Then(l => + l.Literal(CmdName).Executes(c => { + LogUsage(handler.Log); + return 1; + }) + ) + ); + + dispatcher.Register(l => + l.Literal(CmdName).Then(l => + l.Literal("mainhand") + .Executes(c => { + return LogExecuteResult(handler.Log, handler.DoAnimation(0)); + }) + ) + ); + dispatcher.Register(l => + l.Literal(CmdName).Then(l => + l.Literal("0") + .Redirect(dispatcher.GetRoot().GetChild(CmdName).GetChild("mainhand")) + ) + ); + + dispatcher.Register(l => + l.Literal(CmdName).Then(l => + l.Literal("offhand") + .Executes(c => { + return LogExecuteResult(handler.Log, handler.DoAnimation(1)); + }) + ) + ); + dispatcher.Register(l => + l.Literal(CmdName).Then(l => + l.Literal("1") + .Redirect(dispatcher.GetRoot().GetChild(CmdName).GetChild("offhand")) + ) + ); + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/Bed.cs b/MinecraftClient/Commands/Bed.cs index ea2b4b1b..9a77b94a 100644 --- a/MinecraftClient/Commands/Bed.cs +++ b/MinecraftClient/Commands/Bed.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading.Tasks; +using Brigadier.NET; using MinecraftClient.Mapping; namespace MinecraftClient.Commands @@ -13,6 +14,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "bed leave|sleep |sleep "; } } public override string CmdDesc { get { return "cmd.bed.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { string[] args = GetArgs(command); diff --git a/MinecraftClient/Commands/BlockInfo.cs b/MinecraftClient/Commands/BlockInfo.cs index 5aa8ec75..51051c1d 100644 --- a/MinecraftClient/Commands/BlockInfo.cs +++ b/MinecraftClient/Commands/BlockInfo.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Text; +using Brigadier.NET; using MinecraftClient.Mapping; namespace MinecraftClient.Commands @@ -10,6 +11,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "blockinfo [-s]"; } } public override string CmdDesc { get { return "cmd.blockinfo.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (!handler.GetTerrainEnabled()) diff --git a/MinecraftClient/Commands/Bots.cs b/MinecraftClient/Commands/Bots.cs index 46864dd1..b8b23848 100644 --- a/MinecraftClient/Commands/Bots.cs +++ b/MinecraftClient/Commands/Bots.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -10,6 +11,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "bots [list|unload ]"; } } public override string CmdDesc { get { return "cmd.bots.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/ChangeSlot.cs b/MinecraftClient/Commands/ChangeSlot.cs index f278cac7..5280cb67 100644 --- a/MinecraftClient/Commands/ChangeSlot.cs +++ b/MinecraftClient/Commands/ChangeSlot.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -9,6 +10,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "changeslot <1-9>"; } } public override string CmdDesc { get { return "cmd.changeSlot.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (!handler.GetInventoryEnabled()) diff --git a/MinecraftClient/Commands/Chunk.cs b/MinecraftClient/Commands/Chunk.cs index 4007d4e2..c6116928 100644 --- a/MinecraftClient/Commands/Chunk.cs +++ b/MinecraftClient/Commands/Chunk.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Text; +using Brigadier.NET; using MinecraftClient.Mapping; namespace MinecraftClient.Commands @@ -12,6 +13,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "chunk status [chunkX chunkZ|locationX locationY locationZ]"; } } public override string CmdDesc { get { return "cmd.chunk.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/CommandSource.cs b/MinecraftClient/Commands/CommandSource.cs new file mode 100644 index 00000000..89f1f1ff --- /dev/null +++ b/MinecraftClient/Commands/CommandSource.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MinecraftClient.Commands +{ + public class CommandSource + { + public string UserName { get; set; } = string.Empty; + } +} diff --git a/MinecraftClient/Commands/Connect.cs b/MinecraftClient/Commands/Connect.cs index 12c94a3f..a58fba48 100644 --- a/MinecraftClient/Commands/Connect.cs +++ b/MinecraftClient/Commands/Connect.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "connect [account]"; } } public override string CmdDesc { get { return "cmd.connect.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient? handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/Debug.cs b/MinecraftClient/Commands/Debug.cs index c2bbda8a..91d925ff 100644 --- a/MinecraftClient/Commands/Debug.cs +++ b/MinecraftClient/Commands/Debug.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "debug [on|off]"; } } public override string CmdDesc { get { return "cmd.debug.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/Dig.cs b/MinecraftClient/Commands/Dig.cs index 59b9d79d..1fc408a5 100644 --- a/MinecraftClient/Commands/Dig.cs +++ b/MinecraftClient/Commands/Dig.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Brigadier.NET; using MinecraftClient.Mapping; namespace MinecraftClient.Commands @@ -10,6 +11,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "dig "; } } public override string CmdDesc { get { return "cmd.dig.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (!handler.GetTerrainEnabled()) diff --git a/MinecraftClient/Commands/DropItem.cs b/MinecraftClient/Commands/DropItem.cs index 54f93254..430ff675 100644 --- a/MinecraftClient/Commands/DropItem.cs +++ b/MinecraftClient/Commands/DropItem.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Brigadier.NET; using MinecraftClient.Inventory; namespace MinecraftClient.Commands @@ -13,6 +14,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "/dropitem "; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (!handler.GetInventoryEnabled()) diff --git a/MinecraftClient/Commands/Enchant.cs b/MinecraftClient/Commands/Enchant.cs index a75317e2..376c31c5 100644 --- a/MinecraftClient/Commands/Enchant.cs +++ b/MinecraftClient/Commands/Enchant.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Brigadier.NET; using MinecraftClient.Inventory; namespace MinecraftClient.Commands @@ -10,6 +11,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "enchant "; } } public override string CmdDesc { get { return "cmd.enchant.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (!handler.GetInventoryEnabled()) diff --git a/MinecraftClient/Commands/Entitycmd.cs b/MinecraftClient/Commands/Entitycmd.cs index 64bfa6c1..229b7fe7 100644 --- a/MinecraftClient/Commands/Entitycmd.cs +++ b/MinecraftClient/Commands/Entitycmd.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Text; +using Brigadier.NET; using MinecraftClient.Inventory; using MinecraftClient.Mapping; @@ -13,6 +14,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "entity "; } } public override string CmdDesc { get { return ""; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (handler.GetEntityHandlingEnabled()) diff --git a/MinecraftClient/Commands/ExecIf.cs b/MinecraftClient/Commands/ExecIf.cs index 06b8619f..b05acceb 100644 --- a/MinecraftClient/Commands/ExecIf.cs +++ b/MinecraftClient/Commands/ExecIf.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Brigadier.NET; using DynamicExpresso; namespace MinecraftClient.Commands @@ -11,6 +12,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "execif ---> "; } } public override string CmdDesc { get { return "cmd.execif.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/ExecMulti.cs b/MinecraftClient/Commands/ExecMulti.cs index a329da10..40804550 100644 --- a/MinecraftClient/Commands/ExecMulti.cs +++ b/MinecraftClient/Commands/ExecMulti.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -10,6 +11,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "execmulti -> -> -> ..."; } } public override string CmdDesc { get { return "cmd.execmulti.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/Exit.cs b/MinecraftClient/Commands/Exit.cs index 7bca6496..f189e604 100644 --- a/MinecraftClient/Commands/Exit.cs +++ b/MinecraftClient/Commands/Exit.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "exit"; } } public override string CmdDesc { get { return "cmd.exit.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient? handler, string command, Dictionary? localVars) { Program.Exit(); diff --git a/MinecraftClient/Commands/Health.cs b/MinecraftClient/Commands/Health.cs index 68af9b32..01db69f0 100644 --- a/MinecraftClient/Commands/Health.cs +++ b/MinecraftClient/Commands/Health.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "health"; } } public override string CmdDesc { get { return "cmd.health.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { return Translations.Get("cmd.health.response", handler.GetHealth(), handler.GetSaturation(), handler.GetLevel(), handler.GetTotalExperience()); diff --git a/MinecraftClient/Commands/Inventory.cs b/MinecraftClient/Commands/Inventory.cs index f5f1a6c2..6f8877eb 100644 --- a/MinecraftClient/Commands/Inventory.cs +++ b/MinecraftClient/Commands/Inventory.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; +using Brigadier.NET; using MinecraftClient.Inventory; namespace MinecraftClient.Commands @@ -13,6 +14,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return GetBasicUsage(); } } public override string CmdDesc { get { return "cmd.inventory.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (handler.GetInventoryEnabled()) diff --git a/MinecraftClient/Commands/List.cs b/MinecraftClient/Commands/List.cs index f261d670..e833e8a9 100644 --- a/MinecraftClient/Commands/List.cs +++ b/MinecraftClient/Commands/List.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -9,6 +10,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "list"; } } public override string CmdDesc { get { return "cmd.list.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { return Translations.Get("cmd.list.players", String.Join(", ", handler.GetOnlinePlayers())); diff --git a/MinecraftClient/Commands/Log.cs b/MinecraftClient/Commands/Log.cs index 412e401b..896e560a 100644 --- a/MinecraftClient/Commands/Log.cs +++ b/MinecraftClient/Commands/Log.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "log "; } } public override string CmdDesc { get { return "cmd.log.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/Look.cs b/MinecraftClient/Commands/Look.cs index 11065f62..0dcc7642 100644 --- a/MinecraftClient/Commands/Look.cs +++ b/MinecraftClient/Commands/Look.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using Brigadier.NET; using MinecraftClient.Mapping; namespace MinecraftClient.Commands @@ -11,6 +12,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "look "; } } public override string CmdDesc { get { return "cmd.look.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (handler.GetTerrainEnabled()) diff --git a/MinecraftClient/Commands/Move.cs b/MinecraftClient/Commands/Move.cs index bbebcded..026dac82 100644 --- a/MinecraftClient/Commands/Move.cs +++ b/MinecraftClient/Commands/Move.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Brigadier.NET; using MinecraftClient.Mapping; namespace MinecraftClient.Commands @@ -11,6 +12,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "move [-f]"; } } public override string CmdDesc { get { return "walk or start walking. \"-f\": force unsafe movements like falling or touching fire"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { List args = GetArgs(command.ToLower()).ToList(); diff --git a/MinecraftClient/Commands/Reco.cs b/MinecraftClient/Commands/Reco.cs index 5b5b0e0f..206280e3 100644 --- a/MinecraftClient/Commands/Reco.cs +++ b/MinecraftClient/Commands/Reco.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "reco [account]"; } } public override string CmdDesc { get { return "cmd.reco.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient? handler, string command, Dictionary? localVars) { string[] args = GetArgs(command); diff --git a/MinecraftClient/Commands/Reload.cs b/MinecraftClient/Commands/Reload.cs index f4063db7..52bd1ab2 100644 --- a/MinecraftClient/Commands/Reload.cs +++ b/MinecraftClient/Commands/Reload.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "reload"; } } public override string CmdDesc { get { return "cmd.reload.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { handler.Log.Info(Translations.TryGet("cmd.reload.started")); diff --git a/MinecraftClient/Commands/Respawn.cs b/MinecraftClient/Commands/Respawn.cs index 3ff718fd..fd39bc0a 100644 --- a/MinecraftClient/Commands/Respawn.cs +++ b/MinecraftClient/Commands/Respawn.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "respawn"; } } public override string CmdDesc { get { return "cmd.respawn.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { handler.SendRespawnPacket(); diff --git a/MinecraftClient/Commands/Script.cs b/MinecraftClient/Commands/Script.cs index e7e233c5..d345b2e2 100644 --- a/MinecraftClient/Commands/Script.cs +++ b/MinecraftClient/Commands/Script.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "script "; } } public override string CmdDesc { get { return "cmd.script.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/Send.cs b/MinecraftClient/Commands/Send.cs index 55977740..92ef28d4 100644 --- a/MinecraftClient/Commands/Send.cs +++ b/MinecraftClient/Commands/Send.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "send "; } } public override string CmdDesc { get { return "cmd.send.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/Set.cs b/MinecraftClient/Commands/Set.cs index 9f8cfe5d..46f1d716 100644 --- a/MinecraftClient/Commands/Set.cs +++ b/MinecraftClient/Commands/Set.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "set varname=value"; } } public override string CmdDesc { get { return "cmd.set.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/SetRnd.cs b/MinecraftClient/Commands/SetRnd.cs index 6e0d00b2..f489bcca 100644 --- a/MinecraftClient/Commands/SetRnd.cs +++ b/MinecraftClient/Commands/SetRnd.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -10,6 +11,10 @@ namespace MinecraftClient.Commands public override string CmdDesc { get { return "cmd.setrnd.desc"; } } private static readonly Random rand = new(); + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (HasArg(command)) diff --git a/MinecraftClient/Commands/Sneak.cs b/MinecraftClient/Commands/Sneak.cs index 1c8dbf17..2f520b48 100644 --- a/MinecraftClient/Commands/Sneak.cs +++ b/MinecraftClient/Commands/Sneak.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -9,6 +10,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "Sneak"; } } public override string CmdDesc { get { return "cmd.sneak.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (sneaking) diff --git a/MinecraftClient/Commands/Tps.cs b/MinecraftClient/Commands/Tps.cs index 9aaafc5c..cd0f51c1 100644 --- a/MinecraftClient/Commands/Tps.cs +++ b/MinecraftClient/Commands/Tps.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -9,6 +10,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "tps"; } } public override string CmdDesc { get { return "cmd.tps.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { var tps = Math.Round(handler.GetServerTPS(), 2); diff --git a/MinecraftClient/Commands/UseItem.cs b/MinecraftClient/Commands/UseItem.cs index 497633d2..be7eb2b2 100644 --- a/MinecraftClient/Commands/UseItem.cs +++ b/MinecraftClient/Commands/UseItem.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; namespace MinecraftClient.Commands { @@ -8,6 +9,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "useitem"; } } public override string CmdDesc { get { return "cmd.useitem.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (handler.GetInventoryEnabled()) diff --git a/MinecraftClient/Commands/Useblock.cs b/MinecraftClient/Commands/Useblock.cs index 5d8bf32e..3669794a 100644 --- a/MinecraftClient/Commands/Useblock.cs +++ b/MinecraftClient/Commands/Useblock.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Brigadier.NET; using MinecraftClient.Mapping; namespace MinecraftClient.Commands @@ -9,6 +10,10 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "useblock "; } } public override string CmdDesc { get { return "cmd.useblock.desc"; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { if (!handler.GetTerrainEnabled()) diff --git a/MinecraftClient/ConsoleIO.cs b/MinecraftClient/ConsoleIO.cs index 13b55989..022ccaf4 100644 --- a/MinecraftClient/ConsoleIO.cs +++ b/MinecraftClient/ConsoleIO.cs @@ -183,6 +183,7 @@ namespace MinecraftClient return; var buffer = ConsoleInteractive.ConsoleReader.GetBufferContent(); + ConsoleIO.WriteLine("AutoComplete " + buffer); autocomplete_engine.AutoComplete(buffer.Text[..buffer.CursorPosition]); } } diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index 16bb2e9d..e60919c7 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -2,9 +2,13 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; +using System.Security.Cryptography.Pkcs; using System.Text; using System.Threading; +using Brigadier.NET; +using Brigadier.NET.Exceptions; using MinecraftClient.ChatBots; +using MinecraftClient.Commands; using MinecraftClient.Inventory; using MinecraftClient.Logger; using MinecraftClient.Mapping; @@ -25,8 +29,10 @@ namespace MinecraftClient { public static int ReconnectionAttemptsLeft = 0; - private static readonly List cmd_names = new(); - private static readonly Dictionary cmds = new(); + public static readonly CommandSource cmd_source = new(); + public static readonly CommandDispatcher dispatcher = new(); + //private static readonly List cmd_names = new(); + //private static readonly Dictionary cmds = new(); private readonly Dictionary onlinePlayers = new(); private static bool commandsLoaded = false; @@ -584,17 +590,18 @@ namespace MinecraftClient /// True if successfully registered public bool RegisterCommand(string cmdName, string cmdDesc, string cmdUsage, ChatBot.CommandRunner callback) { - if (cmds.ContainsKey(cmdName.ToLower())) - { - return false; - } - else - { - Command cmd = new ChatBot.ChatBotCommand(cmdName, cmdDesc, cmdUsage, callback); - cmds.Add(cmdName.ToLower(), cmd); - cmd_names.Add(cmdName.ToLower()); - return true; - } + // if (cmds.ContainsKey(cmdName.ToLower())) + // { + // return false; + // } + // else + // { + // Command cmd = new ChatBot.ChatBotCommand(cmdName, cmdDesc, cmdUsage, callback); + // cmds.Add(cmdName.ToLower(), cmd); + // cmd_names.Add(cmdName.ToLower()); + // return true; + // } + return true; } /// @@ -608,13 +615,14 @@ namespace MinecraftClient /// public bool UnregisterCommand(string cmdName) { - if (cmds.ContainsKey(cmdName.ToLower())) - { - cmds.Remove(cmdName.ToLower()); - cmd_names.Remove(cmdName.ToLower()); - return true; - } - else return false; + // if (cmds.ContainsKey(cmdName.ToLower())) + // { + // cmds.Remove(cmdName.ToLower()); + // cmd_names.Remove(cmdName.ToLower()); + // return true; + // } + // else return false; + return true; } /// @@ -627,52 +635,79 @@ namespace MinecraftClient public bool PerformInternalCommand(string command, ref string? response_msg, Dictionary? localVars = null) { /* Process the provided command */ - - string command_name = command.Split(' ')[0].ToLower(); - if (command_name == "help") + ParseResults parse; + try { - if (Command.HasArg(command)) - { - string help_cmdname = Command.GetArgs(command)[0].ToLower(); - if (help_cmdname == "help") - { - response_msg = Translations.Get("icmd.help"); - } - else if (cmds.ContainsKey(help_cmdname)) - { - response_msg = cmds[help_cmdname].GetCmdDescTranslated(); - } - else response_msg = Translations.Get("icmd.unknown", command_name); - } - else response_msg = Translations.Get("icmd.list", String.Join(", ", cmd_names.ToArray()), Config.Main.Advanced.InternalCmdChar.ToChar()); + parse = dispatcher.Parse(command, cmd_source); } - else if (cmds.ContainsKey(command_name)) + catch (Exception e) { - response_msg = cmds[command_name].Run(this, command, localVars); - - foreach (ChatBot bot in bots.ToArray()) - { - try - { - bot.OnInternalCommand(command_name, string.Join(" ", Command.GetArgs(command)), response_msg); - } - catch (Exception e) - { - if (e is not ThreadAbortException) - { - Log.Warn(Translations.Get("icmd.error", bot.ToString() ?? string.Empty, e.ToString())); - } - else throw; //ThreadAbortException should not be caught - } - } - } - else - { - response_msg = Translations.Get("icmd.unknown", command_name); - return false; + Log.Error(e.GetFullMessage()); + return true; } - return true; + try + { + int res = dispatcher.Execute(parse); + Log.Info("res = " + res); + return true; + } + catch (CommandSyntaxException e) + { + Log.Warn(e.GetFullMessage()); + return true; + } + catch (Exception e) + { + Log.Error(e.GetFullMessage()); + return true; + } + + //string command_name = command.Split(' ')[0].ToLower(); + //if (command_name == "help") + //{ + // if (Command.HasArg(command)) + // { + // string help_cmdname = Command.GetArgs(command)[0].ToLower(); + // if (help_cmdname == "help") + // { + // response_msg = Translations.Get("icmd.help"); + // } + // else if (cmds.ContainsKey(help_cmdname)) + // { + // response_msg = cmds[help_cmdname].GetCmdDescTranslated(); + // } + // else response_msg = Translations.Get("icmd.unknown", command_name); + // } + // else response_msg = Translations.Get("icmd.list", String.Join(", ", cmd_names.ToArray()), Config.Main.Advanced.InternalCmdChar.ToChar()); + //} + //else if (cmds.ContainsKey(command_name)) + //{ + // response_msg = cmds[command_name].Run(this, command, localVars); + + // foreach (ChatBot bot in bots.ToArray()) + // { + // try + // { + // bot.OnInternalCommand(command_name, string.Join(" ", Command.GetArgs(command)), response_msg); + // } + // catch (Exception e) + // { + // if (e is not ThreadAbortException) + // { + // Log.Warn(Translations.Get("icmd.error", bot.ToString() ?? string.Empty, e.ToString())); + // } + // else throw; //ThreadAbortException should not be caught + // } + // } + //} + //else + //{ + // response_msg = Translations.Get("icmd.unknown", command_name); + // return false; + //} + + //return true; } public void LoadCommands() @@ -689,10 +724,11 @@ namespace MinecraftClient try { Command cmd = (Command)Activator.CreateInstance(type)!; - cmds[Settings.ToLowerIfNeed(cmd.CmdName)] = cmd; - cmd_names.Add(Settings.ToLowerIfNeed(cmd.CmdName)); - foreach (string alias in cmd.GetCMDAliases()) - cmds[Settings.ToLowerIfNeed(alias)] = cmd; + cmd.RegisterCommand(this, dispatcher); + // cmds[Settings.ToLowerIfNeed(cmd.CmdName)] = cmd; + // cmd_names.Add(Settings.ToLowerIfNeed(cmd.CmdName)); + // foreach (string alias in cmd.GetCMDAliases()) + // cmds[Settings.ToLowerIfNeed(alias)] = cmd; } catch (Exception e) { diff --git a/MinecraftClient/MinecraftClient.csproj b/MinecraftClient/MinecraftClient.csproj index 013e6801..5f0061cf 100644 --- a/MinecraftClient/MinecraftClient.csproj +++ b/MinecraftClient/MinecraftClient.csproj @@ -33,6 +33,7 @@ + diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 70670e4b..4856cb6f 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -2082,6 +2082,13 @@ namespace MinecraftClient.Protocol.Handlers /// Completed text IEnumerable IAutoComplete.AutoComplete(string BehindCursor) { + var sug = McClient.dispatcher.GetCompletionSuggestions(McClient.dispatcher.Parse(BehindCursor[1..], McClient.cmd_source)); + sug.Wait(); + foreach (var hint in sug.Result.List) + { + log.Info(hint); + } + //log.Info(McClient.dispatcher.GetSmartUsage(McClient.dispatcher.Parse(BehindCursor, McClient.cmd_source), McClient.cmd_source)); if (String.IsNullOrEmpty(BehindCursor)) return Array.Empty(); diff --git a/MinecraftClient/Scripting/ChatBot.cs b/MinecraftClient/Scripting/ChatBot.cs index 1c8272b1..d8d6a9fb 100644 --- a/MinecraftClient/Scripting/ChatBot.cs +++ b/MinecraftClient/Scripting/ChatBot.cs @@ -4,6 +4,8 @@ using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; +using Brigadier.NET; +using MinecraftClient.Commands; using MinecraftClient.Inventory; using MinecraftClient.Mapping; using static MinecraftClient.Settings; @@ -1676,6 +1678,10 @@ namespace MinecraftClient public override string CmdUsage { get { return _cmdUsage; } } public override string CmdDesc { get { return _cmdDesc; } } + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + } + public override string Run(McClient handler, string command, Dictionary? localVars) { return Runner(command, GetArgs(command)); From 84cf749344c8958dbc1a1e168835e99db5b8f13c Mon Sep 17 00:00:00 2001 From: BruceChen Date: Tue, 6 Dec 2022 15:50:17 +0800 Subject: [PATCH 2/8] Implement command completion suggestions. --- MinecraftClient/ChatBots/Alerts.cs | 1 + MinecraftClient/ChatBots/AntiAFK.cs | 5 +- MinecraftClient/ChatBots/AutoAttack.cs | 5 +- MinecraftClient/ChatBots/AutoCraft.cs | 151 +++-- MinecraftClient/ChatBots/AutoDig.cs | 112 ++-- MinecraftClient/ChatBots/AutoDrop.cs | 222 +++--- MinecraftClient/ChatBots/AutoEat.cs | 1 + MinecraftClient/ChatBots/AutoFishing.cs | 192 +++--- MinecraftClient/ChatBots/AutoRelog.cs | 12 +- MinecraftClient/ChatBots/AutoRespond.cs | 12 +- MinecraftClient/ChatBots/ChatLog.cs | 4 +- MinecraftClient/ChatBots/DiscordBridge.cs | 115 ++-- MinecraftClient/ChatBots/Farmer.cs | 308 +++++---- MinecraftClient/ChatBots/FollowPlayer.cs | 114 ++-- MinecraftClient/ChatBots/HangmanGame.cs | 1 + MinecraftClient/ChatBots/Mailer.cs | 179 +++-- MinecraftClient/ChatBots/Map.cs | 134 ++-- MinecraftClient/ChatBots/PlayerListLogger.cs | 1 + MinecraftClient/ChatBots/RemoteControl.cs | 14 +- MinecraftClient/ChatBots/ReplayCapture.cs | 109 ++- MinecraftClient/ChatBots/Script.cs | 5 +- MinecraftClient/ChatBots/ScriptScheduler.cs | 1 + MinecraftClient/ChatBots/TelegramBridge.cs | 114 ++-- MinecraftClient/ChatBots/TestBot.cs | 4 +- MinecraftClient/Command.cs | 44 +- .../ArgumentType/AccountNickArgumentType.cs | 25 + .../AutoCraftRecipeNameArgumentType.cs | 25 + .../ArgumentType/BotNameArgumentType.cs | 29 + .../ArgumentType/EntityTypeArgumentType.cs | 31 + .../FarmerCropTypeArgumentType.cs | 31 + .../InventoryActionArgumentType.cs | 41 ++ .../ArgumentType/InventoryIdArgumentType.cs | 34 + .../ArgumentType/ItemTypeArgumentType.cs | 31 + .../ArgumentType/LocationArgumentType.cs | 99 +++ .../ArgumentType/MapBotMapIdArgumentType.cs | 39 ++ .../ArgumentType/PlayerNameArgumentType.cs | 36 + .../ArgumentType/ServerNickArgumentType.cs | 25 + .../ArgumentType/TupleArgumentType.cs | 18 + MinecraftClient/CommandHandler/CmdResult.cs | 96 +++ .../CommandHandler/MccArguments.cs | 104 +++ .../Patch/CommandDispatcherExtensions.cs | 36 + .../Patch/CommandNodeExtensions.cs | 28 + MinecraftClient/Commands/Animation.cs | 95 +-- MinecraftClient/Commands/Bed.cs | 276 ++++---- MinecraftClient/Commands/BlockInfo.cs | 72 +- MinecraftClient/Commands/Bots.cs | 125 ++-- MinecraftClient/Commands/ChangeSlot.cs | 63 +- MinecraftClient/Commands/Chunk.cs | 482 ++++++------- MinecraftClient/Commands/CommandSource.cs | 13 - MinecraftClient/Commands/Connect.cs | 76 ++- MinecraftClient/Commands/Debug.cs | 47 +- MinecraftClient/Commands/Dig.cs | 95 +-- MinecraftClient/Commands/DropItem.cs | 81 ++- MinecraftClient/Commands/Enchant.cs | 149 +++-- MinecraftClient/Commands/Entitycmd.cs | 413 ++++++++---- MinecraftClient/Commands/ExecIf.cs | 131 ++-- MinecraftClient/Commands/ExecMulti.cs | 59 +- MinecraftClient/Commands/Exit.cs | 50 +- MinecraftClient/Commands/Health.cs | 30 +- MinecraftClient/Commands/Help.cs | 33 + MinecraftClient/Commands/Inventory.cs | 632 ++++++++++-------- MinecraftClient/Commands/List.cs | 30 +- MinecraftClient/Commands/Log.cs | 36 +- MinecraftClient/Commands/Look.cs | 153 +++-- MinecraftClient/Commands/Move.cs | 255 ++++--- MinecraftClient/Commands/Reco.cs | 50 +- MinecraftClient/Commands/Reload.cs | 30 +- MinecraftClient/Commands/Respawn.cs | 32 +- MinecraftClient/Commands/Script.cs | 34 +- MinecraftClient/Commands/Send.cs | 35 +- MinecraftClient/Commands/Set.cs | 50 +- MinecraftClient/Commands/SetRnd.cs | 98 ++- MinecraftClient/Commands/Sneak.cs | 44 +- MinecraftClient/Commands/Tps.cs | 32 +- MinecraftClient/Commands/UseItem.cs | 40 +- MinecraftClient/Commands/Useblock.cs | 53 +- MinecraftClient/ConsoleIO.cs | 158 ++++- .../Inventory/EnchantmentMapping.cs | 3 +- MinecraftClient/Inventory/Item.cs | 13 +- MinecraftClient/Inventory/ItemMovingHelper.cs | 1 + MinecraftClient/Inventory/VillagerInfo.cs | 2 +- MinecraftClient/Json.cs | 2 +- MinecraftClient/Logger/FileLogLogger.cs | 1 + MinecraftClient/Mapping/Block.cs | 3 +- MinecraftClient/Mapping/Dimension.cs | 6 +- MinecraftClient/Mapping/Entity.cs | 3 +- MinecraftClient/Mapping/Location.cs | 35 + MinecraftClient/Mapping/RaycastHelper.cs | 4 +- MinecraftClient/Mapping/World.cs | 4 +- MinecraftClient/McClient.cs | 220 +++--- MinecraftClient/MinecraftClient.csproj | 13 +- MinecraftClient/Program.cs | 20 +- .../Handlers/Packet/s2c/DeclareCommands.cs | 19 +- .../Protocol/Handlers/Protocol16.cs | 32 +- .../Protocol/Handlers/Protocol18.cs | 50 +- .../Protocol/Handlers/Protocol18Forge.cs | 2 + MinecraftClient/Protocol/IMinecraftCom.cs | 2 +- .../Protocol/IMinecraftComHandler.cs | 8 + .../Protocol/Message/ChatParser.cs | 17 +- MinecraftClient/Protocol/MojangAPI.cs | 2 +- MinecraftClient/Protocol/PlayerInfo.cs | 2 +- .../Protocol/ProfileKey/KeyUtils.cs | 18 +- .../Protocol/ProfileKey/KeysCache.cs | 14 +- .../Protocol/ProfileKey/PlayerKeyPair.cs | 8 +- .../Protocol/ProfileKey/PrivateKey.cs | 2 +- .../Protocol/ProfileKey/PublicKey.cs | 2 +- .../Protocol/Session/SessionToken.cs | 1 + .../Translations/Translations.Designer.cs | 17 +- .../Resources/Translations/Translations.resx | 17 +- MinecraftClient/Scripting/AssemblyResolver.cs | 40 +- MinecraftClient/Scripting/CSharpRunner.cs | 30 +- MinecraftClient/Scripting/ChatBot.cs | 105 ++- .../DynamicRun/Builder/CompileRunner.cs | 3 +- .../Scripting/DynamicRun/Builder/Compiler.cs | 16 +- .../SimpleUnloadableAssemblyLoadContext.cs | 2 +- 115 files changed, 4684 insertions(+), 2695 deletions(-) create mode 100644 MinecraftClient/CommandHandler/ArgumentType/AccountNickArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/AutoCraftRecipeNameArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/BotNameArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/EntityTypeArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/FarmerCropTypeArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/InventoryActionArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/ItemTypeArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/LocationArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/MapBotMapIdArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/PlayerNameArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/ServerNickArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/TupleArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/CmdResult.cs create mode 100644 MinecraftClient/CommandHandler/MccArguments.cs create mode 100644 MinecraftClient/CommandHandler/Patch/CommandDispatcherExtensions.cs create mode 100644 MinecraftClient/CommandHandler/Patch/CommandNodeExtensions.cs delete mode 100644 MinecraftClient/Commands/CommandSource.cs create mode 100644 MinecraftClient/Commands/Help.cs diff --git a/MinecraftClient/ChatBots/Alerts.cs b/MinecraftClient/ChatBots/Alerts.cs index fabdc3b4..e503d52f 100644 --- a/MinecraftClient/ChatBots/Alerts.cs +++ b/MinecraftClient/ChatBots/Alerts.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots diff --git a/MinecraftClient/ChatBots/AntiAFK.cs b/MinecraftClient/ChatBots/AntiAFK.cs index aac824e4..bbf73637 100644 --- a/MinecraftClient/ChatBots/AntiAFK.cs +++ b/MinecraftClient/ChatBots/AntiAFK.cs @@ -1,5 +1,8 @@ using System; +using Brigadier.NET; +using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots @@ -90,7 +93,7 @@ namespace MinecraftClient.ChatBots count = 0; } - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { if (Config.Use_Terrain_Handling) { diff --git a/MinecraftClient/ChatBots/AutoAttack.cs b/MinecraftClient/ChatBots/AutoAttack.cs index e6fd19af..f7bed4ed 100644 --- a/MinecraftClient/ChatBots/AutoAttack.cs +++ b/MinecraftClient/ChatBots/AutoAttack.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using Brigadier.NET; +using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots @@ -109,7 +112,7 @@ namespace MinecraftClient.ChatBots attackPassive = Config.Attack_Passive; } - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { if (!GetEntityHandlingEnabled()) { diff --git a/MinecraftClient/ChatBots/AutoCraft.cs b/MinecraftClient/ChatBots/AutoCraft.cs index 13478736..9c700160 100644 --- a/MinecraftClient/ChatBots/AutoCraft.cs +++ b/MinecraftClient/ChatBots/AutoCraft.cs @@ -2,8 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; using MinecraftClient.Inventory; using MinecraftClient.Mapping; +using MinecraftClient.Scripting; using Tomlet.Attributes; using static MinecraftClient.ChatBots.AutoCraft.Configs; @@ -11,6 +16,8 @@ namespace MinecraftClient.ChatBots { public class AutoCraft : ChatBot { + public const string CommandName = "autocraft"; + public static Configs Config = new(); [TomlDoNotInlineObject] @@ -40,7 +47,7 @@ namespace MinecraftClient.ChatBots Name: "Recipe-Name-2", Type: CraftTypeConfig.table, Result: ItemType.StoneBricks, - Slots: new ItemType[9] { + Slots: new ItemType[9] { ItemType.Stone, ItemType.Stone, ItemType.Null, ItemType.Stone, ItemType.Stone, ItemType.Null, ItemType.Null, ItemType.Null, ItemType.Null, @@ -117,7 +124,7 @@ namespace MinecraftClient.ChatBots public ItemType Result = ItemType.Air; - public ItemType[] Slots = new ItemType[9] { + public ItemType[] Slots = new ItemType[9] { ItemType.Null, ItemType.Null, ItemType.Null, ItemType.Null, ItemType.Null, ItemType.Null, ItemType.Null, ItemType.Null, ItemType.Null, @@ -279,7 +286,7 @@ namespace MinecraftClient.ChatBots } } - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { if (!GetInventoryEnabled()) { @@ -288,81 +295,93 @@ namespace MinecraftClient.ChatBots UnloadBot(); return; } - RegisterChatBotCommand("autocraft", Translations.bot_autoCraft_cmd, GetHelp(), CommandHandler); - RegisterChatBotCommand("ac", Translations.bot_autoCraft_alias, GetHelp(), CommandHandler); + + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CommandName) + .Executes(r => OnCommandHelp(r.Source, string.Empty)) + .Then(l => l.Literal("list") + .Executes(r => OnCommandHelp(r.Source, "list"))) + .Then(l => l.Literal("start") + .Executes(r => OnCommandHelp(r.Source, "start"))) + .Then(l => l.Literal("stop") + .Executes(r => OnCommandHelp(r.Source, "stop"))) + .Then(l => l.Literal("help") + .Executes(r => OnCommandHelp(r.Source, "help"))) + ) + ); + + dispatcher.Register(l => l.Literal(CommandName) + .Then(l => l.Literal("list") + .Executes(r => OnCommandList(r.Source))) + .Then(l => l.Literal("start") + .Then(l => l.Argument("RecipeName", MccArguments.AutoCraftRecipeName()) + .Executes(r => OnCommandStart(r.Source, Arguments.GetString(r, "RecipeName"))))) + .Then(l => l.Literal("stop") + .Executes(r => OnCommandStop(r.Source))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + ); } - public string CommandHandler(string cmd, string[] args) + public override void OnUnload(CommandDispatcher dispatcher) { - if (args.Length > 0) - { - switch (args[0]) - { - case "list": - StringBuilder nameList = new(); - foreach (RecipeConfig recipe in Config.Recipes) - nameList.Append(recipe.Name).Append(", "); - return string.Format(Translations.bot_autoCraft_cmd_list, Config.Recipes.Length, nameList.ToString()); - case "start": - if (args.Length >= 2) - { - string name = args[1]; - - bool hasRecipe = false; - RecipeConfig? recipe = null; - foreach (RecipeConfig recipeConfig in Config.Recipes) - { - if (recipeConfig.Name == name) - { - hasRecipe = true; - recipe = recipeConfig; - break; - } - } - - if (hasRecipe) - { - ResetVar(); - PrepareCrafting(recipe!); - return ""; - } - else - return Translations.bot_autoCraft_recipe_not_exist; - } - else - return Translations.bot_autoCraft_no_recipe_name; - case "stop": - StopCrafting(); - return Translations.bot_autoCraft_stop; - case "help": - return GetCommandHelp(args.Length >= 2 ? args[1] : ""); - default: - return GetHelp(); - } - } - else return GetHelp(); + dispatcher.Unregister(CommandName); + dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } - private static string GetHelp() + private int OnCommandHelp(CmdResult r, string? cmd) { - return string.Format(Translations.bot_autoCraft_available_cmd, "load, list, reload, resetcfg, start, stop, help"); - } - - private string GetCommandHelp(string cmd) - { - return cmd.ToLower() switch + return r.SetAndReturn(cmd switch { #pragma warning disable format // @formatter:off - "load" => Translations.bot_autoCraft_help_load, "list" => Translations.bot_autoCraft_help_list, - "reload" => Translations.bot_autoCraft_help_reload, - "resetcfg" => Translations.bot_autoCraft_help_resetcfg, "start" => Translations.bot_autoCraft_help_start, "stop" => Translations.bot_autoCraft_help_stop, "help" => Translations.bot_autoCraft_help_help, - _ => GetHelp(), + _ => string.Format(Translations.bot_autoCraft_available_cmd, "load, list, reload, resetcfg, start, stop, help") + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on - }; + }); + } + + private int OnCommandList(CmdResult r) + { + StringBuilder nameList = new(); + foreach (RecipeConfig recipe in Config.Recipes) + nameList.Append(recipe.Name).Append(", "); + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.bot_autoCraft_cmd_list, Config.Recipes.Length, nameList.ToString())); + } + + private int OnCommandStart(CmdResult r, string name) + { + bool hasRecipe = false; + RecipeConfig? recipe = null; + foreach (RecipeConfig recipeConfig in Config.Recipes) + { + if (recipeConfig.Name == name) + { + hasRecipe = true; + recipe = recipeConfig; + break; + } + } + + if (hasRecipe) + { + ResetVar(); + PrepareCrafting(recipe!); + return r.SetAndReturn(CmdResult.Status.Done); + } + else + { + return r.SetAndReturn(CmdResult.Status.Fail, Translations.bot_autoCraft_recipe_not_exist); + } + } + + private int OnCommandStop(CmdResult r) + { + StopCrafting(); + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_autoCraft_stop); } #region Core part of auto-crafting @@ -442,7 +461,7 @@ namespace MinecraftClient.ChatBots ItemType ResultItem = recipeConfig.Result; - ContainerType CraftingAreaType = + ContainerType CraftingAreaType = (recipeConfig.Type == CraftTypeConfig.player) ? ContainerType.PlayerInventory : ContainerType.Crafting; PrepareCrafting(new Recipe(materials, ResultItem, CraftingAreaType)); diff --git a/MinecraftClient/ChatBots/AutoDig.cs b/MinecraftClient/ChatBots/AutoDig.cs index 21f93803..740a9053 100644 --- a/MinecraftClient/ChatBots/AutoDig.cs +++ b/MinecraftClient/ChatBots/AutoDig.cs @@ -1,13 +1,20 @@ using System; using System.Collections.Generic; using System.Linq; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; using MinecraftClient.Mapping; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots { public class AutoDig : ChatBot { + public const string CommandName = "autodig"; + public static Configs Config = new(); [TomlDoNotInlineObject] @@ -60,7 +67,7 @@ namespace MinecraftClient.ChatBots { if (Auto_Start_Delay >= 0) Auto_Start_Delay = Math.Max(0.1, Auto_Start_Delay); - + if (Dig_Timeout >= 0) Dig_Timeout = Math.Max(0.1, Dig_Timeout); @@ -103,7 +110,7 @@ namespace MinecraftClient.ChatBots Stopping, } - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { if (!GetTerrainEnabled()) { @@ -117,32 +124,67 @@ namespace MinecraftClient.ChatBots if (!inventoryEnabled && Config.Auto_Tool_Switch) LogToConsole(Translations.bot_autodig_no_inv_handle); - RegisterChatBotCommand("digbot", Translations.bot_autodig_cmd, GetHelp(), CommandHandler); + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CommandName) + .Executes(r => OnCommandHelp(r.Source, string.Empty)) + .Then(l => l.Literal("start") + .Executes(r => OnCommandHelp(r.Source, "start"))) + .Then(l => l.Literal("stop") + .Executes(r => OnCommandHelp(r.Source, "stop"))) + .Then(l => l.Literal("help") + .Executes(r => OnCommandHelp(r.Source, "help"))) + ) + ); + + var cmd = dispatcher.Register(l => l.Literal(CommandName) + .Then(l => l.Literal("start") + .Executes(r => OnCommandStart(r.Source))) + .Then(l => l.Literal("stop") + .Executes(r => OnCommandStop(r.Source))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + ); + + dispatcher.Register(l => l.Literal("digbot") + .Redirect(cmd) + ); } - public string CommandHandler(string cmd, string[] args) + public override void OnUnload(CommandDispatcher dispatcher) { - if (args.Length > 0) + dispatcher.Unregister("digbot"); + dispatcher.Unregister(CommandName); + dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + } + + private int OnCommandHelp(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch { - switch (args[0]) - { - case "start": - lock (stateLock) - { - counter = 0; - state = State.WaitingStart; - } - return Translations.bot_autodig_start; - case "stop": - StopDigging(); - return Translations.bot_autodig_stop; - case "help": - return GetCommandHelp(args.Length >= 2 ? args[1] : ""); - default: - return GetHelp(); - } +#pragma warning disable format // @formatter:off + "start" => Translations.bot_autodig_help_start, + "stop" => Translations.bot_autodig_help_stop, + "help" => Translations.bot_autodig_help_help, + _ => string.Format(Translations.bot_autodig_available_cmd, "start, stop, help") + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), +#pragma warning restore format // @formatter:on + }); + } + + private int OnCommandStart(CmdResult r) + { + lock (stateLock) + { + counter = 0; + state = State.WaitingStart; } - else return GetHelp(); + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_autodig_start); + } + + private int OnCommandStop(CmdResult r) + { + StopDigging(); + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_autodig_stop); } private void StartDigging() @@ -240,7 +282,7 @@ namespace MinecraftClient.ChatBots else if ((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) || (Config.List_Type == Configs.ListType.blacklist && !Config.Blocks.Contains(block.Type))) { - if (Config.Mode == Configs.ModeType.lookat || + if (Config.Mode == Configs.ModeType.lookat || (Config.Mode == Configs.ModeType.both && Config._Locations.Contains(blockLoc))) { if (DigBlock(blockLoc, lookAtBlock: false)) @@ -288,8 +330,8 @@ namespace MinecraftClient.ChatBots foreach (Location location in Config._Locations) { Block block = GetWorld().GetBlock(location); - if (block.Type != Material.Air && - ((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) || + if (block.Type != Material.Air && + ((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) || (Config.List_Type == Configs.ListType.blacklist && !Config.Blocks.Contains(block.Type)))) { double distance = current.Distance(location); @@ -401,23 +443,5 @@ namespace MinecraftClient.ChatBots return base.OnDisconnect(reason, message); } - - private static string GetHelp() - { - return string.Format(Translations.bot_autodig_available_cmd, "start, stop, help"); - } - - private string GetCommandHelp(string cmd) - { - return cmd.ToLower() switch - { -#pragma warning disable format // @formatter:off - "start" => Translations.bot_autodig_help_start, - "stop" => Translations.bot_autodig_help_stop, - "help" => Translations.bot_autodig_help_help, - _ => GetHelp(), -#pragma warning restore format // @formatter:on - }; - } } } diff --git a/MinecraftClient/ChatBots/AutoDrop.cs b/MinecraftClient/ChatBots/AutoDrop.cs index 1ad79917..5781af9e 100644 --- a/MinecraftClient/ChatBots/AutoDrop.cs +++ b/MinecraftClient/ChatBots/AutoDrop.cs @@ -1,7 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; using MinecraftClient.Inventory; +using MinecraftClient.Scripting; using Tomlet.Attributes; using static MinecraftClient.ChatBots.AutoDrop.Configs; @@ -9,6 +14,8 @@ namespace MinecraftClient.ChatBots { public class AutoDrop : ChatBot { + public const string CommandName = "autodrop"; + public static Configs Config = new(); [TomlDoNotInlineObject] @@ -38,111 +45,7 @@ namespace MinecraftClient.ChatBots private readonly int updateDebounceValue = 2; private int inventoryUpdated = -1; - public string CommandHandler(string cmd, string[] args) - { - if (args.Length > 0) - { - switch (args[0].ToLower()) - { - case "on": - Config.Enabled = true; - inventoryUpdated = 0; - OnUpdateFinish(); - return Translations.bot_autoDrop_on; - case "off": - Config.Enabled = false; - return Translations.bot_autoDrop_off; - case "add": - if (args.Length >= 2) - { - if (Enum.TryParse(args[1], true, out ItemType item)) - { - Config.Items.Add(item); - return string.Format(Translations.bot_autoDrop_added, item.ToString()); - } - else - { - return string.Format(Translations.bot_autoDrop_incorrect_name, args[1]); - } - } - else - { - return Translations.cmd_inventory_help_usage + ": add "; - } - case "remove": - if (args.Length >= 2) - { - if (Enum.TryParse(args[1], true, out ItemType item)) - { - if (Config.Items.Contains(item)) - { - Config.Items.Remove(item); - return string.Format(Translations.bot_autoDrop_removed, item.ToString()); - } - else - { - return Translations.bot_autoDrop_not_in_list; - } - } - else - { - return string.Format(Translations.bot_autoDrop_incorrect_name, args[1]); - } - } - else - { - return Translations.cmd_inventory_help_usage + ": remove "; - } - case "list": - if (Config.Items.Count > 0) - { - return string.Format(Translations.bot_autoDrop_list, Config.Items.Count, string.Join("\n", Config.Items)); - } - else - { - return Translations.bot_autoDrop_no_item; - } - case "mode": - if (args.Length >= 2) - { - switch (args[1].ToLower()) - { - case "include": - Config.Mode = DropMode.include; - break; - case "exclude": - Config.Mode = DropMode.exclude; - break; - case "everything": - Config.Mode = DropMode.everything; - break; - default: - return Translations.bot_autoDrop_unknown_mode; // Unknwon mode. Available modes: Include, Exclude, Everything - } - inventoryUpdated = 0; - OnUpdateFinish(); - return string.Format(Translations.bot_autoDrop_switched, Config.Mode.ToString()); // Switched to {0} mode. - } - else - { - return Translations.bot_autoDrop_unknown_mode; - } - default: - return GetHelp(); - } - } - else - { - return GetHelp(); - } - } - - private static string GetHelp() - { - return string.Format(Translations.general_available_cmd, "on, off, add, remove, list, mode"); - } - - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { if (!GetInventoryEnabled()) { @@ -151,8 +54,113 @@ namespace MinecraftClient.ChatBots UnloadBot(); return; } - RegisterChatBotCommand("autodrop", Translations.bot_autoDrop_cmd, GetHelp(), CommandHandler); - RegisterChatBotCommand("ad", Translations.bot_autoDrop_alias, GetHelp(), CommandHandler); + + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CommandName) + .Executes(r => OnCommandHelp(r.Source, string.Empty)) + .Then(l => l.Literal("add") + .Executes(r => OnCommandHelp(r.Source, "add"))) + .Then(l => l.Literal("remove") + .Executes(r => OnCommandHelp(r.Source, "remove"))) + .Then(l => l.Literal("mode") + .Executes(r => OnCommandHelp(r.Source, "mode"))) + ) + ); + + dispatcher.Register(l => l.Literal(CommandName) + .Then(l => l.Literal("on") + .Executes(r => OnCommandEnable(r.Source, true))) + .Then(l => l.Literal("off") + .Executes(r => OnCommandEnable(r.Source, false))) + .Then(l => l.Literal("add") + .Then(l => l.Argument("ItemType", MccArguments.ItemType()) + .Executes(r => OnCommandAdd(r.Source, MccArguments.GetItemType(r, "ItemType"))))) + .Then(l => l.Literal("remove") + .Then(l => l.Argument("ItemType", MccArguments.ItemType()) + .Executes(r => OnCommandRemove(r.Source, MccArguments.GetItemType(r, "ItemType"))))) + .Then(l => l.Literal("list") + .Executes(r => OnCommandList(r.Source))) + .Then(l => l.Literal("mode") + .Then(l => l.Literal("include") + .Executes(r => OnCommandMode(r.Source, DropMode.include))) + .Then(l => l.Literal("exclude") + .Executes(r => OnCommandMode(r.Source, DropMode.exclude))) + .Then(l => l.Literal("everything") + .Executes(r => OnCommandMode(r.Source, DropMode.everything)))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + ); + } + + public override void OnUnload(CommandDispatcher dispatcher) + { + dispatcher.Unregister(CommandName); + dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + } + + private int OnCommandHelp(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + "add" => Translations.cmd_inventory_help_usage + ": add ", + "remove" => Translations.cmd_inventory_help_usage + ": remove ", + "mode" => Translations.bot_autoDrop_unknown_mode, + _ => string.Format(Translations.general_available_cmd, "on, off, add, remove, list, mode") + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), +#pragma warning restore format // @formatter:on + }); + } + + private int OnCommandEnable(CmdResult r, bool enable) + { + if (enable) + { + Config.Enabled = true; + inventoryUpdated = 0; + OnUpdateFinish(); + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_autoDrop_on); + } + else + { + Config.Enabled = false; + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_autoDrop_off); + } + } + + private int OnCommandAdd(CmdResult r, ItemType item) + { + Config.Items.Add(item); + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.bot_autoDrop_added, item.ToString())); + } + + private int OnCommandRemove(CmdResult r, ItemType item) + { + if (Config.Items.Contains(item)) + { + Config.Items.Remove(item); + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.bot_autoDrop_removed, item.ToString())); + } + else + { + return r.SetAndReturn(CmdResult.Status.Fail, Translations.bot_autoDrop_not_in_list); + } + } + + private int OnCommandList(CmdResult r) + { + if (Config.Items.Count > 0) + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.bot_autoDrop_list, Config.Items.Count, string.Join("\n", Config.Items))); + else + return r.SetAndReturn(CmdResult.Status.Fail, Translations.bot_autoDrop_no_item); + } + + private int OnCommandMode(CmdResult r, DropMode mode) + { + Config.Mode = mode; + inventoryUpdated = 0; + OnUpdateFinish(); + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.bot_autoDrop_switched, Config.Mode.ToString())); } public override void Update() diff --git a/MinecraftClient/ChatBots/AutoEat.cs b/MinecraftClient/ChatBots/AutoEat.cs index eb9c3762..eb9eea07 100644 --- a/MinecraftClient/ChatBots/AutoEat.cs +++ b/MinecraftClient/ChatBots/AutoEat.cs @@ -1,5 +1,6 @@ using System; using MinecraftClient.Inventory; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index 73b0af3f..963cc9ad 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -2,8 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; using MinecraftClient.Inventory; using MinecraftClient.Mapping; +using MinecraftClient.Scripting; using Tomlet.Attributes; using static MinecraftClient.ChatBots.AutoFishing.Configs; @@ -15,6 +20,8 @@ namespace MinecraftClient.ChatBots /// public class AutoFishing : ChatBot { + public const string CommandName = "autofishing"; + public static Configs Config = new(); [TomlDoNotInlineObject] @@ -169,87 +176,119 @@ namespace MinecraftClient.ChatBots Stopping, } - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { if (!GetEntityHandlingEnabled()) { LogToConsole(Translations.extra_entity_required); state = FishingState.WaitJoinGame; } + inventoryEnabled = GetInventoryEnabled(); if (!inventoryEnabled) LogToConsole(Translations.bot_autoFish_no_inv_handle); - RegisterChatBotCommand("fish", Translations.bot_autoFish_cmd, GetHelp(), CommandHandler); + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CommandName) + .Executes(r => OnCommandHelp(r.Source, string.Empty)) + .Then(l => l.Literal("start") + .Executes(r => OnCommandHelp(r.Source, "start"))) + .Then(l => l.Literal("stop") + .Executes(r => OnCommandHelp(r.Source, "stop"))) + .Then(l => l.Literal("status") + .Executes(r => OnCommandHelp(r.Source, "status"))) + .Then(l => l.Literal("help") + .Executes(r => OnCommandHelp(r.Source, "help"))) + ) + ); + + dispatcher.Register(l => l.Literal(CommandName) + .Then(l => l.Literal("start") + .Executes(r => OnCommandStart(r.Source))) + .Then(l => l.Literal("stop") + .Executes(r => OnCommandStop(r.Source))) + .Then(l => l.Literal("status") + .Executes(r => OnCommandStatus(r.Source)) + .Then(l => l.Literal("clear") + .Executes(r => OnCommandStatusClear(r.Source)))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + ); } - public string CommandHandler(string cmd, string[] args) + public override void OnUnload(CommandDispatcher dispatcher) { - if (args.Length >= 1) + dispatcher.Unregister(CommandName); + dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + } + + private int OnCommandHelp(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch { - switch (args[0]) - { - case "start": - isFishing = false; - lock (stateLock) - { - isFishing = false; - counter = 0; - state = FishingState.StartMove; - } - return Translations.bot_autoFish_start; - case "stop": - isFishing = false; - lock (stateLock) - { - isFishing = false; - if (state == FishingState.WaitingFishToBite) - UseFishRod(); - state = FishingState.Stopping; - } - StopFishing(); - return Translations.bot_autoFish_stop; - case "status": - if (args.Length >= 2) - { - if (args[1] == "clear") - { - fishItemCnt = new(); - return Translations.bot_autoFish_status_clear; - } - else - { - return GetCommandHelp("status"); - } - } - else - { - if (fishItemCnt.Count == 0) - return Translations.bot_autoFish_status_info; +#pragma warning disable format // @formatter:off + "start" => Translations.bot_autoFish_help_start, + "stop" => Translations.bot_autoFish_help_stop, + "status" => Translations.bot_autoFish_help_status, + "help" => Translations.bot_autoFish_help_help, + _ => string.Format(Translations.bot_autoFish_available_cmd, "start, stop, status, help") + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), +#pragma warning restore format // @formatter:on + }); + } - List> orderedList = fishItemCnt.OrderBy(x => x.Value).ToList(); - int maxLen = orderedList[^1].Value.ToString().Length; - StringBuilder sb = new(); - sb.Append(Translations.bot_autoFish_status_info); - foreach ((ItemType type, uint cnt) in orderedList) - { - sb.Append(Environment.NewLine); - - string cntStr = cnt.ToString(); - sb.Append(' ', maxLen - cntStr.Length).Append(cntStr); - sb.Append(" x "); - sb.Append(Item.GetTypeString(type)); - } - return sb.ToString(); - } - case "help": - return GetCommandHelp(args.Length >= 2 ? args[1] : ""); - default: - return GetHelp(); - } + private int OnCommandStart(CmdResult r) + { + isFishing = false; + lock (stateLock) + { + isFishing = false; + counter = 0; + state = FishingState.StartMove; } - else - return GetHelp(); + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_autoFish_start); + } + + private int OnCommandStop(CmdResult r) + { + isFishing = false; + lock (stateLock) + { + isFishing = false; + if (state == FishingState.WaitingFishToBite) + UseFishRod(); + state = FishingState.Stopping; + } + StopFishing(); + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_autoFish_stop); + } + + private int OnCommandStatus(CmdResult r) + { + if (fishItemCnt.Count == 0) + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_autoFish_status_info); + + List> orderedList = fishItemCnt.OrderBy(x => x.Value).ToList(); + int maxLen = orderedList[^1].Value.ToString().Length; + StringBuilder sb = new(); + sb.Append(Translations.bot_autoFish_status_info); + foreach ((ItemType type, uint cnt) in orderedList) + { + sb.Append(Environment.NewLine); + + string cntStr = cnt.ToString(); + sb.Append(' ', maxLen - cntStr.Length).Append(cntStr); + sb.Append(" x "); + sb.Append(Item.GetTypeString(type)); + } + LogToConsole(sb.ToString()); + return r.SetAndReturn(CmdResult.Status.Done); + } + + private int OnCommandStatusClear(CmdResult r) + { + fishItemCnt = new(); + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_autoFish_status_clear); } private void StartFishing() @@ -386,7 +425,7 @@ namespace MinecraftClient.ChatBots public override void OnEntitySpawn(Entity entity) { if (fishItemCounter < 15 && entity.Type == EntityType.Item && Math.Abs(entity.Location.Y - LastPos.Y) < 2.2 && - Math.Abs(entity.Location.X - LastPos.X) < 0.12 && Math.Abs(entity.Location.Z - LastPos.Z) < 0.12) + Math.Abs(entity.Location.X - LastPos.X) < 0.12 && Math.Abs(entity.Location.Z - LastPos.Z) < 0.12) { if (Config.Log_Fish_Bobber) LogToConsole(string.Format("Item ({0}) spawn at {1}, distance = {2:0.00}", entity.ID, entity.Location, entity.Location.Distance(LastPos))); @@ -440,7 +479,7 @@ namespace MinecraftClient.ChatBots public override void OnEntityMove(Entity entity) { - if (isFishing && entity != null && fishingBobber!.ID == entity.ID && + if (isFishing && entity != null && fishingBobber!.ID == entity.ID && (state == FishingState.WaitingFishToBite || state == FishingState.WaitingFishingBobber)) { Location Pos = entity.Location; @@ -620,24 +659,5 @@ namespace MinecraftClient.ChatBots return false; } } - - private static string GetHelp() - { - return string.Format(Translations.bot_autoFish_available_cmd, "start, stop, status, help"); - } - - private string GetCommandHelp(string cmd) - { - return cmd.ToLower() switch - { -#pragma warning disable format // @formatter:off - "start" => Translations.bot_autoFish_help_start, - "stop" => Translations.bot_autoFish_help_stop, - "status" => Translations.bot_autoFish_help_status, - "help" => Translations.bot_autoFish_help_help, - _ => GetHelp(), -#pragma warning restore format // @formatter:on - }; - } } } diff --git a/MinecraftClient/ChatBots/AutoRelog.cs b/MinecraftClient/ChatBots/AutoRelog.cs index 2795366e..ae69d76f 100644 --- a/MinecraftClient/ChatBots/AutoRelog.cs +++ b/MinecraftClient/ChatBots/AutoRelog.cs @@ -1,4 +1,7 @@ using System; +using Brigadier.NET; +using MinecraftClient.CommandHandler; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots @@ -43,7 +46,7 @@ namespace MinecraftClient.ChatBots if (Delay.min > Delay.max) (Delay.min, Delay.max) = (Delay.max, Delay.min); - + if (Retries == -1) Retries = int.MaxValue; @@ -82,7 +85,12 @@ namespace MinecraftClient.ChatBots LogDebugToConsole(string.Format(Translations.bot_autoRelog_launch, Config.Retries)); } - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) + { + Initialize(); + } + + private void Initialize() { McClient.ReconnectionAttemptsLeft = Config.Retries; if (Config.Ignore_Kick_Message) diff --git a/MinecraftClient/ChatBots/AutoRespond.cs b/MinecraftClient/ChatBots/AutoRespond.cs index 91279191..bb5ff233 100644 --- a/MinecraftClient/ChatBots/AutoRespond.cs +++ b/MinecraftClient/ChatBots/AutoRespond.cs @@ -4,6 +4,10 @@ using System.Globalization; using System.IO; using System.Text; using System.Text.RegularExpressions; +using Brigadier.NET; +using MinecraftClient.CommandHandler; +using MinecraftClient.Scripting; +using PInvoke; using Tomlet.Attributes; using static MinecraftClient.Settings; @@ -183,7 +187,7 @@ namespace MinecraftClient.ChatBots /// /// Initialize the AutoRespond bot from the matches file /// - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { if (File.Exists(Config.Matches_File)) { @@ -304,12 +308,12 @@ namespace MinecraftClient.ChatBots { Dictionary localVars = new(); string? toPerform = rule.Match(sender, message, msgType, localVars); - if (!String.IsNullOrEmpty(toPerform)) + if (!string.IsNullOrEmpty(toPerform)) { - string? response = null; + CmdResult response = new(); LogToConsole(string.Format(Translations.bot_autoRespond_match_run, toPerform)); PerformInternalCommand(toPerform, ref response, localVars); - if (!String.IsNullOrEmpty(response)) + if (response.status != CmdResult.Status.Done || !string.IsNullOrWhiteSpace(response.result)) LogToConsole(response); } } diff --git a/MinecraftClient/ChatBots/ChatLog.cs b/MinecraftClient/ChatBots/ChatLog.cs index b6ad94ef..37aecd36 100644 --- a/MinecraftClient/ChatBots/ChatLog.cs +++ b/MinecraftClient/ChatBots/ChatLog.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using MinecraftClient.CommandHandler; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots @@ -115,7 +117,7 @@ namespace MinecraftClient.ChatBots } } - public override void OnInternalCommand(string commandName, string commandParams, string result) + public override void OnInternalCommand(string commandName, string commandParams, CmdResult result) { if (saveInternal) { diff --git a/MinecraftClient/ChatBots/DiscordBridge.cs b/MinecraftClient/ChatBots/DiscordBridge.cs index 644be296..848fb86b 100644 --- a/MinecraftClient/ChatBots/DiscordBridge.cs +++ b/MinecraftClient/ChatBots/DiscordBridge.cs @@ -3,16 +3,23 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.Builder; using DSharpPlus; using DSharpPlus.Entities; using DSharpPlus.Exceptions; using Microsoft.Extensions.Logging; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots { public class DiscordBridge : ChatBot { + public const string CommandName = "dscbridge"; + private enum BridgeDirection { Both = 0, @@ -68,19 +75,75 @@ namespace MinecraftClient.ChatBots instance = this; } - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { - RegisterChatBotCommand("dscbridge", "bot.DiscordBridge.desc", "dscbridge direction ", OnDscCommand); + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CommandName) + .Executes(r => OnCommandHelp(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CommandName) + .Then(l => l.Literal("direction") + .Then(l => l.Literal("both") + .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Both))) + .Then(l => l.Literal("mc") + .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Minecraft))) + .Then(l => l.Literal("discord") + .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Discord))) + ) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + ); Task.Run(async () => await MainAsync()); } - ~DiscordBridge() + public override void OnUnload(CommandDispatcher dispatcher) { + dispatcher.Unregister(CommandName); + dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); Disconnect(); } - public override void OnUnload() + private int OnCommandHelp(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => "dscbridge direction " + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), +#pragma warning restore format // @formatter:on + }); + } + + private int OnCommandDirection(CmdResult r, BridgeDirection direction) + { + string bridgeName; + switch (direction) + { + case BridgeDirection.Both: + bridgeName = Translations.bot_DiscordBridge_direction_both; + bridgeDirection = BridgeDirection.Both; + break; + + case BridgeDirection.Minecraft: + bridgeName = Translations.bot_DiscordBridge_direction_minecraft; + bridgeDirection = BridgeDirection.Minecraft; + break; + + case BridgeDirection.Discord: + bridgeName = Translations.bot_DiscordBridge_direction_discord; + bridgeDirection = BridgeDirection.Discord; + break; + + default: + goto case BridgeDirection.Both; + } + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.bot_DiscordBridge_direction, bridgeName)); + } + + ~DiscordBridge() { Disconnect(); } @@ -114,47 +177,6 @@ namespace MinecraftClient.ChatBots return instance; } - private string OnDscCommand(string cmd, string[] args) - { - if (args.Length == 2) - { - if (args[0].ToLower().Equals("direction")) - { - string direction = args[1].ToLower().Trim(); - - string bridgeName; - switch (direction) - { - case "b": - case "both": - bridgeName = Translations.bot_DiscordBridge_direction_both; - bridgeDirection = BridgeDirection.Both; - break; - - case "mc": - case "minecraft": - bridgeName = Translations.bot_DiscordBridge_direction_minecraft; - bridgeDirection = BridgeDirection.Minecraft; - break; - - case "d": - case "dcs": - case "discord": - bridgeName = Translations.bot_DiscordBridge_direction_discord; - bridgeDirection = BridgeDirection.Discord; - break; - - default: - return Translations.bot_DiscordBridge_invalid_direction; - } - - return string.Format(Translations.bot_DiscordBridge_direction, bridgeName); - }; - } - - return "dscbridge direction "; - } - public override void GetText(string text) { if (!CanSendMessages()) @@ -369,9 +391,8 @@ namespace MinecraftClient.ChatBots message = message[1..]; await e.Message.CreateReactionAsync(DiscordEmoji.FromName(discordBotClient, ":gear:")); - string? result = ""; + CmdResult result = new(); PerformInternalCommand(message, ref result); - result = string.IsNullOrEmpty(result) ? "-" : result; await e.Message.DeleteOwnReactionAsync(DiscordEmoji.FromName(discordBotClient, ":gear:")); await e.Message.CreateReactionAsync(DiscordEmoji.FromName(discordBotClient, ":white_check_mark:")); diff --git a/MinecraftClient/ChatBots/Farmer.cs b/MinecraftClient/ChatBots/Farmer.cs index 94af1191..e54e5ed7 100644 --- a/MinecraftClient/ChatBots/Farmer.cs +++ b/MinecraftClient/ChatBots/Farmer.cs @@ -3,34 +3,22 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; using MinecraftClient.Inventory; using MinecraftClient.Mapping; using MinecraftClient.Protocol.Handlers; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots { - enum State - { - SearchingForCropsToBreak = 0, - SearchingForFarmlandToPlant, - PlantingCrops, - BonemealingCrops - } - - enum CropType - { - Beetroot, - Carrot, - Melon, - Netherwart, - Pumpkin, - Potato, - Wheat - } - public class Farmer : ChatBot { + public const string CommandName = "farmer"; + public static Configs Config = new(); [TomlDoNotInlineObject] @@ -42,15 +30,34 @@ namespace MinecraftClient.ChatBots public bool Enabled = false; [TomlInlineComment("$config.ChatBot.Farmer.Delay_Between_Tasks$")] - public int Delay_Between_Tasks = 1; + public double Delay_Between_Tasks = 1.0; public void OnSettingUpdate() { - if (Delay_Between_Tasks <= 0) - Delay_Between_Tasks = 1; + if (Delay_Between_Tasks < 1.0) + Delay_Between_Tasks = 1.0; } } + public enum State + { + SearchingForCropsToBreak = 0, + SearchingForFarmlandToPlant, + PlantingCrops, + BonemealingCrops + } + + public enum CropType + { + Beetroot, + Carrot, + Melon, + Netherwart, + Pumpkin, + Potato, + Wheat + } + private State state = State.SearchingForCropsToBreak; private CropType cropType = CropType.Wheat; private int farmingRadius = 30; @@ -59,9 +66,11 @@ namespace MinecraftClient.ChatBots private bool allowTeleport = false; private bool debugEnabled = false; + public int Delay_Between_Tasks_Millisecond => (int)Math.Round(Config.Delay_Between_Tasks * 1000); + private const string commandDescription = "farmer [radius:] [unsafe:] [teleport:] [debug:]|stop>"; - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { if (GetProtocolVersion() < Protocol18Handler.MC_1_13_Version) { @@ -81,130 +90,152 @@ namespace MinecraftClient.ChatBots return; } - RegisterChatBotCommand("farmer", "bot.farmer.desc", commandDescription, OnFarmCommand); + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CommandName) + .Executes(r => OnCommandHelp(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CommandName) + .Then(l => l.Literal("stop") + .Executes(r => OnCommandStop(r.Source))) + .Then(l => l.Literal("start") + .Then(l => l.Argument("CropType", MccArguments.FarmerCropType()) + .Executes(r => OnCommandStart(r.Source, MccArguments.GetFarmerCropType(r, "CropType"), null)) + .Then(l => l.Argument("OtherArgs", Arguments.GreedyString()) + .Executes(r => OnCommandStart(r.Source, MccArguments.GetFarmerCropType(r, "CropType"), Arguments.GetString(r, "OtherArgs")))))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + ); } - private string OnFarmCommand(string cmd, string[] args) + public override void OnUnload(CommandDispatcher dispatcher) { - if (args.Length > 0) + dispatcher.Unregister(CommandName); + dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + } + + private int OnCommandHelp(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch { - if (args[0].Equals("stop", StringComparison.OrdinalIgnoreCase)) - { - if (!running) - return Translations.bot_farmer_already_stopped; +#pragma warning disable format // @formatter:off + _ => Translations.bot_farmer_desc + ": " + commandDescription + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), +#pragma warning restore format // @formatter:on + }); + } - running = false; - return Translations.bot_farmer_stopping; - } + private int OnCommandStop(CmdResult r) + { + if (!running) + { + return r.SetAndReturn(CmdResult.Status.Fail, Translations.bot_farmer_already_stopped); + } + else + { + running = false; + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_farmer_stopping); + } + } - if (args[0].Equals("start", StringComparison.OrdinalIgnoreCase)) + private int OnCommandStart(CmdResult r, CropType whatToFarm, string? otherArgs) + { + if (running) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.bot_farmer_already_running); + + int radius = 30; + + state = State.SearchingForFarmlandToPlant; + cropType = whatToFarm; + allowUnsafe = false; + allowTeleport = false; + debugEnabled = false; + + if (!string.IsNullOrWhiteSpace(otherArgs)) + { + string[] args = otherArgs.ToLower().Split(' ', StringSplitOptions.TrimEntries); + foreach (string currentArg in args) { - if (args.Length >= 2) + if (!currentArg.Contains(':')) { - if (running) - return Translations.bot_farmer_already_running; + LogToConsole("§x§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)); + continue; + } - if (!Enum.TryParse(args[1], true, out CropType whatToFarm)) - return Translations.bot_farmer_invalid_crop_type; + string[] parts = currentArg.Split(":", StringSplitOptions.TrimEntries); - int radius = 30; + if (parts.Length != 2) + { + LogToConsole("§x§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)); + continue; + } - state = State.SearchingForFarmlandToPlant; - cropType = whatToFarm; - allowUnsafe = false; - allowTeleport = false; - debugEnabled = false; + switch (parts[0]) + { + case "r": + case "radius": + if (!int.TryParse(parts[1], NumberStyles.Any, CultureInfo.CurrentCulture, out radius)) + LogToConsole("§x§1§0" + Translations.bot_farmer_invalid_radius); - if (args.Length >= 3) - { - for (int i = 2; i < args.Length; i++) + if (radius <= 0) { - string currentArg = args[i].Trim().ToLower(); - - if (!currentArg.Contains(':')) - { - LogToConsole("§x§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)); - continue; - } - - string[] parts = currentArg.Split(":", StringSplitOptions.TrimEntries); - - if (parts.Length != 2) - { - LogToConsole("§x§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)); - continue; - } - - switch (parts[0]) - { - case "r": - case "radius": - if (!int.TryParse(parts[1], NumberStyles.Any, CultureInfo.CurrentCulture, out radius)) - LogToConsole("§x§1§0" + Translations.bot_farmer_invalid_radius); - - if (radius <= 0) - { - LogToConsole("§x§1§0" + Translations.bot_farmer_invalid_radius); - radius = 30; - } - - break; - - case "f": - case "unsafe": - if (allowUnsafe) - break; - - if (parts[1].Equals("true") || parts[1].Equals("1")) - { - LogToConsole("§x§1§0" + Translations.bot_farmer_warining_force_unsafe); - allowUnsafe = true; - } - else allowUnsafe = false; - - break; - - case "t": - case "teleport": - if (allowTeleport) - break; - - if (parts[1].Equals("true") || parts[1].Equals("1")) - { - LogToConsole("§w§1§f" + Translations.bot_farmer_warining_allow_teleport); - allowTeleport = true; - } - else allowTeleport = false; - - break; - - case "d": - case "debug": - if (debugEnabled) - break; - - if (parts[1].Equals("true") || parts[1].Equals("1")) - { - LogToConsole("Debug enabled!"); - debugEnabled = true; - } - else debugEnabled = false; - - break; - } + LogToConsole("§x§1§0" + Translations.bot_farmer_invalid_radius); + radius = 30; } - } - farmingRadius = radius; - running = true; - new Thread(() => MainPorcess()).Start(); + break; - return ""; + case "f": + case "unsafe": + if (allowUnsafe) + break; + + if (parts[1].Equals("true") || parts[1].Equals("1")) + { + LogToConsole("§x§1§0" + Translations.bot_farmer_warining_force_unsafe); + allowUnsafe = true; + } + else allowUnsafe = false; + + break; + + case "t": + case "teleport": + if (allowTeleport) + break; + + if (parts[1].Equals("true") || parts[1].Equals("1")) + { + LogToConsole("§w§1§f" + Translations.bot_farmer_warining_allow_teleport); + allowTeleport = true; + } + else allowTeleport = false; + + break; + + case "d": + case "debug": + if (debugEnabled) + break; + + if (parts[1].Equals("true") || parts[1].Equals("1")) + { + LogToConsole("Debug enabled!"); + debugEnabled = true; + } + else debugEnabled = false; + + break; } } } - return Translations.bot_farmer_desc + ": " + commandDescription; + farmingRadius = radius; + running = true; + new Thread(() => MainPorcess()).Start(); + + return r.SetAndReturn(CmdResult.Status.Done); } public override void AfterGameJoined() @@ -230,7 +261,7 @@ namespace MinecraftClient.ChatBots if (AutoEat.Eating) { LogDebug("Eating..."); - Thread.Sleep(Config.Delay_Between_Tasks * 1000); + Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } @@ -246,7 +277,7 @@ namespace MinecraftClient.ChatBots { LogDebug("No seeds, trying to find some crops to break"); state = State.SearchingForCropsToBreak; - Thread.Sleep(Config.Delay_Between_Tasks * 1000); + Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } @@ -256,7 +287,7 @@ namespace MinecraftClient.ChatBots { LogDebug("Could not find any farmland, trying to find some crops to break"); state = State.SearchingForCropsToBreak; - Thread.Sleep(Config.Delay_Between_Tasks * 1000); + Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } @@ -272,7 +303,7 @@ namespace MinecraftClient.ChatBots { LogDebug("Ran out of seeds, looking for crops to break..."); state = State.SearchingForCropsToBreak; - Thread.Sleep(Config.Delay_Between_Tasks * 1000); + Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } } @@ -321,7 +352,7 @@ namespace MinecraftClient.ChatBots { LogToConsole("No crops to break, trying to bonemeal ungrown ones"); state = State.BonemealingCrops; - Thread.Sleep(Config.Delay_Between_Tasks * 1000); + Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } @@ -367,7 +398,7 @@ namespace MinecraftClient.ChatBots if (cropType == CropType.Netherwart) { state = State.SearchingForFarmlandToPlant; - Thread.Sleep(Config.Delay_Between_Tasks * 1000); + Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } @@ -376,7 +407,7 @@ namespace MinecraftClient.ChatBots { LogDebug("No bonemeal, searching for some farmland to plant seeds on"); state = State.SearchingForFarmlandToPlant; - Thread.Sleep(Config.Delay_Between_Tasks * 1000); + Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } @@ -386,7 +417,7 @@ namespace MinecraftClient.ChatBots { LogDebug("No crops to bonemeal, searching for farmland to plant seeds on"); state = State.SearchingForFarmlandToPlant; - Thread.Sleep(Config.Delay_Between_Tasks * 1000); + Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } @@ -402,7 +433,7 @@ namespace MinecraftClient.ChatBots { LogDebug("Ran out of Bone Meal, looking for farmland to plant on..."); state = State.SearchingForFarmlandToPlant; - Thread.Sleep(Config.Delay_Between_Tasks * 1000); + Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } } @@ -438,8 +469,8 @@ namespace MinecraftClient.ChatBots break; } - LogDebug("Waiting for " + Config.Delay_Between_Tasks + " seconds for next cycle."); - Thread.Sleep(Config.Delay_Between_Tasks * 1000); + LogDebug(string.Format("Waiting for {0:0.00} seconds for next cycle.", Config.Delay_Between_Tasks)); + Thread.Sleep(Delay_Between_Tasks_Millisecond); } LogToConsole(Translations.bot_farmer_stopped); @@ -815,6 +846,7 @@ namespace MinecraftClient.ChatBots { return GetPlayerInventory().SearchItem(itemType).Length > 0; } + private void LogDebug(object text) { if (debugEnabled) diff --git a/MinecraftClient/ChatBots/FollowPlayer.cs b/MinecraftClient/ChatBots/FollowPlayer.cs index ebbf2c90..231332b4 100644 --- a/MinecraftClient/ChatBots/FollowPlayer.cs +++ b/MinecraftClient/ChatBots/FollowPlayer.cs @@ -1,12 +1,19 @@ using System; using System.Linq; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; using MinecraftClient.Mapping; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots { public class FollowPlayer : ChatBot { + public const string CommandName = "follow"; + public static Configs Config = new(); [TomlDoNotInlineObject] @@ -37,7 +44,7 @@ namespace MinecraftClient.ChatBots private int _updateCounter = 0; private bool _unsafeEnabled = false; - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { if (!GetEntityHandlingEnabled()) { @@ -55,58 +62,85 @@ namespace MinecraftClient.ChatBots return; } - RegisterChatBotCommand("follow", "cmd.follow.desc", "follow ", OnFollowCommand); + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CommandName) + .Executes(r => OnCommandHelp(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CommandName) + .Then(l => l.Literal("start") + .Then(l => l.Argument("PlayerName", MccArguments.PlayerName()) + .Executes(r => OnCommandStart(r.Source, Arguments.GetString(r, "PlayerName"), takeRisk: false)) + .Then(l => l.Literal("-f") + .Executes(r => OnCommandStart(r.Source, Arguments.GetString(r, "PlayerName"), takeRisk: true))))) + .Then(l => l.Literal("stop") + .Executes(r => OnCommandStop(r.Source))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + ); } - private string OnFollowCommand(string cmd, string[] args) + public override void OnUnload(CommandDispatcher dispatcher) { - if (args.Length > 0) + dispatcher.Unregister(CommandName); + dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + } + + private int OnCommandHelp(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch { - if (args[0].Equals("stop", StringComparison.OrdinalIgnoreCase)) - { - if (_playerToFollow == null) - return Translations.cmd_follow_already_stopped; +#pragma warning disable format // @formatter:off + _ => Translations.cmd_follow_desc + ": " + Translations.cmd_follow_usage + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), +#pragma warning restore format // @formatter:on + }); + } - _playerToFollow = null; - return Translations.cmd_follow_stopping; - } - else - { - if (!IsValidName(args[0])) - return Translations.cmd_follow_invalid_name; + private int OnCommandStart(CmdResult r, string name, bool takeRisk) + { + if (!IsValidName(name)) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_follow_invalid_name); - Entity? player = GetEntities().Values.ToList().Find(entity => - entity.Type == EntityType.Player && !string.IsNullOrEmpty(entity.Name) && entity.Name.Equals(args[0], StringComparison.OrdinalIgnoreCase)); + Entity? player = GetEntities().Values.ToList().Find(entity => + entity.Type == EntityType.Player + && !string.IsNullOrEmpty(entity.Name) + && entity.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); - if (player == null) - return Translations.cmd_follow_invalid_player; + if (player == null) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_follow_invalid_player); - if (!CanMoveThere(player.Location)) - return Translations.cmd_follow_cant_reach_player; + if (!CanMoveThere(player.Location)) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_follow_cant_reach_player); - if (_playerToFollow != null && _playerToFollow.Equals(args[0], StringComparison.OrdinalIgnoreCase)) - return string.Format(Translations.cmd_follow_already_following, _playerToFollow); + if (_playerToFollow != null && _playerToFollow.Equals(name, StringComparison.OrdinalIgnoreCase)) + return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_follow_already_following, _playerToFollow)); - string result; - if (_playerToFollow != null) - result = string.Format(Translations.cmd_follow_switched, player.Name!); - else - result = string.Format(Translations.cmd_follow_started, player.Name!); - _playerToFollow = args[0].Trim().ToLower(); + string result; + if (_playerToFollow != null) + result = string.Format(Translations.cmd_follow_switched, player.Name!); + else + result = string.Format(Translations.cmd_follow_started, player.Name!); + _playerToFollow = name.ToLower(); - LogToConsole(Translations.cmd_follow_note); - - if (args.Length == 2 && args[1].Equals("-f", StringComparison.OrdinalIgnoreCase)) - { - _unsafeEnabled = true; - LogToConsole(Translations.cmd_follow_unsafe_enabled); - } - - return result; - } + if (takeRisk) + { + _unsafeEnabled = true; + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_follow_note + '\n' + Translations.cmd_follow_unsafe_enabled); } + else + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_follow_note); + } - return Translations.cmd_follow_desc + ": " + Translations.cmd_follow_usage; + private int OnCommandStop(CmdResult r) + { + if (_playerToFollow == null) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_follow_already_stopped); + + _playerToFollow = null; + + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_follow_stopping); } public override void Update() diff --git a/MinecraftClient/ChatBots/HangmanGame.cs b/MinecraftClient/ChatBots/HangmanGame.cs index 0eb923c9..ac04dd9e 100644 --- a/MinecraftClient/ChatBots/HangmanGame.cs +++ b/MinecraftClient/ChatBots/HangmanGame.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots diff --git a/MinecraftClient/ChatBots/Mailer.cs b/MinecraftClient/ChatBots/Mailer.cs index b6f2ee12..7da1a312 100644 --- a/MinecraftClient/ChatBots/Mailer.cs +++ b/MinecraftClient/ChatBots/Mailer.cs @@ -3,6 +3,11 @@ using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots @@ -12,6 +17,8 @@ namespace MinecraftClient.ChatBots /// public class Mailer : ChatBot { + public const string CommandName = "mailer"; + public static Configs Config = new(); [TomlDoNotInlineObject] @@ -216,7 +223,7 @@ namespace MinecraftClient.ChatBots /// /// Initialization of the Mailer bot /// - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { LogDebugToConsole(Translations.bot_mailer_init); LogDebugToConsole(Translations.bot_mailer_init_db + Config.DatabaseFile); @@ -251,7 +258,123 @@ namespace MinecraftClient.ChatBots mailDbFileMonitor = new FileMonitor(Path.GetDirectoryName(Config.DatabaseFile)!, Path.GetFileName(Config.DatabaseFile), FileMonitorCallback); ignoreListFileMonitor = new FileMonitor(Path.GetDirectoryName(Config.IgnoreListFile)!, Path.GetFileName(Config.IgnoreListFile), FileMonitorCallback); - RegisterChatBotCommand("mailer", Translations.bot_mailer_cmd, "mailer ", ProcessInternalCommand); + dispatcher.Register(l => + l.Literal("help") + .Then(l => l.Literal(CommandName) + .Executes(r => OnCommandHelp(string.Empty)) + .Then(l => l.Argument("any", Arguments.GreedyString()).Executes(r => OnCommandHelp(string.Empty))) + ) + ); + + dispatcher.Register(l => + l.Literal(CommandName) + .Executes(r => OnCommandHelp(string.Empty)) + .Then(l => l.Literal("getmails") + .Executes(r => OnCommandGetMails()) + .Then(l => l.Argument("any", Arguments.GreedyString()).Executes(r => OnCommandHelp("getmails"))) + ) + .Then(l => l.Literal("getignored") + .Executes(r => OnCommandGetIgnored()) + .Then(l => l.Argument("any", Arguments.GreedyString()).Executes(r => OnCommandHelp("getignored"))) + ) + .Then(l => l.Literal("addignored") + .Executes(r => OnCommandHelp("addignored")) + .Then(l => l.Argument("username", Arguments.String()) + .Executes(r => OnCommandAddIgnored(Arguments.GetString(r, "username"))) + .Then(l => l.Argument("any", Arguments.GreedyString()).Executes(r => OnCommandHelp("addignored"))) + ) + .Then(l => l.Argument("any", Arguments.GreedyString()).Executes(r => OnCommandHelp("addignored"))) + ) + .Then(l => l.Literal("removeignored") + .Executes(r => OnCommandHelp("removeignored")) + .Then(l => l.Argument("username", Arguments.String()) + .Executes(r => OnCommandRemoveIgnored(Arguments.GetString(r, "username"))) + .Then(l => l.Argument("any", Arguments.GreedyString()).Executes(r => OnCommandHelp("removeignored"))) + ) + .Then(l => l.Argument("any", Arguments.GreedyString()).Executes(r => OnCommandHelp("removeignored"))) + ) + .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(string.Empty)) + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CommandName)) + ) + .Then(l => l.Argument("any", Arguments.GreedyString()).Executes(r => OnCommandHelp(string.Empty))) + ); + } + + public override void OnUnload(CommandDispatcher dispatcher) + { + dispatcher.Unregister(CommandName); + dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + } + + private int OnCommandHelp(string cmd) + { + LogToConsole(cmd switch + { +#pragma warning disable format // @formatter:off + _ => Translations.bot_mailer_cmd_help + ": /mailer " + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), +#pragma warning restore format // @formatter:on + }); + return 1; + } + + private int OnCommandGetMails() + { + LogToConsole(string.Format(Translations.bot_mailer_cmd_getmails, string.Join("\n", mailDatabase))); + return 1; + } + + private int OnCommandGetIgnored() + { + LogToConsole(string.Format(Translations.bot_mailer_cmd_getignored, string.Join("\n", ignoreList))); + return 1; + } + + private int OnCommandAddIgnored(string username) + { + if (IsValidName(username)) + { + username = username.ToLower(); + lock (readWriteLock) + { + if (!ignoreList.Contains(username)) + { + ignoreList.Add(username); + ignoreList.SaveToFile(Config.IgnoreListFile); + } + } + LogToConsole(string.Format(Translations.bot_mailer_cmd_ignore_added, username)); + return 1; + } + else + { + LogToConsole(string.Format(Translations.bot_mailer_cmd_ignore_invalid, "addignored")); + return 0; + } + } + + private int OnCommandRemoveIgnored(string username) + { + if (IsValidName(username)) + { + username = username.ToLower(); + lock (readWriteLock) + { + if (ignoreList.Contains(username)) + { + ignoreList.Remove(username); + ignoreList.SaveToFile(Config.IgnoreListFile); + } + } + LogToConsole(string.Format(Translations.bot_mailer_cmd_ignore_removed, username)); + return 1; + } + else + { + LogToConsole(string.Format(Translations.bot_mailer_cmd_ignore_invalid, "removeignored")); + return 0; + } } /// @@ -365,57 +488,5 @@ namespace MinecraftClient.ChatBots ignoreList = IgnoreList.FromFile(Config.IgnoreListFile); } } - - /// - /// Interprets local commands. - /// - private string ProcessInternalCommand(string cmd, string[] args) - { - if (args.Length > 0) - { - string commandName = args[0].ToLower(); - switch (commandName) - { - case "getmails": // Sorry, I (ReinforceZwei) replaced "=" to "-" because it would affect the parsing of translation file (key=value) - return string.Format(Translations.bot_mailer_cmd_getmails, string.Join("\n", mailDatabase)); - - case "getignored": - return string.Format(Translations.bot_mailer_cmd_getignored, string.Join("\n", ignoreList)); - - case "addignored": - case "removeignored": - if (args.Length > 1 && IsValidName(args[1])) - { - string username = args[1].ToLower(); - if (commandName == "addignored") - { - lock (readWriteLock) - { - if (!ignoreList.Contains(username)) - { - ignoreList.Add(username); - ignoreList.SaveToFile(Config.IgnoreListFile); - } - } - return string.Format(Translations.bot_mailer_cmd_ignore_added, args[1]); - } - else - { - lock (readWriteLock) - { - if (ignoreList.Contains(username)) - { - ignoreList.Remove(username); - ignoreList.SaveToFile(Config.IgnoreListFile); - } - } - return string.Format(Translations.bot_mailer_cmd_ignore_removed, args[1]); - } - } - else return string.Format(Translations.bot_mailer_cmd_ignore_invalid, commandName); - } - } - return Translations.bot_mailer_cmd_help + ": /help mailer"; - } } } diff --git a/MinecraftClient/ChatBots/Map.cs b/MinecraftClient/ChatBots/Map.cs index d0d01a64..fd06c769 100644 --- a/MinecraftClient/ChatBots/Map.cs +++ b/MinecraftClient/ChatBots/Map.cs @@ -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 cachedMaps = new(); + internal readonly Dictionary cachedMaps = new(); private readonly Queue discordQueue = new(); - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { if (!Directory.Exists(baseDirectory)) Directory.CreateDirectory(baseDirectory); DeleteRenderedMaps(); - RegisterChatBotCommand("maps", "bot.map.cmd.desc", "maps list|render or maps l|r ", 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 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 >" + + '\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(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(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 > | maps >"; - - 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 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 Colors = new() diff --git a/MinecraftClient/ChatBots/PlayerListLogger.cs b/MinecraftClient/ChatBots/PlayerListLogger.cs index 8c59af89..4b0ad7d4 100644 --- a/MinecraftClient/ChatBots/PlayerListLogger.cs +++ b/MinecraftClient/ChatBots/PlayerListLogger.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots diff --git a/MinecraftClient/ChatBots/RemoteControl.cs b/MinecraftClient/ChatBots/RemoteControl.cs index ac1d544e..301e16f8 100644 --- a/MinecraftClient/ChatBots/RemoteControl.cs +++ b/MinecraftClient/ChatBots/RemoteControl.cs @@ -1,4 +1,6 @@ using System; +using MinecraftClient.CommandHandler; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots @@ -32,17 +34,9 @@ namespace MinecraftClient.ChatBots string command = "", sender = ""; if (IsPrivateMessage(text, ref command, ref sender) && Settings.Config.Main.Advanced.BotOwners.Contains(sender.ToLower().Trim())) { - string? response = ""; + CmdResult response = new(); PerformInternalCommand(command, ref response); - response = GetVerbatim(response); - foreach (char disallowedChar in McClient.GetDisallowedChatCharacters()) - { - response = response.Replace(disallowedChar.ToString(), String.Empty); - } - if (response.Length > 0) - { - SendPrivateMessage(sender, response); - } + SendPrivateMessage(sender, response.ToString()); } else if (Config.AutoTpaccept && IsTeleportRequest(text, ref sender) diff --git a/MinecraftClient/ChatBots/ReplayCapture.cs b/MinecraftClient/ChatBots/ReplayCapture.cs index 26315ef2..ee0c0a55 100644 --- a/MinecraftClient/ChatBots/ReplayCapture.cs +++ b/MinecraftClient/ChatBots/ReplayCapture.cs @@ -1,6 +1,11 @@ using System; using System.Collections.Generic; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; using MinecraftClient.Protocol; +using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots @@ -10,6 +15,8 @@ namespace MinecraftClient.ChatBots /// public class ReplayCapture : ChatBot { + public const string CommandName = "replay"; + public static Configs Config = new(); [TomlDoNotInlineObject] @@ -33,14 +40,80 @@ namespace MinecraftClient.ChatBots private ReplayHandler? replay; private int backupCounter = -1; - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { SetNetworkPacketEventEnabled(true); replay = new ReplayHandler(GetProtocolVersion()); replay.MetaData.serverName = GetServerHost() + GetServerPort(); backupCounter = Settings.DoubleToTick(Config.Backup_Interval); - RegisterChatBotCommand("replay", Translations.bot_replayCapture_cmd, "replay ", Command); + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CommandName) + .Executes(r => OnCommandHelp(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CommandName) + .Then(l => l.Literal("save") + .Executes(r => OnCommandSave(r.Source))) + .Then(l => l.Literal("stop") + .Executes(r => OnCommandStop(r.Source))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + ); + } + + public override void OnUnload(CommandDispatcher dispatcher) + { + dispatcher.Unregister(CommandName); + dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + } + + private int OnCommandHelp(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => string.Format(Translations.general_available_cmd, "save, stop") + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), +#pragma warning restore format // @formatter:on + }); + } + + private int OnCommandSave(CmdResult r) + { + try + { + if (replay!.RecordRunning) + { + replay.CreateBackupReplay(@"replay_recordings\" + replay.GetReplayDefaultName()); + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_replayCapture_created); + } + else + return r.SetAndReturn(CmdResult.Status.Fail, Translations.bot_replayCapture_restart); + } + catch (Exception e) + { + return r.SetAndReturn(CmdResult.Status.Fail, e.Message); + } + } + + private int OnCommandStop(CmdResult r) + { + try + { + if (replay!.RecordRunning) + { + replay.OnShutDown(); + return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_replayCapture_stopped); + } + else + return r.SetAndReturn(CmdResult.Status.Fail, Translations.bot_replayCapture_restart); + } + catch (Exception e) + { + return r.SetAndReturn(CmdResult.Status.Fail, e.Message); + } } public override void OnNetworkPacket(int packetID, List packetData, bool isLogin, bool isInbound) @@ -66,37 +139,5 @@ namespace MinecraftClient.ChatBots replay!.OnShutDown(); return base.OnDisconnect(reason, message); } - - public string Command(string cmd, string[] args) - { - try - { - if (replay!.RecordRunning) - { - if (args.Length > 0) - { - switch (args[0].ToLower()) - { - case "save": - { - replay.CreateBackupReplay(@"replay_recordings\" + replay.GetReplayDefaultName()); - return Translations.bot_replayCapture_created; - } - case "stop": - { - replay.OnShutDown(); - return Translations.bot_replayCapture_stopped; - } - } - } - return string.Format(Translations.general_available_cmd, "save, stop"); - } - else return Translations.bot_replayCapture_restart; - } - catch (Exception e) - { - return e.Message; - } - } } } diff --git a/MinecraftClient/ChatBots/Script.cs b/MinecraftClient/ChatBots/Script.cs index 11b9d97e..8f706e11 100644 --- a/MinecraftClient/ChatBots/Script.cs +++ b/MinecraftClient/ChatBots/Script.cs @@ -5,6 +5,9 @@ using System.IO; using System.Reflection; using System.Text; using System.Threading; +using Brigadier.NET; +using MinecraftClient.CommandHandler; +using MinecraftClient.Scripting; namespace MinecraftClient.ChatBots { @@ -124,7 +127,7 @@ namespace MinecraftClient.ChatBots return false; } - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { //Load the given file from the startup parameters if (LookForScript(ref file!)) diff --git a/MinecraftClient/ChatBots/ScriptScheduler.cs b/MinecraftClient/ChatBots/ScriptScheduler.cs index 21e9a977..bf8680a4 100644 --- a/MinecraftClient/ChatBots/ScriptScheduler.cs +++ b/MinecraftClient/ChatBots/ScriptScheduler.cs @@ -1,4 +1,5 @@ using System; +using MinecraftClient.Scripting; using Tomlet.Attributes; using static MinecraftClient.ChatBots.ScriptScheduler.Configs; diff --git a/MinecraftClient/ChatBots/TelegramBridge.cs b/MinecraftClient/ChatBots/TelegramBridge.cs index fb1a93ca..8c98d4cf 100644 --- a/MinecraftClient/ChatBots/TelegramBridge.cs +++ b/MinecraftClient/ChatBots/TelegramBridge.cs @@ -3,6 +3,11 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; +using MinecraftClient.Scripting; using Telegram.Bot; using Telegram.Bot.Exceptions; using Telegram.Bot.Polling; @@ -16,6 +21,8 @@ namespace MinecraftClient.ChatBots { public class TelegramBridge : ChatBot { + public const string CommandName = "tgbridge"; + private enum BridgeDirection { Both = 0, @@ -68,19 +75,74 @@ namespace MinecraftClient.ChatBots instance = this; } - public override void Initialize() + public override void Initialize(CommandDispatcher dispatcher) { - RegisterChatBotCommand("tgbridge", "bot.TelegramBridge.desc", "tgbridge direction ", OnTgCommand); + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CommandName) + .Executes(r => OnCommandHelp(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CommandName) + .Then(l => l.Literal("direction") + .Then(l => l.Literal("both") + .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Both))) + .Then(l => l.Literal("mc") + .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Minecraft))) + .Then(l => l.Literal("telegram") + .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Telegram)))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + ); Task.Run(async () => await MainAsync()); } - ~TelegramBridge() + public override void OnUnload(CommandDispatcher dispatcher) { + dispatcher.Unregister(CommandName); + dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); Disconnect(); } - public override void OnUnload() + private int OnCommandHelp(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => Translations.error_usage + ": /tgbridge direction " + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), +#pragma warning restore format // @formatter:on + }); + } + + private int OnCommandDirection(CmdResult r, BridgeDirection direction) + { + string bridgeName; + switch (direction) + { + case BridgeDirection.Both: + bridgeName = Translations.bot_TelegramBridge_direction_both; + bridgeDirection = BridgeDirection.Both; + break; + + case BridgeDirection.Minecraft: + bridgeName = Translations.bot_TelegramBridge_direction_minecraft; + bridgeDirection = BridgeDirection.Minecraft; + break; + + case BridgeDirection.Telegram: + bridgeName = Translations.bot_TelegramBridge_direction_Telegram; + bridgeDirection = BridgeDirection.Telegram; + break; + + default: + goto case BridgeDirection.Both; + } + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.bot_TelegramBridge_direction, bridgeName)); + } + + ~TelegramBridge() { Disconnect(); } @@ -110,47 +172,6 @@ namespace MinecraftClient.ChatBots return instance; } - private string OnTgCommand(string cmd, string[] args) - { - if (args.Length == 2) - { - if (args[0].ToLower().Equals("direction")) - { - string direction = args[1].ToLower().Trim(); - - string bridgeName; - switch (direction) - { - case "b": - case "both": - bridgeName = Translations.bot_TelegramBridge_direction_both; - bridgeDirection = BridgeDirection.Both; - break; - - case "mc": - case "minecraft": - bridgeName = Translations.bot_TelegramBridge_direction_minecraft; - bridgeDirection = BridgeDirection.Minecraft; - break; - - case "t": - case "tg": - case "telegram": - bridgeName = Translations.bot_TelegramBridge_direction_Telegram; - bridgeDirection = BridgeDirection.Telegram; - break; - - default: - return Translations.bot_TelegramBridge_invalid_direction; - } - - return string.Format(Translations.bot_TelegramBridge_direction, bridgeName); - }; - } - - return "dscbridge direction "; - } - public override void GetText(string text) { if (!CanSendMessages()) @@ -324,9 +345,8 @@ namespace MinecraftClient.ChatBots { var command = text[1..]; - string? result = ""; + CmdResult result = new(); PerformInternalCommand(command, ref result); - result = string.IsNullOrEmpty(result) ? "-" : result; await botClient.SendTextMessageAsync( chatId: chatId, diff --git a/MinecraftClient/ChatBots/TestBot.cs b/MinecraftClient/ChatBots/TestBot.cs index f96e9e8a..8b103535 100644 --- a/MinecraftClient/ChatBots/TestBot.cs +++ b/MinecraftClient/ChatBots/TestBot.cs @@ -1,4 +1,6 @@ -namespace MinecraftClient.ChatBots +using MinecraftClient.Scripting; + +namespace MinecraftClient.ChatBots { /// /// Example of message receiving. diff --git a/MinecraftClient/Command.cs b/MinecraftClient/Command.cs index ddb99ac3..6a6e8ae5 100644 --- a/MinecraftClient/Command.cs +++ b/MinecraftClient/Command.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Text; using Brigadier.NET; -using Microsoft.Extensions.Logging; -using MinecraftClient.Commands; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; namespace MinecraftClient { @@ -25,34 +25,19 @@ namespace MinecraftClient /// public abstract string CmdDesc { get; } - public abstract void RegisterCommand(McClient handler, CommandDispatcher dispatcher); - /// /// Get the translated version of command description. /// /// Translated command description public string GetCmdDescTranslated() { - string s = (string.IsNullOrEmpty(CmdUsage) || string.IsNullOrEmpty(CmdDesc)) ? "" : ": "; // If either one is empty, no colon : - return CmdUsage + s + CmdDesc; - } + char cmdChar = Settings.Config.Main.Advanced.InternalCmdChar.ToChar(); - public void LogUsage(Logger.ILogger logger) - { - logger.Info($"{Translations.Get("error.usage")}: {Settings.Config.Main.Advanced.InternalCmdChar.ToChar()}{CmdUsage}"); - } - - - public static int LogExecuteResult(Logger.ILogger logger, bool result) - { - logger.Info(Translations.Get(result ? "general.done" : "general.fail")); - return result ? 1 : 0; - } - - public static int LogExecuteResult(Logger.ILogger logger, int result) - { - logger.Info(Translations.Get(result > 0 ? "general.done" : "general.fail")); - return result; + StringBuilder sb = new(); + string s = (string.IsNullOrEmpty(CmdUsage) || string.IsNullOrEmpty(CmdDesc)) ? string.Empty : ": "; // If either one is empty, no colon : + sb.Append("§e").Append(cmdChar).Append(CmdUsage).Append("§r").Append(s).AppendLine(CmdDesc); + sb.Append(McClient.dispatcher.GetAllUsageString(CmdName, false)); + return sb.ToString(); } /// @@ -61,18 +46,9 @@ namespace MinecraftClient public abstract string CmdUsage { get; } /// - /// Perform the command + /// Register the command. /// - /// The full command, eg: 'mycommand arg1 arg2' - /// Local variables passed along with the command (may be null) - /// A confirmation/error message, or "" if no message - public abstract string Run(McClient handler, string command, Dictionary? localVars); - - /// - /// Return a list of aliases for this command. - /// Override this method if you wish to put aliases to the command - /// - public virtual IEnumerable GetCMDAliases() { return Array.Empty(); } + public abstract void RegisterCommand(McClient handler, CommandDispatcher dispatcher); /// /// Check if at least one argument has been passed to the command diff --git a/MinecraftClient/CommandHandler/ArgumentType/AccountNickArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/AccountNickArgumentType.cs new file mode 100644 index 00000000..09d11de1 --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/AccountNickArgumentType.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Suggestion; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class AccountNickArgumentType : ArgumentType + { + public override string Parse(IStringReader reader) + { + reader.SkipWhitespace(); + return reader.ReadString(); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + var accountList = Settings.Config.Main.Advanced.AccountList; + foreach (var account in accountList) + builder.Suggest(account.Key); + return builder.BuildFuture(); + } + } +} \ No newline at end of file diff --git a/MinecraftClient/CommandHandler/ArgumentType/AutoCraftRecipeNameArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/AutoCraftRecipeNameArgumentType.cs new file mode 100644 index 00000000..0d2bc0eb --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/AutoCraftRecipeNameArgumentType.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Suggestion; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class AutoCraftRecipeNameArgumentType : ArgumentType + { + public override string Parse(IStringReader reader) + { + reader.SkipWhitespace(); + return reader.ReadString(); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + var recipeList = Settings.Config.ChatBot.AutoCraft.Recipes; + foreach (var recipe in recipeList) + builder.Suggest(recipe.Name); + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/BotNameArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/BotNameArgumentType.cs new file mode 100644 index 00000000..0681ae0d --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/BotNameArgumentType.cs @@ -0,0 +1,29 @@ +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Suggestion; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class BotNameArgumentType : ArgumentType + { + public override string Parse(IStringReader reader) + { + reader.SkipWhitespace(); + return reader.ReadString(); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + McClient? client = CmdResult.client; + if (client != null) + { + var botList = client.GetLoadedChatBots(); + foreach (var bot in botList) + builder.Suggest(bot.GetType().Name); + } + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/EntityTypeArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/EntityTypeArgumentType.cs new file mode 100644 index 00000000..9ba6f999 --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/EntityTypeArgumentType.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Exceptions; +using Brigadier.NET.Suggestion; +using MinecraftClient.Mapping; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class EntityTypeArgumentType : ArgumentType + { + public override EntityType Parse(IStringReader reader) + { + reader.SkipWhitespace(); + string entity = reader.ReadString(); + if (Enum.TryParse(entity, true, out EntityType entityType)) + return entityType; + else + throw CommandSyntaxException.BuiltInExceptions.LiteralIncorrect().CreateWithContext(reader, entity); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + foreach (var result in Enum.GetNames(typeof(EntityType))) + builder.Suggest(result); + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/FarmerCropTypeArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/FarmerCropTypeArgumentType.cs new file mode 100644 index 00000000..16ecdad4 --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/FarmerCropTypeArgumentType.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Exceptions; +using Brigadier.NET.Suggestion; +using static MinecraftClient.ChatBots.Farmer; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class FarmerCropTypeArgumentType : ArgumentType + { + public override CropType Parse(IStringReader reader) + { + reader.SkipWhitespace(); + string inputStr = reader.ReadString(); + if (Enum.TryParse(inputStr, true, out CropType cropType)) + return cropType; + else + throw CommandSyntaxException.BuiltInExceptions.LiteralIncorrect().CreateWithContext(reader, inputStr); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + foreach (var result in Enum.GetNames(typeof(CropType))) + builder.Suggest(result); + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/InventoryActionArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/InventoryActionArgumentType.cs new file mode 100644 index 00000000..89616af6 --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/InventoryActionArgumentType.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Exceptions; +using Brigadier.NET.Suggestion; +using MinecraftClient.Inventory; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class InventoryActionArgumentType : ArgumentType + { + private WindowActionType[] SupportActions = new WindowActionType[] + { + WindowActionType.LeftClick, + WindowActionType.RightClick, + WindowActionType.MiddleClick, + WindowActionType.ShiftClick, + }; + + public override WindowActionType Parse(IStringReader reader) + { + reader.SkipWhitespace(); + string inputStr = reader.ReadString(); + foreach (var action in SupportActions) + { + string actionStr = action.ToString(); + if (string.Compare(inputStr, actionStr, true) == 0) + return action; + } + throw CommandSyntaxException.BuiltInExceptions.LiteralIncorrect().CreateWithContext(reader, inputStr); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + foreach (var action in SupportActions) + builder.Suggest(action.ToString()); + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs new file mode 100644 index 00000000..c697b493 --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs @@ -0,0 +1,34 @@ +using System; +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Suggestion; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class InventoryIdArgumentType : ArgumentType + { + public override int Parse(IStringReader reader) + { + reader.SkipWhitespace(); + return reader.ReadInt(); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + McClient? client = CmdResult.client; + if (client != null) + { + var invList = client.GetInventories(); + foreach (var inv in invList) + { + string invName = inv.Key.ToString(); + if (invName.StartsWith(builder.RemainingLowerCase, StringComparison.InvariantCultureIgnoreCase)) + builder.Suggest(invName); + } + } + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/ItemTypeArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/ItemTypeArgumentType.cs new file mode 100644 index 00000000..28ab93a3 --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/ItemTypeArgumentType.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Exceptions; +using Brigadier.NET.Suggestion; +using MinecraftClient.Inventory; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class ItemTypeArgumentType : ArgumentType + { + public override ItemType Parse(IStringReader reader) + { + reader.SkipWhitespace(); + string entity = reader.ReadString(); + if (Enum.TryParse(entity, true, out ItemType itemType)) + return itemType; + else + throw CommandSyntaxException.BuiltInExceptions.LiteralIncorrect().CreateWithContext(reader, entity); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + foreach (var result in Enum.GetNames(typeof(ItemType))) + builder.Suggest(result); + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/LocationArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/LocationArgumentType.cs new file mode 100644 index 00000000..79f51d62 --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/LocationArgumentType.cs @@ -0,0 +1,99 @@ +using System; +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Suggestion; +using MinecraftClient.Mapping; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class LocationArgumentType : ArgumentType + { + public override Location Parse(IStringReader reader) + { + int[] status = new int[3]; + double[] coords = new double[3]; + for (int i = 0; i < 3; ++i) + { + reader.SkipWhitespace(); + if (reader.Peek() == '~' || reader.Peek() == '~') + { + status[i] = 1; + reader.Next(); + if (reader.CanRead()) + { + char next = reader.Peek(); + if (char.IsDigit(next) || next == '.' || next == '-') + coords[i] = reader.ReadDouble(); + else if (next == '+') + { + reader.Next(); + coords[i] = reader.ReadDouble(); + } + else coords[i] = 0; + } + else coords[i] = 0; + } + else + { + status[i] = 0; + coords[i] = reader.ReadDouble(); + } + } + + return new Location(coords[0], coords[1], coords[2], (byte)(status[0] | status[1] << 1 | status[2] << 2)); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + McClient? client = CmdResult.client; + string[] args = builder.Remaining.Split(' ', StringSplitOptions.TrimEntries); + if (args.Length == 0 || (args.Length == 1 && string.IsNullOrWhiteSpace(args[0]))) + { + if (client != null) + { + Location current = client.GetCurrentLocation(); + builder.Suggest(string.Format("{0:0.00}", current.X)); + builder.Suggest(string.Format("{0:0.00} {1:0.00}", current.X, current.Y)); + builder.Suggest(string.Format("{0:0.00} {1:0.00} {2:0.00}", current.X, current.Y, current.Z)); + } + else + { + builder.Suggest("~"); + builder.Suggest("~ ~"); + builder.Suggest("~ ~ ~"); + } + } + else if (args.Length == 1 || (args.Length == 2 && string.IsNullOrWhiteSpace(args[1]))) + { + string add = args.Length == 1 ? " " : string.Empty; + if (client != null) + { + Location current = client.GetCurrentLocation(); + builder.Suggest(string.Format("{0}{2}{1:0.00}", builder.Remaining, current.Y, add)); + builder.Suggest(string.Format("{0}{3}{1:0.00} {2:0.00}", builder.Remaining, current.Y, current.Z, add)); + } + else + { + builder.Suggest(builder.Remaining + add + "~"); + builder.Suggest(builder.Remaining + add + "~ ~"); + } + } + else if (args.Length == 2 || (args.Length == 3 && string.IsNullOrWhiteSpace(args[2]))) + { + string add = args.Length == 2 ? " " : string.Empty; + if (client != null) + { + Location current = client.GetCurrentLocation(); + builder.Suggest(string.Format("{0}{2}{1:0.00}", builder.Remaining, current.Z, add)); + } + else + { + builder.Suggest(builder.Remaining + add + "~"); + } + } + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/MapBotMapIdArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/MapBotMapIdArgumentType.cs new file mode 100644 index 00000000..55c05020 --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/MapBotMapIdArgumentType.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Suggestion; +using MinecraftClient.ChatBots; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class MapBotMapIdArgumentType : ArgumentType + { + public override int Parse(IStringReader reader) + { + reader.SkipWhitespace(); + return reader.ReadInt(); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + McClient? client = CmdResult.client; + if (client != null) + { + var bot = (Map?)client.GetLoadedChatBots().Find(bot => bot.GetType().Name == "Map"); + if (bot != null) + { + var mapList = bot.cachedMaps; + foreach (var map in mapList) + { + string mapName = map.Key.ToString(); + if (mapName.StartsWith(builder.RemainingLowerCase, StringComparison.InvariantCultureIgnoreCase)) + builder.Suggest(mapName); + } + } + } + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/PlayerNameArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/PlayerNameArgumentType.cs new file mode 100644 index 00000000..d8b88093 --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/PlayerNameArgumentType.cs @@ -0,0 +1,36 @@ +using System.Linq; +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Suggestion; +using MinecraftClient.Mapping; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class PlayerNameArgumentType : ArgumentType + { + public override string Parse(IStringReader reader) + { + reader.SkipWhitespace(); + return reader.ReadString(); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + McClient? client = CmdResult.client; + if (client != null) + { + var entityList = client.GetEntities().Values.ToList(); + foreach (var entity in entityList) + { + if (entity.Type != EntityType.Player || string.IsNullOrWhiteSpace(entity.Name)) + continue; + builder.Suggest(entity.Name); + } + builder.Suggest(client.GetUsername()); + } + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/ServerNickArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/ServerNickArgumentType.cs new file mode 100644 index 00000000..ae520f7d --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/ServerNickArgumentType.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Suggestion; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class ServerNickArgumentType : ArgumentType + { + public override string Parse(IStringReader reader) + { + reader.SkipWhitespace(); + return reader.ReadString(); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + var serverList = Settings.Config.Main.Advanced.ServerList; + foreach (var server in serverList) + builder.Suggest(server.Key); + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/TupleArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/TupleArgumentType.cs new file mode 100644 index 00000000..55157d99 --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/TupleArgumentType.cs @@ -0,0 +1,18 @@ +using System; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class TupleArgumentType : ArgumentType> + { + public override Tuple Parse(IStringReader reader) + { + reader.SkipWhitespace(); + int int1 = reader.ReadInt(); + reader.SkipWhitespace(); + int int2 = reader.ReadInt(); + return new(int1, int2); + } + } +} diff --git a/MinecraftClient/CommandHandler/CmdResult.cs b/MinecraftClient/CommandHandler/CmdResult.cs new file mode 100644 index 00000000..b5477763 --- /dev/null +++ b/MinecraftClient/CommandHandler/CmdResult.cs @@ -0,0 +1,96 @@ +using System; + +namespace MinecraftClient.CommandHandler +{ + public class CmdResult + { + public static readonly CmdResult Empty = new(); + + internal static McClient? client; + + public enum Status + { + NotRun = int.MinValue, + FailChunkNotLoad = -4, + FailNeedEntity = -3, + FailNeedInventory = -2, + FailNeedTerrain = -1, + Fail = 0, + Done = 1, + } + + public CmdResult() + { + this.status = Status.NotRun; + this.result = null; + } + + public Status status; + + public string? result; + + public int SetAndReturn(Status status) + { + this.status = status; + this.result = status switch + { +#pragma warning disable format // @formatter:off + Status.NotRun => null, + Status.FailChunkNotLoad => null, + Status.FailNeedEntity => Translations.extra_entity_required, + Status.FailNeedInventory => Translations.extra_inventory_required, + Status.FailNeedTerrain => Translations.extra_terrainandmovement_required, + Status.Fail => Translations.general_fail, + Status.Done => null, + _ => null, +#pragma warning restore format // @formatter:on + }; + return Convert.ToInt32(this.status); + } + + public int SetAndReturn(Status status, string? result) + { + this.status = status; + this.result = result; + return Convert.ToInt32(this.status); + } + + public int SetAndReturn(int code, string? result) + { + this.status = (Status)Enum.ToObject(typeof(Status), code); + if (!Enum.IsDefined(typeof(Status), status)) + throw new InvalidOperationException($"{code} is not a legal return value."); + this.result = result; + return code; + } + + public int SetAndReturn(bool result) + { + this.status = result ? Status.Done : Status.Fail; + this.result = result ? Translations.general_done : Translations.general_fail; + return Convert.ToInt32(this.status); + } + + public int SetAndReturn(string? result) + { + this.status = Status.Done; + this.result = result; + return Convert.ToInt32(this.status); + } + + public int SetAndReturn(string? resultstr, bool result) + { + this.status = result ? Status.Done : Status.Fail; + this.result = resultstr; + return Convert.ToInt32(this.status); + } + + public override string ToString() + { + if (result != null) + return result; + else + return status.ToString(); + } + } +} diff --git a/MinecraftClient/CommandHandler/MccArguments.cs b/MinecraftClient/CommandHandler/MccArguments.cs new file mode 100644 index 00000000..ef6fbf8a --- /dev/null +++ b/MinecraftClient/CommandHandler/MccArguments.cs @@ -0,0 +1,104 @@ +using System; +using Brigadier.NET.Context; +using MinecraftClient.CommandHandler.ArgumentType; + +namespace MinecraftClient.CommandHandler +{ + public static class MccArguments + { + public static LocationArgumentType Location() + { + return new LocationArgumentType(); + } + + public static Mapping.Location GetLocation(CommandContext context, string name) + { + return context.GetArgument(name); + } + + public static TupleArgumentType Tuple() + { + return new TupleArgumentType(); + } + + public static Tuple GetTuple(CommandContext context, string name) + { + return context.GetArgument>(name); + } + + public static EntityTypeArgumentType EntityType() + { + return new EntityTypeArgumentType(); + } + + public static Mapping.EntityType GetEntityType(CommandContext context, string name) + { + return context.GetArgument(name); + } + + public static ItemTypeArgumentType ItemType() + { + return new ItemTypeArgumentType(); + } + + public static Inventory.ItemType GetItemType(CommandContext context, string name) + { + return context.GetArgument(name); + } + + public static BotNameArgumentType BotName() + { + return new BotNameArgumentType(); + } + + public static ServerNickArgumentType ServerNick() + { + return new ServerNickArgumentType(); + } + + public static AccountNickArgumentType AccountNick() + { + return new AccountNickArgumentType(); + } + + public static InventoryIdArgumentType InventoryId() + { + return new InventoryIdArgumentType(); + } + + public static InventoryActionArgumentType InventoryAction() + { + return new InventoryActionArgumentType(); + } + + public static Inventory.WindowActionType GetInventoryAction(CommandContext context, string name) + { + return context.GetArgument(name); + } + + public static AutoCraftRecipeNameArgumentType AutoCraftRecipeName() + { + return new AutoCraftRecipeNameArgumentType(); + } + + public static FarmerCropTypeArgumentType FarmerCropType() + { + return new FarmerCropTypeArgumentType(); + } + + public static ChatBots.Farmer.CropType GetFarmerCropType(CommandContext context, string name) + { + return context.GetArgument(name); + } + + public static PlayerNameArgumentType PlayerName() + { + return new PlayerNameArgumentType(); + } + + public static MapBotMapIdArgumentType MapBotMapId() + { + return new MapBotMapIdArgumentType(); + } + } +} diff --git a/MinecraftClient/CommandHandler/Patch/CommandDispatcherExtensions.cs b/MinecraftClient/CommandHandler/Patch/CommandDispatcherExtensions.cs new file mode 100644 index 00000000..341fa4ae --- /dev/null +++ b/MinecraftClient/CommandHandler/Patch/CommandDispatcherExtensions.cs @@ -0,0 +1,36 @@ +using System.Text; +using Brigadier.NET; + +namespace MinecraftClient.CommandHandler.Patch +{ + public static class CommandDispatcherExtensions + { + /** + * This method unregisteres a previously declared command + * + * @param The name of the command to remove + */ + public static void Unregister(this CommandDispatcher commandDispatcher, string commandname) + { + commandDispatcher.GetRoot().RemoveChild(commandname); + } + + public static string GetAllUsageString(this CommandDispatcher commandDispatcher, string commandName, bool restricted) + { + char cmdChar = Settings.Config.Main.Advanced.InternalCmdChar.ToChar(); + string[] usages = commandDispatcher.GetAllUsage(commandDispatcher.GetRoot().GetChild(commandName), new(), restricted); + StringBuilder sb = new(); + sb.AppendLine("All Usages:"); + foreach (var usage in usages) + { + sb.Append(cmdChar).Append(commandName).Append(' '); + if (usage.Length > 0 && usage[0] == '_') + sb.AppendLine(usage.Replace("_help -> ", $"_help -> {cmdChar}help ")); + else + sb.AppendLine(usage); + } + sb.Remove(sb.Length - 1, 1); + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/MinecraftClient/CommandHandler/Patch/CommandNodeExtensions.cs b/MinecraftClient/CommandHandler/Patch/CommandNodeExtensions.cs new file mode 100644 index 00000000..23e2a87f --- /dev/null +++ b/MinecraftClient/CommandHandler/Patch/CommandNodeExtensions.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Reflection; +using Brigadier.NET.Tree; + +namespace MinecraftClient.CommandHandler.Patch +{ + public static class CommandNodeExtensions + { + public static void RemoveChild(this CommandNode commandNode, string name) + { + var children = (IDictionary>) + typeof(CommandNode) + .GetField("_children", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)! + .GetValue(commandNode)!; + var literals = (IDictionary>) + typeof(CommandNode) + .GetField("_literals", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)! + .GetValue(commandNode)!; + var arguments = (IDictionary>) + typeof(CommandNode) + .GetField("_arguments", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)! + .GetValue(commandNode)!; + + children.Remove(name); + literals.Remove(name); + } + } +} \ No newline at end of file diff --git a/MinecraftClient/Commands/Animation.cs b/MinecraftClient/Commands/Animation.cs index 54efe765..41f7affe 100644 --- a/MinecraftClient/Commands/Animation.cs +++ b/MinecraftClient/Commands/Animation.cs @@ -1,7 +1,6 @@ -using System; -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -11,76 +10,44 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "animation "; } } public override string CmdDesc { get { return Translations.cmd_animation_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { - dispatcher.Register(l => - l.Literal("help").Then(l => - l.Literal(CmdName).Executes(c => { - LogUsage(handler.Log); - return 1; - }) + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + .Then(l => l.Literal("mainhand") + .Executes(r => GetUsage(r.Source, "mainhand"))) + .Then(l => l.Literal("offhand") + .Executes(r => GetUsage(r.Source, "offhand"))) ) ); - dispatcher.Register(l => - l.Literal(CmdName).Then(l => - l.Literal("mainhand") - .Executes(c => { - return LogExecuteResult(handler.Log, handler.DoAnimation(0)); - }) - ) - ); - dispatcher.Register(l => - l.Literal(CmdName).Then(l => - l.Literal("0") - .Redirect(dispatcher.GetRoot().GetChild(CmdName).GetChild("mainhand")) - ) - ); - - dispatcher.Register(l => - l.Literal(CmdName).Then(l => - l.Literal("offhand") - .Executes(c => { - return LogExecuteResult(handler.Log, handler.DoAnimation(1)); - }) - ) - ); - dispatcher.Register(l => - l.Literal(CmdName).Then(l => - l.Literal("1") - .Redirect(dispatcher.GetRoot().GetChild(CmdName).GetChild("offhand")) - ) + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => DoAnimation(r.Source, handler, mainhand: true)) + .Then(l => l.Literal("mainhand") + .Executes(r => DoAnimation(r.Source, handler, mainhand: true))) + .Then(l => l.Literal("offhand") + .Executes(r => DoAnimation(r.Source, handler, mainhand: false))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - string[] args = GetArgs(command); - if (args.Length > 0) - { - if (args[0] == "mainhand" || args[0] == "0") - { - handler.DoAnimation(0); - return Translations.general_done; - } - else if (args[0] == "offhand" || args[0] == "1") - { - handler.DoAnimation(1); - return Translations.general_done; - } - else - { - return GetCmdDescTranslated(); - } - } - else - { - return GetCmdDescTranslated(); - } - } - else return GetCmdDescTranslated(); +#pragma warning disable format // @formatter:off + "mainhand" => GetCmdDescTranslated(), + "offhand" => GetCmdDescTranslated(), + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private static int DoAnimation(CmdResult r, McClient handler, bool mainhand) + { + return r.SetAndReturn(handler.DoAnimation(mainhand ? 1 : 0)); } } } diff --git a/MinecraftClient/Commands/Bed.cs b/MinecraftClient/Commands/Bed.cs index 6d7e774c..fa6e6958 100644 --- a/MinecraftClient/Commands/Bed.cs +++ b/MinecraftClient/Commands/Bed.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Threading.Tasks; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { @@ -14,142 +16,162 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "bed leave|sleep |sleep "; } } public override string CmdDesc { get { return Translations.cmd_bed_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + .Then(l => l.Literal("leave") + .Executes(r => GetUsage(r.Source, "leave"))) + .Then(l => l.Literal("sleep") + .Executes(r => GetUsage(r.Source, "sleep"))) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Literal("leave") + .Executes(r => DoLeaveBed(r.Source, handler))) + .Then(l => l.Literal("sleep") + .Then(l => l.Argument("Location", MccArguments.Location()) + .Executes(r => DoSleepBedWithLocation(r.Source, handler, MccArguments.GetLocation(r, "Location")))) + .Then(l => l.Argument("Radius", Arguments.Double()) + .Executes(r => DoSleepBedWithRadius(r.Source, handler, Arguments.GetDouble(r, "Radius"))))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - string[] args = GetArgs(command); - - if (args.Length >= 1) + return r.SetAndReturn(cmd switch { - string subcommand = args[0].ToLower().Trim(); +#pragma warning disable format // @formatter:off + "leave" => GetCmdDescTranslated(), + "sleep" => GetCmdDescTranslated(), + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } - if (subcommand.Equals("leave") || subcommand.Equals("l")) + private static int DoLeaveBed(CmdResult r, McClient handler) + { + return r.SetAndReturn(Translations.cmd_bed_leaving, handler.SendEntityAction(Protocol.EntityActionType.LeaveBed)); + } + + private static int DoSleepBedWithRadius(CmdResult r, McClient handler, double radius) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + handler.Log.Info(string.Format(Translations.cmd_bed_searching, radius)); + + Location current = handler.GetCurrentLocation(); + Location bedLocation = current; + + Material[] bedMaterialList = new Material[] + { + Material.BlackBed, + Material.BlueBed, + Material.BrownBed, + Material.CyanBed, + Material.GrayBed, + Material.GreenBed, + Material.LightBlueBed, + Material.LightGrayBed, + Material.LimeBed, + Material.MagentaBed, + Material.OrangeBed, + Material.PinkBed, + Material.PurpleBed, + Material.RedBed, + Material.WhiteBed, + Material.YellowBed + }; + + bool found = false; + foreach (Material material in bedMaterialList) + { + List beds = handler.GetWorld().FindBlock(current, material, radius); + + if (beds.Count > 0) { - handler.SendEntityAction(Protocol.EntityActionType.LeaveBed); - return Translations.cmd_bed_leaving; - } - - if (subcommand.Equals("sleep") || subcommand.Equals("s")) - { - if (!handler.GetTerrainEnabled()) - return Translations.error_terrain_not_enabled; - - if (args.Length == 2) - { - if (!int.TryParse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture, out int radius)) - return CmdUsage; - - handler.GetLogger().Info(string.Format(Translations.cmd_bed_searching, radius)); - - Location current = handler.GetCurrentLocation(); - Location bedLocation = current; - - Material[] bedMaterialList = new Material[]{ - Material.BlackBed, - Material.BlueBed, - Material.BrownBed, - Material.CyanBed, - Material.GrayBed, - Material.GreenBed, - Material.LightBlueBed, - Material.LightGrayBed, - Material.LimeBed, - Material.MagentaBed, - Material.OrangeBed, - Material.PinkBed, - Material.PurpleBed, - Material.RedBed, - Material.WhiteBed, - Material.YellowBed - }; - - bool found = false; - foreach (Material material in bedMaterialList) - { - List beds = handler.GetWorld().FindBlock(current, material, radius); - - if (beds.Count > 0) - { - found = true; - bedLocation = beds.First(); - break; - } - } - - if (!found) - return Translations.cmd_bed_bed_not_found; - - handler.Log.Info(string.Format(Translations.cmd_bed_found_a_bed_at, bedLocation.X, bedLocation.Y, bedLocation.Z)); - - if (!Movement.CheckChunkLoading(handler.GetWorld(), current, bedLocation)) - return string.Format(Translations.cmd_move_chunk_not_loaded, bedLocation.X, bedLocation.Y, bedLocation.Z); - - if (handler.MoveTo(bedLocation)) - { - Task.Factory.StartNew(() => - { - bool atTheLocation = false; - DateTime timeout = DateTime.Now.AddSeconds(60); - - while (DateTime.Now < timeout) - { - if (handler.GetCurrentLocation() == bedLocation || handler.GetCurrentLocation().Distance(bedLocation) <= 2.0) - { - atTheLocation = true; - break; - } - } - - if (!atTheLocation) - { - handler.Log.Info(string.Format(Translations.cmd_bed_failed_to_reach_in_time, bedLocation.X, bedLocation.Y, bedLocation.Z)); - return; - } - - handler.Log.Info(string.Format(Translations.cmd_bed_moving, bedLocation.X, bedLocation.Y, bedLocation.Z)); - - bool res = handler.PlaceBlock(bedLocation, Direction.Down); - - handler.Log.Info(string.Format( - Translations.cmd_bed_trying_to_use, - bedLocation.X, - bedLocation.Y, - bedLocation.Z, - res ? Translations.cmd_bed_in : Translations.cmd_bed_not_in - )); - }); - - return ""; - } - - return Translations.cmd_bed_cant_reach_safely; - } - - if (args.Length >= 3) - { - Location block = Location.Parse(handler.GetCurrentLocation(), args[1], args[2], args[3]).ToFloor(); - Location blockCenter = block.ToCenter(); - - if (!handler.GetWorld().GetBlock(block).Type.IsBed()) - return string.Format(Translations.cmd_bed_not_a_bed, blockCenter.X, blockCenter.Y, blockCenter.Z); - - bool res = handler.PlaceBlock(block, Direction.Down); - - return string.Format( - Translations.cmd_bed_trying_to_use, - blockCenter.X, - blockCenter.Y, - blockCenter.Z, - res ? Translations.cmd_bed_in : Translations.cmd_bed_not_in - ); - } + found = true; + bedLocation = beds.First(); + break; } } - return CmdUsage; + if (!found) + return r.SetAndReturn(Status.Fail, Translations.cmd_bed_bed_not_found); + + handler.Log.Info(string.Format(Translations.cmd_bed_found_a_bed_at, bedLocation.X, bedLocation.Y, bedLocation.Z)); + + if (!Movement.CheckChunkLoading(handler.GetWorld(), current, bedLocation)) + return r.SetAndReturn(Status.FailChunkNotLoad, + string.Format(Translations.cmd_move_chunk_not_loaded, bedLocation.X, bedLocation.Y, bedLocation.Z)); + + if (handler.MoveTo(bedLocation)) + { + Task.Factory.StartNew(() => + { + bool atTheLocation = false; + DateTime timeout = DateTime.Now.AddSeconds(60); + + while (DateTime.Now < timeout) + { + if (handler.GetCurrentLocation() == bedLocation || handler.GetCurrentLocation().Distance(bedLocation) <= 2.0) + { + atTheLocation = true; + break; + } + } + + if (!atTheLocation) + { + handler.Log.Info(string.Format(Translations.cmd_bed_failed_to_reach_in_time, bedLocation.X, bedLocation.Y, bedLocation.Z)); + return; + } + + handler.Log.Info(string.Format(Translations.cmd_bed_moving, bedLocation.X, bedLocation.Y, bedLocation.Z)); + + bool res = handler.PlaceBlock(bedLocation, Direction.Down); + + handler.Log.Info(string.Format( + Translations.cmd_bed_trying_to_use, + bedLocation.X, + bedLocation.Y, + bedLocation.Z, + res ? Translations.cmd_bed_in : Translations.cmd_bed_not_in + )); + }); + + return r.SetAndReturn(Status.Done); + } + else + { + return r.SetAndReturn(Status.Fail, Translations.cmd_bed_cant_reach_safely); + } + } + + private static int DoSleepBedWithLocation(CmdResult r, McClient handler, Location block) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + block.ToAbsolute(handler.GetCurrentLocation()); + Location blockCenter = block.ToCenter(); + + if (!handler.GetWorld().GetBlock(block).Type.IsBed()) + return r.SetAndReturn(Status.Fail, + string.Format(Translations.cmd_bed_not_a_bed, blockCenter.X, blockCenter.Y, blockCenter.Z)); + + return r.SetAndReturn(Status.Done, string.Format( + Translations.cmd_bed_trying_to_use, + blockCenter.X, + blockCenter.Y, + blockCenter.Z, + handler.PlaceBlock(block, Direction.Down) ? Translations.cmd_bed_in : Translations.cmd_bed_not_in + )); } } } \ No newline at end of file diff --git a/MinecraftClient/Commands/BlockInfo.cs b/MinecraftClient/Commands/BlockInfo.cs index d2165eee..dcc82d61 100644 --- a/MinecraftClient/Commands/BlockInfo.cs +++ b/MinecraftClient/Commands/BlockInfo.cs @@ -1,7 +1,9 @@ -using System.Collections.Generic; -using System.Text; +using System.Text; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { @@ -11,40 +13,60 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "blockinfo [-s]"; } } public override string CmdDesc { get { return Translations.cmd_blockinfo_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + .Then(l => l.Literal("-s") + .Executes(r => GetUsage(r.Source, "-s"))) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => LogBlockInfo(r.Source, handler, handler.GetCurrentLocation(), false)) + .Then(l => l.Literal("-s") + .Executes(r => LogBlockInfo(r.Source, handler, handler.GetCurrentLocation(), true))) + .Then(l => l.Argument("Location", MccArguments.Location()) + .Executes(r => LogBlockInfo(r.Source, handler, MccArguments.GetLocation(r, "Location"), false)) + .Then(l => l.Literal("-s") + .Executes(r => LogBlockInfo(r.Source, handler, MccArguments.GetLocation(r, "Location"), true)))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + "-s" => GetCmdDescTranslated(), + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private static int LogBlockInfo(CmdResult r, McClient handler, Location targetBlock, bool reportSurrounding) { if (!handler.GetTerrainEnabled()) - return Translations.error_terrain_not_enabled; + return r.SetAndReturn(Status.FailNeedTerrain); - string[] args = GetArgs(command); - - if (args.Length < 3) - return CmdUsage; - - bool reportSurrounding = args.Length >= 4 && args[3].Equals("-s", System.StringComparison.OrdinalIgnoreCase); - - Location current = handler.GetCurrentLocation(); - Location targetBlockLocation = Location.Parse(current, args[0], args[1], args[2]); - - Block block = handler.GetWorld().GetBlock(targetBlockLocation); + targetBlock.ToAbsolute(handler.GetCurrentLocation()); + Block block = handler.GetWorld().GetBlock(targetBlock); handler.Log.Info($"{Translations.cmd_blockinfo_BlockType}: {block.GetTypeString()}"); - if (reportSurrounding) { StringBuilder sb = new(); sb.AppendLine($"{Translations.cmd_blockinfo_BlocksAround}:"); - Block blockXPositive = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X + 1, targetBlockLocation.Y, targetBlockLocation.Z)); - Block blockXNegative = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X - 1, targetBlockLocation.Y, targetBlockLocation.Z)); - Block blockYPositive = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X, targetBlockLocation.Y + 1, targetBlockLocation.Z)); - Block blockYNegative = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X, targetBlockLocation.Y - 1, targetBlockLocation.Z)); - Block blockZPositive = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X, targetBlockLocation.Y, targetBlockLocation.Z + 1)); - Block blockZNegative = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X, targetBlockLocation.Y, targetBlockLocation.Z - 1)); + Block blockXPositive = handler.GetWorld().GetBlock(new Location(targetBlock.X + 1, targetBlock.Y, targetBlock.Z)); + Block blockXNegative = handler.GetWorld().GetBlock(new Location(targetBlock.X - 1, targetBlock.Y, targetBlock.Z)); + Block blockYPositive = handler.GetWorld().GetBlock(new Location(targetBlock.X, targetBlock.Y + 1, targetBlock.Z)); + Block blockYNegative = handler.GetWorld().GetBlock(new Location(targetBlock.X, targetBlock.Y - 1, targetBlock.Z)); + Block blockZPositive = handler.GetWorld().GetBlock(new Location(targetBlock.X, targetBlock.Y, targetBlock.Z + 1)); + Block blockZNegative = handler.GetWorld().GetBlock(new Location(targetBlock.X, targetBlock.Y, targetBlock.Z - 1)); sb.AppendLine($"[X {Translations.cmd_blockinfo_Positive}] {Translations.cmd_blockinfo_BlockType}: {blockXPositive.GetTypeString()}"); sb.AppendLine($"[X {Translations.cmd_blockinfo_Negative}] {Translations.cmd_blockinfo_BlockType}: {blockXNegative.GetTypeString()}"); @@ -61,9 +83,7 @@ namespace MinecraftClient.Commands handler.Log.Info(sb.ToString()); } - - - return ""; + return r.SetAndReturn(Status.Done); } } } diff --git a/MinecraftClient/Commands/Bots.cs b/MinecraftClient/Commands/Bots.cs index 9d4233f6..58057552 100644 --- a/MinecraftClient/Commands/Bots.cs +++ b/MinecraftClient/Commands/Bots.cs @@ -1,7 +1,9 @@ using System; -using System.Collections.Generic; using System.Text; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using MinecraftClient.Scripting; namespace MinecraftClient.Commands { @@ -11,69 +13,82 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "bots [list|unload ]"; } } public override string CmdDesc { get { return Translations.cmd_bots_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + .Then(l => l.Literal("list") + .Executes(r => GetUsage(r.Source, "list"))) + .Then(l => l.Literal("unload") + .Executes(r => GetUsage(r.Source, "unload"))) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => DoListBot(r.Source, handler)) + .Then(l => l.Literal("list") + .Executes(r => DoListBot(r.Source, handler))) + .Then(l => l.Literal("unload") + .Then(l => l.Argument("BotName", MccArguments.BotName()) + .Executes(r => DoUnloadBot(r.Source, handler, Arguments.GetString(r, "BotName"))))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - string[] args = GetArgs(command); +#pragma warning disable format // @formatter:off + "list" => GetCmdDescTranslated(), + "unload" => GetCmdDescTranslated(), + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } - if (args.Length == 1) - { - if (args[0].Equals("list", StringComparison.OrdinalIgnoreCase)) - { - StringBuilder sb = new(); + private int DoListBot(CmdResult r, McClient handler) + { + int length = handler.GetLoadedChatBots().Count; + if (length == 0) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_bots_noloaded); - int length = handler.GetLoadedChatBots().Count; - - if (length == 0) - return Translations.cmd_bots_noloaded; - - for (int i = 0; i < length; i++) - { - sb.Append(handler.GetLoadedChatBots()[i].GetType().Name); - - if (i != length - 1) - sb.Append(" ,"); - - } - - return Translations.cmd_bots_list + ": " + sb.ToString(); - } - - } - else if (args.Length == 2) - { - if (args[0].Equals("unload", StringComparison.OrdinalIgnoreCase)) - { - string botName = args[1].Trim(); - - if (botName.ToLower().Equals("all", StringComparison.OrdinalIgnoreCase)) - { - if (handler.GetLoadedChatBots().Count == 0) - return Translations.cmd_bots_noloaded; - - handler.UnloadAllBots(); - return Translations.cmd_bots_unloaded_all; - } - else - { - ChatBot? bot = handler.GetLoadedChatBots().Find(bot => bot.GetType().Name.ToLower() == botName.ToLower()); - - if (bot == null) - return string.Format(Translations.cmd_bots_notfound, botName); - - handler.BotUnLoad(bot); - return string.Format(Translations.cmd_bots_unloaded, botName); - } - } - } + StringBuilder sb = new(); + for (int i = 0; i < length; i++) + { + sb.Append(handler.GetLoadedChatBots()[i].GetType().Name); + if (i != length - 1) + sb.Append(" ,"); } - return GetCmdDescTranslated(); + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_bots_list + ": " + sb.ToString()); + } + + private int DoUnloadBot(CmdResult r, McClient handler, string botName) + { + if (botName.ToLower().Equals("all", StringComparison.OrdinalIgnoreCase)) + { + if (handler.GetLoadedChatBots().Count == 0) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_bots_noloaded); + else + { + handler.UnloadAllBots(); + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_bots_unloaded_all); + } + } + else + { + ChatBot? bot = handler.GetLoadedChatBots().Find(bot => bot.GetType().Name.ToLower() == botName.ToLower()); + if (bot == null) + return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_bots_notfound, botName)); + else + { + handler.BotUnLoad(bot); + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_bots_unloaded, botName)); + } + } } } } diff --git a/MinecraftClient/Commands/ChangeSlot.cs b/MinecraftClient/Commands/ChangeSlot.cs index ae74604f..4a565de8 100644 --- a/MinecraftClient/Commands/ChangeSlot.cs +++ b/MinecraftClient/Commands/ChangeSlot.cs @@ -1,6 +1,7 @@ -using System; -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { @@ -10,39 +11,41 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "changeslot <1-9>"; } } public override string CmdDesc { get { return Translations.cmd_changeSlot_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("Slot", Arguments.Integer(1, 9)) + .Executes(r => DoChangeSlot(r.Source, handler, Arguments.GetInteger(r, "Slot")))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoChangeSlot(CmdResult r, McClient handler, int slot) { if (!handler.GetInventoryEnabled()) - return Translations.extra_inventory_required; + return r.SetAndReturn(Status.FailNeedInventory); - if (HasArg(command)) - { - short slot; - try - { - slot = Convert.ToInt16(GetArg(command)); - } - catch (FormatException) - { - return Translations.cmd_changeSlot_nan; - } - if (slot >= 1 && slot <= 9) - { - if (handler.ChangeSlot(slot -= 1)) - { - return string.Format(Translations.cmd_changeSlot_changed, (slot += 1)); - } - else - { - return Translations.cmd_changeSlot_fail; - } - } - } - return GetCmdDescTranslated(); + if (handler.ChangeSlot((short)(slot - 1))) + return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_changeSlot_changed, slot)); + else + return r.SetAndReturn(Status.Fail, Translations.cmd_changeSlot_fail); } } } diff --git a/MinecraftClient/Commands/Chunk.cs b/MinecraftClient/Commands/Chunk.cs index a84fea87..5d225db1 100644 --- a/MinecraftClient/Commands/Chunk.cs +++ b/MinecraftClient/Commands/Chunk.cs @@ -1,9 +1,10 @@ using System; -using System.Collections.Generic; -using System.Globalization; using System.Text; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { @@ -13,252 +14,267 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "chunk status [chunkX chunkZ|locationX locationY locationZ]"; } } public override string CmdDesc { get { return Translations.cmd_chunk_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + .Then(l => l.Literal("status") + .Executes(r => GetUsage(r.Source, "status"))) + .Then(l => l.Literal("_setloading") + .Executes(r => GetUsage(r.Source, "_setloading"))) + .Then(l => l.Literal("_setloaded") + .Executes(r => GetUsage(r.Source, "_setloaded"))) + .Then(l => l.Literal("_delete") + .Executes(r => GetUsage(r.Source, "_delete"))) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Literal("status") + .Executes(r => LogChunkStatus(r.Source, handler)) + .Then(l => l.Argument("Location", MccArguments.Location()) + .Executes(r => LogChunkStatus(r.Source, handler, pos: MccArguments.GetLocation(r, "Location")))) + .Then(l => l.Argument("Chunk", MccArguments.Tuple()) + .Executes(r => LogChunkStatus(r.Source, handler, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) + .Then(l => l.Literal("_setloading") + .Then(l => l.Argument("Location", MccArguments.Location()) + .Executes(r => DebugSetLoading(r.Source, handler, pos: MccArguments.GetLocation(r, "Location")))) + .Then(l => l.Argument("Chunk", MccArguments.Tuple()) + .Executes(r => DebugSetLoading(r.Source, handler, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) + .Then(l => l.Literal("_setloaded") + .Then(l => l.Argument("Location", MccArguments.Location()) + .Executes(r => DebugSetLoaded(r.Source, handler, pos: MccArguments.GetLocation(r, "Location")))) + .Then(l => l.Argument("Chunk", MccArguments.Tuple()) + .Executes(r => DebugSetLoaded(r.Source, handler, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) + .Then(l => l.Literal("_delete") + .Then(l => l.Argument("Location", MccArguments.Location()) + .Executes(r => DebugDelete(r.Source, handler, pos: MccArguments.GetLocation(r, "Location")))) + .Then(l => l.Argument("Chunk", MccArguments.Tuple()) + .Executes(r => DebugDelete(r.Source, handler, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - string[] args = GetArgs(command); - if (args.Length > 0) +#pragma warning disable format // @formatter:off + "status" => GetCmdDescTranslated(), + "_setloading" => GetCmdDescTranslated(), + "_setloaded" => GetCmdDescTranslated(), + "_delete" => GetCmdDescTranslated(), + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private static int LogChunkStatus(CmdResult r, McClient handler, Location? pos = null, Tuple? markedChunkPos = null) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + World world = handler.GetWorld(); + Location current = handler.GetCurrentLocation(); + if (pos.HasValue) + pos.Value.ToAbsolute(current); + + (int markChunkX, int markChunkZ) = markedChunkPos ?? + (pos.HasValue ? new(pos.Value.ChunkX, pos.Value.ChunkZ) : new(current.ChunkX, current.ChunkZ)); + + StringBuilder sb = new(); + + sb.Append(World.GetChunkLoadingStatus(handler.GetWorld())); + sb.Append('\n'); + + sb.AppendLine(string.Format(Translations.cmd_chunk_current, current, current.ChunkX, current.ChunkZ)); + if (markedChunkPos != null) + { + sb.Append(Translations.cmd_chunk_marked); + if (pos.HasValue) + sb.Append(string.Format("X:{0:0.00} Y:{1:0.00} Z:{2:0.00}, ", pos.Value.X, pos.Value.Y, pos.Value.Z)); + sb.AppendLine(string.Format(Translations.cmd_chunk_chunk_pos, markChunkX, markChunkZ)); ; + } + + int consoleHeight = Math.Max(Math.Max(Console.BufferHeight, Settings.Config.Main.Advanced.MinTerminalHeight) - 2, 25); + if (consoleHeight % 2 == 0) + --consoleHeight; + + int consoleWidth = Math.Max(Math.Max(Console.BufferWidth, Settings.Config.Main.Advanced.MinTerminalWidth) / 2, 17); + if (consoleWidth % 2 == 0) + --consoleWidth; + + int startZ = current.ChunkZ - consoleHeight, endZ = current.ChunkZ + consoleHeight; + int startX = current.ChunkX - consoleWidth, endX = current.ChunkX + consoleWidth; + + int leftMost = endX, rightMost = startX, topMost = endZ, bottomMost = startZ; + for (int z = startZ; z <= endZ; z++) + { + for (int x = startX; x <= endX; ++x) { - if (args[0] == "status") + if (world[x, z] != null) { - World world = handler.GetWorld(); - Location current = handler.GetCurrentLocation(); - - Tuple? markedChunkPos = ParseChunkPos(args); - (int markChunkX, int markChunkZ) = markedChunkPos ?? (new(current.ChunkX, current.ChunkZ)); - - StringBuilder sb = new(); - - sb.Append(World.GetChunkLoadingStatus(handler.GetWorld())); - sb.Append('\n'); - - sb.AppendLine(string.Format(Translations.cmd_chunk_current, current, current.ChunkX, current.ChunkZ)); - if (markedChunkPos != null) - { - sb.Append(Translations.cmd_chunk_marked); - if (args.Length == 1 + 3) - sb.Append(String.Format("X:{0:0.00} Y:{1:0.00} Z:{2:0.00}, ", - double.Parse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture), - double.Parse(args[2], NumberStyles.Any, CultureInfo.CurrentCulture), - double.Parse(args[3], NumberStyles.Any, CultureInfo.CurrentCulture))); - sb.AppendLine(string.Format(Translations.cmd_chunk_chunk_pos, markChunkX, markChunkZ));; - } - - int consoleHeight = Math.Max(Math.Max(Console.BufferHeight, Settings.Config.Main.Advanced.MinTerminalHeight) - 2, 25); - if (consoleHeight % 2 == 0) - --consoleHeight; - - int consoleWidth = Math.Max(Math.Max(Console.BufferWidth, Settings.Config.Main.Advanced.MinTerminalWidth) / 2, 17); - if (consoleWidth % 2 == 0) - --consoleWidth; - - int startZ = current.ChunkZ - consoleHeight, endZ = current.ChunkZ + consoleHeight; - int startX = current.ChunkX - consoleWidth, endX = current.ChunkX + consoleWidth; - - int leftMost = endX, rightMost = startX, topMost = endZ, bottomMost = startZ; - for (int z = startZ; z <= endZ; z++) - { - for (int x = startX; x <= endX; ++x) - { - if (world[x, z] != null) - { - leftMost = Math.Min(leftMost, x); - rightMost = Math.Max(rightMost, x); - topMost = Math.Min(topMost, z); - bottomMost = Math.Max(bottomMost, z); - } - } - } - - // Include the player's location - topMost = Math.Min(topMost, current.ChunkZ); - bottomMost = Math.Max(bottomMost, current.ChunkZ); - leftMost = Math.Min(leftMost, current.ChunkX); - rightMost = Math.Max(rightMost, current.ChunkX); - - // Empty one row and one column each - --leftMost; ++rightMost; --topMost; ++bottomMost; - - // Resize according to limitations - if ((bottomMost - topMost + 1) > consoleHeight) - { - int delta = (bottomMost - topMost + 1) - consoleHeight; - if (bottomMost - (delta + 1) / 2 < current.ChunkZ + 1) - { - int bottomReduce = bottomMost - (current.ChunkZ + 1); - bottomMost -= bottomReduce; - topMost += delta - bottomReduce; - } - else if (topMost + delta / 2 > current.ChunkZ - 1) - { - int topAdd = topMost - (current.ChunkZ - 1); - topMost += topAdd; - bottomMost -= delta - topAdd; - } - else - { - topMost += delta / 2; - bottomMost -= (delta + 1) / 2; - } - } - if ((rightMost - leftMost + 1) > consoleWidth) - { - int delta = (rightMost - leftMost + 1) - consoleWidth; - if (rightMost - (delta + 1) / 2 < current.ChunkX + 1) - { - int rightReduce = rightMost - (current.ChunkX + 1); - rightMost -= rightReduce; - leftMost += delta - rightReduce; - } - else if (leftMost + delta / 2 > current.ChunkX - 1) - { - int leftAdd = leftMost - (current.ChunkX - 1); - leftMost += leftAdd; - rightMost -= delta - leftAdd; - } - else - { - leftMost += delta / 2; - rightMost -= (delta + 1) / 2; - } - } - - // Try to include the marker chunk - if (markedChunkPos != null && - (((Math.Max(bottomMost, markChunkZ) - Math.Min(topMost, markChunkZ) + 1) > consoleHeight) || - ((Math.Max(rightMost, markChunkX) - Math.Min(leftMost, markChunkX) + 1) > consoleWidth))) - sb.AppendLine(Translations.cmd_chunk_outside); - else - { - topMost = Math.Min(topMost, markChunkZ); - bottomMost = Math.Max(bottomMost, markChunkZ); - leftMost = Math.Min(leftMost, markChunkX); - rightMost = Math.Max(rightMost, markChunkX); - } - - - // \ud83d\udd33: 🔳, \ud83d\udfe8: 🟨, \ud83d\udfe9: 🟩, \u25A1: □, \u25A3: ▣, \u25A0: ■ - string[] chunkStatusStr = Settings.Config.Main.Advanced.EnableEmoji ? - new string[] { "\ud83d\udd33", "\ud83d\udfe8", "\ud83d\udfe9" } : new string[] { "\u25A1", "\u25A3", "\u25A0" }; - - // Output - for (int z = topMost; z <= bottomMost; ++z) - { - for (int x = leftMost; x <= rightMost; ++x) - { - if (z == current.ChunkZ && x == current.ChunkX) - sb.Append("§z"); // Player Location: background gray - else if (z == markChunkZ && x == markChunkX) - sb.Append("§w"); // Marked chunk: background red - - ChunkColumn? chunkColumn = world[x, z]; - if (chunkColumn == null) - sb.Append(chunkStatusStr[0]); - else if (chunkColumn.FullyLoaded) - sb.Append(chunkStatusStr[2]); - else - sb.Append(chunkStatusStr[1]); - - if ((z == current.ChunkZ && x == current.ChunkX) || (z == markChunkZ && x == markChunkX)) - sb.Append("§r"); // Reset background color - } - sb.Append('\n'); - } - - sb.AppendLine(string.Format(Translations.cmd_chunk_icon, "§z §r", "§w §r", chunkStatusStr[0], chunkStatusStr[1], chunkStatusStr[2])); - return sb.ToString(); + leftMost = Math.Min(leftMost, x); + rightMost = Math.Max(rightMost, x); + topMost = Math.Min(topMost, z); + bottomMost = Math.Max(bottomMost, z); } - else if (args[0] == "setloading") // For debugging - { - Tuple? chunkPos = ParseChunkPos(args); - if (chunkPos != null) - { - handler.Log.Info(Translations.cmd_chunk_for_debug); - World world = handler.GetWorld(); - (int chunkX, int chunkZ) = chunkPos; - ChunkColumn? chunkColumn = world[chunkX, chunkZ]; - if (chunkColumn != null) - chunkColumn.FullyLoaded = false; - return (chunkColumn == null) ? "Fail: chunk dosen't exist!" : - String.Format("Successfully marked chunk ({0}, {1}) as loading.", chunkX, chunkZ); - } - else - return GetCmdDescTranslated(); - } - else if (args[0] == "setloaded") // For debugging - { - Tuple? chunkPos = ParseChunkPos(args); - if (chunkPos != null) - { - handler.Log.Info(Translations.cmd_chunk_for_debug); - World world = handler.GetWorld(); - (int chunkX, int chunkZ) = chunkPos; - ChunkColumn? chunkColumn = world[chunkX, chunkZ]; - if (chunkColumn != null) - chunkColumn.FullyLoaded = true; - return (chunkColumn == null) ? "Fail: chunk dosen't exist!" : - String.Format("Successfully marked chunk ({0}, {1}) as loaded.", chunkX, chunkZ); - } - else - return GetCmdDescTranslated(); - } - else if (args[0] == "delete") // For debugging - { - Tuple? chunkPos = ParseChunkPos(args); - if (chunkPos != null) - { - handler.Log.Info(Translations.cmd_chunk_for_debug); - World world = handler.GetWorld(); - (int chunkX, int chunkZ) = chunkPos; - world[chunkX, chunkZ] = null; - return String.Format("Successfully deleted chunk ({0}, {1}).", chunkX, chunkZ); - } - else - return GetCmdDescTranslated(); - } - else - return GetCmdDescTranslated(); + } + } + + // Include the player's location + topMost = Math.Min(topMost, current.ChunkZ); + bottomMost = Math.Max(bottomMost, current.ChunkZ); + leftMost = Math.Min(leftMost, current.ChunkX); + rightMost = Math.Max(rightMost, current.ChunkX); + + // Empty one row and one column each + --leftMost; ++rightMost; --topMost; ++bottomMost; + + // Resize according to limitations + if ((bottomMost - topMost + 1) > consoleHeight) + { + int delta = (bottomMost - topMost + 1) - consoleHeight; + if (bottomMost - (delta + 1) / 2 < current.ChunkZ + 1) + { + int bottomReduce = bottomMost - (current.ChunkZ + 1); + bottomMost -= bottomReduce; + topMost += delta - bottomReduce; + } + else if (topMost + delta / 2 > current.ChunkZ - 1) + { + int topAdd = topMost - (current.ChunkZ - 1); + topMost += topAdd; + bottomMost -= delta - topAdd; } else - return GetCmdDescTranslated(); + { + topMost += delta / 2; + bottomMost -= (delta + 1) / 2; + } } + if ((rightMost - leftMost + 1) > consoleWidth) + { + int delta = (rightMost - leftMost + 1) - consoleWidth; + if (rightMost - (delta + 1) / 2 < current.ChunkX + 1) + { + int rightReduce = rightMost - (current.ChunkX + 1); + rightMost -= rightReduce; + leftMost += delta - rightReduce; + } + else if (leftMost + delta / 2 > current.ChunkX - 1) + { + int leftAdd = leftMost - (current.ChunkX - 1); + leftMost += leftAdd; + rightMost -= delta - leftAdd; + } + else + { + leftMost += delta / 2; + rightMost -= (delta + 1) / 2; + } + } + + // Try to include the marker chunk + if (markedChunkPos != null && + (((Math.Max(bottomMost, markChunkZ) - Math.Min(topMost, markChunkZ) + 1) > consoleHeight) || + ((Math.Max(rightMost, markChunkX) - Math.Min(leftMost, markChunkX) + 1) > consoleWidth))) + sb.AppendLine(Translations.cmd_chunk_outside); else - return GetCmdDescTranslated(); + { + topMost = Math.Min(topMost, markChunkZ); + bottomMost = Math.Max(bottomMost, markChunkZ); + leftMost = Math.Min(leftMost, markChunkX); + rightMost = Math.Max(rightMost, markChunkX); + } + + + // \ud83d\udd33: 🔳, \ud83d\udfe8: 🟨, \ud83d\udfe9: 🟩, \u25A1: □, \u25A3: ▣, \u25A0: ■ + string[] chunkStatusStr = Settings.Config.Main.Advanced.EnableEmoji ? + new string[] { "\ud83d\udd33", "\ud83d\udfe8", "\ud83d\udfe9" } : new string[] { "\u25A1", "\u25A3", "\u25A0" }; + + // Output + for (int z = topMost; z <= bottomMost; ++z) + { + for (int x = leftMost; x <= rightMost; ++x) + { + if (z == current.ChunkZ && x == current.ChunkX) + sb.Append("§z"); // Player Location: background gray + else if (z == markChunkZ && x == markChunkX) + sb.Append("§w"); // Marked chunk: background red + + ChunkColumn? chunkColumn = world[x, z]; + if (chunkColumn == null) + sb.Append(chunkStatusStr[0]); + else if (chunkColumn.FullyLoaded) + sb.Append(chunkStatusStr[2]); + else + sb.Append(chunkStatusStr[1]); + + if ((z == current.ChunkZ && x == current.ChunkX) || (z == markChunkZ && x == markChunkX)) + sb.Append("§r"); // Reset background color + } + sb.Append('\n'); + } + + sb.Append(string.Format(Translations.cmd_chunk_icon, "§z §r", "§w §r", chunkStatusStr[0], chunkStatusStr[1], chunkStatusStr[2])); + handler.Log.Info(sb.ToString()); + + return r.SetAndReturn(Status.Done); } - private static Tuple? ParseChunkPos(string[] args) + private static int DebugSetLoading(CmdResult r, McClient handler, Location? pos = null, Tuple? markedChunkPos = null) { - try - { - int chunkX, chunkZ; - if (args.Length == 1 + 3) - { - Location pos = new( - double.Parse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture), - double.Parse(args[2], NumberStyles.Any, CultureInfo.CurrentCulture), - double.Parse(args[3], NumberStyles.Any, CultureInfo.CurrentCulture) - ); - chunkX = pos.ChunkX; - chunkZ = pos.ChunkZ; - } - else if (args.Length == 1 + 2) - { - chunkX = int.Parse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture); - chunkZ = int.Parse(args[2], NumberStyles.Any, CultureInfo.CurrentCulture); - } - else - return null; - return new(chunkX, chunkZ); - } - catch (FormatException) - { - return null; - } + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + if (pos.HasValue) + pos.Value.ToAbsolute(handler.GetCurrentLocation()); + handler.Log.Info(Translations.cmd_chunk_for_debug); + (int chunkX, int chunkZ) = markedChunkPos ?? new(pos!.Value.ChunkX, pos!.Value.ChunkZ); + ChunkColumn? chunkColumn = handler.GetWorld()[chunkX, chunkZ]; + if (chunkColumn != null) + chunkColumn.FullyLoaded = false; + + if (chunkColumn == null) + return r.SetAndReturn(Status.Fail, "Fail: chunk dosen't exist!"); + else + return r.SetAndReturn(Status.Done, string.Format("Successfully marked chunk ({0}, {1}) as loading.", chunkX, chunkZ)); + } + + private static int DebugSetLoaded(CmdResult r, McClient handler, Location? pos = null, Tuple? markedChunkPos = null) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + if (pos.HasValue) + pos.Value.ToAbsolute(handler.GetCurrentLocation()); + handler.Log.Info(Translations.cmd_chunk_for_debug); + (int chunkX, int chunkZ) = markedChunkPos ?? new(pos!.Value.ChunkX, pos!.Value.ChunkZ); + ChunkColumn? chunkColumn = handler.GetWorld()[chunkX, chunkZ]; + if (chunkColumn != null) + chunkColumn.FullyLoaded = false; + + if (chunkColumn == null) + return r.SetAndReturn(Status.Fail, "Fail: chunk dosen't exist!"); + else + return r.SetAndReturn(Status.Done, string.Format("Successfully marked chunk ({0}, {1}) as loaded.", chunkX, chunkZ)); + } + + private static int DebugDelete(CmdResult r, McClient handler, Location? pos = null, Tuple? markedChunkPos = null) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + if (pos.HasValue) + pos.Value.ToAbsolute(handler.GetCurrentLocation()); + handler.Log.Info(Translations.cmd_chunk_for_debug); + (int chunkX, int chunkZ) = markedChunkPos ?? new(pos!.Value.ChunkX, pos!.Value.ChunkZ); + handler.GetWorld()[chunkX, chunkZ] = null; + + return r.SetAndReturn(Status.Done, string.Format("Successfully deleted chunk ({0}, {1}).", chunkX, chunkZ)); } } } diff --git a/MinecraftClient/Commands/CommandSource.cs b/MinecraftClient/Commands/CommandSource.cs deleted file mode 100644 index 89f1f1ff..00000000 --- a/MinecraftClient/Commands/CommandSource.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MinecraftClient.Commands -{ - public class CommandSource - { - public string UserName { get; set; } = string.Empty; - } -} diff --git a/MinecraftClient/Commands/Connect.cs b/MinecraftClient/Commands/Connect.cs index 9640eb9d..79892fc4 100644 --- a/MinecraftClient/Commands/Connect.cs +++ b/MinecraftClient/Commands/Connect.cs @@ -1,5 +1,7 @@ -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { @@ -9,31 +11,65 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "connect [account]"; } } public override string CmdDesc { get { return Translations.cmd_connect_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("ServerNick", MccArguments.ServerNick()) + .Executes(r => DoConnect(r.Source, handler, Arguments.GetString(r, "ServerNick"), string.Empty)) + .Then(l => l.Argument("AccountNick", MccArguments.AccountNick()) + .Executes(r => DoConnect(r.Source, handler, Arguments.GetString(r, "ServerNick"), Arguments.GetString(r, "AccountNick"))))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient? handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - string[] args = GetArgs(command); - if (args.Length > 1) - { - if (!Settings.Config.Main.Advanced.SetAccount(args[1])) - { - return string.Format(Translations.cmd_connect_unknown, args[1]); - } - } +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } - if (Settings.Config.Main.SetServerIP(new Settings.MainConfigHealper.MainConfig.ServerInfoConfig(args[0]), true)) - { - Program.Restart(keepAccountAndServerSettings: true); - return ""; - } - else return string.Format(Translations.cmd_connect_invalid_ip, args[0]); + private int DoConnect(CmdResult r, McClient handler, string server, string account) + { + if (!string.IsNullOrWhiteSpace(account) && !Settings.Config.Main.Advanced.SetAccount(account)) + return r.SetAndReturn(Status.Fail, string.Format(Translations.cmd_connect_unknown, account)); + + if (Settings.Config.Main.SetServerIP(new Settings.MainConfigHealper.MainConfig.ServerInfoConfig(server), true)) + { + Program.Restart(keepAccountAndServerSettings: true); + return r.SetAndReturn(Status.Done); + } + else + { + return r.SetAndReturn(Status.Fail, string.Format(Translations.cmd_connect_invalid_ip, server)); + } + } + + internal static string DoConnect(string command) + { + string[] args = GetArgs(command); + if (args.Length > 1 && !Settings.Config.Main.Advanced.SetAccount(args[1])) + return string.Format(Translations.cmd_connect_unknown, args[1]); + + if (Settings.Config.Main.SetServerIP(new Settings.MainConfigHealper.MainConfig.ServerInfoConfig(args[0]), true)) + { + Program.Restart(keepAccountAndServerSettings: true); + return string.Empty; + } + else + { + return string.Format(Translations.cmd_connect_invalid_ip, args[0]); } - else return GetCmdDescTranslated(); } } } diff --git a/MinecraftClient/Commands/Debug.cs b/MinecraftClient/Commands/Debug.cs index 18122daa..acb6f7e9 100644 --- a/MinecraftClient/Commands/Debug.cs +++ b/MinecraftClient/Commands/Debug.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -9,20 +10,46 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "debug [on|off]"; } } public override string CmdDesc { get { return Translations.cmd_debug_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => SetDebugMode(r.Source, true)) + .Then(l => l.Literal("on") + .Executes(r => SetDebugMode(r.Source, false, true))) + .Then(l => l.Literal("off") + .Executes(r => SetDebugMode(r.Source, false, false))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) - Settings.Config.Logging.DebugMessages = (GetArg(command).ToLower() == "on"); - else + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int SetDebugMode(CmdResult r, bool flip, bool mode = false) + { + if (flip) Settings.Config.Logging.DebugMessages = !Settings.Config.Logging.DebugMessages; - if (Settings.Config.Logging.DebugMessages) - return Translations.cmd_debug_state_on; else - return Translations.cmd_debug_state_off; + Settings.Config.Logging.DebugMessages = mode; + + if (Settings.Config.Logging.DebugMessages) + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_debug_state_on); + else + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_debug_state_off); } } } diff --git a/MinecraftClient/Commands/Dig.cs b/MinecraftClient/Commands/Dig.cs index bf68743c..2903a817 100644 --- a/MinecraftClient/Commands/Dig.cs +++ b/MinecraftClient/Commands/Dig.cs @@ -1,7 +1,9 @@ using System; -using System.Collections.Generic; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { @@ -11,53 +13,68 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "dig "; } } public override string CmdDesc { get { return Translations.cmd_dig_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => DigLookAt(r.Source, handler)) + .Then(l => l.Argument("Location", MccArguments.Location()) + .Executes(r => DigAt(r.Source, handler, MccArguments.GetLocation(r, "Location")))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DigAt(CmdResult r, McClient handler, Location blockToBreak) { if (!handler.GetTerrainEnabled()) - return Translations.extra_terrainandmovement_required; + return r.SetAndReturn(Status.FailNeedTerrain); - string[] args = GetArgs(command); - if (args.Length == 0) + Location current = handler.GetCurrentLocation(); + blockToBreak = blockToBreak.ToAbsolute(current); + if (blockToBreak.DistanceSquared(current.EyesLocation()) > 25) + return r.SetAndReturn(Status.Fail, Translations.cmd_dig_too_far); + Block block = handler.GetWorld().GetBlock(blockToBreak); + if (block.Type == Material.Air) + return r.SetAndReturn(Status.Fail, Translations.cmd_dig_no_block); + else if (handler.DigBlock(blockToBreak)) { - (bool hasBlock, Location blockLoc, Block block) = RaycastHelper.RaycastBlock(handler, 4.5, false); - if (!hasBlock) - return Translations.cmd_dig_too_far; - else if (block.Type == Material.Air) - return Translations.cmd_dig_no_block; - else if (handler.DigBlock(blockLoc, lookAtBlock: false)) - return string.Format(Translations.cmd_dig_dig, blockLoc.X, blockLoc.Y, blockLoc.Z, block.GetTypeString()); - else - return Translations.cmd_dig_fail; - } - else if (args.Length == 3) - { - try - { - Location current = handler.GetCurrentLocation(); - Location blockToBreak = Location.Parse(current.ToFloor(), args[0], args[1], args[2]); - if (blockToBreak.DistanceSquared(current.EyesLocation()) > 25) - return Translations.cmd_dig_too_far; - Block block = handler.GetWorld().GetBlock(blockToBreak); - if (block.Type == Material.Air) - return Translations.cmd_dig_no_block; - else if (handler.DigBlock(blockToBreak)) - { - blockToBreak = blockToBreak.ToCenter(); - return string.Format(Translations.cmd_dig_dig, blockToBreak.X, blockToBreak.Y, blockToBreak.Z, block.GetTypeString()); - } - else - return Translations.cmd_dig_fail; - } - catch (FormatException) { return GetCmdDescTranslated(); } + blockToBreak = blockToBreak.ToCenter(); + return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_dig_dig, blockToBreak.X, blockToBreak.Y, blockToBreak.Z, block.GetTypeString())); } else - { - return GetCmdDescTranslated(); - } + return r.SetAndReturn(Status.Fail, Translations.cmd_dig_fail); + } + + private int DigLookAt(CmdResult r, McClient handler) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + (bool hasBlock, Location blockLoc, Block block) = RaycastHelper.RaycastBlock(handler, 4.5, false); + if (!hasBlock) + return r.SetAndReturn(Status.Fail, Translations.cmd_dig_too_far); + else if (block.Type == Material.Air) + return r.SetAndReturn(Status.Fail, Translations.cmd_dig_no_block); + else if (handler.DigBlock(blockLoc, lookAtBlock: false)) + return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_dig_dig, blockLoc.X, blockLoc.Y, blockLoc.Z, block.GetTypeString())); + else + return r.SetAndReturn(Status.Fail, Translations.cmd_dig_fail); } } } diff --git a/MinecraftClient/Commands/DropItem.cs b/MinecraftClient/Commands/DropItem.cs index fa085d47..01e9ecb1 100644 --- a/MinecraftClient/Commands/DropItem.cs +++ b/MinecraftClient/Commands/DropItem.cs @@ -1,57 +1,64 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.Inventory; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { class DropItem : Command { public override string CmdName { get { return "dropitem"; } } - public override string CmdUsage { get { return "/dropitem "; } } + public override string CmdUsage { get { return "dropitem "; } } public override string CmdDesc { get { return Translations.cmd_dropItem_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("ItemType", MccArguments.ItemType()) + .Executes(r => DoDropItem(r.Source, handler, MccArguments.GetItemType(r, "ItemType")))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoDropItem(CmdResult r, McClient handler, ItemType itemType) { if (!handler.GetInventoryEnabled()) - { - return Translations.extra_inventory_required; - } - if (HasArg(command)) - { - string arg = GetArg(command); - if (Enum.TryParse(arg, true, out ItemType itemType)) - { - int inventoryId; - var inventories = handler.GetInventories(); - List availableIds = inventories.Keys.ToList(); - availableIds.Remove(0); // remove player inventory ID from list - if (availableIds.Count == 1) - inventoryId = availableIds[0]; // one container, use it - else - inventoryId = 0; - var p = inventories[inventoryId]; - int[] targetItems = p.SearchItem(itemType); - foreach (int slot in targetItems) - { - handler.DoWindowAction(inventoryId, slot, WindowActionType.DropItemStack); - } - return string.Format(Translations.cmd_dropItem_dropped, itemType.ToString(), inventoryId); - } - else - { - return string.Format(Translations.cmd_dropItem_unknown_item, arg); - } - } + return r.SetAndReturn(Status.FailNeedTerrain); + + int inventoryId; + var inventories = handler.GetInventories(); + List availableIds = inventories.Keys.ToList(); + availableIds.Remove(0); // remove player inventory ID from list + if (availableIds.Count == 1) + inventoryId = availableIds[0]; // one container, use it else - { - return CmdUsage; - } + inventoryId = 0; + var p = inventories[inventoryId]; + int[] targetItems = p.SearchItem(itemType); + foreach (int slot in targetItems) + handler.DoWindowAction(inventoryId, slot, WindowActionType.DropItemStack); + + return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_dropItem_dropped, Item.GetTypeString(itemType), inventoryId)); } } } diff --git a/MinecraftClient/Commands/Enchant.cs b/MinecraftClient/Commands/Enchant.cs index 108a8b95..bc7c7e10 100644 --- a/MinecraftClient/Commands/Enchant.cs +++ b/MinecraftClient/Commands/Enchant.cs @@ -1,6 +1,7 @@ -using System.Collections.Generic; -using System.Linq; +using System.Linq; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.Inventory; namespace MinecraftClient.Commands @@ -11,80 +12,96 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "enchant "; } } public override string CmdDesc { get { return Translations.cmd_enchant_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + .Then(l => l.Literal("top") + .Executes(r => GetUsage(r.Source, "top"))) + .Then(l => l.Literal("middle") + .Executes(r => GetUsage(r.Source, "middle"))) + .Then(l => l.Literal("bottom") + .Executes(r => GetUsage(r.Source, "bottom"))) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Literal("top") + .Executes(r => DoEnchant(r.Source, handler, slotId: 0))) + .Then(l => l.Literal("middle") + .Executes(r => DoEnchant(r.Source, handler, slotId: 1))) + .Then(l => l.Literal("bottom") + .Executes(r => DoEnchant(r.Source, handler, slotId: 2))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (!handler.GetInventoryEnabled()) - return Translations.error_inventoryhandling_not_enabled; - - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - string slot = GetArg(command).ToLower().Trim(); +#pragma warning disable format // @formatter:off + "top" => GetCmdDescTranslated(), + "middle" => GetCmdDescTranslated(), + "bottom" => GetCmdDescTranslated(), + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } - int slotId = slot switch + private int DoEnchant(CmdResult r, McClient handler, int slotId) + { + Container? enchantingTable = null; + + foreach (var (id, container) in handler.GetInventories()) + { + if (container.Type == ContainerType.Enchantment) { - "top" => 0, - "middle" => 1, - "bottom" => 2, - _ => -1 - }; - - if (slotId == -1) - return Translations.cmd_enchant_invalid_slot; - - Container? enchantingTable = null; - - foreach (var (id, container) in handler.GetInventories()) - { - if (container.Type == ContainerType.Enchantment) - { - enchantingTable = container; - break; - } + enchantingTable = container; + break; } - - if (enchantingTable == null) - return Translations.cmd_enchant_enchanting_table_not_opened; - - int[] emptySlots = enchantingTable.GetEmpytSlots(); - - if (emptySlots.Contains(0)) - return Translations.cmd_enchant_enchanting_no_item; - - if (emptySlots.Contains(1)) - return Translations.cmd_enchant_enchanting_no_lapis; - - Item lapisSlot = enchantingTable.Items[1]; - - if (lapisSlot.Type != ItemType.LapisLazuli) - return Translations.cmd_enchant_enchanting_no_lapis; - - if (lapisSlot.Count < 3) - return Translations.cmd_enchant_enchanting_no_lapis; - - EnchantmentData? enchantment = handler.GetLastEnchantments(); - - if (enchantment == null) - return Translations.cmd_enchant_no_enchantments; - - short requiredLevel = slotId switch - { - 0 => enchantment.TopEnchantmentLevelRequirement, - 1 => enchantment.MiddleEnchantmentLevelRequirement, - 2 => enchantment.BottomEnchantmentLevelRequirement, - _ => 9999 - }; - - if (handler.GetLevel() < requiredLevel) - return string.Format(Translations.cmd_enchant_no_levels, handler.GetLevel(), requiredLevel); - - return handler.ClickContainerButton(enchantingTable.ID, slotId) ? Translations.cmd_enchant_clicked : Translations.cmd_enchant_not_clicked; } - return GetCmdDescTranslated(); + if (enchantingTable == null) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_enchant_enchanting_table_not_opened); + + int[] emptySlots = enchantingTable.GetEmpytSlots(); + + if (emptySlots.Contains(0)) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_enchant_enchanting_no_item); + + if (emptySlots.Contains(1)) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_enchant_enchanting_no_lapis); + + Item lapisSlot = enchantingTable.Items[1]; + + if (lapisSlot.Type != ItemType.LapisLazuli || lapisSlot.Count < 3) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_enchant_enchanting_no_lapis); + + EnchantmentData? enchantment = handler.GetLastEnchantments(); + + if (enchantment == null) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_enchant_no_enchantments); + + short requiredLevel = slotId switch + { + 0 => enchantment.TopEnchantmentLevelRequirement, + 1 => enchantment.MiddleEnchantmentLevelRequirement, + 2 => enchantment.BottomEnchantmentLevelRequirement, + _ => 9999 + }; + + if (handler.GetLevel() < requiredLevel) + return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_enchant_no_levels, handler.GetLevel(), requiredLevel)); + else + { + if (handler.ClickContainerButton(enchantingTable.ID, slotId)) + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_enchant_clicked); + else + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_enchant_not_clicked); + } } } } diff --git a/MinecraftClient/Commands/Entitycmd.cs b/MinecraftClient/Commands/Entitycmd.cs index 6fc21bb4..ad9b8c7e 100644 --- a/MinecraftClient/Commands/Entitycmd.cs +++ b/MinecraftClient/Commands/Entitycmd.cs @@ -1,172 +1,321 @@ using System; using System.Collections.Generic; -using System.Globalization; +using System.Diagnostics.CodeAnalysis; using System.Text; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.Inventory; using MinecraftClient.Mapping; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { class Entitycmd : Command { public override string CmdName { get { return "entity"; } } - public override string CmdUsage { get { return "entity "; } } + public override string CmdUsage { get { return "entity [near] "; } } public override string CmdDesc { get { return string.Empty; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + private enum ActionType { Attack, Use, List }; + + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + .Then(l => l.Literal("near") + .Executes(r => GetUsage(r.Source, "near"))) + .Then(l => l.Literal("attack") + .Executes(r => GetUsage(r.Source, "attack"))) + .Then(l => l.Literal("use") + .Executes(r => GetUsage(r.Source, "use"))) + .Then(l => l.Literal("list") + .Executes(r => GetUsage(r.Source, "list"))) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => GetFullEntityList(r.Source, handler)) + .Then(l => l.Literal("near") + .Executes(r => GetClosetEntityList(r.Source, handler)) + .Then(l => l.Argument("EntityID", Arguments.Integer()) + .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.List)) + .Then(l => l.Literal("attack") + .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.Attack))) + .Then(l => l.Literal("use") + .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.Use))) + .Then(l => l.Literal("list") + .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.List)))) + .Then(l => l.Argument("EntityType", MccArguments.EntityType()) + .Executes(r => OperateWithType(r.Source, handler, true, MccArguments.GetEntityType(r, "EntityType"), ActionType.List)) + .Then(l => l.Literal("attack") + .Executes(r => OperateWithType(r.Source, handler, near: true, MccArguments.GetEntityType(r, "EntityType"), ActionType.Attack))) + .Then(l => l.Literal("use") + .Executes(r => OperateWithType(r.Source, handler, near: true, MccArguments.GetEntityType(r, "EntityType"), ActionType.Use))) + .Then(l => l.Literal("list") + .Executes(r => OperateWithType(r.Source, handler, near: true, MccArguments.GetEntityType(r, "EntityType"), ActionType.List))))) + .Then(l => l.Argument("EntityID", Arguments.Integer()) + .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.List)) + .Then(l => l.Literal("attack") + .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.Attack))) + .Then(l => l.Literal("use") + .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.Use))) + .Then(l => l.Literal("list") + .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.List)))) + .Then(l => l.Argument("EntityType", MccArguments.EntityType()) + .Executes(r => OperateWithType(r.Source, handler, true, MccArguments.GetEntityType(r, "EntityType"), ActionType.List)) + .Then(l => l.Literal("attack") + .Executes(r => OperateWithType(r.Source, handler, near: false, MccArguments.GetEntityType(r, "EntityType"), ActionType.Attack))) + .Then(l => l.Literal("use") + .Executes(r => OperateWithType(r.Source, handler, near: false, MccArguments.GetEntityType(r, "EntityType"), ActionType.Use))) + .Then(l => l.Literal("list") + .Executes(r => OperateWithType(r.Source, handler, near: false, MccArguments.GetEntityType(r, "EntityType"), ActionType.List)))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (handler.GetEntityHandlingEnabled()) + return r.SetAndReturn(cmd switch { - string[] args = GetArgs(command); - if (args.Length >= 1) +#pragma warning disable format // @formatter:off + "near" => GetCmdDescTranslated(), + "attack" => GetCmdDescTranslated(), + "use" => GetCmdDescTranslated(), + "list" => GetCmdDescTranslated(), + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int GetFullEntityList(CmdResult r, McClient handler) + { + if (!handler.GetEntityHandlingEnabled()) + return r.SetAndReturn(Status.FailNeedEntity); + + Dictionary entities = handler.GetEntities(); + StringBuilder response = new(); + response.AppendLine(Translations.cmd_entityCmd_entities); + foreach (var entity2 in entities) + response.AppendLine(GetEntityInfoShort(entity2.Value)); + response.Append(GetCmdDescTranslated()); + handler.Log.Info(response.ToString()); + + return r.SetAndReturn(Status.Done); + } + + private int GetClosetEntityList(CmdResult r, McClient handler) + { + if (!handler.GetEntityHandlingEnabled()) + return r.SetAndReturn(Status.FailNeedEntity); + + if (TryGetClosetEntity(handler.GetEntities(), handler.GetCurrentLocation(), null, out Entity? closest)) + { + handler.Log.Info(GetEntityInfoDetailed(handler, closest)); + return r.SetAndReturn(Status.Done); + } + else + return r.SetAndReturn(Status.Fail, Translations.cmd_entityCmd_not_found); + } + + private int OperateWithId(CmdResult r, McClient handler, int entityID, ActionType action) + { + if (!handler.GetEntityHandlingEnabled()) + return r.SetAndReturn(Status.FailNeedEntity); + + if (handler.GetEntities().TryGetValue(entityID, out Entity? entity)) + { + handler.Log.Info(InteractionWithEntity(handler, entity, action)); + return r.SetAndReturn(Status.Done); + } + else + return r.SetAndReturn(Status.Fail, Translations.cmd_entityCmd_not_found); + } + + private int OperateWithType(CmdResult r, McClient handler, bool near, EntityType entityType, ActionType action) + { + if (!handler.GetEntityHandlingEnabled()) + return r.SetAndReturn(Status.FailNeedEntity); + + if (near) + { + if (TryGetClosetEntity(handler.GetEntities(), handler.GetCurrentLocation(), entityType, out Entity? closest)) { - try + handler.Log.Info(InteractionWithEntity(handler, closest, action)); + return r.SetAndReturn(Status.Done); + } + else + return r.SetAndReturn(Status.Fail, Translations.cmd_entityCmd_not_found); + } + else + { + if (action == ActionType.Attack || action == ActionType.Use) + { + string actionst = Translations.cmd_entityCmd_attacked; + int actioncount = 0; + foreach (var entity2 in handler.GetEntities()) { - int entityID = int.Parse(args[0], NumberStyles.Any, CultureInfo.CurrentCulture); - if (entityID != 0) + if (entity2.Value.Type == entityType) { - if (handler.GetEntities().ContainsKey(entityID)) + if (action == ActionType.Attack) { - string action = args.Length > 1 - ? args[1].ToLower() - : "list"; - switch (action) - { - case "attack": - handler.InteractEntity(entityID, InteractType.Attack); - return Translations.cmd_entityCmd_attacked; - case "use": - handler.InteractEntity(entityID, InteractType.Interact); - return Translations.cmd_entityCmd_used; - default: - Entity entity = handler.GetEntities()[entityID]; - int id = entity.ID; - float health = entity.Health; - int latency = entity.Latency; - Item item = entity.Item; - string? nickname = entity.Name; - string? customname = entity.CustomName; - EntityPose pose = entity.Pose; - EntityType type = entity.Type; - double distance = Math.Round(entity.Location.Distance(handler.GetCurrentLocation()), 2); - - string color = "§a"; // Green - if (health < 10) - color = "§c"; // Red - else if (health < 15) - color = "§e"; // Yellow - - string location = $"X:{Math.Round(entity.Location.X, 2)}, Y:{Math.Round(entity.Location.Y, 2)}, Z:{Math.Round(entity.Location.Z, 2)}"; - StringBuilder done = new(); - done.Append($"{Translations.cmd_entityCmd_entity}: {id}\n [MCC] Type: {entity.GetTypeString()}"); - if (!string.IsNullOrEmpty(nickname)) - done.Append($"\n [MCC] {Translations.cmd_entityCmd_nickname}: {nickname}"); - else if (!string.IsNullOrEmpty(customname)) - done.Append($"\n [MCC] {Translations.cmd_entityCmd_customname}: {customname.Replace("&", "§")}§8"); - if (type == EntityType.Player) - done.Append($"\n [MCC] {Translations.cmd_entityCmd_latency}: {latency}"); - else if (type == EntityType.Item || type == EntityType.ItemFrame || type == Mapping.EntityType.EyeOfEnder || type == Mapping.EntityType.Egg || type == Mapping.EntityType.EnderPearl || type == Mapping.EntityType.Potion || type == Mapping.EntityType.Fireball || type == Mapping.EntityType.FireworkRocket) - { - string? displayName = item.DisplayName; - if (string.IsNullOrEmpty(displayName)) - done.Append($"\n [MCC] {Translations.cmd_entityCmd_item}: {item.GetTypeString()} x{item.Count}"); - else - done.Append($"\n [MCC] {Translations.cmd_entityCmd_item}: {item.GetTypeString()} x{item.Count} - {displayName}§8"); - } - - if (entity.Equipment.Count >= 1 && entity.Equipment != null) - { - done.Append($"\n [MCC] {Translations.cmd_entityCmd_equipment}:"); - if (entity.Equipment.ContainsKey(0) && entity.Equipment[0] != null) - done.Append($"\n [MCC] {Translations.cmd_entityCmd_mainhand}: {entity.Equipment[0].GetTypeString()} x{entity.Equipment[0].Count}"); - if (entity.Equipment.ContainsKey(1) && entity.Equipment[1] != null) - done.Append($"\n [MCC] {Translations.cmd_entityCmd_offhand}: {entity.Equipment[1].GetTypeString()} x{entity.Equipment[1].Count}"); - if (entity.Equipment.ContainsKey(5) && entity.Equipment[5] != null) - done.Append($"\n [MCC] {Translations.cmd_entityCmd_helmet}: {entity.Equipment[5].GetTypeString()} x{entity.Equipment[5].Count}"); - if (entity.Equipment.ContainsKey(4) && entity.Equipment[4] != null) - done.Append($"\n [MCC] {Translations.cmd_entityCmd_chestplate}: {entity.Equipment[4].GetTypeString()} x{entity.Equipment[4].Count}"); - if (entity.Equipment.ContainsKey(3) && entity.Equipment[3] != null) - done.Append($"\n [MCC] {Translations.cmd_entityCmd_leggings}: {entity.Equipment[3].GetTypeString()} x{entity.Equipment[3].Count}"); - if (entity.Equipment.ContainsKey(2) && entity.Equipment[2] != null) - done.Append($"\n [MCC] {Translations.cmd_entityCmd_boots}: {entity.Equipment[2].GetTypeString()} x{entity.Equipment[2].Count}"); - } - done.Append($"\n [MCC] {Translations.cmd_entityCmd_pose}: {pose}"); - done.Append($"\n [MCC] {Translations.cmd_entityCmd_health}: {color}{health}§8"); - done.Append($"\n [MCC] {Translations.cmd_entityCmd_distance}: {distance}"); - done.Append($"\n [MCC] {Translations.cmd_entityCmd_location}: {location}"); - return done.ToString(); - } + handler.InteractEntity(entity2.Key, InteractType.Attack); + actionst = Translations.cmd_entityCmd_attacked; } - else return Translations.cmd_entityCmd_not_found; - } - else - { - EntityType interacttype = Enum.Parse(args[0]); - string actionst = Translations.cmd_entityCmd_attacked; - int actioncount = 0; - foreach (var entity2 in handler.GetEntities()) + else if (action == ActionType.Use) { - if (entity2.Value.Type == interacttype) - { - string action = args.Length > 1 - ? args[1].ToLower() - : "list"; - if (action == "attack") - { - handler.InteractEntity(entity2.Key, InteractType.Attack); - actionst = Translations.cmd_entityCmd_attacked; - actioncount++; - } - else if (action == "use") - { - handler.InteractEntity(entity2.Key, InteractType.Interact); - actionst = Translations.cmd_entityCmd_used; - actioncount++; - } - else return GetCmdDescTranslated(); - } + handler.InteractEntity(entity2.Key, InteractType.Interact); + actionst = Translations.cmd_entityCmd_used; } - return actioncount + " " + actionst; + actioncount++; } } - catch (FormatException) { return GetCmdDescTranslated(); } + handler.Log.Info(actioncount + " " + actionst); + return r.SetAndReturn(Status.Done); } else { - Dictionary entities = handler.GetEntities(); StringBuilder response = new(); response.AppendLine(Translations.cmd_entityCmd_entities); - foreach (var entity2 in entities) + foreach (var entity2 in handler.GetEntities()) { - int id = entity2.Key; - float health = entity2.Value.Health; - int latency = entity2.Value.Latency; - string? nickname = entity2.Value.Name; - string? customname = entity2.Value.CustomName; - EntityPose pose = entity2.Value.Pose; - EntityType type = entity2.Value.Type; - Item item = entity2.Value.Item; - string location = $"X:{Math.Round(entity2.Value.Location.X, 2)}, Y:{Math.Round(entity2.Value.Location.Y, 2)}, Z:{Math.Round(entity2.Value.Location.Z, 2)}"; - - if (type == EntityType.Item || type == EntityType.ItemFrame || type == EntityType.EyeOfEnder || type == EntityType.Egg || type == EntityType.EnderPearl || type == EntityType.Potion || type == EntityType.Fireball || type == EntityType.FireworkRocket) - response.AppendLine($" #{id}: {Translations.cmd_entityCmd_type}: {entity2.Value.GetTypeString()}, {Translations.cmd_entityCmd_item}: {item.GetTypeString()}, {Translations.cmd_entityCmd_location}: {location}"); - else if (type == EntityType.Player && !string.IsNullOrEmpty(nickname)) - response.AppendLine($" #{id}: {Translations.cmd_entityCmd_type}: {entity2.Value.GetTypeString()}, {Translations.cmd_entityCmd_nickname}: §8{nickname}§8, {Translations.cmd_entityCmd_latency}: {latency}, {Translations.cmd_entityCmd_health}: {health}, {Translations.cmd_entityCmd_pose}: {pose}, {Translations.cmd_entityCmd_location}: {location}"); - else if (type == EntityType.Player && !string.IsNullOrEmpty(customname)) - response.AppendLine($" #{id}: {Translations.cmd_entityCmd_type}: {entity2.Value.GetTypeString()}, {Translations.cmd_entityCmd_customname}: §8{customname.Replace("&", "§")}§8, {Translations.cmd_entityCmd_latency}: {latency}, {Translations.cmd_entityCmd_health}: {health}, {Translations.cmd_entityCmd_pose}: {pose}, {Translations.cmd_entityCmd_location}: {location}"); - else - response.AppendLine($" #{id}: {Translations.cmd_entityCmd_type}: {entity2.Value.GetTypeString()}, {Translations.cmd_entityCmd_health}: {health}, {Translations.cmd_entityCmd_location}: {location}"); + if (entity2.Value.Type == entityType) + { + response.AppendLine(GetEntityInfoShort(entity2.Value)); + } } response.Append(GetCmdDescTranslated()); - return response.ToString(); + handler.Log.Info(response.ToString()); + return r.SetAndReturn(Status.Done); } } - else return Translations.extra_entity_required; + } + + private static string GetEntityInfoShort(Entity entity) + { + int id = entity.ID; + float health = entity.Health; + int latency = entity.Latency; + string? nickname = entity.Name; + string? customname = entity.CustomName; + EntityPose pose = entity.Pose; + EntityType type = entity.Type; + Item item = entity.Item; + string location = $"X:{Math.Round(entity.Location.X, 2)}, Y:{Math.Round(entity.Location.Y, 2)}, Z:{Math.Round(entity.Location.Z, 2)}"; + + if (type == EntityType.Item || type == EntityType.ItemFrame || type == EntityType.EyeOfEnder || type == EntityType.Egg || type == EntityType.EnderPearl || type == EntityType.Potion || type == EntityType.Fireball || type == EntityType.FireworkRocket) + return $" #{id}: {Translations.cmd_entityCmd_type}: {entity.GetTypeString()}, {Translations.cmd_entityCmd_item}: {item.GetTypeString()}, {Translations.cmd_entityCmd_location}: {location}"; + else if (type == EntityType.Player && !string.IsNullOrEmpty(nickname)) + return $" #{id}: {Translations.cmd_entityCmd_type}: {entity.GetTypeString()}, {Translations.cmd_entityCmd_nickname}: §8{nickname}§8, {Translations.cmd_entityCmd_latency}: {latency}, {Translations.cmd_entityCmd_health}: {health}, {Translations.cmd_entityCmd_pose}: {pose}, {Translations.cmd_entityCmd_location}: {location}"; + else if (type == EntityType.Player && !string.IsNullOrEmpty(customname)) + return $" #{id}: {Translations.cmd_entityCmd_type}: {entity.GetTypeString()}, {Translations.cmd_entityCmd_customname}: §8{customname.Replace("&", "§")}§8, {Translations.cmd_entityCmd_latency}: {latency}, {Translations.cmd_entityCmd_health}: {health}, {Translations.cmd_entityCmd_pose}: {pose}, {Translations.cmd_entityCmd_location}: {location}"; + else + return $" #{id}: {Translations.cmd_entityCmd_type}: {entity.GetTypeString()}, {Translations.cmd_entityCmd_health}: {health}, {Translations.cmd_entityCmd_location}: {location}"; + } + + private static string GetEntityInfoDetailed(McClient handler, Entity entity) + { + StringBuilder sb = new(); + int id = entity.ID; + float health = entity.Health; + int latency = entity.Latency; + Item item = entity.Item; + string? nickname = entity.Name; + string? customname = entity.CustomName; + EntityPose pose = entity.Pose; + EntityType type = entity.Type; + double distance = Math.Round(entity.Location.Distance(handler.GetCurrentLocation()), 2); + string location = $"X:{Math.Round(entity.Location.X, 2)}, Y:{Math.Round(entity.Location.Y, 2)}, Z:{Math.Round(entity.Location.Z, 2)}"; + + string color = "§a"; // Green + if (health < 10) + color = "§c"; // Red + else if (health < 15) + color = "§e"; // Yellow + + sb.Append($"{Translations.cmd_entityCmd_entity}: {id}\n [MCC] Type: {entity.GetTypeString()}"); + + if (!string.IsNullOrEmpty(nickname)) + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_nickname}: {nickname}"); + else if (!string.IsNullOrEmpty(customname)) + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_customname}: {customname.Replace("&", "§")}§8"); + + if (type == EntityType.Player) + { + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_latency}: {latency}"); + } + else if (type == EntityType.Item || type == EntityType.ItemFrame || type == Mapping.EntityType.EyeOfEnder || type == Mapping.EntityType.Egg || type == Mapping.EntityType.EnderPearl || type == Mapping.EntityType.Potion || type == Mapping.EntityType.Fireball || type == Mapping.EntityType.FireworkRocket) + { + string? displayName = item.DisplayName; + if (string.IsNullOrEmpty(displayName)) + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_item}: {item.GetTypeString()} x{item.Count}"); + else + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_item}: {item.GetTypeString()} x{item.Count} - {displayName}§8"); + } + + if (entity.Equipment.Count >= 1 && entity.Equipment != null) + { + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_equipment}:"); + if (entity.Equipment.ContainsKey(0) && entity.Equipment[0] != null) + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_mainhand}: {entity.Equipment[0].GetTypeString()} x{entity.Equipment[0].Count}"); + if (entity.Equipment.ContainsKey(1) && entity.Equipment[1] != null) + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_offhand}: {entity.Equipment[1].GetTypeString()} x{entity.Equipment[1].Count}"); + if (entity.Equipment.ContainsKey(5) && entity.Equipment[5] != null) + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_helmet}: {entity.Equipment[5].GetTypeString()} x{entity.Equipment[5].Count}"); + if (entity.Equipment.ContainsKey(4) && entity.Equipment[4] != null) + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_chestplate}: {entity.Equipment[4].GetTypeString()} x{entity.Equipment[4].Count}"); + if (entity.Equipment.ContainsKey(3) && entity.Equipment[3] != null) + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_leggings}: {entity.Equipment[3].GetTypeString()} x{entity.Equipment[3].Count}"); + if (entity.Equipment.ContainsKey(2) && entity.Equipment[2] != null) + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_boots}: {entity.Equipment[2].GetTypeString()} x{entity.Equipment[2].Count}"); + } + + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_pose}: {pose}"); + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_health}: {color}{health}§8"); + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_distance}: {distance}"); + sb.Append($"\n [MCC] {Translations.cmd_entityCmd_location}: {location}"); + + return sb.ToString(); + } + + private static bool TryGetClosetEntity(Dictionary entities, Location location, EntityType? entityType, [NotNullWhen(true)] out Entity? closest) + { + closest = null; + bool find = false; + double closest_distance = double.PositiveInfinity; + foreach (var entity in entities) + { + if (entityType.HasValue && entity.Value.Type != entityType) + continue; + + double distance = Math.Round(entity.Value.Location.Distance(location), 2); + if (distance < closest_distance) + { + find = true; + closest = entity.Value; + closest_distance = distance; + } + } + return find; + } + + private static string InteractionWithEntity(McClient handler, Entity entity, ActionType action) + { + switch (action) + { + case ActionType.Attack: + handler.InteractEntity(entity.ID, InteractType.Attack); + return Translations.cmd_entityCmd_attacked; + case ActionType.Use: + handler.InteractEntity(entity.ID, InteractType.Interact); + return Translations.cmd_entityCmd_used; + case ActionType.List: + return GetEntityInfoDetailed(handler, entity); + default: + goto case ActionType.List; + } } } -} +} \ No newline at end of file diff --git a/MinecraftClient/Commands/ExecIf.cs b/MinecraftClient/Commands/ExecIf.cs index e19e5bc3..3557e200 100644 --- a/MinecraftClient/Commands/ExecIf.cs +++ b/MinecraftClient/Commands/ExecIf.cs @@ -1,99 +1,94 @@ using System; using System.Collections.Generic; -using System.Linq; using Brigadier.NET; +using Brigadier.NET.Builder; using DynamicExpresso; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { class ExecIf : Command { public override string CmdName { get { return "execif"; } } - public override string CmdUsage { get { return "execif ---> "; } } + public override string CmdUsage { get { return "execif \"\" \"\""; } } public override string CmdDesc { get { return Translations.cmd_execif_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("Condition", Arguments.String()) + .Then(l => l.Argument("Command", Arguments.String()) + .Executes(r => HandleCommand(r.Source, handler, Arguments.GetString(r, "Condition"), Arguments.GetString(r, "Command"))))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - string commandsString = GetArg(command); +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } - if (!commandsString.Contains("--->")) - return GetCmdDescTranslated(); + private int HandleCommand(CmdResult r, McClient handler, string expressionText, string resultCommand) + { + try + { + var interpreter = new Interpreter(); + interpreter.SetVariable("MCC", handler); - string[] parts = commandsString.Split("--->", StringSplitOptions.TrimEntries) - .ToList() - .ConvertAll(command => command.Trim()) - .ToArray(); + foreach (KeyValuePair entry in Settings.Config.AppVar.GetVariables()) + interpreter.SetVariable(entry.Key, entry.Value); - if (parts.Length == 0) - return GetCmdDescTranslated(); + var result = interpreter.Eval(expressionText); - string expressionText = parts[0]; - string resultCommand = parts[1]; + bool shouldExec = result; - try + /*if (result is bool) + shouldExec = (bool)result; + else if (result is string) + shouldExec = !string.IsNullOrEmpty((string)result) && ((string)result).Trim().Contains("true", StringComparison.OrdinalIgnoreCase); + else if (result is int) + shouldExec = (int)result > 0; + else if (result is double) + shouldExec = (double)result > 0; + else if (result is float) + shouldExec = (float)result > 0; + else if (result is Int16) + shouldExec = (Int16)result > 0; + else if (result is Int32) + shouldExec = (Int32)result > 0; + else if (result is Int64) + shouldExec = (Int64)result > 0; + */ + + handler.Log.Debug("[Execif] Result Type: " + result.GetType().Name); + + if (shouldExec) { - var interpreter = new Interpreter(); - interpreter.SetVariable("MCC", handler); + CmdResult output = new(); + handler.PerformInternalCommand(resultCommand, ref output); - foreach (KeyValuePair entry in Settings.Config.AppVar.GetVariables()) - interpreter.SetVariable(entry.Key, entry.Value); - - var result = interpreter.Eval(expressionText); - - bool shouldExec = result; - - /*if (result is bool) - shouldExec = (bool)result; - else if (result is string) - shouldExec = !string.IsNullOrEmpty((string)result) && ((string)result).Trim().Contains("true", StringComparison.OrdinalIgnoreCase); - else if (result is int) - shouldExec = (int)result > 0; - else if (result is double) - shouldExec = (double)result > 0; - else if (result is float) - shouldExec = (float)result > 0; - else if (result is Int16) - shouldExec = (Int16)result > 0; - else if (result is Int32) - shouldExec = (Int32)result > 0; - else if (result is Int64) - shouldExec = (Int64)result > 0; - */ - - handler.Log.Debug("[Execif] Result Type: " + result.GetType().Name); - - if (shouldExec) - { - string? output = ""; - handler.PerformInternalCommand(resultCommand, ref output); - - if (string.IsNullOrEmpty(output)) - handler.Log.Debug(string.Format(Translations.cmd_execif_executed_no_output, expressionText, resultCommand)); - else - handler.Log.Debug(string.Format(Translations.cmd_execif_executed, expressionText, resultCommand, output)); - - return ""; - } - - return ""; + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_execif_executed, expressionText, resultCommand, output)); } - catch (Exception e) + else { - handler.Log.Error(string.Format(Translations.cmd_execif_error_occured, command)); - handler.Log.Error(string.Format(Translations.cmd_execif_error, e.Message)); - return ""; + return r.SetAndReturn(CmdResult.Status.Done); } } - - return GetCmdDescTranslated(); + catch (Exception e) + { + handler.Log.Error(string.Format(Translations.cmd_execif_error, e.Message)); + return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_execif_error_occured, expressionText + " ---> " + resultCommand)); + } } - - } } diff --git a/MinecraftClient/Commands/ExecMulti.cs b/MinecraftClient/Commands/ExecMulti.cs index 983e5f85..bebff1a1 100644 --- a/MinecraftClient/Commands/ExecMulti.cs +++ b/MinecraftClient/Commands/ExecMulti.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Linq; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -11,42 +13,47 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "execmulti -> -> -> ..."; } } public override string CmdDesc { get { return Translations.cmd_execmulti_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("Commands", Arguments.GreedyString()) + .Executes(r => HandleCommand(r.Source, handler, Arguments.GetString(r, "Commands")))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - string commandsString = GetArg(command); +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } - if (commandsString.Contains("execmulti", StringComparison.OrdinalIgnoreCase) || commandsString.Contains("execif", StringComparison.OrdinalIgnoreCase)) - return Translations.cmd_execmulti_prevent; + private int HandleCommand(CmdResult r, McClient handler, string commandsString) + { + if (commandsString.Contains("execmulti", StringComparison.OrdinalIgnoreCase) || commandsString.Contains("execif", StringComparison.OrdinalIgnoreCase)) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_execmulti_prevent); - IEnumerable commands = commandsString.Split("->", StringSplitOptions.TrimEntries) - .ToList() - .FindAll(command => !string.IsNullOrEmpty(command)); + IEnumerable commands = commandsString.Split("->", StringSplitOptions.TrimEntries) + .ToList() + .FindAll(command => !string.IsNullOrEmpty(command)); - foreach (string cmd in commands) - { - string? output = ""; - handler.PerformInternalCommand(cmd, ref output); - - string log = string.Format( - Translations.cmd_execmulti_executed, cmd, - string.IsNullOrEmpty(output) ? Translations.cmd_execmulti_no_result : string.Format(Translations.cmd_execmulti_result, output)); - - if (output != null && output.Contains("unknown command", StringComparison.OrdinalIgnoreCase)) - handler.Log.Error(log); - else - handler.Log.Info(log); - } - - return ""; + foreach (string cmd in commands) + { + CmdResult output = new(); + handler.PerformInternalCommand(cmd, ref output); + handler.Log.Info(string.Format(Translations.cmd_execmulti_executed, cmd, string.Format(Translations.cmd_execmulti_result, output))); } - return GetCmdDescTranslated(); + return r.SetAndReturn(CmdResult.Status.Done); } } } diff --git a/MinecraftClient/Commands/Exit.cs b/MinecraftClient/Commands/Exit.cs index 9a8ade0d..5618b248 100644 --- a/MinecraftClient/Commands/Exit.cs +++ b/MinecraftClient/Commands/Exit.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -9,19 +10,48 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "exit"; } } public override string CmdDesc { get { return Translations.cmd_exit_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + var exit = dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => DoExit(r.Source, 0)) + .Then(l => l.Argument("ExitCode", Arguments.Integer()) + .Executes(r => DoExit(r.Source, Arguments.GetInteger(r, "ExitCode")))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); + + dispatcher.Register(l => l.Literal("quit") + .Executes(r => DoExit(r.Source, 0)) + .Redirect(exit) + ); } - public override string Run(McClient? handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoExit(CmdResult r, int code = 0) + { + Program.Exit(code); + return r.SetAndReturn(CmdResult.Status.Done); + } + + internal static string DoExit(string command) { Program.Exit(); - return ""; - } - - public override IEnumerable GetCMDAliases() - { - return new string[] { "quit" }; + return string.Empty; } } } diff --git a/MinecraftClient/Commands/Health.cs b/MinecraftClient/Commands/Health.cs index 18f0f67c..29c95598 100644 --- a/MinecraftClient/Commands/Health.cs +++ b/MinecraftClient/Commands/Health.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -9,13 +10,34 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "health"; } } public override string CmdDesc { get { return Translations.cmd_health_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => LogHealth(r.Source, handler)) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - return string.Format(Translations.cmd_health_response, handler.GetHealth(), handler.GetSaturation(), handler.GetLevel(), handler.GetTotalExperience()); + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int LogHealth(CmdResult r, McClient handler) + { + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_health_response, handler.GetHealth(), handler.GetSaturation(), handler.GetLevel(), handler.GetTotalExperience())); } } } diff --git a/MinecraftClient/Commands/Help.cs b/MinecraftClient/Commands/Help.cs new file mode 100644 index 00000000..4727f2bb --- /dev/null +++ b/MinecraftClient/Commands/Help.cs @@ -0,0 +1,33 @@ +using System; +using System.Text; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; + +namespace MinecraftClient.Commands +{ + internal class Help : Command + { + public override string CmdName => throw new NotImplementedException(); + public override string CmdDesc => throw new NotImplementedException(); + public override string CmdUsage => throw new NotImplementedException(); + + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { + dispatcher.Register(l => + l.Literal("help") + .Executes(r => LogHelp(r.Source, handler, dispatcher)) + ); + } + + private int LogHelp(CmdResult r, McClient handler, CommandDispatcher dispatcher) + { + var usage = dispatcher.GetSmartUsage(dispatcher.GetRoot(), CmdResult.Empty); + StringBuilder sb = new(); + foreach (var item in usage) + sb.AppendLine(Settings.Config.Main.Advanced.InternalCmdChar.ToChar() + item.Value); + handler.Log.Info(string.Format(Translations.icmd_list, sb.ToString(), Settings.Config.Main.Advanced.InternalCmdChar.ToChar())); + return r.SetAndReturn(CmdResult.Status.Done); + } + } +} diff --git a/MinecraftClient/Commands/Inventory.cs b/MinecraftClient/Commands/Inventory.cs index 17f45c7d..89f48c6e 100644 --- a/MinecraftClient/Commands/Inventory.cs +++ b/MinecraftClient/Commands/Inventory.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Text; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.Inventory; namespace MinecraftClient.Commands @@ -14,270 +15,374 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return GetBasicUsage(); } } public override string CmdDesc { get { return Translations.cmd_inventory_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + .Then(l => l.Literal("list") + .Executes(r => GetUsage(r.Source, "list"))) + .Then(l => l.Literal("close") + .Executes(r => GetUsage(r.Source, "close"))) + .Then(l => l.Literal("click") + .Executes(r => GetUsage(r.Source, "click"))) + .Then(l => l.Literal("drop") + .Executes(r => GetUsage(r.Source, "drop"))) + .Then(l => l.Literal("creativegive") + .Executes(r => GetUsage(r.Source, "creativegive"))) + .Then(l => l.Literal("creativedelete") + .Executes(r => GetUsage(r.Source, "creativedelete"))) + .Then(l => l.Literal("inventories") + .Executes(r => GetUsage(r.Source, "inventories"))) + .Then(l => l.Literal("search") + .Executes(r => GetUsage(r.Source, "search"))) + .Then(l => l.Literal("help") + .Executes(r => GetUsage(r.Source, "help"))) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => ListAllInventories(r.Source, handler)) + .Then(l => l.Literal("creativegive") + .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Then(l => l.Argument("ItemType", MccArguments.ItemType()) + .Then(l => l.Argument("Count", Arguments.Integer(min: 1)) + .Executes(r => DoCreativeGive(r.Source, handler, Arguments.GetInteger(r, "Slot"), MccArguments.GetItemType(r, "ItemType"), Arguments.GetInteger(r, "Count"))))))) + .Then(l => l.Literal("creativedelete") + .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Executes(r => DoCreativeDelete(r.Source, handler, Arguments.GetInteger(r, "Slot"))))) + .Then(l => l.Literal("inventories") + .Executes(r => ListAvailableInventories(r.Source, handler))) + .Then(l => l.Literal("search") + .Then(l => l.Argument("ItemType", MccArguments.ItemType()) + .Executes(r => SearchItem(r.Source, handler, MccArguments.GetItemType(r, "ItemType"), null)) + .Then(l => l.Argument("Count", Arguments.Integer(0, 64)) + .Executes(r => SearchItem(r.Source, handler, MccArguments.GetItemType(r, "ItemType"), Arguments.GetInteger(r, "Count")))))) + .Then(l => l.Argument("InventoryId", MccArguments.InventoryId()) + .Then(l => l.Literal("close") + .Executes(r => DoCloseAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId")))) + .Then(l => l.Literal("list") + .Executes(r => DoListAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId")))) + .Then(l => l.Literal("click") + .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Executes(r => DoClickAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) + .Then(l => l.Argument("Action", MccArguments.InventoryAction()) + .Executes(r => DoClickAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) + .Then(l => l.Literal("drop") + .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Executes(r => DoDropAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) + .Then(l => l.Literal("all") + .Executes(r => DoDropAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) + .Then(l => l.Literal("player") + .Then(l => l.Literal("list") + .Executes(r => DoListAction(r.Source, handler, inventoryId: 0))) + .Then(l => l.Literal("click") + .Then(l => l.Argument("Slot", Arguments.Integer(0, 45)) + .Executes(r => DoClickAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) + .Then(l => l.Argument("Action", MccArguments.InventoryAction()) + .Executes(r => DoClickAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) + .Then(l => l.Literal("drop") + .Then(l => l.Argument("Slot", Arguments.Integer(0, 45)) + .Executes(r => DoDropAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) + .Then(l => l.Literal("all") + .Executes(r => DoDropAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) + .Then(l => l.Literal("container") + .Then(l => l.Literal("close") + .Executes(r => DoCloseAction(r.Source, handler, inventoryId: null))) + .Then(l => l.Literal("list") + .Executes(r => DoListAction(r.Source, handler, inventoryId: null))) + .Then(l => l.Literal("click") + .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Executes(r => DoClickAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) + .Then(l => l.Argument("Action", MccArguments.InventoryAction()) + .Executes(r => DoClickAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) + .Then(l => l.Literal("drop") + .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Executes(r => DoDropAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) + .Then(l => l.Literal("all") + .Executes(r => DoDropAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (handler.GetInventoryEnabled()) + string usageStr = ' ' + Translations.cmd_inventory_help_usage + ": "; + return r.SetAndReturn(cmd switch { - string[] args = GetArgs(command); - if (args.Length >= 1) - { - int inventoryId; - if (args[0].ToLower() == "creativegive") - { - if (args.Length >= 4) - { - if (!int.TryParse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture, out int slot)) - return GetCmdDescTranslated(); +#pragma warning disable format // @formatter:off + "list" => Translations.cmd_inventory_help_list + usageStr + "/inventory > list", + "close" => Translations.cmd_inventory_help_close + usageStr + "/inventory > close", + "click" => Translations.cmd_inventory_help_click + usageStr + "/inventory > click [left|right|middle|shift]\nDefault is left click", + "drop" => Translations.cmd_inventory_help_drop + usageStr + "/inventory > drop [all]\nAll means drop full stack", + "creativegive" => Translations.cmd_inventory_help_creativegive + usageStr + "/inventory creativegive ", + "creativedelete" => Translations.cmd_inventory_help_creativedelete + usageStr + "/inventory creativedelete ", + "inventories" => Translations.cmd_inventory_help_inventories + usageStr + "/inventory inventories", + "search" => Translations.cmd_inventory_help_search + usageStr + "/inventory search [count]", + "help" => GetCmdDescTranslated(), + "action" => Translations.cmd_inventory_help_unknown + GetAvailableActions(), + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } - if (Enum.TryParse(args[2], true, out ItemType itemType)) - { - if (handler.GetGamemode() == 1) - { - if (!int.TryParse(args[3], NumberStyles.Any, CultureInfo.CurrentCulture, out int count)) - return GetCmdDescTranslated(); + private int GetMaximumInventoryId(McClient handler) + { + List availableIds = handler.GetInventories().Keys.ToList(); + return availableIds.Max(); // use foreground container + } - if (handler.DoCreativeGive(slot, itemType, count, null)) - return string.Format(Translations.cmd_inventory_creative_done, itemType, count, slot); - else - return Translations.cmd_inventory_creative_fail; - } - else - return Translations.cmd_inventory_need_creative; - } - else - return GetCmdDescTranslated(); - } - else - return GetCmdDescTranslated(); - } - else if (args[0].ToLower() == "creativedelete") - { - if (args.Length >= 2) - { - if (!int.TryParse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture, out int slot)) - return GetCmdDescTranslated(); + private int ListAllInventories(CmdResult r, McClient handler) + { + if (!handler.GetInventoryEnabled()) + { + handler.Log.Info(Translations.extra_inventory_required); + return -1; + } + StringBuilder response = new(); + response.Append(Translations.cmd_inventory_inventories).Append(":\n"); + foreach ((int invId, Container inv) in handler.GetInventories()) + response.AppendLine(String.Format(" #{0}: {1}§8", invId, inv.Title)); + response.Append(CmdUsage); + handler.Log.Info(response.ToString()); + return r.SetAndReturn(CmdResult.Status.Done); + } - if (handler.GetGamemode() == 1) - { - if (handler.DoCreativeGive(slot, ItemType.Null, 0, null)) - return string.Format(Translations.cmd_inventory_creative_delete, slot); - else - return Translations.cmd_inventory_creative_fail; - } - else - return Translations.cmd_inventory_need_creative; - } - else - return GetCmdDescTranslated(); - } - else if (args[0].ToLower().StartsWith("p")) - { - // player inventory is always ID 0 - inventoryId = 0; - } - else if (args[0].ToLower().StartsWith("c")) - { - List availableIds = handler.GetInventories().Keys.ToList(); - availableIds.Remove(0); // remove player inventory ID from list - if (availableIds.Count > 0) - inventoryId = availableIds.Max(); // use foreground container - else - return Translations.cmd_inventory_container_not_found; - } - else if (args[0].ToLower().StartsWith("inventories") || args[0].ToLower().StartsWith("i")) - { - Dictionary inventories = handler.GetInventories(); - List availableIds = inventories.Keys.ToList(); - StringBuilder response = new(); - response.AppendLine(Translations.cmd_inventory_inventories_available); + private int DoCreativeGive(CmdResult r, McClient handler, int slot, ItemType itemType, int count) + { + if (!handler.GetInventoryEnabled()) + return r.SetAndReturn(CmdResult.Status.FailNeedInventory); - foreach (int id in availableIds) - response.AppendLine(String.Format(" #{0} - {1}§8", id, inventories[id].Title)); - - return response.ToString(); - } - else if (args[0].ToLower().StartsWith("search") || args[0].ToLower().StartsWith("s")) - { - if (args.Length < 2) - return GetCmdDescTranslated(); - - if (!Enum.TryParse(args[1], true, out ItemType parsedItemType)) - return GetCmdDescTranslated(); - - bool shouldUseItemCount = args.Length >= 3; - int itemCount = 0; - - if (shouldUseItemCount && !int.TryParse(args[2], NumberStyles.Any, CultureInfo.CurrentCulture, out itemCount)) - return GetCmdDescTranslated(); - - Dictionary inventories = handler.GetInventories(); - Dictionary> foundItems = new(); - - List availableInventories = inventories.Values.ToList(); - - availableInventories.ForEach(inventory => - { - inventory.Items.Values - .ToList() - .FindAll(item => item.Type == parsedItemType && (!shouldUseItemCount || item.Count == itemCount)) - .ForEach(item => - { - if (!foundItems.ContainsKey(inventory.ID)) - { - foundItems.Add(inventory.ID, new List() { item }); - return; - } - - List invItems = foundItems[inventory.ID]; - invItems.Add(item); - foundItems.Remove(inventory.ID); - foundItems.Add(inventory.ID, invItems); - }); - }); - - if (foundItems.Count == 0) - return Translations.cmd_inventory_no_found_items; - - StringBuilder response = new(); - - response.AppendLine(Translations.cmd_inventory_found_items + ":"); - - foreach ((int invId, List itemsList) in new SortedDictionary>(foundItems)) - { - if (itemsList.Count > 0) - { - response.AppendLine(String.Format("{0} (#{1}):", inventories[invId].Title, invId)); - - foreach (Item item in itemsList) - response.AppendLine(String.Format("\t- {0}", item.ToFullString())); - - response.AppendLine(" "); - } - } - - return response.ToString(); - } - else if (args[0].ToLower() == "help") - { - if (args.Length >= 2) - return GetSubCommandHelp(args[1]); - else - return GetHelp(); - } - else if (!int.TryParse(args[0], NumberStyles.Any, CultureInfo.CurrentCulture, out inventoryId)) - return GetCmdDescTranslated(); - - Container? inventory = handler.GetInventory(inventoryId); - if (inventory == null) - return string.Format(Translations.cmd_inventory_not_exist, inventoryId); - - string action = args.Length > 1 ? args[1].ToLower() : "list"; - if (action == "close") - { - if (handler.CloseInventory(inventoryId)) - return string.Format(Translations.cmd_inventory_close, inventoryId); - else - return string.Format(Translations.cmd_inventory_close_fail, inventoryId); - } - else if (action == "list") - { - StringBuilder response = new(); - response.Append(Translations.cmd_inventory_inventory); - response.AppendLine(String.Format(" #{0} - {1}§8", inventoryId, inventory.Title)); - - string? asciiArt = inventory.Type.GetAsciiArt(); - if (asciiArt != null && Settings.Config.Main.Advanced.ShowInventoryLayout) - response.AppendLine(asciiArt); - - int selectedHotbar = handler.GetCurrentSlot() + 1; - foreach ((int itemId, Item item) in new SortedDictionary(inventory.Items)) - { - bool isHotbar = inventory.IsHotbar(itemId, out int hotbar); - string hotbarString = isHotbar ? (hotbar + 1).ToString() : " "; - if ((hotbar + 1) == selectedHotbar) - hotbarString = ">" + hotbarString; - response.AppendLine(String.Format("{0,2} | #{1,-2}: {2}", hotbarString, itemId, item.ToFullString())); - } - - if (inventoryId == 0) - response.AppendLine(string.Format(Translations.cmd_inventory_hotbar, (handler.GetCurrentSlot() + 1))); - - response.Remove(response.Length - 1, 1); // Remove last '\n' - return response.ToString(); - } - else if (action == "click" && args.Length >= 3) - { - if (!int.TryParse(args[2], NumberStyles.Any, CultureInfo.CurrentCulture, out int slot)) - return GetCmdDescTranslated(); - - WindowActionType actionType = WindowActionType.LeftClick; - string keyName = Translations.cmd_inventory_left; - if (args.Length >= 4) - { - string b = args[3]; - if (b.ToLower()[0] == 'r') - (actionType, keyName) = (WindowActionType.RightClick, Translations.cmd_inventory_right); - else if (b.ToLower()[0] == 'm') - (actionType, keyName) = (WindowActionType.MiddleClick, Translations.cmd_inventory_middle); - } - - handler.DoWindowAction(inventoryId, slot, actionType); - return string.Format(Translations.cmd_inventory_clicking, keyName, slot, inventoryId); - } - else if (action == "shiftclick" && args.Length >= 3) - { - if (!int.TryParse(args[2], NumberStyles.Any, CultureInfo.CurrentCulture, out int slot)) - return GetCmdDescTranslated(); - - if (!handler.DoWindowAction(inventoryId, slot, WindowActionType.ShiftClick)) - return Translations.cmd_inventory_shiftclick_fail; - - return string.Format(Translations.cmd_inventory_shiftclick, slot, inventoryId); - } - else if (action == "drop" && args.Length >= 3) - { - if (!int.TryParse(args[2], NumberStyles.Any, CultureInfo.CurrentCulture, out int slot)) - return GetCmdDescTranslated(); - - // check item exist - if (!inventory.Items.ContainsKey(slot)) - return string.Format(Translations.cmd_inventory_no_item, slot); - - WindowActionType actionType = WindowActionType.DropItem; - if (args.Length >= 4 && args[3].ToLower() == "all") - actionType = WindowActionType.DropItemStack; - - if (handler.DoWindowAction(inventoryId, slot, actionType)) - { - if (actionType == WindowActionType.DropItemStack) - return string.Format(Translations.cmd_inventory_drop_stack, slot); - else - return string.Format(Translations.cmd_inventory_drop, slot); - } - else - return "Failed"; - } - else - return GetCmdDescTranslated(); - } + if (handler.GetGamemode() == 1) + { + if (handler.DoCreativeGive(slot, itemType, count, null)) + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_inventory_creative_done, itemType, count, slot)); else - { - StringBuilder response = new(); - response.Append(Translations.cmd_inventory_inventories).Append(":\n"); - foreach ((int invId, Container inv) in handler.GetInventories()) - response.AppendLine(String.Format(" #{0}: {1}§8", invId, inv.Title)); - response.Append(CmdUsage); - return response.ToString(); - } + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_inventory_creative_fail); } else - return Translations.extra_inventory_required; + { + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_inventory_need_creative); + } } + private int DoCreativeDelete(CmdResult r, McClient handler, int slot) + { + if (!handler.GetInventoryEnabled()) + return r.SetAndReturn(CmdResult.Status.FailNeedInventory); + + if (handler.GetGamemode() == 1) + { + if (handler.DoCreativeGive(slot, ItemType.Null, 0, null)) + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_inventory_creative_delete, slot)); + else + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_inventory_creative_fail); + } + else + { + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_inventory_need_creative); + } + } + + private int ListAvailableInventories(CmdResult r, McClient handler) + { + if (!handler.GetInventoryEnabled()) + return r.SetAndReturn(CmdResult.Status.FailNeedInventory); + + Dictionary inventories = handler.GetInventories(); + List availableIds = inventories.Keys.ToList(); + StringBuilder response = new(); + response.AppendLine(Translations.cmd_inventory_inventories_available); + + foreach (int id in availableIds) + response.AppendLine(String.Format(" #{0} - {1}§8", id, inventories[id].Title)); + + handler.Log.Info(response.ToString()); + return r.SetAndReturn(CmdResult.Status.Done); + } + + private int SearchItem(CmdResult r, McClient handler, ItemType itemType, int? itemCount) + { + if (!handler.GetInventoryEnabled()) + return r.SetAndReturn(CmdResult.Status.FailNeedInventory); + + Dictionary inventories = handler.GetInventories(); + Dictionary> foundItems = new(); + + List availableInventories = inventories.Values.ToList(); + + availableInventories.ForEach(inventory => + { + inventory.Items.Values + .ToList() + .FindAll(item => item.Type == itemType && (!itemCount.HasValue || item.Count == itemCount)) + .ForEach(item => + { + if (!foundItems.ContainsKey(inventory.ID)) + { + foundItems.Add(inventory.ID, new List() { item }); + return; + } + + List invItems = foundItems[inventory.ID]; + invItems.Add(item); + foundItems.Remove(inventory.ID); + foundItems.Add(inventory.ID, invItems); + }); + }); + + if (foundItems.Count == 0) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_inventory_no_found_items); + + StringBuilder response = new(); + + response.AppendLine(Translations.cmd_inventory_found_items + ":"); + + foreach ((int invId, List itemsList) in new SortedDictionary>(foundItems)) + { + if (itemsList.Count > 0) + { + response.AppendLine(String.Format("{0} (#{1}):", inventories[invId].Title, invId)); + + foreach (Item item in itemsList) + response.AppendLine(String.Format("\t- {0}", item.ToFullString())); + + response.AppendLine(" "); + } + } + + handler.Log.Info(response.ToString()); + return r.SetAndReturn(CmdResult.Status.Done); + } + + private int DoCloseAction(CmdResult r, McClient handler, int? inventoryId) + { + if (!handler.GetInventoryEnabled()) + return r.SetAndReturn(CmdResult.Status.FailNeedInventory); + + if (!inventoryId.HasValue) + { + inventoryId = GetMaximumInventoryId(handler); + if (inventoryId == 0) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_inventory_container_not_found); + } + + Container? inventory = handler.GetInventory(inventoryId.Value); + if (inventory == null) + return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_inventory_not_exist, inventoryId)); + + if (handler.CloseInventory(inventoryId.Value)) + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_inventory_close, inventoryId)); + else + return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_inventory_close_fail, inventoryId)); + } + + private int DoListAction(CmdResult r, McClient handler, int? inventoryId) + { + if (!handler.GetInventoryEnabled()) + return r.SetAndReturn(CmdResult.Status.FailNeedInventory); + + if (!inventoryId.HasValue) + { + inventoryId = GetMaximumInventoryId(handler); + if (inventoryId == 0) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_inventory_container_not_found); + } + + Container? inventory = handler.GetInventory(inventoryId.Value); + if (inventory == null) + return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_inventory_not_exist, inventoryId)); + + StringBuilder response = new(); + response.Append(Translations.cmd_inventory_inventory); + response.AppendLine(String.Format(" #{0} - {1}§8", inventoryId, inventory.Title)); + + string? asciiArt = inventory.Type.GetAsciiArt(); + if (asciiArt != null && Settings.Config.Main.Advanced.ShowInventoryLayout) + response.AppendLine(asciiArt); + + int selectedHotbar = handler.GetCurrentSlot() + 1; + foreach ((int itemId, Item item) in new SortedDictionary(inventory.Items)) + { + bool isHotbar = inventory.IsHotbar(itemId, out int hotbar); + string hotbarString = isHotbar ? (hotbar + 1).ToString() : " "; + if ((hotbar + 1) == selectedHotbar) + hotbarString = ">" + hotbarString; + response.AppendLine(String.Format("{0,2} | #{1,-2}: {2}", hotbarString, itemId, item.ToFullString())); + } + + if (inventoryId == 0) + response.AppendLine(string.Format(Translations.cmd_inventory_hotbar, (handler.GetCurrentSlot() + 1))); + + response.Remove(response.Length - 1, 1); // Remove last '\n' + handler.Log.Info(response.ToString()); + return r.SetAndReturn(CmdResult.Status.Done); + } + + private int DoClickAction(CmdResult r, McClient handler, int? inventoryId, int slot, WindowActionType actionType) + { + if (!handler.GetInventoryEnabled()) + return r.SetAndReturn(CmdResult.Status.FailNeedInventory); + + if (!inventoryId.HasValue) + { + inventoryId = GetMaximumInventoryId(handler); + if (inventoryId == 0) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_inventory_container_not_found); + } + + Container? inventory = handler.GetInventory(inventoryId.Value); + if (inventory == null) + return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_inventory_not_exist, inventoryId)); + + string keyName = actionType switch + { + WindowActionType.LeftClick => Translations.cmd_inventory_left, + WindowActionType.RightClick => Translations.cmd_inventory_right, + WindowActionType.MiddleClick => Translations.cmd_inventory_middle, + WindowActionType.ShiftClick => Translations.cmd_inventory_shiftclick, + _ => "unknown", + }; + + handler.Log.Info(string.Format(Translations.cmd_inventory_clicking, keyName, slot, inventoryId)); + return r.SetAndReturn(handler.DoWindowAction(inventoryId.Value, slot, actionType)); + } + + private int DoDropAction(CmdResult r, McClient handler, int? inventoryId, int slot, WindowActionType actionType) + { + if (!handler.GetInventoryEnabled()) + return r.SetAndReturn(CmdResult.Status.FailNeedInventory); + + if (!inventoryId.HasValue) + { + inventoryId = GetMaximumInventoryId(handler); + if (inventoryId == 0) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_inventory_container_not_found); + } + + Container? inventory = handler.GetInventory(inventoryId.Value); + if (inventory == null) + return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_inventory_not_exist, inventoryId)); + + // check item exist + if (!inventory.Items.ContainsKey(slot)) + return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_inventory_no_item, slot)); + + if (handler.DoWindowAction(inventoryId.Value, slot, actionType)) + { + if (actionType == WindowActionType.DropItemStack) + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_inventory_drop_stack, slot)); + else + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_inventory_drop, slot)); + } + else + { + return r.SetAndReturn(CmdResult.Status.Fail, "Drop Failed"); + } + } + + #region Methods for commands help private static string GetAvailableActions() @@ -290,31 +395,6 @@ namespace MinecraftClient.Commands return Translations.cmd_inventory_help_basic + ": /inventory > ."; } - private static string GetHelp() - { - return string.Format(Translations.cmd_inventory_help_help, GetAvailableActions()); - } - - private static string GetSubCommandHelp(string cmd) - { - string usageStr = ' ' + Translations.cmd_inventory_help_usage + ": "; - return cmd switch - { -#pragma warning disable format // @formatter:off - "list" => Translations.cmd_inventory_help_list + usageStr + "/inventory > list", - "close" => Translations.cmd_inventory_help_close + usageStr + "/inventory > close", - "click" => Translations.cmd_inventory_help_click + usageStr + "/inventory > click [left|right|middle]\nDefault is left click", - "shiftclick" => Translations.cmd_inventory_help_shiftclick + usageStr + "/inventory > shiftclick ", - "drop" => Translations.cmd_inventory_help_drop + usageStr + "/inventory > drop [all]\nAll means drop full stack", - "creativegive" => Translations.cmd_inventory_help_creativegive + usageStr + "/inventory creativegive ", - "creativedelete" => Translations.cmd_inventory_help_creativedelete + usageStr + "/inventory creativedelete ", - "inventories" => Translations.cmd_inventory_help_inventories + usageStr + "/inventory inventories", - "search" => Translations.cmd_inventory_help_search + usageStr + "/inventory search [count]", - "help" => GetHelp(), - _ => Translations.cmd_inventory_help_unknown + GetAvailableActions(), -#pragma warning restore format // @formatter:on - }; - } #endregion } } diff --git a/MinecraftClient/Commands/List.cs b/MinecraftClient/Commands/List.cs index 64273a89..78b3c9d2 100644 --- a/MinecraftClient/Commands/List.cs +++ b/MinecraftClient/Commands/List.cs @@ -1,6 +1,7 @@ using System; -using System.Collections.Generic; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -10,13 +11,34 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "list"; } } public override string CmdDesc { get { return Translations.cmd_list_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => DoListPlayers(r.Source, handler)) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - return string.Format(Translations.cmd_list_players, String.Join(", ", handler.GetOnlinePlayers())); + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoListPlayers(CmdResult r, McClient handler) + { + return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_list_players, String.Join(", ", handler.GetOnlinePlayers()))); } } } diff --git a/MinecraftClient/Commands/Log.cs b/MinecraftClient/Commands/Log.cs index 4b03e93f..e9181ed3 100644 --- a/MinecraftClient/Commands/Log.cs +++ b/MinecraftClient/Commands/Log.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -9,18 +10,35 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "log "; } } public override string CmdDesc { get { return Translations.cmd_log_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("String", Arguments.GreedyString()) + .Executes(r => DoLog(r.Source, Arguments.GetString(r, "String")))) + .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - ConsoleIO.WriteLogLine(GetArg(command)); - return ""; - } - else return GetCmdDescTranslated(); +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoLog(CmdResult r, string command) + { + return r.SetAndReturn(CmdResult.Status.Done, command); } } } diff --git a/MinecraftClient/Commands/Look.cs b/MinecraftClient/Commands/Look.cs index f03e69d3..2376bbc1 100644 --- a/MinecraftClient/Commands/Look.cs +++ b/MinecraftClient/Commands/Look.cs @@ -1,8 +1,9 @@ using System; -using System.Collections.Generic; -using System.Globalization; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { @@ -12,74 +13,102 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "look "; } } public override string CmdDesc { get { return Translations.cmd_look_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + .Then(l => l.Literal("direction") + .Executes(r => GetUsage(r.Source, "direction"))) + .Then(l => l.Literal("angle") + .Executes(r => GetUsage(r.Source, "angle"))) + .Then(l => l.Literal("location") + .Executes(r => GetUsage(r.Source, "location"))) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => LogCurrentLooking(r.Source, handler)) + .Then(l => l.Literal("up") + .Executes(r => LookAtDirection(r.Source, handler, Direction.Up))) + .Then(l => l.Literal("down") + .Executes(r => LookAtDirection(r.Source, handler, Direction.Down))) + .Then(l => l.Literal("east") + .Executes(r => LookAtDirection(r.Source, handler, Direction.East))) + .Then(l => l.Literal("west") + .Executes(r => LookAtDirection(r.Source, handler, Direction.West))) + .Then(l => l.Literal("north") + .Executes(r => LookAtDirection(r.Source, handler, Direction.North))) + .Then(l => l.Literal("south") + .Executes(r => LookAtDirection(r.Source, handler, Direction.South))) + .Then(l => l.Argument("Yaw", Arguments.Float()) + .Then(l => l.Argument("Pitch", Arguments.Float()) + .Executes(r => LookAtAngle(r.Source, handler, Arguments.GetFloat(r, "Yaw"), Arguments.GetFloat(r, "Pitch"))))) + .Then(l => l.Argument("Location", MccArguments.Location()) + .Executes(r => LookAtLocation(r.Source, handler, MccArguments.GetLocation(r, "Location")))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (handler.GetTerrainEnabled()) + return r.SetAndReturn(cmd switch { - string[] args = GetArgs(command); - if (args.Length == 0) - { - const double maxDistance = 8.0; - (bool hasBlock, Location target, Block block) = RaycastHelper.RaycastBlock(handler, maxDistance, false); - if (!hasBlock) - return string.Format(Translations.cmd_look_noinspection, maxDistance); - else - { - Location current = handler.GetCurrentLocation(), target_center = target.ToCenter(); - return string.Format(Translations.cmd_look_inspection, block.Type, target.X, target.Y, target.Z, - current.Distance(target_center), current.EyesLocation().Distance(target_center)); - } - } - else if (args.Length == 1) - { - string dirStr = GetArg(command).Trim().ToLower(); - Direction direction; - switch (dirStr) - { - case "up": direction = Direction.Up; break; - case "down": direction = Direction.Down; break; - case "east": direction = Direction.East; break; - case "west": direction = Direction.West; break; - case "north": direction = Direction.North; break; - case "south": direction = Direction.South; break; - default: return string.Format(Translations.cmd_look_unknown, dirStr); - } +#pragma warning disable format // @formatter:off + "direction" => GetCmdDescTranslated(), + "angle" => GetCmdDescTranslated(), + "location" => GetCmdDescTranslated(), + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } - handler.UpdateLocation(handler.GetCurrentLocation(), direction); - return "Looking " + dirStr; - } - else if (args.Length == 2) - { - try - { - float yaw = float.Parse(args[0], NumberStyles.Any, CultureInfo.CurrentCulture); - float pitch = float.Parse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture); + private int LogCurrentLooking(CmdResult r, McClient handler) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); - handler.UpdateLocation(handler.GetCurrentLocation(), yaw, pitch); - return string.Format(Translations.cmd_look_at, yaw.ToString("0.00"), pitch.ToString("0.00")); - } - catch (FormatException) { return GetCmdDescTranslated(); } - } - else if (args.Length == 3) - { - try - { - Location current = handler.GetCurrentLocation(); - Location block = Location.Parse(current, args[0], args[1], args[2]); - handler.UpdateLocation(current, block); - - return string.Format(Translations.cmd_look_block, block); - } - catch (FormatException) { return CmdUsage; } - - } - else return GetCmdDescTranslated(); + const double maxDistance = 8.0; + (bool hasBlock, Location target, Block block) = RaycastHelper.RaycastBlock(handler, maxDistance, false); + if (!hasBlock) + { + return r.SetAndReturn(Status.Fail, string.Format(Translations.cmd_look_noinspection, maxDistance)); } - else return Translations.extra_terrainandmovement_required; + else + { + Location current = handler.GetCurrentLocation(), target_center = target.ToCenter(); + return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_look_inspection, block.Type, target.X, target.Y, target.Z, + current.Distance(target_center), current.EyesLocation().Distance(target_center))); + } + } + + private int LookAtDirection(CmdResult r, McClient handler, Direction direction) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + handler.UpdateLocation(handler.GetCurrentLocation(), direction); + return r.SetAndReturn(Status.Done, "Looking " + direction.ToString()); + } + + private int LookAtAngle(CmdResult r, McClient handler, float yaw, float pitch) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + handler.UpdateLocation(handler.GetCurrentLocation(), yaw, pitch); + return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_look_at, yaw.ToString("0.00"), pitch.ToString("0.00"))); + } + + private int LookAtLocation(CmdResult r, McClient handler, Location location) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + Location current = handler.GetCurrentLocation(); + handler.UpdateLocation(current, location); + return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_look_block, location)); } } } diff --git a/MinecraftClient/Commands/Move.cs b/MinecraftClient/Commands/Move.cs index 679f51f6..d3b0897b 100644 --- a/MinecraftClient/Commands/Move.cs +++ b/MinecraftClient/Commands/Move.cs @@ -1,8 +1,9 @@ using System; -using System.Collections.Generic; -using System.Linq; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { @@ -12,111 +13,183 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "move [-f]"; } } public override string CmdDesc { get { return Translations.cmd_move_desc + " \"-f\": " + Translations.cmd_move_desc_force; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + .Then(l => l.Literal("enable") + .Executes(r => GetUsage(r.Source, "enable"))) + .Then(l => l.Literal("gravity") + .Executes(r => GetUsage(r.Source, "gravity"))) + .Then(l => l.Literal("direction") + .Executes(r => GetUsage(r.Source, "direction"))) + .Then(l => l.Literal("center") + .Executes(r => GetUsage(r.Source, "center"))) + .Then(l => l.Literal("get") + .Executes(r => GetUsage(r.Source, "get"))) + .Then(l => l.Literal("location") + .Executes(r => GetUsage(r.Source, "location"))) + .Then(l => l.Literal("-f") + .Executes(r => GetUsage(r.Source, "-f"))) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Literal("on") + .Executes(r => SetMovementEnable(r.Source, handler, enable: true))) + .Then(l => l.Literal("off") + .Executes(r => SetMovementEnable(r.Source, handler, enable: false))) + .Then(l => l.Literal("gravity") + .Executes(r => SetGravityEnable(r.Source, handler, enable: null)) + .Then(l => l.Literal("on") + .Executes(r => SetGravityEnable(r.Source, handler, enable: true))) + .Then(l => l.Literal("off") + .Executes(r => SetGravityEnable(r.Source, handler, enable: false)))) + .Then(l => l.Literal("up") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.Up, false)) + .Then(l => l.Literal("-f") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.Up, true)))) + .Then(l => l.Literal("down") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.Down, false)) + .Then(l => l.Literal("-f") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.Down, true)))) + .Then(l => l.Literal("east") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.East, false)) + .Then(l => l.Literal("-f") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.East, true)))) + .Then(l => l.Literal("west") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.West, false)) + .Then(l => l.Literal("-f") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.West, true)))) + .Then(l => l.Literal("north") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.North, false)) + .Then(l => l.Literal("-f") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.North, true)))) + .Then(l => l.Literal("south") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.South, false)) + .Then(l => l.Literal("-f") + .Executes(r => MoveOnDirection(r.Source, handler, Direction.South, true)))) + .Then(l => l.Literal("center") + .Executes(r => MoveToCenter(r.Source, handler))) + .Then(l => l.Literal("get") + .Executes(r => GetCurrentLocation(r.Source, handler))) + .Then(l => l.Argument("location", MccArguments.Location()) + .Executes(r => MoveToLocation(r.Source, handler, MccArguments.GetLocation(r, "location"), false)) + .Then(l => l.Literal("-f") + .Executes(r => MoveToLocation(r.Source, handler, MccArguments.GetLocation(r, "location"), true)))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - List args = GetArgs(command.ToLower()).ToList(); - bool takeRisk = false; - - if (args.Count < 1) + return r.SetAndReturn(cmd switch { - string desc = GetCmdDescTranslated(); +#pragma warning disable format // @formatter:off + "enable" => GetCmdDescTranslated(), + "gravity" => GetCmdDescTranslated(), + "direction" => GetCmdDescTranslated(), + "center" => GetCmdDescTranslated(), + "get" => GetCmdDescTranslated(), + "location" => GetCmdDescTranslated(), + "-f" => GetCmdDescTranslated(), + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } - if (handler.GetTerrainEnabled()) - handler.Log.Info(World.GetChunkLoadingStatus(handler.GetWorld())); - - return desc; - } - - if (args.Contains("-f")) - { - takeRisk = true; - args.Remove("-f"); - } - - if (args[0] == "on") + private int SetMovementEnable(CmdResult r, McClient handler, bool enable) + { + if (enable) { handler.SetTerrainEnabled(true); - return Translations.cmd_move_enable; + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_move_enable); } - else if (args[0] == "off") + else { handler.SetTerrainEnabled(false); - return Translations.cmd_move_disable; + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_move_disable); } - else if (args[0] == "gravity") + } + + private int SetGravityEnable(CmdResult r, McClient handler, bool? enable) + { + if (enable.HasValue) + Settings.InternalConfig.GravityEnabled = enable.Value; + + if (Settings.InternalConfig.GravityEnabled) + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_move_gravity_enabled); + else + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_move_gravity_disabled); + } + + private int GetCurrentLocation(CmdResult r, McClient handler) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + return r.SetAndReturn(Status.Done, handler.GetCurrentLocation().ToString()); + } + + private int MoveToCenter(CmdResult r, McClient handler) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + Location current = handler.GetCurrentLocation(); + Location currentCenter = new(Math.Floor(current.X) + 0.5, current.Y, Math.Floor(current.Z) + 0.5); + handler.MoveTo(currentCenter, allowDirectTeleport: true); + return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_move_walk, currentCenter, current)); + } + + private int MoveOnDirection(CmdResult r, McClient handler, Direction direction, bool takeRisk) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + Location goal = Movement.Move(handler.GetCurrentLocation(), direction); + + if (!Movement.CheckChunkLoading(handler.GetWorld(), handler.GetCurrentLocation(), goal)) + return r.SetAndReturn(Status.FailChunkNotLoad, string.Format(Translations.cmd_move_chunk_not_loaded, goal.X, goal.Y, goal.Z)); + + if (Movement.CanMove(handler.GetWorld(), handler.GetCurrentLocation(), direction)) { - if (args.Count >= 2) - Settings.InternalConfig.GravityEnabled = (args[1] == "on"); - if (Settings.InternalConfig.GravityEnabled) - return Translations.cmd_move_gravity_enabled; - else return Translations.cmd_move_gravity_disabled; + if (handler.MoveTo(goal, allowUnsafe: takeRisk)) + return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_move_moving, direction.ToString())); + else + return r.SetAndReturn(Status.Fail, takeRisk ? Translations.cmd_move_dir_fail : Translations.cmd_move_suggestforce); } - else if (handler.GetTerrainEnabled()) + else { - if (args.Count == 1) - { - Direction direction; - switch (args[0]) - { - case "up": direction = Direction.Up; break; - case "down": direction = Direction.Down; break; - case "east": direction = Direction.East; break; - case "west": direction = Direction.West; break; - case "north": direction = Direction.North; break; - case "south": direction = Direction.South; break; - case "center": - Location current = handler.GetCurrentLocation(); - Location currentCenter = new(Math.Floor(current.X) + 0.5, current.Y, Math.Floor(current.Z) + 0.5); - handler.MoveTo(currentCenter, allowDirectTeleport: true); - return string.Format(Translations.cmd_move_walk, currentCenter, current); - case "get": return handler.GetCurrentLocation().ToString(); - default: return string.Format(Translations.cmd_look_unknown, args[0]); - } - - Location goal = Movement.Move(handler.GetCurrentLocation(), direction); - - if (!Movement.CheckChunkLoading(handler.GetWorld(), handler.GetCurrentLocation(), goal)) - return string.Format(Translations.cmd_move_chunk_not_loaded, goal.X, goal.Y, goal.Z); - - if (Movement.CanMove(handler.GetWorld(), handler.GetCurrentLocation(), direction)) - { - if (handler.MoveTo(goal, allowUnsafe: takeRisk)) - return string.Format(Translations.cmd_move_moving, args[0]); - else - return takeRisk ? Translations.cmd_move_dir_fail : Translations.cmd_move_suggestforce; - } - else return Translations.cmd_move_dir_fail; - } - else if (args.Count == 3) - { - try - { - Location current = handler.GetCurrentLocation(), currentCenter = current.ToCenter(); - Location goal = Location.Parse(current, args[0], args[1], args[2]); - - if (!Movement.CheckChunkLoading(handler.GetWorld(), current, goal)) - return string.Format(Translations.cmd_move_chunk_not_loaded, goal.X, goal.Y, goal.Z); - - if (takeRisk || Movement.PlayerFitsHere(handler.GetWorld(), goal)) - { - if (current.ToFloor() == goal.ToFloor()) - handler.MoveTo(goal, allowDirectTeleport: true); - else if (!handler.MoveTo(goal, allowUnsafe: takeRisk)) - return takeRisk ? string.Format(Translations.cmd_move_fail, goal) : string.Format(Translations.cmd_move_suggestforce, goal); - return string.Format(Translations.cmd_move_walk, goal, current); - } - else - return string.Format(Translations.cmd_move_suggestforce, goal); - } - catch (FormatException) { return GetCmdDescTranslated(); } - } - else return GetCmdDescTranslated(); + return r.SetAndReturn(Status.Fail, Translations.cmd_move_dir_fail); + } + } + + private int MoveToLocation(CmdResult r, McClient handler, Location goal, bool takeRisk) + { + if (!handler.GetTerrainEnabled()) + return r.SetAndReturn(Status.FailNeedTerrain); + + Location current = handler.GetCurrentLocation(), currentCenter = current.ToCenter(); + goal.ToAbsolute(current); + + if (!Movement.CheckChunkLoading(handler.GetWorld(), current, goal)) + return r.SetAndReturn(Status.FailChunkNotLoad, string.Format(Translations.cmd_move_chunk_not_loaded, goal.X, goal.Y, goal.Z)); + + if (takeRisk || Movement.PlayerFitsHere(handler.GetWorld(), goal)) + { + if (current.ToFloor() == goal.ToFloor()) + handler.MoveTo(goal, allowDirectTeleport: true); + else if (!handler.MoveTo(goal, allowUnsafe: takeRisk)) + return r.SetAndReturn(Status.Fail, takeRisk ? string.Format(Translations.cmd_move_fail, goal) : string.Format(Translations.cmd_move_suggestforce, goal)); + return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_move_walk, goal, current)); + } + else + { + return r.SetAndReturn(Status.Fail, string.Format(Translations.cmd_move_suggestforce, goal)); } - else return Translations.extra_terrainandmovement_required; } } } diff --git a/MinecraftClient/Commands/Reco.cs b/MinecraftClient/Commands/Reco.cs index b92b4fcb..c2ef3081 100644 --- a/MinecraftClient/Commands/Reco.cs +++ b/MinecraftClient/Commands/Reco.cs @@ -1,5 +1,7 @@ -using System.Collections.Generic; +using System; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -9,22 +11,58 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "reco [account]"; } } public override string CmdDesc { get { return Translations.cmd_reco_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => DoReconnect(r.Source, string.Empty)) + .Then(l => l.Argument("AccountNick", MccArguments.AccountNick()) + .Executes(r => DoReconnect(r.Source, Arguments.GetString(r, "AccountNick")))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient? handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoReconnect(CmdResult r, string account) + { + if (string.IsNullOrWhiteSpace(account)) + { + account = account.Trim(); + if (!Settings.Config.Main.Advanced.SetAccount(account)) + return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_connect_unknown, account)); + } + Program.Restart(keepAccountAndServerSettings: true); + return r.SetAndReturn(CmdResult.Status.Done); + } + + internal static string DoReconnect(string command) { string[] args = GetArgs(command); if (args.Length > 0) { - if (!Settings.Config.Main.Advanced.SetAccount(args[0])) + string account = args[0].Trim(); + if (!Settings.Config.Main.Advanced.SetAccount(account)) { - return string.Format(Translations.cmd_connect_unknown, args[0]); + return string.Format(Translations.cmd_connect_unknown, account); } } Program.Restart(keepAccountAndServerSettings: true); - return ""; + return String.Empty; } } } diff --git a/MinecraftClient/Commands/Reload.cs b/MinecraftClient/Commands/Reload.cs index 2409827e..6ab4cfaf 100644 --- a/MinecraftClient/Commands/Reload.cs +++ b/MinecraftClient/Commands/Reload.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -9,11 +10,32 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "reload"; } } public override string CmdDesc { get { return Translations.cmd_reload_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => DoReload(r.Source, handler)) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoReload(CmdResult r, McClient handler) { handler.Log.Info(Translations.cmd_reload_started); handler.ReloadSettings(); @@ -22,7 +44,7 @@ namespace MinecraftClient.Commands handler.Log.Warn(Translations.cmd_reload_warning3); handler.Log.Warn(Translations.cmd_reload_warning4); - return Translations.cmd_reload_finished; + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_reload_finished); } } } diff --git a/MinecraftClient/Commands/Respawn.cs b/MinecraftClient/Commands/Respawn.cs index 2eedc088..d9bfbcbf 100644 --- a/MinecraftClient/Commands/Respawn.cs +++ b/MinecraftClient/Commands/Respawn.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -9,14 +10,35 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "respawn"; } } public override string CmdDesc { get { return Translations.cmd_respawn_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => DoRespawn(r.Source, handler)) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoRespawn(CmdResult r, McClient handler) { handler.SendRespawnPacket(); - return Translations.cmd_respawn_done; + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_respawn_done); } } } diff --git a/MinecraftClient/Commands/Script.cs b/MinecraftClient/Commands/Script.cs index 239f7737..f7f850f2 100644 --- a/MinecraftClient/Commands/Script.cs +++ b/MinecraftClient/Commands/Script.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -9,18 +11,36 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "script "; } } public override string CmdDesc { get { return Translations.cmd_script_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("Script", Arguments.GreedyString()) + .Executes(r => DoExecuteScript(r.Source, handler, Arguments.GetString(r, "Script"), null))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - handler.BotLoad(new ChatBots.Script(GetArg(command), null, localVars)); - return ""; - } - else return GetCmdDescTranslated(); +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoExecuteScript(CmdResult r, McClient handler, string command, Dictionary? localVars) + { + handler.BotLoad(new ChatBots.Script(command.Trim(), null, localVars)); + return r.SetAndReturn(CmdResult.Status.Done); } } } diff --git a/MinecraftClient/Commands/Send.cs b/MinecraftClient/Commands/Send.cs index 2e868904..d17bc3b5 100644 --- a/MinecraftClient/Commands/Send.cs +++ b/MinecraftClient/Commands/Send.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -9,18 +10,34 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "send "; } } public override string CmdDesc { get { return Translations.cmd_send_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("any", Arguments.GreedyString()) + .Executes(r => DoSendText(r.Source, handler, Arguments.GetString(r, "any")))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - handler.SendText(GetArg(command)); - return ""; - } - else return GetCmdDescTranslated(); +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoSendText(CmdResult r, McClient handler, string command) + { + handler.SendText(command); + return r.SetAndReturn(CmdResult.Status.Done); } } } diff --git a/MinecraftClient/Commands/Set.cs b/MinecraftClient/Commands/Set.cs index 09db64e7..3bf6d86f 100644 --- a/MinecraftClient/Commands/Set.cs +++ b/MinecraftClient/Commands/Set.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -9,27 +10,50 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "set varname=value"; } } public override string CmdDesc { get { return Translations.cmd_set_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("Expression", Arguments.GreedyString()) + .Executes(r => DoSetVar(r.Source, Arguments.GetString(r, "Expression")))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - string[] temp = GetArg(command).Split('='); - if (temp.Length > 1) +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoSetVar(CmdResult r, string command) + { + string[] temp = command.Trim().Split('='); + if (temp.Length > 1) + { + if (Settings.Config.AppVar.SetVar(temp[0], command[(temp[0].Length + 1)..])) { - if (Settings.Config.AppVar.SetVar(temp[0], GetArg(command).Substring(temp[0].Length + 1))) - return ""; //Success - else - return Translations.cmd_set_format; + return r.SetAndReturn(CmdResult.Status.Done); //Success } else - return GetCmdDescTranslated(); + { + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_set_format); + } } else - return GetCmdDescTranslated(); + { + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_set_format); + } } } } diff --git a/MinecraftClient/Commands/SetRnd.cs b/MinecraftClient/Commands/SetRnd.cs index d6f23b7c..73e8673b 100644 --- a/MinecraftClient/Commands/SetRnd.cs +++ b/MinecraftClient/Commands/SetRnd.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -11,65 +13,61 @@ namespace MinecraftClient.Commands public override string CmdDesc { get { return Translations.cmd_setrnd_desc; } } private static readonly Random rand = new(); - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + .Then(l => l.Literal("range") + .Executes(r => GetUsage(r.Source, "range"))) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("VarName", Arguments.String()) + .Then(l => l.Argument("Min", Arguments.Long()) + .Then(l => l.Literal("to") + .Then(l => l.Argument("Max", Arguments.Long()) + .Executes(r => DoSetRnd(r.Source, Arguments.GetString(r, "VarName"), Arguments.GetLong(r, "Min"), Arguments.GetLong(r, "Max")))))) + .Then(l => l.Argument("Expression", Arguments.GreedyString()) + .Executes(r => DoSetRnd(r.Source, Arguments.GetString(r, "VarName"), Arguments.GetString(r, "Expression"))))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (HasArg(command)) + return r.SetAndReturn(cmd switch { - string[] args = GetArg(command).Split(' '); +#pragma warning disable format // @formatter:off + "range" => GetCmdDescTranslated(), + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } - if (args.Length > 1) - { - // detect "to" keyword in string - if (args.Length == 2 && args[1].Contains("to")) - { - int num1; - int num2; + private int DoSetRnd(CmdResult r, string var, string argString) + { + // process all arguments similar to regular terminals with quotes and escaping + List values = ParseCommandLine(argString); - // try to extract the two numbers from the string - try - { - num1 = Convert.ToInt32(args[1][..args[1].IndexOf('t')]); - num2 = Convert.ToInt32(args[1].Substring(args[1].IndexOf('o') + 1, args[1].Length - 1 - args[1].IndexOf('o'))); - } - catch (Exception) - { - return Translations.cmd_setrndnum_format; - } + // create a variable or set it to one of the values + if (values.Count > 0 && Settings.Config.AppVar.SetVar(var, values[rand.Next(0, values.Count)])) + return r.SetAndReturn(CmdResult.Status.Done, string.Format("Set %{0}% to {1}.", var, Settings.Config.AppVar.GetVar(var))); + else + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_setrndstr_format); + } - // switch the values if they were entered in the wrong way - if (num2 < num1) - (num2, num1) = (num1, num2); + private int DoSetRnd(CmdResult r, string var, long min, long max) + { + // switch the values if they were entered in the wrong way + if (max < min) + (max, min) = (min, max); - // create a variable or set it to num1 <= varlue < num2 - if (Settings.Config.AppVar.SetVar(args[0], rand.Next(num1, num2))) - { - return string.Format("Set %{0}% to {1}.", args[0], Settings.Config.AppVar.GetVar(args[0])); //Success - } - else return Translations.cmd_setrndnum_format; - } - else - { - // extract all arguments of the command - string argString = command[(8 + command.Split(' ')[1].Length)..]; - - // process all arguments similar to regular terminals with quotes and escaping - List values = ParseCommandLine(argString); - - // create a variable or set it to one of the values - if (values.Count > 0 && Settings.Config.AppVar.SetVar(args[0], values[rand.Next(0, values.Count)])) - { - return string.Format("Set %{0}% to {1}.", args[0], Settings.Config.AppVar.GetVar(args[0])); //Success - } - else return Translations.cmd_setrndstr_format; - } - } - else return GetCmdDescTranslated(); - } - else return GetCmdDescTranslated(); + // create a variable or set it to num1 <= varlue < num2 + if (Settings.Config.AppVar.SetVar(var, rand.NextInt64(min, max))) + return r.SetAndReturn(CmdResult.Status.Fail, string.Format("Set %{0}% to {1}.", var, Settings.Config.AppVar.GetVar(var))); + else + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_setrndstr_format); } } } diff --git a/MinecraftClient/Commands/Sneak.cs b/MinecraftClient/Commands/Sneak.cs index eac0a7cd..d21bea8a 100644 --- a/MinecraftClient/Commands/Sneak.cs +++ b/MinecraftClient/Commands/Sneak.cs @@ -1,34 +1,62 @@ -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { public class Sneak : Command { private bool sneaking = false; - public override string CmdName { get { return "Sneak"; } } - public override string CmdUsage { get { return "Sneak"; } } + public override string CmdName { get { return "sneak"; } } + public override string CmdUsage { get { return "sneak"; } } public override string CmdDesc { get { return Translations.cmd_sneak_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => DoSneak(r.Source, handler)) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoSneak(CmdResult r, McClient handler) { if (sneaking) { var result = handler.SendEntityAction(Protocol.EntityActionType.StopSneaking); if (result) sneaking = false; - return result ? Translations.cmd_sneak_off : Translations.general_fail; + if (result) + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_sneak_off); + else + return r.SetAndReturn(CmdResult.Status.Fail); } else { var result = handler.SendEntityAction(Protocol.EntityActionType.StartSneaking); if (result) sneaking = true; - return result ? Translations.cmd_sneak_on : Translations.general_fail; + if (result) + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_sneak_on); + else + return r.SetAndReturn(CmdResult.Status.Fail); } } } diff --git a/MinecraftClient/Commands/Tps.cs b/MinecraftClient/Commands/Tps.cs index 029fe22d..92fb0924 100644 --- a/MinecraftClient/Commands/Tps.cs +++ b/MinecraftClient/Commands/Tps.cs @@ -1,6 +1,7 @@ using System; -using System.Collections.Generic; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; namespace MinecraftClient.Commands { @@ -10,11 +11,32 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "tps"; } } public override string CmdDesc { get { return Translations.cmd_tps_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => DoLogTps(r.Source, handler)) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoLogTps(CmdResult r, McClient handler) { var tps = Math.Round(handler.GetServerTPS(), 2); string color; @@ -22,9 +44,9 @@ namespace MinecraftClient.Commands color = "§c"; // Red else if (tps < 15) color = "§e"; // Yellow - else + else color = "§a"; // Green - return Translations.cmd_tps_current + ": " + color + tps; + return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_tps_current + ": " + color + tps); } } } diff --git a/MinecraftClient/Commands/UseItem.cs b/MinecraftClient/Commands/UseItem.cs index 52ea97c3..41f056da 100644 --- a/MinecraftClient/Commands/UseItem.cs +++ b/MinecraftClient/Commands/UseItem.cs @@ -1,5 +1,7 @@ -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { @@ -9,18 +11,38 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "useitem"; } } public override string CmdDesc { get { return Translations.cmd_useitem_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Executes(r => DoUseItem(r.Source, handler)) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) { - if (handler.GetInventoryEnabled()) + return r.SetAndReturn(cmd switch { - handler.UseItemOnHand(); - return Translations.cmd_useitem_use; - } - else return Translations.extra_inventory_required; +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int DoUseItem(CmdResult r, McClient handler) + { + if (!handler.GetInventoryEnabled()) + return r.SetAndReturn(Status.FailNeedInventory); + + handler.UseItemOnHand(); + return r.SetAndReturn(Status.Done, Translations.cmd_useitem_use); } } } diff --git a/MinecraftClient/Commands/Useblock.cs b/MinecraftClient/Commands/Useblock.cs index 10125f43..784185ee 100644 --- a/MinecraftClient/Commands/Useblock.cs +++ b/MinecraftClient/Commands/Useblock.cs @@ -1,6 +1,8 @@ -using System.Collections.Generic; using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; +using static MinecraftClient.CommandHandler.CmdResult; namespace MinecraftClient.Commands { @@ -10,29 +12,42 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "useblock "; } } public override string CmdDesc { get { return Translations.cmd_useblock_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("Location", MccArguments.Location()) + .Executes(r => UseBlockAtLocation(r.Source, handler, MccArguments.GetLocation(r, "Location")))) + .Then(l => l.Literal("_help") + .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) + ); } - public override string Run(McClient handler, string command, Dictionary? localVars) + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { +#pragma warning disable format // @formatter:off + _ => GetCmdDescTranslated(), +#pragma warning restore format // @formatter:on + }); + } + + private int UseBlockAtLocation(CmdResult r, McClient handler, Location block) { if (!handler.GetTerrainEnabled()) - return Translations.extra_terrainandmovement_required; - else if (HasArg(command)) - { - string[] args = GetArgs(command); - if (args.Length >= 3) - { - Location block = Location.Parse(handler.GetCurrentLocation().ToFloor(), args[0], args[1], args[2]).ToFloor(); - Location blockCenter = block.ToCenter(); - bool res = handler.PlaceBlock(block, Direction.Down); - return string.Format(Translations.cmd_useblock_use, blockCenter.X, blockCenter.Y, blockCenter.Z, res ? "succeeded" : "failed"); - } - else - return GetCmdDescTranslated(); - } - else - return GetCmdDescTranslated(); + return r.SetAndReturn(Status.FailNeedTerrain); + + Location current = handler.GetCurrentLocation(); + block = block.ToAbsolute(current).ToFloor(); + Location blockCenter = block.ToCenter(); + bool res = handler.PlaceBlock(block, Direction.Down); + return r.SetAndReturn(string.Format(Translations.cmd_useblock_use, blockCenter.X, blockCenter.Y, blockCenter.Z, res ? "succeeded" : "failed"), res); } } } diff --git a/MinecraftClient/ConsoleIO.cs b/MinecraftClient/ConsoleIO.cs index 022ccaf4..5561e003 100644 --- a/MinecraftClient/ConsoleIO.cs +++ b/MinecraftClient/ConsoleIO.cs @@ -1,6 +1,13 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; +using System.Threading; +using System.Threading.Tasks; +using FuzzySharp; +using MinecraftClient.CommandHandler; +using MinecraftClient.Scripting; +using static MinecraftClient.Settings; namespace MinecraftClient { @@ -175,16 +182,151 @@ namespace MinecraftClient #endregion - public static void AutocompleteHandler(object? sender, ConsoleKey e) + + internal static bool AutoCompleteDone = false; + internal static string[] AutoCompleteResult = Array.Empty(); + + private static HashSet Commands = new(); + private static string[] CommandsFromAutoComplete = Array.Empty(); + private static string[] CommandsFromDeclareCommands = Array.Empty(); + + private static Task _latestTask = Task.CompletedTask; + private static CancellationTokenSource? _cancellationTokenSource; + + private static void MccAutocompleteHandler(ConsoleInteractive.ConsoleReader.Buffer buffer) { - if (e != ConsoleKey.Tab) return; - - if (autocomplete_engine == null) + string fullCommand = buffer.Text; + if (string.IsNullOrEmpty(fullCommand)) + { + ConsoleInteractive.ConsoleSuggestion.ClearSuggestions(); return; + } - var buffer = ConsoleInteractive.ConsoleReader.GetBufferContent(); - ConsoleIO.WriteLine("AutoComplete " + buffer); - autocomplete_engine.AutoComplete(buffer.Text[..buffer.CursorPosition]); + var InternalCmdChar = Config.Main.Advanced.InternalCmdChar; + if (InternalCmdChar == MainConfigHealper.MainConfig.AdvancedConfig.InternalCmdCharType.none || fullCommand[0] == InternalCmdChar.ToChar()) + { + int offset = InternalCmdChar == MainConfigHealper.MainConfig.AdvancedConfig.InternalCmdCharType.none ? 0 : 1; + if (buffer.CursorPosition - offset < 0) + { + ConsoleInteractive.ConsoleSuggestion.ClearSuggestions(); + return; + } + _cancellationTokenSource?.Cancel(); + using var cts = new CancellationTokenSource(); + _cancellationTokenSource = cts; + var previousTask = _latestTask; + var newTask = new Task(async () => + { + string command = fullCommand[offset..]; + if (command.Length == 0) + { + var childs = McClient.dispatcher.GetRoot().Children; + int index = 0; + var sugList = new ConsoleInteractive.ConsoleSuggestion.Suggestion[childs.Count + Commands.Count + 1]; + + sugList[index++] = new("/"); + foreach (var child in childs) + sugList[index++] = new(child.Name); + foreach (var cmd in Commands) + sugList[index++] = new(cmd); + ConsoleInteractive.ConsoleSuggestion.UpdateSuggestions(sugList, new(offset, offset)); + } + else if (command.Length > 0 && command[0] == '/' && !command.Contains(' ')) + { + var sorted = Process.ExtractSorted(command[1..], Commands); + var sugList = new ConsoleInteractive.ConsoleSuggestion.Suggestion[sorted.Count()]; + + int index = 0; + foreach (var sug in sorted) + sugList[index++] = new(sug.Value); + ConsoleInteractive.ConsoleSuggestion.UpdateSuggestions(sugList, new(offset, offset + command.Length)); + } + else + { + var parse = McClient.dispatcher.Parse(command, CmdResult.Empty); + + var suggestion = await McClient.dispatcher.GetCompletionSuggestions(parse, buffer.CursorPosition - offset); + + int sugLen = suggestion.List.Count; + if (sugLen == 0) + { + ConsoleInteractive.ConsoleSuggestion.ClearSuggestions(); + return; + } + + var sugList = new ConsoleInteractive.ConsoleSuggestion.Suggestion[sugLen]; + if (cts.IsCancellationRequested) + return; + + Tuple range = new(suggestion.Range.Start + offset, suggestion.Range.End + offset); + var sorted = Process.ExtractSorted(fullCommand[range.Item1..range.Item2], suggestion.List.Select(_ => _.Text).ToList()); + if (cts.IsCancellationRequested) + return; + + int index = 0; + foreach (var sug in sorted) + sugList[index++] = new(sug.Value); + + ConsoleInteractive.ConsoleSuggestion.UpdateSuggestions(sugList, range); + } + }, cts.Token); + _latestTask = newTask; + try { newTask.Start(); } catch { } + if (_cancellationTokenSource == cts) _cancellationTokenSource = null; + } + else + { + ConsoleInteractive.ConsoleSuggestion.ClearSuggestions(); + return; + } + } + + public static void AutocompleteHandler(object? sender, ConsoleInteractive.ConsoleReader.Buffer buffer) + { + MccAutocompleteHandler(buffer); + } + + public static void CancelAutocomplete() + { + _cancellationTokenSource?.Cancel(); + _latestTask = Task.CompletedTask; + ConsoleInteractive.ConsoleSuggestion.ClearSuggestions(); + + AutoCompleteDone = false; + AutoCompleteResult = Array.Empty(); + CommandsFromAutoComplete = Array.Empty(); + CommandsFromDeclareCommands = Array.Empty(); + } + + private static void MergeCommands() + { + Commands.Clear(); + foreach (string cmd in CommandsFromAutoComplete) + Commands.Add('/' + cmd); + foreach (string cmd in CommandsFromDeclareCommands) + Commands.Add('/' + cmd); + } + + public static void OnAutoCompleteDone(int transactionId, string[] result) + { + AutoCompleteResult = result; + if (transactionId == 0) + { + CommandsFromAutoComplete = result; + MergeCommands(); + } + AutoCompleteDone = true; + } + + public static void OnDeclareMinecraftCommand(string[] rootCommands) + { + CommandsFromDeclareCommands = rootCommands; + MergeCommands(); + } + + public static void InitAutocomplete() + { + autocomplete_engine!.AutoComplete("/"); } } @@ -199,6 +341,6 @@ namespace MinecraftClient /// /// Text behind the cursor, e.g. "my input comm" /// List of auto-complete words, e.g. ["command", "comment"] - IEnumerable AutoComplete(string BehindCursor); + int AutoComplete(string BehindCursor); } } diff --git a/MinecraftClient/Inventory/EnchantmentMapping.cs b/MinecraftClient/Inventory/EnchantmentMapping.cs index d6ffba32..badadb99 100644 --- a/MinecraftClient/Inventory/EnchantmentMapping.cs +++ b/MinecraftClient/Inventory/EnchantmentMapping.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using MinecraftClient.Protocol.Handlers; +using MinecraftClient.Protocol.Message; namespace MinecraftClient.Inventory { @@ -158,7 +159,7 @@ namespace MinecraftClient.Inventory public static string GetEnchantmentName(Enchantment enchantment) { - string? trans = Protocol.ChatParser.TranslateString("enchantment.minecraft." + enchantment.ToString().ToUnderscoreCase()); + string? trans = ChatParser.TranslateString("enchantment.minecraft." + enchantment.ToString().ToUnderscoreCase()); if (string.IsNullOrEmpty(trans)) return "Unknown Enchantment with ID: " + ((short)enchantment) + " (Probably not named in the code yet)"; else diff --git a/MinecraftClient/Inventory/Item.cs b/MinecraftClient/Inventory/Item.cs index 28a5754e..d0c523b3 100644 --- a/MinecraftClient/Inventory/Item.cs +++ b/MinecraftClient/Inventory/Item.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; +using MinecraftClient.Protocol.Message; namespace MinecraftClient.Inventory { @@ -64,7 +65,7 @@ namespace MinecraftClient.Inventory { string? displayName = displayProperties["Name"] as string; if (!String.IsNullOrEmpty(displayName)) - return MinecraftClient.Protocol.ChatParser.ParseText(displayProperties["Name"].ToString() ?? string.Empty); + return ChatParser.ParseText(displayProperties["Name"].ToString() ?? string.Empty); } } return null; @@ -85,7 +86,7 @@ namespace MinecraftClient.Inventory { object[] displayName = (object[])displayProperties["Lore"]; lores.AddRange(from string st in displayName - let str = MinecraftClient.Protocol.ChatParser.ParseText(st.ToString()) + let str = ChatParser.ParseText(st.ToString()) select str); return lores.ToArray(); } @@ -117,10 +118,10 @@ namespace MinecraftClient.Inventory { string type_str = type.ToString(); string type_renamed = type_str.ToUnderscoreCase(); - string? res1 = Protocol.ChatParser.TranslateString("item.minecraft." + type_renamed); + string? res1 = ChatParser.TranslateString("item.minecraft." + type_renamed); if (!string.IsNullOrEmpty(res1)) return res1; - string? res2 = Protocol.ChatParser.TranslateString("block.minecraft." + type_renamed); + string? res2 = ChatParser.TranslateString("block.minecraft." + type_renamed); if (!string.IsNullOrEmpty(res2)) return res2; return type_str; @@ -145,8 +146,8 @@ namespace MinecraftClient.Inventory short level = (short)enchantment["lvl"]; string id = ((string)enchantment["id"]).Replace(':', '.'); sb.AppendFormat(" | {0} {1}", - Protocol.ChatParser.TranslateString("enchantment." + id) ?? id, - Protocol.ChatParser.TranslateString("enchantment.level." + level) ?? level.ToString()); + ChatParser.TranslateString("enchantment." + id) ?? id, + ChatParser.TranslateString("enchantment.level." + level) ?? level.ToString()); } } } diff --git a/MinecraftClient/Inventory/ItemMovingHelper.cs b/MinecraftClient/Inventory/ItemMovingHelper.cs index 07b1e686..da9a0097 100644 --- a/MinecraftClient/Inventory/ItemMovingHelper.cs +++ b/MinecraftClient/Inventory/ItemMovingHelper.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using MinecraftClient.Scripting; namespace MinecraftClient.Inventory { diff --git a/MinecraftClient/Inventory/VillagerInfo.cs b/MinecraftClient/Inventory/VillagerInfo.cs index 28f793af..c93781e8 100644 --- a/MinecraftClient/Inventory/VillagerInfo.cs +++ b/MinecraftClient/Inventory/VillagerInfo.cs @@ -1,4 +1,4 @@ -namespace MinecraftClient.Mapping +namespace MinecraftClient.Inventory { /// /// Properties of a villager diff --git a/MinecraftClient/Json.cs b/MinecraftClient/Json.cs index e77e32bf..be70b48e 100644 --- a/MinecraftClient/Json.cs +++ b/MinecraftClient/Json.cs @@ -103,7 +103,7 @@ namespace MinecraftClient && IsHex(toparse[cursorpos + 5])) { //"abc\u0123abc" => "0123" => 0123 => Unicode char n°0123 => Add char to string - data.StringValue += char.ConvertFromUtf32(int.Parse(toparse.Substring(cursorpos + 2, 4), + data.StringValue += char.ConvertFromUtf32(int.Parse(toparse.Substring(cursorpos + 2, 4), System.Globalization.NumberStyles.HexNumber)); cursorpos += 6; continue; } diff --git a/MinecraftClient/Logger/FileLogLogger.cs b/MinecraftClient/Logger/FileLogLogger.cs index 8418ec6c..9614a5c4 100644 --- a/MinecraftClient/Logger/FileLogLogger.cs +++ b/MinecraftClient/Logger/FileLogLogger.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using MinecraftClient.Scripting; namespace MinecraftClient.Logger { diff --git a/MinecraftClient/Mapping/Block.cs b/MinecraftClient/Mapping/Block.cs index 065699a7..ffbe499c 100644 --- a/MinecraftClient/Mapping/Block.cs +++ b/MinecraftClient/Mapping/Block.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.CompilerServices; using MinecraftClient.Mapping.BlockPalettes; +using MinecraftClient.Protocol.Message; namespace MinecraftClient.Mapping { @@ -115,7 +116,7 @@ namespace MinecraftClient.Mapping public string GetTypeString() { string typeStr = Type.ToString(); - string? trans = Protocol.ChatParser.TranslateString("block.minecraft." + typeStr.ToUnderscoreCase()); + string? trans = ChatParser.TranslateString("block.minecraft." + typeStr.ToUnderscoreCase()); return string.IsNullOrEmpty(trans) ? typeStr : trans; } diff --git a/MinecraftClient/Mapping/Dimension.cs b/MinecraftClient/Mapping/Dimension.cs index 3aea6744..fe52b0e0 100644 --- a/MinecraftClient/Mapping/Dimension.cs +++ b/MinecraftClient/Mapping/Dimension.cs @@ -139,9 +139,9 @@ namespace MinecraftClient.Mapping try { var monsterSpawnLightLevelObj = nbt["monster_spawn_light_level"]; - try - { - monsterSpawnMinLightLevel = monsterSpawnMaxLightLevel = Convert.ToInt32(monsterSpawnLightLevelObj); + try + { + monsterSpawnMinLightLevel = monsterSpawnMaxLightLevel = Convert.ToInt32(monsterSpawnLightLevelObj); } catch (Exception) { diff --git a/MinecraftClient/Mapping/Entity.cs b/MinecraftClient/Mapping/Entity.cs index fa7646b7..8d11ba27 100644 --- a/MinecraftClient/Mapping/Entity.cs +++ b/MinecraftClient/Mapping/Entity.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using MinecraftClient.Inventory; +using MinecraftClient.Protocol.Message; namespace MinecraftClient.Mapping { @@ -158,7 +159,7 @@ namespace MinecraftClient.Mapping public string GetTypeString() { string typeStr = Type.ToString(); - string? trans = Protocol.ChatParser.TranslateString("entity.minecraft." + typeStr.ToUnderscoreCase()); + string? trans = ChatParser.TranslateString("entity.minecraft." + typeStr.ToUnderscoreCase()); return string.IsNullOrEmpty(trans) ? typeStr : trans; } } diff --git a/MinecraftClient/Mapping/Location.cs b/MinecraftClient/Mapping/Location.cs index 5094648f..4a6a7320 100644 --- a/MinecraftClient/Mapping/Location.cs +++ b/MinecraftClient/Mapping/Location.cs @@ -26,6 +26,15 @@ namespace MinecraftClient.Mapping /// public double Z; + /// + /// Identifies whether the coordinates are absolute or relative. + /// true for relative coordinates, false for absolute coordinates. + /// X-axis: ((Status & (1 << 0)) > 0) + /// Y-axis: ((Status & (1 << 1)) > 0) + /// Z-axis: ((Status & (1 << 2)) > 0) + /// + public byte Status; + /// /// Create a new location /// @@ -34,6 +43,18 @@ namespace MinecraftClient.Mapping X = x; Y = y; Z = z; + Status = 0; + } + + /// + /// Create a new location + /// + public Location(double x, double y, double z, byte status) + { + X = x; + Y = y; + Z = z; + Status = status; } /// @@ -44,6 +65,7 @@ namespace MinecraftClient.Mapping X = loc.X; Y = loc.Y; Z = loc.Z; + Status = loc.Status; } /// @@ -60,6 +82,19 @@ namespace MinecraftClient.Mapping X = chunkX * Chunk.SizeX + blockX; Y = blockY; Z = chunkZ * Chunk.SizeZ + blockZ; + Status = 0; + } + + public Location ToAbsolute(Location based) + { + if ((Status & (1 << 0)) > 0) + X += based.X; + if ((Status & (1 << 1)) > 0) + Y += based.Y; + if ((Status & (1 << 2)) > 0) + Z += based.Z; + Status = 0; + return this; } /// diff --git a/MinecraftClient/Mapping/RaycastHelper.cs b/MinecraftClient/Mapping/RaycastHelper.cs index a1afecef..483b0b86 100644 --- a/MinecraftClient/Mapping/RaycastHelper.cs +++ b/MinecraftClient/Mapping/RaycastHelper.cs @@ -36,7 +36,7 @@ namespace MinecraftClient.Mapping { if (start == end) return new(false, Location.Zero, Block.Air); - + double start_x = MathHelper.Lerp(-1.0E-7, start.X, end.X); double start_y = MathHelper.Lerp(-1.0E-7, start.Y, end.Y); double start_z = MathHelper.Lerp(-1.0E-7, start.Z, end.Z); @@ -87,7 +87,7 @@ namespace MinecraftClient.Mapping res_location.Z += dz_sign; z_frac += z_step; } - + block = CheckRaycastResult(world, res_location, includeFluids); if (block.Type != Material.Air) return new(true, res_location, block); diff --git a/MinecraftClient/Mapping/World.cs b/MinecraftClient/Mapping/World.cs index 97792cfe..0b2e02f9 100644 --- a/MinecraftClient/Mapping/World.cs +++ b/MinecraftClient/Mapping/World.cs @@ -153,7 +153,7 @@ namespace MinecraftClient.Mapping /// Block type /// Search radius - larger is slower: O^3 complexity /// Block matching the specified block type - public List FindBlock(Location from, Material block, int radius) + public List FindBlock(Location from, Material block, double radius) { return FindBlock(from, block, radius, radius, radius); } @@ -167,7 +167,7 @@ namespace MinecraftClient.Mapping /// Search radius on the Y axis /// Search radius on the Z axis /// Block matching the specified block type - public List FindBlock(Location from, Material block, int radiusx, int radiusy, int radiusz) + public List FindBlock(Location from, Material block, double radiusx, double radiusy, double radiusz) { Location minPoint = new Location(from.X - radiusx, from.Y - radiusy, from.Z - radiusz); Location maxPoint = new Location(from.X + radiusx, from.Y + radiusy, from.Z + radiusz); diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index f33e6456..a33f0fae 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -2,22 +2,23 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; -using System.Security.Cryptography.Pkcs; using System.Text; using System.Threading; using Brigadier.NET; using Brigadier.NET.Exceptions; using MinecraftClient.ChatBots; -using MinecraftClient.Commands; +using MinecraftClient.CommandHandler; +using MinecraftClient.CommandHandler.Patch; using MinecraftClient.Inventory; using MinecraftClient.Logger; using MinecraftClient.Mapping; using MinecraftClient.Protocol; using MinecraftClient.Protocol.Handlers.Forge; -using MinecraftClient.Protocol.Keys; using MinecraftClient.Protocol.Message; +using MinecraftClient.Protocol.ProfileKey; using MinecraftClient.Protocol.Session; using MinecraftClient.Proxy; +using MinecraftClient.Scripting; using static MinecraftClient.Settings; namespace MinecraftClient @@ -29,10 +30,7 @@ namespace MinecraftClient { public static int ReconnectionAttemptsLeft = 0; - public static readonly CommandSource cmd_source = new(); - public static readonly CommandDispatcher dispatcher = new(); - //private static readonly List cmd_names = new(); - //private static readonly Dictionary cmds = new(); + public static CommandDispatcher dispatcher = new(); private readonly Dictionary onlinePlayers = new(); private static bool commandsLoaded = false; @@ -152,6 +150,8 @@ namespace MinecraftClient /// ForgeInfo item stating that Forge is enabled public McClient(SessionToken session, PlayerKeyPair? playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo? forgeInfo) { + dispatcher = new(); + CmdResult.client = this; terrainAndMovementsEnabled = Config.Main.Advanced.TerrainAndMovements; inventoryHandlingEnabled = Config.Main.Advanced.InventoryHandling; entityHandlingEnabled = Config.Main.Advanced.EntityHandling; @@ -206,7 +206,7 @@ namespace MinecraftClient cmdprompt = new CancellationTokenSource(); ConsoleInteractive.ConsoleReader.BeginReadThread(cmdprompt); ConsoleInteractive.ConsoleReader.MessageReceived += ConsoleReaderOnMessageReceived; - ConsoleInteractive.ConsoleReader.OnKeyInput += ConsoleIO.AutocompleteHandler; + ConsoleInteractive.ConsoleReader.OnInputChange += ConsoleIO.AutocompleteHandler; } else { @@ -230,7 +230,7 @@ namespace MinecraftClient return; - Retry: + Retry: if (timeoutdetector != null) { timeoutdetector.Item2.Cancel(); @@ -247,7 +247,7 @@ namespace MinecraftClient { ConsoleInteractive.ConsoleReader.StopReadThread(); ConsoleInteractive.ConsoleReader.MessageReceived -= ConsoleReaderOnMessageReceived; - ConsoleInteractive.ConsoleReader.OnKeyInput -= ConsoleIO.AutocompleteHandler; + ConsoleInteractive.ConsoleReader.OnInputChange -= ConsoleIO.AutocompleteHandler; Program.HandleFailure(); } @@ -456,6 +456,8 @@ namespace MinecraftClient /// public void OnConnectionLost(ChatBot.DisconnectReason reason, string message) { + ConsoleIO.CancelAutocomplete(); + handler.Dispose(); world.Clear(); @@ -514,7 +516,7 @@ namespace MinecraftClient { ConsoleInteractive.ConsoleReader.StopReadThread(); ConsoleInteractive.ConsoleReader.MessageReceived -= ConsoleReaderOnMessageReceived; - ConsoleInteractive.ConsoleReader.OnKeyInput -= ConsoleIO.AutocompleteHandler; + ConsoleInteractive.ConsoleReader.OnInputChange -= ConsoleIO.AutocompleteHandler; Program.HandleFailure(); } } @@ -553,7 +555,9 @@ namespace MinecraftClient switch (command[0].ToLower()) { case "autocomplete": - if (command.Length > 1) { ConsoleIO.WriteLine((char)0x00 + "autocomplete" + (char)0x00 + handler.AutoComplete(command[1])); } + int id = handler.AutoComplete(command[1]); + while (!ConsoleIO.AutoCompleteDone) { Thread.Sleep(100); } + if (command.Length > 1) { ConsoleIO.WriteLine((char)0x00 + "autocomplete" + (char)0x00 + ConsoleIO.AutoCompleteResult); } else ConsoleIO.WriteLine((char)0x00 + "autocomplete" + (char)0x00); break; } @@ -561,70 +565,44 @@ namespace MinecraftClient else { text = text.Trim(); - if (text.Length > 0) + + if (text.Length > 1 + && Config.Main.Advanced.InternalCmdChar == MainConfigHealper.MainConfig.AdvancedConfig.InternalCmdCharType.none + && text[0] == '/') { - if (Config.Main.Advanced.InternalCmdChar.ToChar() == ' ' || text[0] == Config.Main.Advanced.InternalCmdChar.ToChar()) + SendText(text); + } + else if (text.Length > 2 + && Config.Main.Advanced.InternalCmdChar != MainConfigHealper.MainConfig.AdvancedConfig.InternalCmdCharType.none + && text[0] == Config.Main.Advanced.InternalCmdChar.ToChar() + && text[1] == '/') + { + SendText(text[1..]); + } + else if (text.Length > 0) + { + if (Config.Main.Advanced.InternalCmdChar == MainConfigHealper.MainConfig.AdvancedConfig.InternalCmdCharType.none + || text[0] == Config.Main.Advanced.InternalCmdChar.ToChar()) { - string? response_msg = ""; + CmdResult result = new(); string command = Config.Main.Advanced.InternalCmdChar.ToChar() == ' ' ? text : text[1..]; - if (!PerformInternalCommand(Config.AppVar.ExpandVars(command), ref response_msg, Settings.Config.AppVar.GetVariables()) && Config.Main.Advanced.InternalCmdChar.ToChar() == '/') + if (!PerformInternalCommand(Config.AppVar.ExpandVars(command), ref result, Settings.Config.AppVar.GetVariables()) && Config.Main.Advanced.InternalCmdChar.ToChar() == '/') { SendText(text); } - else if (!String.IsNullOrEmpty(response_msg)) + else if (result.status != CmdResult.Status.NotRun && (result.status != CmdResult.Status.Done || !string.IsNullOrWhiteSpace(result.result))) { - Log.Info(response_msg); + Log.Info(result); } } - else SendText(text); + else + { + SendText(text); + } } } } - /// - /// Register a custom console command - /// - /// Name of the command - /// Description/usage of the command - /// Method for handling the command - /// True if successfully registered - public bool RegisterCommand(string cmdName, string cmdDesc, string cmdUsage, ChatBot.CommandRunner callback) - { - // if (cmds.ContainsKey(cmdName.ToLower())) - // { - // return false; - // } - // else - // { - // Command cmd = new ChatBot.ChatBotCommand(cmdName, cmdDesc, cmdUsage, callback); - // cmds.Add(cmdName.ToLower(), cmd); - // cmd_names.Add(cmdName.ToLower()); - // return true; - // } - return true; - } - - /// - /// Unregister a console command - /// - /// - /// There is no check for the command is registered by above method or is embedded command. - /// Which mean this can unload any command - /// - /// The name of command to be unregistered - /// - public bool UnregisterCommand(string cmdName) - { - // if (cmds.ContainsKey(cmdName.ToLower())) - // { - // cmds.Remove(cmdName.ToLower()); - // cmd_names.Remove(cmdName.ToLower()); - // return true; - // } - // else return false; - return true; - } - /// /// Perform an internal MCC command (not a server command, use SendText() instead for that!) /// @@ -632,82 +610,55 @@ namespace MinecraftClient /// May contain a confirmation or error message after processing the command, or "" otherwise. /// Local variables passed along with the command /// TRUE if the command was indeed an internal MCC command - public bool PerformInternalCommand(string command, ref string? response_msg, Dictionary? localVars = null) + public bool PerformInternalCommand(string command, ref CmdResult result, Dictionary? localVars = null) { /* Process the provided command */ - ParseResults parse; + ParseResults parse; try { - parse = dispatcher.Parse(command, cmd_source); + parse = dispatcher.Parse(command, result); } catch (Exception e) { - Log.Error(e.GetFullMessage()); - return true; + Log.Debug("Parse fail: " + e.GetFullMessage()); + return false; } try { - int res = dispatcher.Execute(parse); - Log.Info("res = " + res); + dispatcher.Execute(parse); + + foreach (ChatBot bot in bots.ToArray()) + { + try + { + bot.OnInternalCommand(command, string.Join(" ", Command.GetArgs(command)), result); + } + catch (Exception e) + { + if (e is not ThreadAbortException) + { + Log.Warn(string.Format(Translations.icmd_error, bot.ToString() ?? string.Empty, e.ToString())); + } + else throw; //ThreadAbortException should not be caught + } + } + return true; } catch (CommandSyntaxException e) { - Log.Warn(e.GetFullMessage()); - return true; + if (parse.Context.Nodes.Count == 0) + { + return false; + } + else + { + Log.Info("§e" + e.Message ?? e.StackTrace ?? "Incorrect argument."); + Log.Info(dispatcher.GetAllUsageString(parse.Context.Nodes[0].Node.Name, false)); + return true; + } } - catch (Exception e) - { - Log.Error(e.GetFullMessage()); - return true; - } - - //string command_name = command.Split(' ')[0].ToLower(); - //if (command_name == "help") - //{ - // if (Command.HasArg(command)) - // { - // string help_cmdname = Command.GetArgs(command)[0].ToLower(); - // if (help_cmdname == "help") - // { - // response_msg = Translations.icmd_help; - // } - // else if (cmds.ContainsKey(help_cmdname)) - // { - // response_msg = cmds[help_cmdname].GetCmdDescTranslated(); - // } - // else response_msg = string.Format(Translations.icmd_unknown, command_name); - // } - // else response_msg = string.Format(Translations.icmd_list, String.Join(", ", cmd_names.ToArray()), Config.Main.Advanced.InternalCmdChar.ToChar()); - //} - //else if (cmds.ContainsKey(command_name)) - //{ - // response_msg = cmds[command_name].Run(this, command, localVars); - - // foreach (ChatBot bot in bots.ToArray()) - // { - // try - // { - // bot.OnInternalCommand(command_name, string.Join(" ", Command.GetArgs(command)), response_msg); - // } - // catch (Exception e) - // { - // if (e is not ThreadAbortException) - // { - // Log.Warn(string.Format(Translations.icmd_error, bot.ToString() ?? string.Empty, e.ToString())); - // } - // else throw; //ThreadAbortException should not be caught - // } - // } - //} - //else - //{ - // response_msg = string.Format(Translations.icmd_unknown, command_name); - // return false; - //} - - //return true; } public void LoadCommands() @@ -725,10 +676,6 @@ namespace MinecraftClient { Command cmd = (Command)Activator.CreateInstance(type)!; cmd.RegisterCommand(this, dispatcher); - // cmds[Settings.ToLowerIfNeed(cmd.CmdName)] = cmd; - // cmd_names.Add(Settings.ToLowerIfNeed(cmd.CmdName)); - // foreach (string alias in cmd.GetCMDAliases()) - // cmds[Settings.ToLowerIfNeed(alias)] = cmd; } catch (Exception e) { @@ -863,7 +810,7 @@ namespace MinecraftClient b.SetHandler(this); bots.Add(b); if (init) - DispatchBotEvent(bot => bot.Initialize(), new ChatBot[] { b }); + DispatchBotEvent(bot => bot.Initialize(dispatcher), new ChatBot[] { b }); if (handler != null) DispatchBotEvent(bot => bot.AfterGameJoined(), new ChatBot[] { b }); } @@ -879,8 +826,9 @@ namespace MinecraftClient return; } - b.OnUnload(); - bots.RemoveAll(item => object.ReferenceEquals(item, b)); + b.OnUnload(dispatcher); + + bots.RemoveAll(item => ReferenceEquals(item, b)); // ToList is needed to avoid an InvalidOperationException from modfiying the list while it's being iterated upon. var botRegistrations = registeredBotPluginChannels.Where(entry => entry.Value.Contains(b)).ToList(); @@ -2449,6 +2397,8 @@ namespace MinecraftClient ClearInventories(); DispatchBotEvent(bot => bot.AfterGameJoined()); + + ConsoleIO.InitAutocomplete(); } /// @@ -3471,6 +3421,16 @@ namespace MinecraftClient DispatchBotEvent(bot => bot.OnBlockChange(location, block)); } + /// + /// Called when "AutoComplete" completes. + /// + /// The number of this result. + /// All commands. + public void OnAutoCompleteDone(int transactionId, string[] result) + { + ConsoleIO.OnAutoCompleteDone(transactionId, result); + } + /// /// Send a click container button packet to the server. /// Used for Enchanting table, Lectern, stone cutter and loom diff --git a/MinecraftClient/MinecraftClient.csproj b/MinecraftClient/MinecraftClient.csproj index e6f2477c..f0a01aaa 100644 --- a/MinecraftClient/MinecraftClient.csproj +++ b/MinecraftClient/MinecraftClient.csproj @@ -28,20 +28,21 @@ - + - - + + + - - + + NU1701 - + diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index d8ae2250..52aaf0f4 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -14,8 +14,9 @@ using MinecraftClient.Mapping.BlockPalettes; using MinecraftClient.Mapping.EntityPalettes; using MinecraftClient.Protocol; using MinecraftClient.Protocol.Handlers.Forge; -using MinecraftClient.Protocol.Keys; +using MinecraftClient.Protocol.ProfileKey; using MinecraftClient.Protocol.Session; +using MinecraftClient.Scripting; using MinecraftClient.WinAPI; using Tomlet; using static MinecraftClient.Settings; @@ -573,7 +574,7 @@ namespace MinecraftClient } //Retrieve server info if version is not manually set OR if need to retrieve Forge information - if (!isRealms && (protocolversion == 0 || (Config.Main.Advanced.EnableForge == ForgeConfigType.auto) || + if (!isRealms && (protocolversion == 0 || (Config.Main.Advanced.EnableForge == ForgeConfigType.auto) || ((Config.Main.Advanced.EnableForge == ForgeConfigType.force) && !ProtocolHandler.ProtocolMayForceForge(protocolversion)))) { if (protocolversion != 0) @@ -587,9 +588,9 @@ namespace MinecraftClient } } - if (Config.Main.General.AccountType == LoginType.microsoft + if (Config.Main.General.AccountType == LoginType.microsoft && (InternalConfig.Account.Password != "-" || Config.Main.General.Method == LoginMethod.browser) - && Config.Signature.LoginWithSecureProfile + && Config.Signature.LoginWithSecureProfile && protocolversion >= 759 /* 1.19 and above */) { // Load cached profile key from disk if necessary @@ -683,7 +684,7 @@ namespace MinecraftClient /// public static void ReloadSettings(bool keepAccountAndServerSettings = false) { - if(Settings.LoadFromFile(settingsIniPath, keepAccountAndServerSettings).Item1) + if (Settings.LoadFromFile(settingsIniPath, keepAccountAndServerSettings).Item1) ConsoleIO.WriteLine(string.Format(Translations.config_load, settingsIniPath)); } @@ -720,6 +721,7 @@ namespace MinecraftClient public static void DoExit(int exitcode = 0) { WriteBackSettings(true); + ConsoleInteractive.ConsoleSuggestion.ClearSuggestions(); ConsoleIO.WriteLineFormatted(string.Format(Translations.config_saving, settingsIniPath)); if (client != null) { client.Disconnect(); ConsoleIO.Reset(); } @@ -807,7 +809,7 @@ namespace MinecraftClient if (command.StartsWith("reco")) { - message = new Commands.Reco().Run(null, Config.AppVar.ExpandVars(command), null); + message = Commands.Reco.DoReconnect(Config.AppVar.ExpandVars(command)); if (message == "") { exitThread = true; @@ -816,7 +818,7 @@ namespace MinecraftClient } else if (command.StartsWith("connect")) { - message = new Commands.Connect().Run(null, Config.AppVar.ExpandVars(command), null); + message = Commands.Connect.DoConnect(Config.AppVar.ExpandVars(command)); if (message == "") { exitThread = true; @@ -825,7 +827,7 @@ namespace MinecraftClient } else if (command.StartsWith("exit") || command.StartsWith("quit")) { - message = new Commands.Exit().Run(null, Config.AppVar.ExpandVars(command), null); + message = Commands.Exit.DoExit(Config.AppVar.ExpandVars(command)); } else if (command.StartsWith("help")) { @@ -844,7 +846,7 @@ namespace MinecraftClient } else { - _ = new Commands.Exit().Run(null, Config.AppVar.ExpandVars(command), null); + Commands.Exit.DoExit(Config.AppVar.ExpandVars(command)); } } diff --git a/MinecraftClient/Protocol/Handlers/Packet/s2c/DeclareCommands.cs b/MinecraftClient/Protocol/Handlers/Packet/s2c/DeclareCommands.cs index a850dd2a..22835b61 100644 --- a/MinecraftClient/Protocol/Handlers/Packet/s2c/DeclareCommands.cs +++ b/MinecraftClient/Protocol/Handlers/Packet/s2c/DeclareCommands.cs @@ -54,7 +54,22 @@ namespace MinecraftClient.Protocol.Handlers.packet.s2c Nodes[i] = new(flags, childs, redirectNode, name, paser, suggestionsType); } - RootIdx = dataTypes.ReadNextVarInt(packetData); + RootIdx = dataTypes.ReadNextVarInt(packetData); + + ConsoleIO.OnDeclareMinecraftCommand(ExtractRootCommand()); + } + + private static string[] ExtractRootCommand() + { + List commands = new(); + CommandNode root = Nodes[RootIdx]; + foreach (var child in root.Clildren) + { + string? childName = Nodes[child].Name; + if (childName != null) + commands.Add(childName); + } + return commands.ToArray(); } public static List> CollectSignArguments(string command) @@ -113,7 +128,7 @@ namespace MinecraftClient.Protocol.Handlers.packet.s2c public string? Name; public Paser? Paser; public string? SuggestionsType; - + public CommandNode(byte Flags, int[] Clildren, diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index 9db07050..1bf99fdc 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -9,10 +9,11 @@ using System.Threading; using MinecraftClient.Crypto; using MinecraftClient.Inventory; using MinecraftClient.Mapping; -using MinecraftClient.Protocol.Keys; using MinecraftClient.Protocol.Message; +using MinecraftClient.Protocol.ProfileKey; using MinecraftClient.Protocol.Session; using MinecraftClient.Proxy; +using MinecraftClient.Scripting; using static MinecraftClient.Settings; namespace MinecraftClient.Protocol.Handlers @@ -24,8 +25,6 @@ namespace MinecraftClient.Protocol.Handlers class Protocol16Handler : IMinecraftCom { readonly IMinecraftComHandler handler; - private bool autocomplete_received = false; - private string autocomplete_result = ""; private bool encrypted = false; private readonly int protocolversion; private Tuple? netRead = null; @@ -193,7 +192,14 @@ namespace MinecraftClient.Protocol.Handlers if (online) { handler.OnPlayerJoin(new PlayerInfo(name, FakeUUID)); } else { handler.OnPlayerLeave(FakeUUID); } break; case 0xCA: if (protocolversion >= 72) { ReadData(9); } else ReadData(3); break; - case 0xCB: autocomplete_result = ReadNextString(); autocomplete_received = true; break; + case 0xCB: + string resultString = ReadNextString(); + if (!string.IsNullOrEmpty(resultString)) + { + string[] result = resultString.Split((char)0x00); + handler.OnAutoCompleteDone(0, result); + } + break; case 0xCC: ReadNextString(); ReadData(4); break; case 0xCD: ReadData(1); break; case 0xCE: if (protocolversion > 51) { ReadNextString(); ReadNextString(); ReadData(1); } break; @@ -820,27 +826,21 @@ namespace MinecraftClient.Protocol.Handlers catch (System.IO.IOException) { return false; } } - IEnumerable IAutoComplete.AutoComplete(string BehindCursor) + int IAutoComplete.AutoComplete(string BehindCursor) { if (String.IsNullOrEmpty(BehindCursor)) - return Array.Empty(); + return -1; byte[] autocomplete = new byte[3 + (BehindCursor.Length * 2)]; autocomplete[0] = 0xCB; byte[] msglen = BitConverter.GetBytes((short)BehindCursor.Length); - Array.Reverse(msglen); msglen.CopyTo(autocomplete, 1); + Array.Reverse(msglen); + msglen.CopyTo(autocomplete, 1); byte[] msg = Encoding.BigEndianUnicode.GetBytes(BehindCursor); msg.CopyTo(autocomplete, 3); - - autocomplete_received = false; - autocomplete_result = BehindCursor; + ConsoleIO.AutoCompleteDone = false; Send(autocomplete); - - int wait_left = 50; //do not wait more than 5 seconds (50 * 100 ms) - while (wait_left > 0 && !autocomplete_received) { System.Threading.Thread.Sleep(100); wait_left--; } - if (!String.IsNullOrEmpty(autocomplete_result) && autocomplete_received) - ConsoleIO.WriteLineFormatted("§8" + autocomplete_result.Replace((char)0x00, ' '), false); - return autocomplete_result.Split((char)0x00); + return 0; } private static byte[] ConcatBytes(params byte[][] bytes) diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 5f0f855d..de33417e 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -19,10 +19,11 @@ using MinecraftClient.Mapping.EntityPalettes; using MinecraftClient.Protocol.Handlers.Forge; using MinecraftClient.Protocol.Handlers.packet.s2c; using MinecraftClient.Protocol.Handlers.PacketPalettes; -using MinecraftClient.Protocol.Keys; using MinecraftClient.Protocol.Message; +using MinecraftClient.Protocol.ProfileKey; using MinecraftClient.Protocol.Session; using MinecraftClient.Proxy; +using MinecraftClient.Scripting; using static MinecraftClient.Settings; namespace MinecraftClient.Protocol.Handlers @@ -64,9 +65,7 @@ namespace MinecraftClient.Protocol.Handlers internal const int MC_1_19_2_Version = 760; private int compression_treshold = 0; - private bool autocomplete_received = false; private int autocomplete_transaction_id = 0; - private readonly List autocomplete_result = new(); private readonly Dictionary window_actions = new(); private bool login_phase = true; private readonly int protocolVersion; @@ -1325,6 +1324,7 @@ namespace MinecraftClient.Protocol.Handlers } break; case PacketTypesIn.TabComplete: + int old_transaction_id = autocomplete_transaction_id; if (protocolVersion >= MC_1_13_Version) { autocomplete_transaction_id = dataTypes.ReadNextVarInt(packetData); @@ -1333,20 +1333,19 @@ namespace MinecraftClient.Protocol.Handlers } int autocomplete_count = dataTypes.ReadNextVarInt(packetData); - autocomplete_result.Clear(); + string[] autocomplete_result = new string[autocomplete_count]; for (int i = 0; i < autocomplete_count; i++) { - autocomplete_result.Add(dataTypes.ReadNextString(packetData)); + autocomplete_result[i] = dataTypes.ReadNextString(packetData); if (protocolVersion >= MC_1_13_Version) { - // Skip optional tooltip for each tab-complete result + // Skip optional tooltip for each tab-complete resul`t if (dataTypes.ReadNextBool(packetData)) dataTypes.SkipNextString(packetData); } } - - autocomplete_received = true; + handler.OnAutoCompleteDone(old_transaction_id, autocomplete_result); break; case PacketTypesIn.PluginMessage: String channel = dataTypes.ReadNextString(packetData); @@ -2110,18 +2109,10 @@ namespace MinecraftClient.Protocol.Handlers /// /// Text behind cursor /// Completed text - IEnumerable IAutoComplete.AutoComplete(string BehindCursor) + int IAutoComplete.AutoComplete(string BehindCursor) { - var sug = McClient.dispatcher.GetCompletionSuggestions(McClient.dispatcher.Parse(BehindCursor[1..], McClient.cmd_source)); - sug.Wait(); - foreach (var hint in sug.Result.List) - { - log.Info(hint); - } - //log.Info(McClient.dispatcher.GetSmartUsage(McClient.dispatcher.Parse(BehindCursor, McClient.cmd_source), McClient.cmd_source)); - - if (String.IsNullOrEmpty(BehindCursor)) - return Array.Empty(); + if (string.IsNullOrEmpty(BehindCursor)) + return -1; byte[] transaction_id = dataTypes.GetVarInt(autocomplete_transaction_id); byte[] assume_command = new byte[] { 0x00 }; @@ -2134,16 +2125,14 @@ namespace MinecraftClient.Protocol.Handlers if (protocolVersion >= MC_1_13_Version) { tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, transaction_id); - tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, dataTypes.GetString(BehindCursor)); + tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, dataTypes.GetString(BehindCursor.Replace(' ', (char)0x00))); } else { tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, dataTypes.GetString(BehindCursor)); if (protocolVersion >= MC_1_9_Version) - { tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, assume_command); - } tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, has_position); } @@ -2152,22 +2141,9 @@ namespace MinecraftClient.Protocol.Handlers { tabcomplete_packet = dataTypes.ConcatBytes(dataTypes.GetString(BehindCursor)); } - - autocomplete_received = false; - autocomplete_result.Clear(); - autocomplete_result.Add(BehindCursor); + ConsoleIO.AutoCompleteDone = false; SendPacket(PacketTypesOut.TabComplete, tabcomplete_packet); - - int wait_left = 50; //do not wait more than 5 seconds (50 * 100 ms) - ThreadStart start = new(delegate - { - while (wait_left > 0 && !autocomplete_received) { System.Threading.Thread.Sleep(100); wait_left--; } - if (autocomplete_result.Count > 0) - ConsoleIO.WriteLineFormatted("§8" + String.Join(" ", autocomplete_result), false); - }); - Thread t1 = new(start); - t1.Start(); - return autocomplete_result; + return autocomplete_transaction_id; } /// diff --git a/MinecraftClient/Protocol/Handlers/Protocol18Forge.cs b/MinecraftClient/Protocol/Handlers/Protocol18Forge.cs index 382ba5c5..922496d1 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18Forge.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18Forge.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using System.Threading; using MinecraftClient.Protocol.Handlers.Forge; +using MinecraftClient.Protocol.Message; +using MinecraftClient.Scripting; namespace MinecraftClient.Protocol.Handlers { diff --git a/MinecraftClient/Protocol/IMinecraftCom.cs b/MinecraftClient/Protocol/IMinecraftCom.cs index afe5b1ba..5597dafb 100644 --- a/MinecraftClient/Protocol/IMinecraftCom.cs +++ b/MinecraftClient/Protocol/IMinecraftCom.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using MinecraftClient.Inventory; using MinecraftClient.Mapping; -using MinecraftClient.Protocol.Keys; +using MinecraftClient.Protocol.ProfileKey; namespace MinecraftClient.Protocol { diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs index 1ac38a39..2e8986bd 100644 --- a/MinecraftClient/Protocol/IMinecraftComHandler.cs +++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs @@ -4,6 +4,7 @@ using MinecraftClient.Inventory; using MinecraftClient.Logger; using MinecraftClient.Mapping; using MinecraftClient.Protocol.Message; +using MinecraftClient.Scripting; namespace MinecraftClient.Protocol { @@ -456,6 +457,13 @@ namespace MinecraftClient.Protocol /// The block public void OnBlockChange(Location location, Block block); + /// + /// Called when "AutoComplete" completes. + /// + /// The number of this result. + /// All commands. + public void OnAutoCompleteDone(int transactionId, string[] result); + /// /// Send a click container button packet to the server. /// Used for Enchanting table, Lectern, stone cutter and loom diff --git a/MinecraftClient/Protocol/Message/ChatParser.cs b/MinecraftClient/Protocol/Message/ChatParser.cs index 47e02256..5255e957 100644 --- a/MinecraftClient/Protocol/Message/ChatParser.cs +++ b/MinecraftClient/Protocol/Message/ChatParser.cs @@ -4,10 +4,9 @@ using System.IO; using System.Net.Http; using System.Text; using System.Threading.Tasks; -using MinecraftClient.Protocol.Message; using static MinecraftClient.Settings; -namespace MinecraftClient.Protocol +namespace MinecraftClient.Protocol.Message { /// /// This class parses JSON chat data from MC 1.6+ and returns the appropriate string to be printed. @@ -223,7 +222,7 @@ namespace MinecraftClient.Protocol HttpClient httpClient = new(); try { - Task fetch_index = httpClient.GetStringAsync(Settings.TranslationsFile_Website_Index); + Task fetch_index = httpClient.GetStringAsync(TranslationsFile_Website_Index); fetch_index.Wait(); string assets_index = fetch_index.Result; fetch_index.Dispose(); @@ -231,8 +230,8 @@ namespace MinecraftClient.Protocol string[] tmp = assets_index.Split(new string[] { "minecraft/lang/" + Config.Main.Advanced.Language.ToLower() + ".json" }, StringSplitOptions.None); tmp = tmp[1].Split(new string[] { "hash\": \"" }, StringSplitOptions.None); string hash = tmp[1].Split('"')[0]; //Translations file identifier on Mojang's servers - string translation_file_location = Settings.TranslationsFile_Website_Download + '/' + hash[..2] + '/' + hash; - if (Settings.Config.Logging.DebugMessages) + string translation_file_location = TranslationsFile_Website_Download + '/' + hash[..2] + '/' + hash; + if (Config.Logging.DebugMessages) ConsoleIO.WriteLineFormatted(string.Format(Translations.chat_request, translation_file_location)); Task fetch_file = httpClient.GetStringAsync(translation_file_location); @@ -242,7 +241,7 @@ namespace MinecraftClient.Protocol StringBuilder stringBuilder = new(); foreach (KeyValuePair entry in Json.ParseJson(translation_file).Properties) - stringBuilder.Append(entry.Key).Append('=').Append(entry.Value.StringValue.Replace("\n", "\\n").Replace("\r", String.Empty)).Append(Environment.NewLine); + stringBuilder.Append(entry.Key).Append('=').Append(entry.Value.StringValue.Replace("\n", "\\n").Replace("\r", string.Empty)).Append(Environment.NewLine); File.WriteAllText(Language_File, stringBuilder.ToString()); ConsoleIO.WriteLineFormatted(string.Format(Translations.chat_done, Language_File)); @@ -256,9 +255,9 @@ namespace MinecraftClient.Protocol //Download Failed? Defaulting to en_GB.lang if the game is installed if (!File.Exists(Language_File) //Try en_GB.lang - && File.Exists(Settings.TranslationsFile_FromMCDir)) + && File.Exists(TranslationsFile_FromMCDir)) { - Language_File = Settings.TranslationsFile_FromMCDir; + Language_File = TranslationsFile_FromMCDir; ConsoleIO.WriteLineFormatted(Translations.chat_from_dir, acceptnewlines: true); } @@ -277,7 +276,7 @@ namespace MinecraftClient.Protocol } } - if (Settings.Config.Logging.DebugMessages) + if (Config.Logging.DebugMessages) ConsoleIO.WriteLineFormatted(Translations.chat_loaded, acceptnewlines: true); } else //No external dictionnary found. diff --git a/MinecraftClient/Protocol/MojangAPI.cs b/MinecraftClient/Protocol/MojangAPI.cs index e0dade07..8ee28b31 100644 --- a/MinecraftClient/Protocol/MojangAPI.cs +++ b/MinecraftClient/Protocol/MojangAPI.cs @@ -214,7 +214,7 @@ namespace MinecraftClient.Protocol fetchTask.Dispose(); } catch (Exception) - { + { return new MojangServiceStatus(); } diff --git a/MinecraftClient/Protocol/PlayerInfo.cs b/MinecraftClient/Protocol/PlayerInfo.cs index b77aea58..31e4300e 100644 --- a/MinecraftClient/Protocol/PlayerInfo.cs +++ b/MinecraftClient/Protocol/PlayerInfo.cs @@ -1,7 +1,7 @@ using System; using System.Linq; -using MinecraftClient.Protocol.Keys; using MinecraftClient.Protocol.Message; +using MinecraftClient.Protocol.ProfileKey; namespace MinecraftClient.Protocol { diff --git a/MinecraftClient/Protocol/ProfileKey/KeyUtils.cs b/MinecraftClient/Protocol/ProfileKey/KeyUtils.cs index 94cce827..fdd68560 100644 --- a/MinecraftClient/Protocol/ProfileKey/KeyUtils.cs +++ b/MinecraftClient/Protocol/ProfileKey/KeyUtils.cs @@ -4,7 +4,7 @@ using System.Security.Cryptography; using System.Text; using MinecraftClient.Protocol.Message; -namespace MinecraftClient.Protocol.Keys +namespace MinecraftClient.Protocol.ProfileKey { static class KeyUtils { @@ -45,7 +45,7 @@ namespace MinecraftClient.Protocol.Keys } catch (Exception e) { - int code = (response == null) ? 0 : response.StatusCode; + int code = response == null ? 0 : response.StatusCode; ConsoleIO.WriteLineFormatted("§cFetch profile key failed: HttpCode = " + code + ", Error = " + e.Message); if (Settings.Config.Logging.DebugMessages) { @@ -55,7 +55,7 @@ namespace MinecraftClient.Protocol.Keys } } - public static byte[] DecodePemKey(String key, String prefix, String suffix) + public static byte[] DecodePemKey(string key, string prefix, string suffix) { int i = key.IndexOf(prefix); if (i != -1) @@ -64,8 +64,8 @@ namespace MinecraftClient.Protocol.Keys int j = key.IndexOf(suffix, i); key = key[i..j]; } - key = key.Replace("\r", String.Empty); - key = key.Replace("\n", String.Empty); + key = key.Replace("\r", string.Empty); + key = key.Replace("\n", string.Empty); return Convert.FromBase64String(key); } @@ -135,11 +135,11 @@ namespace MinecraftClient.Protocol.Keys char c = src[i]; bool needEscape = c < 32 || c == '"' || c == '\\'; // Broken lead surrogate - needEscape = needEscape || (c >= '\uD800' && c <= '\uDBFF' && - (i == src.Length - 1 || src[i + 1] < '\uDC00' || src[i + 1] > '\uDFFF')); + needEscape = needEscape || c >= '\uD800' && c <= '\uDBFF' && + (i == src.Length - 1 || src[i + 1] < '\uDC00' || src[i + 1] > '\uDFFF'); // Broken tail surrogate - needEscape = needEscape || (c >= '\uDC00' && c <= '\uDFFF' && - (i == 0 || src[i - 1] < '\uD800' || src[i - 1] > '\uDBFF')); + needEscape = needEscape || c >= '\uDC00' && c <= '\uDFFF' && + (i == 0 || src[i - 1] < '\uD800' || src[i - 1] > '\uDBFF'); // To produce valid JavaScript needEscape = needEscape || c == '\u2028' || c == '\u2029'; diff --git a/MinecraftClient/Protocol/ProfileKey/KeysCache.cs b/MinecraftClient/Protocol/ProfileKey/KeysCache.cs index 9962e2aa..4b052f96 100644 --- a/MinecraftClient/Protocol/ProfileKey/KeysCache.cs +++ b/MinecraftClient/Protocol/ProfileKey/KeysCache.cs @@ -6,7 +6,7 @@ using System.Timers; using static MinecraftClient.Settings; using static MinecraftClient.Settings.MainConfigHealper.MainConfig.AdvancedConfig; -namespace MinecraftClient.Protocol.Keys +namespace MinecraftClient.Protocol.ProfileKey { /// /// Handle keys caching and storage. @@ -115,7 +115,7 @@ namespace MinecraftClient.Protocol.Keys //User-editable keys cache file in text format if (File.Exists(KeysCacheFilePlaintext)) { - if (Settings.Config.Logging.DebugMessages) + if (Config.Logging.DebugMessages) ConsoleIO.WriteLineFormatted(string.Format(Translations.cache_loading_keys, KeysCacheFilePlaintext)); try @@ -134,27 +134,27 @@ namespace MinecraftClient.Protocol.Keys { PlayerKeyPair playerKeyPair = PlayerKeyPair.FromString(value); keys[login] = playerKeyPair; - if (Settings.Config.Logging.DebugMessages) + if (Config.Logging.DebugMessages) ConsoleIO.WriteLineFormatted(string.Format(Translations.cache_loaded_keys, playerKeyPair.ExpiresAt.ToString())); } catch (InvalidDataException e) { - if (Settings.Config.Logging.DebugMessages) + if (Config.Logging.DebugMessages) ConsoleIO.WriteLineFormatted(string.Format(Translations.cache_ignore_string_keys, value, e.Message)); } catch (FormatException e) { - if (Settings.Config.Logging.DebugMessages) + if (Config.Logging.DebugMessages) ConsoleIO.WriteLineFormatted(string.Format(Translations.cache_ignore_string_keys, value, e.Message)); } catch (ArgumentNullException e) { - if (Settings.Config.Logging.DebugMessages) + if (Config.Logging.DebugMessages) ConsoleIO.WriteLineFormatted(string.Format(Translations.cache_ignore_string_keys, value, e.Message)); } } - else if (Settings.Config.Logging.DebugMessages) + else if (Config.Logging.DebugMessages) { ConsoleIO.WriteLineFormatted(string.Format(Translations.cache_ignore_line_keys, line)); } diff --git a/MinecraftClient/Protocol/ProfileKey/PlayerKeyPair.cs b/MinecraftClient/Protocol/ProfileKey/PlayerKeyPair.cs index d7b0fe39..572b0d06 100644 --- a/MinecraftClient/Protocol/ProfileKey/PlayerKeyPair.cs +++ b/MinecraftClient/Protocol/ProfileKey/PlayerKeyPair.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; -namespace MinecraftClient.Protocol.Keys +namespace MinecraftClient.Protocol.ProfileKey { public class PlayerKeyPair { @@ -74,17 +74,17 @@ namespace MinecraftClient.Protocol.Keys List datas = new(); datas.Add(Convert.ToBase64String(PublicKey.Key)); if (PublicKey.Signature == null) - datas.Add(String.Empty); + datas.Add(string.Empty); else datas.Add(Convert.ToBase64String(PublicKey.Signature)); if (PublicKey.SignatureV2 == null) - datas.Add(String.Empty); + datas.Add(string.Empty); else datas.Add(Convert.ToBase64String(PublicKey.SignatureV2)); datas.Add(Convert.ToBase64String(PrivateKey.Key)); datas.Add(ExpiresAt.ToString(DataTimeFormat)); datas.Add(RefreshedAfter.ToString(DataTimeFormat)); - return String.Join(",", datas.ToArray()); + return string.Join(",", datas.ToArray()); } } } diff --git a/MinecraftClient/Protocol/ProfileKey/PrivateKey.cs b/MinecraftClient/Protocol/ProfileKey/PrivateKey.cs index b3dd4093..6cb8103b 100644 --- a/MinecraftClient/Protocol/ProfileKey/PrivateKey.cs +++ b/MinecraftClient/Protocol/ProfileKey/PrivateKey.cs @@ -2,7 +2,7 @@ using System.Security.Cryptography; using MinecraftClient.Protocol.Message; -namespace MinecraftClient.Protocol.Keys +namespace MinecraftClient.Protocol.ProfileKey { public class PrivateKey { diff --git a/MinecraftClient/Protocol/ProfileKey/PublicKey.cs b/MinecraftClient/Protocol/ProfileKey/PublicKey.cs index 429c3962..2f01fa84 100644 --- a/MinecraftClient/Protocol/ProfileKey/PublicKey.cs +++ b/MinecraftClient/Protocol/ProfileKey/PublicKey.cs @@ -2,7 +2,7 @@ using System.Security.Cryptography; using MinecraftClient.Protocol.Message; -namespace MinecraftClient.Protocol.Keys +namespace MinecraftClient.Protocol.ProfileKey { public class PublicKey { diff --git a/MinecraftClient/Protocol/Session/SessionToken.cs b/MinecraftClient/Protocol/Session/SessionToken.cs index e48567d9..c3c0aee9 100644 --- a/MinecraftClient/Protocol/Session/SessionToken.cs +++ b/MinecraftClient/Protocol/Session/SessionToken.cs @@ -2,6 +2,7 @@ using System.IO; using System.Text.RegularExpressions; using System.Threading.Tasks; +using MinecraftClient.Scripting; namespace MinecraftClient.Protocol.Session { diff --git a/MinecraftClient/Resources/Translations/Translations.Designer.cs b/MinecraftClient/Resources/Translations/Translations.Designer.cs index 3f5208f1..fd93a259 100644 --- a/MinecraftClient/Resources/Translations/Translations.Designer.cs +++ b/MinecraftClient/Resources/Translations/Translations.Designer.cs @@ -151,7 +151,7 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to Available commands: {0}. Use /autocraft help <cmd name> for more information. You may use /ac as command alias.. + /// Looks up a localized string similar to Available commands: {0}. Use /autocraft help <cmd name> for more information.. /// internal static string bot_autoCraft_available_cmd { get { @@ -403,7 +403,7 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to Available commands: {0}. Use /digbot help <cmd name> for more information.. + /// Looks up a localized string similar to Available commands: {0}. Use /autodig help <cmd name> for more information.. /// internal static string bot_autodig_available_cmd { get { @@ -430,7 +430,7 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to Get the command description. Usage: /digbot help <command name>. + /// Looks up a localized string similar to Get the command description. Usage: /autodig help <command name>. /// internal static string bot_autodig_help_help { get { @@ -2488,7 +2488,7 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to Searching for a bed in radius of {0}.... + /// Looks up a localized string similar to Searching for a bed in radius of {0:0.00}.... /// internal static string cmd_bed_searching { get { @@ -3599,7 +3599,7 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to Unknown action. . + /// Looks up a localized string similar to Unknown action.. /// internal static string cmd_inventory_help_unknown { get { @@ -4068,7 +4068,7 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to setrnd variable -7to17 OR setrnd variable string1 "\"string2\" string3". + /// Looks up a localized string similar to setrnd variable -7 to 17 OR setrnd variable string1 "\"string2\" string3". /// internal static string cmd_setrnd_format { get { @@ -4077,7 +4077,7 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to setrnd variable -7to17. + /// Looks up a localized string similar to setrnd variable -7 to 17. /// internal static string cmd_setrndnum_format { get { @@ -6875,7 +6875,8 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to help <cmdname>. Available commands: {0}. For server help, use '{1}send /help' instead.. + /// Looks up a localized string similar to help <cmdname>. Available commands: + ///{0}For server help, use '{1}send /help' instead.. /// internal static string icmd_list { get { diff --git a/MinecraftClient/Resources/Translations/Translations.resx b/MinecraftClient/Resources/Translations/Translations.resx index 8e041df0..2beab3d2 100644 --- a/MinecraftClient/Resources/Translations/Translations.resx +++ b/MinecraftClient/Resources/Translations/Translations.resx @@ -148,7 +148,7 @@ Auto-crafting ChatBot command alias - Available commands: {0}. Use /autocraft help <cmd name> for more information. You may use /ac as command alias. + Available commands: {0}. Use /autocraft help <cmd name> for more information. Inventory #{0} was closed by AutoCraft @@ -232,7 +232,7 @@ Action timeout! Reason: {0} - Available commands: {0}. Use /digbot help <cmd name> for more information. + Available commands: {0}. Use /autodig help <cmd name> for more information. Auto-digging ChatBot command @@ -241,7 +241,7 @@ Digging block timeout, retry. - Get the command description. Usage: /digbot help <command name> + Get the command description. Usage: /autodig help <command name> Start the automatic digging bot. @@ -937,7 +937,7 @@ Some messages won't be properly printed without this file. Could not lay in bed. Are you trying to sleep in a bed? (PS: You must use the head block coordinates of the bed) - Searching for a bed in radius of {0}... + Searching for a bed in radius of {0:0.00}... Trying to sleep in a bed on location (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}). Result: {3} @@ -1307,7 +1307,7 @@ Note that parameters in '[]' are optional. Shift click an item. - Unknown action. + Unknown action. Usage @@ -1461,7 +1461,7 @@ You can use "/chunk status {0:0.0} {1:0.0} {2:0.0}" to check the chunk loading s set a custom %variable% randomly to a given value. - setrnd variable -7to17 + setrnd variable -7 to 17 setrnd variable string1 "\"string2\" string3" @@ -2471,7 +2471,8 @@ If the connection to the Minecraft game server is blocked by the firewall, set E help <cmdname>: show brief help about a command. - help <cmdname>. Available commands: {0}. For server help, use '{1}send /help' instead. + help <cmdname>. Available commands: +{0}For server help, use '{1}send /help' instead. Unknown command '{0}'. Use 'help' for command list. @@ -2644,7 +2645,7 @@ Logging in... Load translations applied to MCC when available, turn it off to use English only. - setrnd variable -7to17 OR setrnd variable string1 "\"string2\" string3" + setrnd variable -7 to 17 OR setrnd variable string1 "\"string2\" string3" Please update health field handling for this Minecraft version. diff --git a/MinecraftClient/Scripting/AssemblyResolver.cs b/MinecraftClient/Scripting/AssemblyResolver.cs index f9f970ea..85b16405 100644 --- a/MinecraftClient/Scripting/AssemblyResolver.cs +++ b/MinecraftClient/Scripting/AssemblyResolver.cs @@ -4,34 +4,36 @@ using System.Reflection; namespace MinecraftClient.Scripting; -public static class AssemblyResolver { +public static class AssemblyResolver +{ private static Dictionary ScriptAssemblies = new(); - static AssemblyResolver() { + static AssemblyResolver() + { // Manually resolve assemblies that .NET can't resolve automatically. - AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => + AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { - var asmReqName = new AssemblyName(args.Name); - - // Check the script-referenced assemblies if we have the DLL that is required. - foreach (var dll in ScriptAssemblies) - { - // If we have the assembly, load it. - if (asmReqName.FullName == dll.Key) - { - return Assembly.LoadFile(dll.Value); - } - } + var asmReqName = new AssemblyName(args.Name); - ConsoleIO.WriteLogLine($"[Script Error] Failed to resolve assembly {args.Name} (are you missing a DLL file?)"); - return null; - }; + // Check the script-referenced assemblies if we have the DLL that is required. + foreach (var dll in ScriptAssemblies) + { + // If we have the assembly, load it. + if (asmReqName.FullName == dll.Key) + { + return Assembly.LoadFile(dll.Value); + } + } + + ConsoleIO.WriteLogLine($"[Script Error] Failed to resolve assembly {args.Name} (are you missing a DLL file?)"); + return null; + }; } - internal static void AddAssembly(string AssemblyFullName, string AssemblyPath) + internal static void AddAssembly(string AssemblyFullName, string AssemblyPath) { if (ScriptAssemblies.ContainsKey(AssemblyFullName)) return; - + ScriptAssemblies.Add(AssemblyFullName, AssemblyPath); } } \ No newline at end of file diff --git a/MinecraftClient/Scripting/CSharpRunner.cs b/MinecraftClient/Scripting/CSharpRunner.cs index 026a29fa..1d6f258a 100644 --- a/MinecraftClient/Scripting/CSharpRunner.cs +++ b/MinecraftClient/Scripting/CSharpRunner.cs @@ -4,10 +4,10 @@ using System.ComponentModel; using System.IO; using System.Linq; using System.Text; -using DynamicRun.Builder; +using MinecraftClient.Scripting.DynamicRun.Builder; using static MinecraftClient.Settings; -namespace MinecraftClient +namespace MinecraftClient.Scripting { /// /// C# Script runner - Compile on-the-fly and run C# scripts @@ -77,7 +77,7 @@ namespace MinecraftClient script.Add("return null;"); //Generate a class from the given script - string code = String.Join("\n", new string[] + string code = string.Join("\n", new string[] { "using System;", "using System.Collections.Generic;", @@ -90,15 +90,15 @@ namespace MinecraftClient "using MinecraftClient;", "using MinecraftClient.Mapping;", "using MinecraftClient.Inventory;", - String.Join("\n", libs), + string.Join("\n", libs), "namespace ScriptLoader {", "public class Script {", "public CSharpAPI MCC;", "public object __run(CSharpAPI __apiHandler, string[] args) {", "this.MCC = __apiHandler;", - String.Join("\n", script), + string.Join("\n", script), "}", - String.Join("\n", extensions), + string.Join("\n", extensions), "}}", }); @@ -108,11 +108,13 @@ namespace MinecraftClient var result = compiler.Compile(code, Guid.NewGuid().ToString(), dlls); //Process compile warnings and errors - if (result.Failures != null) { - + if (result.Failures != null) + { + ConsoleIO.WriteLogLine("[Script] Compilation failed with error(s):"); - foreach (var failure in result.Failures) { + foreach (var failure in result.Failures) + { ConsoleIO.WriteLogLine($"[Script] Error in {scriptName}, line:col{failure.Location.GetMappedLineSpan()}: [{failure.Id}] {failure.GetMessage()}"); } @@ -226,7 +228,7 @@ namespace MinecraftClient /// TRUE if successfully sent (Deprectated, always returns TRUE for compatibility purposes with existing scripts) public bool SendText(object text) { - return base.SendText(text is string str ? str : (text.ToString() ?? string.Empty)); + return base.SendText(text is string str ? str : text.ToString() ?? string.Empty); } /// @@ -305,7 +307,7 @@ namespace MinecraftClient if (localVars != null && localVars.ContainsKey(varName)) return localVars[varName]; else - return Settings.Config.AppVar.GetVar(varName); + return Config.AppVar.GetVar(varName); } /// @@ -317,7 +319,7 @@ namespace MinecraftClient { if (localVars != null && localVars.ContainsKey(varName)) localVars.Remove(varName); - return Settings.Config.AppVar.SetVar(varName, varValue); + return Config.AppVar.SetVar(varName, varValue); } /// @@ -359,7 +361,7 @@ namespace MinecraftClient /// True if the account was found and loaded public bool SetAccount(string accountAlias, bool andReconnect = false) { - bool result = Settings.Config.Main.Advanced.SetAccount(accountAlias); + bool result = Config.Main.Advanced.SetAccount(accountAlias); if (result && andReconnect) ReconnectToTheServer(keepAccountAndServerSettings: true); return result; @@ -372,7 +374,7 @@ namespace MinecraftClient /// True if the server IP was valid and loaded, false otherwise public bool SetServer(string server, bool andReconnect = false) { - bool result = Settings.Config.Main.SetServerIP(new MainConfigHealper.MainConfig.ServerInfoConfig(server), true); + bool result = Config.Main.SetServerIP(new MainConfigHealper.MainConfig.ServerInfoConfig(server), true); if (result && andReconnect) ReconnectToTheServer(keepAccountAndServerSettings: true); return result; diff --git a/MinecraftClient/Scripting/ChatBot.cs b/MinecraftClient/Scripting/ChatBot.cs index 61cd85c7..245a1a4a 100644 --- a/MinecraftClient/Scripting/ChatBot.cs +++ b/MinecraftClient/Scripting/ChatBot.cs @@ -5,12 +5,12 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; using Brigadier.NET; -using MinecraftClient.Commands; +using MinecraftClient.CommandHandler; using MinecraftClient.Inventory; using MinecraftClient.Mapping; using static MinecraftClient.Settings; -namespace MinecraftClient +namespace MinecraftClient.Scripting { /// /// Welcome to the Bot API file ! @@ -42,7 +42,6 @@ namespace MinecraftClient private McClient? _handler = null; private ChatBot? master = null; private readonly List registeredPluginChannels = new(); - private readonly List registeredCommands = new(); private readonly object delayTasksLock = new(); private readonly List delayedTasks = new(); protected McClient Handler @@ -101,12 +100,12 @@ namespace MinecraftClient /// NOTE: Chat messages cannot be sent at this point in the login process. /// If you want to send a message when the bot is loaded, use AfterGameJoined. /// - public virtual void Initialize() { } + public virtual void Initialize(CommandDispatcher dispatcher) { } /// /// This method is called when the bot is being unloaded, you can use it to free up resources like DB connections /// - public virtual void OnUnload() { } + public virtual void OnUnload(CommandDispatcher dispatcher) { } /// /// Called after the server has been joined successfully and chat messages are able to be sent. @@ -175,13 +174,13 @@ namespace MinecraftClient /// Called when properties for the Player entity are received from the server /// /// Dictionary of player properties - public virtual void OnPlayerProperty(Dictionary prop) { } + public virtual void OnPlayerProperty(Dictionary prop) { } /// /// Called when server TPS are recalculated by MCC based on world time updates /// /// New estimated server TPS (between 0 and 20) - public virtual void OnServerTpsUpdate(Double tps) { } + public virtual void OnServerTpsUpdate(double tps) { } /// /// Called when a time changed @@ -194,7 +193,7 @@ namespace MinecraftClient /// Called when an entity moved nearby /// /// Entity with updated location - public virtual void OnEntityMove(Mapping.Entity entity) { } + public virtual void OnEntityMove(Entity entity) { } /// /// Called after an internal MCC command has been performed @@ -202,19 +201,19 @@ namespace MinecraftClient /// MCC Command Name /// MCC Command Parameters /// MCC command result - public virtual void OnInternalCommand(string commandName, string commandParams, string Result) { } + public virtual void OnInternalCommand(string commandName, string commandParams, CmdResult Result) { } /// /// Called when an entity spawned nearby /// /// New Entity - public virtual void OnEntitySpawn(Mapping.Entity entity) { } + public virtual void OnEntitySpawn(Entity entity) { } /// /// Called when an entity despawns/dies nearby /// /// Entity wich has just disappeared - public virtual void OnEntityDespawn(Mapping.Entity entity) { } + public virtual void OnEntityDespawn(Entity entity) { } /// /// Called when the player held item has changed @@ -515,7 +514,7 @@ namespace MinecraftClient /// TRUE if the command was indeed an internal MCC command protected bool PerformInternalCommand(string command, Dictionary? localVars = null) { - string? temp = ""; + CmdResult temp = new(); return Handler.PerformInternalCommand(command, ref temp, localVars); } @@ -526,9 +525,9 @@ namespace MinecraftClient /// May contain a confirmation or error message after processing the command, or "" otherwise. /// Local variables passed along with the command /// TRUE if the command was indeed an internal MCC command - protected bool PerformInternalCommand(string command, ref string? response_msg, Dictionary? localVars = null) + protected bool PerformInternalCommand(string command, ref CmdResult result, Dictionary? localVars = null) { - return Handler.PerformInternalCommand(command, ref response_msg, localVars); + return Handler.PerformInternalCommand(command, ref result, localVars); } /// @@ -536,8 +535,8 @@ namespace MinecraftClient /// public static string GetVerbatim(string? text) { - if (String.IsNullOrEmpty(text)) - return String.Empty; + if (string.IsNullOrEmpty(text)) + return string.Empty; int idx = 0; var data = new char[text.Length]; @@ -556,13 +555,13 @@ namespace MinecraftClient /// public static bool IsValidName(string username) { - if (String.IsNullOrEmpty(username)) + if (string.IsNullOrEmpty(username)) return false; foreach (char c in username) - if (!((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') + if (!(c >= 'a' && c <= 'z' + || c >= 'A' && c <= 'Z' + || c >= '0' && c <= '9' || c == '_')) return false; @@ -578,7 +577,7 @@ namespace MinecraftClient /// Returns true if the text is a private message protected static bool IsPrivateMessage(string text, ref string message, ref string sender) { - if (String.IsNullOrEmpty(text)) + if (string.IsNullOrEmpty(text)) return false; text = GetVerbatim(text); @@ -689,7 +688,7 @@ namespace MinecraftClient /// Returns true if the text is a chat message protected static bool IsChatMessage(string text, ref string message, ref string sender) { - if (String.IsNullOrEmpty(text)) + if (string.IsNullOrEmpty(text)) return false; text = GetVerbatim(text); @@ -792,7 +791,7 @@ namespace MinecraftClient /// Returns true if the text is a teleport request protected static bool IsTeleportRequest(string text, ref string sender) { - if (String.IsNullOrEmpty(text)) + if (string.IsNullOrEmpty(text)) return false; text = GetVerbatim(text); @@ -820,8 +819,8 @@ namespace MinecraftClient { // Username has requested... //[Rank] Username has requested... - if (((tmp[0].StartsWith("<") && tmp[0].EndsWith(">")) - || (tmp[0].StartsWith("[") && tmp[0].EndsWith("]"))) + if ((tmp[0].StartsWith("<") && tmp[0].EndsWith(">") + || tmp[0].StartsWith("[") && tmp[0].EndsWith("]")) && tmp.Length > 1) sender = tmp[1]; else //Username has requested.. @@ -847,12 +846,12 @@ namespace MinecraftClient { string botName = Translations.ResourceManager.GetString("botname." + GetType().Name) ?? GetType().Name; if (_handler == null || master == null) - ConsoleIO.WriteLogLine(String.Format("[{0}] {1}", botName, text)); + ConsoleIO.WriteLogLine(string.Format("[{0}] {1}", botName, text)); else - Handler.Log.Info(String.Format("[{0}] {1}", botName, text)); - string logfile = Settings.Config.AppVar.ExpandVars(Config.Main.Advanced.ChatbotLogFile); + Handler.Log.Info(string.Format("[{0}] {1}", botName, text)); + string logfile = Config.AppVar.ExpandVars(Config.Main.Advanced.ChatbotLogFile); - if (!String.IsNullOrEmpty(logfile)) + if (!string.IsNullOrEmpty(logfile)) { if (!File.Exists(logfile)) { @@ -869,10 +868,10 @@ namespace MinecraftClient protected static void LogToConsole(string originBotName, object? text) { string botName = Translations.ResourceManager.GetString(originBotName) ?? originBotName; - ConsoleIO.WriteLogLine(String.Format("[{0}] {1}", botName, text)); - string logfile = Settings.Config.AppVar.ExpandVars(Config.Main.Advanced.ChatbotLogFile); + ConsoleIO.WriteLogLine(string.Format("[{0}] {1}", botName, text)); + string logfile = Config.AppVar.ExpandVars(Config.Main.Advanced.ChatbotLogFile); - if (!String.IsNullOrEmpty(logfile)) + if (!string.IsNullOrEmpty(logfile)) { if (!File.Exists(logfile)) { @@ -892,7 +891,7 @@ namespace MinecraftClient /// Debug log text to write protected void LogDebugToConsole(object text) { - if (Settings.Config.Logging.DebugMessages) + if (Config.Logging.DebugMessages) LogToConsole(text); } @@ -924,7 +923,7 @@ namespace MinecraftClient /// Optional delay, in seconds, before restarting protected void ReconnectToTheServer(int ExtraAttempts = 3, int delaySeconds = 0, bool keepAccountAndServerSettings = false) { - if (Settings.Config.Logging.DebugMessages) + if (Config.Logging.DebugMessages) { string botName = Translations.ResourceManager.GetString("botname." + GetType().Name) ?? GetType().Name; ConsoleIO.WriteLogLine(string.Format(Translations.chatbot_reconnect, botName)); @@ -946,10 +945,6 @@ namespace MinecraftClient /// protected void UnloadBot() { - foreach (string cmdName in registeredCommands) - { - Handler.UnregisterCommand(cmdName); - } Handler.BotUnLoad(this); } @@ -960,7 +955,7 @@ namespace MinecraftClient /// Message protected void SendPrivateMessage(string player, string message) { - SendText(String.Format("/{0} {1} {2}", Config.Main.Advanced.PrivateMsgsCmdName, player, message)); + SendText(string.Format("/{0} {1} {2}", Config.Main.Advanced.PrivateMsgsCmdName, player, message)); } /// @@ -1079,7 +1074,7 @@ namespace MinecraftClient /// Get the current location of the player (Feet location) /// /// Minecraft world or null if associated setting is disabled - protected Mapping.Location GetCurrentLocation() + protected Location GetCurrentLocation() { return Handler.GetCurrentLocation(); } @@ -1095,7 +1090,7 @@ namespace MinecraftClient /// How long to wait before stopping computation (default: 5 seconds) /// When location is unreachable, computation will reach timeout, then optionally fallback to a close location within maxOffset /// True if a path has been found - protected bool MoveToLocation(Mapping.Location location, bool allowUnsafe = false, bool allowDirectTeleport = false, int maxOffset = 0, int minOffset = 0, TimeSpan? timeout = null) + protected bool MoveToLocation(Location location, bool allowUnsafe = false, bool allowDirectTeleport = false, int maxOffset = 0, int minOffset = 0, TimeSpan? timeout = null) { return Handler.MoveTo(location, allowUnsafe, allowDirectTeleport, maxOffset, minOffset, timeout); } @@ -1113,7 +1108,7 @@ namespace MinecraftClient /// Look at the specified location /// /// Location to look at - protected void LookAtLocation(Mapping.Location location) + protected void LookAtLocation(Location location) { Handler.UpdateLocation(Handler.GetCurrentLocation(), location); } @@ -1167,13 +1162,13 @@ namespace MinecraftClient //Read all lines from file, remove lines with no text, convert to lowercase, //remove duplicate entries, convert to a string array, and return the result. return File.ReadAllLines(file, Encoding.UTF8) - .Where(line => !String.IsNullOrWhiteSpace(line)) + .Where(line => !string.IsNullOrWhiteSpace(line)) .Select(line => line.ToLower()) .Distinct().ToArray(); } else { - LogToConsole("File not found: " + System.IO.Path.GetFullPath(file)); + LogToConsole("File not found: " + Path.GetFullPath(file)); return Array.Empty(); } } @@ -1315,7 +1310,7 @@ namespace MinecraftClient /// Get server current TPS (tick per second) /// /// tps - protected Double GetServerTPS() + protected double GetServerTPS() { return Handler.GetServerTPS(); } @@ -1541,21 +1536,6 @@ namespace MinecraftClient return Handler.UpdateCommandBlock(location, command, mode, flags); } - /// - /// Register a command in command prompt. Command will be automatically unregistered when unloading ChatBot - /// - /// Name of the command - /// Description/usage of the command - /// Method for handling the command - /// True if successfully registered - protected bool RegisterChatBotCommand(string cmdName, string cmdDesc, string cmdUsage, CommandRunner callback) - { - bool result = Handler.RegisterCommand(cmdName, cmdDesc, cmdUsage, callback); - if (result) - registeredCommands.Add(cmdName.ToLower()); - return result; - } - /// /// Close a opened inventory /// @@ -1687,11 +1667,12 @@ namespace MinecraftClient public override string CmdUsage { get { return _cmdUsage; } } public override string CmdDesc { get { return _cmdDesc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + } - public override string Run(McClient handler, string command, Dictionary? localVars) + public string Run(McClient handler, string command, Dictionary? localVars) { return Runner(command, GetArgs(command)); } diff --git a/MinecraftClient/Scripting/DynamicRun/Builder/CompileRunner.cs b/MinecraftClient/Scripting/DynamicRun/Builder/CompileRunner.cs index 8a1e492c..ee5bf460 100644 --- a/MinecraftClient/Scripting/DynamicRun/Builder/CompileRunner.cs +++ b/MinecraftClient/Scripting/DynamicRun/Builder/CompileRunner.cs @@ -8,9 +8,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; -using MinecraftClient; -namespace DynamicRun.Builder +namespace MinecraftClient.Scripting.DynamicRun.Builder { internal class CompileRunner { diff --git a/MinecraftClient/Scripting/DynamicRun/Builder/Compiler.cs b/MinecraftClient/Scripting/DynamicRun/Builder/Compiler.cs index 4bb02b07..078f97a0 100644 --- a/MinecraftClient/Scripting/DynamicRun/Builder/Compiler.cs +++ b/MinecraftClient/Scripting/DynamicRun/Builder/Compiler.cs @@ -14,11 +14,9 @@ using System.Runtime.InteropServices; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; -using MinecraftClient; -using MinecraftClient.Scripting; using SingleFileExtractor.Core; -namespace DynamicRun.Builder +namespace MinecraftClient.Scripting.DynamicRun.Builder { internal class Compiler { @@ -38,7 +36,7 @@ namespace DynamicRun.Builder Failures = failures.ToList() }; } - + peStream.Seek(0, SeekOrigin.Begin); return new CompileResult() @@ -55,20 +53,20 @@ namespace DynamicRun.Builder var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9); var parsedSyntaxTree = SyntaxFactory.ParseSyntaxTree(codeString, options); - + var references = new List(); // Find if any additional assembly DLL exists in the base directory where the .exe exists. - foreach (var assembly in additionalAssemblies) + foreach (var assembly in additionalAssemblies) { var dllPath = Path.Combine(AppContext.BaseDirectory, assembly); - if (File.Exists(dllPath)) + if (File.Exists(dllPath)) { references.Add(MetadataReference.CreateFromFile(dllPath)); // Store the reference in our Assembly Resolver for future reference. AssemblyResolver.AddAssembly(Assembly.LoadFile(dllPath).FullName!, dllPath); } - else + else { ConsoleIO.WriteLogLine($"[Script Error] {assembly} is defined in script, but cannot find DLL! Script may not run."); } @@ -79,7 +77,7 @@ namespace DynamicRun.Builder var SystemPrivateCoreLib = typeof(object).Assembly.Location; // System.Private.CoreLib var SystemConsole = typeof(Console).Assembly.Location; // System.Console var MinecraftClientDll = typeof(Program).Assembly.Location; // The path to MinecraftClient.dll - + // We're on a self-contained binary, so we need to extract the executable to get the assemblies. if (string.IsNullOrEmpty(MinecraftClientDll)) { diff --git a/MinecraftClient/Scripting/DynamicRun/Builder/SimpleUnloadableAssemblyLoadContext.cs b/MinecraftClient/Scripting/DynamicRun/Builder/SimpleUnloadableAssemblyLoadContext.cs index de44652c..e210bcac 100644 --- a/MinecraftClient/Scripting/DynamicRun/Builder/SimpleUnloadableAssemblyLoadContext.cs +++ b/MinecraftClient/Scripting/DynamicRun/Builder/SimpleUnloadableAssemblyLoadContext.cs @@ -7,7 +7,7 @@ https://github.com/laurentkempe/DynamicRun/blob/master/LICENSE using System.Reflection; using System.Runtime.Loader; -namespace DynamicRun.Builder +namespace MinecraftClient.Scripting.DynamicRun.Builder { internal class SimpleUnloadableAssemblyLoadContext : AssemblyLoadContext { From 5e11ed38962b56d92c6e09cdca0457e9f271e54e Mon Sep 17 00:00:00 2001 From: BruceChen Date: Sun, 11 Dec 2022 13:00:19 +0800 Subject: [PATCH 3/8] Tooltip support & Bug fix --- MinecraftClient/ChatBots/AntiAFK.cs | 2 - MinecraftClient/ChatBots/AutoAttack.cs | 2 - MinecraftClient/ChatBots/AutoDig.cs | 1 - MinecraftClient/ChatBots/AutoDrop.cs | 1 - MinecraftClient/ChatBots/AutoFishing.cs | 1 - MinecraftClient/ChatBots/AutoRelog.cs | 2 - MinecraftClient/ChatBots/AutoRespond.cs | 2 - MinecraftClient/ChatBots/DiscordBridge.cs | 1 - MinecraftClient/ChatBots/Mailer.cs | 1 - MinecraftClient/ChatBots/ReplayCapture.cs | 1 - MinecraftClient/ChatBots/Script.cs | 2 - MinecraftClient/ChatBots/TelegramBridge.cs | 1 - .../ArgumentType/EntityTypeArgumentType.cs | 23 +- .../ArgumentType/HotbarSlotArgumentType.cs | 43 + .../ArgumentType/InventoryIdArgumentType.cs | 8 +- .../ArgumentType/InventorySlotArgumentType.cs | 55 + .../ArgumentType/ItemTypeArgumentType.cs | 25 +- .../CommandHandler/MccArguments.cs | 10 + .../Patch/CommandDispatcherExtensions.cs | 29 +- .../CommandHandler/SuggestionTooltip.cs | 14 + MinecraftClient/Commands/ChangeSlot.cs | 2 +- MinecraftClient/Commands/Inventory.cs | 16 +- MinecraftClient/Commands/Upgrade.cs | 12 +- MinecraftClient/ConsoleIO.cs | 42 +- MinecraftClient/Mapping/Entity.cs | 9 +- MinecraftClient/McClient.cs | 8 +- MinecraftClient/MinecraftClient.csproj | 10 + MinecraftClient/Program.cs | 2 +- .../Protocol/Message/ChatParser.cs | 120 +- MinecraftClient/Protocol/ProxiedWebRequest.cs | 4 +- MinecraftClient/Proxy/ProxyHandler.cs | 2 +- .../ConfigComments/ConfigComments.Designer.cs | 3680 ++++++----- .../ConfigComments/ConfigComments.resx | 15 + .../Resources/MinecraftAssets.Designer.cs | 73 + .../Resources/MinecraftAssets.resx | 124 + .../Translations/Translations.Designer.cs | 36 +- .../Resources/Translations/Translations.resx | 19 +- MinecraftClient/Resources/en_us.json | 5822 +++++++++++++++++ MinecraftClient/Settings.cs | 172 +- MinecraftClient/UpgradeHelper.cs | 4 +- 40 files changed, 8409 insertions(+), 1987 deletions(-) create mode 100644 MinecraftClient/CommandHandler/ArgumentType/HotbarSlotArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/ArgumentType/InventorySlotArgumentType.cs create mode 100644 MinecraftClient/CommandHandler/SuggestionTooltip.cs create mode 100644 MinecraftClient/Resources/MinecraftAssets.Designer.cs create mode 100644 MinecraftClient/Resources/MinecraftAssets.resx create mode 100644 MinecraftClient/Resources/en_us.json diff --git a/MinecraftClient/ChatBots/AntiAFK.cs b/MinecraftClient/ChatBots/AntiAFK.cs index a6fd308b..bb43045d 100644 --- a/MinecraftClient/ChatBots/AntiAFK.cs +++ b/MinecraftClient/ChatBots/AntiAFK.cs @@ -1,6 +1,4 @@ using System; -using Brigadier.NET; -using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; using MinecraftClient.Scripting; using Tomlet.Attributes; diff --git a/MinecraftClient/ChatBots/AutoAttack.cs b/MinecraftClient/ChatBots/AutoAttack.cs index 771d5769..8cd8ee2f 100644 --- a/MinecraftClient/ChatBots/AutoAttack.cs +++ b/MinecraftClient/ChatBots/AutoAttack.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using Brigadier.NET; -using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; using MinecraftClient.Scripting; using Tomlet.Attributes; diff --git a/MinecraftClient/ChatBots/AutoDig.cs b/MinecraftClient/ChatBots/AutoDig.cs index 8c2180e6..49b9b44e 100644 --- a/MinecraftClient/ChatBots/AutoDig.cs +++ b/MinecraftClient/ChatBots/AutoDig.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Brigadier.NET; using Brigadier.NET.Builder; using MinecraftClient.CommandHandler; using MinecraftClient.CommandHandler.Patch; diff --git a/MinecraftClient/ChatBots/AutoDrop.cs b/MinecraftClient/ChatBots/AutoDrop.cs index 00854a67..7dea2c18 100644 --- a/MinecraftClient/ChatBots/AutoDrop.cs +++ b/MinecraftClient/ChatBots/AutoDrop.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Brigadier.NET; using Brigadier.NET.Builder; using MinecraftClient.CommandHandler; using MinecraftClient.CommandHandler.Patch; diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index 652c7b3f..28886bfd 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Brigadier.NET; using Brigadier.NET.Builder; using MinecraftClient.CommandHandler; using MinecraftClient.CommandHandler.Patch; diff --git a/MinecraftClient/ChatBots/AutoRelog.cs b/MinecraftClient/ChatBots/AutoRelog.cs index 4f461d83..c384eb7c 100644 --- a/MinecraftClient/ChatBots/AutoRelog.cs +++ b/MinecraftClient/ChatBots/AutoRelog.cs @@ -1,6 +1,4 @@ using System; -using Brigadier.NET; -using MinecraftClient.CommandHandler; using MinecraftClient.Scripting; using Tomlet.Attributes; diff --git a/MinecraftClient/ChatBots/AutoRespond.cs b/MinecraftClient/ChatBots/AutoRespond.cs index 823dfa16..3b5a2991 100644 --- a/MinecraftClient/ChatBots/AutoRespond.cs +++ b/MinecraftClient/ChatBots/AutoRespond.cs @@ -4,10 +4,8 @@ using System.Globalization; using System.IO; using System.Text; using System.Text.RegularExpressions; -using Brigadier.NET; using MinecraftClient.CommandHandler; using MinecraftClient.Scripting; -using PInvoke; using Tomlet.Attributes; using static MinecraftClient.Settings; diff --git a/MinecraftClient/ChatBots/DiscordBridge.cs b/MinecraftClient/ChatBots/DiscordBridge.cs index 528805b5..c9aa29a2 100644 --- a/MinecraftClient/ChatBots/DiscordBridge.cs +++ b/MinecraftClient/ChatBots/DiscordBridge.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using Brigadier.NET; using Brigadier.NET.Builder; using DSharpPlus; using DSharpPlus.Entities; diff --git a/MinecraftClient/ChatBots/Mailer.cs b/MinecraftClient/ChatBots/Mailer.cs index 1ca5f034..8ef5c1d1 100644 --- a/MinecraftClient/ChatBots/Mailer.cs +++ b/MinecraftClient/ChatBots/Mailer.cs @@ -5,7 +5,6 @@ using System.IO; using System.Linq; using Brigadier.NET; using Brigadier.NET.Builder; -using MinecraftClient.CommandHandler; using MinecraftClient.CommandHandler.Patch; using MinecraftClient.Scripting; using Tomlet.Attributes; diff --git a/MinecraftClient/ChatBots/ReplayCapture.cs b/MinecraftClient/ChatBots/ReplayCapture.cs index 651431f6..9db42ec2 100644 --- a/MinecraftClient/ChatBots/ReplayCapture.cs +++ b/MinecraftClient/ChatBots/ReplayCapture.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Brigadier.NET; using Brigadier.NET.Builder; using MinecraftClient.CommandHandler; using MinecraftClient.CommandHandler.Patch; diff --git a/MinecraftClient/ChatBots/Script.cs b/MinecraftClient/ChatBots/Script.cs index 194a1f48..8ed7cb42 100644 --- a/MinecraftClient/ChatBots/Script.cs +++ b/MinecraftClient/ChatBots/Script.cs @@ -5,8 +5,6 @@ using System.IO; using System.Reflection; using System.Text; using System.Threading; -using Brigadier.NET; -using MinecraftClient.CommandHandler; using MinecraftClient.Scripting; namespace MinecraftClient.ChatBots diff --git a/MinecraftClient/ChatBots/TelegramBridge.cs b/MinecraftClient/ChatBots/TelegramBridge.cs index f83b60a3..392bc1cf 100644 --- a/MinecraftClient/ChatBots/TelegramBridge.cs +++ b/MinecraftClient/ChatBots/TelegramBridge.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Brigadier.NET; using Brigadier.NET.Builder; using MinecraftClient.CommandHandler; using MinecraftClient.CommandHandler.Patch; diff --git a/MinecraftClient/CommandHandler/ArgumentType/EntityTypeArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/EntityTypeArgumentType.cs index 9ba6f999..fc3ce124 100644 --- a/MinecraftClient/CommandHandler/ArgumentType/EntityTypeArgumentType.cs +++ b/MinecraftClient/CommandHandler/ArgumentType/EntityTypeArgumentType.cs @@ -23,8 +23,27 @@ namespace MinecraftClient.CommandHandler.ArgumentType public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) { - foreach (var result in Enum.GetNames(typeof(EntityType))) - builder.Suggest(result); + foreach (EntityType result in Enum.GetValues()) + { + string name = result.ToString(); + string localName = Entity.GetTypeString(result); + bool same = true; + for (int i = 0, j = 0; i < name.Length; ++i, ++j) + { + while (j < localName.Length && localName[j] == ' ') + ++j; + if (j >= localName.Length || name[i] != localName[j]) + { + same = false; + break; + } + } + if (same) + builder.Suggest(name); + else + builder.Suggest(name, new SuggestionTooltip(localName)); + } + return builder.BuildFuture(); } } diff --git a/MinecraftClient/CommandHandler/ArgumentType/HotbarSlotArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/HotbarSlotArgumentType.cs new file mode 100644 index 00000000..16d07611 --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/HotbarSlotArgumentType.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Suggestion; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class HotbarSlotArgumentType : ArgumentType + { + public override int Parse(IStringReader reader) + { + reader.SkipWhitespace(); + return reader.ReadInt(); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + McClient? client = CmdResult.client; + if (client != null) + { + Inventory.Container? inventory = client.GetInventory(0); + if (inventory != null) + { + for (int i = 1; i <= 9; ++i) + { + if (inventory.Items.TryGetValue(i - 1 + 36, out Inventory.Item? item)) + { + string slotStr = i.ToString(); + if (slotStr.StartsWith(builder.RemainingLowerCase, StringComparison.InvariantCultureIgnoreCase)) + { + string itemDesc = item.Count == 1 ? item.GetTypeString() : string.Format("{0}x{1}", item.Count, item.GetTypeString()); + builder.Suggest(slotStr, new SuggestionTooltip(itemDesc)); + } + } + } + } + } + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs index c697b493..6c7ae2af 100644 --- a/MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs +++ b/MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs @@ -25,7 +25,13 @@ namespace MinecraftClient.CommandHandler.ArgumentType { string invName = inv.Key.ToString(); if (invName.StartsWith(builder.RemainingLowerCase, StringComparison.InvariantCultureIgnoreCase)) - builder.Suggest(invName); + { + string? invTitle = inv.Value.Title; + if (!string.IsNullOrWhiteSpace(invTitle)) + builder.Suggest(invName, new SuggestionTooltip(invTitle)); + else + builder.Suggest(invName); + } } } return builder.BuildFuture(); diff --git a/MinecraftClient/CommandHandler/ArgumentType/InventorySlotArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/InventorySlotArgumentType.cs new file mode 100644 index 00000000..ecc796ca --- /dev/null +++ b/MinecraftClient/CommandHandler/ArgumentType/InventorySlotArgumentType.cs @@ -0,0 +1,55 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Brigadier.NET; +using Brigadier.NET.ArgumentTypes; +using Brigadier.NET.Context; +using Brigadier.NET.Suggestion; + +namespace MinecraftClient.CommandHandler.ArgumentType +{ + public class InventorySlotArgumentType : ArgumentType + { + public override int Parse(IStringReader reader) + { + reader.SkipWhitespace(); + return reader.ReadInt(); + } + + public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) + { + McClient? client = CmdResult.client; + if (client != null && context.Nodes.Count >= 2) + { + string invName = context.Nodes[1].Range.Get(builder.Input); + if (!int.TryParse(invName, out int invId)) + invId = invName switch + { + "creativegive" => 0, + "creativedelete" => 0, + "player" => 0, + "container" => client.GetInventories().Keys.ToList().Max(), + _ => -1, + }; + + Inventory.Container? inventory = client.GetInventory(invId); + if (inventory != null) + { + foreach ((int slot, Inventory.Item item) in inventory.Items) + { + if (item != null && item.Count > 0) + { + string slotStr = slot.ToString(); + if (slotStr.StartsWith(builder.RemainingLowerCase, StringComparison.InvariantCultureIgnoreCase)) + { + string itemDesc = item.Count == 1 ? item.GetTypeString() : string.Format("{0}x{1}", item.Count, item.GetTypeString()); + builder.Suggest(slotStr, new SuggestionTooltip(itemDesc)); + } + } + } + } + } + return builder.BuildFuture(); + } + } +} diff --git a/MinecraftClient/CommandHandler/ArgumentType/ItemTypeArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/ItemTypeArgumentType.cs index 28ab93a3..fcd270bf 100644 --- a/MinecraftClient/CommandHandler/ArgumentType/ItemTypeArgumentType.cs +++ b/MinecraftClient/CommandHandler/ArgumentType/ItemTypeArgumentType.cs @@ -23,8 +23,29 @@ namespace MinecraftClient.CommandHandler.ArgumentType public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) { - foreach (var result in Enum.GetNames(typeof(ItemType))) - builder.Suggest(result); + foreach (ItemType result in Enum.GetValues()) + { + if (result == ItemType.Unknown || result == ItemType.Null) + continue; + + string name = result.ToString(); + string localName = Item.GetTypeString(result); + bool same = true; + for (int i = 0, j = 0; i < name.Length; ++i, ++j) + { + while (j < localName.Length && localName[j] == ' ') + ++j; + if (j >= localName.Length || name[i] != localName[j]) + { + same = false; + break; + } + } + if (same) + builder.Suggest(name); + else + builder.Suggest(name, new SuggestionTooltip(localName)); + } return builder.BuildFuture(); } } diff --git a/MinecraftClient/CommandHandler/MccArguments.cs b/MinecraftClient/CommandHandler/MccArguments.cs index ef6fbf8a..c659ee3e 100644 --- a/MinecraftClient/CommandHandler/MccArguments.cs +++ b/MinecraftClient/CommandHandler/MccArguments.cs @@ -71,6 +71,11 @@ namespace MinecraftClient.CommandHandler return new InventoryActionArgumentType(); } + public static InventorySlotArgumentType InventorySlot() + { + return new InventorySlotArgumentType(); + } + public static Inventory.WindowActionType GetInventoryAction(CommandContext context, string name) { return context.GetArgument(name); @@ -100,5 +105,10 @@ namespace MinecraftClient.CommandHandler { return new MapBotMapIdArgumentType(); } + + public static HotbarSlotArgumentType HotbarSlot() + { + return new HotbarSlotArgumentType(); + } } } diff --git a/MinecraftClient/CommandHandler/Patch/CommandDispatcherExtensions.cs b/MinecraftClient/CommandHandler/Patch/CommandDispatcherExtensions.cs index 341fa4ae..37ef9cc4 100644 --- a/MinecraftClient/CommandHandler/Patch/CommandDispatcherExtensions.cs +++ b/MinecraftClient/CommandHandler/Patch/CommandDispatcherExtensions.cs @@ -18,19 +18,26 @@ namespace MinecraftClient.CommandHandler.Patch public static string GetAllUsageString(this CommandDispatcher commandDispatcher, string commandName, bool restricted) { char cmdChar = Settings.Config.Main.Advanced.InternalCmdChar.ToChar(); - string[] usages = commandDispatcher.GetAllUsage(commandDispatcher.GetRoot().GetChild(commandName), new(), restricted); - StringBuilder sb = new(); - sb.AppendLine("All Usages:"); - foreach (var usage in usages) + try { - sb.Append(cmdChar).Append(commandName).Append(' '); - if (usage.Length > 0 && usage[0] == '_') - sb.AppendLine(usage.Replace("_help -> ", $"_help -> {cmdChar}help ")); - else - sb.AppendLine(usage); + string[] usages = commandDispatcher.GetAllUsage(commandDispatcher.GetRoot().GetChild(commandName), new(), restricted); + StringBuilder sb = new(); + sb.AppendLine("All Usages:"); + foreach (var usage in usages) + { + sb.Append(cmdChar).Append(commandName).Append(' '); + if (usage.Length > 0 && usage[0] == '_') + sb.AppendLine(usage.Replace("_help -> ", $"_help -> {cmdChar}help ")); + else + sb.AppendLine(usage); + } + sb.Remove(sb.Length - 1, 1); + return sb.ToString(); + } + catch + { + return string.Empty; } - sb.Remove(sb.Length - 1, 1); - return sb.ToString(); } } } \ No newline at end of file diff --git a/MinecraftClient/CommandHandler/SuggestionTooltip.cs b/MinecraftClient/CommandHandler/SuggestionTooltip.cs new file mode 100644 index 00000000..c235f061 --- /dev/null +++ b/MinecraftClient/CommandHandler/SuggestionTooltip.cs @@ -0,0 +1,14 @@ +using Brigadier.NET; + +namespace MinecraftClient.CommandHandler +{ + internal class SuggestionTooltip : IMessage + { + public SuggestionTooltip(string tooltip) + { + String = tooltip; + } + + public string String { get; set; } + } +} diff --git a/MinecraftClient/Commands/ChangeSlot.cs b/MinecraftClient/Commands/ChangeSlot.cs index 4a565de8..0353fe1e 100644 --- a/MinecraftClient/Commands/ChangeSlot.cs +++ b/MinecraftClient/Commands/ChangeSlot.cs @@ -20,7 +20,7 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Then(l => l.Argument("Slot", Arguments.Integer(1, 9)) + .Then(l => l.Argument("Slot", MccArguments.HotbarSlot()) .Executes(r => DoChangeSlot(r.Source, handler, Arguments.GetInteger(r, "Slot")))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) diff --git a/MinecraftClient/Commands/Inventory.cs b/MinecraftClient/Commands/Inventory.cs index 2fde9d2d..cc674cc3 100644 --- a/MinecraftClient/Commands/Inventory.cs +++ b/MinecraftClient/Commands/Inventory.cs @@ -44,12 +44,12 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Executes(r => ListAllInventories(r.Source, handler)) .Then(l => l.Literal("creativegive") - .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) .Then(l => l.Argument("ItemType", MccArguments.ItemType()) .Then(l => l.Argument("Count", Arguments.Integer(min: 1)) .Executes(r => DoCreativeGive(r.Source, handler, Arguments.GetInteger(r, "Slot"), MccArguments.GetItemType(r, "ItemType"), Arguments.GetInteger(r, "Count"))))))) .Then(l => l.Literal("creativedelete") - .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) .Executes(r => DoCreativeDelete(r.Source, handler, Arguments.GetInteger(r, "Slot"))))) .Then(l => l.Literal("inventories") .Executes(r => ListAvailableInventories(r.Source, handler))) @@ -64,12 +64,12 @@ namespace MinecraftClient.Commands .Then(l => l.Literal("list") .Executes(r => DoListAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId")))) .Then(l => l.Literal("click") - .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) .Executes(r => DoClickAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) .Then(l => l.Argument("Action", MccArguments.InventoryAction()) .Executes(r => DoClickAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) .Then(l => l.Literal("drop") - .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) .Executes(r => DoDropAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) .Then(l => l.Literal("all") .Executes(r => DoDropAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) @@ -77,12 +77,12 @@ namespace MinecraftClient.Commands .Then(l => l.Literal("list") .Executes(r => DoListAction(r.Source, handler, inventoryId: 0))) .Then(l => l.Literal("click") - .Then(l => l.Argument("Slot", Arguments.Integer(0, 45)) + .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) .Executes(r => DoClickAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) .Then(l => l.Argument("Action", MccArguments.InventoryAction()) .Executes(r => DoClickAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) .Then(l => l.Literal("drop") - .Then(l => l.Argument("Slot", Arguments.Integer(0, 45)) + .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) .Executes(r => DoDropAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) .Then(l => l.Literal("all") .Executes(r => DoDropAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) @@ -92,12 +92,12 @@ namespace MinecraftClient.Commands .Then(l => l.Literal("list") .Executes(r => DoListAction(r.Source, handler, inventoryId: null))) .Then(l => l.Literal("click") - .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) .Executes(r => DoClickAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) .Then(l => l.Argument("Action", MccArguments.InventoryAction()) .Executes(r => DoClickAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) .Then(l => l.Literal("drop") - .Then(l => l.Argument("Slot", Arguments.Integer(0, 89)) + .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) .Executes(r => DoDropAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) .Then(l => l.Literal("all") .Executes(r => DoDropAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) diff --git a/MinecraftClient/Commands/Upgrade.cs b/MinecraftClient/Commands/Upgrade.cs index 227cb995..625b5d5b 100644 --- a/MinecraftClient/Commands/Upgrade.cs +++ b/MinecraftClient/Commands/Upgrade.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using Brigadier.NET; +using Brigadier.NET; using Brigadier.NET.Builder; using MinecraftClient.CommandHandler; @@ -11,7 +10,8 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "upgrade [-f|check|cancel|download]"; } } public override string CmdDesc { get { return string.Empty; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) { + public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) .Executes(r => GetUsage(r.Source, string.Empty)) @@ -41,8 +41,10 @@ namespace MinecraftClient.Commands ); } - private int GetUsage(CmdResult r, string? cmd) { - return r.SetAndReturn(cmd switch { + private int GetUsage(CmdResult r, string? cmd) + { + return r.SetAndReturn(cmd switch + { #pragma warning disable format // @formatter:off "cancel" => GetCmdDescTranslated(), "check" => GetCmdDescTranslated(), diff --git a/MinecraftClient/ConsoleIO.cs b/MinecraftClient/ConsoleIO.cs index 099fb84b..db2f849b 100644 --- a/MinecraftClient/ConsoleIO.cs +++ b/MinecraftClient/ConsoleIO.cs @@ -220,16 +220,19 @@ namespace MinecraftClient string command = fullCommand[offset..]; if (command.Length == 0) { - var childs = CmdResult.client!.dispatcher.GetRoot().Children; - int index = 0; - var sugList = new ConsoleInteractive.ConsoleSuggestion.Suggestion[childs.Count + Commands.Count + 1]; + List sugList = new(); + + sugList.Add(new("/")); + + var childs = CmdResult.client?.dispatcher.GetRoot().Children; + if (childs != null) + foreach (var child in childs) + sugList.Add(new(child.Name)); - sugList[index++] = new("/"); - foreach (var child in childs) - sugList[index++] = new(child.Name); foreach (var cmd in Commands) - sugList[index++] = new(cmd); - ConsoleInteractive.ConsoleSuggestion.UpdateSuggestions(sugList, new(offset, offset)); + sugList.Add(new(cmd)); + + ConsoleInteractive.ConsoleSuggestion.UpdateSuggestions(sugList.ToArray(), new(offset, offset)); } else if (command.Length > 0 && command[0] == '/' && !command.Contains(' ')) { @@ -243,29 +246,37 @@ namespace MinecraftClient } else { - var parse = CmdResult.client!.dispatcher.Parse(command, CmdResult.Empty); + CommandDispatcher? dispatcher = CmdResult.client?.dispatcher; + if (dispatcher == null) + return; - var suggestion = await CmdResult.client!.dispatcher.GetCompletionSuggestions(parse, buffer.CursorPosition - offset); + ParseResults parse = dispatcher.Parse(command, CmdResult.Empty); - int sugLen = suggestion.List.Count; + Brigadier.NET.Suggestion.Suggestions suggestions = await dispatcher.GetCompletionSuggestions(parse, buffer.CursorPosition - offset); + + int sugLen = suggestions.List.Count; if (sugLen == 0) { ConsoleInteractive.ConsoleSuggestion.ClearSuggestions(); return; } + Dictionary dictionary = new(); + foreach (var sug in suggestions.List) + dictionary.Add(sug.Text, sug.Tooltip?.String); + var sugList = new ConsoleInteractive.ConsoleSuggestion.Suggestion[sugLen]; if (cts.IsCancellationRequested) return; - Tuple range = new(suggestion.Range.Start + offset, suggestion.Range.End + offset); - var sorted = Process.ExtractSorted(fullCommand[range.Item1..range.Item2], suggestion.List.Select(_ => _.Text).ToList()); + Tuple range = new(suggestions.Range.Start + offset, suggestions.Range.End + offset); + var sorted = Process.ExtractSorted(fullCommand[range.Item1..range.Item2], dictionary.Keys); if (cts.IsCancellationRequested) return; int index = 0; foreach (var sug in sorted) - sugList[index++] = new(sug.Value); + sugList[index++] = new(sug.Value, dictionary[sug.Value] ?? string.Empty); ConsoleInteractive.ConsoleSuggestion.UpdateSuggestions(sugList, range); } @@ -283,7 +294,8 @@ namespace MinecraftClient public static void AutocompleteHandler(object? sender, ConsoleInteractive.ConsoleReader.Buffer buffer) { - MccAutocompleteHandler(buffer); + if (Settings.Config.Console.CommandSuggestion.Enable) + MccAutocompleteHandler(buffer); } public static void CancelAutocomplete() diff --git a/MinecraftClient/Mapping/Entity.cs b/MinecraftClient/Mapping/Entity.cs index 60364780..ad9fbf7b 100644 --- a/MinecraftClient/Mapping/Entity.cs +++ b/MinecraftClient/Mapping/Entity.cs @@ -156,11 +156,16 @@ namespace MinecraftClient.Mapping Pitch = pitch * (1 / 256) * 360; } - public string GetTypeString() + public static string GetTypeString(EntityType type) { - string typeStr = Type.ToString(); + string typeStr = type.ToString(); string? trans = ChatParser.TranslateString("entity.minecraft." + typeStr.ToUnderscoreCase()); return string.IsNullOrEmpty(trans) ? typeStr : trans; } + + public string GetTypeString() + { + return GetTypeString(Type); + } } } diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index 668d656f..2b38ab50 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -150,7 +150,6 @@ namespace MinecraftClient /// ForgeInfo item stating that Forge is enabled public McClient(SessionToken session, PlayerKeyPair? playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo? forgeInfo) { - dispatcher = new(); CmdResult.client = this; terrainAndMovementsEnabled = Config.Main.Advanced.TerrainAndMovements; inventoryHandlingEnabled = Config.Main.Advanced.InventoryHandling; @@ -1048,9 +1047,10 @@ namespace MinecraftClient if (InvokeRequired) return InvokeOnMainThread(() => GetInventory(inventoryID)); - if (inventories.ContainsKey(inventoryID)) - return inventories[inventoryID]; - return null; + if (inventories.TryGetValue(inventoryID, out Container? inv)) + return inv; + else + return null; } /// diff --git a/MinecraftClient/MinecraftClient.csproj b/MinecraftClient/MinecraftClient.csproj index d824a836..95597b42 100644 --- a/MinecraftClient/MinecraftClient.csproj +++ b/MinecraftClient/MinecraftClient.csproj @@ -85,6 +85,11 @@ True ConfigComments.resx + + True + True + MinecraftAssets.resx + True True @@ -102,6 +107,11 @@ ConfigComments.Designer.cs MinecraftClient + + ResXFileCodeGenerator + MinecraftAssets.Designer.cs + MinecraftClient + ResXFileCodeGenerator Translations.Designer.cs diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index ea6af5eb..cd525fb4 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -692,7 +692,7 @@ namespace MinecraftClient { WriteBackSettings(true); ConsoleInteractive.ConsoleSuggestion.ClearSuggestions(); - ConsoleIO.WriteLineFormatted(string.Format(Translations.config_saving, settingsIniPath)); + ConsoleIO.WriteLineFormatted("§a" + string.Format(Translations.config_saving, settingsIniPath)); if (client != null) { client.Disconnect(); ConsoleIO.Reset(); } if (offlinePrompt != null) { offlinePrompt.Item2.Cancel(); offlinePrompt.Item1.Join(); offlinePrompt = null; ConsoleIO.Reset(); } diff --git a/MinecraftClient/Protocol/Message/ChatParser.cs b/MinecraftClient/Protocol/Message/ChatParser.cs index 55a1999f..3df06572 100644 --- a/MinecraftClient/Protocol/Message/ChatParser.cs +++ b/MinecraftClient/Protocol/Message/ChatParser.cs @@ -1,8 +1,9 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Text; +using System.Text.Json; +using System.Text.RegularExpressions; using System.Threading.Tasks; using static MinecraftClient.Settings; @@ -186,7 +187,7 @@ namespace MinecraftClient.Protocol.Message /// /// Set of translation rules for formatting text /// - private static readonly Dictionary TranslationRules = new(); + private static Dictionary TranslationRules = new(); /// /// Initialize translation rules. @@ -199,90 +200,85 @@ namespace MinecraftClient.Protocol.Message /// private static void InitRules() { - //Small default dictionnary of translation rules - TranslationRules["chat.type.admin"] = "[%s: %s]"; - TranslationRules["chat.type.announcement"] = "§d[%s] %s"; - TranslationRules["chat.type.emote"] = " * %s %s"; - TranslationRules["chat.type.text"] = "<%s> %s"; - TranslationRules["multiplayer.player.joined"] = "§e%s joined the game."; - TranslationRules["multiplayer.player.left"] = "§e%s left the game."; - TranslationRules["commands.message.display.incoming"] = "§7%s whispers to you: %s"; - TranslationRules["commands.message.display.outgoing"] = "§7You whisper to %s: %s"; + if (Config.Main.Advanced.Language == "en_us") + { + TranslationRules = JsonSerializer.Deserialize>((byte[])MinecraftAssets.ResourceManager.GetObject("en_us.json")!)!; + return; + } //Language file in a subfolder, depending on the language setting if (!Directory.Exists("lang")) Directory.CreateDirectory("lang"); - string Language_File = "lang" + Path.DirectorySeparatorChar + Config.Main.Advanced.Language + ".lang"; + string languageFilePath = "lang" + Path.DirectorySeparatorChar + Config.Main.Advanced.Language + ".json"; - //File not found? Try downloading language file from Mojang's servers? - if (!File.Exists(Language_File)) + // Load the external dictionnary of translation rules or display an error message + if (File.Exists(languageFilePath)) { - ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_download, Config.Main.Advanced.Language)); - HttpClient httpClient = new(); try { - Task fetch_index = httpClient.GetStringAsync(TranslationsFile_Website_Index); - fetch_index.Wait(); - string assets_index = fetch_index.Result; - fetch_index.Dispose(); + TranslationRules = JsonSerializer.Deserialize>(File.OpenRead(languageFilePath))!; + } + catch (IOException) { } + catch (JsonException) { } + } - string[] tmp = assets_index.Split(new string[] { "minecraft/lang/" + Config.Main.Advanced.Language.ToLower() + ".json" }, StringSplitOptions.None); - tmp = tmp[1].Split(new string[] { "hash\": \"" }, StringSplitOptions.None); - string hash = tmp[1].Split('"')[0]; //Translations file identifier on Mojang's servers + if (TranslationRules.TryGetValue("Version", out string? version) && version == Settings.TranslationsFile_Version) + { + if (Config.Logging.DebugMessages) + ConsoleIO.WriteLineFormatted(Translations.chat_loaded, acceptnewlines: true); + return; + } + + // Try downloading language file from Mojang's servers? + ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_download, Config.Main.Advanced.Language)); + HttpClient httpClient = new(); + try + { + Task fetch_index = httpClient.GetStringAsync(TranslationsFile_Website_Index); + fetch_index.Wait(); + Match match = Regex.Match(fetch_index.Result, $"minecraft/lang/{Config.Main.Advanced.Language}.json" + @""":\s\{""hash"":\s""([\d\w]{40})"""); + fetch_index.Dispose(); + if (match.Success && match.Groups.Count == 2) + { + string hash = match.Groups[1].Value; string translation_file_location = TranslationsFile_Website_Download + '/' + hash[..2] + '/' + hash; if (Config.Logging.DebugMessages) ConsoleIO.WriteLineFormatted(string.Format(Translations.chat_request, translation_file_location)); - Task fetch_file = httpClient.GetStringAsync(translation_file_location); + Task fetch_file = httpClient.GetStreamAsync(translation_file_location); fetch_file.Wait(); - string translation_file = fetch_file.Result; + TranslationRules = JsonSerializer.Deserialize>(fetch_file.Result)!; fetch_file.Dispose(); - StringBuilder stringBuilder = new(); - foreach (KeyValuePair entry in Json.ParseJson(translation_file).Properties) - stringBuilder.Append(entry.Key).Append('=').Append(entry.Value.StringValue.Replace("\n", "\\n").Replace("\r", string.Empty)).Append(Environment.NewLine); - File.WriteAllText(Language_File, stringBuilder.ToString()); + TranslationRules["Version"] = TranslationsFile_Version; - ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_done, Language_File)); + File.WriteAllText(languageFilePath, JsonSerializer.Serialize(TranslationRules, typeof(Dictionary)), Encoding.UTF8); + + ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_done, languageFilePath)); + + return; } - catch + else { ConsoleIO.WriteLineFormatted("§8" + Translations.chat_fail, acceptnewlines: true); } + } + catch (HttpRequestException) + { + ConsoleIO.WriteLineFormatted("§8" + Translations.chat_fail, acceptnewlines: true); + } + catch (IOException) + { + ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_save_fail, languageFilePath), acceptnewlines: true); + } + finally + { httpClient.Dispose(); } - //Download Failed? Defaulting to en_GB.lang if the game is installed - if (!File.Exists(Language_File) //Try en_GB.lang - && File.Exists(TranslationsFile_FromMCDir)) - { - Language_File = TranslationsFile_FromMCDir; - ConsoleIO.WriteLineFormatted(Translations.chat_from_dir, acceptnewlines: true); - } - - //Load the external dictionnary of translation rules or display an error message - if (File.Exists(Language_File)) - { - foreach (var line in File.ReadLines(Language_File)) - { - if (line.Length > 0) - { - string[] splitted = line.Split('='); - if (splitted.Length == 2) - { - TranslationRules[splitted[0]] = splitted[1]; - } - } - } - - if (Config.Logging.DebugMessages) - ConsoleIO.WriteLineFormatted(Translations.chat_loaded, acceptnewlines: true); - } - else //No external dictionnary found. - { - ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_not_found, Language_File)); - } + TranslationRules = JsonSerializer.Deserialize>((byte[])MinecraftAssets.ResourceManager.GetObject("en_us.json")!)!; + ConsoleIO.WriteLine(Translations.chat_use_default); } public static string? TranslateString(string rulename) diff --git a/MinecraftClient/Protocol/ProxiedWebRequest.cs b/MinecraftClient/Protocol/ProxiedWebRequest.cs index 1e028abb..06e69a9d 100644 --- a/MinecraftClient/Protocol/ProxiedWebRequest.cs +++ b/MinecraftClient/Protocol/ProxiedWebRequest.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; -using System.Linq; using System.Globalization; using System.IO; +using System.Linq; using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; @@ -193,7 +193,7 @@ namespace MinecraftClient.Protocol response.Body = rbody ?? ""; response.StatusCode = statusCode; response.Headers = headers; - + try { stream.Close(); diff --git a/MinecraftClient/Proxy/ProxyHandler.cs b/MinecraftClient/Proxy/ProxyHandler.cs index fca377bd..1cd55e40 100644 --- a/MinecraftClient/Proxy/ProxyHandler.cs +++ b/MinecraftClient/Proxy/ProxyHandler.cs @@ -82,7 +82,7 @@ namespace MinecraftClient.Proxy case Configs.ProxyType.SOCKS5: innerProxytype = ProxyType.Socks5; break; } - if (!string.IsNullOrWhiteSpace(Config.Username)&& !string.IsNullOrWhiteSpace(Config.Password)) + if (!string.IsNullOrWhiteSpace(Config.Username) && !string.IsNullOrWhiteSpace(Config.Password)) proxy = factory.CreateProxyClient(innerProxytype, Config.Server.Host, Config.Server.Port, Config.Username, Config.Password); else proxy = factory.CreateProxyClient(innerProxytype, Config.Server.Host, Config.Server.Port); diff --git a/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs b/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs index 5dd4bfbb..c27a20e8 100644 --- a/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs +++ b/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs @@ -1,1818 +1,1862 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace MinecraftClient { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class ConfigComments { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal ConfigComments() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MinecraftClient.Resources.ConfigComments.ConfigComments", typeof(ConfigComments).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to can be used in some other fields as %yourvar% - ///%username% and %serverip% are reserved variables.. - /// - internal static string AppVars_Variables { - get { - return ResourceManager.GetString("AppVars.Variables", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to =============================== # - /// Minecraft Console Client Bots # - ///=============================== #. - /// - internal static string ChatBot { - get { - return ResourceManager.GetString("ChatBot", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Get alerted when specified words are detected in chat - ///Useful for moderating your server or detecting when someone is talking to you. - /// - internal static string ChatBot_Alerts { - get { - return ResourceManager.GetString("ChatBot.Alerts", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Play a beep sound when a word is detected in addition to highlighting.. - /// - internal static string ChatBot_Alerts_Beep_Enabled { - get { - return ResourceManager.GetString("ChatBot.Alerts.Beep_Enabled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to List of words/strings to NOT alert you on.. - /// - internal static string ChatBot_Alerts_Excludes { - get { - return ResourceManager.GetString("ChatBot.Alerts.Excludes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The name of a file where alers logs will be written.. - /// - internal static string ChatBot_Alerts_Log_File { - get { - return ResourceManager.GetString("ChatBot.Alerts.Log_File", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Log alerts info a file.. - /// - internal static string ChatBot_Alerts_Log_To_File { - get { - return ResourceManager.GetString("ChatBot.Alerts.Log_To_File", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to List of words/strings to alert you on.. - /// - internal static string ChatBot_Alerts_Matches { - get { - return ResourceManager.GetString("ChatBot.Alerts.Matches", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Trigger alerts when it rains and when it stops.. - /// - internal static string ChatBot_Alerts_Trigger_By_Rain { - get { - return ResourceManager.GetString("ChatBot.Alerts.Trigger_By_Rain", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Triggers alerts at the beginning and end of thunderstorms.. - /// - internal static string ChatBot_Alerts_Trigger_By_Thunderstorm { - get { - return ResourceManager.GetString("ChatBot.Alerts.Trigger_By_Thunderstorm", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Triggers an alert after receiving a specified keyword.. - /// - internal static string ChatBot_Alerts_Trigger_By_Words { - get { - return ResourceManager.GetString("ChatBot.Alerts.Trigger_By_Words", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Send a command on a regular or random basis or make the bot walk around randomly to avoid automatic AFK disconnection - ////!\ Make sure your server rules do not forbid anti-AFK mechanisms! - ////!\ Make sure you keep the bot in an enclosure to prevent it wandering off if you're using terrain handling! (Recommended size 5x5x5). - /// - internal static string ChatBot_AntiAfk { - get { - return ResourceManager.GetString("ChatBot.AntiAfk", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Command to send to the server.. - /// - internal static string ChatBot_AntiAfk_Command { - get { - return ResourceManager.GetString("ChatBot.AntiAfk.Command", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The time interval for execution. (in seconds). - /// - internal static string ChatBot_AntiAfk_Delay { - get { - return ResourceManager.GetString("ChatBot.AntiAfk.Delay", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to sneak when sending the command.. - /// - internal static string ChatBot_AntiAfk_Use_Sneak { - get { - return ResourceManager.GetString("ChatBot.AntiAfk.Use_Sneak", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use terrain handling to enable the bot to move around.. - /// - internal static string ChatBot_AntiAfk_Use_Terrain_Handling { - get { - return ResourceManager.GetString("ChatBot.AntiAfk.Use_Terrain_Handling", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The range the bot can move around randomly (Note: the bigger the range, the slower the bot will be). - /// - internal static string ChatBot_AntiAfk_Walk_Range { - get { - return ResourceManager.GetString("ChatBot.AntiAfk.Walk_Range", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to How many times can the bot fail trying to move before using the command method.. - /// - internal static string ChatBot_AntiAfk_Walk_Retries { - get { - return ResourceManager.GetString("ChatBot.AntiAfk.Walk_Retries", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Automatically attack hostile mobs around you - ///You need to enable Entity Handling to use this bot - ////!\ Make sure server rules allow your planned use of AutoAttack - ////!\ SERVER PLUGINS may consider AutoAttack to be a CHEAT MOD and TAKE ACTION AGAINST YOUR ACCOUNT so DOUBLE CHECK WITH SERVER RULES!. - /// - internal static string ChatBot_AutoAttack { - get { - return ResourceManager.GetString("ChatBot.AutoAttack", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Allow attacking hostile mobs.. - /// - internal static string ChatBot_AutoAttack_Attack_Hostile { - get { - return ResourceManager.GetString("ChatBot.AutoAttack.Attack_Hostile", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Allow attacking passive mobs.. - /// - internal static string ChatBot_AutoAttack_Attack_Passive { - get { - return ResourceManager.GetString("ChatBot.AutoAttack.Attack_Passive", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to How long to wait between each attack. Set "Custom = false" to let MCC calculate it.. - /// - internal static string ChatBot_AutoAttack_Cooldown_Time { - get { - return ResourceManager.GetString("ChatBot.AutoAttack.Cooldown_Time", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to All entity types can be found here: https://mccteam.github.io/r/entity/#L15. - /// - internal static string ChatBot_AutoAttack_Entites_List { - get { - return ResourceManager.GetString("ChatBot.AutoAttack.Entites_List", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Possible values: "Interact", "Attack" (default), "InteractAt" (Interact and Attack).. - /// - internal static string ChatBot_AutoAttack_Interaction { - get { - return ResourceManager.GetString("ChatBot.AutoAttack.Interaction", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Wether to treat the entities list as a "whitelist" or as a "blacklist".. - /// - internal static string ChatBot_AutoAttack_List_Mode { - get { - return ResourceManager.GetString("ChatBot.AutoAttack.List_Mode", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to "single" or "multi". single target one mob per attack. multi target all mobs in range per attack. - /// - internal static string ChatBot_AutoAttack_Mode { - get { - return ResourceManager.GetString("ChatBot.AutoAttack.Mode", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to "health" or "distance". Only needed when using single mode. - /// - internal static string ChatBot_AutoAttack_Priority { - get { - return ResourceManager.GetString("ChatBot.AutoAttack.Priority", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Automatically craft items in your inventory - ///See https://mccteam.github.io/g/bots/#auto-craft for how to use - ///You need to enable Inventory Handling to use this bot - ///You should also enable Terrain and Movements if you need to use a crafting table. - /// - internal static string ChatBot_AutoCraft { - get { - return ResourceManager.GetString("ChatBot.AutoCraft", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Location of the crafting table if you intended to use it. Terrain and movements must be enabled.. - /// - internal static string ChatBot_AutoCraft_CraftingTable { - get { - return ResourceManager.GetString("ChatBot.AutoCraft.CraftingTable", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to What to do on crafting failure, "abort" or "wait".. - /// - internal static string ChatBot_AutoCraft_OnFailure { - get { - return ResourceManager.GetString("ChatBot.AutoCraft.OnFailure", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Recipes.Name: The name can be whatever you like and it is used to represent the recipe. - ///Recipes.Type: crafting table type: "player" or "table" - ///Recipes.Result: the resulting item - ///Recipes.Slots: All slots, counting from left to right, top to bottom. Please fill in "Null" for empty slots. - ///For the naming of the items, please see: https://mccteam.github.io/r/item/#L12. - /// - internal static string ChatBot_AutoCraft_Recipes { - get { - return ResourceManager.GetString("ChatBot.AutoCraft.Recipes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Auto-digging blocks. - ///You need to enable Terrain Handling to use this bot - ///You can use "/digbot start" and "/digbot stop" to control the start and stop of AutoDig. - ///Since MCC does not yet support accurate calculation of the collision volume of blocks, all blocks are considered as complete cubes when obtaining the position of the lookahead. - ///For the naming of the block, please see https://mccteam.github.io/r/block/#L15. - /// - internal static string ChatBot_AutoDig { - get { - return ResourceManager.GetString("ChatBot.AutoDig", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to How many seconds to wait after entering the game to start digging automatically, set to -1 to disable automatic start.. - /// - internal static string ChatBot_AutoDig_Auto_Start_Delay { - get { - return ResourceManager.GetString("ChatBot.AutoDig.Auto_Start_Delay", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Automatically switch to the appropriate tool.. - /// - internal static string ChatBot_AutoDig_Auto_Tool_Switch { - get { - return ResourceManager.GetString("ChatBot.AutoDig.Auto_Tool_Switch", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Mining a block for more than "Dig_Timeout" seconds will be considered a timeout.. - /// - internal static string ChatBot_AutoDig_Dig_Timeout { - get { - return ResourceManager.GetString("ChatBot.AutoDig.Dig_Timeout", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to drop the current tool when its durability is too low.. - /// - internal static string ChatBot_AutoDig_Drop_Low_Durability_Tools { - get { - return ResourceManager.GetString("ChatBot.AutoDig.Drop_Low_Durability_Tools", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Will not use tools with less durability than this. Set to zero to disable this feature.. - /// - internal static string ChatBot_AutoDig_Durability_Limit { - get { - return ResourceManager.GetString("ChatBot.AutoDig.Durability_Limit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Wether to treat the blocks list as a "whitelist" or as a "blacklist".. - /// - internal static string ChatBot_AutoDig_List_Type { - get { - return ResourceManager.GetString("ChatBot.AutoDig.List_Type", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to "distance" or "index", When using the "fixedpos" mode, the blocks are determined by distance to the player, or by the order in the list.. - /// - internal static string ChatBot_AutoDig_Location_Order { - get { - return ResourceManager.GetString("ChatBot.AutoDig.Location_Order", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The position of the blocks when using "fixedpos" or "both" mode.. - /// - internal static string ChatBot_AutoDig_Locations { - get { - return ResourceManager.GetString("ChatBot.AutoDig.Locations", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to output logs when digging blocks.. - /// - internal static string ChatBot_AutoDig_Log_Block_Dig { - get { - return ResourceManager.GetString("ChatBot.AutoDig.Log_Block_Dig", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to "lookat", "fixedpos" or "both". Digging the block being looked at, the block in a fixed position, or the block that needs to be all met.. - /// - internal static string ChatBot_AutoDig_Mode { - get { - return ResourceManager.GetString("ChatBot.AutoDig.Mode", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Automatically drop items in inventory - ///You need to enable Inventory Handling to use this bot - ///See this file for an up-to-date list of item types you can use with this bot: https://mccteam.github.io/r/item/#L12. - /// - internal static string ChatBot_AutoDrop { - get { - return ResourceManager.GetString("ChatBot.AutoDrop", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to "include", "exclude" or "everything". Include: drop item IN the list. Exclude: drop item NOT IN the list. - /// - internal static string ChatBot_AutoDrop_Mode { - get { - return ResourceManager.GetString("ChatBot.AutoDrop.Mode", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Automatically eat food when your Hunger value is low - ///You need to enable Inventory Handling to use this bot. - /// - internal static string ChatBot_AutoEat { - get { - return ResourceManager.GetString("ChatBot.AutoEat", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Automatically catch fish using a fishing rod - ///Guide: https://mccteam.github.io/g/bots/#auto-fishing - ///You can use "/fish" to control the bot manually. - ////!\ Make sure server rules allow automated farming before using this bot. - /// - internal static string ChatBot_AutoFishing { - get { - return ResourceManager.GetString("ChatBot.AutoFishing", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Keep it as false if you have not changed it before.. - /// - internal static string ChatBot_AutoFishing_Antidespawn { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Antidespawn", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Switch to a new rod from inventory after the current rod is unavailable.. - /// - internal static string ChatBot_AutoFishing_Auto_Rod_Switch { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Auto_Rod_Switch", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to start fishing automatically after entering a world.. - /// - internal static string ChatBot_AutoFishing_Auto_Start { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Auto_Start", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to How soon to re-cast after successful fishing.. - /// - internal static string ChatBot_AutoFishing_Cast_Delay { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Cast_Delay", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Will not use rods with less durability than this (full durability is 64). Set to zero to disable this feature.. - /// - internal static string ChatBot_AutoFishing_Durability_Limit { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Durability_Limit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This allows the player to change position/facing after each fish caught.. - /// - internal static string ChatBot_AutoFishing_Enable_Move { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Enable_Move", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to How long after entering the game to start fishing (seconds).. - /// - internal static string ChatBot_AutoFishing_Fishing_Delay { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Fishing_Delay", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Fishing timeout (seconds). Timeout will trigger a re-cast.. - /// - internal static string ChatBot_AutoFishing_Fishing_Timeout { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Fishing_Timeout", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to A "stationary" hook that moves above this threshold in the Y-axis will be considered to have caught a fish.. - /// - internal static string ChatBot_AutoFishing_Hook_Threshold { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Hook_Threshold", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Used to adjust the above two thresholds, which when enabled will print the change in the position of the fishhook entity upon receipt of its movement packet.. - /// - internal static string ChatBot_AutoFishing_Log_Fish_Bobber { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Log_Fish_Bobber", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use the mainhand or the offhand to hold the rod.. - /// - internal static string ChatBot_AutoFishing_Mainhand { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Mainhand", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It will move in order "1->2->3->4->3->2->1->2->..." and can change position or facing or both each time. It is recommended to change the facing only.. - /// - internal static string ChatBot_AutoFishing_Movements { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Movements", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Hook movement in the X and Z axis less than this value will be considered stationary.. - /// - internal static string ChatBot_AutoFishing_Stationary_Threshold { - get { - return ResourceManager.GetString("ChatBot.AutoFishing.Stationary_Threshold", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Automatically relog when disconnected by server, for example because the server is restating - ////!\ Use Ignore_Kick_Message=true at own risk! Server staff might not appreciate if you auto-relog on manual kicks. - /// - internal static string ChatBot_AutoRelog { - get { - return ResourceManager.GetString("ChatBot.AutoRelog", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The delay time before joining the server. (in seconds). - /// - internal static string ChatBot_AutoRelog_Delay { - get { - return ResourceManager.GetString("ChatBot.AutoRelog.Delay", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to When set to true, autorelog will reconnect regardless of kick messages.. - /// - internal static string ChatBot_AutoRelog_Ignore_Kick_Message { - get { - return ResourceManager.GetString("ChatBot.AutoRelog.Ignore_Kick_Message", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to If the kickout message matches any of the strings, then autorelog will be triggered.. - /// - internal static string ChatBot_AutoRelog_Kick_Messages { - get { - return ResourceManager.GetString("ChatBot.AutoRelog.Kick_Messages", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Retries when failing to relog to the server. use -1 for unlimited retries.. - /// - internal static string ChatBot_AutoRelog_Retries { - get { - return ResourceManager.GetString("ChatBot.AutoRelog.Retries", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Run commands or send messages automatically when a specified pattern is detected in chat - ///Server admins can spoof chat messages (/nick, /tellraw) so keep this in mind when implementing AutoRespond rules - ////!\ This bot may get spammy depending on your rules, although the global messagecooldown setting can help you avoiding accidental spam. - /// - internal static string ChatBot_AutoRespond { - get { - return ResourceManager.GetString("ChatBot.AutoRespond", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Do not remove colors from text (Note: Your matches will have to include color codes (ones using the § character) in order to work). - /// - internal static string ChatBot_AutoRespond_Match_Colors { - get { - return ResourceManager.GetString("ChatBot.AutoRespond.Match_Colors", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Logs chat messages in a file on disk.. - /// - internal static string ChatBot_ChatLog { - get { - return ResourceManager.GetString("ChatBot.ChatLog", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This bot allows you to send and recieve messages and commands via a Discord channel. - ///For Setup you can either use the documentation or read here (Documentation has images). - ///Documentation: https://mccteam.github.io/g/bots/#discord-bridge - ///Setup: - ///First you need to create a Bot on the Discord Developers Portal, here is a video tutorial: https://www.youtube.com/watch?v=2FgMnZViNPA . - ////!\ IMPORTANT /!\: When creating a bot, you MUST ENABLE "Message Content Intent", "Server Members Intent" and "Presence Intent [rest of string was truncated]";. - /// - internal static string ChatBot_DiscordBridge { - get { - return ResourceManager.GetString("ChatBot.DiscordBridge", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The ID of a channel where you want to interact with the MCC using the bot.. - /// - internal static string ChatBot_DiscordBridge_ChannelId { - get { - return ResourceManager.GetString("ChatBot.DiscordBridge.ChannelId", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Message formats - ///Words wrapped with { and } are going to be replaced during the code execution, do not change them! - ///For example. {message} is going to be replace with an actual message, {username} will be replaced with an username, {timestamp} with the current time. - ///For Discord message formatting, check the following: https://mccteam.github.io/r/dc-fmt.html. - /// - internal static string ChatBot_DiscordBridge_Formats { - get { - return ResourceManager.GetString("ChatBot.DiscordBridge.Formats", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The ID of a server/guild where you have invited the bot to.. - /// - internal static string ChatBot_DiscordBridge_GuildId { - get { - return ResourceManager.GetString("ChatBot.DiscordBridge.GuildId", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to How long to wait (in seconds) if a message can not be sent to discord before canceling the task (minimum 1 second).. - /// - internal static string ChatBot_DiscordBridge_MessageSendTimeout { - get { - return ResourceManager.GetString("ChatBot.DiscordBridge.MessageSendTimeout", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to A list of IDs of people you want to be able to interact with the MCC using the bot.. - /// - internal static string ChatBot_DiscordBridge_OwnersIds { - get { - return ResourceManager.GetString("ChatBot.DiscordBridge.OwnersIds", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your Discord Bot token.. - /// - internal static string ChatBot_DiscordBridge_Token { - get { - return ResourceManager.GetString("ChatBot.DiscordBridge.Token", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Automatically farms crops for you (plants, breaks and bonemeals them). - ///Crop types available: Beetroot, Carrot, Melon, Netherwart, Pumpkin, Potato, Wheat. - ///Usage: "/farmer start" command and "/farmer stop" command. - ///NOTE: This a newly added bot, it is not perfect and was only tested in 1.19.2, there are some minor issues like not being able to bonemeal carrots/potatoes sometimes. - ///or bot jumps onto the farm land and breaks it (this happens rarely but still happens). We are looking forward at improving this. [rest of string was truncated]";. - /// - internal static string ChatBot_Farmer { - get { - return ResourceManager.GetString("ChatBot.Farmer", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delay between tasks in seconds (Minimum 1 second). - /// - internal static string ChatBot_Farmer_Delay_Between_Tasks { - get { - return ResourceManager.GetString("ChatBot.Farmer.Delay_Between_Tasks", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Enabled you to make the bot follow you - ///NOTE: This is an experimental feature, the bot can be slow at times, you need to walk with a normal speed and to sometimes stop for it to be able to keep up with you - ///It's similar to making animals follow you when you're holding food in your hand. - ///This is due to a slow pathfinding algorithm, we're working on getting a better one - ///You can tweak the update limit and find what works best for you. (NOTE: Do not but a very low one, because you might achieve the opposite, - /// [rest of string was truncated]";. - /// - internal static string ChatBot_FollowPlayer { - get { - return ResourceManager.GetString("ChatBot.FollowPlayer", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Do not follow the player if he is in the range of 3 blocks (prevents the bot from pushing a player in an infinite loop). - /// - internal static string ChatBot_FollowPlayer_Stop_At_Distance { - get { - return ResourceManager.GetString("ChatBot.FollowPlayer.Stop_At_Distance", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The rate at which the bot does calculations (in seconds) (You can tweak this if you feel the bot is too slow). - /// - internal static string ChatBot_FollowPlayer_Update_Limit { - get { - return ResourceManager.GetString("ChatBot.FollowPlayer.Update_Limit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to A small game to demonstrate chat interactions. Players can guess mystery words one letter at a time. - ///You need to have ChatFormat working correctly and add yourself in botowners to start the game with /tell <bot username> start - ////!\ This bot may get a bit spammy if many players are interacting with it. - /// - internal static string ChatBot_HangmanGame { - get { - return ResourceManager.GetString("ChatBot.HangmanGame", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Relay messages between players and servers, like a mail plugin - ///This bot can store messages when the recipients are offline, and send them when they join the server - ////!\ Server admins can spoof PMs (/tellraw, /nick) so enable this bot only if you trust server admins. - /// - internal static string ChatBot_Mailer { - get { - return ResourceManager.GetString("ChatBot.Mailer", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Allows you to render maps in the console and into images (which can be then sent to Discord using Discord Bridge Chat Bot) - ///This is useful for solving captchas which use maps - ///The maps are rendered into Rendered_Maps folder if the Save_To_File is enabled. - ///NOTE: - ///If some servers have a very short time for solving captchas, enabe Auto_Render_On_Update to see them immediatelly in the console. - ////!\ Make sure server rules allow bots to be used on the server, or you risk being punished.. - /// - internal static string ChatBot_Map { - get { - return ResourceManager.GetString("ChatBot.Map", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Automatically render the map once it is received or updated from/by the server. - /// - internal static string ChatBot_Map_Auto_Render_On_Update { - get { - return ResourceManager.GetString("ChatBot.Map.Auto_Render_On_Update", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete all rendered maps on unload/reload or when you launch the MCC again.. - /// - internal static string ChatBot_Map_Delete_All_On_Unload { - get { - return ResourceManager.GetString("ChatBot.Map.Delete_All_On_Unload", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Get a notification when you have gotten a map from the server for the first time. - /// - internal static string ChatBot_Map_Notify_On_First_Update { - get { - return ResourceManager.GetString("ChatBot.Map.Notify_On_First_Update", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Resize an rendered image, this is useful when images that are rendered are small and when are being sent to Discord.. - /// - internal static string ChatBot_Map_Rasize_Rendered_Image { - get { - return ResourceManager.GetString("ChatBot.Map.Rasize_Rendered_Image", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to render the map in the console.. - /// - internal static string ChatBot_Map_Render_In_Console { - get { - return ResourceManager.GetString("ChatBot.Map.Render_In_Console", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The size that a rendered image should be resized to, in pixels (eg. 512).. - /// - internal static string ChatBot_Map_Resize_To { - get { - return ResourceManager.GetString("ChatBot.Map.Resize_To", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to store the rendered map as a file (You need this setting if you want to get a map on Discord using Discord Bridge).. - /// - internal static string ChatBot_Map_Save_To_File { - get { - return ResourceManager.GetString("ChatBot.Map.Save_To_File", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Send a rendered map (saved to a file) to a Discord or a Telegram channel via the Discord or Telegram Bride chat bot (The Discord/Telegram Bridge chat bot must be enabled and configured!) - ///You need to enable Save_To_File in order for this to work. - ///We also recommend turning on resizing.. - /// - internal static string ChatBot_Map_Send_Rendered_To_Bridges { - get { - return ResourceManager.GetString("ChatBot.Map.Send_Rendered_To_Bridges", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Log the list of players periodically into a textual file.. - /// - internal static string ChatBot_PlayerListLogger { - get { - return ResourceManager.GetString("ChatBot.PlayerListLogger", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to (In seconds). - /// - internal static string ChatBot_PlayerListLogger_Delay { - get { - return ResourceManager.GetString("ChatBot.PlayerListLogger.Delay", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Send MCC console commands to your bot through server PMs (/tell) - ///You need to have ChatFormat working correctly and add yourself in botowners to use the bot - ////!\ Server admins can spoof PMs (/tellraw, /nick) so enable RemoteControl only if you trust server admins. - /// - internal static string ChatBot_RemoteControl { - get { - return ResourceManager.GetString("ChatBot.RemoteControl", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Enable recording of the game (/replay start) and replay it later using the Replay Mod (https://www.replaymod.com/) - ///Please note that due to technical limitations, the client player (you) will not be shown in the replay file - ////!\ You SHOULD use /replay stop or exit the program gracefully with /quit OR THE REPLAY FILE MAY GET CORRUPT!. - /// - internal static string ChatBot_ReplayCapture { - get { - return ResourceManager.GetString("ChatBot.ReplayCapture", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to How long should replay file be auto-saved, in seconds. Use -1 to disable.. - /// - internal static string ChatBot_ReplayCapture_Backup_Interval { - get { - return ResourceManager.GetString("ChatBot.ReplayCapture.Backup_Interval", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Schedule commands and scripts to launch on various events such as server join, date/time or time interval - ///See https://mccteam.github.io/g/bots/#script-scheduler for more info. - /// - internal static string ChatBot_ScriptScheduler { - get { - return ResourceManager.GetString("ChatBot.ScriptScheduler", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This bot allows you to send and receive messages and commands via a Telegram Bot DM or to receive messages in a Telegram channel. - ////!\ NOTE: You can't send messages and commands from a group channel, you can only send them in the bot DM, but you can get the messages from the client in a group channel. - ///----------------------------------------------------------- - ///Setup: - ///First you need to create a Telegram bot and obtain an API key, to do so, go to Telegram and find @botfather - ///Click on "Start" button and re [rest of string was truncated]";. - /// - internal static string ChatBot_TelegramBridge { - get { - return ResourceManager.GetString("ChatBot.TelegramBridge", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to A list of Chat IDs that are allowed to send messages and execute commands. To get an id of your chat DM with the bot use ".chatid" bot command in Telegram.. - /// - internal static string ChatBot_TelegramBridge_Authorized_Chat_Ids { - get { - return ResourceManager.GetString("ChatBot.TelegramBridge.Authorized_Chat_Ids", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An ID of a channel where you want to interact with the MCC using the bot.. - /// - internal static string ChatBot_TelegramBridge_ChannelId { - get { - return ResourceManager.GetString("ChatBot.TelegramBridge.ChannelId", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Message formats - ///Words wrapped with { and } are going to be replaced during the code execution, do not change them! - ///For example. {message} is going to be replace with an actual message, {username} will be replaced with an username, {timestamp} with the current time. - ///For Telegram message formatting, check the following: https://mccteam.github.io/r/tg-fmt.html. - /// - internal static string ChatBot_TelegramBridge_Formats { - get { - return ResourceManager.GetString("ChatBot.TelegramBridge.Formats", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to How long to wait (in seconds) if a message can not be sent to Telegram before canceling the task (minimum 1 second).. - /// - internal static string ChatBot_TelegramBridge_MessageSendTimeout { - get { - return ResourceManager.GetString("ChatBot.TelegramBridge.MessageSendTimeout", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your Telegram Bot token.. - /// - internal static string ChatBot_TelegramBridge_Token { - get { - return ResourceManager.GetString("ChatBot.TelegramBridge.Token", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MCC does it best to detect chat messages, but some server have unusual chat formats - ///When this happens, you'll need to configure chat format below, see https://mccteam.github.io/g/conf/#chat-format-section. - /// - internal static string ChatFormat { - get { - return ResourceManager.GetString("ChatFormat", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MCC support for common message formats. Set "false" to avoid conflicts with custom formats.. - /// - internal static string ChatFormat_Builtins { - get { - return ResourceManager.GetString("ChatFormat.Builtins", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to use the custom regular expressions below for detection.. - /// - internal static string ChatFormat_UserDefined { - get { - return ResourceManager.GetString("ChatFormat.UserDefined", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Startup Config File - ///Please do not record extraneous data in this file as it will be overwritten by MCC. - /// - ///New to Minecraft Console Client? Check out this document: https://mccteam.github.io/g/conf.html - ///Want to upgrade to a newer version? See https://github.com/MCCTeam/Minecraft-Console-Client/#download. - /// - internal static string Head { - get { - return ResourceManager.GetString("Head", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This setting affects only the messages in the console.. - /// - internal static string Logging { - get { - return ResourceManager.GetString("Logging", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Regex for filtering chat message.. - /// - internal static string Logging_ChatFilter { - get { - return ResourceManager.GetString("Logging.ChatFilter", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Show server chat messages.. - /// - internal static string Logging_ChatMessages { - get { - return ResourceManager.GetString("Logging.ChatMessages", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Regex for filtering debug message.. - /// - internal static string Logging_DebugFilter { - get { - return ResourceManager.GetString("Logging.DebugFilter", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Please enable this before submitting bug reports. Thanks!. - /// - internal static string Logging_DebugMessages { - get { - return ResourceManager.GetString("Logging.DebugMessages", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Show error messages.. - /// - internal static string Logging_ErrorMessages { - get { - return ResourceManager.GetString("Logging.ErrorMessages", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to "disable" or "blacklist" OR "whitelist". Blacklist hide message match regex. Whitelist show message match regex.. - /// - internal static string Logging_FilterMode { - get { - return ResourceManager.GetString("Logging.FilterMode", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Informative messages. (i.e Most of the message from MCC). - /// - internal static string Logging_InfoMessages { - get { - return ResourceManager.GetString("Logging.InfoMessages", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Log file name.. - /// - internal static string Logging_LogFile { - get { - return ResourceManager.GetString("Logging.LogFile", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Write log messages to file.. - /// - internal static string Logging_LogToFile { - get { - return ResourceManager.GetString("Logging.LogToFile", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Prepend timestamp to messages in log file.. - /// - internal static string Logging_PrependTimestamp { - get { - return ResourceManager.GetString("Logging.PrependTimestamp", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Keep color codes in the saved text.(look like "§b"). - /// - internal static string Logging_SaveColorCodes { - get { - return ResourceManager.GetString("Logging.SaveColorCodes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Show warning messages.. - /// - internal static string Logging_WarningMessages { - get { - return ResourceManager.GetString("Logging.WarningMessages", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Make sure you understand what each setting does before changing anything!. - /// - internal static string Main_Advanced { - get { - return ResourceManager.GetString("Main.Advanced", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to AccountList: It allows a fast account switching without directly using the credentials - ///Usage examples: "/tell <mybot> reco Player2", "/connect <serverip> Player1". - /// - internal static string Main_Advanced_account_list { - get { - return ResourceManager.GetString("Main.Advanced.account_list", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Toggle auto respawn if client player was dead (make sure your spawn point is safe).. - /// - internal static string Main_Advanced_auto_respawn { - get { - return ResourceManager.GetString("Main.Advanced.auto_respawn", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Set the owner of the bot. /!\ Server admins can impersonate owners!. - /// - internal static string Main_Advanced_bot_owners { - get { - return ResourceManager.GetString("Main.Advanced.bot_owners", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use "mcc", "vanilla" or "none". This is how MCC identifies itself to the server.. - /// - internal static string Main_Advanced_brand_info { - get { - return ResourceManager.GetString("Main.Advanced.brand_info", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Leave empty for no logfile.. - /// - internal static string Main_Advanced_chatbot_log_file { - get { - return ResourceManager.GetString("Main.Advanced.chatbot_log_file", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to If turned off, the emoji will be replaced with a simpler character (for /chunk status).. - /// - internal static string Main_Advanced_enable_emoji { - get { - return ResourceManager.GetString("Main.Advanced.enable_emoji", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Toggle entity handling.. - /// - internal static string Main_Advanced_entity_handling { - get { - return ResourceManager.GetString("Main.Advanced.entity_handling", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to exit directly when an error occurs, for using MCC in non-interactive scripts.. - /// - internal static string Main_Advanced_exit_on_failure { - get { - return ResourceManager.GetString("Main.Advanced.exit_on_failure", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use "none", "slash"(/) or "backslash"(\).. - /// - internal static string Main_Advanced_internal_cmd_char { - get { - return ResourceManager.GetString("Main.Advanced.internal_cmd_char", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Toggle inventory handling.. - /// - internal static string Main_Advanced_inventory_handling { - get { - return ResourceManager.GetString("Main.Advanced.inventory_handling", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Fill in with in-game locale code, check https://mccteam.github.io/r/l-code.html. - /// - internal static string Main_Advanced_language { - get { - return ResourceManager.GetString("Main.Advanced.language", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Load translations applied to MCC when available, turn it off to use English only.. - /// - internal static string Main_Advanced_LoadMccTrans { - get { - return ResourceManager.GetString("Main.Advanced.LoadMccTrans", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use "auto", "no" or "force". Force-enabling only works for MC 1.13+.. - /// - internal static string Main_Advanced_mc_forge { - get { - return ResourceManager.GetString("Main.Advanced.mc_forge", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use "auto" or "1.X.X" values. Allows to skip server info retrieval.. - /// - internal static string Main_Advanced_mc_version { - get { - return ResourceManager.GetString("Main.Advanced.mc_version", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Controls the minimum interval (in seconds) between sending each message to the server.. - /// - internal static string Main_Advanced_message_cooldown { - get { - return ResourceManager.GetString("Main.Advanced.message_cooldown", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Enable support for joining Minecraft Realms worlds.. - /// - internal static string Main_Advanced_minecraft_realms { - get { - return ResourceManager.GetString("Main.Advanced.minecraft_realms", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The minimum height to use when calculating the image size from the height of the terminal.. - /// - internal static string Main_Advanced_MinTerminalHeight { - get { - return ResourceManager.GetString("Main.Advanced.MinTerminalHeight", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The minimum width used when calculating the image size from the width of the terminal.. - /// - internal static string Main_Advanced_MinTerminalWidth { - get { - return ResourceManager.GetString("Main.Advanced.MinTerminalWidth", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Enable head movement while walking to avoid anti-cheat triggers.. - /// - internal static string Main_Advanced_move_head_while_walking { - get { - return ResourceManager.GetString("Main.Advanced.move_head_while_walking", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to A movement speed higher than 2 may be considered cheating.. - /// - internal static string Main_Advanced_movement_speed { - get { - return ResourceManager.GetString("Main.Advanced.movement_speed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Only works on Windows XP-8 or Windows 10 with old console.. - /// - internal static string Main_Advanced_player_head_icon { - get { - return ResourceManager.GetString("Main.Advanced.player_head_icon", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to For remote control of the bot.. - /// - internal static string Main_Advanced_private_msgs_cmd_name { - get { - return ResourceManager.GetString("Main.Advanced.private_msgs_cmd_name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to How to retain profile key. Use "none", "memory" or "disk".. - /// - internal static string Main_Advanced_profilekey_cache { - get { - return ResourceManager.GetString("Main.Advanced.profilekey_cache", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use "no", "fast" (5s timeout), or "yes". Required for joining some servers.. - /// - internal static string Main_Advanced_resolve_srv_records { - get { - return ResourceManager.GetString("Main.Advanced.resolve_srv_records", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cache compiled scripts for faster load on low-end devices.. - /// - internal static string Main_Advanced_script_cache { - get { - return ResourceManager.GetString("Main.Advanced.script_cache", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to ServerList: It allows an easier and faster server switching with short aliases instead of full server IP - ///Aliases cannot contain dots or spaces, and the name "localhost" cannot be used as an alias. - ///Usage examples: "/tell <mybot> connect Server1", "/connect Server2". - /// - internal static string Main_Advanced_server_list { - get { - return ResourceManager.GetString("Main.Advanced.server_list", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to How to retain session tokens. Use "none", "memory" or "disk".. - /// - internal static string Main_Advanced_session_cache { - get { - return ResourceManager.GetString("Main.Advanced.session_cache", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Decode links embedded in chat messages and show them in console.. - /// - internal static string Main_Advanced_show_chat_links { - get { - return ResourceManager.GetString("Main.Advanced.show_chat_links", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Show inventory layout as ASCII art in inventory command.. - /// - internal static string Main_Advanced_show_inventory_layout { - get { - return ResourceManager.GetString("Main.Advanced.show_inventory_layout", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to System messages for server ops.. - /// - internal static string Main_Advanced_show_system_messages { - get { - return ResourceManager.GetString("Main.Advanced.show_system_messages", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Messages displayed above xp bar, set this to false in case of xp bar spam.. - /// - internal static string Main_Advanced_show_xpbar_messages { - get { - return ResourceManager.GetString("Main.Advanced.show_xpbar_messages", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Temporary fix for Badpacket issue on some servers.. - /// - internal static string Main_Advanced_temporary_fix_badpacket { - get { - return ResourceManager.GetString("Main.Advanced.temporary_fix_badpacket", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use "none", "bit_4", "bit_8" or "bit_24". This can be checked by opening the debug log.. - /// - internal static string Main_Advanced_TerminalColorDepth { - get { - return ResourceManager.GetString("Main.Advanced.TerminalColorDepth", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Uses more ram, cpu, bandwidth but allows you to move around.. - /// - internal static string Main_Advanced_terrain_and_movements { - get { - return ResourceManager.GetString("Main.Advanced.terrain_and_movements", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Customize the TCP connection timeout with the server. (in seconds). - /// - internal static string Main_Advanced_timeout { - get { - return ResourceManager.GetString("Main.Advanced.timeout", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Prepend timestamps to chat messages.. - /// - internal static string Main_Advanced_timestamps { - get { - return ResourceManager.GetString("Main.Advanced.timestamps", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Login=Email or Name. Use "-" as password for offline mode. Leave blank to prompt user on startup.. - /// - internal static string Main_General_account { - get { - return ResourceManager.GetString("Main.General.account", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The address of the game server, "Host" can be filled in with domain name or IP address. (The "Port" field can be deleted, it will be resolved automatically). - /// - internal static string Main_General_login { - get { - return ResourceManager.GetString("Main.General.login", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Microsoft Account sign-in method: "mcc" OR "browser". If the login always fails, please try to use the "browser" once.. - /// - internal static string Main_General_method { - get { - return ResourceManager.GetString("Main.General.method", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Account type: "mojang" OR "microsoft". Also affects interactive login in console.. - /// - internal static string Main_General_server_info { - get { - return ResourceManager.GetString("Main.General.server_info", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Settings below are sent to the server and only affect server-side things like your skin.. - /// - internal static string MCSettings { - get { - return ResourceManager.GetString("MCSettings", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Allows disabling chat colors server-side.. - /// - internal static string MCSettings_ChatColors { - get { - return ResourceManager.GetString("MCSettings.ChatColors", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use "enabled", "commands", or "disabled". Allows to mute yourself.... - /// - internal static string MCSettings_ChatMode { - get { - return ResourceManager.GetString("MCSettings.ChatMode", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MC 1.7- difficulty. "peaceful", "easy", "normal", "difficult".. - /// - internal static string MCSettings_Difficulty { - get { - return ResourceManager.GetString("MCSettings.Difficulty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to If disabled, settings below are not sent to the server.. - /// - internal static string MCSettings_Enabled { - get { - return ResourceManager.GetString("MCSettings.Enabled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use any language implemented in Minecraft.. - /// - internal static string MCSettings_Locale { - get { - return ResourceManager.GetString("MCSettings.Locale", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MC 1.9+ main hand. "left" or "right".. - /// - internal static string MCSettings_MainHand { - get { - return ResourceManager.GetString("MCSettings.MainHand", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Value range: [0 - 255].. - /// - internal static string MCSettings_RenderDistance { - get { - return ResourceManager.GetString("MCSettings.RenderDistance", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Connect to a server via a proxy instead of connecting directly - ///If Mojang session services are blocked on your network, set Enabled_Login=true to login using proxy. - ///If the connection to the Minecraft game server is blocked by the firewall, set Enabled_Ingame=true to use a proxy to connect to the game server. - ////!\ Make sure your server rules allow Proxies or VPNs before setting enabled=true, or you may face consequences!. - /// - internal static string Proxy { - get { - return ResourceManager.GetString("Proxy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to connect to the game server through a proxy.. - /// - internal static string Proxy_Enabled_Ingame { - get { - return ResourceManager.GetString("Proxy.Enabled_Ingame", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to connect to the login server through a proxy.. - /// - internal static string Proxy_Enabled_Login { - get { - return ResourceManager.GetString("Proxy.Enabled_Login", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to download MCC updates via proxy.. - /// - internal static string Proxy_Enabled_Update { - get { - return ResourceManager.GetString("Proxy.Enabled_Update", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Only required for password-protected proxies.. - /// - internal static string Proxy_Password { - get { - return ResourceManager.GetString("Proxy.Password", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Supported types: "HTTP", "SOCKS4", "SOCKS4a", "SOCKS5".. - /// - internal static string Proxy_Proxy_Type { - get { - return ResourceManager.GetString("Proxy.Proxy_Type", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Proxy server must allow HTTPS for login, and non-443 ports for playing.. - /// - internal static string Proxy_Server { - get { - return ResourceManager.GetString("Proxy.Server", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Only required for password-protected proxies.. - /// - internal static string Proxy_Username { - get { - return ResourceManager.GetString("Proxy.Username", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Chat signature related settings (affects minecraft 1.19+). - /// - internal static string Signature { - get { - return ResourceManager.GetString("Signature", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Microsoft accounts only. If disabled, will not be able to sign chat and join servers configured with "enforce-secure-profile=true". - /// - internal static string Signature_LoginWithSecureProfile { - get { - return ResourceManager.GetString("Signature.LoginWithSecureProfile", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use red    color block to mark chat without legitimate signature. - /// - internal static string Signature_MarkIllegallySignedMsg { - get { - return ResourceManager.GetString("Signature.MarkIllegallySignedMsg", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use green  color block to mark chat with legitimate signatures. - /// - internal static string Signature_MarkLegallySignedMsg { - get { - return ResourceManager.GetString("Signature.MarkLegallySignedMsg", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use yellow color block to mark chat that have been modified by the server.. - /// - internal static string Signature_MarkModifiedMsg { - get { - return ResourceManager.GetString("Signature.MarkModifiedMsg", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use gray   color block to mark system message (always without signature). - /// - internal static string Signature_MarkSystemMessage { - get { - return ResourceManager.GetString("Signature.MarkSystemMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to display chat and messages in commands without legal signatures. - /// - internal static string Signature_ShowIllegalSignedChat { - get { - return ResourceManager.GetString("Signature.ShowIllegalSignedChat", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Set to true to display messages modified by the server, false to display the original signed messages. - /// - internal static string Signature_ShowModifiedChat { - get { - return ResourceManager.GetString("Signature.ShowModifiedChat", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to sign the chat send from MCC. - /// - internal static string Signature_SignChat { - get { - return ResourceManager.GetString("Signature.SignChat", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Whether to sign the messages contained in the commands sent by MCC. For example, the message in "/msg" and "/me". - /// - internal static string Signature_SignMessageInCommand { - get { - return ResourceManager.GetString("Signature.SignMessageInCommand", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MinecraftClient { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class ConfigComments { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ConfigComments() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MinecraftClient.Resources.ConfigComments.ConfigComments", typeof(ConfigComments).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to can be used in some other fields as %yourvar% + ///%username% and %serverip% are reserved variables.. + /// + internal static string AppVars_Variables { + get { + return ResourceManager.GetString("AppVars.Variables", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to =============================== # + /// Minecraft Console Client Bots # + ///=============================== #. + /// + internal static string ChatBot { + get { + return ResourceManager.GetString("ChatBot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Get alerted when specified words are detected in chat + ///Useful for moderating your server or detecting when someone is talking to you. + /// + internal static string ChatBot_Alerts { + get { + return ResourceManager.GetString("ChatBot.Alerts", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Play a beep sound when a word is detected in addition to highlighting.. + /// + internal static string ChatBot_Alerts_Beep_Enabled { + get { + return ResourceManager.GetString("ChatBot.Alerts.Beep_Enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of words/strings to NOT alert you on.. + /// + internal static string ChatBot_Alerts_Excludes { + get { + return ResourceManager.GetString("ChatBot.Alerts.Excludes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The name of a file where alers logs will be written.. + /// + internal static string ChatBot_Alerts_Log_File { + get { + return ResourceManager.GetString("ChatBot.Alerts.Log_File", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Log alerts info a file.. + /// + internal static string ChatBot_Alerts_Log_To_File { + get { + return ResourceManager.GetString("ChatBot.Alerts.Log_To_File", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of words/strings to alert you on.. + /// + internal static string ChatBot_Alerts_Matches { + get { + return ResourceManager.GetString("ChatBot.Alerts.Matches", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trigger alerts when it rains and when it stops.. + /// + internal static string ChatBot_Alerts_Trigger_By_Rain { + get { + return ResourceManager.GetString("ChatBot.Alerts.Trigger_By_Rain", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Triggers alerts at the beginning and end of thunderstorms.. + /// + internal static string ChatBot_Alerts_Trigger_By_Thunderstorm { + get { + return ResourceManager.GetString("ChatBot.Alerts.Trigger_By_Thunderstorm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Triggers an alert after receiving a specified keyword.. + /// + internal static string ChatBot_Alerts_Trigger_By_Words { + get { + return ResourceManager.GetString("ChatBot.Alerts.Trigger_By_Words", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Send a command on a regular or random basis or make the bot walk around randomly to avoid automatic AFK disconnection + ////!\ Make sure your server rules do not forbid anti-AFK mechanisms! + ////!\ Make sure you keep the bot in an enclosure to prevent it wandering off if you're using terrain handling! (Recommended size 5x5x5). + /// + internal static string ChatBot_AntiAfk { + get { + return ResourceManager.GetString("ChatBot.AntiAfk", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Command to send to the server.. + /// + internal static string ChatBot_AntiAfk_Command { + get { + return ResourceManager.GetString("ChatBot.AntiAfk.Command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The time interval for execution. (in seconds). + /// + internal static string ChatBot_AntiAfk_Delay { + get { + return ResourceManager.GetString("ChatBot.AntiAfk.Delay", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to sneak when sending the command.. + /// + internal static string ChatBot_AntiAfk_Use_Sneak { + get { + return ResourceManager.GetString("ChatBot.AntiAfk.Use_Sneak", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use terrain handling to enable the bot to move around.. + /// + internal static string ChatBot_AntiAfk_Use_Terrain_Handling { + get { + return ResourceManager.GetString("ChatBot.AntiAfk.Use_Terrain_Handling", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The range the bot can move around randomly (Note: the bigger the range, the slower the bot will be). + /// + internal static string ChatBot_AntiAfk_Walk_Range { + get { + return ResourceManager.GetString("ChatBot.AntiAfk.Walk_Range", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How many times can the bot fail trying to move before using the command method.. + /// + internal static string ChatBot_AntiAfk_Walk_Retries { + get { + return ResourceManager.GetString("ChatBot.AntiAfk.Walk_Retries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatically attack hostile mobs around you + ///You need to enable Entity Handling to use this bot + ////!\ Make sure server rules allow your planned use of AutoAttack + ////!\ SERVER PLUGINS may consider AutoAttack to be a CHEAT MOD and TAKE ACTION AGAINST YOUR ACCOUNT so DOUBLE CHECK WITH SERVER RULES!. + /// + internal static string ChatBot_AutoAttack { + get { + return ResourceManager.GetString("ChatBot.AutoAttack", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Allow attacking hostile mobs.. + /// + internal static string ChatBot_AutoAttack_Attack_Hostile { + get { + return ResourceManager.GetString("ChatBot.AutoAttack.Attack_Hostile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Allow attacking passive mobs.. + /// + internal static string ChatBot_AutoAttack_Attack_Passive { + get { + return ResourceManager.GetString("ChatBot.AutoAttack.Attack_Passive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How long to wait between each attack. Set "Custom = false" to let MCC calculate it.. + /// + internal static string ChatBot_AutoAttack_Cooldown_Time { + get { + return ResourceManager.GetString("ChatBot.AutoAttack.Cooldown_Time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All entity types can be found here: https://mccteam.github.io/r/entity/#L15. + /// + internal static string ChatBot_AutoAttack_Entites_List { + get { + return ResourceManager.GetString("ChatBot.AutoAttack.Entites_List", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Possible values: "Interact", "Attack" (default), "InteractAt" (Interact and Attack).. + /// + internal static string ChatBot_AutoAttack_Interaction { + get { + return ResourceManager.GetString("ChatBot.AutoAttack.Interaction", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wether to treat the entities list as a "whitelist" or as a "blacklist".. + /// + internal static string ChatBot_AutoAttack_List_Mode { + get { + return ResourceManager.GetString("ChatBot.AutoAttack.List_Mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to "single" or "multi". single target one mob per attack. multi target all mobs in range per attack. + /// + internal static string ChatBot_AutoAttack_Mode { + get { + return ResourceManager.GetString("ChatBot.AutoAttack.Mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to "health" or "distance". Only needed when using single mode. + /// + internal static string ChatBot_AutoAttack_Priority { + get { + return ResourceManager.GetString("ChatBot.AutoAttack.Priority", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatically craft items in your inventory + ///See https://mccteam.github.io/g/bots/#auto-craft for how to use + ///You need to enable Inventory Handling to use this bot + ///You should also enable Terrain and Movements if you need to use a crafting table. + /// + internal static string ChatBot_AutoCraft { + get { + return ResourceManager.GetString("ChatBot.AutoCraft", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Location of the crafting table if you intended to use it. Terrain and movements must be enabled.. + /// + internal static string ChatBot_AutoCraft_CraftingTable { + get { + return ResourceManager.GetString("ChatBot.AutoCraft.CraftingTable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to What to do on crafting failure, "abort" or "wait".. + /// + internal static string ChatBot_AutoCraft_OnFailure { + get { + return ResourceManager.GetString("ChatBot.AutoCraft.OnFailure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recipes.Name: The name can be whatever you like and it is used to represent the recipe. + ///Recipes.Type: crafting table type: "player" or "table" + ///Recipes.Result: the resulting item + ///Recipes.Slots: All slots, counting from left to right, top to bottom. Please fill in "Null" for empty slots. + ///For the naming of the items, please see: https://mccteam.github.io/r/item/#L12. + /// + internal static string ChatBot_AutoCraft_Recipes { + get { + return ResourceManager.GetString("ChatBot.AutoCraft.Recipes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Auto-digging blocks. + ///You need to enable Terrain Handling to use this bot + ///You can use "/digbot start" and "/digbot stop" to control the start and stop of AutoDig. + ///Since MCC does not yet support accurate calculation of the collision volume of blocks, all blocks are considered as complete cubes when obtaining the position of the lookahead. + ///For the naming of the block, please see https://mccteam.github.io/r/block/#L15. + /// + internal static string ChatBot_AutoDig { + get { + return ResourceManager.GetString("ChatBot.AutoDig", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How many seconds to wait after entering the game to start digging automatically, set to -1 to disable automatic start.. + /// + internal static string ChatBot_AutoDig_Auto_Start_Delay { + get { + return ResourceManager.GetString("ChatBot.AutoDig.Auto_Start_Delay", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatically switch to the appropriate tool.. + /// + internal static string ChatBot_AutoDig_Auto_Tool_Switch { + get { + return ResourceManager.GetString("ChatBot.AutoDig.Auto_Tool_Switch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mining a block for more than "Dig_Timeout" seconds will be considered a timeout.. + /// + internal static string ChatBot_AutoDig_Dig_Timeout { + get { + return ResourceManager.GetString("ChatBot.AutoDig.Dig_Timeout", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to drop the current tool when its durability is too low.. + /// + internal static string ChatBot_AutoDig_Drop_Low_Durability_Tools { + get { + return ResourceManager.GetString("ChatBot.AutoDig.Drop_Low_Durability_Tools", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Will not use tools with less durability than this. Set to zero to disable this feature.. + /// + internal static string ChatBot_AutoDig_Durability_Limit { + get { + return ResourceManager.GetString("ChatBot.AutoDig.Durability_Limit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wether to treat the blocks list as a "whitelist" or as a "blacklist".. + /// + internal static string ChatBot_AutoDig_List_Type { + get { + return ResourceManager.GetString("ChatBot.AutoDig.List_Type", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to "distance" or "index", When using the "fixedpos" mode, the blocks are determined by distance to the player, or by the order in the list.. + /// + internal static string ChatBot_AutoDig_Location_Order { + get { + return ResourceManager.GetString("ChatBot.AutoDig.Location_Order", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The position of the blocks when using "fixedpos" or "both" mode.. + /// + internal static string ChatBot_AutoDig_Locations { + get { + return ResourceManager.GetString("ChatBot.AutoDig.Locations", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to output logs when digging blocks.. + /// + internal static string ChatBot_AutoDig_Log_Block_Dig { + get { + return ResourceManager.GetString("ChatBot.AutoDig.Log_Block_Dig", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to "lookat", "fixedpos" or "both". Digging the block being looked at, the block in a fixed position, or the block that needs to be all met.. + /// + internal static string ChatBot_AutoDig_Mode { + get { + return ResourceManager.GetString("ChatBot.AutoDig.Mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatically drop items in inventory + ///You need to enable Inventory Handling to use this bot + ///See this file for an up-to-date list of item types you can use with this bot: https://mccteam.github.io/r/item/#L12. + /// + internal static string ChatBot_AutoDrop { + get { + return ResourceManager.GetString("ChatBot.AutoDrop", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to "include", "exclude" or "everything". Include: drop item IN the list. Exclude: drop item NOT IN the list. + /// + internal static string ChatBot_AutoDrop_Mode { + get { + return ResourceManager.GetString("ChatBot.AutoDrop.Mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatically eat food when your Hunger value is low + ///You need to enable Inventory Handling to use this bot. + /// + internal static string ChatBot_AutoEat { + get { + return ResourceManager.GetString("ChatBot.AutoEat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatically catch fish using a fishing rod + ///Guide: https://mccteam.github.io/g/bots/#auto-fishing + ///You can use "/fish" to control the bot manually. + ////!\ Make sure server rules allow automated farming before using this bot. + /// + internal static string ChatBot_AutoFishing { + get { + return ResourceManager.GetString("ChatBot.AutoFishing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Keep it as false if you have not changed it before.. + /// + internal static string ChatBot_AutoFishing_Antidespawn { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Antidespawn", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Switch to a new rod from inventory after the current rod is unavailable.. + /// + internal static string ChatBot_AutoFishing_Auto_Rod_Switch { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Auto_Rod_Switch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to start fishing automatically after entering a world.. + /// + internal static string ChatBot_AutoFishing_Auto_Start { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Auto_Start", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How soon to re-cast after successful fishing.. + /// + internal static string ChatBot_AutoFishing_Cast_Delay { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Cast_Delay", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Will not use rods with less durability than this (full durability is 64). Set to zero to disable this feature.. + /// + internal static string ChatBot_AutoFishing_Durability_Limit { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Durability_Limit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This allows the player to change position/facing after each fish caught.. + /// + internal static string ChatBot_AutoFishing_Enable_Move { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Enable_Move", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How long after entering the game to start fishing (seconds).. + /// + internal static string ChatBot_AutoFishing_Fishing_Delay { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Fishing_Delay", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fishing timeout (seconds). Timeout will trigger a re-cast.. + /// + internal static string ChatBot_AutoFishing_Fishing_Timeout { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Fishing_Timeout", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A "stationary" hook that moves above this threshold in the Y-axis will be considered to have caught a fish.. + /// + internal static string ChatBot_AutoFishing_Hook_Threshold { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Hook_Threshold", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Used to adjust the above two thresholds, which when enabled will print the change in the position of the fishhook entity upon receipt of its movement packet.. + /// + internal static string ChatBot_AutoFishing_Log_Fish_Bobber { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Log_Fish_Bobber", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use the mainhand or the offhand to hold the rod.. + /// + internal static string ChatBot_AutoFishing_Mainhand { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Mainhand", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It will move in order "1->2->3->4->3->2->1->2->..." and can change position or facing or both each time. It is recommended to change the facing only.. + /// + internal static string ChatBot_AutoFishing_Movements { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Movements", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hook movement in the X and Z axis less than this value will be considered stationary.. + /// + internal static string ChatBot_AutoFishing_Stationary_Threshold { + get { + return ResourceManager.GetString("ChatBot.AutoFishing.Stationary_Threshold", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatically relog when disconnected by server, for example because the server is restating + ////!\ Use Ignore_Kick_Message=true at own risk! Server staff might not appreciate if you auto-relog on manual kicks. + /// + internal static string ChatBot_AutoRelog { + get { + return ResourceManager.GetString("ChatBot.AutoRelog", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The delay time before joining the server. (in seconds). + /// + internal static string ChatBot_AutoRelog_Delay { + get { + return ResourceManager.GetString("ChatBot.AutoRelog.Delay", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to When set to true, autorelog will reconnect regardless of kick messages.. + /// + internal static string ChatBot_AutoRelog_Ignore_Kick_Message { + get { + return ResourceManager.GetString("ChatBot.AutoRelog.Ignore_Kick_Message", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If the kickout message matches any of the strings, then autorelog will be triggered.. + /// + internal static string ChatBot_AutoRelog_Kick_Messages { + get { + return ResourceManager.GetString("ChatBot.AutoRelog.Kick_Messages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Retries when failing to relog to the server. use -1 for unlimited retries.. + /// + internal static string ChatBot_AutoRelog_Retries { + get { + return ResourceManager.GetString("ChatBot.AutoRelog.Retries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Run commands or send messages automatically when a specified pattern is detected in chat + ///Server admins can spoof chat messages (/nick, /tellraw) so keep this in mind when implementing AutoRespond rules + ////!\ This bot may get spammy depending on your rules, although the global messagecooldown setting can help you avoiding accidental spam. + /// + internal static string ChatBot_AutoRespond { + get { + return ResourceManager.GetString("ChatBot.AutoRespond", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Do not remove colors from text (Note: Your matches will have to include color codes (ones using the § character) in order to work). + /// + internal static string ChatBot_AutoRespond_Match_Colors { + get { + return ResourceManager.GetString("ChatBot.AutoRespond.Match_Colors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logs chat messages in a file on disk.. + /// + internal static string ChatBot_ChatLog { + get { + return ResourceManager.GetString("ChatBot.ChatLog", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This bot allows you to send and recieve messages and commands via a Discord channel. + ///For Setup you can either use the documentation or read here (Documentation has images). + ///Documentation: https://mccteam.github.io/g/bots/#discord-bridge + ///Setup: + ///First you need to create a Bot on the Discord Developers Portal, here is a video tutorial: https://www.youtube.com/watch?v=2FgMnZViNPA . + ////!\ IMPORTANT /!\: When creating a bot, you MUST ENABLE "Message Content Intent", "Server Members Intent" and "Presence Intent [rest of string was truncated]";. + /// + internal static string ChatBot_DiscordBridge { + get { + return ResourceManager.GetString("ChatBot.DiscordBridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The ID of a channel where you want to interact with the MCC using the bot.. + /// + internal static string ChatBot_DiscordBridge_ChannelId { + get { + return ResourceManager.GetString("ChatBot.DiscordBridge.ChannelId", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Message formats + ///Words wrapped with { and } are going to be replaced during the code execution, do not change them! + ///For example. {message} is going to be replace with an actual message, {username} will be replaced with an username, {timestamp} with the current time. + ///For Discord message formatting, check the following: https://mccteam.github.io/r/dc-fmt.html. + /// + internal static string ChatBot_DiscordBridge_Formats { + get { + return ResourceManager.GetString("ChatBot.DiscordBridge.Formats", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The ID of a server/guild where you have invited the bot to.. + /// + internal static string ChatBot_DiscordBridge_GuildId { + get { + return ResourceManager.GetString("ChatBot.DiscordBridge.GuildId", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How long to wait (in seconds) if a message can not be sent to discord before canceling the task (minimum 1 second).. + /// + internal static string ChatBot_DiscordBridge_MessageSendTimeout { + get { + return ResourceManager.GetString("ChatBot.DiscordBridge.MessageSendTimeout", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of IDs of people you want to be able to interact with the MCC using the bot.. + /// + internal static string ChatBot_DiscordBridge_OwnersIds { + get { + return ResourceManager.GetString("ChatBot.DiscordBridge.OwnersIds", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your Discord Bot token.. + /// + internal static string ChatBot_DiscordBridge_Token { + get { + return ResourceManager.GetString("ChatBot.DiscordBridge.Token", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatically farms crops for you (plants, breaks and bonemeals them). + ///Crop types available: Beetroot, Carrot, Melon, Netherwart, Pumpkin, Potato, Wheat. + ///Usage: "/farmer start" command and "/farmer stop" command. + ///NOTE: This a newly added bot, it is not perfect and was only tested in 1.19.2, there are some minor issues like not being able to bonemeal carrots/potatoes sometimes. + ///or bot jumps onto the farm land and breaks it (this happens rarely but still happens). We are looking forward at improving this. [rest of string was truncated]";. + /// + internal static string ChatBot_Farmer { + get { + return ResourceManager.GetString("ChatBot.Farmer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Delay between tasks in seconds (Minimum 1 second). + /// + internal static string ChatBot_Farmer_Delay_Between_Tasks { + get { + return ResourceManager.GetString("ChatBot.Farmer.Delay_Between_Tasks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled you to make the bot follow you + ///NOTE: This is an experimental feature, the bot can be slow at times, you need to walk with a normal speed and to sometimes stop for it to be able to keep up with you + ///It's similar to making animals follow you when you're holding food in your hand. + ///This is due to a slow pathfinding algorithm, we're working on getting a better one + ///You can tweak the update limit and find what works best for you. (NOTE: Do not but a very low one, because you might achieve the opposite, /// [rest of string was truncated]";. + /// + internal static string ChatBot_FollowPlayer { + get { + return ResourceManager.GetString("ChatBot.FollowPlayer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Do not follow the player if he is in the range of 3 blocks (prevents the bot from pushing a player in an infinite loop). + /// + internal static string ChatBot_FollowPlayer_Stop_At_Distance { + get { + return ResourceManager.GetString("ChatBot.FollowPlayer.Stop_At_Distance", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The rate at which the bot does calculations (in seconds) (You can tweak this if you feel the bot is too slow). + /// + internal static string ChatBot_FollowPlayer_Update_Limit { + get { + return ResourceManager.GetString("ChatBot.FollowPlayer.Update_Limit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A small game to demonstrate chat interactions. Players can guess mystery words one letter at a time. + ///You need to have ChatFormat working correctly and add yourself in botowners to start the game with /tell <bot username> start + ////!\ This bot may get a bit spammy if many players are interacting with it. + /// + internal static string ChatBot_HangmanGame { + get { + return ResourceManager.GetString("ChatBot.HangmanGame", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Relay messages between players and servers, like a mail plugin + ///This bot can store messages when the recipients are offline, and send them when they join the server + ////!\ Server admins can spoof PMs (/tellraw, /nick) so enable this bot only if you trust server admins. + /// + internal static string ChatBot_Mailer { + get { + return ResourceManager.GetString("ChatBot.Mailer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Allows you to render maps in the console and into images (which can be then sent to Discord using Discord Bridge Chat Bot) + ///This is useful for solving captchas which use maps + ///The maps are rendered into Rendered_Maps folder if the Save_To_File is enabled. + ///NOTE: + ///If some servers have a very short time for solving captchas, enabe Auto_Render_On_Update to see them immediatelly in the console. + ////!\ Make sure server rules allow bots to be used on the server, or you risk being punished.. + /// + internal static string ChatBot_Map { + get { + return ResourceManager.GetString("ChatBot.Map", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatically render the map once it is received or updated from/by the server. + /// + internal static string ChatBot_Map_Auto_Render_On_Update { + get { + return ResourceManager.GetString("ChatBot.Map.Auto_Render_On_Update", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Delete all rendered maps on unload/reload or when you launch the MCC again.. + /// + internal static string ChatBot_Map_Delete_All_On_Unload { + get { + return ResourceManager.GetString("ChatBot.Map.Delete_All_On_Unload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Get a notification when you have gotten a map from the server for the first time. + /// + internal static string ChatBot_Map_Notify_On_First_Update { + get { + return ResourceManager.GetString("ChatBot.Map.Notify_On_First_Update", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Resize an rendered image, this is useful when images that are rendered are small and when are being sent to Discord.. + /// + internal static string ChatBot_Map_Rasize_Rendered_Image { + get { + return ResourceManager.GetString("ChatBot.Map.Rasize_Rendered_Image", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to render the map in the console.. + /// + internal static string ChatBot_Map_Render_In_Console { + get { + return ResourceManager.GetString("ChatBot.Map.Render_In_Console", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The size that a rendered image should be resized to, in pixels (eg. 512).. + /// + internal static string ChatBot_Map_Resize_To { + get { + return ResourceManager.GetString("ChatBot.Map.Resize_To", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to store the rendered map as a file (You need this setting if you want to get a map on Discord using Discord Bridge).. + /// + internal static string ChatBot_Map_Save_To_File { + get { + return ResourceManager.GetString("ChatBot.Map.Save_To_File", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Send a rendered map (saved to a file) to a Discord or a Telegram channel via the Discord or Telegram Bride chat bot (The Discord/Telegram Bridge chat bot must be enabled and configured!) + ///You need to enable Save_To_File in order for this to work. + ///We also recommend turning on resizing.. + /// + internal static string ChatBot_Map_Send_Rendered_To_Bridges { + get { + return ResourceManager.GetString("ChatBot.Map.Send_Rendered_To_Bridges", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Log the list of players periodically into a textual file.. + /// + internal static string ChatBot_PlayerListLogger { + get { + return ResourceManager.GetString("ChatBot.PlayerListLogger", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (In seconds). + /// + internal static string ChatBot_PlayerListLogger_Delay { + get { + return ResourceManager.GetString("ChatBot.PlayerListLogger.Delay", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Send MCC console commands to your bot through server PMs (/tell) + ///You need to have ChatFormat working correctly and add yourself in botowners to use the bot + ////!\ Server admins can spoof PMs (/tellraw, /nick) so enable RemoteControl only if you trust server admins. + /// + internal static string ChatBot_RemoteControl { + get { + return ResourceManager.GetString("ChatBot.RemoteControl", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable recording of the game (/replay start) and replay it later using the Replay Mod (https://www.replaymod.com/) + ///Please note that due to technical limitations, the client player (you) will not be shown in the replay file + ////!\ You SHOULD use /replay stop or exit the program gracefully with /quit OR THE REPLAY FILE MAY GET CORRUPT!. + /// + internal static string ChatBot_ReplayCapture { + get { + return ResourceManager.GetString("ChatBot.ReplayCapture", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How long should replay file be auto-saved, in seconds. Use -1 to disable.. + /// + internal static string ChatBot_ReplayCapture_Backup_Interval { + get { + return ResourceManager.GetString("ChatBot.ReplayCapture.Backup_Interval", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Schedule commands and scripts to launch on various events such as server join, date/time or time interval + ///See https://mccteam.github.io/g/bots/#script-scheduler for more info. + /// + internal static string ChatBot_ScriptScheduler { + get { + return ResourceManager.GetString("ChatBot.ScriptScheduler", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This bot allows you to send and receive messages and commands via a Telegram Bot DM or to receive messages in a Telegram channel. + ////!\ NOTE: You can't send messages and commands from a group channel, you can only send them in the bot DM, but you can get the messages from the client in a group channel. + ///----------------------------------------------------------- + ///Setup: + ///First you need to create a Telegram bot and obtain an API key, to do so, go to Telegram and find @botfather + ///Click on "Start" button and re [rest of string was truncated]";. + /// + internal static string ChatBot_TelegramBridge { + get { + return ResourceManager.GetString("ChatBot.TelegramBridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A list of Chat IDs that are allowed to send messages and execute commands. To get an id of your chat DM with the bot use ".chatid" bot command in Telegram.. + /// + internal static string ChatBot_TelegramBridge_Authorized_Chat_Ids { + get { + return ResourceManager.GetString("ChatBot.TelegramBridge.Authorized_Chat_Ids", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An ID of a channel where you want to interact with the MCC using the bot.. + /// + internal static string ChatBot_TelegramBridge_ChannelId { + get { + return ResourceManager.GetString("ChatBot.TelegramBridge.ChannelId", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Message formats + ///Words wrapped with { and } are going to be replaced during the code execution, do not change them! + ///For example. {message} is going to be replace with an actual message, {username} will be replaced with an username, {timestamp} with the current time. + ///For Telegram message formatting, check the following: https://mccteam.github.io/r/tg-fmt.html. + /// + internal static string ChatBot_TelegramBridge_Formats { + get { + return ResourceManager.GetString("ChatBot.TelegramBridge.Formats", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How long to wait (in seconds) if a message can not be sent to Telegram before canceling the task (minimum 1 second).. + /// + internal static string ChatBot_TelegramBridge_MessageSendTimeout { + get { + return ResourceManager.GetString("ChatBot.TelegramBridge.MessageSendTimeout", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your Telegram Bot token.. + /// + internal static string ChatBot_TelegramBridge_Token { + get { + return ResourceManager.GetString("ChatBot.TelegramBridge.Token", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MCC does it best to detect chat messages, but some server have unusual chat formats + ///When this happens, you'll need to configure chat format below, see https://mccteam.github.io/g/conf/#chat-format-section. + /// + internal static string ChatFormat { + get { + return ResourceManager.GetString("ChatFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MCC support for common message formats. Set "false" to avoid conflicts with custom formats.. + /// + internal static string ChatFormat_Builtins { + get { + return ResourceManager.GetString("ChatFormat.Builtins", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to use the custom regular expressions below for detection.. + /// + internal static string ChatFormat_UserDefined { + get { + return ResourceManager.GetString("ChatFormat.UserDefined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Console-related settings.. + /// + internal static string Console { + get { + return ResourceManager.GetString("Console", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The settings for command completion suggestions.. + /// + internal static string Console_CommandSuggestion { + get { + return ResourceManager.GetString("Console.CommandSuggestion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to display command suggestions in the console.. + /// + internal static string Console_CommandSuggestion_Enable { + get { + return ResourceManager.GetString("Console.CommandSuggestion.Enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If a garbled code like "←[0m" appears on the terminal, you can turn off this.. + /// + internal static string Console_Enable_Color { + get { + return ResourceManager.GetString("Console.Enable_Color", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can use "Ctrl+P" to print out the current input and cursor position.. + /// + internal static string Console_General_Display_Uesr_Input { + get { + return ResourceManager.GetString("Console.General.Display_Uesr_Input", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Startup Config File + ///Please do not record extraneous data in this file as it will be overwritten by MCC. + /// + ///New to Minecraft Console Client? Check out this document: https://mccteam.github.io/g/conf.html + ///Want to upgrade to a newer version? See https://github.com/MCCTeam/Minecraft-Console-Client/#download. + /// + internal static string Head { + get { + return ResourceManager.GetString("Head", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This setting affects only the messages in the console.. + /// + internal static string Logging { + get { + return ResourceManager.GetString("Logging", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Regex for filtering chat message.. + /// + internal static string Logging_ChatFilter { + get { + return ResourceManager.GetString("Logging.ChatFilter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show server chat messages.. + /// + internal static string Logging_ChatMessages { + get { + return ResourceManager.GetString("Logging.ChatMessages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Regex for filtering debug message.. + /// + internal static string Logging_DebugFilter { + get { + return ResourceManager.GetString("Logging.DebugFilter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Please enable this before submitting bug reports. Thanks!. + /// + internal static string Logging_DebugMessages { + get { + return ResourceManager.GetString("Logging.DebugMessages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show error messages.. + /// + internal static string Logging_ErrorMessages { + get { + return ResourceManager.GetString("Logging.ErrorMessages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to "disable" or "blacklist" OR "whitelist". Blacklist hide message match regex. Whitelist show message match regex.. + /// + internal static string Logging_FilterMode { + get { + return ResourceManager.GetString("Logging.FilterMode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Informative messages. (i.e Most of the message from MCC). + /// + internal static string Logging_InfoMessages { + get { + return ResourceManager.GetString("Logging.InfoMessages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Log file name.. + /// + internal static string Logging_LogFile { + get { + return ResourceManager.GetString("Logging.LogFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write log messages to file.. + /// + internal static string Logging_LogToFile { + get { + return ResourceManager.GetString("Logging.LogToFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prepend timestamp to messages in log file.. + /// + internal static string Logging_PrependTimestamp { + get { + return ResourceManager.GetString("Logging.PrependTimestamp", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Keep color codes in the saved text.(look like "§b"). + /// + internal static string Logging_SaveColorCodes { + get { + return ResourceManager.GetString("Logging.SaveColorCodes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show warning messages.. + /// + internal static string Logging_WarningMessages { + get { + return ResourceManager.GetString("Logging.WarningMessages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Make sure you understand what each setting does before changing anything!. + /// + internal static string Main_Advanced { + get { + return ResourceManager.GetString("Main.Advanced", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AccountList: It allows a fast account switching without directly using the credentials + ///Usage examples: "/tell <mybot> reco Player2", "/connect <serverip> Player1". + /// + internal static string Main_Advanced_account_list { + get { + return ResourceManager.GetString("Main.Advanced.account_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Toggle auto respawn if client player was dead (make sure your spawn point is safe).. + /// + internal static string Main_Advanced_auto_respawn { + get { + return ResourceManager.GetString("Main.Advanced.auto_respawn", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Set the owner of the bot. /!\ Server admins can impersonate owners!. + /// + internal static string Main_Advanced_bot_owners { + get { + return ResourceManager.GetString("Main.Advanced.bot_owners", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use "mcc", "vanilla" or "none". This is how MCC identifies itself to the server.. + /// + internal static string Main_Advanced_brand_info { + get { + return ResourceManager.GetString("Main.Advanced.brand_info", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Leave empty for no logfile.. + /// + internal static string Main_Advanced_chatbot_log_file { + get { + return ResourceManager.GetString("Main.Advanced.chatbot_log_file", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If turned off, the emoji will be replaced with a simpler character (for /chunk status).. + /// + internal static string Main_Advanced_enable_emoji { + get { + return ResourceManager.GetString("Main.Advanced.enable_emoji", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Toggle entity handling.. + /// + internal static string Main_Advanced_entity_handling { + get { + return ResourceManager.GetString("Main.Advanced.entity_handling", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to exit directly when an error occurs, for using MCC in non-interactive scripts.. + /// + internal static string Main_Advanced_exit_on_failure { + get { + return ResourceManager.GetString("Main.Advanced.exit_on_failure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use "none", "slash"(/) or "backslash"(\).. + /// + internal static string Main_Advanced_internal_cmd_char { + get { + return ResourceManager.GetString("Main.Advanced.internal_cmd_char", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Toggle inventory handling.. + /// + internal static string Main_Advanced_inventory_handling { + get { + return ResourceManager.GetString("Main.Advanced.inventory_handling", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fill in with in-game locale code, check https://mccteam.github.io/r/l-code.html. + /// + internal static string Main_Advanced_language { + get { + return ResourceManager.GetString("Main.Advanced.language", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Load translations applied to MCC when available, turn it off to use English only.. + /// + internal static string Main_Advanced_LoadMccTrans { + get { + return ResourceManager.GetString("Main.Advanced.LoadMccTrans", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use "auto", "no" or "force". Force-enabling only works for MC 1.13+.. + /// + internal static string Main_Advanced_mc_forge { + get { + return ResourceManager.GetString("Main.Advanced.mc_forge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use "auto" or "1.X.X" values. Allows to skip server info retrieval.. + /// + internal static string Main_Advanced_mc_version { + get { + return ResourceManager.GetString("Main.Advanced.mc_version", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Controls the minimum interval (in seconds) between sending each message to the server.. + /// + internal static string Main_Advanced_message_cooldown { + get { + return ResourceManager.GetString("Main.Advanced.message_cooldown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable support for joining Minecraft Realms worlds.. + /// + internal static string Main_Advanced_minecraft_realms { + get { + return ResourceManager.GetString("Main.Advanced.minecraft_realms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The minimum height to use when calculating the image size from the height of the terminal.. + /// + internal static string Main_Advanced_MinTerminalHeight { + get { + return ResourceManager.GetString("Main.Advanced.MinTerminalHeight", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The minimum width used when calculating the image size from the width of the terminal.. + /// + internal static string Main_Advanced_MinTerminalWidth { + get { + return ResourceManager.GetString("Main.Advanced.MinTerminalWidth", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable head movement while walking to avoid anti-cheat triggers.. + /// + internal static string Main_Advanced_move_head_while_walking { + get { + return ResourceManager.GetString("Main.Advanced.move_head_while_walking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A movement speed higher than 2 may be considered cheating.. + /// + internal static string Main_Advanced_movement_speed { + get { + return ResourceManager.GetString("Main.Advanced.movement_speed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only works on Windows XP-8 or Windows 10 with old console.. + /// + internal static string Main_Advanced_player_head_icon { + get { + return ResourceManager.GetString("Main.Advanced.player_head_icon", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to For remote control of the bot.. + /// + internal static string Main_Advanced_private_msgs_cmd_name { + get { + return ResourceManager.GetString("Main.Advanced.private_msgs_cmd_name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How to retain profile key. Use "none", "memory" or "disk".. + /// + internal static string Main_Advanced_profilekey_cache { + get { + return ResourceManager.GetString("Main.Advanced.profilekey_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use "no", "fast" (5s timeout), or "yes". Required for joining some servers.. + /// + internal static string Main_Advanced_resolve_srv_records { + get { + return ResourceManager.GetString("Main.Advanced.resolve_srv_records", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cache compiled scripts for faster load on low-end devices.. + /// + internal static string Main_Advanced_script_cache { + get { + return ResourceManager.GetString("Main.Advanced.script_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ServerList: It allows an easier and faster server switching with short aliases instead of full server IP + ///Aliases cannot contain dots or spaces, and the name "localhost" cannot be used as an alias. + ///Usage examples: "/tell <mybot> connect Server1", "/connect Server2". + /// + internal static string Main_Advanced_server_list { + get { + return ResourceManager.GetString("Main.Advanced.server_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How to retain session tokens. Use "none", "memory" or "disk".. + /// + internal static string Main_Advanced_session_cache { + get { + return ResourceManager.GetString("Main.Advanced.session_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Decode links embedded in chat messages and show them in console.. + /// + internal static string Main_Advanced_show_chat_links { + get { + return ResourceManager.GetString("Main.Advanced.show_chat_links", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show inventory layout as ASCII art in inventory command.. + /// + internal static string Main_Advanced_show_inventory_layout { + get { + return ResourceManager.GetString("Main.Advanced.show_inventory_layout", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System messages for server ops.. + /// + internal static string Main_Advanced_show_system_messages { + get { + return ResourceManager.GetString("Main.Advanced.show_system_messages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Messages displayed above xp bar, set this to false in case of xp bar spam.. + /// + internal static string Main_Advanced_show_xpbar_messages { + get { + return ResourceManager.GetString("Main.Advanced.show_xpbar_messages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Temporary fix for Badpacket issue on some servers.. + /// + internal static string Main_Advanced_temporary_fix_badpacket { + get { + return ResourceManager.GetString("Main.Advanced.temporary_fix_badpacket", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use "none", "bit_4", "bit_8" or "bit_24". This can be checked by opening the debug log.. + /// + internal static string Main_Advanced_TerminalColorDepth { + get { + return ResourceManager.GetString("Main.Advanced.TerminalColorDepth", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Uses more ram, cpu, bandwidth but allows you to move around.. + /// + internal static string Main_Advanced_terrain_and_movements { + get { + return ResourceManager.GetString("Main.Advanced.terrain_and_movements", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Customize the TCP connection timeout with the server. (in seconds). + /// + internal static string Main_Advanced_timeout { + get { + return ResourceManager.GetString("Main.Advanced.timeout", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prepend timestamps to chat messages.. + /// + internal static string Main_Advanced_timestamps { + get { + return ResourceManager.GetString("Main.Advanced.timestamps", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Login=Email or Name. Use "-" as password for offline mode. Leave blank to prompt user on startup.. + /// + internal static string Main_General_account { + get { + return ResourceManager.GetString("Main.General.account", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The address of the game server, "Host" can be filled in with domain name or IP address. (The "Port" field can be deleted, it will be resolved automatically). + /// + internal static string Main_General_login { + get { + return ResourceManager.GetString("Main.General.login", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Microsoft Account sign-in method: "mcc" OR "browser". If the login always fails, please try to use the "browser" once.. + /// + internal static string Main_General_method { + get { + return ResourceManager.GetString("Main.General.method", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Account type: "mojang" OR "microsoft". Also affects interactive login in console.. + /// + internal static string Main_General_server_info { + get { + return ResourceManager.GetString("Main.General.server_info", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Settings below are sent to the server and only affect server-side things like your skin.. + /// + internal static string MCSettings { + get { + return ResourceManager.GetString("MCSettings", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Allows disabling chat colors server-side.. + /// + internal static string MCSettings_ChatColors { + get { + return ResourceManager.GetString("MCSettings.ChatColors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use "enabled", "commands", or "disabled". Allows to mute yourself.... + /// + internal static string MCSettings_ChatMode { + get { + return ResourceManager.GetString("MCSettings.ChatMode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MC 1.7- difficulty. "peaceful", "easy", "normal", "difficult".. + /// + internal static string MCSettings_Difficulty { + get { + return ResourceManager.GetString("MCSettings.Difficulty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If disabled, settings below are not sent to the server.. + /// + internal static string MCSettings_Enabled { + get { + return ResourceManager.GetString("MCSettings.Enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use any language implemented in Minecraft.. + /// + internal static string MCSettings_Locale { + get { + return ResourceManager.GetString("MCSettings.Locale", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MC 1.9+ main hand. "left" or "right".. + /// + internal static string MCSettings_MainHand { + get { + return ResourceManager.GetString("MCSettings.MainHand", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Value range: [0 - 255].. + /// + internal static string MCSettings_RenderDistance { + get { + return ResourceManager.GetString("MCSettings.RenderDistance", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Connect to a server via a proxy instead of connecting directly + ///If Mojang session services are blocked on your network, set Enabled_Login=true to login using proxy. + ///If the connection to the Minecraft game server is blocked by the firewall, set Enabled_Ingame=true to use a proxy to connect to the game server. + ////!\ Make sure your server rules allow Proxies or VPNs before setting enabled=true, or you may face consequences!. + /// + internal static string Proxy { + get { + return ResourceManager.GetString("Proxy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to connect to the game server through a proxy.. + /// + internal static string Proxy_Enabled_Ingame { + get { + return ResourceManager.GetString("Proxy.Enabled_Ingame", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to connect to the login server through a proxy.. + /// + internal static string Proxy_Enabled_Login { + get { + return ResourceManager.GetString("Proxy.Enabled_Login", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to download MCC updates via proxy.. + /// + internal static string Proxy_Enabled_Update { + get { + return ResourceManager.GetString("Proxy.Enabled_Update", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only required for password-protected proxies.. + /// + internal static string Proxy_Password { + get { + return ResourceManager.GetString("Proxy.Password", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supported types: "HTTP", "SOCKS4", "SOCKS4a", "SOCKS5".. + /// + internal static string Proxy_Proxy_Type { + get { + return ResourceManager.GetString("Proxy.Proxy_Type", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Proxy server must allow HTTPS for login, and non-443 ports for playing.. + /// + internal static string Proxy_Server { + get { + return ResourceManager.GetString("Proxy.Server", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only required for password-protected proxies.. + /// + internal static string Proxy_Username { + get { + return ResourceManager.GetString("Proxy.Username", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Chat signature related settings (affects minecraft 1.19+). + /// + internal static string Signature { + get { + return ResourceManager.GetString("Signature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Microsoft accounts only. If disabled, will not be able to sign chat and join servers configured with "enforce-secure-profile=true". + /// + internal static string Signature_LoginWithSecureProfile { + get { + return ResourceManager.GetString("Signature.LoginWithSecureProfile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use red    color block to mark chat without legitimate signature. + /// + internal static string Signature_MarkIllegallySignedMsg { + get { + return ResourceManager.GetString("Signature.MarkIllegallySignedMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use green  color block to mark chat with legitimate signatures. + /// + internal static string Signature_MarkLegallySignedMsg { + get { + return ResourceManager.GetString("Signature.MarkLegallySignedMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use yellow color block to mark chat that have been modified by the server.. + /// + internal static string Signature_MarkModifiedMsg { + get { + return ResourceManager.GetString("Signature.MarkModifiedMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use gray   color block to mark system message (always without signature). + /// + internal static string Signature_MarkSystemMessage { + get { + return ResourceManager.GetString("Signature.MarkSystemMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to display chat and messages in commands without legal signatures. + /// + internal static string Signature_ShowIllegalSignedChat { + get { + return ResourceManager.GetString("Signature.ShowIllegalSignedChat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Set to true to display messages modified by the server, false to display the original signed messages. + /// + internal static string Signature_ShowModifiedChat { + get { + return ResourceManager.GetString("Signature.ShowModifiedChat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to sign the chat send from MCC. + /// + internal static string Signature_SignChat { + get { + return ResourceManager.GetString("Signature.SignChat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether to sign the messages contained in the commands sent by MCC. For example, the message in "/msg" and "/me". + /// + internal static string Signature_SignMessageInCommand { + get { + return ResourceManager.GetString("Signature.SignMessageInCommand", resourceCulture); + } + } + } +} diff --git a/MinecraftClient/Resources/ConfigComments/ConfigComments.resx b/MinecraftClient/Resources/ConfigComments/ConfigComments.resx index da56bedc..3413fd87 100644 --- a/MinecraftClient/Resources/ConfigComments/ConfigComments.resx +++ b/MinecraftClient/Resources/ConfigComments/ConfigComments.resx @@ -535,6 +535,21 @@ When this happens, you'll need to configure chat format below, see https://mccte Whether to use the custom regular expressions below for detection. + + Console-related settings. + + + The settings for command completion suggestions. + + + Whether to display command suggestions in the console. + + + If a garbled code like "←[0m" appears on the terminal, you can turn off this. + + + You can use "Ctrl+P" to print out the current input and cursor position. + Startup Config File Please do not record extraneous data in this file as it will be overwritten by MCC. diff --git a/MinecraftClient/Resources/MinecraftAssets.Designer.cs b/MinecraftClient/Resources/MinecraftAssets.Designer.cs new file mode 100644 index 00000000..052c11b7 --- /dev/null +++ b/MinecraftClient/Resources/MinecraftAssets.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MinecraftClient { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class MinecraftAssets { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal MinecraftAssets() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MinecraftClient.Resources.MinecraftAssets", typeof(MinecraftAssets).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] en_us_json { + get { + object obj = ResourceManager.GetObject("en_us.json", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/MinecraftClient/Resources/MinecraftAssets.resx b/MinecraftClient/Resources/MinecraftAssets.resx new file mode 100644 index 00000000..0e01945f --- /dev/null +++ b/MinecraftClient/Resources/MinecraftAssets.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + en_us.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/MinecraftClient/Resources/Translations/Translations.Designer.cs b/MinecraftClient/Resources/Translations/Translations.Designer.cs index 64fe6379..7af00b17 100644 --- a/MinecraftClient/Resources/Translations/Translations.Designer.cs +++ b/MinecraftClient/Resources/Translations/Translations.Designer.cs @@ -2270,15 +2270,6 @@ namespace MinecraftClient { } } - /// - /// Looks up a localized string similar to Defaulting to en_GB.lang from your Minecraft directory.. - /// - internal static string chat_from_dir { - get { - return ResourceManager.GetString("chat.from_dir", resourceCulture); - } - } - /// /// Looks up a localized string similar to Translations file loaded.. /// @@ -2316,6 +2307,24 @@ namespace MinecraftClient { } } + /// + /// Looks up a localized string similar to Failed to save the file {0}.. + /// + internal static string chat_save_fail { + get { + return ResourceManager.GetString("chat.save_fail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Switch to use Minecraft's default language resource "en_us.json".. + /// + internal static string chat_use_default { + get { + return ResourceManager.GetString("chat.use_default", resourceCulture); + } + } + /// /// Looks up a localized string similar to [{0}] Disconnecting and Reconnecting to the Server. /// @@ -4112,6 +4121,15 @@ namespace MinecraftClient { } } + /// + /// Looks up a localized string similar to The color code {1} in {0} is in illegal format and the default value has been restored.. + /// + internal static string config_commandsuggestion_illegal_color { + get { + return ResourceManager.GetString("config.commandsuggestion.illegal_color", resourceCulture); + } + } + /// /// Looks up a localized string similar to Settings have been loaded from {0}. /// diff --git a/MinecraftClient/Resources/Translations/Translations.resx b/MinecraftClient/Resources/Translations/Translations.resx index ed73e510..1888597a 100644 --- a/MinecraftClient/Resources/Translations/Translations.resx +++ b/MinecraftClient/Resources/Translations/Translations.resx @@ -869,9 +869,6 @@ Add the ID of this chat to "Authorized_Chat_Ids" field in the configuration file Failed to download the file. - - Defaulting to en_GB.lang from your Minecraft directory. - Translations file loaded. @@ -885,6 +882,12 @@ Some messages won't be properly printed without this file. Performing request to {0} + + Failed to save the file {0}. + + + Switch to use Minecraft's default language resource "en_us.json". + [{0}] Disconnecting and Reconnecting to the Server @@ -1449,7 +1452,7 @@ You can use "/chunk status {0:0.0} {1:0.0} {2:0.0}" to check the chunk loading s set a custom %variable% randomly to a given value. - setrnd variable -7to17 OR setrnd variable string1 "\"string2\" string3" + setrnd variable -7 to 17 OR setrnd variable string1 "\"string2\" string3" setrnd variable -7 to 17 @@ -1487,6 +1490,9 @@ You can use "/chunk status {0:0.0} {1:0.0} {2:0.0}" to check the chunk loading s Failed to write to backup file {0} + + The color code {1} in {0} is in illegal format and the default value has been restored. + Settings have been loaded from {0} @@ -1991,9 +1997,6 @@ Switching to autodetection mode. Self-updating: {0:00.00}%, ETA {4}, Downloaded {1:00.0}MB of {2:00.0}MB, Avg {3:0.0}KB/s - - setrnd variable -7 to 17 OR setrnd variable string1 "\"string2\" string3" - Self-updating: Downloaded {0:00.0}MB, Avg {1:0.0}KB/s @@ -2025,4 +2028,4 @@ Logging in... Connected to proxy {0}:{1} - + \ No newline at end of file diff --git a/MinecraftClient/Resources/en_us.json b/MinecraftClient/Resources/en_us.json new file mode 100644 index 00000000..f02b7bf1 --- /dev/null +++ b/MinecraftClient/Resources/en_us.json @@ -0,0 +1,5822 @@ +{ + "language.name": "English", + "language.region": "United States", + "language.code": "en_us", + "narrator.button.accessibility": "Accessibility", + "narrator.button.language": "Language", + "narrator.button.difficulty_lock": "Difficulty lock", + "narrator.button.difficulty_lock.unlocked": "Unlocked", + "narrator.button.difficulty_lock.locked": "Locked", + "narrator.screen.title": "Title Screen", + "narrator.controls.reset": "Reset %s button", + "narrator.controls.bound": "%s is bound to %s", + "narrator.controls.unbound": "%s is not bound", + "narrator.select": "Selected: %s", + "narrator.select.world": "Selected %s, last played: %s, %s, %s, version: %s", + "narrator.loading": "Loading: %s", + "narrator.loading.done": "Done", + "narrator.joining": "Joining", + "narrator.position.screen": "Screen element %s out of %s", + "narrator.screen.usage": "Use mouse cursor or Tab button to select element", + "narrator.position.list": "Selected list row %s out of %s", + "narrator.position.object_list": "Selected row element %s out of %s", + "narration.suggestion.tooltip": "Selected suggestion %d out of %d: %s (%s)", + "narration.suggestion": "Selected suggestion %d out of %d: %s", + "narration.button": "Button: %s", + "narration.button.usage.focused": "Press Enter to activate", + "narration.button.usage.hovered": "Left click to activate", + "narration.cycle_button.usage.focused": "Press Enter to switch to %s", + "narration.cycle_button.usage.hovered": "Left click to switch to %s", + "narration.checkbox": "Checkbox: %s", + "narration.checkbox.usage.focused": "Press Enter to toggle", + "narration.checkbox.usage.hovered": "Left click to toggle", + "narration.recipe": "Recipe for %s", + "narration.recipe.usage": "Left click to select", + "narration.recipe.usage.more": "Right click to show more recipes", + "narration.selection.usage": "Press up and down buttons to move to another entry", + "narration.component_list.usage": "Press Tab to navigate to next element", + "narration.slider.usage.focused": "Press left or right keyboard buttons to change value", + "narration.slider.usage.hovered": "Drag slider to change value", + "narration.edit_box": "Edit box: %s", + "chat_screen.title": "Chat screen", + "chat_screen.usage": "Input message and press Enter to send", + "chat_screen.message": "Message to send: %s", + "gui.done": "Done", + "gui.cancel": "Cancel", + "gui.back": "Back", + "gui.toTitle": "Back to Title Screen", + "gui.toMenu": "Back to Server List", + "gui.up": "Up", + "gui.down": "Down", + "gui.yes": "Yes", + "gui.no": "No", + "gui.none": "None", + "gui.all": "All", + "gui.ok": "Ok", + "gui.proceed": "Proceed", + "gui.acknowledge": "Acknowledge", + "gui.recipebook.moreRecipes": "Right Click for More", + "gui.recipebook.search_hint": "Search...", + "gui.recipebook.toggleRecipes.all": "Showing All", + "gui.recipebook.toggleRecipes.craftable": "Showing Craftable", + "gui.recipebook.toggleRecipes.smeltable": "Showing Smeltable", + "gui.recipebook.toggleRecipes.blastable": "Showing Blastable", + "gui.recipebook.toggleRecipes.smokable": "Showing Smokable", + "gui.socialInteractions.title": "Social Interactions", + "gui.socialInteractions.tab_all": "All", + "gui.socialInteractions.tab_hidden": "Hidden", + "gui.socialInteractions.tab_blocked": "Blocked", + "gui.socialInteractions.blocking_hint": "Manage with Microsoft account", + "gui.socialInteractions.status_hidden": "Hidden", + "gui.socialInteractions.status_blocked": "Blocked", + "gui.socialInteractions.status_offline": "Offline", + "gui.socialInteractions.status_hidden_offline": "Hidden - Offline", + "gui.socialInteractions.status_blocked_offline": "Blocked - Offline", + "gui.socialInteractions.server_label.single": "%s - %s player", + "gui.socialInteractions.server_label.multiple": "%s - %s players", + "gui.socialInteractions.search_hint": "Search...", + "gui.socialInteractions.search_empty": "Couldn't find any players with that name", + "gui.socialInteractions.empty_hidden": "No players hidden in chat", + "gui.socialInteractions.empty_blocked": "No blocked players in chat", + "gui.socialInteractions.hide": "Hide in Chat", + "gui.socialInteractions.show": "Show in Chat", + "gui.socialInteractions.report": "Report", + "gui.socialInteractions.hidden_in_chat": "Chat messages from %s will be hidden", + "gui.socialInteractions.shown_in_chat": "Chat messages from %s will be shown", + "gui.socialInteractions.tooltip.hide": "Hide messages", + "gui.socialInteractions.tooltip.show": "Show messages", + "gui.socialInteractions.tooltip.report": "Report player", + "gui.socialInteractions.tooltip.report.disabled": "The reporting service is unavailable", + "gui.socialInteractions.tooltip.report.no_messages": "No reportable messages from player %s", + "gui.socialInteractions.tooltip.report.not_reportable": "This player can't be reported, because their chat messages can't be verified on this server", + "gui.socialInteractions.narration.hide": "Hide messages from %s", + "gui.socialInteractions.narration.show": "Show messages from %s", + "gui.socialInteractions.narration.report": "Report player %s", + "gui.narrate.button": "%s button", + "gui.narrate.slider": "%s slider", + "gui.narrate.editBox": "%s edit box: %s", + "gui.chatReport.title": "Report Player", + "gui.chatReport.send": "Send Report", + "gui.chatReport.send.comments_too_long": "Please shorten the comment", + "gui.chatReport.send.no_reason": "Please select a report category", + "gui.chatReport.send.no_reported_messages": "Please select at least one chat message to report", + "gui.chatReport.send.too_many_messages": "Trying to include too many messages in the report", + "gui.chatReport.observed_what": "Why are you reporting this?", + "gui.chatReport.select_reason": "Select Report Category", + "gui.chatReport.more_comments": "Please describe what happened:", + "gui.chatReport.describe": "Sharing details will help us make a well-informed decision.", + "gui.chatReport.comments": "Comments", + "gui.chatReport.read_info": "Learn About Reporting", + "gui.chatReport.select_chat": "Select Chat Messages to Report", + "gui.chatReport.selected_chat": "%s Chat Message(s) Selected to Report", + "gui.chatReport.report_sent_msg": "We’ve successfully received your report. Thank you!\n\nOur team will review it as soon as possible.", + "gui.chatReport.discard.title": "Discard report and comments?", + "gui.chatReport.discard.content": "If you leave, you'll lose this report and your comments.\nAre you sure you want to leave?", + "gui.chatReport.discard.discard": "Leave and Discard Report", + "gui.chatReport.discard.draft": "Save as Draft", + "gui.chatReport.discard.return": "Continue Editing", + "gui.chatReport.draft.title": "Edit draft chat report?", + "gui.chatReport.draft.content": "Would you like to continue editing the existing report or discard it and create a new one?", + "gui.chatReport.draft.quittotitle.title": "You have a draft chat report that will be lost if you quit", + "gui.chatReport.draft.quittotitle.content": "Would you like to continue editing it or discard it?", + "gui.chatReport.draft.discard": "Discard", + "gui.chatReport.draft.edit": "Continue Editing", + "gui.abuseReport.reason.title": "Select Report Category", + "gui.abuseReport.reason.description": "Description:", + "gui.abuseReport.reason.narration": "%s: %s", + "gui.abuseReport.reason.false_reporting": "False Reporting", + "gui.abuseReport.reason.child_sexual_exploitation_or_abuse": "Child sexual exploitation or abuse", + "gui.abuseReport.reason.child_sexual_exploitation_or_abuse.description": "Someone is talking about or otherwise promoting indecent behavior involving children.", + "gui.abuseReport.reason.terrorism_or_violent_extremism": "Terrorism or violent extremism", + "gui.abuseReport.reason.terrorism_or_violent_extremism.description": "Someone is talking about, promoting, or threatening to commit acts of terrorism or violent extremism for political, religious, ideological, or other reasons.", + "gui.abuseReport.reason.hate_speech": "Hate speech", + "gui.abuseReport.reason.hate_speech.description": "Someone is attacking you or another player based on characteristics of their identity, like religion, race, or sexuality.", + "gui.abuseReport.reason.harassment_or_bullying": "Harassment or bullying", + "gui.abuseReport.reason.harassment_or_bullying.description": "Someone is shaming, attacking, or bullying you or someone else. This includes when someone is repeatedly trying to contact you or someone else without consent or posting private personal information about you or someone else without consent (\"doxing\").", + "gui.abuseReport.reason.imminent_harm": "Imminent harm - Threat to harm others", + "gui.abuseReport.reason.imminent_harm.description": "Someone is threatening to harm you or someone else in real life.", + "gui.abuseReport.reason.defamation_impersonation_false_information": "Defamation, impersonation, or false information", + "gui.abuseReport.reason.defamation_impersonation_false_information.description": "Someone is damaging someone else's reputation, pretending to be someone they're not, or sharing false information with the aim to exploit or mislead others.", + "gui.abuseReport.reason.self_harm_or_suicide": "Imminent harm - Self-harm or suicide", + "gui.abuseReport.reason.self_harm_or_suicide.description": "Someone is threatening to harm themselves in real life or talking about harming themselves in real life.", + "gui.abuseReport.reason.alcohol_tobacco_drugs": "Drugs or alcohol", + "gui.abuseReport.reason.alcohol_tobacco_drugs.description": "Someone is encouraging others to partake in illegal drug related activities or encouraging underage drinking.", + "gui.abuseReport.reason.non_consensual_intimate_imagery": "Non-consensual intimate imagery", + "gui.abuseReport.reason.non_consensual_intimate_imagery.description": "Someone is talking about, sharing, or otherwise promoting private and intimate images.", + "gui.abuseReport.sending.title": "Sending your report...", + "gui.abuseReport.sent.title": "Report sent", + "gui.abuseReport.error.title": "Problem sending your report", + "gui.abuseReport.send.generic_error": "Encountered an unexpected error while sending your report.", + "gui.abuseReport.send.error_message": "An error was returned while sending your report:\n'%s'", + "gui.abuseReport.send.service_unavailable": "Unable to reach the Abuse Reporting service. Please make sure you are connected to the internet and try again.", + "gui.abuseReport.send.http_error": "An unexpected HTTP error occurred while sending your report.", + "gui.abuseReport.send.json_error": "Encountered malformed payload while sending your report.", + "gui.chatSelection.title": "Select Chat Messages to Report", + "gui.chatSelection.context": "Messages surrounding this selection will be included to provide additional context", + "gui.chatSelection.selected": "%s/%s message(s) selected", + "gui.chatSelection.heading": "%s %s", + "gui.chatSelection.message.narrate": "%s said: %s at %s", + "gui.chatSelection.fold": "%s message(s) hidden", + "gui.chatSelection.join": "%s joined the chat", + "gui.multiLineEditBox.character_limit": "%s/%s", + "gui.banned.title.temporary": "Account temporarily suspended", + "gui.banned.title.permanent": "Account permanently banned", + "gui.banned.description": "%s\n\n%s\n\nLearn more at the following link: %s", + "gui.banned.description.reason": "We recently received a report for bad behavior by your account. Our moderators have now reviewed your case and identified it as %s, which goes against the Minecraft Community Standards.", + "gui.banned.description.reason_id": "Code: %s", + "gui.banned.description.reason_id_message": "Code: %s - %s", + "gui.banned.description.unknownreason": "We recently received a report for bad behavior by your account. Our moderators have now reviewed your case and identified that it goes against the Minecraft Community Standards.", + "gui.banned.description.temporary.duration": "Your account is temporarily suspended and will be reactivated in %s.", + "gui.banned.description.temporary": "%s Until then, you can’t play online or join Realms.", + "gui.banned.description.permanent": "Your account is permanently banned, which means you can’t play online or join Realms.", + "translation.test.none": "Hello, world!", + "translation.test.complex": "Prefix, %s%2$s again %s and %1$s lastly %s and also %1$s again!", + "translation.test.escape": "%%s %%%s %%%%s %%%%%s", + "translation.test.invalid": "hi %", + "translation.test.invalid2": "hi % s", + "translation.test.args": "%s %s", + "translation.test.world": "world", + "menu.game": "Game Menu", + "menu.singleplayer": "Singleplayer", + "menu.multiplayer": "Multiplayer", + "menu.online": "Minecraft Realms", + "menu.options": "Options...", + "menu.quit": "Quit Game", + "menu.returnToMenu": "Save and Quit to Title", + "menu.disconnect": "Disconnect", + "menu.returnToGame": "Back to Game", + "menu.generatingLevel": "Generating world", + "menu.loadingLevel": "Loading world", + "menu.savingLevel": "Saving world", + "menu.working": "Working...", + "menu.savingChunks": "Saving chunks", + "menu.preparingSpawn": "Preparing spawn area: %s%%", + "menu.loadingForcedChunks": "Loading forced chunks for dimension %s", + "menu.generatingTerrain": "Building terrain", + "menu.convertingLevel": "Converting world", + "menu.respawning": "Respawning", + "menu.shareToLan": "Open to LAN", + "menu.sendFeedback": "Give Feedback", + "menu.reportBugs": "Report Bugs", + "menu.playerReporting": "Player Reporting", + "menu.paused": "Game Paused", + "menu.modded": " (Modded)", + "optimizeWorld.confirm.title": "Optimize World", + "optimizeWorld.confirm.description": "This will attempt to optimize your world by making sure all data is stored in the most recent game format. This can take a very long time, depending on your world. Once done, your world may play faster but will no longer be compatible with older versions of the game. Are you sure you wish to proceed?", + "optimizeWorld.title": "Optimizing World '%s'", + "optimizeWorld.stage.counting": "Counting chunks...", + "optimizeWorld.stage.upgrading": "Upgrading all chunks...", + "optimizeWorld.stage.finished": "Finishing up...", + "optimizeWorld.stage.failed": "Failed! :(", + "optimizeWorld.info.converted": "Upgraded chunks: %s", + "optimizeWorld.info.skipped": "Skipped chunks: %s", + "optimizeWorld.info.total": "Total chunks: %s", + "selectWorld.title": "Select World", + "selectWorld.search": "search for worlds", + "selectWorld.world": "World", + "selectWorld.select": "Play Selected World", + "selectWorld.create": "Create New World", + "selectWorld.recreate": "Re-Create", + "selectWorld.createDemo": "Play New Demo World", + "selectWorld.delete": "Delete", + "selectWorld.edit": "Edit", + "selectWorld.edit.title": "Edit World", + "selectWorld.edit.resetIcon": "Reset Icon", + "selectWorld.edit.openFolder": "Open World Folder", + "selectWorld.edit.save": "Save", + "selectWorld.edit.backup": "Make Backup", + "selectWorld.edit.backupFolder": "Open Backups Folder", + "selectWorld.edit.backupFailed": "Backup failed", + "selectWorld.edit.backupCreated": "Backed up: %s", + "selectWorld.edit.backupSize": "size: %s MB", + "selectWorld.edit.optimize": "Optimize World", + "selectWorld.edit.export_worldgen_settings": "Export World Generation Settings", + "selectWorld.edit.export_worldgen_settings.success": "Exported", + "selectWorld.edit.export_worldgen_settings.failure": "Export failed", + "selectWorld.deleteQuestion": "Are you sure you want to delete this world?", + "selectWorld.deleteWarning": "'%s' will be lost forever! (A long time!)", + "selectWorld.deleteButton": "Delete", + "selectWorld.conversion": "Must be converted!", + "selectWorld.conversion.tooltip": "This world must be opened in an older version (like 1.6.4) to be safely converted", + "selectWorld.locked": "Locked by another running instance of Minecraft", + "selectWorld.incompatible_series": "Created by an incompatible version", + "selectWorld.newWorld": "New World", + "selectWorld.enterName": "World Name", + "selectWorld.resultFolder": "Will be saved in:", + "selectWorld.enterSeed": "Seed for the world generator", + "selectWorld.seedInfo": "Leave blank for a random seed", + "selectWorld.cheats": "Cheats", + "selectWorld.experimental": "Experimental", + "selectWorld.customizeType": "Customize", + "selectWorld.version": "Version:", + "selectWorld.versionUnknown": "unknown", + "selectWorld.versionQuestion": "Do you really want to load this world?", + "selectWorld.versionWarning": "This world was last played in version %s and loading it in this version could cause corruption!", + "selectWorld.versionJoinButton": "Load Anyway", + "selectWorld.backupQuestion.snapshot": "Do you really want to load this world?", + "selectWorld.backupWarning.snapshot": "This world was last played in version %s; you are on version %s. Please make a backup in case you experience world corruptions!", + "selectWorld.backupQuestion.downgrade": "Downgrading a world is not supported", + "selectWorld.backupWarning.downgrade": "This world was last played in version %s; you are on version %s. Downgrading a world could cause corruption - we cannot guarantee that it will load or work. If you still want to continue, please make a backup!", + "selectWorld.backupQuestion.customized": "Customized worlds are no longer supported", + "selectWorld.backupWarning.customized": "Unfortunately, we do not support customized worlds in this version of Minecraft. We can still load this world and keep everything the way it was, but any newly generated terrain will no longer be customized. We're sorry for the inconvenience!", + "selectWorld.backupQuestion.experimental": "Worlds using Experimental Settings are not supported", + "selectWorld.backupWarning.experimental": "This world uses experimental settings that could stop working at any time. We cannot guarantee it will load or work. Here be dragons!", + "selectWorld.backupEraseCache": "Erase Cached Data", + "selectWorld.backupJoinConfirmButton": "Create Backup and Load", + "selectWorld.backupJoinSkipButton": "I know what I'm doing!", + "selectWorld.tooltip.fromNewerVersion1": "World was saved in a newer version,", + "selectWorld.tooltip.fromNewerVersion2": "loading this world could cause problems!", + "selectWorld.tooltip.snapshot1": "Don't forget to back up this world", + "selectWorld.tooltip.snapshot2": "before you load it in this snapshot.", + "selectWorld.unable_to_load": "Unable to load worlds", + "selectWorld.futureworld.error.title": "An error occurred!", + "selectWorld.futureworld.error.text": "Something went wrong while trying to load a world from a future version. This was a risky operation to begin with; sorry it didn't work.", + "selectWorld.recreate.error.title": "An error occurred!", + "selectWorld.recreate.error.text": "Something went wrong while trying to recreate a world.", + "selectWorld.recreate.customized.title": "Customized worlds are no longer supported", + "selectWorld.recreate.customized.text": "Customized worlds are no longer supported in this version of Minecraft. We can try to recreate it with the same seed and properties, but any terrain customizations will be lost. We're sorry for the inconvenience!", + "selectWorld.load_folder_access": "Unable to read or access folder where game worlds are saved!", + "selectWorld.access_failure": "Failed to access world", + "selectWorld.delete_failure": "Failed to delete world", + "selectWorld.data_read": "Reading world data...", + "selectWorld.loading_list": "Loading world list", + "createWorld.customize.presets": "Presets", + "createWorld.customize.presets.title": "Select a Preset", + "createWorld.customize.presets.select": "Use Preset", + "createWorld.customize.presets.share": "Want to share your preset with someone? Use the box below!", + "createWorld.customize.presets.list": "Alternatively, here's some we made earlier!", + "createWorld.customize.flat.title": "Superflat Customization", + "createWorld.customize.flat.tile": "Layer Material", + "createWorld.customize.flat.height": "Height", + "createWorld.customize.flat.removeLayer": "Remove Layer", + "createWorld.customize.flat.layer.top": "Top - %s", + "createWorld.customize.flat.layer": "%s", + "createWorld.customize.flat.layer.bottom": "Bottom - %s", + "createWorld.customize.buffet.title": "Buffet world customization", + "createWorld.customize.buffet.biome": "Please select a biome", + "flat_world_preset.unknown": "???", + "flat_world_preset.minecraft.classic_flat": "Classic Flat", + "flat_world_preset.minecraft.tunnelers_dream": "Tunnelers' Dream", + "flat_world_preset.minecraft.water_world": "Water World", + "flat_world_preset.minecraft.overworld": "Overworld", + "flat_world_preset.minecraft.snowy_kingdom": "Snowy Kingdom", + "flat_world_preset.minecraft.bottomless_pit": "Bottomless Pit", + "flat_world_preset.minecraft.desert": "Desert", + "flat_world_preset.minecraft.redstone_ready": "Redstone Ready", + "flat_world_preset.minecraft.the_void": "The Void", + "createWorld.customize.custom.page0": "Basic Settings", + "createWorld.customize.custom.page1": "Ore Settings", + "createWorld.customize.custom.page2": "Advanced Settings (Expert Users Only!)", + "createWorld.customize.custom.page3": "Extra Advanced Settings (Expert Users Only!)", + "createWorld.customize.custom.randomize": "Randomize", + "createWorld.customize.custom.prev": "Previous Page", + "createWorld.customize.custom.next": "Next Page", + "createWorld.customize.custom.defaults": "Defaults", + "createWorld.customize.custom.confirm1": "This will overwrite your current", + "createWorld.customize.custom.confirm2": "settings and cannot be undone.", + "createWorld.customize.custom.confirmTitle": "Warning!", + "createWorld.customize.custom.mainNoiseScaleX": "Main Noise Scale X", + "createWorld.customize.custom.mainNoiseScaleY": "Main Noise Scale Y", + "createWorld.customize.custom.mainNoiseScaleZ": "Main Noise Scale Z", + "createWorld.customize.custom.depthNoiseScaleX": "Depth Noise Scale X", + "createWorld.customize.custom.depthNoiseScaleZ": "Depth Noise Scale Z", + "createWorld.customize.custom.depthNoiseScaleExponent": "Depth Noise Exponent", + "createWorld.customize.custom.baseSize": "Depth Base Size", + "createWorld.customize.custom.coordinateScale": "Coordinate Scale", + "createWorld.customize.custom.heightScale": "Height Scale", + "createWorld.customize.custom.stretchY": "Height Stretch", + "createWorld.customize.custom.upperLimitScale": "Upper Limit Scale", + "createWorld.customize.custom.lowerLimitScale": "Lower Limit Scale", + "createWorld.customize.custom.biomeDepthWeight": "Biome Depth Weight", + "createWorld.customize.custom.biomeDepthOffset": "Biome Depth Offset", + "createWorld.customize.custom.biomeScaleWeight": "Biome Scale Weight", + "createWorld.customize.custom.biomeScaleOffset": "Biome Scale Offset", + "createWorld.customize.custom.seaLevel": "Sea Level", + "createWorld.customize.custom.useCaves": "Caves", + "createWorld.customize.custom.useStrongholds": "Strongholds", + "createWorld.customize.custom.useVillages": "Villages", + "createWorld.customize.custom.useMineShafts": "Mineshafts", + "createWorld.customize.custom.useTemples": "Temples", + "createWorld.customize.custom.useOceanRuins": "Ocean Ruins", + "createWorld.customize.custom.useMonuments": "Ocean Monuments", + "createWorld.customize.custom.useMansions": "Woodland Mansions", + "createWorld.customize.custom.useRavines": "Ravines", + "createWorld.customize.custom.useDungeons": "Dungeons", + "createWorld.customize.custom.dungeonChance": "Dungeon Count", + "createWorld.customize.custom.useWaterLakes": "Water Lakes", + "createWorld.customize.custom.waterLakeChance": "Water Lake Rarity", + "createWorld.customize.custom.useLavaLakes": "Lava Lakes", + "createWorld.customize.custom.lavaLakeChance": "Lava Lake Rarity", + "createWorld.customize.custom.useLavaOceans": "Lava Oceans", + "createWorld.customize.custom.fixedBiome": "Biome", + "createWorld.customize.custom.biomeSize": "Biome Size", + "createWorld.customize.custom.riverSize": "River Size", + "createWorld.customize.custom.size": "Spawn Size", + "createWorld.customize.custom.count": "Spawn Tries", + "createWorld.customize.custom.minHeight": "Min. Height", + "createWorld.customize.custom.maxHeight": "Max. Height", + "createWorld.customize.custom.center": "Center Height", + "createWorld.customize.custom.spread": "Spread Height", + "createWorld.customize.custom.presets.title": "Customize World Presets", + "createWorld.customize.custom.presets": "Presets", + "createWorld.customize.custom.preset.waterWorld": "Water World", + "createWorld.customize.custom.preset.isleLand": "Isle Land", + "createWorld.customize.custom.preset.caveDelight": "Caver's Delight", + "createWorld.customize.custom.preset.mountains": "Mountain Madness", + "createWorld.customize.custom.preset.drought": "Drought", + "createWorld.customize.custom.preset.caveChaos": "Caves of Chaos", + "createWorld.customize.custom.preset.goodLuck": "Good Luck", + "createWorld.preparing": "Preparing for world creation...", + "datapackFailure.title": "Errors in currently selected datapacks prevented the world from loading.\nYou can either try to load it with only the vanilla data pack (\"safe mode\"), or go back to the title screen and fix it manually.", + "datapackFailure.safeMode": "Safe Mode", + "editGamerule.title": "Edit Game Rules", + "editGamerule.default": "Default: %s", + "gameMode.survival": "Survival Mode", + "gameMode.creative": "Creative Mode", + "gameMode.adventure": "Adventure Mode", + "gameMode.spectator": "Spectator Mode", + "gameMode.hardcore": "Hardcore Mode!", + "gameMode.changed": "Your game mode has been updated to %s", + "spectatorMenu.previous_page": "Previous Page", + "spectatorMenu.next_page": "Next Page", + "spectatorMenu.close": "Close Menu", + "spectatorMenu.teleport": "Teleport to Player", + "spectatorMenu.teleport.prompt": "Select a player to teleport to", + "spectatorMenu.team_teleport": "Teleport to Team Member", + "spectatorMenu.team_teleport.prompt": "Select a team to teleport to", + "spectatorMenu.root.prompt": "Press a key to select a command, and again to use it.", + "selectWorld.gameMode": "Game Mode", + "selectWorld.gameMode.survival": "Survival", + "selectWorld.gameMode.survival.line1": "Search for resources, craft, gain", + "selectWorld.gameMode.survival.line2": "levels, health and hunger", + "selectWorld.gameMode.creative": "Creative", + "selectWorld.gameMode.creative.line1": "Unlimited resources, free flying and", + "selectWorld.gameMode.creative.line2": "destroy blocks instantly", + "selectWorld.gameMode.spectator": "Spectator", + "selectWorld.gameMode.spectator.line1": "You can look but don't touch", + "selectWorld.gameMode.spectator.line2": "", + "selectWorld.gameMode.hardcore": "Hardcore", + "selectWorld.gameMode.hardcore.line1": "Same as Survival Mode, locked at hardest", + "selectWorld.gameMode.hardcore.line2": "difficulty, and one life only", + "selectWorld.gameMode.adventure": "Adventure", + "selectWorld.gameMode.adventure.line1": "Same as Survival Mode, but blocks can't", + "selectWorld.gameMode.adventure.line2": "be added or removed", + "selectWorld.moreWorldOptions": "More World Options...", + "selectWorld.gameRules": "Game Rules", + "selectWorld.mapFeatures": "Generate Structures", + "selectWorld.mapFeatures.info": "Villages, dungeons etc.", + "selectWorld.mapType": "World Type", + "selectWorld.mapType.normal": "Normal", + "selectWorld.allowCommands": "Allow Cheats", + "selectWorld.allowCommands.info": "Commands like /gamemode, /experience", + "selectWorld.dataPacks": "Data Packs", + "selectWorld.bonusItems": "Bonus Chest", + "selectWorld.import_worldgen_settings": "Import Settings", + "selectWorld.import_worldgen_settings.select_file": "Select settings file (.json)", + "selectWorld.import_worldgen_settings.failure": "Error importing settings", + "selectWorld.warning.experimental.title": "Warning! These settings are using experimental features", + "selectWorld.warning.experimental.question": "These settings are experimental and could one day stop working. Do you wish to proceed?", + "selectWorld.warning.deprecated.title": "Warning! These settings are using deprecated features", + "selectWorld.warning.deprecated.question": "Some features used are deprecated and will stop working in the future. Do you wish to proceed?", + "selectWorld.experimental.title": "Experimental Features Warning", + "selectWorld.experimental.message": "Be careful!\nSome of the selected packs require features that are still under development. Your world might crash, break or not work with future updates.", + "selectWorld.experimental.details": "Details", + "selectWorld.experimental.details.title": "Experimental feature requirements", + "selectWorld.experimental.details.entry": "Required experimental features: %s", + "generator.custom": "Custom", + "generator.minecraft.normal": "Default", + "generator.minecraft.flat": "Superflat", + "generator.minecraft.large_biomes": "Large Biomes", + "generator.minecraft.amplified": "AMPLIFIED", + "generator.minecraft.amplified.info": "Notice: Just for fun! Requires a beefy computer.", + "generator.minecraft.debug_all_block_states": "Debug Mode", + "generator.minecraft.single_biome_surface": "Single Biome", + "generator.customized": "Old Customized", + "generator.single_biome_caves": "Caves", + "generator.single_biome_floating_islands": "Floating Islands", + "selectServer.title": "Select Server", + "selectServer.select": "Join Server", + "selectServer.direct": "Direct Connection", + "selectServer.edit": "Edit", + "selectServer.delete": "Delete", + "selectServer.add": "Add Server", + "selectServer.defaultName": "Minecraft Server", + "selectServer.deleteQuestion": "Are you sure you want to remove this server?", + "selectServer.deleteWarning": "'%s' will be lost forever! (A long time!)", + "selectServer.deleteButton": "Delete", + "selectServer.refresh": "Refresh", + "selectServer.hiddenAddress": "(Hidden)", + "addServer.title": "Edit Server Info", + "addServer.enterName": "Server Name", + "addServer.enterIp": "Server Address", + "addServer.add": "Done", + "addServer.hideAddress": "Hide Address", + "addServer.resourcePack": "Server Resource Packs", + "addServer.resourcePack.enabled": "Enabled", + "addServer.resourcePack.disabled": "Disabled", + "addServer.resourcePack.prompt": "Prompt", + "lanServer.title": "LAN World", + "lanServer.scanning": "Scanning for games on your local network", + "lanServer.start": "Start LAN World", + "lanServer.otherPlayers": "Settings for Other Players", + "lanServer.port": "Port Number", + "lanServer.port.unavailable": "Port not available.\nLeave the edit box empty or enter a different number between 1024 and 65535.", + "lanServer.port.unavailable.new": "Port not available.\nLeave the edit box empty or enter a different number between %s and %s.", + "lanServer.port.invalid": "Not a valid port.\nLeave the edit box empty or enter a number between 1024 and 65535.", + "lanServer.port.invalid.new": "Not a valid port.\nLeave the edit box empty or enter a number between %s and %s.", + "multiplayerWarning.header": "Caution: Third-Party Online Play", + "multiplayerWarning.message": "Caution: Online play is offered by third-party servers that are not owned, operated, or supervised by Mojang Studios or Microsoft. During online play, you may be exposed to unmoderated chat messages or other types of user-generated content that may not be suitable for everyone.", + "multiplayerWarning.check": "Do not show this screen again", + "multiplayer.title": "Play Multiplayer", + "multiplayer.texturePrompt.line1": "This server recommends the use of a custom resource pack.", + "multiplayer.texturePrompt.line2": "Would you like to download and install it automagically?", + "multiplayer.requiredTexturePrompt.line1": "This server requires the use of a custom resource pack.", + "multiplayer.requiredTexturePrompt.line2": "Rejecting this custom resource pack will disconnect you from this server.", + "multiplayer.requiredTexturePrompt.disconnect": "Server requires a custom resource pack", + "multiplayer.texturePrompt.failure.line1": "Server resource pack couldn't be applied", + "multiplayer.texturePrompt.failure.line2": "Any functionality that requires custom resources might not work as expected", + "multiplayer.texturePrompt.serverPrompt": "%s\n\nMessage from server:\n%s", + "multiplayer.applyingPack": "Applying resource pack", + "multiplayer.downloadingTerrain": "Loading terrain...", + "multiplayer.downloadingStats": "Retrieving statistics...", + "multiplayer.stopSleeping": "Leave Bed", + "multiplayer.message_not_delivered": "Can't deliver chat message, check server logs: %s", + "multiplayer.player.joined": "%s joined the game", + "multiplayer.player.joined.renamed": "%s (formerly known as %s) joined the game", + "multiplayer.player.left": "%s left the game", + "multiplayer.status.and_more": "... and %s more ...", + "multiplayer.status.cancelled": "Cancelled", + "multiplayer.status.cannot_connect": "Can't connect to server", + "multiplayer.status.cannot_resolve": "Can't resolve hostname", + "multiplayer.status.finished": "Finished", + "multiplayer.status.incompatible": "Incompatible version!", + "multiplayer.status.no_connection": "(no connection)", + "multiplayer.status.ping": "%s ms", + "multiplayer.status.old": "Old", + "multiplayer.status.pinging": "Pinging...", + "multiplayer.status.quitting": "Quitting", + "multiplayer.status.unknown": "???", + "multiplayer.status.unrequested": "Received unrequested status", + "multiplayer.status.request_handled": "Status request has been handled", + "multiplayer.disconnect.authservers_down": "Authentication servers are down. Please try again later, sorry!", + "multiplayer.disconnect.banned": "You are banned from this server", + "multiplayer.disconnect.banned.reason": "You are banned from this server.\nReason: %s", + "multiplayer.disconnect.banned.expiration": "\nYour ban will be removed on %s", + "multiplayer.disconnect.banned_ip.reason": "Your IP address is banned from this server.\nReason: %s", + "multiplayer.disconnect.banned_ip.expiration": "\nYour ban will be removed on %s", + "multiplayer.disconnect.duplicate_login": "You logged in from another location", + "multiplayer.disconnect.flying": "Flying is not enabled on this server", + "multiplayer.disconnect.generic": "Disconnected", + "multiplayer.disconnect.idling": "You have been idle for too long!", + "multiplayer.disconnect.illegal_characters": "Illegal characters in chat", + "multiplayer.disconnect.invalid_entity_attacked": "Attempting to attack an invalid entity", + "multiplayer.disconnect.invalid_packet": "Server sent an invalid packet", + "multiplayer.disconnect.invalid_player_data": "Invalid player data", + "multiplayer.disconnect.invalid_player_movement": "Invalid move player packet received", + "multiplayer.disconnect.invalid_vehicle_movement": "Invalid move vehicle packet received", + "multiplayer.disconnect.ip_banned": "You have been IP banned from this server", + "multiplayer.disconnect.kicked": "Kicked by an operator", + "multiplayer.disconnect.incompatible": "Incompatible client! Please use %s", + "multiplayer.disconnect.outdated_client": "Incompatible client! Please use %s", + "multiplayer.disconnect.outdated_server": "Incompatible client! Please use %s", + "multiplayer.disconnect.server_shutdown": "Server closed", + "multiplayer.disconnect.slow_login": "Took too long to log in", + "multiplayer.disconnect.unverified_username": "Failed to verify username!", + "multiplayer.disconnect.not_whitelisted": "You are not white-listed on this server!", + "multiplayer.disconnect.server_full": "The server is full!", + "multiplayer.disconnect.name_taken": "That name is already taken", + "multiplayer.disconnect.unexpected_query_response": "Unexpected custom data from client", + "multiplayer.disconnect.missing_tags": "Incomplete set of tags received from server.\nPlease contact server operator.", + "multiplayer.disconnect.expired_public_key": "Expired profile public key. Check that your system time is synchronized, and try restarting your game.", + "multiplayer.disconnect.invalid_public_key_signature": "Invalid signature for profile public key.\nTry restarting your game.", + "multiplayer.disconnect.out_of_order_chat": "Out-of-order chat packet received. Did your system time change?", + "multiplayer.disconnect.unsigned_chat": "Received chat packet with missing or invalid signature.", + "multiplayer.disconnect.too_many_pending_chats": "Too many unacknowledged chat messages", + "multiplayer.disconnect.chat_validation_failed": "Chat message validation failure", + "multiplayer.socialInteractions.not_available": "Social Interactions are only available in Multiplayer worlds", + "multiplayer.unsecureserver.toast.title": "Chat messages can't be verified", + "multiplayer.unsecureserver.toast": "Messages sent on this server may be modified and might not reflect the original message", + "chat.editBox": "chat", + "chat.cannotSend": "Cannot send chat message", + "chat.disabled.options": "Chat disabled in client options", + "chat.disabled.launcher": "Chat disabled by launcher option. Cannot send message", + "chat.disabled.profile": "Chat not allowed by account settings. Press '%s' again for more information", + "chat.disabled.profile.moreInfo": "Chat not allowed by account settings. Cannot send or view messages.", + "chat.disabled.expiredProfileKey": "Chat disabled due to expired profile public key. Please try reconnecting.", + "chat.disabled.chain_broken": "Chat disabled due to broken chain. Please try reconnecting.", + "chat.disabled.missingProfileKey": "Chat disabled due to missing profile public key. Please try reconnecting.", + "chat.type.text": "<%s> %s", + "chat.type.text.narrate": "%s says %s", + "chat.type.emote": "* %s %s", + "chat.type.announcement": "[%s] %s", + "chat.type.admin": "[%s: %s]", + "chat.type.advancement.task": "%s has made the advancement %s", + "chat.type.advancement.challenge": "%s has completed the challenge %s", + "chat.type.advancement.goal": "%s has reached the goal %s", + "chat.type.team.text": "%s <%s> %s", + "chat.type.team.sent": "-> %s <%s> %s", + "chat.type.team.hover": "Message Team", + "chat.link.confirm": "Are you sure you want to open the following website?", + "chat.link.warning": "Never open links from people that you don't trust!", + "chat.copy": "Copy to Clipboard", + "chat.copy.click": "Click to Copy to Clipboard", + "chat.link.confirmTrusted": "Do you want to open this link or copy it to your clipboard?", + "chat.link.open": "Open in Browser", + "chat.coordinates": "%s, %s, %s", + "chat.coordinates.tooltip": "Click to teleport", + "chat.queue": "[+%s pending lines]", + "chat.square_brackets": "[%s]", + "chat.tag.system": "Server message. Cannot be reported.", + "chat.tag.system_single_player": "Server message.", + "chat.tag.not_secure": "Unverified message. Cannot be reported.", + "chat.tag.modified": "Message modified by the server. Original:", + "chat.filtered_full": "The server has hidden your message for some players.", + "chat.filtered": "Filtered by the server.", + "chat.deleted_marker": "This chat message has been deleted by the server.", + "menu.playdemo": "Play Demo World", + "menu.resetdemo": "Reset Demo World", + "demo.day.1": "This demo will last five game days. Do your best!", + "demo.day.2": "Day Two", + "demo.day.3": "Day Three", + "demo.day.4": "Day Four", + "demo.day.5": "This is your last day!", + "demo.day.warning": "Your time is almost up!", + "demo.day.6": "You have passed your fifth day. Use %s to save a screenshot of your creation.", + "demo.reminder": "The demo time has expired. Buy the game to continue or start a new world!", + "demo.remainingTime": "Remaining time: %s", + "demo.demoExpired": "Demo time's up!", + "demo.help.movement": "Use the %1$s, %2$s, %3$s, %4$s keys and the mouse to move around", + "demo.help.movementShort": "Move by pressing the %1$s, %2$s, %3$s, %4$s keys", + "demo.help.movementMouse": "Look around using the mouse", + "demo.help.jump": "Jump by pressing the %1$s key", + "demo.help.inventory": "Use the %1$s key to open your inventory", + "demo.help.title": "Minecraft Demo Mode", + "demo.help.fullWrapped": "This demo will last 5 in-game days (about 1 hour and 40 minutes of real time). Check the advancements for hints! Have fun!", + "demo.help.buy": "Purchase Now!", + "demo.help.later": "Continue Playing!", + "connect.connecting": "Connecting to the server...", + "connect.aborted": "Aborted", + "connect.authorizing": "Logging in...", + "connect.negotiating": "Negotiating...", + "connect.encrypting": "Encrypting...", + "connect.joining": "Joining world...", + "connect.failed": "Failed to connect to the server", + "disconnect.genericReason": "%s", + "disconnect.unknownHost": "Unknown host", + "disconnect.disconnected": "Disconnected by Server", + "disconnect.lost": "Connection Lost", + "disconnect.kicked": "Was kicked from the game", + "disconnect.timeout": "Timed out", + "disconnect.closed": "Connection closed", + "disconnect.loginFailed": "Failed to log in", + "disconnect.loginFailedInfo": "Failed to log in: %s", + "disconnect.loginFailedInfo.serversUnavailable": "The authentication servers are currently not reachable. Please try again.", + "disconnect.loginFailedInfo.invalidSession": "Invalid session (Try restarting your game and the launcher)", + "disconnect.loginFailedInfo.insufficientPrivileges": "Multiplayer is disabled. Please check your Microsoft account settings.", + "disconnect.loginFailedInfo.userBanned": "You are banned from playing online", + "disconnect.quitting": "Quitting", + "disconnect.endOfStream": "End of stream", + "disconnect.overflow": "Buffer overflow", + "disconnect.spam": "Kicked for spamming", + "disconnect.exceeded_packet_rate": "Kicked for exceeding packet rate limit", + "soundCategory.master": "Master Volume", + "soundCategory.music": "Music", + "soundCategory.record": "Jukebox/Note Blocks", + "soundCategory.weather": "Weather", + "soundCategory.hostile": "Hostile Creatures", + "soundCategory.neutral": "Friendly Creatures", + "soundCategory.player": "Players", + "soundCategory.block": "Blocks", + "soundCategory.ambient": "Ambient/Environment", + "soundCategory.voice": "Voice/Speech", + "record.nowPlaying": "Now Playing: %s", + "options.off": "OFF", + "options.on": "ON", + "options.off.composed": "%s: OFF", + "options.on.composed": "%s: ON", + "options.generic_value": "%s: %s", + "options.pixel_value": "%s: %spx", + "options.percent_value": "%s: %s%%", + "options.percent_add_value": "%s: +%s%%", + "options.visible": "Shown", + "options.hidden": "Hidden", + "options.title": "Options", + "options.controls": "Controls...", + "options.video": "Video Settings...", + "options.language": "Language...", + "options.sounds": "Music & Sounds...", + "options.sounds.title": "Music & Sound Options", + "options.languageWarning": "Language translations may not be 100%% accurate", + "options.videoTitle": "Video Settings", + "options.mouse_settings": "Mouse Settings...", + "options.mouse_settings.title": "Mouse Settings", + "options.customizeTitle": "Customize World Settings", + "options.invertMouse": "Invert Mouse", + "options.fov": "FOV", + "options.fov.min": "Normal", + "options.fov.max": "Quake Pro", + "options.screenEffectScale": "Distortion Effects", + "options.screenEffectScale.tooltip": "Strength of nausea and Nether portal screen distortion effects.\nAt lower values, the nausea effect is replaced with a green overlay.", + "options.fovEffectScale": "FOV Effects", + "options.fovEffectScale.tooltip": "Controls how much the field of view can change with gameplay effects.", + "options.darknessEffectScale": "Darkness Pulsing", + "options.darknessEffectScale.tooltip": "Controls how much the Darkness effect pulses when a Warden or Sculk Shrieker gives it to you.", + "options.biomeBlendRadius": "Biome Blend", + "options.biomeBlendRadius.1": "OFF (Fastest)", + "options.biomeBlendRadius.3": "3x3 (Fast)", + "options.biomeBlendRadius.5": "5x5 (Normal)", + "options.biomeBlendRadius.7": "7x7 (High)", + "options.biomeBlendRadius.9": "9x9 (Very High)", + "options.biomeBlendRadius.11": "11x11 (Extreme)", + "options.biomeBlendRadius.13": "13x13 (Showoff)", + "options.biomeBlendRadius.15": "15x15 (Maximum)", + "options.gamma": "Brightness", + "options.gamma.min": "Moody", + "options.gamma.default": "Default", + "options.gamma.max": "Bright", + "options.sensitivity": "Sensitivity", + "options.sensitivity.min": "*yawn*", + "options.sensitivity.max": "HYPERSPEED!!!", + "options.renderDistance": "Render Distance", + "options.simulationDistance": "Simulation Distance", + "options.entityDistanceScaling": "Entity Distance", + "options.viewBobbing": "View Bobbing", + "options.ao": "Smooth Lighting", + "options.ao.off": "OFF", + "options.ao.min": "Minimum", + "options.ao.max": "Maximum", + "options.prioritizeChunkUpdates": "Chunk Builder", + "options.prioritizeChunkUpdates.none": "Threaded", + "options.prioritizeChunkUpdates.byPlayer": "Semi Blocking", + "options.prioritizeChunkUpdates.nearby": "Fully Blocking", + "options.prioritizeChunkUpdates.none.tooltip": "Nearby chunks are compiled in parallel threads. This may result in brief visual holes when blocks are destroyed.", + "options.prioritizeChunkUpdates.byPlayer.tooltip": "Some actions within a chunk will recompile the chunk immediately. This includes block placing & destroying.", + "options.prioritizeChunkUpdates.nearby.tooltip": "Nearby chunks are always compiled immediately. This may impact game performance when blocks are placed or destroyed.", + "options.chunks": "%s chunks", + "options.framerate": "%s fps", + "options.framerateLimit": "Max Framerate", + "options.framerateLimit.max": "Unlimited", + "options.difficulty": "Difficulty", + "options.difficulty.online": "Server Difficulty", + "options.difficulty.peaceful": "Peaceful", + "options.difficulty.easy": "Easy", + "options.difficulty.normal": "Normal", + "options.difficulty.hard": "Hard", + "options.difficulty.hardcore": "Hardcore", + "options.graphics": "Graphics", + "options.graphics.fabulous.tooltip": "%s graphics uses screen shaders for drawing weather, clouds, and particles behind translucent blocks and water.\nThis may severely impact performance for portable devices and 4K displays.", + "options.graphics.fabulous": "Fabulous!", + "options.graphics.fancy.tooltip": "Fancy graphics balances performance and quality for the majority of machines.\nWeather, clouds, and particles may not appear behind translucent blocks or water.", + "options.graphics.fancy": "Fancy", + "options.graphics.fast.tooltip": "Fast graphics reduces the amount of visible rain and snow.\nTransparency effects are disabled for various blocks such as leaves.", + "options.graphics.fast": "Fast", + "options.graphics.warning.title": "Graphics Device Unsupported", + "options.graphics.warning.message": "Your graphics device is detected as unsupported for the %s graphics option.\n\nYou may ignore this and continue, however support will not be provided for your device if you choose to use %s graphics.", + "options.graphics.warning.renderer": "Renderer detected: [%s]", + "options.graphics.warning.vendor": "Vendor detected: [%s]", + "options.graphics.warning.version": "OpenGL Version detected: [%s]", + "options.graphics.warning.accept": "Continue without Support", + "options.graphics.warning.cancel": "Take me Back", + "options.clouds.fancy": "Fancy", + "options.clouds.fast": "Fast", + "options.guiScale": "GUI Scale", + "options.guiScale.auto": "Auto", + "options.renderClouds": "Clouds", + "options.particles": "Particles", + "options.particles.all": "All", + "options.particles.decreased": "Decreased", + "options.particles.minimal": "Minimal", + "options.multiplayer.title": "Multiplayer Settings...", + "options.chat.title": "Chat Settings...", + "options.chat.visibility": "Chat", + "options.chat.visibility.full": "Shown", + "options.chat.visibility.system": "Commands Only", + "options.chat.visibility.hidden": "Hidden", + "options.chat.color": "Colors", + "options.chat.opacity": "Chat Text Opacity", + "options.chat.line_spacing": "Line Spacing", + "options.chat.links": "Web Links", + "options.chat.links.prompt": "Prompt on Links", + "options.chat.delay_none": "Chat Delay: None", + "options.chat.delay": "Chat Delay: %s seconds", + "options.chat.scale": "Chat Text Size", + "options.chat.width": "Width", + "options.chat.height.focused": "Focused Height", + "options.chat.height.unfocused": "Unfocused Height", + "options.onlyShowSecureChat": "Only Show Secure Chat", + "options.onlyShowSecureChat.tooltip": "Only display messages from other players that can be verified to have been sent by that player, and have not been modified.", + "options.accessibility.title": "Accessibility Settings...", + "options.accessibility.text_background": "Text Background", + "options.accessibility.text_background.chat": "Chat", + "options.accessibility.text_background.everywhere": "Everywhere", + "options.accessibility.text_background_opacity": "Text Background Opacity", + "options.accessibility.panorama_speed": "Panorama Scroll Speed", + "options.accessibility.link": "Accessibility Guide", + "options.telemetry": "Telemetry Data", + "options.telemetry.button": "Data Collection", + "options.telemetry.state.none": "None", + "options.telemetry.state.minimal": "Minimal", + "options.telemetry.state.all": "All", + "options.telemetry.button.tooltip": "\"%s\" includes only the required data.\n\"%s\" includes optional, as well as the required data.", + "options.audioDevice": "Device", + "options.audioDevice.default": "System Default", + "options.key.toggle": "Toggle", + "options.key.hold": "Hold", + "options.skinCustomisation": "Skin Customization...", + "options.skinCustomisation.title": "Skin Customization", + "options.modelPart.cape": "Cape", + "options.modelPart.hat": "Hat", + "options.modelPart.jacket": "Jacket", + "options.modelPart.left_sleeve": "Left Sleeve", + "options.modelPart.right_sleeve": "Right Sleeve", + "options.modelPart.left_pants_leg": "Left Pants Leg", + "options.modelPart.right_pants_leg": "Right Pants Leg", + "options.resourcepack": "Resource Packs...", + "options.fullscreen": "Fullscreen", + "options.vsync": "VSync", + "options.touchscreen": "Touchscreen Mode", + "options.reducedDebugInfo": "Reduced Debug Info", + "options.entityShadows": "Entity Shadows", + "options.mainHand": "Main Hand", + "options.mainHand.left": "Left", + "options.mainHand.right": "Right", + "options.attackIndicator": "Attack Indicator", + "options.attack.crosshair": "Crosshair", + "options.attack.hotbar": "Hotbar", + "options.showSubtitles": "Show Subtitles", + "options.directionalAudio": "Directional Audio", + "options.directionalAudio.on.tooltip": "Uses HRTF-based directional audio to improve the simulation of 3D sound. Requires HRTF compatible audio hardware, and is best experienced with headphones.", + "options.directionalAudio.off.tooltip": "Classic Stereo sound", + "options.online": "Online...", + "options.online.title": "Online Options", + "options.allowServerListing": "Allow Server Listings", + "options.allowServerListing.tooltip": "Servers may list online players as part of their public status.\nWith this option off your name will not show up in such lists.", + "options.realmsNotifications": "Realms Notifications", + "options.autoJump": "Auto-Jump", + "options.operatorItemsTab": "Operator Items Tab", + "options.autoSuggestCommands": "Command Suggestions", + "options.autosaveIndicator": "Autosave Indicator", + "options.discrete_mouse_scroll": "Discrete Scrolling", + "options.mouseWheelSensitivity": "Scroll Sensitivity", + "options.rawMouseInput": "Raw Input", + "options.narrator": "Narrator", + "options.narrator.off": "OFF", + "options.narrator.all": "Narrates All", + "options.narrator.chat": "Narrates Chat", + "options.narrator.system": "Narrates System", + "options.narrator.notavailable": "Not Available", + "options.fullscreen.resolution": "Fullscreen Resolution", + "options.fullscreen.unavailable": "Setting unavailable", + "options.fullscreen.current": "Current", + "options.mipmapLevels": "Mipmap Levels", + "options.forceUnicodeFont": "Force Unicode Font", + "options.hideMatchedNames": "Hide Matched Names", + "options.hideMatchedNames.tooltip": "3rd-party Servers may send chat messages in non-standard formats.\nWith this option on: hidden players will be matched based on chat sender names.", + "options.darkMojangStudiosBackgroundColor": "Monochrome Logo", + "options.darkMojangStudiosBackgroundColor.tooltip": "Changes the Mojang Studios loading screen background color to black.", + "options.hideLightningFlashes": "Hide Lightning Flashes", + "options.hideLightningFlashes.tooltip": "Prevents lightning bolts from making the sky flash. The bolts themselves will still be visible.", + "narrator.toast.disabled": "Narrator Disabled", + "narrator.toast.enabled": "Narrator Enabled", + "difficulty.lock.title": "Lock World Difficulty", + "difficulty.lock.question": "Are you sure you want to lock the difficulty of this world? This will set this world to always be %1$s, and you will never be able to change that again.", + "title.32bit.deprecation": "32-bit system detected: this may prevent you from playing in the future as a 64-bit system will be required!", + "title.32bit.deprecation.realms.header": "32-bit system detected", + "title.32bit.deprecation.realms": "Minecraft will soon require a 64-bit system, which will prevent you from playing or using Realms on this device. You will need to manually cancel any Realms subscription.", + "title.32bit.deprecation.realms.check": "Do not show this screen again", + "title.multiplayer.disabled": "Multiplayer is disabled. Please check your Microsoft account settings.", + "title.multiplayer.disabled.banned.temporary": "Your account is temporarily suspended from online play", + "title.multiplayer.disabled.banned.permanent": "Your account is permanently suspended from online play", + "controls.title": "Controls", + "controls.reset": "Reset", + "controls.resetAll": "Reset Keys", + "controls.keybinds": "Key Binds...", + "controls.keybinds.title": "Key Binds", + "key.sprint": "Sprint", + "key.forward": "Walk Forwards", + "key.left": "Strafe Left", + "key.back": "Walk Backwards", + "key.right": "Strafe Right", + "key.jump": "Jump", + "key.inventory": "Open/Close Inventory", + "key.drop": "Drop Selected Item", + "key.swapOffhand": "Swap Item With Offhand", + "key.chat": "Open Chat", + "key.sneak": "Sneak", + "key.playerlist": "List Players", + "key.attack": "Attack/Destroy", + "key.use": "Use Item/Place Block", + "key.pickItem": "Pick Block", + "key.command": "Open Command", + "key.socialInteractions": "Social Interactions Screen", + "key.screenshot": "Take Screenshot", + "key.togglePerspective": "Toggle Perspective", + "key.smoothCamera": "Toggle Cinematic Camera", + "key.fullscreen": "Toggle Fullscreen", + "key.spectatorOutlines": "Highlight Players (Spectators)", + "key.hotbar.1": "Hotbar Slot 1", + "key.hotbar.2": "Hotbar Slot 2", + "key.hotbar.3": "Hotbar Slot 3", + "key.hotbar.4": "Hotbar Slot 4", + "key.hotbar.5": "Hotbar Slot 5", + "key.hotbar.6": "Hotbar Slot 6", + "key.hotbar.7": "Hotbar Slot 7", + "key.hotbar.8": "Hotbar Slot 8", + "key.hotbar.9": "Hotbar Slot 9", + "key.saveToolbarActivator": "Save Hotbar Activator", + "key.loadToolbarActivator": "Load Hotbar Activator", + "key.advancements": "Advancements", + "key.categories.movement": "Movement", + "key.categories.misc": "Miscellaneous", + "key.categories.multiplayer": "Multiplayer", + "key.categories.gameplay": "Gameplay", + "key.categories.ui": "Game Interface", + "key.categories.inventory": "Inventory", + "key.categories.creative": "Creative Mode", + "key.mouse.left": "Left Button", + "key.mouse.right": "Right Button", + "key.mouse.middle": "Middle Button", + "key.mouse": "Button %1$s", + "key.keyboard.unknown": "Not bound", + "key.keyboard.apostrophe": "'", + "key.keyboard.backslash": "\\", + "key.keyboard.backspace": "Backspace", + "key.keyboard.comma": ",", + "key.keyboard.delete": "Delete", + "key.keyboard.end": "End", + "key.keyboard.enter": "Enter", + "key.keyboard.equal": "=", + "key.keyboard.escape": "Escape", + "key.keyboard.f1": "F1", + "key.keyboard.f2": "F2", + "key.keyboard.f3": "F3", + "key.keyboard.f4": "F4", + "key.keyboard.f5": "F5", + "key.keyboard.f6": "F6", + "key.keyboard.f7": "F7", + "key.keyboard.f8": "F8", + "key.keyboard.f9": "F9", + "key.keyboard.f10": "F10", + "key.keyboard.f11": "F11", + "key.keyboard.f12": "F12", + "key.keyboard.f13": "F13", + "key.keyboard.f14": "F14", + "key.keyboard.f15": "F15", + "key.keyboard.f16": "F16", + "key.keyboard.f17": "F17", + "key.keyboard.f18": "F18", + "key.keyboard.f19": "F19", + "key.keyboard.f20": "F20", + "key.keyboard.f21": "F21", + "key.keyboard.f22": "F22", + "key.keyboard.f23": "F23", + "key.keyboard.f24": "F24", + "key.keyboard.f25": "F25", + "key.keyboard.grave.accent": "`", + "key.keyboard.home": "Home", + "key.keyboard.insert": "Insert", + "key.keyboard.keypad.0": "Keypad 0", + "key.keyboard.keypad.1": "Keypad 1", + "key.keyboard.keypad.2": "Keypad 2", + "key.keyboard.keypad.3": "Keypad 3", + "key.keyboard.keypad.4": "Keypad 4", + "key.keyboard.keypad.5": "Keypad 5", + "key.keyboard.keypad.6": "Keypad 6", + "key.keyboard.keypad.7": "Keypad 7", + "key.keyboard.keypad.8": "Keypad 8", + "key.keyboard.keypad.9": "Keypad 9", + "key.keyboard.keypad.add": "Keypad +", + "key.keyboard.keypad.decimal": "Keypad Decimal", + "key.keyboard.keypad.enter": "Keypad Enter", + "key.keyboard.keypad.equal": "Keypad =", + "key.keyboard.keypad.multiply": "Keypad *", + "key.keyboard.keypad.divide": "Keypad /", + "key.keyboard.keypad.subtract": "Keypad -", + "key.keyboard.left.bracket": "[", + "key.keyboard.right.bracket": "]", + "key.keyboard.minus": "-", + "key.keyboard.num.lock": "Num Lock", + "key.keyboard.caps.lock": "Caps Lock", + "key.keyboard.scroll.lock": "Scroll Lock", + "key.keyboard.page.down": "Page Down", + "key.keyboard.page.up": "Page Up", + "key.keyboard.pause": "Pause", + "key.keyboard.period": ".", + "key.keyboard.left.control": "Left Control", + "key.keyboard.right.control": "Right Control", + "key.keyboard.left.alt": "Left Alt", + "key.keyboard.right.alt": "Right Alt", + "key.keyboard.left.shift": "Left Shift", + "key.keyboard.right.shift": "Right Shift", + "key.keyboard.left.win": "Left Win", + "key.keyboard.right.win": "Right Win", + "key.keyboard.semicolon": ";", + "key.keyboard.slash": "/", + "key.keyboard.space": "Space", + "key.keyboard.tab": "Tab", + "key.keyboard.up": "Up Arrow", + "key.keyboard.down": "Down Arrow", + "key.keyboard.left": "Left Arrow", + "key.keyboard.right": "Right Arrow", + "key.keyboard.menu": "Menu", + "key.keyboard.print.screen": "Print Screen", + "key.keyboard.world.1": "World 1", + "key.keyboard.world.2": "World 2", + "pack.available.title": "Available", + "pack.selected.title": "Selected", + "pack.incompatible": "Incompatible", + "pack.incompatible.old": "(Made for an older version of Minecraft)", + "pack.incompatible.new": "(Made for a newer version of Minecraft)", + "pack.incompatible.confirm.title": "Are you sure you want to load this pack?", + "pack.incompatible.confirm.old": "This pack was made for an older version of Minecraft and may no longer work correctly.", + "pack.incompatible.confirm.new": "This pack was made for a newer version of Minecraft and may not work correctly.", + "pack.dropInfo": "Drag and drop files into this window to add packs", + "pack.dropConfirm": "Do you want to add the following packs to Minecraft?", + "pack.copyFailure": "Failed to copy packs", + "pack.nameAndSource": "%s (%s)", + "pack.openFolder": "Open Pack Folder", + "pack.folderInfo": "(Place pack files here)", + "resourcePack.title": "Select Resource Packs", + "resourcePack.server.name": "World Specific Resources", + "resourcePack.programmer_art.name": "Programmer Art", + "resourcePack.broken_assets": "BROKEN ASSETS DETECTED", + "resourcePack.vanilla.name": "Default", + "resourcePack.vanilla.description": "The default look and feel of Minecraft", + "resourcePack.load_fail": "Resource reload failed", + "dataPack.title": "Select Data Packs", + "dataPack.validation.working": "Validating selected data packs...", + "dataPack.validation.failed": "Data pack validation failed!", + "dataPack.validation.back": "Go Back", + "dataPack.validation.reset": "Reset to Default", + "dataPack.vanilla.name": "Default", + "dataPack.vanilla.description": "The default data for Minecraft", + "dataPack.bundle.description": "Enables experimental Bundle item", + "dataPack.update_1_20.description": "New features and content for Minecraft 1.20", + "sign.edit": "Edit Sign Message", + "hanging_sign.edit": "Edit Hanging Sign Message", + "book.pageIndicator": "Page %1$s of %2$s", + "book.byAuthor": "by %1$s", + "book.signButton": "Sign", + "book.editTitle": "Enter Book Title:", + "book.finalizeButton": "Sign and Close", + "book.finalizeWarning": "Note! When you sign the book, it will no longer be editable.", + "book.generation.0": "Original", + "book.generation.1": "Copy of original", + "book.generation.2": "Copy of a copy", + "book.generation.3": "Tattered", + "book.invalid.tag": "* Invalid book tag *", + "merchant.deprecated": "Villagers restock up to two times per day.", + "merchant.current_level": "Trader's current level", + "merchant.next_level": "Trader's next level", + "merchant.level.1": "Novice", + "merchant.level.2": "Apprentice", + "merchant.level.3": "Journeyman", + "merchant.level.4": "Expert", + "merchant.level.5": "Master", + "merchant.trades": "Trades", + "block.minecraft.air": "Air", + "block.minecraft.barrier": "Barrier", + "block.minecraft.light": "Light", + "block.minecraft.stone": "Stone", + "block.minecraft.granite": "Granite", + "block.minecraft.polished_granite": "Polished Granite", + "block.minecraft.diorite": "Diorite", + "block.minecraft.polished_diorite": "Polished Diorite", + "block.minecraft.andesite": "Andesite", + "block.minecraft.polished_andesite": "Polished Andesite", + "block.minecraft.hay_block": "Hay Bale", + "block.minecraft.grass_block": "Grass Block", + "block.minecraft.dirt": "Dirt", + "block.minecraft.coarse_dirt": "Coarse Dirt", + "block.minecraft.podzol": "Podzol", + "block.minecraft.cobblestone": "Cobblestone", + "block.minecraft.oak_planks": "Oak Planks", + "block.minecraft.spruce_planks": "Spruce Planks", + "block.minecraft.birch_planks": "Birch Planks", + "block.minecraft.jungle_planks": "Jungle Planks", + "block.minecraft.acacia_planks": "Acacia Planks", + "block.minecraft.dark_oak_planks": "Dark Oak Planks", + "block.minecraft.mangrove_planks": "Mangrove Planks", + "block.minecraft.bamboo_planks": "Bamboo Planks", + "block.minecraft.bamboo_mosaic": "Bamboo Mosaic", + "block.minecraft.oak_sapling": "Oak Sapling", + "block.minecraft.spruce_sapling": "Spruce Sapling", + "block.minecraft.birch_sapling": "Birch Sapling", + "block.minecraft.jungle_sapling": "Jungle Sapling", + "block.minecraft.acacia_sapling": "Acacia Sapling", + "block.minecraft.dark_oak_sapling": "Dark Oak Sapling", + "block.minecraft.mangrove_propagule": "Mangrove Propagule", + "block.minecraft.oak_door": "Oak Door", + "block.minecraft.spruce_door": "Spruce Door", + "block.minecraft.birch_door": "Birch Door", + "block.minecraft.jungle_door": "Jungle Door", + "block.minecraft.acacia_door": "Acacia Door", + "block.minecraft.dark_oak_door": "Dark Oak Door", + "block.minecraft.mangrove_door": "Mangrove Door", + "block.minecraft.bamboo_door": "Bamboo Door", + "block.minecraft.bedrock": "Bedrock", + "block.minecraft.water": "Water", + "block.minecraft.lava": "Lava", + "block.minecraft.sand": "Sand", + "block.minecraft.red_sand": "Red Sand", + "block.minecraft.sandstone": "Sandstone", + "block.minecraft.chiseled_sandstone": "Chiseled Sandstone", + "block.minecraft.cut_sandstone": "Cut Sandstone", + "block.minecraft.red_sandstone": "Red Sandstone", + "block.minecraft.chiseled_red_sandstone": "Chiseled Red Sandstone", + "block.minecraft.cut_red_sandstone": "Cut Red Sandstone", + "block.minecraft.gravel": "Gravel", + "block.minecraft.gold_ore": "Gold Ore", + "block.minecraft.deepslate_gold_ore": "Deepslate Gold Ore", + "block.minecraft.nether_gold_ore": "Nether Gold Ore", + "block.minecraft.iron_ore": "Iron Ore", + "block.minecraft.deepslate_iron_ore": "Deepslate Iron Ore", + "block.minecraft.coal_ore": "Coal Ore", + "block.minecraft.deepslate_coal_ore": "Deepslate Coal Ore", + "block.minecraft.oak_wood": "Oak Wood", + "block.minecraft.spruce_wood": "Spruce Wood", + "block.minecraft.birch_wood": "Birch Wood", + "block.minecraft.jungle_wood": "Jungle Wood", + "block.minecraft.acacia_wood": "Acacia Wood", + "block.minecraft.dark_oak_wood": "Dark Oak Wood", + "block.minecraft.mangrove_wood": "Mangrove Wood", + "block.minecraft.oak_log": "Oak Log", + "block.minecraft.spruce_log": "Spruce Log", + "block.minecraft.birch_log": "Birch Log", + "block.minecraft.jungle_log": "Jungle Log", + "block.minecraft.acacia_log": "Acacia Log", + "block.minecraft.dark_oak_log": "Dark Oak Log", + "block.minecraft.mangrove_log": "Mangrove Log", + "block.minecraft.mangrove_roots": "Mangrove Roots", + "block.minecraft.muddy_mangrove_roots": "Muddy Mangrove Roots", + "block.minecraft.bamboo_block": "Block of Bamboo", + "block.minecraft.stripped_oak_log": "Stripped Oak Log", + "block.minecraft.stripped_spruce_log": "Stripped Spruce Log", + "block.minecraft.stripped_birch_log": "Stripped Birch Log", + "block.minecraft.stripped_jungle_log": "Stripped Jungle Log", + "block.minecraft.stripped_acacia_log": "Stripped Acacia Log", + "block.minecraft.stripped_dark_oak_log": "Stripped Dark Oak Log", + "block.minecraft.stripped_mangrove_log": "Stripped Mangrove Log", + "block.minecraft.stripped_bamboo_block": "Block of Stripped Bamboo", + "block.minecraft.stripped_oak_wood": "Stripped Oak Wood", + "block.minecraft.stripped_spruce_wood": "Stripped Spruce Wood", + "block.minecraft.stripped_birch_wood": "Stripped Birch Wood", + "block.minecraft.stripped_jungle_wood": "Stripped Jungle Wood", + "block.minecraft.stripped_acacia_wood": "Stripped Acacia Wood", + "block.minecraft.stripped_dark_oak_wood": "Stripped Dark Oak Wood", + "block.minecraft.stripped_mangrove_wood": "Stripped Mangrove Wood", + "block.minecraft.oak_leaves": "Oak Leaves", + "block.minecraft.spruce_leaves": "Spruce Leaves", + "block.minecraft.birch_leaves": "Birch Leaves", + "block.minecraft.jungle_leaves": "Jungle Leaves", + "block.minecraft.acacia_leaves": "Acacia Leaves", + "block.minecraft.dark_oak_leaves": "Dark Oak Leaves", + "block.minecraft.mangrove_leaves": "Mangrove Leaves", + "block.minecraft.dead_bush": "Dead Bush", + "block.minecraft.grass": "Grass", + "block.minecraft.fern": "Fern", + "block.minecraft.sponge": "Sponge", + "block.minecraft.wet_sponge": "Wet Sponge", + "block.minecraft.glass": "Glass", + "block.minecraft.kelp_plant": "Kelp Plant", + "block.minecraft.kelp": "Kelp", + "block.minecraft.dried_kelp_block": "Dried Kelp Block", + "block.minecraft.white_stained_glass": "White Stained Glass", + "block.minecraft.orange_stained_glass": "Orange Stained Glass", + "block.minecraft.magenta_stained_glass": "Magenta Stained Glass", + "block.minecraft.light_blue_stained_glass": "Light Blue Stained Glass", + "block.minecraft.yellow_stained_glass": "Yellow Stained Glass", + "block.minecraft.lime_stained_glass": "Lime Stained Glass", + "block.minecraft.pink_stained_glass": "Pink Stained Glass", + "block.minecraft.gray_stained_glass": "Gray Stained Glass", + "block.minecraft.light_gray_stained_glass": "Light Gray Stained Glass", + "block.minecraft.cyan_stained_glass": "Cyan Stained Glass", + "block.minecraft.purple_stained_glass": "Purple Stained Glass", + "block.minecraft.blue_stained_glass": "Blue Stained Glass", + "block.minecraft.brown_stained_glass": "Brown Stained Glass", + "block.minecraft.green_stained_glass": "Green Stained Glass", + "block.minecraft.red_stained_glass": "Red Stained Glass", + "block.minecraft.black_stained_glass": "Black Stained Glass", + "block.minecraft.white_stained_glass_pane": "White Stained Glass Pane", + "block.minecraft.orange_stained_glass_pane": "Orange Stained Glass Pane", + "block.minecraft.magenta_stained_glass_pane": "Magenta Stained Glass Pane", + "block.minecraft.light_blue_stained_glass_pane": "Light Blue Stained Glass Pane", + "block.minecraft.yellow_stained_glass_pane": "Yellow Stained Glass Pane", + "block.minecraft.lime_stained_glass_pane": "Lime Stained Glass Pane", + "block.minecraft.pink_stained_glass_pane": "Pink Stained Glass Pane", + "block.minecraft.gray_stained_glass_pane": "Gray Stained Glass Pane", + "block.minecraft.light_gray_stained_glass_pane": "Light Gray Stained Glass Pane", + "block.minecraft.cyan_stained_glass_pane": "Cyan Stained Glass Pane", + "block.minecraft.purple_stained_glass_pane": "Purple Stained Glass Pane", + "block.minecraft.blue_stained_glass_pane": "Blue Stained Glass Pane", + "block.minecraft.brown_stained_glass_pane": "Brown Stained Glass Pane", + "block.minecraft.green_stained_glass_pane": "Green Stained Glass Pane", + "block.minecraft.red_stained_glass_pane": "Red Stained Glass Pane", + "block.minecraft.black_stained_glass_pane": "Black Stained Glass Pane", + "block.minecraft.glass_pane": "Glass Pane", + "block.minecraft.dandelion": "Dandelion", + "block.minecraft.poppy": "Poppy", + "block.minecraft.blue_orchid": "Blue Orchid", + "block.minecraft.allium": "Allium", + "block.minecraft.azure_bluet": "Azure Bluet", + "block.minecraft.red_tulip": "Red Tulip", + "block.minecraft.orange_tulip": "Orange Tulip", + "block.minecraft.white_tulip": "White Tulip", + "block.minecraft.pink_tulip": "Pink Tulip", + "block.minecraft.oxeye_daisy": "Oxeye Daisy", + "block.minecraft.cornflower": "Cornflower", + "block.minecraft.lily_of_the_valley": "Lily of the Valley", + "block.minecraft.wither_rose": "Wither Rose", + "block.minecraft.sunflower": "Sunflower", + "block.minecraft.lilac": "Lilac", + "block.minecraft.tall_grass": "Tall Grass", + "block.minecraft.tall_seagrass": "Tall Seagrass", + "block.minecraft.large_fern": "Large Fern", + "block.minecraft.rose_bush": "Rose Bush", + "block.minecraft.peony": "Peony", + "block.minecraft.seagrass": "Seagrass", + "block.minecraft.sea_pickle": "Sea Pickle", + "block.minecraft.brown_mushroom": "Brown Mushroom", + "block.minecraft.red_mushroom_block": "Red Mushroom Block", + "block.minecraft.brown_mushroom_block": "Brown Mushroom Block", + "block.minecraft.mushroom_stem": "Mushroom Stem", + "block.minecraft.gold_block": "Block of Gold", + "block.minecraft.iron_block": "Block of Iron", + "block.minecraft.smooth_stone": "Smooth Stone", + "block.minecraft.smooth_sandstone": "Smooth Sandstone", + "block.minecraft.smooth_red_sandstone": "Smooth Red Sandstone", + "block.minecraft.smooth_quartz": "Smooth Quartz Block", + "block.minecraft.stone_slab": "Stone Slab", + "block.minecraft.smooth_stone_slab": "Smooth Stone Slab", + "block.minecraft.sandstone_slab": "Sandstone Slab", + "block.minecraft.red_sandstone_slab": "Red Sandstone Slab", + "block.minecraft.cut_sandstone_slab": "Cut Sandstone Slab", + "block.minecraft.cut_red_sandstone_slab": "Cut Red Sandstone Slab", + "block.minecraft.petrified_oak_slab": "Petrified Oak Slab", + "block.minecraft.cobblestone_slab": "Cobblestone Slab", + "block.minecraft.brick_slab": "Brick Slab", + "block.minecraft.stone_brick_slab": "Stone Brick Slab", + "block.minecraft.mud_brick_slab": "Mud Brick Slab", + "block.minecraft.nether_brick_slab": "Nether Brick Slab", + "block.minecraft.quartz_slab": "Quartz Slab", + "block.minecraft.oak_slab": "Oak Slab", + "block.minecraft.spruce_slab": "Spruce Slab", + "block.minecraft.birch_slab": "Birch Slab", + "block.minecraft.jungle_slab": "Jungle Slab", + "block.minecraft.acacia_slab": "Acacia Slab", + "block.minecraft.dark_oak_slab": "Dark Oak Slab", + "block.minecraft.mangrove_slab": "Mangrove Slab", + "block.minecraft.bamboo_slab": "Bamboo Slab", + "block.minecraft.bamboo_mosaic_slab": "Bamboo Mosaic Slab", + "block.minecraft.dark_prismarine_slab": "Dark Prismarine Slab", + "block.minecraft.prismarine_slab": "Prismarine Slab", + "block.minecraft.prismarine_brick_slab": "Prismarine Brick Slab", + "block.minecraft.bricks": "Bricks", + "block.minecraft.tnt": "TNT", + "block.minecraft.bookshelf": "Bookshelf", + "block.minecraft.chiseled_bookshelf": "Chiseled Bookshelf", + "block.minecraft.mossy_cobblestone": "Mossy Cobblestone", + "block.minecraft.obsidian": "Obsidian", + "block.minecraft.torch": "Torch", + "block.minecraft.wall_torch": "Wall Torch", + "block.minecraft.soul_torch": "Soul Torch", + "block.minecraft.soul_wall_torch": "Soul Wall Torch", + "block.minecraft.fire": "Fire", + "block.minecraft.spawner": "Monster Spawner", + "block.minecraft.spawner.desc1": "Interact with Spawn Egg:", + "block.minecraft.spawner.desc2": "Sets Mob Type", + "block.minecraft.respawn_anchor": "Respawn Anchor", + "block.minecraft.oak_stairs": "Oak Stairs", + "block.minecraft.spruce_stairs": "Spruce Stairs", + "block.minecraft.birch_stairs": "Birch Stairs", + "block.minecraft.jungle_stairs": "Jungle Stairs", + "block.minecraft.acacia_stairs": "Acacia Stairs", + "block.minecraft.dark_oak_stairs": "Dark Oak Stairs", + "block.minecraft.mangrove_stairs": "Mangrove Stairs", + "block.minecraft.bamboo_stairs": "Bamboo Stairs", + "block.minecraft.bamboo_mosaic_stairs": "Bamboo Mosaic Stairs", + "block.minecraft.dark_prismarine_stairs": "Dark Prismarine Stairs", + "block.minecraft.prismarine_stairs": "Prismarine Stairs", + "block.minecraft.prismarine_brick_stairs": "Prismarine Brick Stairs", + "block.minecraft.chest": "Chest", + "block.minecraft.trapped_chest": "Trapped Chest", + "block.minecraft.redstone_wire": "Redstone Wire", + "block.minecraft.diamond_ore": "Diamond Ore", + "block.minecraft.deepslate_diamond_ore": "Deepslate Diamond Ore", + "block.minecraft.coal_block": "Block of Coal", + "block.minecraft.diamond_block": "Block of Diamond", + "block.minecraft.crafting_table": "Crafting Table", + "block.minecraft.wheat": "Wheat Crops", + "block.minecraft.farmland": "Farmland", + "block.minecraft.furnace": "Furnace", + "block.minecraft.oak_sign": "Oak Sign", + "block.minecraft.spruce_sign": "Spruce Sign", + "block.minecraft.birch_sign": "Birch Sign", + "block.minecraft.acacia_sign": "Acacia Sign", + "block.minecraft.jungle_sign": "Jungle Sign", + "block.minecraft.dark_oak_sign": "Dark Oak Sign", + "block.minecraft.mangrove_sign": "Mangrove Sign", + "block.minecraft.bamboo_sign": "Bamboo Sign", + "block.minecraft.oak_wall_sign": "Oak Wall Sign", + "block.minecraft.spruce_wall_sign": "Spruce Wall Sign", + "block.minecraft.birch_wall_sign": "Birch Wall Sign", + "block.minecraft.acacia_wall_sign": "Acacia Wall Sign", + "block.minecraft.jungle_wall_sign": "Jungle Wall Sign", + "block.minecraft.dark_oak_wall_sign": "Dark Oak Wall Sign", + "block.minecraft.mangrove_wall_sign": "Mangrove Wall Sign", + "block.minecraft.bamboo_wall_sign": "Bamboo Wall Sign", + "block.minecraft.oak_hanging_sign": "Oak Hanging Sign", + "block.minecraft.spruce_hanging_sign": "Spruce Hanging Sign", + "block.minecraft.birch_hanging_sign": "Birch Hanging Sign", + "block.minecraft.acacia_hanging_sign": "Acacia Hanging Sign", + "block.minecraft.jungle_hanging_sign": "Jungle Hanging Sign", + "block.minecraft.crimson_hanging_sign": "Crimson Hanging Sign", + "block.minecraft.warped_hanging_sign": "Warped Hanging Sign", + "block.minecraft.dark_oak_hanging_sign": "Dark Oak Hanging Sign", + "block.minecraft.mangrove_hanging_sign": "Mangrove Hanging Sign", + "block.minecraft.bamboo_hanging_sign": "Bamboo Hanging Sign", + "block.minecraft.oak_wall_hanging_sign": "Oak Wall Hanging Sign", + "block.minecraft.spruce_wall_hanging_sign": "Spruce Wall Hanging Sign", + "block.minecraft.birch_wall_hanging_sign": "Birch Wall Hanging Sign", + "block.minecraft.acacia_wall_hanging_sign": "Acacia Wall Hanging Sign", + "block.minecraft.jungle_wall_hanging_sign": "Jungle Wall Hanging Sign", + "block.minecraft.dark_oak_wall_hanging_sign": "Dark Oak Wall Hanging Sign", + "block.minecraft.mangrove_wall_hanging_sign": "Mangrove Wall Hanging Sign", + "block.minecraft.crimson_wall_hanging_sign": "Crimson Wall Hanging Sign", + "block.minecraft.warped_wall_hanging_sign": "Warped Wall Hanging Sign", + "block.minecraft.bamboo_wall_hanging_sign": "Bamboo Wall Hanging Sign", + "block.minecraft.ladder": "Ladder", + "block.minecraft.scaffolding": "Scaffolding", + "block.minecraft.rail": "Rail", + "block.minecraft.powered_rail": "Powered Rail", + "block.minecraft.activator_rail": "Activator Rail", + "block.minecraft.detector_rail": "Detector Rail", + "block.minecraft.cobblestone_stairs": "Cobblestone Stairs", + "block.minecraft.sandstone_stairs": "Sandstone Stairs", + "block.minecraft.red_sandstone_stairs": "Red Sandstone Stairs", + "block.minecraft.lever": "Lever", + "block.minecraft.stone_pressure_plate": "Stone Pressure Plate", + "block.minecraft.oak_pressure_plate": "Oak Pressure Plate", + "block.minecraft.spruce_pressure_plate": "Spruce Pressure Plate", + "block.minecraft.birch_pressure_plate": "Birch Pressure Plate", + "block.minecraft.jungle_pressure_plate": "Jungle Pressure Plate", + "block.minecraft.acacia_pressure_plate": "Acacia Pressure Plate", + "block.minecraft.dark_oak_pressure_plate": "Dark Oak Pressure Plate", + "block.minecraft.mangrove_pressure_plate": "Mangrove Pressure Plate", + "block.minecraft.bamboo_pressure_plate": "Bamboo Pressure Plate", + "block.minecraft.light_weighted_pressure_plate": "Light Weighted Pressure Plate", + "block.minecraft.heavy_weighted_pressure_plate": "Heavy Weighted Pressure Plate", + "block.minecraft.iron_door": "Iron Door", + "block.minecraft.redstone_ore": "Redstone Ore", + "block.minecraft.deepslate_redstone_ore": "Deepslate Redstone Ore", + "block.minecraft.redstone_torch": "Redstone Torch", + "block.minecraft.redstone_wall_torch": "Redstone Wall Torch", + "block.minecraft.stone_button": "Stone Button", + "block.minecraft.oak_button": "Oak Button", + "block.minecraft.spruce_button": "Spruce Button", + "block.minecraft.birch_button": "Birch Button", + "block.minecraft.jungle_button": "Jungle Button", + "block.minecraft.acacia_button": "Acacia Button", + "block.minecraft.dark_oak_button": "Dark Oak Button", + "block.minecraft.mangrove_button": "Mangrove Button", + "block.minecraft.bamboo_button": "Bamboo Button", + "block.minecraft.snow": "Snow", + "block.minecraft.white_carpet": "White Carpet", + "block.minecraft.orange_carpet": "Orange Carpet", + "block.minecraft.magenta_carpet": "Magenta Carpet", + "block.minecraft.light_blue_carpet": "Light Blue Carpet", + "block.minecraft.yellow_carpet": "Yellow Carpet", + "block.minecraft.lime_carpet": "Lime Carpet", + "block.minecraft.pink_carpet": "Pink Carpet", + "block.minecraft.gray_carpet": "Gray Carpet", + "block.minecraft.light_gray_carpet": "Light Gray Carpet", + "block.minecraft.cyan_carpet": "Cyan Carpet", + "block.minecraft.purple_carpet": "Purple Carpet", + "block.minecraft.blue_carpet": "Blue Carpet", + "block.minecraft.brown_carpet": "Brown Carpet", + "block.minecraft.green_carpet": "Green Carpet", + "block.minecraft.red_carpet": "Red Carpet", + "block.minecraft.black_carpet": "Black Carpet", + "block.minecraft.ice": "Ice", + "block.minecraft.frosted_ice": "Frosted Ice", + "block.minecraft.packed_ice": "Packed Ice", + "block.minecraft.blue_ice": "Blue Ice", + "block.minecraft.cactus": "Cactus", + "block.minecraft.clay": "Clay", + "block.minecraft.white_terracotta": "White Terracotta", + "block.minecraft.orange_terracotta": "Orange Terracotta", + "block.minecraft.magenta_terracotta": "Magenta Terracotta", + "block.minecraft.light_blue_terracotta": "Light Blue Terracotta", + "block.minecraft.yellow_terracotta": "Yellow Terracotta", + "block.minecraft.lime_terracotta": "Lime Terracotta", + "block.minecraft.pink_terracotta": "Pink Terracotta", + "block.minecraft.gray_terracotta": "Gray Terracotta", + "block.minecraft.light_gray_terracotta": "Light Gray Terracotta", + "block.minecraft.cyan_terracotta": "Cyan Terracotta", + "block.minecraft.purple_terracotta": "Purple Terracotta", + "block.minecraft.blue_terracotta": "Blue Terracotta", + "block.minecraft.brown_terracotta": "Brown Terracotta", + "block.minecraft.green_terracotta": "Green Terracotta", + "block.minecraft.red_terracotta": "Red Terracotta", + "block.minecraft.black_terracotta": "Black Terracotta", + "block.minecraft.terracotta": "Terracotta", + "block.minecraft.sugar_cane": "Sugar Cane", + "block.minecraft.jukebox": "Jukebox", + "block.minecraft.oak_fence": "Oak Fence", + "block.minecraft.spruce_fence": "Spruce Fence", + "block.minecraft.birch_fence": "Birch Fence", + "block.minecraft.jungle_fence": "Jungle Fence", + "block.minecraft.acacia_fence": "Acacia Fence", + "block.minecraft.dark_oak_fence": "Dark Oak Fence", + "block.minecraft.mangrove_fence": "Mangrove Fence", + "block.minecraft.bamboo_fence": "Bamboo Fence", + "block.minecraft.oak_fence_gate": "Oak Fence Gate", + "block.minecraft.spruce_fence_gate": "Spruce Fence Gate", + "block.minecraft.birch_fence_gate": "Birch Fence Gate", + "block.minecraft.jungle_fence_gate": "Jungle Fence Gate", + "block.minecraft.acacia_fence_gate": "Acacia Fence Gate", + "block.minecraft.dark_oak_fence_gate": "Dark Oak Fence Gate", + "block.minecraft.mangrove_fence_gate": "Mangrove Fence Gate", + "block.minecraft.bamboo_fence_gate": "Bamboo Fence Gate", + "block.minecraft.pumpkin_stem": "Pumpkin Stem", + "block.minecraft.attached_pumpkin_stem": "Attached Pumpkin Stem", + "block.minecraft.pumpkin": "Pumpkin", + "block.minecraft.carved_pumpkin": "Carved Pumpkin", + "block.minecraft.jack_o_lantern": "Jack o'Lantern", + "block.minecraft.netherrack": "Netherrack", + "block.minecraft.soul_sand": "Soul Sand", + "block.minecraft.glowstone": "Glowstone", + "block.minecraft.nether_portal": "Nether Portal", + "block.minecraft.white_wool": "White Wool", + "block.minecraft.orange_wool": "Orange Wool", + "block.minecraft.magenta_wool": "Magenta Wool", + "block.minecraft.light_blue_wool": "Light Blue Wool", + "block.minecraft.yellow_wool": "Yellow Wool", + "block.minecraft.lime_wool": "Lime Wool", + "block.minecraft.pink_wool": "Pink Wool", + "block.minecraft.gray_wool": "Gray Wool", + "block.minecraft.light_gray_wool": "Light Gray Wool", + "block.minecraft.cyan_wool": "Cyan Wool", + "block.minecraft.purple_wool": "Purple Wool", + "block.minecraft.blue_wool": "Blue Wool", + "block.minecraft.brown_wool": "Brown Wool", + "block.minecraft.green_wool": "Green Wool", + "block.minecraft.red_wool": "Red Wool", + "block.minecraft.black_wool": "Black Wool", + "block.minecraft.lapis_ore": "Lapis Lazuli Ore", + "block.minecraft.deepslate_lapis_ore": "Deepslate Lapis Lazuli Ore", + "block.minecraft.lapis_block": "Block of Lapis Lazuli", + "block.minecraft.dispenser": "Dispenser", + "block.minecraft.dropper": "Dropper", + "block.minecraft.note_block": "Note Block", + "block.minecraft.cake": "Cake", + "block.minecraft.bed.occupied": "This bed is occupied", + "block.minecraft.bed.obstructed": "This bed is obstructed", + "block.minecraft.bed.no_sleep": "You can sleep only at night or during thunderstorms", + "block.minecraft.bed.too_far_away": "You may not rest now; the bed is too far away", + "block.minecraft.bed.not_safe": "You may not rest now; there are monsters nearby", + "block.minecraft.spawn.not_valid": "You have no home bed or charged respawn anchor, or it was obstructed", + "block.minecraft.set_spawn": "Respawn point set", + "block.minecraft.oak_trapdoor": "Oak Trapdoor", + "block.minecraft.spruce_trapdoor": "Spruce Trapdoor", + "block.minecraft.birch_trapdoor": "Birch Trapdoor", + "block.minecraft.jungle_trapdoor": "Jungle Trapdoor", + "block.minecraft.acacia_trapdoor": "Acacia Trapdoor", + "block.minecraft.dark_oak_trapdoor": "Dark Oak Trapdoor", + "block.minecraft.mangrove_trapdoor": "Mangrove Trapdoor", + "block.minecraft.bamboo_trapdoor": "Bamboo Trapdoor", + "block.minecraft.iron_trapdoor": "Iron Trapdoor", + "block.minecraft.cobweb": "Cobweb", + "block.minecraft.stone_bricks": "Stone Bricks", + "block.minecraft.mossy_stone_bricks": "Mossy Stone Bricks", + "block.minecraft.cracked_stone_bricks": "Cracked Stone Bricks", + "block.minecraft.chiseled_stone_bricks": "Chiseled Stone Bricks", + "block.minecraft.packed_mud": "Packed Mud", + "block.minecraft.mud_bricks": "Mud Bricks", + "block.minecraft.infested_stone": "Infested Stone", + "block.minecraft.infested_cobblestone": "Infested Cobblestone", + "block.minecraft.infested_stone_bricks": "Infested Stone Bricks", + "block.minecraft.infested_mossy_stone_bricks": "Infested Mossy Stone Bricks", + "block.minecraft.infested_cracked_stone_bricks": "Infested Cracked Stone Bricks", + "block.minecraft.infested_chiseled_stone_bricks": "Infested Chiseled Stone Bricks", + "block.minecraft.piston": "Piston", + "block.minecraft.sticky_piston": "Sticky Piston", + "block.minecraft.iron_bars": "Iron Bars", + "block.minecraft.melon": "Melon", + "block.minecraft.brick_stairs": "Brick Stairs", + "block.minecraft.stone_brick_stairs": "Stone Brick Stairs", + "block.minecraft.mud_brick_stairs": "Mud Brick Stairs", + "block.minecraft.vine": "Vines", + "block.minecraft.nether_bricks": "Nether Bricks", + "block.minecraft.nether_brick_fence": "Nether Brick Fence", + "block.minecraft.nether_brick_stairs": "Nether Brick Stairs", + "block.minecraft.nether_wart": "Nether Wart", + "block.minecraft.warped_wart_block": "Warped Wart Block", + "block.minecraft.warped_stem": "Warped Stem", + "block.minecraft.stripped_warped_stem": "Stripped Warped Stem", + "block.minecraft.warped_hyphae": "Warped Hyphae", + "block.minecraft.stripped_warped_hyphae": "Stripped Warped Hyphae", + "block.minecraft.crimson_stem": "Crimson Stem", + "block.minecraft.stripped_crimson_stem": "Stripped Crimson Stem", + "block.minecraft.crimson_hyphae": "Crimson Hyphae", + "block.minecraft.stripped_crimson_hyphae": "Stripped Crimson Hyphae", + "block.minecraft.warped_nylium": "Warped Nylium", + "block.minecraft.crimson_nylium": "Crimson Nylium", + "block.minecraft.warped_fungus": "Warped Fungus", + "block.minecraft.crimson_fungus": "Crimson Fungus", + "block.minecraft.crimson_roots": "Crimson Roots", + "block.minecraft.warped_roots": "Warped Roots", + "block.minecraft.nether_sprouts": "Nether Sprouts", + "block.minecraft.shroomlight": "Shroomlight", + "block.minecraft.weeping_vines": "Weeping Vines", + "block.minecraft.weeping_vines_plant": "Weeping Vines Plant", + "block.minecraft.twisting_vines": "Twisting Vines", + "block.minecraft.twisting_vines_plant": "Twisting Vines Plant", + "block.minecraft.soul_soil": "Soul Soil", + "block.minecraft.basalt": "Basalt", + "block.minecraft.polished_basalt": "Polished Basalt", + "block.minecraft.warped_planks": "Warped Planks", + "block.minecraft.warped_slab": "Warped Slab", + "block.minecraft.warped_pressure_plate": "Warped Pressure Plate", + "block.minecraft.warped_fence": "Warped Fence", + "block.minecraft.warped_trapdoor": "Warped Trapdoor", + "block.minecraft.warped_fence_gate": "Warped Fence Gate", + "block.minecraft.warped_stairs": "Warped Stairs", + "block.minecraft.warped_button": "Warped Button", + "block.minecraft.warped_door": "Warped Door", + "block.minecraft.warped_sign": "Warped Sign", + "block.minecraft.warped_wall_sign": "Warped Wall Sign", + "block.minecraft.crimson_planks": "Crimson Planks", + "block.minecraft.crimson_slab": "Crimson Slab", + "block.minecraft.crimson_pressure_plate": "Crimson Pressure Plate", + "block.minecraft.crimson_fence": "Crimson Fence", + "block.minecraft.crimson_trapdoor": "Crimson Trapdoor", + "block.minecraft.crimson_fence_gate": "Crimson Fence Gate", + "block.minecraft.crimson_stairs": "Crimson Stairs", + "block.minecraft.crimson_button": "Crimson Button", + "block.minecraft.crimson_door": "Crimson Door", + "block.minecraft.crimson_sign": "Crimson Sign", + "block.minecraft.crimson_wall_sign": "Crimson Wall Sign", + "block.minecraft.soul_fire": "Soul Fire", + "block.minecraft.cauldron": "Cauldron", + "block.minecraft.water_cauldron": "Water Cauldron", + "block.minecraft.lava_cauldron": "Lava Cauldron", + "block.minecraft.powder_snow_cauldron": "Powder Snow Cauldron", + "block.minecraft.enchanting_table": "Enchanting Table", + "block.minecraft.anvil": "Anvil", + "block.minecraft.chipped_anvil": "Chipped Anvil", + "block.minecraft.damaged_anvil": "Damaged Anvil", + "block.minecraft.end_stone": "End Stone", + "block.minecraft.end_portal_frame": "End Portal Frame", + "block.minecraft.mycelium": "Mycelium", + "block.minecraft.lily_pad": "Lily Pad", + "block.minecraft.dragon_egg": "Dragon Egg", + "block.minecraft.redstone_lamp": "Redstone Lamp", + "block.minecraft.cocoa": "Cocoa", + "block.minecraft.ender_chest": "Ender Chest", + "block.minecraft.emerald_ore": "Emerald Ore", + "block.minecraft.deepslate_emerald_ore": "Deepslate Emerald Ore", + "block.minecraft.emerald_block": "Block of Emerald", + "block.minecraft.redstone_block": "Block of Redstone", + "block.minecraft.tripwire": "Tripwire", + "block.minecraft.tripwire_hook": "Tripwire Hook", + "block.minecraft.command_block": "Command Block", + "block.minecraft.repeating_command_block": "Repeating Command Block", + "block.minecraft.chain_command_block": "Chain Command Block", + "block.minecraft.beacon": "Beacon", + "block.minecraft.beacon.primary": "Primary Power", + "block.minecraft.beacon.secondary": "Secondary Power", + "block.minecraft.cobblestone_wall": "Cobblestone Wall", + "block.minecraft.mossy_cobblestone_wall": "Mossy Cobblestone Wall", + "block.minecraft.carrots": "Carrots", + "block.minecraft.potatoes": "Potatoes", + "block.minecraft.daylight_detector": "Daylight Detector", + "block.minecraft.nether_quartz_ore": "Nether Quartz Ore", + "block.minecraft.hopper": "Hopper", + "block.minecraft.quartz_block": "Block of Quartz", + "block.minecraft.chiseled_quartz_block": "Chiseled Quartz Block", + "block.minecraft.quartz_pillar": "Quartz Pillar", + "block.minecraft.quartz_stairs": "Quartz Stairs", + "block.minecraft.slime_block": "Slime Block", + "block.minecraft.prismarine": "Prismarine", + "block.minecraft.prismarine_bricks": "Prismarine Bricks", + "block.minecraft.dark_prismarine": "Dark Prismarine", + "block.minecraft.sea_lantern": "Sea Lantern", + "block.minecraft.end_rod": "End Rod", + "block.minecraft.chorus_plant": "Chorus Plant", + "block.minecraft.chorus_flower": "Chorus Flower", + "block.minecraft.purpur_block": "Purpur Block", + "block.minecraft.purpur_pillar": "Purpur Pillar", + "block.minecraft.purpur_stairs": "Purpur Stairs", + "block.minecraft.purpur_slab": "Purpur Slab", + "block.minecraft.end_stone_bricks": "End Stone Bricks", + "block.minecraft.beetroots": "Beetroots", + "block.minecraft.dirt_path": "Dirt Path", + "block.minecraft.magma_block": "Magma Block", + "block.minecraft.nether_wart_block": "Nether Wart Block", + "block.minecraft.red_nether_bricks": "Red Nether Bricks", + "block.minecraft.bone_block": "Bone Block", + "block.minecraft.observer": "Observer", + "block.minecraft.shulker_box": "Shulker Box", + "block.minecraft.white_shulker_box": "White Shulker Box", + "block.minecraft.orange_shulker_box": "Orange Shulker Box", + "block.minecraft.magenta_shulker_box": "Magenta Shulker Box", + "block.minecraft.light_blue_shulker_box": "Light Blue Shulker Box", + "block.minecraft.yellow_shulker_box": "Yellow Shulker Box", + "block.minecraft.lime_shulker_box": "Lime Shulker Box", + "block.minecraft.pink_shulker_box": "Pink Shulker Box", + "block.minecraft.gray_shulker_box": "Gray Shulker Box", + "block.minecraft.light_gray_shulker_box": "Light Gray Shulker Box", + "block.minecraft.cyan_shulker_box": "Cyan Shulker Box", + "block.minecraft.purple_shulker_box": "Purple Shulker Box", + "block.minecraft.blue_shulker_box": "Blue Shulker Box", + "block.minecraft.brown_shulker_box": "Brown Shulker Box", + "block.minecraft.green_shulker_box": "Green Shulker Box", + "block.minecraft.red_shulker_box": "Red Shulker Box", + "block.minecraft.black_shulker_box": "Black Shulker Box", + "block.minecraft.white_glazed_terracotta": "White Glazed Terracotta", + "block.minecraft.orange_glazed_terracotta": "Orange Glazed Terracotta", + "block.minecraft.magenta_glazed_terracotta": "Magenta Glazed Terracotta", + "block.minecraft.light_blue_glazed_terracotta": "Light Blue Glazed Terracotta", + "block.minecraft.yellow_glazed_terracotta": "Yellow Glazed Terracotta", + "block.minecraft.lime_glazed_terracotta": "Lime Glazed Terracotta", + "block.minecraft.pink_glazed_terracotta": "Pink Glazed Terracotta", + "block.minecraft.gray_glazed_terracotta": "Gray Glazed Terracotta", + "block.minecraft.light_gray_glazed_terracotta": "Light Gray Glazed Terracotta", + "block.minecraft.cyan_glazed_terracotta": "Cyan Glazed Terracotta", + "block.minecraft.purple_glazed_terracotta": "Purple Glazed Terracotta", + "block.minecraft.blue_glazed_terracotta": "Blue Glazed Terracotta", + "block.minecraft.brown_glazed_terracotta": "Brown Glazed Terracotta", + "block.minecraft.green_glazed_terracotta": "Green Glazed Terracotta", + "block.minecraft.red_glazed_terracotta": "Red Glazed Terracotta", + "block.minecraft.black_glazed_terracotta": "Black Glazed Terracotta", + "block.minecraft.black_concrete": "Black Concrete", + "block.minecraft.red_concrete": "Red Concrete", + "block.minecraft.green_concrete": "Green Concrete", + "block.minecraft.brown_concrete": "Brown Concrete", + "block.minecraft.blue_concrete": "Blue Concrete", + "block.minecraft.purple_concrete": "Purple Concrete", + "block.minecraft.cyan_concrete": "Cyan Concrete", + "block.minecraft.light_gray_concrete": "Light Gray Concrete", + "block.minecraft.gray_concrete": "Gray Concrete", + "block.minecraft.pink_concrete": "Pink Concrete", + "block.minecraft.lime_concrete": "Lime Concrete", + "block.minecraft.yellow_concrete": "Yellow Concrete", + "block.minecraft.light_blue_concrete": "Light Blue Concrete", + "block.minecraft.magenta_concrete": "Magenta Concrete", + "block.minecraft.orange_concrete": "Orange Concrete", + "block.minecraft.white_concrete": "White Concrete", + "block.minecraft.black_concrete_powder": "Black Concrete Powder", + "block.minecraft.red_concrete_powder": "Red Concrete Powder", + "block.minecraft.green_concrete_powder": "Green Concrete Powder", + "block.minecraft.brown_concrete_powder": "Brown Concrete Powder", + "block.minecraft.blue_concrete_powder": "Blue Concrete Powder", + "block.minecraft.purple_concrete_powder": "Purple Concrete Powder", + "block.minecraft.cyan_concrete_powder": "Cyan Concrete Powder", + "block.minecraft.light_gray_concrete_powder": "Light Gray Concrete Powder", + "block.minecraft.gray_concrete_powder": "Gray Concrete Powder", + "block.minecraft.pink_concrete_powder": "Pink Concrete Powder", + "block.minecraft.lime_concrete_powder": "Lime Concrete Powder", + "block.minecraft.yellow_concrete_powder": "Yellow Concrete Powder", + "block.minecraft.light_blue_concrete_powder": "Light Blue Concrete Powder", + "block.minecraft.magenta_concrete_powder": "Magenta Concrete Powder", + "block.minecraft.orange_concrete_powder": "Orange Concrete Powder", + "block.minecraft.white_concrete_powder": "White Concrete Powder", + "block.minecraft.turtle_egg": "Turtle Egg", + "block.minecraft.piston_head": "Piston Head", + "block.minecraft.moving_piston": "Moving Piston", + "block.minecraft.red_mushroom": "Red Mushroom", + "block.minecraft.snow_block": "Snow Block", + "block.minecraft.attached_melon_stem": "Attached Melon Stem", + "block.minecraft.melon_stem": "Melon Stem", + "block.minecraft.brewing_stand": "Brewing Stand", + "block.minecraft.end_portal": "End Portal", + "block.minecraft.flower_pot": "Flower Pot", + "block.minecraft.potted_oak_sapling": "Potted Oak Sapling", + "block.minecraft.potted_spruce_sapling": "Potted Spruce Sapling", + "block.minecraft.potted_birch_sapling": "Potted Birch Sapling", + "block.minecraft.potted_jungle_sapling": "Potted Jungle Sapling", + "block.minecraft.potted_acacia_sapling": "Potted Acacia Sapling", + "block.minecraft.potted_dark_oak_sapling": "Potted Dark Oak Sapling", + "block.minecraft.potted_mangrove_propagule": "Potted Mangrove Propagule", + "block.minecraft.potted_fern": "Potted Fern", + "block.minecraft.potted_dandelion": "Potted Dandelion", + "block.minecraft.potted_poppy": "Potted Poppy", + "block.minecraft.potted_blue_orchid": "Potted Blue Orchid", + "block.minecraft.potted_allium": "Potted Allium", + "block.minecraft.potted_azure_bluet": "Potted Azure Bluet", + "block.minecraft.potted_red_tulip": "Potted Red Tulip", + "block.minecraft.potted_orange_tulip": "Potted Orange Tulip", + "block.minecraft.potted_white_tulip": "Potted White Tulip", + "block.minecraft.potted_pink_tulip": "Potted Pink Tulip", + "block.minecraft.potted_oxeye_daisy": "Potted Oxeye Daisy", + "block.minecraft.potted_cornflower": "Potted Cornflower", + "block.minecraft.potted_lily_of_the_valley": "Potted Lily of the Valley", + "block.minecraft.potted_wither_rose": "Potted Wither Rose", + "block.minecraft.potted_red_mushroom": "Potted Red Mushroom", + "block.minecraft.potted_brown_mushroom": "Potted Brown Mushroom", + "block.minecraft.potted_dead_bush": "Potted Dead Bush", + "block.minecraft.potted_cactus": "Potted Cactus", + "block.minecraft.potted_bamboo": "Potted Bamboo", + "block.minecraft.potted_crimson_fungus": "Potted Crimson Fungus", + "block.minecraft.potted_warped_fungus": "Potted Warped Fungus", + "block.minecraft.potted_crimson_roots": "Potted Crimson Roots", + "block.minecraft.potted_warped_roots": "Potted Warped Roots", + "block.minecraft.potted_azalea_bush": "Potted Azalea", + "block.minecraft.potted_flowering_azalea_bush": "Potted Flowering Azalea", + "block.minecraft.skeleton_wall_skull": "Skeleton Wall Skull", + "block.minecraft.skeleton_skull": "Skeleton Skull", + "block.minecraft.wither_skeleton_wall_skull": "Wither Skeleton Wall Skull", + "block.minecraft.wither_skeleton_skull": "Wither Skeleton Skull", + "block.minecraft.zombie_wall_head": "Zombie Wall Head", + "block.minecraft.zombie_head": "Zombie Head", + "block.minecraft.player_wall_head": "Player Wall Head", + "block.minecraft.player_head": "Player Head", + "block.minecraft.player_head.named": "%s's Head", + "block.minecraft.creeper_wall_head": "Creeper Wall Head", + "block.minecraft.creeper_head": "Creeper Head", + "block.minecraft.dragon_wall_head": "Dragon Wall Head", + "block.minecraft.dragon_head": "Dragon Head", + "block.minecraft.piglin_wall_head": "Piglin Wall Head", + "block.minecraft.piglin_head": "Piglin Head", + "block.minecraft.end_gateway": "End Gateway", + "block.minecraft.structure_void": "Structure Void", + "block.minecraft.structure_block": "Structure Block", + "block.minecraft.void_air": "Void Air", + "block.minecraft.cave_air": "Cave Air", + "block.minecraft.bubble_column": "Bubble Column", + "block.minecraft.dead_tube_coral_block": "Dead Tube Coral Block", + "block.minecraft.dead_brain_coral_block": "Dead Brain Coral Block", + "block.minecraft.dead_bubble_coral_block": "Dead Bubble Coral Block", + "block.minecraft.dead_fire_coral_block": "Dead Fire Coral Block", + "block.minecraft.dead_horn_coral_block": "Dead Horn Coral Block", + "block.minecraft.tube_coral_block": "Tube Coral Block", + "block.minecraft.brain_coral_block": "Brain Coral Block", + "block.minecraft.bubble_coral_block": "Bubble Coral Block", + "block.minecraft.fire_coral_block": "Fire Coral Block", + "block.minecraft.horn_coral_block": "Horn Coral Block", + "block.minecraft.tube_coral": "Tube Coral", + "block.minecraft.brain_coral": "Brain Coral", + "block.minecraft.bubble_coral": "Bubble Coral", + "block.minecraft.fire_coral": "Fire Coral", + "block.minecraft.horn_coral": "Horn Coral", + "block.minecraft.dead_tube_coral": "Dead Tube Coral", + "block.minecraft.dead_brain_coral": "Dead Brain Coral", + "block.minecraft.dead_bubble_coral": "Dead Bubble Coral", + "block.minecraft.dead_fire_coral": "Dead Fire Coral", + "block.minecraft.dead_horn_coral": "Dead Horn Coral", + "block.minecraft.tube_coral_fan": "Tube Coral Fan", + "block.minecraft.brain_coral_fan": "Brain Coral Fan", + "block.minecraft.bubble_coral_fan": "Bubble Coral Fan", + "block.minecraft.fire_coral_fan": "Fire Coral Fan", + "block.minecraft.horn_coral_fan": "Horn Coral Fan", + "block.minecraft.dead_tube_coral_fan": "Dead Tube Coral Fan", + "block.minecraft.dead_brain_coral_fan": "Dead Brain Coral Fan", + "block.minecraft.dead_bubble_coral_fan": "Dead Bubble Coral Fan", + "block.minecraft.dead_fire_coral_fan": "Dead Fire Coral Fan", + "block.minecraft.dead_horn_coral_fan": "Dead Horn Coral Fan", + "block.minecraft.tube_coral_wall_fan": "Tube Coral Wall Fan", + "block.minecraft.brain_coral_wall_fan": "Brain Coral Wall Fan", + "block.minecraft.bubble_coral_wall_fan": "Bubble Coral Wall Fan", + "block.minecraft.fire_coral_wall_fan": "Fire Coral Wall Fan", + "block.minecraft.horn_coral_wall_fan": "Horn Coral Wall Fan", + "block.minecraft.dead_tube_coral_wall_fan": "Dead Tube Coral Wall Fan", + "block.minecraft.dead_brain_coral_wall_fan": "Dead Brain Coral Wall Fan", + "block.minecraft.dead_bubble_coral_wall_fan": "Dead Bubble Coral Wall Fan", + "block.minecraft.dead_fire_coral_wall_fan": "Dead Fire Coral Wall Fan", + "block.minecraft.dead_horn_coral_wall_fan": "Dead Horn Coral Wall Fan", + "block.minecraft.loom": "Loom", + "block.minecraft.conduit": "Conduit", + "block.minecraft.bamboo": "Bamboo", + "block.minecraft.bamboo_sapling": "Bamboo Shoot", + "block.minecraft.jigsaw": "Jigsaw Block", + "block.minecraft.composter": "Composter", + "block.minecraft.target": "Target", + "block.minecraft.polished_granite_stairs": "Polished Granite Stairs", + "block.minecraft.smooth_red_sandstone_stairs": "Smooth Red Sandstone Stairs", + "block.minecraft.mossy_stone_brick_stairs": "Mossy Stone Brick Stairs", + "block.minecraft.polished_diorite_stairs": "Polished Diorite Stairs", + "block.minecraft.mossy_cobblestone_stairs": "Mossy Cobblestone Stairs", + "block.minecraft.end_stone_brick_stairs": "End Stone Brick Stairs", + "block.minecraft.stone_stairs": "Stone Stairs", + "block.minecraft.smooth_sandstone_stairs": "Smooth Sandstone Stairs", + "block.minecraft.smooth_quartz_stairs": "Smooth Quartz Stairs", + "block.minecraft.granite_stairs": "Granite Stairs", + "block.minecraft.andesite_stairs": "Andesite Stairs", + "block.minecraft.red_nether_brick_stairs": "Red Nether Brick Stairs", + "block.minecraft.polished_andesite_stairs": "Polished Andesite Stairs", + "block.minecraft.diorite_stairs": "Diorite Stairs", + "block.minecraft.polished_granite_slab": "Polished Granite Slab", + "block.minecraft.smooth_red_sandstone_slab": "Smooth Red Sandstone Slab", + "block.minecraft.mossy_stone_brick_slab": "Mossy Stone Brick Slab", + "block.minecraft.polished_diorite_slab": "Polished Diorite Slab", + "block.minecraft.mossy_cobblestone_slab": "Mossy Cobblestone Slab", + "block.minecraft.end_stone_brick_slab": "End Stone Brick Slab", + "block.minecraft.smooth_sandstone_slab": "Smooth Sandstone Slab", + "block.minecraft.smooth_quartz_slab": "Smooth Quartz Slab", + "block.minecraft.granite_slab": "Granite Slab", + "block.minecraft.andesite_slab": "Andesite Slab", + "block.minecraft.red_nether_brick_slab": "Red Nether Brick Slab", + "block.minecraft.polished_andesite_slab": "Polished Andesite Slab", + "block.minecraft.diorite_slab": "Diorite Slab", + "block.minecraft.brick_wall": "Brick Wall", + "block.minecraft.prismarine_wall": "Prismarine Wall", + "block.minecraft.red_sandstone_wall": "Red Sandstone Wall", + "block.minecraft.mossy_stone_brick_wall": "Mossy Stone Brick Wall", + "block.minecraft.granite_wall": "Granite Wall", + "block.minecraft.stone_brick_wall": "Stone Brick Wall", + "block.minecraft.mud_brick_wall": "Mud Brick Wall", + "block.minecraft.nether_brick_wall": "Nether Brick Wall", + "block.minecraft.andesite_wall": "Andesite Wall", + "block.minecraft.red_nether_brick_wall": "Red Nether Brick Wall", + "block.minecraft.sandstone_wall": "Sandstone Wall", + "block.minecraft.end_stone_brick_wall": "End Stone Brick Wall", + "block.minecraft.diorite_wall": "Diorite Wall", + "block.minecraft.barrel": "Barrel", + "block.minecraft.smoker": "Smoker", + "block.minecraft.blast_furnace": "Blast Furnace", + "block.minecraft.cartography_table": "Cartography Table", + "block.minecraft.fletching_table": "Fletching Table", + "block.minecraft.smithing_table": "Smithing Table", + "block.minecraft.grindstone": "Grindstone", + "block.minecraft.lectern": "Lectern", + "block.minecraft.stonecutter": "Stonecutter", + "block.minecraft.bell": "Bell", + "block.minecraft.ominous_banner": "Ominous Banner", + "block.minecraft.lantern": "Lantern", + "block.minecraft.soul_lantern": "Soul Lantern", + "block.minecraft.sweet_berry_bush": "Sweet Berry Bush", + "block.minecraft.campfire": "Campfire", + "block.minecraft.soul_campfire": "Soul Campfire", + "block.minecraft.beehive": "Beehive", + "block.minecraft.bee_nest": "Bee Nest", + "block.minecraft.honey_block": "Honey Block", + "block.minecraft.honeycomb_block": "Honeycomb Block", + "block.minecraft.lodestone": "Lodestone", + "block.minecraft.netherite_block": "Block of Netherite", + "block.minecraft.ancient_debris": "Ancient Debris", + "block.minecraft.crying_obsidian": "Crying Obsidian", + "block.minecraft.blackstone": "Blackstone", + "block.minecraft.blackstone_slab": "Blackstone Slab", + "block.minecraft.blackstone_stairs": "Blackstone Stairs", + "block.minecraft.blackstone_wall": "Blackstone Wall", + "block.minecraft.polished_blackstone_bricks": "Polished Blackstone Bricks", + "block.minecraft.polished_blackstone_brick_slab": "Polished Blackstone Brick Slab", + "block.minecraft.polished_blackstone_brick_stairs": "Polished Blackstone Brick Stairs", + "block.minecraft.polished_blackstone_brick_wall": "Polished Blackstone Brick Wall", + "block.minecraft.chiseled_polished_blackstone": "Chiseled Polished Blackstone", + "block.minecraft.cracked_polished_blackstone_bricks": "Cracked Polished Blackstone Bricks", + "block.minecraft.gilded_blackstone": "Gilded Blackstone", + "block.minecraft.polished_blackstone": "Polished Blackstone", + "block.minecraft.polished_blackstone_wall": "Polished Blackstone Wall", + "block.minecraft.polished_blackstone_slab": "Polished Blackstone Slab", + "block.minecraft.polished_blackstone_stairs": "Polished Blackstone Stairs", + "block.minecraft.polished_blackstone_pressure_plate": "Polished Blackstone Pressure Plate", + "block.minecraft.polished_blackstone_button": "Polished Blackstone Button", + "block.minecraft.cracked_nether_bricks": "Cracked Nether Bricks", + "block.minecraft.chiseled_nether_bricks": "Chiseled Nether Bricks", + "block.minecraft.quartz_bricks": "Quartz Bricks", + "block.minecraft.chain": "Chain", + "block.minecraft.candle": "Candle", + "block.minecraft.white_candle": "White Candle", + "block.minecraft.orange_candle": "Orange Candle", + "block.minecraft.magenta_candle": "Magenta Candle", + "block.minecraft.light_blue_candle": "Light Blue Candle", + "block.minecraft.yellow_candle": "Yellow Candle", + "block.minecraft.lime_candle": "Lime Candle", + "block.minecraft.pink_candle": "Pink Candle", + "block.minecraft.gray_candle": "Gray Candle", + "block.minecraft.light_gray_candle": "Light Gray Candle", + "block.minecraft.cyan_candle": "Cyan Candle", + "block.minecraft.purple_candle": "Purple Candle", + "block.minecraft.blue_candle": "Blue Candle", + "block.minecraft.brown_candle": "Brown Candle", + "block.minecraft.green_candle": "Green Candle", + "block.minecraft.red_candle": "Red Candle", + "block.minecraft.black_candle": "Black Candle", + "block.minecraft.candle_cake": "Cake with Candle", + "block.minecraft.white_candle_cake": "Cake with White Candle", + "block.minecraft.orange_candle_cake": "Cake with Orange Candle", + "block.minecraft.magenta_candle_cake": "Cake with Magenta Candle", + "block.minecraft.light_blue_candle_cake": "Cake with Light Blue Candle", + "block.minecraft.yellow_candle_cake": "Cake with Yellow Candle", + "block.minecraft.lime_candle_cake": "Cake with Lime Candle", + "block.minecraft.pink_candle_cake": "Cake with Pink Candle", + "block.minecraft.gray_candle_cake": "Cake with Gray Candle", + "block.minecraft.light_gray_candle_cake": "Cake with Light Gray Candle", + "block.minecraft.cyan_candle_cake": "Cake with Cyan Candle", + "block.minecraft.purple_candle_cake": "Cake with Purple Candle", + "block.minecraft.blue_candle_cake": "Cake with Blue Candle", + "block.minecraft.brown_candle_cake": "Cake with Brown Candle", + "block.minecraft.green_candle_cake": "Cake with Green Candle", + "block.minecraft.red_candle_cake": "Cake with Red Candle", + "block.minecraft.black_candle_cake": "Cake with Black Candle", + "block.minecraft.amethyst_block": "Block of Amethyst", + "block.minecraft.small_amethyst_bud": "Small Amethyst Bud", + "block.minecraft.medium_amethyst_bud": "Medium Amethyst Bud", + "block.minecraft.large_amethyst_bud": "Large Amethyst Bud", + "block.minecraft.amethyst_cluster": "Amethyst Cluster", + "block.minecraft.budding_amethyst": "Budding Amethyst", + "block.minecraft.calcite": "Calcite", + "block.minecraft.tuff": "Tuff", + "block.minecraft.tinted_glass": "Tinted Glass", + "block.minecraft.dripstone_block": "Dripstone Block", + "block.minecraft.pointed_dripstone": "Pointed Dripstone", + "block.minecraft.copper_ore": "Copper Ore", + "block.minecraft.deepslate_copper_ore": "Deepslate Copper Ore", + "block.minecraft.copper_block": "Block of Copper", + "block.minecraft.exposed_copper": "Exposed Copper", + "block.minecraft.weathered_copper": "Weathered Copper", + "block.minecraft.oxidized_copper": "Oxidized Copper", + "block.minecraft.cut_copper": "Cut Copper", + "block.minecraft.exposed_cut_copper": "Exposed Cut Copper", + "block.minecraft.weathered_cut_copper": "Weathered Cut Copper", + "block.minecraft.oxidized_cut_copper": "Oxidized Cut Copper", + "block.minecraft.cut_copper_stairs": "Cut Copper Stairs", + "block.minecraft.exposed_cut_copper_stairs": "Exposed Cut Copper Stairs", + "block.minecraft.weathered_cut_copper_stairs": "Weathered Cut Copper Stairs", + "block.minecraft.oxidized_cut_copper_stairs": "Oxidized Cut Copper Stairs", + "block.minecraft.cut_copper_slab": "Cut Copper Slab", + "block.minecraft.exposed_cut_copper_slab": "Exposed Cut Copper Slab", + "block.minecraft.weathered_cut_copper_slab": "Weathered Cut Copper Slab", + "block.minecraft.oxidized_cut_copper_slab": "Oxidized Cut Copper Slab", + "block.minecraft.waxed_copper_block": "Waxed Block of Copper", + "block.minecraft.waxed_exposed_copper": "Waxed Exposed Copper", + "block.minecraft.waxed_weathered_copper": "Waxed Weathered Copper", + "block.minecraft.waxed_oxidized_copper": "Waxed Oxidized Copper", + "block.minecraft.waxed_cut_copper": "Waxed Cut Copper", + "block.minecraft.waxed_exposed_cut_copper": "Waxed Exposed Cut Copper", + "block.minecraft.waxed_weathered_cut_copper": "Waxed Weathered Cut Copper", + "block.minecraft.waxed_oxidized_cut_copper": "Waxed Oxidized Cut Copper", + "block.minecraft.waxed_cut_copper_stairs": "Waxed Cut Copper Stairs", + "block.minecraft.waxed_exposed_cut_copper_stairs": "Waxed Exposed Cut Copper Stairs", + "block.minecraft.waxed_weathered_cut_copper_stairs": "Waxed Weathered Cut Copper Stairs", + "block.minecraft.waxed_oxidized_cut_copper_stairs": "Waxed Oxidized Cut Copper Stairs", + "block.minecraft.waxed_cut_copper_slab": "Waxed Cut Copper Slab", + "block.minecraft.waxed_exposed_cut_copper_slab": "Waxed Exposed Cut Copper Slab", + "block.minecraft.waxed_weathered_cut_copper_slab": "Waxed Weathered Cut Copper Slab", + "block.minecraft.waxed_oxidized_cut_copper_slab": "Waxed Oxidized Cut Copper Slab", + "block.minecraft.lightning_rod": "Lightning Rod", + "block.minecraft.cave_vines": "Cave Vines", + "block.minecraft.cave_vines_plant": "Cave Vines Plant", + "block.minecraft.spore_blossom": "Spore Blossom", + "block.minecraft.azalea": "Azalea", + "block.minecraft.flowering_azalea": "Flowering Azalea", + "block.minecraft.azalea_leaves": "Azalea Leaves", + "block.minecraft.flowering_azalea_leaves": "Flowering Azalea Leaves", + "block.minecraft.moss_carpet": "Moss Carpet", + "block.minecraft.moss_block": "Moss Block", + "block.minecraft.big_dripleaf": "Big Dripleaf", + "block.minecraft.big_dripleaf_stem": "Big Dripleaf Stem", + "block.minecraft.small_dripleaf": "Small Dripleaf", + "block.minecraft.rooted_dirt": "Rooted Dirt", + "block.minecraft.mud": "Mud", + "block.minecraft.hanging_roots": "Hanging Roots", + "block.minecraft.powder_snow": "Powder Snow", + "block.minecraft.glow_lichen": "Glow Lichen", + "block.minecraft.sculk_sensor": "Sculk Sensor", + "block.minecraft.deepslate": "Deepslate", + "block.minecraft.cobbled_deepslate": "Cobbled Deepslate", + "block.minecraft.cobbled_deepslate_slab": "Cobbled Deepslate Slab", + "block.minecraft.cobbled_deepslate_stairs": "Cobbled Deepslate Stairs", + "block.minecraft.cobbled_deepslate_wall": "Cobbled Deepslate Wall", + "block.minecraft.chiseled_deepslate": "Chiseled Deepslate", + "block.minecraft.polished_deepslate": "Polished Deepslate", + "block.minecraft.polished_deepslate_slab": "Polished Deepslate Slab", + "block.minecraft.polished_deepslate_stairs": "Polished Deepslate Stairs", + "block.minecraft.polished_deepslate_wall": "Polished Deepslate Wall", + "block.minecraft.deepslate_bricks": "Deepslate Bricks", + "block.minecraft.deepslate_brick_slab": "Deepslate Brick Slab", + "block.minecraft.deepslate_brick_stairs": "Deepslate Brick Stairs", + "block.minecraft.deepslate_brick_wall": "Deepslate Brick Wall", + "block.minecraft.deepslate_tiles": "Deepslate Tiles", + "block.minecraft.deepslate_tile_slab": "Deepslate Tile Slab", + "block.minecraft.deepslate_tile_stairs": "Deepslate Tile Stairs", + "block.minecraft.deepslate_tile_wall": "Deepslate Tile Wall", + "block.minecraft.cracked_deepslate_bricks": "Cracked Deepslate Bricks", + "block.minecraft.cracked_deepslate_tiles": "Cracked Deepslate Tiles", + "block.minecraft.infested_deepslate": "Infested Deepslate", + "block.minecraft.smooth_basalt": "Smooth Basalt", + "block.minecraft.raw_iron_block": "Block of Raw Iron", + "block.minecraft.raw_copper_block": "Block of Raw Copper", + "block.minecraft.raw_gold_block": "Block of Raw Gold", + "block.minecraft.sculk": "Sculk", + "block.minecraft.sculk_catalyst": "Sculk Catalyst", + "block.minecraft.sculk_shrieker": "Sculk Shrieker", + "block.minecraft.sculk_vein": "Sculk Vein", + "block.minecraft.ochre_froglight": "Ochre Froglight", + "block.minecraft.verdant_froglight": "Verdant Froglight", + "block.minecraft.pearlescent_froglight": "Pearlescent Froglight", + "block.minecraft.frogspawn": "Frogspawn", + "block.minecraft.reinforced_deepslate": "Reinforced Deepslate", + "item.minecraft.name_tag": "Name Tag", + "item.minecraft.lead": "Lead", + "item.minecraft.iron_shovel": "Iron Shovel", + "item.minecraft.iron_pickaxe": "Iron Pickaxe", + "item.minecraft.iron_axe": "Iron Axe", + "item.minecraft.flint_and_steel": "Flint and Steel", + "item.minecraft.apple": "Apple", + "item.minecraft.cookie": "Cookie", + "item.minecraft.bow": "Bow", + "item.minecraft.bundle": "Bundle", + "item.minecraft.bundle.fullness": "%s/%s", + "item.minecraft.arrow": "Arrow", + "item.minecraft.spectral_arrow": "Spectral Arrow", + "item.minecraft.tipped_arrow": "Tipped Arrow", + "item.minecraft.dried_kelp": "Dried Kelp", + "item.minecraft.coal": "Coal", + "item.minecraft.charcoal": "Charcoal", + "item.minecraft.raw_copper": "Raw Copper", + "item.minecraft.raw_iron": "Raw Iron", + "item.minecraft.raw_gold": "Raw Gold", + "item.minecraft.diamond": "Diamond", + "item.minecraft.emerald": "Emerald", + "item.minecraft.iron_ingot": "Iron Ingot", + "item.minecraft.copper_ingot": "Copper Ingot", + "item.minecraft.gold_ingot": "Gold Ingot", + "item.minecraft.iron_sword": "Iron Sword", + "item.minecraft.wooden_sword": "Wooden Sword", + "item.minecraft.wooden_shovel": "Wooden Shovel", + "item.minecraft.wooden_pickaxe": "Wooden Pickaxe", + "item.minecraft.wooden_axe": "Wooden Axe", + "item.minecraft.stone_sword": "Stone Sword", + "item.minecraft.stone_shovel": "Stone Shovel", + "item.minecraft.stone_pickaxe": "Stone Pickaxe", + "item.minecraft.stone_axe": "Stone Axe", + "item.minecraft.diamond_sword": "Diamond Sword", + "item.minecraft.diamond_shovel": "Diamond Shovel", + "item.minecraft.diamond_pickaxe": "Diamond Pickaxe", + "item.minecraft.diamond_axe": "Diamond Axe", + "item.minecraft.stick": "Stick", + "item.minecraft.bowl": "Bowl", + "item.minecraft.mushroom_stew": "Mushroom Stew", + "item.minecraft.golden_sword": "Golden Sword", + "item.minecraft.golden_shovel": "Golden Shovel", + "item.minecraft.golden_pickaxe": "Golden Pickaxe", + "item.minecraft.golden_axe": "Golden Axe", + "item.minecraft.string": "String", + "item.minecraft.feather": "Feather", + "item.minecraft.gunpowder": "Gunpowder", + "item.minecraft.wooden_hoe": "Wooden Hoe", + "item.minecraft.stone_hoe": "Stone Hoe", + "item.minecraft.iron_hoe": "Iron Hoe", + "item.minecraft.diamond_hoe": "Diamond Hoe", + "item.minecraft.golden_hoe": "Golden Hoe", + "item.minecraft.wheat_seeds": "Wheat Seeds", + "item.minecraft.pumpkin_seeds": "Pumpkin Seeds", + "item.minecraft.melon_seeds": "Melon Seeds", + "item.minecraft.melon_slice": "Melon Slice", + "item.minecraft.wheat": "Wheat", + "item.minecraft.bread": "Bread", + "item.minecraft.leather_helmet": "Leather Cap", + "item.minecraft.leather_chestplate": "Leather Tunic", + "item.minecraft.leather_leggings": "Leather Pants", + "item.minecraft.leather_boots": "Leather Boots", + "item.minecraft.chainmail_helmet": "Chainmail Helmet", + "item.minecraft.chainmail_chestplate": "Chainmail Chestplate", + "item.minecraft.chainmail_leggings": "Chainmail Leggings", + "item.minecraft.chainmail_boots": "Chainmail Boots", + "item.minecraft.iron_helmet": "Iron Helmet", + "item.minecraft.iron_chestplate": "Iron Chestplate", + "item.minecraft.iron_leggings": "Iron Leggings", + "item.minecraft.iron_boots": "Iron Boots", + "item.minecraft.diamond_helmet": "Diamond Helmet", + "item.minecraft.diamond_chestplate": "Diamond Chestplate", + "item.minecraft.diamond_leggings": "Diamond Leggings", + "item.minecraft.diamond_boots": "Diamond Boots", + "item.minecraft.golden_helmet": "Golden Helmet", + "item.minecraft.golden_chestplate": "Golden Chestplate", + "item.minecraft.golden_leggings": "Golden Leggings", + "item.minecraft.golden_boots": "Golden Boots", + "item.minecraft.flint": "Flint", + "item.minecraft.porkchop": "Raw Porkchop", + "item.minecraft.cooked_porkchop": "Cooked Porkchop", + "item.minecraft.chicken": "Raw Chicken", + "item.minecraft.cooked_chicken": "Cooked Chicken", + "item.minecraft.mutton": "Raw Mutton", + "item.minecraft.cooked_mutton": "Cooked Mutton", + "item.minecraft.rabbit": "Raw Rabbit", + "item.minecraft.cooked_rabbit": "Cooked Rabbit", + "item.minecraft.rabbit_stew": "Rabbit Stew", + "item.minecraft.rabbit_foot": "Rabbit's Foot", + "item.minecraft.rabbit_hide": "Rabbit Hide", + "item.minecraft.beef": "Raw Beef", + "item.minecraft.cooked_beef": "Steak", + "item.minecraft.painting": "Painting", + "item.minecraft.item_frame": "Item Frame", + "item.minecraft.golden_apple": "Golden Apple", + "item.minecraft.enchanted_golden_apple": "Enchanted Golden Apple", + "item.minecraft.sign": "Sign", + "item.minecraft.bucket": "Bucket", + "item.minecraft.water_bucket": "Water Bucket", + "item.minecraft.lava_bucket": "Lava Bucket", + "item.minecraft.pufferfish_bucket": "Bucket of Pufferfish", + "item.minecraft.salmon_bucket": "Bucket of Salmon", + "item.minecraft.cod_bucket": "Bucket of Cod", + "item.minecraft.tropical_fish_bucket": "Bucket of Tropical Fish", + "item.minecraft.powder_snow_bucket": "Powder Snow Bucket", + "item.minecraft.axolotl_bucket": "Bucket of Axolotl", + "item.minecraft.tadpole_bucket": "Bucket of Tadpole", + "item.minecraft.minecart": "Minecart", + "item.minecraft.saddle": "Saddle", + "item.minecraft.redstone": "Redstone Dust", + "item.minecraft.snowball": "Snowball", + "item.minecraft.oak_boat": "Oak Boat", + "item.minecraft.oak_chest_boat": "Oak Boat with Chest", + "item.minecraft.spruce_boat": "Spruce Boat", + "item.minecraft.spruce_chest_boat": "Spruce Boat with Chest", + "item.minecraft.birch_boat": "Birch Boat", + "item.minecraft.birch_chest_boat": "Birch Boat with Chest", + "item.minecraft.jungle_boat": "Jungle Boat", + "item.minecraft.jungle_chest_boat": "Jungle Boat with Chest", + "item.minecraft.acacia_boat": "Acacia Boat", + "item.minecraft.acacia_chest_boat": "Acacia Boat with Chest", + "item.minecraft.dark_oak_boat": "Dark Oak Boat", + "item.minecraft.dark_oak_chest_boat": "Dark Oak Boat with Chest", + "item.minecraft.mangrove_boat": "Mangrove Boat", + "item.minecraft.mangrove_chest_boat": "Mangrove Boat with Chest", + "item.minecraft.bamboo_raft": "Bamboo Raft", + "item.minecraft.bamboo_chest_raft": "Bamboo Raft with Chest", + "item.minecraft.leather": "Leather", + "item.minecraft.milk_bucket": "Milk Bucket", + "item.minecraft.brick": "Brick", + "item.minecraft.clay_ball": "Clay Ball", + "item.minecraft.paper": "Paper", + "item.minecraft.book": "Book", + "item.minecraft.slime_ball": "Slimeball", + "item.minecraft.chest_minecart": "Minecart with Chest", + "item.minecraft.furnace_minecart": "Minecart with Furnace", + "item.minecraft.tnt_minecart": "Minecart with TNT", + "item.minecraft.hopper_minecart": "Minecart with Hopper", + "item.minecraft.command_block_minecart": "Minecart with Command Block", + "item.minecraft.egg": "Egg", + "item.minecraft.compass": "Compass", + "item.minecraft.recovery_compass": "Recovery Compass", + "item.minecraft.fishing_rod": "Fishing Rod", + "item.minecraft.clock": "Clock", + "item.minecraft.glowstone_dust": "Glowstone Dust", + "item.minecraft.cod": "Raw Cod", + "item.minecraft.salmon": "Raw Salmon", + "item.minecraft.pufferfish": "Pufferfish", + "item.minecraft.tropical_fish": "Tropical Fish", + "item.minecraft.cooked_cod": "Cooked Cod", + "item.minecraft.cooked_salmon": "Cooked Salmon", + "item.minecraft.music_disc_13": "Music Disc", + "item.minecraft.music_disc_cat": "Music Disc", + "item.minecraft.music_disc_blocks": "Music Disc", + "item.minecraft.music_disc_chirp": "Music Disc", + "item.minecraft.music_disc_far": "Music Disc", + "item.minecraft.music_disc_mall": "Music Disc", + "item.minecraft.music_disc_mellohi": "Music Disc", + "item.minecraft.music_disc_stal": "Music Disc", + "item.minecraft.music_disc_strad": "Music Disc", + "item.minecraft.music_disc_ward": "Music Disc", + "item.minecraft.music_disc_11": "Music Disc", + "item.minecraft.music_disc_wait": "Music Disc", + "item.minecraft.music_disc_pigstep": "Music Disc", + "item.minecraft.music_disc_otherside": "Music Disc", + "item.minecraft.music_disc_5": "Music Disc", + "item.minecraft.music_disc_13.desc": "C418 - 13", + "item.minecraft.music_disc_cat.desc": "C418 - cat", + "item.minecraft.music_disc_blocks.desc": "C418 - blocks", + "item.minecraft.music_disc_chirp.desc": "C418 - chirp", + "item.minecraft.music_disc_far.desc": "C418 - far", + "item.minecraft.music_disc_mall.desc": "C418 - mall", + "item.minecraft.music_disc_mellohi.desc": "C418 - mellohi", + "item.minecraft.music_disc_stal.desc": "C418 - stal", + "item.minecraft.music_disc_strad.desc": "C418 - strad", + "item.minecraft.music_disc_ward.desc": "C418 - ward", + "item.minecraft.music_disc_11.desc": "C418 - 11", + "item.minecraft.music_disc_wait.desc": "C418 - wait", + "item.minecraft.music_disc_pigstep.desc": "Lena Raine - Pigstep", + "item.minecraft.music_disc_otherside.desc": "Lena Raine - otherside", + "item.minecraft.music_disc_5.desc": "Samuel Åberg - 5", + "item.minecraft.bone": "Bone", + "item.minecraft.ink_sac": "Ink Sac", + "item.minecraft.red_dye": "Red Dye", + "item.minecraft.green_dye": "Green Dye", + "item.minecraft.cocoa_beans": "Cocoa Beans", + "item.minecraft.lapis_lazuli": "Lapis Lazuli", + "item.minecraft.purple_dye": "Purple Dye", + "item.minecraft.cyan_dye": "Cyan Dye", + "item.minecraft.light_gray_dye": "Light Gray Dye", + "item.minecraft.gray_dye": "Gray Dye", + "item.minecraft.pink_dye": "Pink Dye", + "item.minecraft.lime_dye": "Lime Dye", + "item.minecraft.yellow_dye": "Yellow Dye", + "item.minecraft.light_blue_dye": "Light Blue Dye", + "item.minecraft.magenta_dye": "Magenta Dye", + "item.minecraft.orange_dye": "Orange Dye", + "item.minecraft.bone_meal": "Bone Meal", + "item.minecraft.blue_dye": "Blue Dye", + "item.minecraft.black_dye": "Black Dye", + "item.minecraft.brown_dye": "Brown Dye", + "item.minecraft.white_dye": "White Dye", + "item.minecraft.sugar": "Sugar", + "item.minecraft.amethyst_shard": "Amethyst Shard", + "item.minecraft.spyglass": "Spyglass", + "item.minecraft.glow_berries": "Glow Berries", + "item.minecraft.disc_fragment_5": "Disc Fragment", + "item.minecraft.disc_fragment_5.desc": "Music Disc - 5", + "block.minecraft.black_bed": "Black Bed", + "block.minecraft.red_bed": "Red Bed", + "block.minecraft.green_bed": "Green Bed", + "block.minecraft.brown_bed": "Brown Bed", + "block.minecraft.blue_bed": "Blue Bed", + "block.minecraft.purple_bed": "Purple Bed", + "block.minecraft.cyan_bed": "Cyan Bed", + "block.minecraft.light_gray_bed": "Light Gray Bed", + "block.minecraft.gray_bed": "Gray Bed", + "block.minecraft.pink_bed": "Pink Bed", + "block.minecraft.lime_bed": "Lime Bed", + "block.minecraft.yellow_bed": "Yellow Bed", + "block.minecraft.light_blue_bed": "Light Blue Bed", + "block.minecraft.magenta_bed": "Magenta Bed", + "block.minecraft.orange_bed": "Orange Bed", + "block.minecraft.white_bed": "White Bed", + "block.minecraft.repeater": "Redstone Repeater", + "block.minecraft.comparator": "Redstone Comparator", + "item.minecraft.filled_map": "Map", + "item.minecraft.shears": "Shears", + "item.minecraft.rotten_flesh": "Rotten Flesh", + "item.minecraft.ender_pearl": "Ender Pearl", + "item.minecraft.blaze_rod": "Blaze Rod", + "item.minecraft.ghast_tear": "Ghast Tear", + "item.minecraft.nether_wart": "Nether Wart", + "item.minecraft.potion": "Potion", + "item.minecraft.splash_potion": "Splash Potion", + "item.minecraft.lingering_potion": "Lingering Potion", + "item.minecraft.end_crystal": "End Crystal", + "item.minecraft.gold_nugget": "Gold Nugget", + "item.minecraft.glass_bottle": "Glass Bottle", + "item.minecraft.spider_eye": "Spider Eye", + "item.minecraft.fermented_spider_eye": "Fermented Spider Eye", + "item.minecraft.blaze_powder": "Blaze Powder", + "item.minecraft.magma_cream": "Magma Cream", + "item.minecraft.cauldron": "Cauldron", + "item.minecraft.brewing_stand": "Brewing Stand", + "item.minecraft.ender_eye": "Eye of Ender", + "item.minecraft.glistering_melon_slice": "Glistering Melon Slice", + "item.minecraft.allay_spawn_egg": "Allay Spawn Egg", + "item.minecraft.axolotl_spawn_egg": "Axolotl Spawn Egg", + "item.minecraft.bat_spawn_egg": "Bat Spawn Egg", + "item.minecraft.bee_spawn_egg": "Bee Spawn Egg", + "item.minecraft.blaze_spawn_egg": "Blaze Spawn Egg", + "item.minecraft.cat_spawn_egg": "Cat Spawn Egg", + "item.minecraft.camel_spawn_egg": "Camel Spawn Egg", + "item.minecraft.cave_spider_spawn_egg": "Cave Spider Spawn Egg", + "item.minecraft.chicken_spawn_egg": "Chicken Spawn Egg", + "item.minecraft.cod_spawn_egg": "Cod Spawn Egg", + "item.minecraft.cow_spawn_egg": "Cow Spawn Egg", + "item.minecraft.creeper_spawn_egg": "Creeper Spawn Egg", + "item.minecraft.dolphin_spawn_egg": "Dolphin Spawn Egg", + "item.minecraft.donkey_spawn_egg": "Donkey Spawn Egg", + "item.minecraft.drowned_spawn_egg": "Drowned Spawn Egg", + "item.minecraft.elder_guardian_spawn_egg": "Elder Guardian Spawn Egg", + "item.minecraft.ender_dragon_spawn_egg": "Ender Dragon Spawn Egg", + "item.minecraft.enderman_spawn_egg": "Enderman Spawn Egg", + "item.minecraft.endermite_spawn_egg": "Endermite Spawn Egg", + "item.minecraft.evoker_spawn_egg": "Evoker Spawn Egg", + "item.minecraft.ghast_spawn_egg": "Ghast Spawn Egg", + "item.minecraft.glow_squid_spawn_egg": "Glow Squid Spawn Egg", + "item.minecraft.guardian_spawn_egg": "Guardian Spawn Egg", + "item.minecraft.hoglin_spawn_egg": "Hoglin Spawn Egg", + "item.minecraft.horse_spawn_egg": "Horse Spawn Egg", + "item.minecraft.husk_spawn_egg": "Husk Spawn Egg", + "item.minecraft.iron_golem_spawn_egg": "Iron Golem Spawn Egg", + "item.minecraft.ravager_spawn_egg": "Ravager Spawn Egg", + "item.minecraft.llama_spawn_egg": "Llama Spawn Egg", + "item.minecraft.magma_cube_spawn_egg": "Magma Cube Spawn Egg", + "item.minecraft.mooshroom_spawn_egg": "Mooshroom Spawn Egg", + "item.minecraft.mule_spawn_egg": "Mule Spawn Egg", + "item.minecraft.ocelot_spawn_egg": "Ocelot Spawn Egg", + "item.minecraft.panda_spawn_egg": "Panda Spawn Egg", + "item.minecraft.parrot_spawn_egg": "Parrot Spawn Egg", + "item.minecraft.pig_spawn_egg": "Pig Spawn Egg", + "item.minecraft.piglin_spawn_egg": "Piglin Spawn Egg", + "item.minecraft.piglin_brute_spawn_egg": "Piglin Brute Spawn Egg", + "item.minecraft.pillager_spawn_egg": "Pillager Spawn Egg", + "item.minecraft.phantom_spawn_egg": "Phantom Spawn Egg", + "item.minecraft.polar_bear_spawn_egg": "Polar Bear Spawn Egg", + "item.minecraft.pufferfish_spawn_egg": "Pufferfish Spawn Egg", + "item.minecraft.rabbit_spawn_egg": "Rabbit Spawn Egg", + "item.minecraft.fox_spawn_egg": "Fox Spawn Egg", + "item.minecraft.frog_spawn_egg": "Frog Spawn Egg", + "item.minecraft.salmon_spawn_egg": "Salmon Spawn Egg", + "item.minecraft.sheep_spawn_egg": "Sheep Spawn Egg", + "item.minecraft.shulker_spawn_egg": "Shulker Spawn Egg", + "item.minecraft.silverfish_spawn_egg": "Silverfish Spawn Egg", + "item.minecraft.skeleton_spawn_egg": "Skeleton Spawn Egg", + "item.minecraft.skeleton_horse_spawn_egg": "Skeleton Horse Spawn Egg", + "item.minecraft.slime_spawn_egg": "Slime Spawn Egg", + "item.minecraft.snow_golem_spawn_egg": "Snow Golem Spawn Egg", + "item.minecraft.spider_spawn_egg": "Spider Spawn Egg", + "item.minecraft.squid_spawn_egg": "Squid Spawn Egg", + "item.minecraft.stray_spawn_egg": "Stray Spawn Egg", + "item.minecraft.strider_spawn_egg": "Strider Spawn Egg", + "item.minecraft.tadpole_spawn_egg": "Tadpole Spawn Egg", + "item.minecraft.trader_llama_spawn_egg": "Trader Llama Spawn Egg", + "item.minecraft.tropical_fish_spawn_egg": "Tropical Fish Spawn Egg", + "item.minecraft.turtle_spawn_egg": "Turtle Spawn Egg", + "item.minecraft.vex_spawn_egg": "Vex Spawn Egg", + "item.minecraft.villager_spawn_egg": "Villager Spawn Egg", + "item.minecraft.wandering_trader_spawn_egg": "Wandering Trader Spawn Egg", + "item.minecraft.vindicator_spawn_egg": "Vindicator Spawn Egg", + "item.minecraft.warden_spawn_egg": "Warden Spawn Egg", + "item.minecraft.witch_spawn_egg": "Witch Spawn Egg", + "item.minecraft.wither_spawn_egg": "Wither Spawn Egg", + "item.minecraft.wither_skeleton_spawn_egg": "Wither Skeleton Spawn Egg", + "item.minecraft.wolf_spawn_egg": "Wolf Spawn Egg", + "item.minecraft.zoglin_spawn_egg": "Zoglin Spawn Egg", + "item.minecraft.zombie_spawn_egg": "Zombie Spawn Egg", + "item.minecraft.zombie_horse_spawn_egg": "Zombie Horse Spawn Egg", + "item.minecraft.zombified_piglin_spawn_egg": "Zombified Piglin Spawn Egg", + "item.minecraft.zombie_villager_spawn_egg": "Zombie Villager Spawn Egg", + "item.minecraft.goat_spawn_egg": "Goat Spawn Egg", + "item.minecraft.experience_bottle": "Bottle o' Enchanting", + "item.minecraft.fire_charge": "Fire Charge", + "item.minecraft.writable_book": "Book and Quill", + "item.minecraft.written_book": "Written Book", + "item.minecraft.flower_pot": "Flower Pot", + "item.minecraft.map": "Empty Map", + "item.minecraft.carrot": "Carrot", + "item.minecraft.golden_carrot": "Golden Carrot", + "item.minecraft.potato": "Potato", + "item.minecraft.baked_potato": "Baked Potato", + "item.minecraft.poisonous_potato": "Poisonous Potato", + "item.minecraft.carrot_on_a_stick": "Carrot on a Stick", + "item.minecraft.nether_star": "Nether Star", + "item.minecraft.pumpkin_pie": "Pumpkin Pie", + "item.minecraft.enchanted_book": "Enchanted Book", + "item.minecraft.firework_rocket": "Firework Rocket", + "item.minecraft.firework_rocket.flight": "Flight Duration:", + "item.minecraft.firework_star": "Firework Star", + "item.minecraft.firework_star.black": "Black", + "item.minecraft.firework_star.red": "Red", + "item.minecraft.firework_star.green": "Green", + "item.minecraft.firework_star.brown": "Brown", + "item.minecraft.firework_star.blue": "Blue", + "item.minecraft.firework_star.purple": "Purple", + "item.minecraft.firework_star.cyan": "Cyan", + "item.minecraft.firework_star.light_gray": "Light Gray", + "item.minecraft.firework_star.gray": "Gray", + "item.minecraft.firework_star.pink": "Pink", + "item.minecraft.firework_star.lime": "Lime", + "item.minecraft.firework_star.yellow": "Yellow", + "item.minecraft.firework_star.light_blue": "Light Blue", + "item.minecraft.firework_star.magenta": "Magenta", + "item.minecraft.firework_star.orange": "Orange", + "item.minecraft.firework_star.white": "White", + "item.minecraft.firework_star.custom_color": "Custom", + "item.minecraft.firework_star.fade_to": "Fade to", + "item.minecraft.firework_star.flicker": "Twinkle", + "item.minecraft.firework_star.trail": "Trail", + "item.minecraft.firework_star.shape.small_ball": "Small Ball", + "item.minecraft.firework_star.shape.large_ball": "Large Ball", + "item.minecraft.firework_star.shape.star": "Star-shaped", + "item.minecraft.firework_star.shape.creeper": "Creeper-shaped", + "item.minecraft.firework_star.shape.burst": "Burst", + "item.minecraft.firework_star.shape": "Unknown Shape", + "item.minecraft.nether_brick": "Nether Brick", + "item.minecraft.quartz": "Nether Quartz", + "item.minecraft.armor_stand": "Armor Stand", + "item.minecraft.iron_horse_armor": "Iron Horse Armor", + "item.minecraft.golden_horse_armor": "Golden Horse Armor", + "item.minecraft.diamond_horse_armor": "Diamond Horse Armor", + "item.minecraft.leather_horse_armor": "Leather Horse Armor", + "item.minecraft.prismarine_shard": "Prismarine Shard", + "item.minecraft.prismarine_crystals": "Prismarine Crystals", + "item.minecraft.chorus_fruit": "Chorus Fruit", + "item.minecraft.popped_chorus_fruit": "Popped Chorus Fruit", + "item.minecraft.beetroot": "Beetroot", + "item.minecraft.beetroot_seeds": "Beetroot Seeds", + "item.minecraft.beetroot_soup": "Beetroot Soup", + "item.minecraft.dragon_breath": "Dragon's Breath", + "item.minecraft.elytra": "Elytra", + "item.minecraft.totem_of_undying": "Totem of Undying", + "item.minecraft.shulker_shell": "Shulker Shell", + "item.minecraft.iron_nugget": "Iron Nugget", + "item.minecraft.knowledge_book": "Knowledge Book", + "item.minecraft.debug_stick": "Debug Stick", + "item.minecraft.debug_stick.empty": "%s has no properties", + "item.minecraft.debug_stick.update": "\"%s\" to %s", + "item.minecraft.debug_stick.select": "selected \"%s\" (%s)", + "item.minecraft.trident": "Trident", + "item.minecraft.scute": "Scute", + "item.minecraft.turtle_helmet": "Turtle Shell", + "item.minecraft.phantom_membrane": "Phantom Membrane", + "item.minecraft.nautilus_shell": "Nautilus Shell", + "item.minecraft.heart_of_the_sea": "Heart of the Sea", + "item.minecraft.crossbow": "Crossbow", + "item.minecraft.crossbow.projectile": "Projectile:", + "item.minecraft.suspicious_stew": "Suspicious Stew", + "item.minecraft.creeper_banner_pattern": "Banner Pattern", + "item.minecraft.skull_banner_pattern": "Banner Pattern", + "item.minecraft.flower_banner_pattern": "Banner Pattern", + "item.minecraft.mojang_banner_pattern": "Banner Pattern", + "item.minecraft.globe_banner_pattern": "Banner Pattern", + "item.minecraft.creeper_banner_pattern.desc": "Creeper Charge", + "item.minecraft.skull_banner_pattern.desc": "Skull Charge", + "item.minecraft.flower_banner_pattern.desc": "Flower Charge", + "item.minecraft.mojang_banner_pattern.desc": "Thing", + "item.minecraft.globe_banner_pattern.desc": "Globe", + "item.minecraft.piglin_banner_pattern": "Banner Pattern", + "item.minecraft.piglin_banner_pattern.desc": "Snout", + "item.minecraft.sweet_berries": "Sweet Berries", + "item.minecraft.honey_bottle": "Honey Bottle", + "item.minecraft.honeycomb": "Honeycomb", + "item.minecraft.lodestone_compass": "Lodestone Compass", + "item.minecraft.netherite_scrap": "Netherite Scrap", + "item.minecraft.netherite_ingot": "Netherite Ingot", + "item.minecraft.netherite_helmet": "Netherite Helmet", + "item.minecraft.netherite_chestplate": "Netherite Chestplate", + "item.minecraft.netherite_leggings": "Netherite Leggings", + "item.minecraft.netherite_boots": "Netherite Boots", + "item.minecraft.netherite_axe": "Netherite Axe", + "item.minecraft.netherite_pickaxe": "Netherite Pickaxe", + "item.minecraft.netherite_hoe": "Netherite Hoe", + "item.minecraft.netherite_shovel": "Netherite Shovel", + "item.minecraft.netherite_sword": "Netherite Sword", + "item.minecraft.warped_fungus_on_a_stick": "Warped Fungus on a Stick", + "item.minecraft.glow_ink_sac": "Glow Ink Sac", + "item.minecraft.glow_item_frame": "Glow Item Frame", + "item.minecraft.echo_shard": "Echo Shard", + "item.minecraft.goat_horn": "Goat Horn", + "instrument.minecraft.ponder_goat_horn": "Ponder", + "instrument.minecraft.sing_goat_horn": "Sing", + "instrument.minecraft.seek_goat_horn": "Seek", + "instrument.minecraft.feel_goat_horn": "Feel", + "instrument.minecraft.admire_goat_horn": "Admire", + "instrument.minecraft.call_goat_horn": "Call", + "instrument.minecraft.yearn_goat_horn": "Yearn", + "instrument.minecraft.dream_goat_horn": "Dream", + "container.inventory": "Inventory", + "container.hopper": "Item Hopper", + "container.crafting": "Crafting", + "container.dispenser": "Dispenser", + "container.dropper": "Dropper", + "container.furnace": "Furnace", + "container.enchant": "Enchant", + "container.smoker": "Smoker", + "container.lectern": "Lectern", + "container.blast_furnace": "Blast Furnace", + "container.enchant.lapis.one": "1 Lapis Lazuli", + "container.enchant.lapis.many": "%s Lapis Lazuli", + "container.enchant.level.one": "1 Enchantment Level", + "container.enchant.level.many": "%s Enchantment Levels", + "container.enchant.level.requirement": "Level Requirement: %s", + "container.enchant.clue": "%s . . . ?", + "container.repair": "Repair & Name", + "container.repair.cost": "Enchantment Cost: %1$s", + "container.repair.expensive": "Too Expensive!", + "container.creative": "Item Selection", + "container.brewing": "Brewing Stand", + "container.chest": "Chest", + "container.chestDouble": "Large Chest", + "container.enderchest": "Ender Chest", + "container.beacon": "Beacon", + "container.shulkerBox": "Shulker Box", + "container.shulkerBox.more": "and %s more...", + "container.barrel": "Barrel", + "container.spectatorCantOpen": "Unable to open. Loot not generated yet.", + "container.isLocked": "%s is locked!", + "container.loom": "Loom", + "container.grindstone_title": "Repair & Disenchant", + "container.cartography_table": "Cartography Table", + "container.stonecutter": "Stonecutter", + "container.upgrade": "Upgrade Gear", + "structure_block.invalid_structure_name": "Invalid structure name '%s'", + "structure_block.save_success": "Structure saved as '%s'", + "structure_block.save_failure": "Unable to save structure '%s'", + "structure_block.load_success": "Structure loaded from '%s'", + "structure_block.load_prepare": "Structure '%s' position prepared", + "structure_block.load_not_found": "Structure '%s' is not available", + "structure_block.size_success": "Size successfully detected for '%s'", + "structure_block.size_failure": "Unable to detect structure size. Add corners with matching structure names", + "structure_block.mode.save": "Save", + "structure_block.mode.load": "Load", + "structure_block.mode.data": "Data", + "structure_block.mode.corner": "Corner", + "structure_block.hover.save": "Save: %s", + "structure_block.hover.load": "Load: %s", + "structure_block.hover.data": "Data: %s", + "structure_block.hover.corner": "Corner: %s", + "structure_block.mode_info.save": "Save Mode - Write to File", + "structure_block.mode_info.load": "Load Mode - Load from File", + "structure_block.mode_info.data": "Data Mode - Game Logic Marker", + "structure_block.mode_info.corner": "Corner Mode - Placement and Size Marker", + "structure_block.structure_name": "Structure Name", + "structure_block.custom_data": "Custom Data Tag Name", + "structure_block.position": "Relative Position", + "structure_block.position.x": "relative Position x", + "structure_block.position.y": "relative position y", + "structure_block.position.z": "relative position z", + "structure_block.size": "Structure Size", + "structure_block.size.x": "structure size x", + "structure_block.size.y": "structure size y", + "structure_block.size.z": "structure size z", + "structure_block.integrity": "Structure Integrity and Seed", + "structure_block.integrity.integrity": "Structure Integrity", + "structure_block.integrity.seed": "Structure Seed", + "structure_block.include_entities": "Include entities:", + "structure_block.detect_size": "Detect structure size and position:", + "structure_block.button.detect_size": "DETECT", + "structure_block.button.save": "SAVE", + "structure_block.button.load": "LOAD", + "structure_block.show_air": "Show Invisible Blocks:", + "structure_block.show_boundingbox": "Show Bounding Box:", + "jigsaw_block.pool": "Target Pool:", + "jigsaw_block.name": "Name:", + "jigsaw_block.target": "Target Name:", + "jigsaw_block.final_state": "Turns into:", + "jigsaw_block.levels": "Levels: %s", + "jigsaw_block.keep_jigsaws": "Keep Jigsaws", + "jigsaw_block.generate": "Generate", + "jigsaw_block.joint_label": "Joint Type:", + "jigsaw_block.joint.rollable": "Rollable", + "jigsaw_block.joint.aligned": "Aligned", + "item.dyed": "Dyed", + "item.unbreakable": "Unbreakable", + "item.canBreak": "Can break:", + "item.canPlace": "Can be placed on:", + "item.color": "Color: %s", + "item.nbt_tags": "NBT: %s tag(s)", + "item.durability": "Durability: %s / %s", + "item.disabled": "Disabled item", + "filled_map.mansion": "Woodland Explorer Map", + "filled_map.monument": "Ocean Explorer Map", + "filled_map.buried_treasure": "Buried Treasure Map", + "filled_map.unknown": "Unknown Map", + "filled_map.id": "Id #%s", + "filled_map.level": "(Level %s/%s)", + "filled_map.scale": "Scaling at 1:%s", + "filled_map.locked": "Locked", + "entity.minecraft.allay": "Allay", + "entity.minecraft.area_effect_cloud": "Area Effect Cloud", + "entity.minecraft.armor_stand": "Armor Stand", + "entity.minecraft.arrow": "Arrow", + "entity.minecraft.axolotl": "Axolotl", + "entity.minecraft.bat": "Bat", + "entity.minecraft.bee": "Bee", + "entity.minecraft.blaze": "Blaze", + "entity.minecraft.boat": "Boat", + "entity.minecraft.chest_boat": "Boat with Chest", + "entity.minecraft.cat": "Cat", + "entity.minecraft.camel": "Camel", + "entity.minecraft.cave_spider": "Cave Spider", + "entity.minecraft.chest_minecart": "Minecart with Chest", + "entity.minecraft.chicken": "Chicken", + "entity.minecraft.command_block_minecart": "Minecart with Command Block", + "entity.minecraft.cod": "Cod", + "entity.minecraft.cow": "Cow", + "entity.minecraft.creeper": "Creeper", + "entity.minecraft.dolphin": "Dolphin", + "entity.minecraft.donkey": "Donkey", + "entity.minecraft.drowned": "Drowned", + "entity.minecraft.dragon_fireball": "Dragon Fireball", + "entity.minecraft.egg": "Thrown Egg", + "entity.minecraft.elder_guardian": "Elder Guardian", + "entity.minecraft.end_crystal": "End Crystal", + "entity.minecraft.ender_dragon": "Ender Dragon", + "entity.minecraft.ender_pearl": "Thrown Ender Pearl", + "entity.minecraft.enderman": "Enderman", + "entity.minecraft.endermite": "Endermite", + "entity.minecraft.evoker_fangs": "Evoker Fangs", + "entity.minecraft.evoker": "Evoker", + "entity.minecraft.eye_of_ender": "Eye of Ender", + "entity.minecraft.falling_block": "Falling Block", + "entity.minecraft.fireball": "Fireball", + "entity.minecraft.firework_rocket": "Firework Rocket", + "entity.minecraft.fishing_bobber": "Fishing Bobber", + "entity.minecraft.fox": "Fox", + "entity.minecraft.frog": "Frog", + "entity.minecraft.furnace_minecart": "Minecart with Furnace", + "entity.minecraft.ghast": "Ghast", + "entity.minecraft.giant": "Giant", + "entity.minecraft.glow_item_frame": "Glow Item Frame", + "entity.minecraft.glow_squid": "Glow Squid", + "entity.minecraft.goat": "Goat", + "entity.minecraft.guardian": "Guardian", + "entity.minecraft.hoglin": "Hoglin", + "entity.minecraft.hopper_minecart": "Minecart with Hopper", + "entity.minecraft.horse": "Horse", + "entity.minecraft.husk": "Husk", + "entity.minecraft.ravager": "Ravager", + "entity.minecraft.illusioner": "Illusioner", + "entity.minecraft.item": "Item", + "entity.minecraft.item_frame": "Item Frame", + "entity.minecraft.killer_bunny": "The Killer Bunny", + "entity.minecraft.leash_knot": "Leash Knot", + "entity.minecraft.lightning_bolt": "Lightning Bolt", + "entity.minecraft.llama": "Llama", + "entity.minecraft.llama_spit": "Llama Spit", + "entity.minecraft.magma_cube": "Magma Cube", + "entity.minecraft.marker": "Marker", + "entity.minecraft.minecart": "Minecart", + "entity.minecraft.mooshroom": "Mooshroom", + "entity.minecraft.mule": "Mule", + "entity.minecraft.ocelot": "Ocelot", + "entity.minecraft.painting": "Painting", + "entity.minecraft.panda": "Panda", + "entity.minecraft.parrot": "Parrot", + "entity.minecraft.phantom": "Phantom", + "entity.minecraft.pig": "Pig", + "entity.minecraft.piglin": "Piglin", + "entity.minecraft.piglin_brute": "Piglin Brute", + "entity.minecraft.pillager": "Pillager", + "entity.minecraft.player": "Player", + "entity.minecraft.polar_bear": "Polar Bear", + "entity.minecraft.potion": "Potion", + "entity.minecraft.pufferfish": "Pufferfish", + "entity.minecraft.rabbit": "Rabbit", + "entity.minecraft.salmon": "Salmon", + "entity.minecraft.sheep": "Sheep", + "entity.minecraft.shulker": "Shulker", + "entity.minecraft.shulker_bullet": "Shulker Bullet", + "entity.minecraft.silverfish": "Silverfish", + "entity.minecraft.skeleton": "Skeleton", + "entity.minecraft.skeleton_horse": "Skeleton Horse", + "entity.minecraft.slime": "Slime", + "entity.minecraft.small_fireball": "Small Fireball", + "entity.minecraft.snowball": "Snowball", + "entity.minecraft.snow_golem": "Snow Golem", + "entity.minecraft.spawner_minecart": "Minecart with Monster Spawner", + "entity.minecraft.spectral_arrow": "Spectral Arrow", + "entity.minecraft.spider": "Spider", + "entity.minecraft.squid": "Squid", + "entity.minecraft.stray": "Stray", + "entity.minecraft.strider": "Strider", + "entity.minecraft.tadpole": "Tadpole", + "entity.minecraft.tnt": "Primed TNT", + "entity.minecraft.tnt_minecart": "Minecart with TNT", + "entity.minecraft.trader_llama": "Trader Llama", + "entity.minecraft.trident": "Trident", + "entity.minecraft.tropical_fish": "Tropical Fish", + "entity.minecraft.tropical_fish.predefined.0": "Anemone", + "entity.minecraft.tropical_fish.predefined.1": "Black Tang", + "entity.minecraft.tropical_fish.predefined.2": "Blue Tang", + "entity.minecraft.tropical_fish.predefined.3": "Butterflyfish", + "entity.minecraft.tropical_fish.predefined.4": "Cichlid", + "entity.minecraft.tropical_fish.predefined.5": "Clownfish", + "entity.minecraft.tropical_fish.predefined.6": "Cotton Candy Betta", + "entity.minecraft.tropical_fish.predefined.7": "Dottyback", + "entity.minecraft.tropical_fish.predefined.8": "Emperor Red Snapper", + "entity.minecraft.tropical_fish.predefined.9": "Goatfish", + "entity.minecraft.tropical_fish.predefined.10": "Moorish Idol", + "entity.minecraft.tropical_fish.predefined.11": "Ornate Butterflyfish", + "entity.minecraft.tropical_fish.predefined.12": "Parrotfish", + "entity.minecraft.tropical_fish.predefined.13": "Queen Angelfish", + "entity.minecraft.tropical_fish.predefined.14": "Red Cichlid", + "entity.minecraft.tropical_fish.predefined.15": "Red Lipped Blenny", + "entity.minecraft.tropical_fish.predefined.16": "Red Snapper", + "entity.minecraft.tropical_fish.predefined.17": "Threadfin", + "entity.minecraft.tropical_fish.predefined.18": "Tomato Clownfish", + "entity.minecraft.tropical_fish.predefined.19": "Triggerfish", + "entity.minecraft.tropical_fish.predefined.20": "Yellowtail Parrotfish", + "entity.minecraft.tropical_fish.predefined.21": "Yellow Tang", + "entity.minecraft.tropical_fish.type.flopper": "Flopper", + "entity.minecraft.tropical_fish.type.stripey": "Stripey", + "entity.minecraft.tropical_fish.type.glitter": "Glitter", + "entity.minecraft.tropical_fish.type.blockfish": "Blockfish", + "entity.minecraft.tropical_fish.type.betty": "Betty", + "entity.minecraft.tropical_fish.type.clayfish": "Clayfish", + "entity.minecraft.tropical_fish.type.kob": "Kob", + "entity.minecraft.tropical_fish.type.sunstreak": "Sunstreak", + "entity.minecraft.tropical_fish.type.snooper": "Snooper", + "entity.minecraft.tropical_fish.type.dasher": "Dasher", + "entity.minecraft.tropical_fish.type.brinely": "Brinely", + "entity.minecraft.tropical_fish.type.spotty": "Spotty", + "entity.minecraft.turtle": "Turtle", + "entity.minecraft.vex": "Vex", + "entity.minecraft.villager.armorer": "Armorer", + "entity.minecraft.villager.butcher": "Butcher", + "entity.minecraft.villager.cartographer": "Cartographer", + "entity.minecraft.villager.cleric": "Cleric", + "entity.minecraft.villager.farmer": "Farmer", + "entity.minecraft.villager.fisherman": "Fisherman", + "entity.minecraft.villager.fletcher": "Fletcher", + "entity.minecraft.villager.leatherworker": "Leatherworker", + "entity.minecraft.villager.librarian": "Librarian", + "entity.minecraft.villager.mason": "Mason", + "entity.minecraft.villager.none": "Villager", + "entity.minecraft.villager.nitwit": "Nitwit", + "entity.minecraft.villager.shepherd": "Shepherd", + "entity.minecraft.villager.toolsmith": "Toolsmith", + "entity.minecraft.villager.weaponsmith": "Weaponsmith", + "entity.minecraft.villager": "Villager", + "entity.minecraft.wandering_trader": "Wandering Trader", + "entity.minecraft.iron_golem": "Iron Golem", + "entity.minecraft.vindicator": "Vindicator", + "entity.minecraft.warden": "Warden", + "entity.minecraft.witch": "Witch", + "entity.minecraft.wither": "Wither", + "entity.minecraft.wither_skeleton": "Wither Skeleton", + "entity.minecraft.wither_skull": "Wither Skull", + "entity.minecraft.wolf": "Wolf", + "entity.minecraft.experience_bottle": "Thrown Bottle o' Enchanting", + "entity.minecraft.experience_orb": "Experience Orb", + "entity.minecraft.zoglin": "Zoglin", + "entity.minecraft.zombie": "Zombie", + "entity.minecraft.zombie_horse": "Zombie Horse", + "entity.minecraft.zombified_piglin": "Zombified Piglin", + "entity.minecraft.zombie_villager": "Zombie Villager", + "death.fell.accident.ladder": "%1$s fell off a ladder", + "death.fell.accident.vines": "%1$s fell off some vines", + "death.fell.accident.weeping_vines": "%1$s fell off some weeping vines", + "death.fell.accident.twisting_vines": "%1$s fell off some twisting vines", + "death.fell.accident.scaffolding": "%1$s fell off scaffolding", + "death.fell.accident.other_climbable": "%1$s fell while climbing", + "death.fell.accident.generic": "%1$s fell from a high place", + "death.fell.killer": "%1$s was doomed to fall", + "death.fell.assist": "%1$s was doomed to fall by %2$s", + "death.fell.assist.item": "%1$s was doomed to fall by %2$s using %3$s", + "death.fell.finish": "%1$s fell too far and was finished by %2$s", + "death.fell.finish.item": "%1$s fell too far and was finished by %2$s using %3$s", + "death.attack.lightningBolt": "%1$s was struck by lightning", + "death.attack.lightningBolt.player": "%1$s was struck by lightning whilst fighting %2$s", + "death.attack.inFire": "%1$s went up in flames", + "death.attack.inFire.player": "%1$s walked into fire whilst fighting %2$s", + "death.attack.onFire": "%1$s burned to death", + "death.attack.onFire.item": "%1$s was burnt to a crisp whilst fighting %2$s wielding %3$s", + "death.attack.onFire.player": "%1$s was burnt to a crisp whilst fighting %2$s", + "death.attack.lava": "%1$s tried to swim in lava", + "death.attack.lava.player": "%1$s tried to swim in lava to escape %2$s", + "death.attack.hotFloor": "%1$s discovered the floor was lava", + "death.attack.hotFloor.player": "%1$s walked into danger zone due to %2$s", + "death.attack.inWall": "%1$s suffocated in a wall", + "death.attack.inWall.player": "%1$s suffocated in a wall whilst fighting %2$s", + "death.attack.cramming": "%1$s was squished too much", + "death.attack.cramming.player": "%1$s was squashed by %2$s", + "death.attack.drown": "%1$s drowned", + "death.attack.drown.player": "%1$s drowned whilst trying to escape %2$s", + "death.attack.dryout": "%1$s died from dehydration", + "death.attack.dryout.player": "%1$s died from dehydration whilst trying to escape %2$s", + "death.attack.starve": "%1$s starved to death", + "death.attack.starve.player": "%1$s starved to death whilst fighting %2$s", + "death.attack.cactus": "%1$s was pricked to death", + "death.attack.cactus.player": "%1$s walked into a cactus whilst trying to escape %2$s", + "death.attack.generic": "%1$s died", + "death.attack.generic.player": "%1$s died because of %2$s", + "death.attack.explosion": "%1$s blew up", + "death.attack.explosion.player": "%1$s was blown up by %2$s", + "death.attack.explosion.player.item": "%1$s was blown up by %2$s using %3$s", + "death.attack.magic": "%1$s was killed by magic", + "death.attack.magic.player": "%1$s was killed by magic whilst trying to escape %2$s", + "death.attack.even_more_magic": "%1$s was killed by even more magic", + "death.attack.message_too_long": "Actually, message was too long to deliver fully. Sorry! Here's stripped version: %s", + "death.attack.wither": "%1$s withered away", + "death.attack.wither.player": "%1$s withered away whilst fighting %2$s", + "death.attack.witherSkull": "%1$s was shot by a skull from %2$s", + "death.attack.witherSkull.item": "%1$s was shot by a skull from %2$s using %3$s", + "death.attack.anvil": "%1$s was squashed by a falling anvil", + "death.attack.anvil.player": "%1$s was squashed by a falling anvil whilst fighting %2$s", + "death.attack.fallingBlock": "%1$s was squashed by a falling block", + "death.attack.fallingBlock.player": "%1$s was squashed by a falling block whilst fighting %2$s", + "death.attack.stalagmite": "%1$s was impaled on a stalagmite", + "death.attack.stalagmite.player": "%1$s was impaled on a stalagmite whilst fighting %2$s", + "death.attack.fallingStalactite": "%1$s was skewered by a falling stalactite", + "death.attack.fallingStalactite.player": "%1$s was skewered by a falling stalactite whilst fighting %2$s", + "death.attack.sonic_boom": "%1$s was obliterated by a sonically-charged shriek", + "death.attack.sonic_boom.item": "%1$s was obliterated by a sonically-charged shriek whilst trying to escape %2$s wielding %3$s", + "death.attack.sonic_boom.player": "%1$s was obliterated by a sonically-charged shriek whilst trying to escape %2$s", + "death.attack.mob": "%1$s was slain by %2$s", + "death.attack.mob.item": "%1$s was slain by %2$s using %3$s", + "death.attack.player": "%1$s was slain by %2$s", + "death.attack.player.item": "%1$s was slain by %2$s using %3$s", + "death.attack.arrow": "%1$s was shot by %2$s", + "death.attack.arrow.item": "%1$s was shot by %2$s using %3$s", + "death.attack.fireball": "%1$s was fireballed by %2$s", + "death.attack.fireball.item": "%1$s was fireballed by %2$s using %3$s", + "death.attack.thrown": "%1$s was pummeled by %2$s", + "death.attack.thrown.item": "%1$s was pummeled by %2$s using %3$s", + "death.attack.indirectMagic": "%1$s was killed by %2$s using magic", + "death.attack.indirectMagic.item": "%1$s was killed by %2$s using %3$s", + "death.attack.thorns": "%1$s was killed trying to hurt %2$s", + "death.attack.thorns.item": "%1$s was killed by %3$s trying to hurt %2$s", + "death.attack.trident": "%1$s was impaled by %2$s", + "death.attack.trident.item": "%1$s was impaled by %2$s with %3$s", + "death.attack.fall": "%1$s hit the ground too hard", + "death.attack.fall.player": "%1$s hit the ground too hard whilst trying to escape %2$s", + "death.attack.outOfWorld": "%1$s fell out of the world", + "death.attack.outOfWorld.player": "%1$s didn't want to live in the same world as %2$s", + "death.attack.dragonBreath": "%1$s was roasted in dragon breath", + "death.attack.dragonBreath.player": "%1$s was roasted in dragon breath by %2$s", + "death.attack.flyIntoWall": "%1$s experienced kinetic energy", + "death.attack.flyIntoWall.player": "%1$s experienced kinetic energy whilst trying to escape %2$s", + "death.attack.fireworks": "%1$s went off with a bang", + "death.attack.fireworks.player": "%1$s went off with a bang whilst fighting %2$s", + "death.attack.fireworks.item": "%1$s went off with a bang due to a firework fired from %3$s by %2$s", + "death.attack.badRespawnPoint.message": "%1$s was killed by %2$s", + "death.attack.badRespawnPoint.link": "Intentional Game Design", + "death.attack.sweetBerryBush": "%1$s was poked to death by a sweet berry bush", + "death.attack.sweetBerryBush.player": "%1$s was poked to death by a sweet berry bush whilst trying to escape %2$s", + "death.attack.sting": "%1$s was stung to death", + "death.attack.sting.item": "%1$s was stung to death by %2$s using %3$s", + "death.attack.sting.player": "%1$s was stung to death by %2$s", + "death.attack.freeze": "%1$s froze to death", + "death.attack.freeze.player": "%1$s was frozen to death by %2$s", + "deathScreen.respawn": "Respawn", + "deathScreen.spectate": "Spectate World", + "deathScreen.titleScreen": "Title Screen", + "deathScreen.score": "Score", + "deathScreen.title.hardcore": "Game Over!", + "deathScreen.title": "You Died!", + "deathScreen.quit.confirm": "Are you sure you want to quit?", + "effect.none": "No Effects", + "effect.minecraft.speed": "Speed", + "effect.minecraft.slowness": "Slowness", + "effect.minecraft.haste": "Haste", + "effect.minecraft.mining_fatigue": "Mining Fatigue", + "effect.minecraft.strength": "Strength", + "effect.minecraft.instant_health": "Instant Health", + "effect.minecraft.instant_damage": "Instant Damage", + "effect.minecraft.jump_boost": "Jump Boost", + "effect.minecraft.nausea": "Nausea", + "effect.minecraft.regeneration": "Regeneration", + "effect.minecraft.resistance": "Resistance", + "effect.minecraft.fire_resistance": "Fire Resistance", + "effect.minecraft.water_breathing": "Water Breathing", + "effect.minecraft.invisibility": "Invisibility", + "effect.minecraft.blindness": "Blindness", + "effect.minecraft.night_vision": "Night Vision", + "effect.minecraft.hunger": "Hunger", + "effect.minecraft.weakness": "Weakness", + "effect.minecraft.poison": "Poison", + "effect.minecraft.wither": "Wither", + "effect.minecraft.health_boost": "Health Boost", + "effect.minecraft.absorption": "Absorption", + "effect.minecraft.saturation": "Saturation", + "effect.minecraft.glowing": "Glowing", + "effect.minecraft.luck": "Luck", + "effect.minecraft.unluck": "Bad Luck", + "effect.minecraft.levitation": "Levitation", + "effect.minecraft.slow_falling": "Slow Falling", + "effect.minecraft.conduit_power": "Conduit Power", + "effect.minecraft.dolphins_grace": "Dolphin's Grace", + "effect.minecraft.bad_omen": "Bad Omen", + "effect.minecraft.hero_of_the_village": "Hero of the Village", + "effect.minecraft.darkness": "Darkness", + "event.minecraft.raid": "Raid", + "event.minecraft.raid.raiders_remaining": "Raiders Remaining: %s", + "event.minecraft.raid.victory": "Victory", + "event.minecraft.raid.defeat": "Defeat", + "item.minecraft.tipped_arrow.effect.empty": "Uncraftable Tipped Arrow", + "item.minecraft.tipped_arrow.effect.water": "Arrow of Splashing", + "item.minecraft.tipped_arrow.effect.mundane": "Tipped Arrow", + "item.minecraft.tipped_arrow.effect.thick": "Tipped Arrow", + "item.minecraft.tipped_arrow.effect.awkward": "Tipped Arrow", + "item.minecraft.tipped_arrow.effect.night_vision": "Arrow of Night Vision", + "item.minecraft.tipped_arrow.effect.invisibility": "Arrow of Invisibility", + "item.minecraft.tipped_arrow.effect.leaping": "Arrow of Leaping", + "item.minecraft.tipped_arrow.effect.fire_resistance": "Arrow of Fire Resistance", + "item.minecraft.tipped_arrow.effect.swiftness": "Arrow of Swiftness", + "item.minecraft.tipped_arrow.effect.slowness": "Arrow of Slowness", + "item.minecraft.tipped_arrow.effect.water_breathing": "Arrow of Water Breathing", + "item.minecraft.tipped_arrow.effect.healing": "Arrow of Healing", + "item.minecraft.tipped_arrow.effect.harming": "Arrow of Harming", + "item.minecraft.tipped_arrow.effect.poison": "Arrow of Poison", + "item.minecraft.tipped_arrow.effect.regeneration": "Arrow of Regeneration", + "item.minecraft.tipped_arrow.effect.strength": "Arrow of Strength", + "item.minecraft.tipped_arrow.effect.weakness": "Arrow of Weakness", + "item.minecraft.tipped_arrow.effect.levitation": "Arrow of Levitation", + "item.minecraft.tipped_arrow.effect.luck": "Arrow of Luck", + "item.minecraft.tipped_arrow.effect.turtle_master": "Arrow of the Turtle Master", + "item.minecraft.tipped_arrow.effect.slow_falling": "Arrow of Slow Falling", + "potion.whenDrank": "When Applied:", + "potion.withAmplifier": "%s %s", + "potion.withDuration": "%s (%s)", + "item.minecraft.potion.effect.empty": "Uncraftable Potion", + "item.minecraft.potion.effect.water": "Water Bottle", + "item.minecraft.potion.effect.mundane": "Mundane Potion", + "item.minecraft.potion.effect.thick": "Thick Potion", + "item.minecraft.potion.effect.awkward": "Awkward Potion", + "item.minecraft.potion.effect.night_vision": "Potion of Night Vision", + "item.minecraft.potion.effect.invisibility": "Potion of Invisibility", + "item.minecraft.potion.effect.leaping": "Potion of Leaping", + "item.minecraft.potion.effect.fire_resistance": "Potion of Fire Resistance", + "item.minecraft.potion.effect.swiftness": "Potion of Swiftness", + "item.minecraft.potion.effect.slowness": "Potion of Slowness", + "item.minecraft.potion.effect.water_breathing": "Potion of Water Breathing", + "item.minecraft.potion.effect.healing": "Potion of Healing", + "item.minecraft.potion.effect.harming": "Potion of Harming", + "item.minecraft.potion.effect.poison": "Potion of Poison", + "item.minecraft.potion.effect.regeneration": "Potion of Regeneration", + "item.minecraft.potion.effect.strength": "Potion of Strength", + "item.minecraft.potion.effect.weakness": "Potion of Weakness", + "item.minecraft.potion.effect.levitation": "Potion of Levitation", + "item.minecraft.potion.effect.luck": "Potion of Luck", + "item.minecraft.potion.effect.turtle_master": "Potion of the Turtle Master", + "item.minecraft.potion.effect.slow_falling": "Potion of Slow Falling", + "item.minecraft.splash_potion.effect.empty": "Splash Uncraftable Potion", + "item.minecraft.splash_potion.effect.water": "Splash Water Bottle", + "item.minecraft.splash_potion.effect.mundane": "Mundane Splash Potion", + "item.minecraft.splash_potion.effect.thick": "Thick Splash Potion", + "item.minecraft.splash_potion.effect.awkward": "Awkward Splash Potion", + "item.minecraft.splash_potion.effect.night_vision": "Splash Potion of Night Vision", + "item.minecraft.splash_potion.effect.invisibility": "Splash Potion of Invisibility", + "item.minecraft.splash_potion.effect.leaping": "Splash Potion of Leaping", + "item.minecraft.splash_potion.effect.fire_resistance": "Splash Potion of Fire Resistance", + "item.minecraft.splash_potion.effect.swiftness": "Splash Potion of Swiftness", + "item.minecraft.splash_potion.effect.slowness": "Splash Potion of Slowness", + "item.minecraft.splash_potion.effect.water_breathing": "Splash Potion of Water Breathing", + "item.minecraft.splash_potion.effect.healing": "Splash Potion of Healing", + "item.minecraft.splash_potion.effect.harming": "Splash Potion of Harming", + "item.minecraft.splash_potion.effect.poison": "Splash Potion of Poison", + "item.minecraft.splash_potion.effect.regeneration": "Splash Potion of Regeneration", + "item.minecraft.splash_potion.effect.strength": "Splash Potion of Strength", + "item.minecraft.splash_potion.effect.weakness": "Splash Potion of Weakness", + "item.minecraft.splash_potion.effect.levitation": "Splash Potion of Levitation", + "item.minecraft.splash_potion.effect.luck": "Splash Potion of Luck", + "item.minecraft.splash_potion.effect.turtle_master": "Splash Potion of the Turtle Master", + "item.minecraft.splash_potion.effect.slow_falling": "Splash Potion of Slow Falling", + "item.minecraft.lingering_potion.effect.empty": "Lingering Uncraftable Potion", + "item.minecraft.lingering_potion.effect.water": "Lingering Water Bottle", + "item.minecraft.lingering_potion.effect.mundane": "Mundane Lingering Potion", + "item.minecraft.lingering_potion.effect.thick": "Thick Lingering Potion", + "item.minecraft.lingering_potion.effect.awkward": "Awkward Lingering Potion", + "item.minecraft.lingering_potion.effect.night_vision": "Lingering Potion of Night Vision", + "item.minecraft.lingering_potion.effect.invisibility": "Lingering Potion of Invisibility", + "item.minecraft.lingering_potion.effect.leaping": "Lingering Potion of Leaping", + "item.minecraft.lingering_potion.effect.fire_resistance": "Lingering Potion of Fire Resistance", + "item.minecraft.lingering_potion.effect.swiftness": "Lingering Potion of Swiftness", + "item.minecraft.lingering_potion.effect.slowness": "Lingering Potion of Slowness", + "item.minecraft.lingering_potion.effect.water_breathing": "Lingering Potion of Water Breathing", + "item.minecraft.lingering_potion.effect.healing": "Lingering Potion of Healing", + "item.minecraft.lingering_potion.effect.harming": "Lingering Potion of Harming", + "item.minecraft.lingering_potion.effect.poison": "Lingering Potion of Poison", + "item.minecraft.lingering_potion.effect.regeneration": "Lingering Potion of Regeneration", + "item.minecraft.lingering_potion.effect.strength": "Lingering Potion of Strength", + "item.minecraft.lingering_potion.effect.weakness": "Lingering Potion of Weakness", + "item.minecraft.lingering_potion.effect.levitation": "Lingering Potion of Levitation", + "item.minecraft.lingering_potion.effect.luck": "Lingering Potion of Luck", + "item.minecraft.lingering_potion.effect.turtle_master": "Lingering Potion of the Turtle Master", + "item.minecraft.lingering_potion.effect.slow_falling": "Lingering Potion of Slow Falling", + "potion.potency.0": "", + "potion.potency.1": "II", + "potion.potency.2": "III", + "potion.potency.3": "IV", + "potion.potency.4": "V", + "potion.potency.5": "VI", + "enchantment.minecraft.sharpness": "Sharpness", + "enchantment.minecraft.smite": "Smite", + "enchantment.minecraft.bane_of_arthropods": "Bane of Arthropods", + "enchantment.minecraft.knockback": "Knockback", + "enchantment.minecraft.fire_aspect": "Fire Aspect", + "enchantment.minecraft.sweeping": "Sweeping Edge", + "enchantment.minecraft.protection": "Protection", + "enchantment.minecraft.fire_protection": "Fire Protection", + "enchantment.minecraft.feather_falling": "Feather Falling", + "enchantment.minecraft.blast_protection": "Blast Protection", + "enchantment.minecraft.projectile_protection": "Projectile Protection", + "enchantment.minecraft.respiration": "Respiration", + "enchantment.minecraft.aqua_affinity": "Aqua Affinity", + "enchantment.minecraft.depth_strider": "Depth Strider", + "enchantment.minecraft.frost_walker": "Frost Walker", + "enchantment.minecraft.soul_speed": "Soul Speed", + "enchantment.minecraft.swift_sneak": "Swift Sneak", + "enchantment.minecraft.efficiency": "Efficiency", + "enchantment.minecraft.silk_touch": "Silk Touch", + "enchantment.minecraft.unbreaking": "Unbreaking", + "enchantment.minecraft.looting": "Looting", + "enchantment.minecraft.fortune": "Fortune", + "enchantment.minecraft.luck_of_the_sea": "Luck of the Sea", + "enchantment.minecraft.lure": "Lure", + "enchantment.minecraft.power": "Power", + "enchantment.minecraft.flame": "Flame", + "enchantment.minecraft.punch": "Punch", + "enchantment.minecraft.infinity": "Infinity", + "enchantment.minecraft.thorns": "Thorns", + "enchantment.minecraft.mending": "Mending", + "enchantment.minecraft.binding_curse": "Curse of Binding", + "enchantment.minecraft.vanishing_curse": "Curse of Vanishing", + "enchantment.minecraft.loyalty": "Loyalty", + "enchantment.minecraft.impaling": "Impaling", + "enchantment.minecraft.riptide": "Riptide", + "enchantment.minecraft.channeling": "Channeling", + "enchantment.minecraft.multishot": "Multishot", + "enchantment.minecraft.quick_charge": "Quick Charge", + "enchantment.minecraft.piercing": "Piercing", + "enchantment.level.1": "I", + "enchantment.level.2": "II", + "enchantment.level.3": "III", + "enchantment.level.4": "IV", + "enchantment.level.5": "V", + "enchantment.level.6": "VI", + "enchantment.level.7": "VII", + "enchantment.level.8": "VIII", + "enchantment.level.9": "IX", + "enchantment.level.10": "X", + "gui.minutes": "%s minute(s)", + "gui.hours": "%s hour(s)", + "gui.days": "%s day(s)", + "gui.advancements": "Advancements", + "gui.stats": "Statistics", + "gui.entity_tooltip.type": "Type: %s", + "advancements.empty": "There doesn't seem to be anything here...", + "advancements.sad_label": ":(", + "advancements.toast.task": "Advancement Made!", + "advancements.toast.challenge": "Challenge Complete!", + "advancements.toast.goal": "Goal Reached!", + "stats.tooltip.type.statistic": "Statistic", + "stat.generalButton": "General", + "stat.itemsButton": "Items", + "stat.mobsButton": "Mobs", + "stat_type.minecraft.mined": "Times Mined", + "stat_type.minecraft.crafted": "Times Crafted", + "stat_type.minecraft.used": "Times Used", + "stat_type.minecraft.broken": "Times Broken", + "stat_type.minecraft.picked_up": "Picked Up", + "stat_type.minecraft.dropped": "Dropped", + "stat_type.minecraft.killed": "You killed %s %s", + "stat_type.minecraft.killed.none": "You have never killed %s", + "stat_type.minecraft.killed_by": "%s killed you %s time(s)", + "stat_type.minecraft.killed_by.none": "You have never been killed by %s", + "stat.minecraft.animals_bred": "Animals Bred", + "stat.minecraft.aviate_one_cm": "Distance by Elytra", + "stat.minecraft.clean_armor": "Armor Pieces Cleaned", + "stat.minecraft.clean_banner": "Banners Cleaned", + "stat.minecraft.clean_shulker_box": "Shulker Boxes Cleaned", + "stat.minecraft.climb_one_cm": "Distance Climbed", + "stat.minecraft.bell_ring": "Bells Rung", + "stat.minecraft.target_hit": "Targets Hit", + "stat.minecraft.boat_one_cm": "Distance by Boat", + "stat.minecraft.crouch_one_cm": "Distance Crouched", + "stat.minecraft.damage_dealt": "Damage Dealt", + "stat.minecraft.damage_dealt_absorbed": "Damage Dealt (Absorbed)", + "stat.minecraft.damage_dealt_resisted": "Damage Dealt (Resisted)", + "stat.minecraft.damage_taken": "Damage Taken", + "stat.minecraft.damage_blocked_by_shield": "Damage Blocked by Shield", + "stat.minecraft.damage_absorbed": "Damage Absorbed", + "stat.minecraft.damage_resisted": "Damage Resisted", + "stat.minecraft.deaths": "Number of Deaths", + "stat.minecraft.walk_under_water_one_cm": "Distance Walked under Water", + "stat.minecraft.drop": "Items Dropped", + "stat.minecraft.eat_cake_slice": "Cake Slices Eaten", + "stat.minecraft.enchant_item": "Items Enchanted", + "stat.minecraft.fall_one_cm": "Distance Fallen", + "stat.minecraft.fill_cauldron": "Cauldrons Filled", + "stat.minecraft.fish_caught": "Fish Caught", + "stat.minecraft.fly_one_cm": "Distance Flown", + "stat.minecraft.horse_one_cm": "Distance by Horse", + "stat.minecraft.inspect_dispenser": "Dispensers Searched", + "stat.minecraft.inspect_dropper": "Droppers Searched", + "stat.minecraft.inspect_hopper": "Hoppers Searched", + "stat.minecraft.interact_with_anvil": "Interactions with Anvil", + "stat.minecraft.interact_with_beacon": "Interactions with Beacon", + "stat.minecraft.interact_with_brewingstand": "Interactions with Brewing Stand", + "stat.minecraft.interact_with_campfire": "Interactions with Campfire", + "stat.minecraft.interact_with_cartography_table": "Interactions with Cartography Table", + "stat.minecraft.interact_with_crafting_table": "Interactions with Crafting Table", + "stat.minecraft.interact_with_furnace": "Interactions with Furnace", + "stat.minecraft.interact_with_grindstone": "Interactions with Grindstone", + "stat.minecraft.interact_with_lectern": "Interactions with Lectern", + "stat.minecraft.interact_with_loom": "Interactions with Loom", + "stat.minecraft.interact_with_blast_furnace": "Interactions with Blast Furnace", + "stat.minecraft.interact_with_smithing_table": "Interactions with Smithing Table", + "stat.minecraft.interact_with_smoker": "Interactions with Smoker", + "stat.minecraft.interact_with_stonecutter": "Interactions with Stonecutter", + "stat.minecraft.jump": "Jumps", + "stat.minecraft.junk_fished": "Junk Fished", + "stat.minecraft.leave_game": "Games Quit", + "stat.minecraft.minecart_one_cm": "Distance by Minecart", + "stat.minecraft.mob_kills": "Mob Kills", + "stat.minecraft.open_barrel": "Barrels Opened", + "stat.minecraft.open_chest": "Chests Opened", + "stat.minecraft.open_enderchest": "Ender Chests Opened", + "stat.minecraft.open_shulker_box": "Shulker Boxes Opened", + "stat.minecraft.pig_one_cm": "Distance by Pig", + "stat.minecraft.strider_one_cm": "Distance by Strider", + "stat.minecraft.player_kills": "Player Kills", + "stat.minecraft.play_noteblock": "Note Blocks Played", + "stat.minecraft.play_time": "Time Played", + "stat.minecraft.play_record": "Music Discs Played", + "stat.minecraft.pot_flower": "Plants Potted", + "stat.minecraft.raid_trigger": "Raids Triggered", + "stat.minecraft.raid_win": "Raids Won", + "stat.minecraft.ring_bell": "Bells Rung", + "stat.minecraft.sleep_in_bed": "Times Slept in a Bed", + "stat.minecraft.sneak_time": "Sneak Time", + "stat.minecraft.sprint_one_cm": "Distance Sprinted", + "stat.minecraft.walk_on_water_one_cm": "Distance Walked on Water", + "stat.minecraft.swim_one_cm": "Distance Swum", + "stat.minecraft.talked_to_villager": "Talked to Villagers", + "stat.minecraft.time_since_rest": "Time Since Last Rest", + "stat.minecraft.time_since_death": "Time Since Last Death", + "stat.minecraft.total_world_time": "Time with World Open", + "stat.minecraft.traded_with_villager": "Traded with Villagers", + "stat.minecraft.treasure_fished": "Treasure Fished", + "stat.minecraft.trigger_trapped_chest": "Trapped Chests Triggered", + "stat.minecraft.tune_noteblock": "Note Blocks Tuned", + "stat.minecraft.use_cauldron": "Water Taken from Cauldron", + "stat.minecraft.walk_one_cm": "Distance Walked", + "recipe.toast.title": "New Recipes Unlocked!", + "recipe.toast.description": "Check your recipe book", + "itemGroup.buildingBlocks": "Building Blocks", + "itemGroup.coloredBlocks": "Colored Blocks", + "itemGroup.natural": "Natural Blocks", + "itemGroup.functional": "Functional Blocks", + "itemGroup.redstone": "Redstone Blocks", + "itemGroup.op": "Operator Utilities", + "itemGroup.spawnEggs": "Spawn Eggs", + "itemGroup.search": "Search Items", + "itemGroup.consumables": "Consumables", + "itemGroup.foodAndDrink": "Food & Drinks", + "itemGroup.tools": "Tools & Utilities", + "itemGroup.combat": "Combat", + "itemGroup.crafting": "Crafting", + "itemGroup.ingredients": "Ingredients", + "itemGroup.inventory": "Survival Inventory", + "itemGroup.hotbar": "Saved Hotbars", + "inventory.binSlot": "Destroy Item", + "inventory.hotbarSaved": "Item hotbar saved (restore with %1$s+%2$s)", + "inventory.hotbarInfo": "Save hotbar with %1$s+%2$s", + "advMode.setCommand": "Set Console Command for Block", + "advMode.setCommand.success": "Command set: %s", + "advMode.command": "Console Command", + "advMode.nearestPlayer": "Use \"@p\" to target nearest player", + "advMode.randomPlayer": "Use \"@r\" to target random player", + "advMode.allPlayers": "Use \"@a\" to target all players", + "advMode.allEntities": "Use \"@e\" to target all entities", + "advMode.self": "Use \"@s\" to target the executing entity", + "advMode.previousOutput": "Previous Output", + "advMode.mode": "Mode", + "advMode.mode.sequence": "Chain", + "advMode.mode.auto": "Repeat", + "advMode.mode.redstone": "Impulse", + "advMode.type": "Type", + "advMode.mode.conditional": "Conditional", + "advMode.mode.unconditional": "Unconditional", + "advMode.triggering": "Triggering", + "advMode.mode.redstoneTriggered": "Needs Redstone", + "advMode.mode.autoexec.bat": "Always Active", + "advMode.notEnabled": "Command blocks are not enabled on this server", + "advMode.notAllowed": "Must be an opped player in creative mode", + "advMode.trackOutput": "Track output", + "mount.onboard": "Press %1$s to Dismount", + "build.tooHigh": "Height limit for building is %s", + "item.modifiers.mainhand": "When in Main Hand:", + "item.modifiers.offhand": "When in Off Hand:", + "item.modifiers.feet": "When on Feet:", + "item.modifiers.legs": "When on Legs:", + "item.modifiers.chest": "When on Body:", + "item.modifiers.head": "When on Head:", + "attribute.modifier.plus.0": "+%s %s", + "attribute.modifier.plus.1": "+%s%% %s", + "attribute.modifier.plus.2": "+%s%% %s", + "attribute.modifier.take.0": "-%s %s", + "attribute.modifier.take.1": "-%s%% %s", + "attribute.modifier.take.2": "-%s%% %s", + "attribute.modifier.equals.0": "%s %s", + "attribute.modifier.equals.1": "%s%% %s", + "attribute.modifier.equals.2": "%s%% %s", + "attribute.name.horse.jump_strength": "Horse Jump Strength", + "attribute.name.zombie.spawn_reinforcements": "Zombie Reinforcements", + "attribute.name.generic.max_health": "Max Health", + "attribute.name.generic.follow_range": "Mob Follow Range", + "attribute.name.generic.knockback_resistance": "Knockback Resistance", + "attribute.name.generic.movement_speed": "Speed", + "attribute.name.generic.flying_speed": "Flying Speed", + "attribute.name.generic.attack_damage": "Attack Damage", + "attribute.name.generic.attack_knockback": "Attack Knockback", + "attribute.name.generic.attack_speed": "Attack Speed", + "attribute.name.generic.luck": "Luck", + "attribute.name.generic.armor": "Armor", + "attribute.name.generic.armor_toughness": "Armor Toughness", + "screenshot.success": "Saved screenshot as %s", + "screenshot.failure": "Couldn't save screenshot: %s", + "block.minecraft.black_banner": "Black Banner", + "block.minecraft.red_banner": "Red Banner", + "block.minecraft.green_banner": "Green Banner", + "block.minecraft.brown_banner": "Brown Banner", + "block.minecraft.blue_banner": "Blue Banner", + "block.minecraft.purple_banner": "Purple Banner", + "block.minecraft.cyan_banner": "Cyan Banner", + "block.minecraft.light_gray_banner": "Light Gray Banner", + "block.minecraft.gray_banner": "Gray Banner", + "block.minecraft.pink_banner": "Pink Banner", + "block.minecraft.lime_banner": "Lime Banner", + "block.minecraft.yellow_banner": "Yellow Banner", + "block.minecraft.light_blue_banner": "Light Blue Banner", + "block.minecraft.magenta_banner": "Magenta Banner", + "block.minecraft.orange_banner": "Orange Banner", + "block.minecraft.white_banner": "White Banner", + "item.minecraft.shield": "Shield", + "item.minecraft.shield.black": "Black Shield", + "item.minecraft.shield.red": "Red Shield", + "item.minecraft.shield.green": "Green Shield", + "item.minecraft.shield.brown": "Brown Shield", + "item.minecraft.shield.blue": "Blue Shield", + "item.minecraft.shield.purple": "Purple Shield", + "item.minecraft.shield.cyan": "Cyan Shield", + "item.minecraft.shield.light_gray": "Light Gray Shield", + "item.minecraft.shield.gray": "Gray Shield", + "item.minecraft.shield.pink": "Pink Shield", + "item.minecraft.shield.lime": "Lime Shield", + "item.minecraft.shield.yellow": "Yellow Shield", + "item.minecraft.shield.light_blue": "Light Blue Shield", + "item.minecraft.shield.magenta": "Magenta Shield", + "item.minecraft.shield.orange": "Orange Shield", + "item.minecraft.shield.white": "White Shield", + "block.minecraft.banner.base.black": "Fully Black Field", + "block.minecraft.banner.base.red": "Fully Red Field", + "block.minecraft.banner.base.green": "Fully Green Field", + "block.minecraft.banner.base.brown": "Fully Brown Field", + "block.minecraft.banner.base.blue": "Fully Blue Field", + "block.minecraft.banner.base.purple": "Fully Purple Field", + "block.minecraft.banner.base.cyan": "Fully Cyan Field", + "block.minecraft.banner.base.light_gray": "Fully Light Gray Field", + "block.minecraft.banner.base.gray": "Fully Gray Field", + "block.minecraft.banner.base.pink": "Fully Pink Field", + "block.minecraft.banner.base.lime": "Fully Lime Field", + "block.minecraft.banner.base.yellow": "Fully Yellow Field", + "block.minecraft.banner.base.light_blue": "Fully Light Blue Field", + "block.minecraft.banner.base.magenta": "Fully Magenta Field", + "block.minecraft.banner.base.orange": "Fully Orange Field", + "block.minecraft.banner.base.white": "Fully White Field", + "block.minecraft.banner.square_bottom_left.black": "Black Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.red": "Red Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.green": "Green Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.brown": "Brown Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.blue": "Blue Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.purple": "Purple Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.cyan": "Cyan Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.light_gray": "Light Gray Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.gray": "Gray Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.pink": "Pink Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.lime": "Lime Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.yellow": "Yellow Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.light_blue": "Light Blue Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.magenta": "Magenta Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.orange": "Orange Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.white": "White Base Dexter Canton", + "block.minecraft.banner.square_bottom_right.black": "Black Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.red": "Red Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.green": "Green Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.brown": "Brown Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.blue": "Blue Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.purple": "Purple Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.cyan": "Cyan Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.light_gray": "Light Gray Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.gray": "Gray Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.pink": "Pink Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.lime": "Lime Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.yellow": "Yellow Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.light_blue": "Light Blue Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.magenta": "Magenta Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.orange": "Orange Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.white": "White Base Sinister Canton", + "block.minecraft.banner.square_top_left.black": "Black Chief Dexter Canton", + "block.minecraft.banner.square_top_left.red": "Red Chief Dexter Canton", + "block.minecraft.banner.square_top_left.green": "Green Chief Dexter Canton", + "block.minecraft.banner.square_top_left.brown": "Brown Chief Dexter Canton", + "block.minecraft.banner.square_top_left.blue": "Blue Chief Dexter Canton", + "block.minecraft.banner.square_top_left.purple": "Purple Chief Dexter Canton", + "block.minecraft.banner.square_top_left.cyan": "Cyan Chief Dexter Canton", + "block.minecraft.banner.square_top_left.light_gray": "Light Gray Chief Dexter Canton", + "block.minecraft.banner.square_top_left.gray": "Gray Chief Dexter Canton", + "block.minecraft.banner.square_top_left.pink": "Pink Chief Dexter Canton", + "block.minecraft.banner.square_top_left.lime": "Lime Chief Dexter Canton", + "block.minecraft.banner.square_top_left.yellow": "Yellow Chief Dexter Canton", + "block.minecraft.banner.square_top_left.light_blue": "Light Blue Chief Dexter Canton", + "block.minecraft.banner.square_top_left.magenta": "Magenta Chief Dexter Canton", + "block.minecraft.banner.square_top_left.orange": "Orange Chief Dexter Canton", + "block.minecraft.banner.square_top_left.white": "White Chief Dexter Canton", + "block.minecraft.banner.square_top_right.black": "Black Chief Sinister Canton", + "block.minecraft.banner.square_top_right.red": "Red Chief Sinister Canton", + "block.minecraft.banner.square_top_right.green": "Green Chief Sinister Canton", + "block.minecraft.banner.square_top_right.brown": "Brown Chief Sinister Canton", + "block.minecraft.banner.square_top_right.blue": "Blue Chief Sinister Canton", + "block.minecraft.banner.square_top_right.purple": "Purple Chief Sinister Canton", + "block.minecraft.banner.square_top_right.cyan": "Cyan Chief Sinister Canton", + "block.minecraft.banner.square_top_right.light_gray": "Light Gray Chief Sinister Canton", + "block.minecraft.banner.square_top_right.gray": "Gray Chief Sinister Canton", + "block.minecraft.banner.square_top_right.pink": "Pink Chief Sinister Canton", + "block.minecraft.banner.square_top_right.lime": "Lime Chief Sinister Canton", + "block.minecraft.banner.square_top_right.yellow": "Yellow Chief Sinister Canton", + "block.minecraft.banner.square_top_right.light_blue": "Light Blue Chief Sinister Canton", + "block.minecraft.banner.square_top_right.magenta": "Magenta Chief Sinister Canton", + "block.minecraft.banner.square_top_right.orange": "Orange Chief Sinister Canton", + "block.minecraft.banner.square_top_right.white": "White Chief Sinister Canton", + "block.minecraft.banner.stripe_bottom.black": "Black Base", + "block.minecraft.banner.stripe_bottom.red": "Red Base", + "block.minecraft.banner.stripe_bottom.green": "Green Base", + "block.minecraft.banner.stripe_bottom.brown": "Brown Base", + "block.minecraft.banner.stripe_bottom.blue": "Blue Base", + "block.minecraft.banner.stripe_bottom.purple": "Purple Base", + "block.minecraft.banner.stripe_bottom.cyan": "Cyan Base", + "block.minecraft.banner.stripe_bottom.light_gray": "Light Gray Base", + "block.minecraft.banner.stripe_bottom.gray": "Gray Base", + "block.minecraft.banner.stripe_bottom.pink": "Pink Base", + "block.minecraft.banner.stripe_bottom.lime": "Lime Base", + "block.minecraft.banner.stripe_bottom.yellow": "Yellow Base", + "block.minecraft.banner.stripe_bottom.light_blue": "Light Blue Base", + "block.minecraft.banner.stripe_bottom.magenta": "Magenta Base", + "block.minecraft.banner.stripe_bottom.orange": "Orange Base", + "block.minecraft.banner.stripe_bottom.white": "White Base", + "block.minecraft.banner.stripe_top.black": "Black Chief", + "block.minecraft.banner.stripe_top.red": "Red Chief", + "block.minecraft.banner.stripe_top.green": "Green Chief", + "block.minecraft.banner.stripe_top.brown": "Brown Chief", + "block.minecraft.banner.stripe_top.blue": "Blue Chief", + "block.minecraft.banner.stripe_top.purple": "Purple Chief", + "block.minecraft.banner.stripe_top.cyan": "Cyan Chief", + "block.minecraft.banner.stripe_top.light_gray": "Light Gray Chief", + "block.minecraft.banner.stripe_top.gray": "Gray Chief", + "block.minecraft.banner.stripe_top.pink": "Pink Chief", + "block.minecraft.banner.stripe_top.lime": "Lime Chief", + "block.minecraft.banner.stripe_top.yellow": "Yellow Chief", + "block.minecraft.banner.stripe_top.light_blue": "Light Blue Chief", + "block.minecraft.banner.stripe_top.magenta": "Magenta Chief", + "block.minecraft.banner.stripe_top.orange": "Orange Chief", + "block.minecraft.banner.stripe_top.white": "White Chief", + "block.minecraft.banner.stripe_left.black": "Black Pale Dexter", + "block.minecraft.banner.stripe_left.red": "Red Pale Dexter", + "block.minecraft.banner.stripe_left.green": "Green Pale Dexter", + "block.minecraft.banner.stripe_left.brown": "Brown Pale Dexter", + "block.minecraft.banner.stripe_left.blue": "Blue Pale Dexter", + "block.minecraft.banner.stripe_left.purple": "Purple Pale Dexter", + "block.minecraft.banner.stripe_left.cyan": "Cyan Pale Dexter", + "block.minecraft.banner.stripe_left.light_gray": "Light Gray Pale Dexter", + "block.minecraft.banner.stripe_left.gray": "Gray Pale Dexter", + "block.minecraft.banner.stripe_left.pink": "Pink Pale Dexter", + "block.minecraft.banner.stripe_left.lime": "Lime Pale Dexter", + "block.minecraft.banner.stripe_left.yellow": "Yellow Pale Dexter", + "block.minecraft.banner.stripe_left.light_blue": "Light Blue Pale Dexter", + "block.minecraft.banner.stripe_left.magenta": "Magenta Pale Dexter", + "block.minecraft.banner.stripe_left.orange": "Orange Pale Dexter", + "block.minecraft.banner.stripe_left.white": "White Pale Dexter", + "block.minecraft.banner.stripe_right.black": "Black Pale Sinister", + "block.minecraft.banner.stripe_right.red": "Red Pale Sinister", + "block.minecraft.banner.stripe_right.green": "Green Pale Sinister", + "block.minecraft.banner.stripe_right.brown": "Brown Pale Sinister", + "block.minecraft.banner.stripe_right.blue": "Blue Pale Sinister", + "block.minecraft.banner.stripe_right.purple": "Purple Pale Sinister", + "block.minecraft.banner.stripe_right.cyan": "Cyan Pale Sinister", + "block.minecraft.banner.stripe_right.light_gray": "Light Gray Pale Sinister", + "block.minecraft.banner.stripe_right.gray": "Gray Pale Sinister", + "block.minecraft.banner.stripe_right.pink": "Pink Pale Sinister", + "block.minecraft.banner.stripe_right.lime": "Lime Pale Sinister", + "block.minecraft.banner.stripe_right.yellow": "Yellow Pale Sinister", + "block.minecraft.banner.stripe_right.light_blue": "Light Blue Pale Sinister", + "block.minecraft.banner.stripe_right.magenta": "Magenta Pale Sinister", + "block.minecraft.banner.stripe_right.orange": "Orange Pale Sinister", + "block.minecraft.banner.stripe_right.white": "White Pale Sinister", + "block.minecraft.banner.stripe_center.black": "Black Pale", + "block.minecraft.banner.stripe_center.red": "Red Pale", + "block.minecraft.banner.stripe_center.green": "Green Pale", + "block.minecraft.banner.stripe_center.brown": "Brown Pale", + "block.minecraft.banner.stripe_center.blue": "Blue Pale", + "block.minecraft.banner.stripe_center.purple": "Purple Pale", + "block.minecraft.banner.stripe_center.cyan": "Cyan Pale", + "block.minecraft.banner.stripe_center.light_gray": "Light Gray Pale", + "block.minecraft.banner.stripe_center.gray": "Gray Pale", + "block.minecraft.banner.stripe_center.pink": "Pink Pale", + "block.minecraft.banner.stripe_center.lime": "Lime Pale", + "block.minecraft.banner.stripe_center.yellow": "Yellow Pale", + "block.minecraft.banner.stripe_center.light_blue": "Light Blue Pale", + "block.minecraft.banner.stripe_center.magenta": "Magenta Pale", + "block.minecraft.banner.stripe_center.orange": "Orange Pale", + "block.minecraft.banner.stripe_center.white": "White Pale", + "block.minecraft.banner.stripe_middle.black": "Black Fess", + "block.minecraft.banner.stripe_middle.red": "Red Fess", + "block.minecraft.banner.stripe_middle.green": "Green Fess", + "block.minecraft.banner.stripe_middle.brown": "Brown Fess", + "block.minecraft.banner.stripe_middle.blue": "Blue Fess", + "block.minecraft.banner.stripe_middle.purple": "Purple Fess", + "block.minecraft.banner.stripe_middle.cyan": "Cyan Fess", + "block.minecraft.banner.stripe_middle.light_gray": "Light Gray Fess", + "block.minecraft.banner.stripe_middle.gray": "Gray Fess", + "block.minecraft.banner.stripe_middle.pink": "Pink Fess", + "block.minecraft.banner.stripe_middle.lime": "Lime Fess", + "block.minecraft.banner.stripe_middle.yellow": "Yellow Fess", + "block.minecraft.banner.stripe_middle.light_blue": "Light Blue Fess", + "block.minecraft.banner.stripe_middle.magenta": "Magenta Fess", + "block.minecraft.banner.stripe_middle.orange": "Orange Fess", + "block.minecraft.banner.stripe_middle.white": "White Fess", + "block.minecraft.banner.stripe_downright.black": "Black Bend", + "block.minecraft.banner.stripe_downright.red": "Red Bend", + "block.minecraft.banner.stripe_downright.green": "Green Bend", + "block.minecraft.banner.stripe_downright.brown": "Brown Bend", + "block.minecraft.banner.stripe_downright.blue": "Blue Bend", + "block.minecraft.banner.stripe_downright.purple": "Purple Bend", + "block.minecraft.banner.stripe_downright.cyan": "Cyan Bend", + "block.minecraft.banner.stripe_downright.light_gray": "Light Gray Bend", + "block.minecraft.banner.stripe_downright.gray": "Gray Bend", + "block.minecraft.banner.stripe_downright.pink": "Pink Bend", + "block.minecraft.banner.stripe_downright.lime": "Lime Bend", + "block.minecraft.banner.stripe_downright.yellow": "Yellow Bend", + "block.minecraft.banner.stripe_downright.light_blue": "Light Blue Bend", + "block.minecraft.banner.stripe_downright.magenta": "Magenta Bend", + "block.minecraft.banner.stripe_downright.orange": "Orange Bend", + "block.minecraft.banner.stripe_downright.white": "White Bend", + "block.minecraft.banner.stripe_downleft.black": "Black Bend Sinister", + "block.minecraft.banner.stripe_downleft.red": "Red Bend Sinister", + "block.minecraft.banner.stripe_downleft.green": "Green Bend Sinister", + "block.minecraft.banner.stripe_downleft.brown": "Brown Bend Sinister", + "block.minecraft.banner.stripe_downleft.blue": "Blue Bend Sinister", + "block.minecraft.banner.stripe_downleft.purple": "Purple Bend Sinister", + "block.minecraft.banner.stripe_downleft.cyan": "Cyan Bend Sinister", + "block.minecraft.banner.stripe_downleft.light_gray": "Light Gray Bend Sinister", + "block.minecraft.banner.stripe_downleft.gray": "Gray Bend Sinister", + "block.minecraft.banner.stripe_downleft.pink": "Pink Bend Sinister", + "block.minecraft.banner.stripe_downleft.lime": "Lime Bend Sinister", + "block.minecraft.banner.stripe_downleft.yellow": "Yellow Bend Sinister", + "block.minecraft.banner.stripe_downleft.light_blue": "Light Blue Bend Sinister", + "block.minecraft.banner.stripe_downleft.magenta": "Magenta Bend Sinister", + "block.minecraft.banner.stripe_downleft.orange": "Orange Bend Sinister", + "block.minecraft.banner.stripe_downleft.white": "White Bend Sinister", + "block.minecraft.banner.small_stripes.black": "Black Paly", + "block.minecraft.banner.small_stripes.red": "Red Paly", + "block.minecraft.banner.small_stripes.green": "Green Paly", + "block.minecraft.banner.small_stripes.brown": "Brown Paly", + "block.minecraft.banner.small_stripes.blue": "Blue Paly", + "block.minecraft.banner.small_stripes.purple": "Purple Paly", + "block.minecraft.banner.small_stripes.cyan": "Cyan Paly", + "block.minecraft.banner.small_stripes.light_gray": "Light Gray Paly", + "block.minecraft.banner.small_stripes.gray": "Gray Paly", + "block.minecraft.banner.small_stripes.pink": "Pink Paly", + "block.minecraft.banner.small_stripes.lime": "Lime Paly", + "block.minecraft.banner.small_stripes.yellow": "Yellow Paly", + "block.minecraft.banner.small_stripes.light_blue": "Light Blue Paly", + "block.minecraft.banner.small_stripes.magenta": "Magenta Paly", + "block.minecraft.banner.small_stripes.orange": "Orange Paly", + "block.minecraft.banner.small_stripes.white": "White Paly", + "block.minecraft.banner.cross.black": "Black Saltire", + "block.minecraft.banner.cross.red": "Red Saltire", + "block.minecraft.banner.cross.green": "Green Saltire", + "block.minecraft.banner.cross.brown": "Brown Saltire", + "block.minecraft.banner.cross.blue": "Blue Saltire", + "block.minecraft.banner.cross.purple": "Purple Saltire", + "block.minecraft.banner.cross.cyan": "Cyan Saltire", + "block.minecraft.banner.cross.light_gray": "Light Gray Saltire", + "block.minecraft.banner.cross.gray": "Gray Saltire", + "block.minecraft.banner.cross.pink": "Pink Saltire", + "block.minecraft.banner.cross.lime": "Lime Saltire", + "block.minecraft.banner.cross.yellow": "Yellow Saltire", + "block.minecraft.banner.cross.light_blue": "Light Blue Saltire", + "block.minecraft.banner.cross.magenta": "Magenta Saltire", + "block.minecraft.banner.cross.orange": "Orange Saltire", + "block.minecraft.banner.cross.white": "White Saltire", + "block.minecraft.banner.triangle_bottom.black": "Black Chevron", + "block.minecraft.banner.triangle_bottom.red": "Red Chevron", + "block.minecraft.banner.triangle_bottom.green": "Green Chevron", + "block.minecraft.banner.triangle_bottom.brown": "Brown Chevron", + "block.minecraft.banner.triangle_bottom.blue": "Blue Chevron", + "block.minecraft.banner.triangle_bottom.purple": "Purple Chevron", + "block.minecraft.banner.triangle_bottom.cyan": "Cyan Chevron", + "block.minecraft.banner.triangle_bottom.light_gray": "Light Gray Chevron", + "block.minecraft.banner.triangle_bottom.gray": "Gray Chevron", + "block.minecraft.banner.triangle_bottom.pink": "Pink Chevron", + "block.minecraft.banner.triangle_bottom.lime": "Lime Chevron", + "block.minecraft.banner.triangle_bottom.yellow": "Yellow Chevron", + "block.minecraft.banner.triangle_bottom.light_blue": "Light Blue Chevron", + "block.minecraft.banner.triangle_bottom.magenta": "Magenta Chevron", + "block.minecraft.banner.triangle_bottom.orange": "Orange Chevron", + "block.minecraft.banner.triangle_bottom.white": "White Chevron", + "block.minecraft.banner.triangle_top.black": "Black Inverted Chevron", + "block.minecraft.banner.triangle_top.red": "Red Inverted Chevron", + "block.minecraft.banner.triangle_top.green": "Green Inverted Chevron", + "block.minecraft.banner.triangle_top.brown": "Brown Inverted Chevron", + "block.minecraft.banner.triangle_top.blue": "Blue Inverted Chevron", + "block.minecraft.banner.triangle_top.purple": "Purple Inverted Chevron", + "block.minecraft.banner.triangle_top.cyan": "Cyan Inverted Chevron", + "block.minecraft.banner.triangle_top.light_gray": "Light Gray Inverted Chevron", + "block.minecraft.banner.triangle_top.gray": "Gray Inverted Chevron", + "block.minecraft.banner.triangle_top.pink": "Pink Inverted Chevron", + "block.minecraft.banner.triangle_top.lime": "Lime Inverted Chevron", + "block.minecraft.banner.triangle_top.yellow": "Yellow Inverted Chevron", + "block.minecraft.banner.triangle_top.light_blue": "Light Blue Inverted Chevron", + "block.minecraft.banner.triangle_top.magenta": "Magenta Inverted Chevron", + "block.minecraft.banner.triangle_top.orange": "Orange Inverted Chevron", + "block.minecraft.banner.triangle_top.white": "White Inverted Chevron", + "block.minecraft.banner.triangles_bottom.black": "Black Base Indented", + "block.minecraft.banner.triangles_bottom.red": "Red Base Indented", + "block.minecraft.banner.triangles_bottom.green": "Green Base Indented", + "block.minecraft.banner.triangles_bottom.brown": "Brown Base Indented", + "block.minecraft.banner.triangles_bottom.blue": "Blue Base Indented", + "block.minecraft.banner.triangles_bottom.purple": "Purple Base Indented", + "block.minecraft.banner.triangles_bottom.cyan": "Cyan Base Indented", + "block.minecraft.banner.triangles_bottom.light_gray": "Light Gray Base Indented", + "block.minecraft.banner.triangles_bottom.gray": "Gray Base Indented", + "block.minecraft.banner.triangles_bottom.pink": "Pink Base Indented", + "block.minecraft.banner.triangles_bottom.lime": "Lime Base Indented", + "block.minecraft.banner.triangles_bottom.yellow": "Yellow Base Indented", + "block.minecraft.banner.triangles_bottom.light_blue": "Light Blue Base Indented", + "block.minecraft.banner.triangles_bottom.magenta": "Magenta Base Indented", + "block.minecraft.banner.triangles_bottom.orange": "Orange Base Indented", + "block.minecraft.banner.triangles_bottom.white": "White Base Indented", + "block.minecraft.banner.triangles_top.black": "Black Chief Indented", + "block.minecraft.banner.triangles_top.red": "Red Chief Indented", + "block.minecraft.banner.triangles_top.green": "Green Chief Indented", + "block.minecraft.banner.triangles_top.brown": "Brown Chief Indented", + "block.minecraft.banner.triangles_top.blue": "Blue Chief Indented", + "block.minecraft.banner.triangles_top.purple": "Purple Chief Indented", + "block.minecraft.banner.triangles_top.cyan": "Cyan Chief Indented", + "block.minecraft.banner.triangles_top.light_gray": "Light Gray Chief Indented", + "block.minecraft.banner.triangles_top.gray": "Gray Chief Indented", + "block.minecraft.banner.triangles_top.pink": "Pink Chief Indented", + "block.minecraft.banner.triangles_top.lime": "Lime Chief Indented", + "block.minecraft.banner.triangles_top.yellow": "Yellow Chief Indented", + "block.minecraft.banner.triangles_top.light_blue": "Light Blue Chief Indented", + "block.minecraft.banner.triangles_top.magenta": "Magenta Chief Indented", + "block.minecraft.banner.triangles_top.orange": "Orange Chief Indented", + "block.minecraft.banner.triangles_top.white": "White Chief Indented", + "block.minecraft.banner.diagonal_left.black": "Black Per Bend Sinister", + "block.minecraft.banner.diagonal_left.red": "Red Per Bend Sinister", + "block.minecraft.banner.diagonal_left.green": "Green Per Bend Sinister", + "block.minecraft.banner.diagonal_left.brown": "Brown Per Bend Sinister", + "block.minecraft.banner.diagonal_left.blue": "Blue Per Bend Sinister", + "block.minecraft.banner.diagonal_left.purple": "Purple Per Bend Sinister", + "block.minecraft.banner.diagonal_left.cyan": "Cyan Per Bend Sinister", + "block.minecraft.banner.diagonal_left.light_gray": "Light Gray Per Bend Sinister", + "block.minecraft.banner.diagonal_left.gray": "Gray Per Bend Sinister", + "block.minecraft.banner.diagonal_left.pink": "Pink Per Bend Sinister", + "block.minecraft.banner.diagonal_left.lime": "Lime Per Bend Sinister", + "block.minecraft.banner.diagonal_left.yellow": "Yellow Per Bend Sinister", + "block.minecraft.banner.diagonal_left.light_blue": "Light Blue Per Bend Sinister", + "block.minecraft.banner.diagonal_left.magenta": "Magenta Per Bend Sinister", + "block.minecraft.banner.diagonal_left.orange": "Orange Per Bend Sinister", + "block.minecraft.banner.diagonal_left.white": "White Per Bend Sinister", + "block.minecraft.banner.diagonal_right.black": "Black Per Bend", + "block.minecraft.banner.diagonal_right.red": "Red Per Bend", + "block.minecraft.banner.diagonal_right.green": "Green Per Bend", + "block.minecraft.banner.diagonal_right.brown": "Brown Per Bend", + "block.minecraft.banner.diagonal_right.blue": "Blue Per Bend", + "block.minecraft.banner.diagonal_right.purple": "Purple Per Bend", + "block.minecraft.banner.diagonal_right.cyan": "Cyan Per Bend", + "block.minecraft.banner.diagonal_right.light_gray": "Light Gray Per Bend", + "block.minecraft.banner.diagonal_right.gray": "Gray Per Bend", + "block.minecraft.banner.diagonal_right.pink": "Pink Per Bend", + "block.minecraft.banner.diagonal_right.lime": "Lime Per Bend", + "block.minecraft.banner.diagonal_right.yellow": "Yellow Per Bend", + "block.minecraft.banner.diagonal_right.light_blue": "Light Blue Per Bend", + "block.minecraft.banner.diagonal_right.magenta": "Magenta Per Bend", + "block.minecraft.banner.diagonal_right.orange": "Orange Per Bend", + "block.minecraft.banner.diagonal_right.white": "White Per Bend", + "block.minecraft.banner.diagonal_up_left.black": "Black Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.red": "Red Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.green": "Green Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.brown": "Brown Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.blue": "Blue Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.purple": "Purple Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.cyan": "Cyan Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.light_gray": "Light Gray Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.gray": "Gray Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.pink": "Pink Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.lime": "Lime Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.yellow": "Yellow Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.light_blue": "Light Blue Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.magenta": "Magenta Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.orange": "Orange Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.white": "White Per Bend Inverted", + "block.minecraft.banner.diagonal_up_right.black": "Black Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.red": "Red Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.green": "Green Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.brown": "Brown Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.blue": "Blue Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.purple": "Purple Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.cyan": "Cyan Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.light_gray": "Light Gray Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.gray": "Gray Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.pink": "Pink Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.lime": "Lime Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.yellow": "Yellow Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.light_blue": "Light Blue Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.magenta": "Magenta Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.orange": "Orange Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.white": "White Per Bend Sinister Inverted", + "block.minecraft.banner.circle.black": "Black Roundel", + "block.minecraft.banner.circle.red": "Red Roundel", + "block.minecraft.banner.circle.green": "Green Roundel", + "block.minecraft.banner.circle.brown": "Brown Roundel", + "block.minecraft.banner.circle.blue": "Blue Roundel", + "block.minecraft.banner.circle.purple": "Purple Roundel", + "block.minecraft.banner.circle.cyan": "Cyan Roundel", + "block.minecraft.banner.circle.light_gray": "Light Gray Roundel", + "block.minecraft.banner.circle.gray": "Gray Roundel", + "block.minecraft.banner.circle.pink": "Pink Roundel", + "block.minecraft.banner.circle.lime": "Lime Roundel", + "block.minecraft.banner.circle.yellow": "Yellow Roundel", + "block.minecraft.banner.circle.light_blue": "Light Blue Roundel", + "block.minecraft.banner.circle.magenta": "Magenta Roundel", + "block.minecraft.banner.circle.orange": "Orange Roundel", + "block.minecraft.banner.circle.white": "White Roundel", + "block.minecraft.banner.rhombus.black": "Black Lozenge", + "block.minecraft.banner.rhombus.red": "Red Lozenge", + "block.minecraft.banner.rhombus.green": "Green Lozenge", + "block.minecraft.banner.rhombus.brown": "Brown Lozenge", + "block.minecraft.banner.rhombus.blue": "Blue Lozenge", + "block.minecraft.banner.rhombus.purple": "Purple Lozenge", + "block.minecraft.banner.rhombus.cyan": "Cyan Lozenge", + "block.minecraft.banner.rhombus.light_gray": "Light Gray Lozenge", + "block.minecraft.banner.rhombus.gray": "Gray Lozenge", + "block.minecraft.banner.rhombus.pink": "Pink Lozenge", + "block.minecraft.banner.rhombus.lime": "Lime Lozenge", + "block.minecraft.banner.rhombus.yellow": "Yellow Lozenge", + "block.minecraft.banner.rhombus.light_blue": "Light Blue Lozenge", + "block.minecraft.banner.rhombus.magenta": "Magenta Lozenge", + "block.minecraft.banner.rhombus.orange": "Orange Lozenge", + "block.minecraft.banner.rhombus.white": "White Lozenge", + "block.minecraft.banner.half_vertical.black": "Black Per Pale", + "block.minecraft.banner.half_vertical.red": "Red Per Pale", + "block.minecraft.banner.half_vertical.green": "Green Per Pale", + "block.minecraft.banner.half_vertical.brown": "Brown Per Pale", + "block.minecraft.banner.half_vertical.blue": "Blue Per Pale", + "block.minecraft.banner.half_vertical.purple": "Purple Per Pale", + "block.minecraft.banner.half_vertical.cyan": "Cyan Per Pale", + "block.minecraft.banner.half_vertical.light_gray": "Light Gray Per Pale", + "block.minecraft.banner.half_vertical.gray": "Gray Per Pale", + "block.minecraft.banner.half_vertical.pink": "Pink Per Pale", + "block.minecraft.banner.half_vertical.lime": "Lime Per Pale", + "block.minecraft.banner.half_vertical.yellow": "Yellow Per Pale", + "block.minecraft.banner.half_vertical.light_blue": "Light Blue Per Pale", + "block.minecraft.banner.half_vertical.magenta": "Magenta Per Pale", + "block.minecraft.banner.half_vertical.orange": "Orange Per Pale", + "block.minecraft.banner.half_vertical.white": "White Per Pale", + "block.minecraft.banner.half_horizontal.black": "Black Per Fess", + "block.minecraft.banner.half_horizontal.red": "Red Per Fess", + "block.minecraft.banner.half_horizontal.green": "Green Per Fess", + "block.minecraft.banner.half_horizontal.brown": "Brown Per Fess", + "block.minecraft.banner.half_horizontal.blue": "Blue Per Fess", + "block.minecraft.banner.half_horizontal.purple": "Purple Per Fess", + "block.minecraft.banner.half_horizontal.cyan": "Cyan Per Fess", + "block.minecraft.banner.half_horizontal.light_gray": "Light Gray Per Fess", + "block.minecraft.banner.half_horizontal.gray": "Gray Per Fess", + "block.minecraft.banner.half_horizontal.pink": "Pink Per Fess", + "block.minecraft.banner.half_horizontal.lime": "Lime Per Fess", + "block.minecraft.banner.half_horizontal.yellow": "Yellow Per Fess", + "block.minecraft.banner.half_horizontal.light_blue": "Light Blue Per Fess", + "block.minecraft.banner.half_horizontal.magenta": "Magenta Per Fess", + "block.minecraft.banner.half_horizontal.orange": "Orange Per Fess", + "block.minecraft.banner.half_horizontal.white": "White Per Fess", + "block.minecraft.banner.half_vertical_right.black": "Black Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.red": "Red Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.green": "Green Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.brown": "Brown Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.blue": "Blue Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.purple": "Purple Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.cyan": "Cyan Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.light_gray": "Light Gray Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.gray": "Gray Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.pink": "Pink Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.lime": "Lime Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.yellow": "Yellow Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.light_blue": "Light Blue Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.magenta": "Magenta Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.orange": "Orange Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.white": "White Per Pale Inverted", + "block.minecraft.banner.half_horizontal_bottom.black": "Black Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.red": "Red Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.green": "Green Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.brown": "Brown Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.blue": "Blue Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.purple": "Purple Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.cyan": "Cyan Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.light_gray": "Light Gray Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.gray": "Gray Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.pink": "Pink Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.lime": "Lime Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.yellow": "Yellow Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.light_blue": "Light Blue Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.magenta": "Magenta Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.orange": "Orange Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.white": "White Per Fess Inverted", + "block.minecraft.banner.creeper.black": "Black Creeper Charge", + "block.minecraft.banner.creeper.red": "Red Creeper Charge", + "block.minecraft.banner.creeper.green": "Green Creeper Charge", + "block.minecraft.banner.creeper.brown": "Brown Creeper Charge", + "block.minecraft.banner.creeper.blue": "Blue Creeper Charge", + "block.minecraft.banner.creeper.purple": "Purple Creeper Charge", + "block.minecraft.banner.creeper.cyan": "Cyan Creeper Charge", + "block.minecraft.banner.creeper.light_gray": "Light Gray Creeper Charge", + "block.minecraft.banner.creeper.gray": "Gray Creeper Charge", + "block.minecraft.banner.creeper.pink": "Pink Creeper Charge", + "block.minecraft.banner.creeper.lime": "Lime Creeper Charge", + "block.minecraft.banner.creeper.yellow": "Yellow Creeper Charge", + "block.minecraft.banner.creeper.light_blue": "Light Blue Creeper Charge", + "block.minecraft.banner.creeper.magenta": "Magenta Creeper Charge", + "block.minecraft.banner.creeper.orange": "Orange Creeper Charge", + "block.minecraft.banner.creeper.white": "White Creeper Charge", + "block.minecraft.banner.bricks.black": "Black Field Masoned", + "block.minecraft.banner.bricks.red": "Red Field Masoned", + "block.minecraft.banner.bricks.green": "Green Field Masoned", + "block.minecraft.banner.bricks.brown": "Brown Field Masoned", + "block.minecraft.banner.bricks.blue": "Blue Field Masoned", + "block.minecraft.banner.bricks.purple": "Purple Field Masoned", + "block.minecraft.banner.bricks.cyan": "Cyan Field Masoned", + "block.minecraft.banner.bricks.light_gray": "Light Gray Field Masoned", + "block.minecraft.banner.bricks.gray": "Gray Field Masoned", + "block.minecraft.banner.bricks.pink": "Pink Field Masoned", + "block.minecraft.banner.bricks.lime": "Lime Field Masoned", + "block.minecraft.banner.bricks.yellow": "Yellow Field Masoned", + "block.minecraft.banner.bricks.light_blue": "Light Blue Field Masoned", + "block.minecraft.banner.bricks.magenta": "Magenta Field Masoned", + "block.minecraft.banner.bricks.orange": "Orange Field Masoned", + "block.minecraft.banner.bricks.white": "White Field Masoned", + "block.minecraft.banner.gradient.black": "Black Gradient", + "block.minecraft.banner.gradient.red": "Red Gradient", + "block.minecraft.banner.gradient.green": "Green Gradient", + "block.minecraft.banner.gradient.brown": "Brown Gradient", + "block.minecraft.banner.gradient.blue": "Blue Gradient", + "block.minecraft.banner.gradient.purple": "Purple Gradient", + "block.minecraft.banner.gradient.cyan": "Cyan Gradient", + "block.minecraft.banner.gradient.light_gray": "Light Gray Gradient", + "block.minecraft.banner.gradient.gray": "Gray Gradient", + "block.minecraft.banner.gradient.pink": "Pink Gradient", + "block.minecraft.banner.gradient.lime": "Lime Gradient", + "block.minecraft.banner.gradient.yellow": "Yellow Gradient", + "block.minecraft.banner.gradient.light_blue": "Light Blue Gradient", + "block.minecraft.banner.gradient.magenta": "Magenta Gradient", + "block.minecraft.banner.gradient.orange": "Orange Gradient", + "block.minecraft.banner.gradient.white": "White Gradient", + "block.minecraft.banner.gradient_up.black": "Black Base Gradient", + "block.minecraft.banner.gradient_up.red": "Red Base Gradient", + "block.minecraft.banner.gradient_up.green": "Green Base Gradient", + "block.minecraft.banner.gradient_up.brown": "Brown Base Gradient", + "block.minecraft.banner.gradient_up.blue": "Blue Base Gradient", + "block.minecraft.banner.gradient_up.purple": "Purple Base Gradient", + "block.minecraft.banner.gradient_up.cyan": "Cyan Base Gradient", + "block.minecraft.banner.gradient_up.light_gray": "Light Gray Base Gradient", + "block.minecraft.banner.gradient_up.gray": "Gray Base Gradient", + "block.minecraft.banner.gradient_up.pink": "Pink Base Gradient", + "block.minecraft.banner.gradient_up.lime": "Lime Base Gradient", + "block.minecraft.banner.gradient_up.yellow": "Yellow Base Gradient", + "block.minecraft.banner.gradient_up.light_blue": "Light Blue Base Gradient", + "block.minecraft.banner.gradient_up.magenta": "Magenta Base Gradient", + "block.minecraft.banner.gradient_up.orange": "Orange Base Gradient", + "block.minecraft.banner.gradient_up.white": "White Base Gradient", + "block.minecraft.banner.skull.black": "Black Skull Charge", + "block.minecraft.banner.skull.red": "Red Skull Charge", + "block.minecraft.banner.skull.green": "Green Skull Charge", + "block.minecraft.banner.skull.brown": "Brown Skull Charge", + "block.minecraft.banner.skull.blue": "Blue Skull Charge", + "block.minecraft.banner.skull.purple": "Purple Skull Charge", + "block.minecraft.banner.skull.cyan": "Cyan Skull Charge", + "block.minecraft.banner.skull.light_gray": "Light Gray Skull Charge", + "block.minecraft.banner.skull.gray": "Gray Skull Charge", + "block.minecraft.banner.skull.pink": "Pink Skull Charge", + "block.minecraft.banner.skull.lime": "Lime Skull Charge", + "block.minecraft.banner.skull.yellow": "Yellow Skull Charge", + "block.minecraft.banner.skull.light_blue": "Light Blue Skull Charge", + "block.minecraft.banner.skull.magenta": "Magenta Skull Charge", + "block.minecraft.banner.skull.orange": "Orange Skull Charge", + "block.minecraft.banner.skull.white": "White Skull Charge", + "block.minecraft.banner.flower.black": "Black Flower Charge", + "block.minecraft.banner.flower.red": "Red Flower Charge", + "block.minecraft.banner.flower.green": "Green Flower Charge", + "block.minecraft.banner.flower.brown": "Brown Flower Charge", + "block.minecraft.banner.flower.blue": "Blue Flower Charge", + "block.minecraft.banner.flower.purple": "Purple Flower Charge", + "block.minecraft.banner.flower.cyan": "Cyan Flower Charge", + "block.minecraft.banner.flower.light_gray": "Light Gray Flower Charge", + "block.minecraft.banner.flower.gray": "Gray Flower Charge", + "block.minecraft.banner.flower.pink": "Pink Flower Charge", + "block.minecraft.banner.flower.lime": "Lime Flower Charge", + "block.minecraft.banner.flower.yellow": "Yellow Flower Charge", + "block.minecraft.banner.flower.light_blue": "Light Blue Flower Charge", + "block.minecraft.banner.flower.magenta": "Magenta Flower Charge", + "block.minecraft.banner.flower.orange": "Orange Flower Charge", + "block.minecraft.banner.flower.white": "White Flower Charge", + "block.minecraft.banner.border.black": "Black Bordure", + "block.minecraft.banner.border.red": "Red Bordure", + "block.minecraft.banner.border.green": "Green Bordure", + "block.minecraft.banner.border.brown": "Brown Bordure", + "block.minecraft.banner.border.blue": "Blue Bordure", + "block.minecraft.banner.border.purple": "Purple Bordure", + "block.minecraft.banner.border.cyan": "Cyan Bordure", + "block.minecraft.banner.border.light_gray": "Light Gray Bordure", + "block.minecraft.banner.border.gray": "Gray Bordure", + "block.minecraft.banner.border.pink": "Pink Bordure", + "block.minecraft.banner.border.lime": "Lime Bordure", + "block.minecraft.banner.border.yellow": "Yellow Bordure", + "block.minecraft.banner.border.light_blue": "Light Blue Bordure", + "block.minecraft.banner.border.magenta": "Magenta Bordure", + "block.minecraft.banner.border.orange": "Orange Bordure", + "block.minecraft.banner.border.white": "White Bordure", + "block.minecraft.banner.curly_border.black": "Black Bordure Indented", + "block.minecraft.banner.curly_border.red": "Red Bordure Indented", + "block.minecraft.banner.curly_border.green": "Green Bordure Indented", + "block.minecraft.banner.curly_border.brown": "Brown Bordure Indented", + "block.minecraft.banner.curly_border.blue": "Blue Bordure Indented", + "block.minecraft.banner.curly_border.purple": "Purple Bordure Indented", + "block.minecraft.banner.curly_border.cyan": "Cyan Bordure Indented", + "block.minecraft.banner.curly_border.light_gray": "Light Gray Bordure Indented", + "block.minecraft.banner.curly_border.gray": "Gray Bordure Indented", + "block.minecraft.banner.curly_border.pink": "Pink Bordure Indented", + "block.minecraft.banner.curly_border.lime": "Lime Bordure Indented", + "block.minecraft.banner.curly_border.yellow": "Yellow Bordure Indented", + "block.minecraft.banner.curly_border.light_blue": "Light Blue Bordure Indented", + "block.minecraft.banner.curly_border.magenta": "Magenta Bordure Indented", + "block.minecraft.banner.curly_border.orange": "Orange Bordure Indented", + "block.minecraft.banner.curly_border.white": "White Bordure Indented", + "block.minecraft.banner.mojang.black": "Black Thing", + "block.minecraft.banner.mojang.red": "Red Thing", + "block.minecraft.banner.mojang.green": "Green Thing", + "block.minecraft.banner.mojang.brown": "Brown Thing", + "block.minecraft.banner.mojang.blue": "Blue Thing", + "block.minecraft.banner.mojang.purple": "Purple Thing", + "block.minecraft.banner.mojang.cyan": "Cyan Thing", + "block.minecraft.banner.mojang.light_gray": "Light Gray Thing", + "block.minecraft.banner.mojang.gray": "Gray Thing", + "block.minecraft.banner.mojang.pink": "Pink Thing", + "block.minecraft.banner.mojang.lime": "Lime Thing", + "block.minecraft.banner.mojang.yellow": "Yellow Thing", + "block.minecraft.banner.mojang.light_blue": "Light Blue Thing", + "block.minecraft.banner.mojang.magenta": "Magenta Thing", + "block.minecraft.banner.mojang.orange": "Orange Thing", + "block.minecraft.banner.mojang.white": "White Thing", + "block.minecraft.banner.straight_cross.black": "Black Cross", + "block.minecraft.banner.straight_cross.red": "Red Cross", + "block.minecraft.banner.straight_cross.green": "Green Cross", + "block.minecraft.banner.straight_cross.brown": "Brown Cross", + "block.minecraft.banner.straight_cross.blue": "Blue Cross", + "block.minecraft.banner.straight_cross.purple": "Purple Cross", + "block.minecraft.banner.straight_cross.cyan": "Cyan Cross", + "block.minecraft.banner.straight_cross.light_gray": "Light Gray Cross", + "block.minecraft.banner.straight_cross.gray": "Gray Cross", + "block.minecraft.banner.straight_cross.pink": "Pink Cross", + "block.minecraft.banner.straight_cross.lime": "Lime Cross", + "block.minecraft.banner.straight_cross.yellow": "Yellow Cross", + "block.minecraft.banner.straight_cross.light_blue": "Light Blue Cross", + "block.minecraft.banner.straight_cross.magenta": "Magenta Cross", + "block.minecraft.banner.straight_cross.orange": "Orange Cross", + "block.minecraft.banner.straight_cross.white": "White Cross", + "block.minecraft.banner.globe.black": "Black Globe", + "block.minecraft.banner.globe.red": "Red Globe", + "block.minecraft.banner.globe.green": "Green Globe", + "block.minecraft.banner.globe.brown": "Brown Globe", + "block.minecraft.banner.globe.blue": "Blue Globe", + "block.minecraft.banner.globe.purple": "Purple Globe", + "block.minecraft.banner.globe.cyan": "Cyan Globe", + "block.minecraft.banner.globe.light_gray": "Light Gray Globe", + "block.minecraft.banner.globe.gray": "Gray Globe", + "block.minecraft.banner.globe.pink": "Pink Globe", + "block.minecraft.banner.globe.lime": "Lime Globe", + "block.minecraft.banner.globe.yellow": "Yellow Globe", + "block.minecraft.banner.globe.light_blue": "Light Blue Globe", + "block.minecraft.banner.globe.magenta": "Magenta Globe", + "block.minecraft.banner.globe.orange": "Orange Globe", + "block.minecraft.banner.globe.white": "White Globe", + "block.minecraft.banner.piglin.black": "Black Snout", + "block.minecraft.banner.piglin.red": "Red Snout", + "block.minecraft.banner.piglin.green": "Green Snout", + "block.minecraft.banner.piglin.brown": "Brown Snout", + "block.minecraft.banner.piglin.blue": "Blue Snout", + "block.minecraft.banner.piglin.purple": "Purple Snout", + "block.minecraft.banner.piglin.cyan": "Cyan Snout", + "block.minecraft.banner.piglin.light_gray": "Light Gray Snout", + "block.minecraft.banner.piglin.gray": "Gray Snout", + "block.minecraft.banner.piglin.pink": "Pink Snout", + "block.minecraft.banner.piglin.lime": "Lime Snout", + "block.minecraft.banner.piglin.yellow": "Yellow Snout", + "block.minecraft.banner.piglin.light_blue": "Light Blue Snout", + "block.minecraft.banner.piglin.magenta": "Magenta Snout", + "block.minecraft.banner.piglin.orange": "Orange Snout", + "block.minecraft.banner.piglin.white": "White Snout", + "subtitles.ambient.cave": "Eerie noise", + "subtitles.block.amethyst_block.chime": "Amethyst chimes", + "subtitles.block.anvil.destroy": "Anvil destroyed", + "subtitles.block.anvil.land": "Anvil landed", + "subtitles.block.anvil.use": "Anvil used", + "subtitles.block.barrel.close": "Barrel closes", + "subtitles.block.barrel.open": "Barrel opens", + "subtitles.block.beacon.activate": "Beacon activates", + "subtitles.block.beacon.ambient": "Beacon hums", + "subtitles.block.beacon.deactivate": "Beacon deactivates", + "subtitles.block.beacon.power_select": "Beacon power selected", + "subtitles.block.beehive.drip": "Honey drips", + "subtitles.block.beehive.enter": "Bee enters hive", + "subtitles.block.beehive.exit": "Bee leaves hive", + "subtitles.block.beehive.shear": "Shears scrape", + "subtitles.block.beehive.work": "Bees work", + "subtitles.block.bell.resonate": "Bell resonates", + "subtitles.block.bell.use": "Bell rings", + "subtitles.block.big_dripleaf.tilt_down": "Dripleaf tilts down", + "subtitles.block.big_dripleaf.tilt_up": "Dripleaf tilts up", + "subtitles.block.blastfurnace.fire_crackle": "Blast Furnace crackles", + "subtitles.block.brewing_stand.brew": "Brewing Stand bubbles", + "subtitles.block.bubble_column.bubble_pop": "Bubbles pop", + "subtitles.block.bubble_column.upwards_ambient": "Bubbles flow", + "subtitles.block.bubble_column.upwards_inside": "Bubbles woosh", + "subtitles.block.bubble_column.whirlpool_ambient": "Bubbles whirl", + "subtitles.block.bubble_column.whirlpool_inside": "Bubbles zoom", + "subtitles.block.button.click": "Button clicks", + "subtitles.block.campfire.crackle": "Campfire crackles", + "subtitles.block.candle.crackle": "Candle crackles", + "subtitles.block.cake.add_candle": "Cake squishes", + "subtitles.block.chest.close": "Chest closes", + "subtitles.block.chest.locked": "Chest locked", + "subtitles.block.chest.open": "Chest opens", + "subtitles.chiseled_bookshelf.insert": "Book placed", + "subtitles.chiseled_bookshelf.insert_enchanted": "Enchanted book placed", + "subtitles.chiseled_bookshelf.take": "Book taken", + "subtitles.chiseled_bookshelf.take_enchanted": "Enchanted book taken", + "subtitles.block.chorus_flower.death": "Chorus Flower withers", + "subtitles.block.chorus_flower.grow": "Chorus Flower grows", + "subtitles.block.comparator.click": "Comparator clicks", + "subtitles.block.composter.empty": "Composter emptied", + "subtitles.block.composter.fill": "Composter filled", + "subtitles.block.composter.ready": "Composter composts", + "subtitles.block.conduit.activate": "Conduit activates", + "subtitles.block.conduit.ambient": "Conduit pulses", + "subtitles.block.conduit.attack.target": "Conduit attacks", + "subtitles.block.conduit.deactivate": "Conduit deactivates", + "subtitles.block.dispenser.dispense": "Dispensed item", + "subtitles.block.dispenser.fail": "Dispenser failed", + "subtitles.block.door.toggle": "Door creaks", + "subtitles.block.enchantment_table.use": "Enchanting Table used", + "subtitles.block.end_portal.spawn": "End Portal opens", + "subtitles.block.end_portal_frame.fill": "Eye of Ender attaches", + "subtitles.block.fence_gate.toggle": "Fence Gate creaks", + "subtitles.block.fire.ambient": "Fire crackles", + "subtitles.block.fire.extinguish": "Fire extinguished", + "subtitles.block.frogspawn.hatch": "Tadpole hatches", + "subtitles.block.furnace.fire_crackle": "Furnace crackles", + "subtitles.block.generic.break": "Block broken", + "subtitles.block.generic.footsteps": "Footsteps", + "subtitles.block.generic.hit": "Block breaking", + "subtitles.block.generic.place": "Block placed", + "subtitles.block.grindstone.use": "Grindstone used", + "subtitles.block.growing_plant.crop": "Plant cropped", + "subtitles.block.honey_block.slide": "Sliding down a honey block", + "subtitles.item.honeycomb.wax_on": "Wax on", + "subtitles.block.iron_trapdoor.close": "Trapdoor closes", + "subtitles.block.iron_trapdoor.open": "Trapdoor opens", + "subtitles.block.lava.ambient": "Lava pops", + "subtitles.block.lava.extinguish": "Lava hisses", + "subtitles.block.lever.click": "Lever clicks", + "subtitles.block.note_block.note": "Note Block plays", + "subtitles.block.piston.move": "Piston moves", + "subtitles.block.pointed_dripstone.land": "Stalactite crashes down", + "subtitles.block.pointed_dripstone.drip_lava": "Lava drips", + "subtitles.block.pointed_dripstone.drip_water": "Water drips", + "subtitles.block.pointed_dripstone.drip_lava_into_cauldron": "Lava drips into Cauldron", + "subtitles.block.pointed_dripstone.drip_water_into_cauldron": "Water drips into Cauldron", + "subtitles.block.portal.ambient": "Portal whooshes", + "subtitles.block.portal.travel": "Portal noise fades", + "subtitles.block.portal.trigger": "Portal noise intensifies", + "subtitles.block.pressure_plate.click": "Pressure Plate clicks", + "subtitles.block.pumpkin.carve": "Shears carve", + "subtitles.block.redstone_torch.burnout": "Torch fizzes", + "subtitles.block.respawn_anchor.ambient": "Portal whooshes", + "subtitles.block.respawn_anchor.charge": "Respawn Anchor is charged", + "subtitles.block.respawn_anchor.deplete": "Respawn Anchor depletes", + "subtitles.block.respawn_anchor.set_spawn": "Respawn Anchor sets spawn", + "subtitles.block.sculk.charge": "Sculk bubbles", + "subtitles.block.sculk.spread": "Sculk spreads", + "subtitles.block.sculk_catalyst.bloom": "Sculk Catalyst blooms", + "subtitles.block.sculk_sensor.clicking": "Sculk Sensor starts clicking", + "subtitles.block.sculk_sensor.clicking_stop": "Sculk Sensor stops clicking", + "subtitles.block.sculk_shrieker.shriek": "Sculk Shrieker shrieks", + "subtitles.block.shulker_box.close": "Shulker closes", + "subtitles.block.shulker_box.open": "Shulker opens", + "subtitles.block.smithing_table.use": "Smithing Table used", + "subtitles.block.smoker.smoke": "Smoker smokes", + "subtitles.block.sweet_berry_bush.pick_berries": "Berries pop", + "subtitles.block.trapdoor.toggle": "Trapdoor creaks", + "subtitles.block.tripwire.attach": "Tripwire attaches", + "subtitles.block.tripwire.click": "Tripwire clicks", + "subtitles.block.tripwire.detach": "Tripwire detaches", + "subtitles.block.water.ambient": "Water flows", + "subtitles.enchant.thorns.hit": "Thorns prick", + "subtitles.entity.allay.death": "Allay dies", + "subtitles.entity.allay.hurt": "Allay hurts", + "subtitles.entity.allay.ambient_with_item": "Allay seeks", + "subtitles.entity.allay.ambient_without_item": "Allay yearns", + "subtitles.entity.allay.item_given": "Allay chortles", + "subtitles.entity.allay.item_taken": "Allay allays", + "subtitles.entity.allay.item_thrown": "Allay tosses", + "subtitles.entity.armor_stand.fall": "Something fell", + "subtitles.entity.arrow.hit": "Arrow hits", + "subtitles.entity.arrow.hit_player": "Player hit", + "subtitles.entity.arrow.shoot": "Arrow fired", + "subtitles.entity.axolotl.attack": "Axolotl attacks", + "subtitles.entity.axolotl.death": "Axolotl dies", + "subtitles.entity.axolotl.hurt": "Axolotl hurts", + "subtitles.entity.axolotl.idle_air": "Axolotl chirps", + "subtitles.entity.axolotl.idle_water": "Axolotl chirps", + "subtitles.entity.axolotl.splash": "Axolotl splashes", + "subtitles.entity.axolotl.swim": "Axolotl swims", + "subtitles.entity.bat.ambient": "Bat screeches", + "subtitles.entity.bat.death": "Bat dies", + "subtitles.entity.bat.hurt": "Bat hurts", + "subtitles.entity.bat.takeoff": "Bat takes off", + "subtitles.entity.bee.ambient": "Bee buzzes", + "subtitles.entity.bee.death": "Bee dies", + "subtitles.entity.bee.hurt": "Bee hurts", + "subtitles.entity.bee.loop": "Bee buzzes", + "subtitles.entity.bee.loop_aggressive": "Bee buzzes angrily", + "subtitles.entity.bee.pollinate": "Bee buzzes happily", + "subtitles.entity.bee.sting": "Bee stings", + "subtitles.entity.blaze.ambient": "Blaze breathes", + "subtitles.entity.blaze.burn": "Blaze crackles", + "subtitles.entity.blaze.death": "Blaze dies", + "subtitles.entity.blaze.hurt": "Blaze hurts", + "subtitles.entity.blaze.shoot": "Blaze shoots", + "subtitles.entity.boat.paddle_land": "Rowing", + "subtitles.entity.boat.paddle_water": "Rowing", + "subtitles.entity.camel.ambient": "Camel grunts", + "subtitles.entity.camel.dash": "Camel yeets", + "subtitles.entity.camel.dash_ready": "Camel recovers", + "subtitles.entity.camel.death": "Camel dies", + "subtitles.entity.camel.eat": "Camel eats", + "subtitles.entity.camel.hurt": "Camel hurts", + "subtitles.entity.camel.saddle": "Saddle equips", + "subtitles.entity.camel.sit": "Camel sits down", + "subtitles.entity.camel.stand": "Camel stands up", + "subtitles.entity.camel.step": "Camel steps", + "subtitles.entity.camel.step_sand": "Camel sands", + "subtitles.entity.cat.ambient": "Cat meows", + "subtitles.entity.cat.beg_for_food": "Cat begs", + "subtitles.entity.cat.death": "Cat dies", + "subtitles.entity.cat.eat": "Cat eats", + "subtitles.entity.cat.hiss": "Cat hisses", + "subtitles.entity.cat.hurt": "Cat hurts", + "subtitles.entity.cat.purr": "Cat purrs", + "subtitles.entity.chicken.ambient": "Chicken clucks", + "subtitles.entity.chicken.death": "Chicken dies", + "subtitles.entity.chicken.egg": "Chicken plops", + "subtitles.entity.chicken.hurt": "Chicken hurts", + "subtitles.entity.cod.death": "Cod dies", + "subtitles.entity.cod.flop": "Cod flops", + "subtitles.entity.cod.hurt": "Cod hurts", + "subtitles.entity.cow.ambient": "Cow moos", + "subtitles.entity.cow.death": "Cow dies", + "subtitles.entity.cow.hurt": "Cow hurts", + "subtitles.entity.cow.milk": "Cow gets milked", + "subtitles.entity.creeper.death": "Creeper dies", + "subtitles.entity.creeper.hurt": "Creeper hurts", + "subtitles.entity.creeper.primed": "Creeper hisses", + "subtitles.entity.dolphin.ambient": "Dolphin chirps", + "subtitles.entity.dolphin.ambient_water": "Dolphin whistles", + "subtitles.entity.dolphin.attack": "Dolphin attacks", + "subtitles.entity.dolphin.death": "Dolphin dies", + "subtitles.entity.dolphin.eat": "Dolphin eats", + "subtitles.entity.dolphin.hurt": "Dolphin hurts", + "subtitles.entity.dolphin.jump": "Dolphin jumps", + "subtitles.entity.dolphin.play": "Dolphin plays", + "subtitles.entity.dolphin.splash": "Dolphin splashes", + "subtitles.entity.dolphin.swim": "Dolphin swims", + "subtitles.entity.donkey.ambient": "Donkey hee-haws", + "subtitles.entity.donkey.angry": "Donkey neighs", + "subtitles.entity.donkey.chest": "Donkey Chest equips", + "subtitles.entity.donkey.death": "Donkey dies", + "subtitles.entity.donkey.eat": "Donkey eats", + "subtitles.entity.donkey.hurt": "Donkey hurts", + "subtitles.entity.drowned.ambient": "Drowned gurgles", + "subtitles.entity.drowned.ambient_water": "Drowned gurgles", + "subtitles.entity.drowned.death": "Drowned dies", + "subtitles.entity.drowned.hurt": "Drowned hurts", + "subtitles.entity.drowned.shoot": "Drowned throws Trident", + "subtitles.entity.drowned.step": "Drowned steps", + "subtitles.entity.drowned.swim": "Drowned swims", + "subtitles.entity.egg.throw": "Egg flies", + "subtitles.entity.elder_guardian.ambient": "Elder Guardian moans", + "subtitles.entity.elder_guardian.ambient_land": "Elder Guardian flaps", + "subtitles.entity.elder_guardian.curse": "Elder Guardian curses", + "subtitles.entity.elder_guardian.death": "Elder Guardian dies", + "subtitles.entity.elder_guardian.flop": "Elder Guardian flops", + "subtitles.entity.elder_guardian.hurt": "Elder Guardian hurts", + "subtitles.entity.ender_dragon.ambient": "Dragon roars", + "subtitles.entity.ender_dragon.death": "Dragon dies", + "subtitles.entity.ender_dragon.flap": "Dragon flaps", + "subtitles.entity.ender_dragon.growl": "Dragon growls", + "subtitles.entity.ender_dragon.hurt": "Dragon hurts", + "subtitles.entity.ender_dragon.shoot": "Dragon shoots", + "subtitles.entity.ender_eye.death": "Eye of Ender falls", + "subtitles.entity.ender_eye.launch": "Eye of Ender shoots", + "subtitles.entity.ender_pearl.throw": "Ender Pearl flies", + "subtitles.entity.enderman.ambient": "Enderman vwoops", + "subtitles.entity.enderman.death": "Enderman dies", + "subtitles.entity.enderman.hurt": "Enderman hurts", + "subtitles.entity.enderman.scream": "Enderman screams", + "subtitles.entity.enderman.stare": "Enderman cries out", + "subtitles.entity.enderman.teleport": "Enderman teleports", + "subtitles.entity.endermite.ambient": "Endermite scuttles", + "subtitles.entity.endermite.death": "Endermite dies", + "subtitles.entity.endermite.hurt": "Endermite hurts", + "subtitles.entity.evoker.ambient": "Evoker murmurs", + "subtitles.entity.evoker.cast_spell": "Evoker casts spell", + "subtitles.entity.evoker.celebrate": "Evoker cheers", + "subtitles.entity.evoker.death": "Evoker dies", + "subtitles.entity.evoker.hurt": "Evoker hurts", + "subtitles.entity.evoker.prepare_attack": "Evoker prepares attack", + "subtitles.entity.evoker.prepare_summon": "Evoker prepares summoning", + "subtitles.entity.evoker.prepare_wololo": "Evoker prepares charming", + "subtitles.entity.evoker_fangs.attack": "Fangs snap", + "subtitles.entity.experience_orb.pickup": "Experience gained", + "subtitles.entity.firework_rocket.blast": "Firework blasts", + "subtitles.entity.firework_rocket.launch": "Firework launches", + "subtitles.entity.firework_rocket.twinkle": "Firework twinkles", + "subtitles.entity.fishing_bobber.retrieve": "Bobber retrieved", + "subtitles.entity.fishing_bobber.splash": "Fishing Bobber splashes", + "subtitles.entity.fishing_bobber.throw": "Bobber thrown", + "subtitles.entity.fox.aggro": "Fox angers", + "subtitles.entity.fox.ambient": "Fox squeaks", + "subtitles.entity.fox.bite": "Fox bites", + "subtitles.entity.fox.death": "Fox dies", + "subtitles.entity.fox.eat": "Fox eats", + "subtitles.entity.fox.hurt": "Fox hurts", + "subtitles.entity.fox.screech": "Fox screeches", + "subtitles.entity.fox.sleep": "Fox snores", + "subtitles.entity.fox.sniff": "Fox sniffs", + "subtitles.entity.fox.spit": "Fox spits", + "subtitles.entity.fox.teleport": "Fox teleports", + "subtitles.entity.frog.ambient": "Frog croaks", + "subtitles.entity.frog.death": "Frog dies", + "subtitles.entity.frog.eat": "Frog eats", + "subtitles.entity.frog.hurt": "Frog hurts", + "subtitles.entity.frog.lay_spawn": "Frog lays spawn", + "subtitles.entity.frog.long_jump": "Frog jumps", + "subtitles.entity.generic.big_fall": "Something fell", + "subtitles.entity.generic.burn": "Burning", + "subtitles.entity.generic.death": "Dying", + "subtitles.entity.generic.drink": "Sipping", + "subtitles.entity.generic.eat": "Eating", + "subtitles.entity.generic.explode": "Explosion", + "subtitles.entity.generic.extinguish_fire": "Fire extinguishes", + "subtitles.entity.generic.hurt": "Something hurts", + "subtitles.entity.generic.small_fall": "Something trips", + "subtitles.entity.generic.splash": "Splashing", + "subtitles.entity.generic.swim": "Swimming", + "subtitles.entity.ghast.ambient": "Ghast cries", + "subtitles.entity.ghast.death": "Ghast dies", + "subtitles.entity.ghast.hurt": "Ghast hurts", + "subtitles.entity.ghast.shoot": "Ghast shoots", + "subtitles.entity.glow_item_frame.add_item": "Glow Item Frame fills", + "subtitles.entity.glow_item_frame.break": "Glow Item Frame breaks", + "subtitles.entity.glow_item_frame.place": "Glow Item Frame placed", + "subtitles.entity.glow_item_frame.remove_item": "Glow Item Frame empties", + "subtitles.entity.glow_item_frame.rotate_item": "Glow Item Frame clicks", + "subtitles.entity.glow_squid.ambient": "Glow Squid swims", + "subtitles.entity.glow_squid.death": "Glow Squid dies", + "subtitles.entity.glow_squid.hurt": "Glow Squid hurts", + "subtitles.entity.glow_squid.squirt": "Glow Squid shoots ink", + "subtitles.entity.goat.ambient": "Goat bleats", + "subtitles.entity.goat.screaming.ambient": "Goat bellows", + "subtitles.entity.goat.death": "Goat dies", + "subtitles.entity.goat.eat": "Goat eats", + "subtitles.entity.goat.horn_break": "Goat Horn breaks off", + "subtitles.entity.goat.hurt": "Goat hurts", + "subtitles.entity.goat.long_jump": "Goat leaps", + "subtitles.entity.goat.milk": "Goat gets milked", + "subtitles.entity.goat.prepare_ram": "Goat stomps", + "subtitles.entity.goat.ram_impact": "Goat rams", + "subtitles.entity.goat.step": "Goat steps", + "subtitles.entity.guardian.ambient": "Guardian moans", + "subtitles.entity.guardian.ambient_land": "Guardian flaps", + "subtitles.entity.guardian.attack": "Guardian shoots", + "subtitles.entity.guardian.death": "Guardian dies", + "subtitles.entity.guardian.flop": "Guardian flops", + "subtitles.entity.guardian.hurt": "Guardian hurts", + "subtitles.entity.hoglin.ambient": "Hoglin growls", + "subtitles.entity.hoglin.angry": "Hoglin growls angrily", + "subtitles.entity.hoglin.attack": "Hoglin attacks", + "subtitles.entity.hoglin.converted_to_zombified": "Hoglin converts to Zoglin", + "subtitles.entity.hoglin.death": "Hoglin dies", + "subtitles.entity.hoglin.hurt": "Hoglin hurts", + "subtitles.entity.hoglin.retreat": "Hoglin retreats", + "subtitles.entity.hoglin.step": "Hoglin steps", + "subtitles.entity.horse.ambient": "Horse neighs", + "subtitles.entity.horse.angry": "Horse neighs", + "subtitles.entity.horse.armor": "Horse armor equips", + "subtitles.entity.horse.breathe": "Horse breathes", + "subtitles.entity.horse.death": "Horse dies", + "subtitles.entity.horse.eat": "Horse eats", + "subtitles.entity.horse.gallop": "Horse gallops", + "subtitles.entity.horse.hurt": "Horse hurts", + "subtitles.entity.horse.jump": "Horse jumps", + "subtitles.entity.horse.saddle": "Saddle equips", + "subtitles.entity.husk.ambient": "Husk groans", + "subtitles.entity.husk.converted_to_zombie": "Husk converts to Zombie", + "subtitles.entity.husk.death": "Husk dies", + "subtitles.entity.husk.hurt": "Husk hurts", + "subtitles.entity.illusioner.ambient": "Illusioner murmurs", + "subtitles.entity.illusioner.cast_spell": "Illusioner casts spell", + "subtitles.entity.illusioner.death": "Illusioner dies", + "subtitles.entity.illusioner.hurt": "Illusioner hurts", + "subtitles.entity.illusioner.mirror_move": "Illusioner displaces", + "subtitles.entity.illusioner.prepare_blindness": "Illusioner prepares blindness", + "subtitles.entity.illusioner.prepare_mirror": "Illusioner prepares mirror image", + "subtitles.entity.iron_golem.attack": "Iron Golem attacks", + "subtitles.entity.iron_golem.damage": "Iron Golem breaks", + "subtitles.entity.iron_golem.death": "Iron Golem dies", + "subtitles.entity.iron_golem.hurt": "Iron Golem hurts", + "subtitles.entity.iron_golem.repair": "Iron Golem repaired", + "subtitles.entity.item.break": "Item breaks", + "subtitles.entity.item.pickup": "Item plops", + "subtitles.entity.item_frame.add_item": "Item Frame fills", + "subtitles.entity.item_frame.break": "Item Frame breaks", + "subtitles.entity.item_frame.place": "Item Frame placed", + "subtitles.entity.item_frame.remove_item": "Item Frame empties", + "subtitles.entity.item_frame.rotate_item": "Item Frame clicks", + "subtitles.entity.leash_knot.break": "Leash knot breaks", + "subtitles.entity.leash_knot.place": "Leash knot tied", + "subtitles.entity.lightning_bolt.impact": "Lightning strikes", + "subtitles.entity.lightning_bolt.thunder": "Thunder roars", + "subtitles.entity.llama.ambient": "Llama bleats", + "subtitles.entity.llama.angry": "Llama bleats angrily", + "subtitles.entity.llama.chest": "Llama Chest equips", + "subtitles.entity.llama.death": "Llama dies", + "subtitles.entity.llama.eat": "Llama eats", + "subtitles.entity.llama.hurt": "Llama hurts", + "subtitles.entity.llama.spit": "Llama spits", + "subtitles.entity.llama.step": "Llama steps", + "subtitles.entity.llama.swag": "Llama is decorated", + "subtitles.entity.magma_cube.death": "Magma Cube dies", + "subtitles.entity.magma_cube.hurt": "Magma Cube hurts", + "subtitles.entity.magma_cube.squish": "Magma Cube squishes", + "subtitles.entity.minecart.riding": "Minecart rolls", + "subtitles.entity.mooshroom.convert": "Mooshroom transforms", + "subtitles.entity.mooshroom.eat": "Mooshroom eats", + "subtitles.entity.mooshroom.milk": "Mooshroom gets milked", + "subtitles.entity.mooshroom.suspicious_milk": "Mooshroom gets milked suspiciously", + "subtitles.entity.mule.ambient": "Mule hee-haws", + "subtitles.entity.mule.angry": "Mule neighs", + "subtitles.entity.mule.chest": "Mule Chest equips", + "subtitles.entity.mule.death": "Mule dies", + "subtitles.entity.mule.eat": "Mule eats", + "subtitles.entity.mule.hurt": "Mule hurts", + "subtitles.entity.painting.break": "Painting breaks", + "subtitles.entity.painting.place": "Painting placed", + "subtitles.entity.panda.aggressive_ambient": "Panda huffs", + "subtitles.entity.panda.ambient": "Panda pants", + "subtitles.entity.panda.bite": "Panda bites", + "subtitles.entity.panda.cant_breed": "Panda bleats", + "subtitles.entity.panda.death": "Panda dies", + "subtitles.entity.panda.eat": "Panda eats", + "subtitles.entity.panda.hurt": "Panda hurts", + "subtitles.entity.panda.pre_sneeze": "Panda's nose tickles", + "subtitles.entity.panda.sneeze": "Panda sneezes", + "subtitles.entity.panda.step": "Panda steps", + "subtitles.entity.panda.worried_ambient": "Panda whimpers", + "subtitles.entity.parrot.ambient": "Parrot talks", + "subtitles.entity.parrot.death": "Parrot dies", + "subtitles.entity.parrot.eats": "Parrot eats", + "subtitles.entity.parrot.fly": "Parrot flutters", + "subtitles.entity.parrot.hurts": "Parrot hurts", + "subtitles.entity.parrot.imitate.blaze": "Parrot breathes", + "subtitles.entity.parrot.imitate.creeper": "Parrot hisses", + "subtitles.entity.parrot.imitate.drowned": "Parrot gurgles", + "subtitles.entity.parrot.imitate.elder_guardian": "Parrot moans", + "subtitles.entity.parrot.imitate.ender_dragon": "Parrot roars", + "subtitles.entity.parrot.imitate.endermite": "Parrot scuttles", + "subtitles.entity.parrot.imitate.evoker": "Parrot murmurs", + "subtitles.entity.parrot.imitate.ghast": "Parrot cries", + "subtitles.entity.parrot.imitate.guardian": "Parrot moans", + "subtitles.entity.parrot.imitate.hoglin": "Parrot growls", + "subtitles.entity.parrot.imitate.husk": "Parrot groans", + "subtitles.entity.parrot.imitate.illusioner": "Parrot murmurs", + "subtitles.entity.parrot.imitate.magma_cube": "Parrot squishes", + "subtitles.entity.parrot.imitate.phantom": "Parrot screeches", + "subtitles.entity.parrot.imitate.piglin": "Parrot snorts", + "subtitles.entity.parrot.imitate.piglin_brute": "Parrot snorts", + "subtitles.entity.parrot.imitate.pillager": "Parrot murmurs", + "subtitles.entity.parrot.imitate.ravager": "Parrot grunts", + "subtitles.entity.parrot.imitate.shulker": "Parrot lurks", + "subtitles.entity.parrot.imitate.silverfish": "Parrot hisses", + "subtitles.entity.parrot.imitate.skeleton": "Parrot rattles", + "subtitles.entity.parrot.imitate.slime": "Parrot squishes", + "subtitles.entity.parrot.imitate.spider": "Parrot hisses", + "subtitles.entity.parrot.imitate.stray": "Parrot rattles", + "subtitles.entity.parrot.imitate.vex": "Parrot vexes", + "subtitles.entity.parrot.imitate.vindicator": "Parrot mutters", + "subtitles.entity.parrot.imitate.warden": "Parrot whines", + "subtitles.entity.parrot.imitate.witch": "Parrot giggles", + "subtitles.entity.parrot.imitate.wither": "Parrot angers", + "subtitles.entity.parrot.imitate.wither_skeleton": "Parrot rattles", + "subtitles.entity.parrot.imitate.zoglin": "Parrot growls", + "subtitles.entity.parrot.imitate.zombie": "Parrot groans", + "subtitles.entity.parrot.imitate.zombie_villager": "Parrot groans", + "subtitles.entity.phantom.ambient": "Phantom screeches", + "subtitles.entity.phantom.bite": "Phantom bites", + "subtitles.entity.phantom.death": "Phantom dies", + "subtitles.entity.phantom.flap": "Phantom flaps", + "subtitles.entity.phantom.hurt": "Phantom hurts", + "subtitles.entity.phantom.swoop": "Phantom swoops", + "subtitles.entity.pig.ambient": "Pig oinks", + "subtitles.entity.pig.death": "Pig dies", + "subtitles.entity.pig.hurt": "Pig hurts", + "subtitles.entity.pig.saddle": "Saddle equips", + "subtitles.entity.piglin.admiring_item": "Piglin admires item", + "subtitles.entity.piglin.ambient": "Piglin snorts", + "subtitles.entity.piglin.angry": "Piglin snorts angrily", + "subtitles.entity.piglin.celebrate": "Piglin celebrates", + "subtitles.entity.piglin.converted_to_zombified": "Piglin converts to Zombified Piglin", + "subtitles.entity.piglin.death": "Piglin dies", + "subtitles.entity.piglin.hurt": "Piglin hurts", + "subtitles.entity.piglin.jealous": "Piglin snorts enviously", + "subtitles.entity.piglin.retreat": "Piglin retreats", + "subtitles.entity.piglin.step": "Piglin steps", + "subtitles.entity.piglin_brute.ambient": "Piglin Brute snorts", + "subtitles.entity.piglin_brute.angry": "Piglin Brute snorts angrily", + "subtitles.entity.piglin_brute.death": "Piglin Brute dies", + "subtitles.entity.piglin_brute.hurt": "Piglin Brute hurts", + "subtitles.entity.piglin_brute.step": "Piglin Brute steps", + "subtitles.entity.piglin_brute.converted_to_zombified": "Piglin Brute converts to Zombified Piglin", + "subtitles.entity.pillager.ambient": "Pillager murmurs", + "subtitles.entity.pillager.celebrate": "Pillager cheers", + "subtitles.entity.pillager.death": "Pillager dies", + "subtitles.entity.pillager.hurt": "Pillager hurts", + "subtitles.entity.player.attack.crit": "Critical attack", + "subtitles.entity.player.attack.knockback": "Knockback attack", + "subtitles.entity.player.attack.strong": "Strong attack", + "subtitles.entity.player.attack.sweep": "Sweeping attack", + "subtitles.entity.player.attack.weak": "Weak attack", + "subtitles.entity.player.burp": "Burp", + "subtitles.entity.player.death": "Player dies", + "subtitles.entity.player.hurt": "Player hurts", + "subtitles.entity.player.hurt_drown": "Player drowning", + "subtitles.entity.player.hurt_on_fire": "Player burns", + "subtitles.entity.player.levelup": "Player dings", + "subtitles.entity.player.freeze_hurt": "Player freezes", + "subtitles.entity.polar_bear.ambient": "Polar Bear groans", + "subtitles.entity.polar_bear.ambient_baby": "Polar Bear hums", + "subtitles.entity.polar_bear.death": "Polar Bear dies", + "subtitles.entity.polar_bear.hurt": "Polar Bear hurts", + "subtitles.entity.polar_bear.warning": "Polar Bear roars", + "subtitles.entity.potion.splash": "Bottle smashes", + "subtitles.entity.potion.throw": "Bottle thrown", + "subtitles.entity.puffer_fish.blow_out": "Pufferfish deflates", + "subtitles.entity.puffer_fish.blow_up": "Pufferfish inflates", + "subtitles.entity.puffer_fish.death": "Pufferfish dies", + "subtitles.entity.puffer_fish.flop": "Pufferfish flops", + "subtitles.entity.puffer_fish.hurt": "Pufferfish hurts", + "subtitles.entity.puffer_fish.sting": "Pufferfish stings", + "subtitles.entity.rabbit.ambient": "Rabbit squeaks", + "subtitles.entity.rabbit.attack": "Rabbit attacks", + "subtitles.entity.rabbit.death": "Rabbit dies", + "subtitles.entity.rabbit.hurt": "Rabbit hurts", + "subtitles.entity.rabbit.jump": "Rabbit hops", + "subtitles.entity.ravager.ambient": "Ravager grunts", + "subtitles.entity.ravager.attack": "Ravager bites", + "subtitles.entity.ravager.celebrate": "Ravager cheers", + "subtitles.entity.ravager.death": "Ravager dies", + "subtitles.entity.ravager.hurt": "Ravager hurts", + "subtitles.entity.ravager.roar": "Ravager roars", + "subtitles.entity.ravager.step": "Ravager steps", + "subtitles.entity.ravager.stunned": "Ravager stunned", + "subtitles.entity.salmon.death": "Salmon dies", + "subtitles.entity.salmon.flop": "Salmon flops", + "subtitles.entity.salmon.hurt": "Salmon hurts", + "subtitles.entity.sheep.ambient": "Sheep baahs", + "subtitles.entity.sheep.death": "Sheep dies", + "subtitles.entity.sheep.hurt": "Sheep hurts", + "subtitles.entity.shulker.ambient": "Shulker lurks", + "subtitles.entity.shulker.close": "Shulker closes", + "subtitles.entity.shulker.death": "Shulker dies", + "subtitles.entity.shulker.hurt": "Shulker hurts", + "subtitles.entity.shulker.open": "Shulker opens", + "subtitles.entity.shulker.shoot": "Shulker shoots", + "subtitles.entity.shulker.teleport": "Shulker teleports", + "subtitles.entity.shulker_bullet.hit": "Shulker Bullet explodes", + "subtitles.entity.shulker_bullet.hurt": "Shulker Bullet breaks", + "subtitles.entity.silverfish.ambient": "Silverfish hisses", + "subtitles.entity.silverfish.death": "Silverfish dies", + "subtitles.entity.silverfish.hurt": "Silverfish hurts", + "subtitles.entity.skeleton.ambient": "Skeleton rattles", + "subtitles.entity.skeleton.converted_to_stray": "Skeleton converts to Stray", + "subtitles.entity.skeleton.death": "Skeleton dies", + "subtitles.entity.skeleton.hurt": "Skeleton hurts", + "subtitles.entity.skeleton.shoot": "Skeleton shoots", + "subtitles.entity.skeleton_horse.ambient": "Skeleton Horse cries", + "subtitles.entity.skeleton_horse.death": "Skeleton Horse dies", + "subtitles.entity.skeleton_horse.hurt": "Skeleton Horse hurts", + "subtitles.entity.skeleton_horse.swim": "Skeleton Horse swims", + "subtitles.entity.slime.attack": "Slime attacks", + "subtitles.entity.slime.death": "Slime dies", + "subtitles.entity.slime.hurt": "Slime hurts", + "subtitles.entity.slime.squish": "Slime squishes", + "subtitles.entity.snow_golem.death": "Snow Golem dies", + "subtitles.entity.snow_golem.hurt": "Snow Golem hurts", + "subtitles.entity.snowball.throw": "Snowball flies", + "subtitles.entity.spider.ambient": "Spider hisses", + "subtitles.entity.spider.death": "Spider dies", + "subtitles.entity.spider.hurt": "Spider hurts", + "subtitles.entity.squid.ambient": "Squid swims", + "subtitles.entity.squid.death": "Squid dies", + "subtitles.entity.squid.hurt": "Squid hurts", + "subtitles.entity.squid.squirt": "Squid shoots ink", + "subtitles.entity.stray.ambient": "Stray rattles", + "subtitles.entity.stray.death": "Stray dies", + "subtitles.entity.stray.hurt": "Stray hurts", + "subtitles.entity.strider.death": "Strider dies", + "subtitles.entity.strider.eat": "Strider eats", + "subtitles.entity.strider.happy": "Strider warbles", + "subtitles.entity.strider.hurt": "Strider hurts", + "subtitles.entity.strider.idle": "Strider chirps", + "subtitles.entity.strider.retreat": "Strider retreats", + "subtitles.entity.tadpole.death": "Tadpole dies", + "subtitles.entity.tadpole.flop": "Tadpole flops", + "subtitles.entity.tadpole.grow_up": "Tadpole grows up", + "subtitles.entity.tadpole.hurt": "Tadpole hurts", + "subtitles.entity.tnt.primed": "TNT fizzes", + "subtitles.entity.tropical_fish.death": "Tropical Fish dies", + "subtitles.entity.tropical_fish.flop": "Tropical Fish flops", + "subtitles.entity.tropical_fish.hurt": "Tropical Fish hurts", + "subtitles.entity.turtle.ambient_land": "Turtle chirps", + "subtitles.entity.turtle.death": "Turtle dies", + "subtitles.entity.turtle.death_baby": "Turtle baby dies", + "subtitles.entity.turtle.egg_break": "Turtle Egg breaks", + "subtitles.entity.turtle.egg_crack": "Turtle Egg cracks", + "subtitles.entity.turtle.egg_hatch": "Turtle Egg hatches", + "subtitles.entity.turtle.hurt": "Turtle hurts", + "subtitles.entity.turtle.hurt_baby": "Turtle baby hurts", + "subtitles.entity.turtle.lay_egg": "Turtle lays egg", + "subtitles.entity.turtle.shamble": "Turtle shambles", + "subtitles.entity.turtle.shamble_baby": "Turtle baby shambles", + "subtitles.entity.turtle.swim": "Turtle swims", + "subtitles.entity.vex.ambient": "Vex vexes", + "subtitles.entity.vex.charge": "Vex shrieks", + "subtitles.entity.vex.death": "Vex dies", + "subtitles.entity.vex.hurt": "Vex hurts", + "subtitles.entity.villager.ambient": "Villager mumbles", + "subtitles.entity.villager.celebrate": "Villager cheers", + "subtitles.entity.villager.death": "Villager dies", + "subtitles.entity.villager.hurt": "Villager hurts", + "subtitles.entity.villager.no": "Villager disagrees", + "subtitles.entity.villager.trade": "Villager trades", + "subtitles.entity.villager.work_armorer": "Armorer works", + "subtitles.entity.villager.work_butcher": "Butcher works", + "subtitles.entity.villager.work_cartographer": "Cartographer works", + "subtitles.entity.villager.work_cleric": "Cleric works", + "subtitles.entity.villager.work_farmer": "Farmer works", + "subtitles.entity.villager.work_fisherman": "Fisherman works", + "subtitles.entity.villager.work_fletcher": "Fletcher works", + "subtitles.entity.villager.work_leatherworker": "Leatherworker works", + "subtitles.entity.villager.work_librarian": "Librarian works", + "subtitles.entity.villager.work_mason": "Mason works", + "subtitles.entity.villager.work_shepherd": "Shepherd works", + "subtitles.entity.villager.work_toolsmith": "Toolsmith works", + "subtitles.entity.villager.work_weaponsmith": "Weaponsmith works", + "subtitles.entity.villager.yes": "Villager agrees", + "subtitles.entity.vindicator.ambient": "Vindicator mutters", + "subtitles.entity.vindicator.celebrate": "Vindicator cheers", + "subtitles.entity.vindicator.death": "Vindicator dies", + "subtitles.entity.vindicator.hurt": "Vindicator hurts", + "subtitles.entity.wandering_trader.ambient": "Wandering Trader mumbles", + "subtitles.entity.wandering_trader.death": "Wandering Trader dies", + "subtitles.entity.wandering_trader.disappeared": "Wandering Trader disappears", + "subtitles.entity.wandering_trader.drink_milk": "Wandering Trader drinks milk", + "subtitles.entity.wandering_trader.drink_potion": "Wandering Trader drinks potion", + "subtitles.entity.wandering_trader.hurt": "Wandering Trader hurts", + "subtitles.entity.wandering_trader.no": "Wandering Trader disagrees", + "subtitles.entity.wandering_trader.reappeared": "Wandering Trader appears", + "subtitles.entity.wandering_trader.trade": "Wandering Trader trades", + "subtitles.entity.wandering_trader.yes": "Wandering Trader agrees", + "subtitles.entity.warden.roar": "Warden roars", + "subtitles.entity.warden.sniff": "Warden sniffs", + "subtitles.entity.warden.emerge": "Warden emerges", + "subtitles.entity.warden.dig": "Warden digs", + "subtitles.entity.warden.hurt": "Warden hurts", + "subtitles.entity.warden.death": "Warden dies", + "subtitles.entity.warden.step": "Warden steps", + "subtitles.entity.warden.listening": "Warden takes notice", + "subtitles.entity.warden.listening_angry": "Warden takes notice angrily", + "subtitles.entity.warden.heartbeat": "Warden's heart beats", + "subtitles.entity.warden.attack_impact": "Warden lands hit", + "subtitles.entity.warden.tendril_clicks": "Warden's tendrils click", + "subtitles.entity.warden.angry": "Warden rages", + "subtitles.entity.warden.agitated": "Warden groans angrily", + "subtitles.entity.warden.ambient": "Warden whines", + "subtitles.entity.warden.nearby_close": "Warden approaches", + "subtitles.entity.warden.nearby_closer": "Warden advances", + "subtitles.entity.warden.nearby_closest": "Warden draws close", + "subtitles.entity.warden.sonic_charge": "Warden charges", + "subtitles.entity.warden.sonic_boom": "Warden booms", + "subtitles.entity.witch.ambient": "Witch giggles", + "subtitles.entity.witch.celebrate": "Witch cheers", + "subtitles.entity.witch.death": "Witch dies", + "subtitles.entity.witch.drink": "Witch drinks", + "subtitles.entity.witch.hurt": "Witch hurts", + "subtitles.entity.witch.throw": "Witch throws", + "subtitles.entity.wither.ambient": "Wither angers", + "subtitles.entity.wither.death": "Wither dies", + "subtitles.entity.wither.hurt": "Wither hurts", + "subtitles.entity.wither.shoot": "Wither attacks", + "subtitles.entity.wither.spawn": "Wither released", + "subtitles.entity.wither_skeleton.ambient": "Wither Skeleton rattles", + "subtitles.entity.wither_skeleton.death": "Wither Skeleton dies", + "subtitles.entity.wither_skeleton.hurt": "Wither Skeleton hurts", + "subtitles.entity.wolf.ambient": "Wolf pants", + "subtitles.entity.wolf.death": "Wolf dies", + "subtitles.entity.wolf.growl": "Wolf growls", + "subtitles.entity.wolf.hurt": "Wolf hurts", + "subtitles.entity.wolf.shake": "Wolf shakes", + "subtitles.entity.zoglin.ambient": "Zoglin growls", + "subtitles.entity.zoglin.angry": "Zoglin growls angrily", + "subtitles.entity.zoglin.attack": "Zoglin attacks", + "subtitles.entity.zoglin.death": "Zoglin dies", + "subtitles.entity.zoglin.hurt": "Zoglin hurts", + "subtitles.entity.zoglin.step": "Zoglin steps", + "subtitles.entity.zombie.ambient": "Zombie groans", + "subtitles.entity.zombie.attack_wooden_door": "Door shakes", + "subtitles.entity.zombie.converted_to_drowned": "Zombie converts to Drowned", + "subtitles.entity.zombie.break_wooden_door": "Door breaks", + "subtitles.entity.zombie.death": "Zombie dies", + "subtitles.entity.zombie.destroy_egg": "Turtle Egg stomped", + "subtitles.entity.zombie.hurt": "Zombie hurts", + "subtitles.entity.zombie.infect": "Zombie infects", + "subtitles.entity.zombie_horse.ambient": "Zombie Horse cries", + "subtitles.entity.zombie_horse.death": "Zombie Horse dies", + "subtitles.entity.zombie_horse.hurt": "Zombie Horse hurts", + "subtitles.entity.zombie_villager.ambient": "Zombie Villager groans", + "subtitles.entity.zombie_villager.converted": "Zombie Villager vociferates", + "subtitles.entity.zombie_villager.cure": "Zombie Villager snuffles", + "subtitles.entity.zombie_villager.death": "Zombie Villager dies", + "subtitles.entity.zombie_villager.hurt": "Zombie Villager hurts", + "subtitles.entity.zombified_piglin.ambient": "Zombified Piglin grunts", + "subtitles.entity.zombified_piglin.angry": "Zombified Piglin grunts angrily", + "subtitles.entity.zombified_piglin.death": "Zombified Piglin dies", + "subtitles.entity.zombified_piglin.hurt": "Zombified Piglin hurts", + "subtitles.event.raid.horn": "Ominous horn blares", + "subtitles.item.armor.equip": "Gear equips", + "subtitles.item.armor.equip_chain": "Chain armor jingles", + "subtitles.item.armor.equip_diamond": "Diamond armor clangs", + "subtitles.item.armor.equip_elytra": "Elytra rustle", + "subtitles.item.armor.equip_gold": "Gold armor clinks", + "subtitles.item.armor.equip_iron": "Iron armor clanks", + "subtitles.item.armor.equip_leather": "Leather armor rustles", + "subtitles.item.armor.equip_netherite": "Netherite armor clanks", + "subtitles.item.armor.equip_turtle": "Turtle Shell thunks", + "subtitles.item.axe.strip": "Axe strips", + "subtitles.item.axe.scrape": "Axe scrapes", + "subtitles.item.axe.wax_off": "Wax off", + "subtitles.item.bone_meal.use": "Bone Meal crinkles", + "subtitles.item.book.page_turn": "Page rustles", + "subtitles.item.book.put": "Book thumps", + "subtitles.item.bottle.empty": "Bottle empties", + "subtitles.item.bottle.fill": "Bottle fills", + "subtitles.item.bucket.empty": "Bucket empties", + "subtitles.item.bucket.fill": "Bucket fills", + "subtitles.item.bucket.fill_axolotl": "Axolotl scooped", + "subtitles.item.bucket.fill_fish": "Fish captured", + "subtitles.item.bucket.fill_tadpole": "Tadpole captured", + "subtitles.item.bundle.drop_contents": "Bundle empties", + "subtitles.item.bundle.insert": "Item packed", + "subtitles.item.bundle.remove_one": "Item unpacked", + "subtitles.item.chorus_fruit.teleport": "Player teleports", + "subtitles.item.crop.plant": "Crop planted", + "subtitles.item.crossbow.charge": "Crossbow charges up", + "subtitles.item.crossbow.hit": "Arrow hits", + "subtitles.item.crossbow.load": "Crossbow loads", + "subtitles.item.crossbow.shoot": "Crossbow fires", + "subtitles.item.firecharge.use": "Fireball whooshes", + "subtitles.item.flintandsteel.use": "Flint and Steel click", + "subtitles.item.goat_horn.play": "Goat Horn plays", + "subtitles.item.hoe.till": "Hoe tills", + "subtitles.item.honey_bottle.drink": "Gulping", + "subtitles.item.lodestone_compass.lock": "Lodestone Compass locks onto Lodestone", + "subtitles.item.nether_wart.plant": "Crop planted", + "subtitles.item.shears.shear": "Shears click", + "subtitles.item.shield.block": "Shield blocks", + "subtitles.item.shovel.flatten": "Shovel flattens", + "subtitles.item.totem.use": "Totem activates", + "subtitles.item.trident.hit": "Trident stabs", + "subtitles.item.trident.hit_ground": "Trident vibrates", + "subtitles.item.trident.return": "Trident returns", + "subtitles.item.trident.riptide": "Trident zooms", + "subtitles.item.trident.throw": "Trident clangs", + "subtitles.item.trident.thunder": "Trident thunder cracks", + "subtitles.item.spyglass.use": "Spyglass expands", + "subtitles.item.spyglass.stop_using": "Spyglass retracts", + "subtitles.item.ink_sac.use": "Ink Sac splotches", + "subtitles.item.glow_ink_sac.use": "Glow Ink Sac splotches", + "subtitles.item.dye.use": "Dye stains", + "subtitles.particle.soul_escape": "Soul escapes", + "subtitles.ui.cartography_table.take_result": "Map drawn", + "subtitles.ui.loom.take_result": "Loom used", + "subtitles.ui.stonecutter.take_result": "Stonecutter used", + "subtitles.weather.rain": "Rain falls", + "telemetry_info.screen.title": "Telemetry Data Collection", + "telemetry_info.screen.description": "Collecting this data helps us improve Minecraft by guiding us in directions that are relevant to our players.\nYou can also send in additional feedback to help us keep improving Minecraft.", + "telemetry_info.button.show_data": "Open My Data", + "telemetry_info.button.give_feedback": "Give Feedback", + "telemetry_info.property_title": "Included Data", + "telemetry.property.user_id.title": "User ID", + "telemetry.property.client_id.title": "Client ID", + "telemetry.property.minecraft_session_id.title": "Minecraft Session ID", + "telemetry.property.game_version.title": "Game Version", + "telemetry.property.operating_system.title": "Operating System", + "telemetry.property.platform.title": "Platform", + "telemetry.property.client_modded.title": "Client Modded", + "telemetry.property.event_timestamp_utc.title": "Event Timestamp (UTC)", + "telemetry.property.opt_in.title": "Opt-In", + "telemetry.property.world_session_id.title": "World Session ID", + "telemetry.property.server_modded.title": "Server Modded", + "telemetry.property.server_type.title": "Server Type", + "telemetry.property.frame_rate_samples.title": "Frame Rate Samples (FPS)", + "telemetry.property.render_time_samples.title": "Render Time Samples", + "telemetry.property.used_memory_samples.title": "Used Random Access Memory", + "telemetry.property.number_of_samples.title": "Sample Count", + "telemetry.property.render_distance.title": "Render Distance", + "telemetry.property.dedicated_memory_kb.title": "Dedicated Memory (kB)", + "telemetry.property.game_mode.title": "Game Mode", + "telemetry.property.seconds_since_load.title": "Time Since Load (Seconds)", + "telemetry.property.ticks_since_load.title": "Time Since Load (Ticks)", + "telemetry.property.world_load_time_ms.title": "World Load Time (Milliseconds)", + "telemetry.property.new_world.title": "New World", + "telemetry.event.required": "%s (Required)", + "telemetry.event.optional": "%s (Optional)", + "telemetry.event.world_loaded.title": "World Loaded", + "telemetry.event.world_loaded.description": "Knowing how players play Minecraft (such as Game Mode, client or server modded, and game version) allows us to focus game updates to improve the areas that players care about most.\nThe World Loaded event is paired with the World Unloaded event to calculate how long the play session has lasted.", + "telemetry.event.world_unloaded.title": "World Unloaded", + "telemetry.event.world_unloaded.description": "This event is paired with the World Loaded event to calculate how long the world session has lasted.\nThe duration (in seconds and ticks) is measured when a world session has ended (quitting to title, disconnecting from a server).", + "telemetry.event.performance_metrics.title": "Performance Metrics", + "telemetry.event.performance_metrics.description": "Knowing the overall performance profile of Minecraft helps us tune and optimize the game for a wide range of machine specifications and operating systems. \nGame version is included to help us compare the performance profile for new versions of Minecraft.", + "telemetry.event.world_load_times.title": "World Load Times", + "telemetry.event.world_load_times.description": "It’s important for us to understand how long it takes to join a world, and how that changes over time. For example, when we add new features or do larger technical changes, we need to see what impact that had on load times.", + "debug.prefix": "[Debug]:", + "debug.reload_chunks.help": "F3 + A = Reload chunks", + "debug.show_hitboxes.help": "F3 + B = Show hitboxes", + "debug.clear_chat.help": "F3 + D = Clear chat", + "debug.chunk_boundaries.help": "F3 + G = Show chunk boundaries", + "debug.advanced_tooltips.help": "F3 + H = Advanced tooltips", + "debug.creative_spectator.help": "F3 + N = Cycle previous gamemode <-> spectator", + "debug.pause_focus.help": "F3 + P = Pause on lost focus", + "debug.help.help": "F3 + Q = Show this list", + "debug.reload_resourcepacks.help": "F3 + T = Reload resource packs", + "debug.pause.help": "F3 + Esc = Pause without pause menu (if pausing is possible)", + "debug.copy_location.help": "F3 + C = Copy location as /tp command, hold F3 + C to crash the game", + "debug.inspect.help": "F3 + I = Copy entity or block data to clipboard", + "debug.gamemodes.help": "F3 + F4 = Open game mode switcher", + "debug.profiling.help": "F3 + L = Start/stop profiling", + "debug.copy_location.message": "Copied location to clipboard", + "debug.inspect.server.block": "Copied server-side block data to clipboard", + "debug.inspect.server.entity": "Copied server-side entity data to clipboard", + "debug.inspect.client.block": "Copied client-side block data to clipboard", + "debug.inspect.client.entity": "Copied client-side entity data to clipboard", + "debug.reload_chunks.message": "Reloading all chunks", + "debug.show_hitboxes.on": "Hitboxes: shown", + "debug.show_hitboxes.off": "Hitboxes: hidden", + "debug.chunk_boundaries.on": "Chunk borders: shown", + "debug.chunk_boundaries.off": "Chunk borders: hidden", + "debug.advanced_tooltips.on": "Advanced tooltips: shown", + "debug.advanced_tooltips.off": "Advanced tooltips: hidden", + "debug.creative_spectator.error": "Unable to switch gamemode; no permission", + "debug.gamemodes.error": "Unable to open game mode switcher; no permission", + "debug.pause_focus.on": "Pause on lost focus: enabled", + "debug.pause_focus.off": "Pause on lost focus: disabled", + "debug.help.message": "Key bindings:", + "debug.reload_resourcepacks.message": "Reloaded resource packs", + "debug.crash.message": "F3 + C is held down. This will crash the game unless released.", + "debug.crash.warning": "Crashing in %s...", + "debug.gamemodes.press_f4": "[ F4 ]", + "debug.gamemodes.select_next": "%s Next", + "debug.profiling.start": "Profiling started for %s seconds. Use F3 + L to stop early", + "debug.profiling.stop": "Profiling ended. Saved results to %s", + "resourcepack.downloading": "Downloading Resource Pack", + "resourcepack.requesting": "Making Request...", + "resourcepack.progress": "Downloading file (%s MB)...", + "tutorial.bundleInsert.title": "Use a Bundle", + "tutorial.bundleInsert.description": "Right Click to add items", + "tutorial.move.title": "Move with %s, %s, %s and %s", + "tutorial.move.description": "Jump with %s", + "tutorial.look.title": "Look around", + "tutorial.look.description": "Use your mouse to turn", + "tutorial.find_tree.title": "Find a tree", + "tutorial.find_tree.description": "Punch it to collect wood", + "tutorial.punch_tree.title": "Destroy the tree", + "tutorial.punch_tree.description": "Hold down %s", + "tutorial.open_inventory.title": "Open your inventory", + "tutorial.open_inventory.description": "Press %s", + "tutorial.craft_planks.title": "Craft wooden planks", + "tutorial.craft_planks.description": "The recipe book can help", + "tutorial.socialInteractions.title": "Social Interactions", + "tutorial.socialInteractions.description": "Press %s to open", + "advancements.adventure.adventuring_time.title": "Adventuring Time", + "advancements.adventure.adventuring_time.description": "Discover every biome", + "advancements.adventure.arbalistic.title": "Arbalistic", + "advancements.adventure.arbalistic.description": "Kill five unique mobs with one crossbow shot", + "advancements.adventure.avoid_vibration.title": "Sneak 100", + "advancements.adventure.avoid_vibration.description": "Sneak near a Sculk Sensor or Warden to prevent it from detecting you", + "advancements.adventure.bullseye.title": "Bullseye", + "advancements.adventure.bullseye.description": "Hit the bullseye of a Target block from at least 30 meters away", + "advancements.adventure.fall_from_world_height.title": "Caves & Cliffs", + "advancements.adventure.fall_from_world_height.description": "Free fall from the top of the world (build limit) to the bottom of the world and survive", + "advancements.adventure.kill_mob_near_sculk_catalyst.title": "It Spreads", + "advancements.adventure.kill_mob_near_sculk_catalyst.description": "Kill a mob near a Sculk Catalyst", + "advancements.adventure.walk_on_powder_snow_with_leather_boots.title": "Light as a Rabbit", + "advancements.adventure.walk_on_powder_snow_with_leather_boots.description": "Walk on Powder Snow...without sinking in it", + "advancements.adventure.lightning_rod_with_villager_no_fire.title": "Surge Protector", + "advancements.adventure.lightning_rod_with_villager_no_fire.description": "Protect a Villager from an undesired shock without starting a fire", + "advancements.adventure.spyglass_at_parrot.title": "Is It a Bird?", + "advancements.adventure.spyglass_at_parrot.description": "Look at a Parrot through a Spyglass", + "advancements.adventure.spyglass_at_ghast.title": "Is It a Balloon?", + "advancements.adventure.spyglass_at_ghast.description": "Look at a Ghast through a Spyglass", + "advancements.adventure.spyglass_at_dragon.title": "Is It a Plane?", + "advancements.adventure.spyglass_at_dragon.description": "Look at the Ender Dragon through a Spyglass", + "advancements.adventure.hero_of_the_village.title": "Hero of the Village", + "advancements.adventure.hero_of_the_village.description": "Successfully defend a village from a raid", + "advancements.adventure.honey_block_slide.title": "Sticky Situation", + "advancements.adventure.honey_block_slide.description": "Jump into a Honey Block to break your fall", + "advancements.adventure.kill_all_mobs.title": "Monsters Hunted", + "advancements.adventure.kill_all_mobs.description": "Kill one of every hostile monster", + "advancements.adventure.kill_a_mob.title": "Monster Hunter", + "advancements.adventure.kill_a_mob.description": "Kill any hostile monster", + "advancements.adventure.ol_betsy.title": "Ol' Betsy", + "advancements.adventure.ol_betsy.description": "Shoot a Crossbow", + "advancements.adventure.play_jukebox_in_meadows.title": "Sound of Music", + "advancements.adventure.play_jukebox_in_meadows.description": "Make the Meadows come alive with the sound of music from a Jukebox", + "advancements.adventure.root.title": "Adventure", + "advancements.adventure.root.description": "Adventure, exploration and combat", + "advancements.adventure.shoot_arrow.title": "Take Aim", + "advancements.adventure.shoot_arrow.description": "Shoot something with an Arrow", + "advancements.adventure.sleep_in_bed.title": "Sweet Dreams", + "advancements.adventure.sleep_in_bed.description": "Sleep in a Bed to change your respawn point", + "advancements.adventure.sniper_duel.title": "Sniper Duel", + "advancements.adventure.sniper_duel.description": "Kill a Skeleton from at least 50 meters away", + "advancements.adventure.summon_iron_golem.title": "Hired Help", + "advancements.adventure.summon_iron_golem.description": "Summon an Iron Golem to help defend a village", + "advancements.adventure.totem_of_undying.title": "Postmortal", + "advancements.adventure.totem_of_undying.description": "Use a Totem of Undying to cheat death", + "advancements.adventure.trade.title": "What a Deal!", + "advancements.adventure.trade.description": "Successfully trade with a Villager", + "advancements.adventure.trade_at_world_height.title": "Star Trader", + "advancements.adventure.trade_at_world_height.description": "Trade with a Villager at the build height limit", + "advancements.adventure.throw_trident.title": "A Throwaway Joke", + "advancements.adventure.throw_trident.description": "Throw a Trident at something.\nNote: Throwing away your only weapon is not a good idea.", + "advancements.adventure.two_birds_one_arrow.title": "Two Birds, One Arrow", + "advancements.adventure.two_birds_one_arrow.description": "Kill two Phantoms with a piercing Arrow", + "advancements.adventure.very_very_frightening.title": "Very Very Frightening", + "advancements.adventure.very_very_frightening.description": "Strike a Villager with lightning", + "advancements.adventure.voluntary_exile.title": "Voluntary Exile", + "advancements.adventure.voluntary_exile.description": "Kill a raid captain.\nMaybe consider staying away from villages for the time being...", + "advancements.adventure.whos_the_pillager_now.title": "Who's the Pillager Now?", + "advancements.adventure.whos_the_pillager_now.description": "Give a Pillager a taste of their own medicine", + "advancements.husbandry.root.title": "Husbandry", + "advancements.husbandry.root.description": "The world is full of friends and food", + "advancements.husbandry.breed_an_animal.title": "The Parrots and the Bats", + "advancements.husbandry.breed_an_animal.description": "Breed two animals together", + "advancements.husbandry.fishy_business.title": "Fishy Business", + "advancements.husbandry.fishy_business.description": "Catch a fish", + "advancements.husbandry.make_a_sign_glow.title": "Glow and Behold!", + "advancements.husbandry.make_a_sign_glow.description": "Make the text of any kind of sign glow", + "advancements.husbandry.ride_a_boat_with_a_goat.title": "Whatever Floats Your Goat!", + "advancements.husbandry.ride_a_boat_with_a_goat.description": "Get in a Boat and float with a Goat", + "advancements.husbandry.tactical_fishing.title": "Tactical Fishing", + "advancements.husbandry.tactical_fishing.description": "Catch a Fish... without a Fishing Rod!", + "advancements.husbandry.axolotl_in_a_bucket.title": "The Cutest Predator", + "advancements.husbandry.axolotl_in_a_bucket.description": "Catch an Axolotl in a Bucket", + "advancements.husbandry.froglights.title": "With Our Powers Combined!", + "advancements.husbandry.froglights.description": "Have all Froglights in your inventory", + "advancements.husbandry.tadpole_in_a_bucket.title": "Bukkit Bukkit", + "advancements.husbandry.tadpole_in_a_bucket.description": "Catch a Tadpole in a Bucket", + "advancements.husbandry.leash_all_frog_variants.title": "When the Squad Hops into Town", + "advancements.husbandry.leash_all_frog_variants.description": "Get each Frog variant on a Lead", + "advancements.husbandry.kill_axolotl_target.title": "The Healing Power of Friendship!", + "advancements.husbandry.kill_axolotl_target.description": "Team up with an Axolotl and win a fight", + "advancements.husbandry.breed_all_animals.title": "Two by Two", + "advancements.husbandry.breed_all_animals.description": "Breed all the animals!", + "advancements.husbandry.tame_an_animal.title": "Best Friends Forever", + "advancements.husbandry.tame_an_animal.description": "Tame an animal", + "advancements.husbandry.plant_seed.title": "A Seedy Place", + "advancements.husbandry.plant_seed.description": "Plant a seed and watch it grow", + "advancements.husbandry.netherite_hoe.title": "Serious Dedication", + "advancements.husbandry.netherite_hoe.description": "Use a Netherite Ingot to upgrade a Hoe, and then reevaluate your life choices", + "advancements.husbandry.balanced_diet.title": "A Balanced Diet", + "advancements.husbandry.balanced_diet.description": "Eat everything that is edible, even if it's not good for you", + "advancements.husbandry.complete_catalogue.title": "A Complete Catalogue", + "advancements.husbandry.complete_catalogue.description": "Tame all Cat variants!", + "advancements.husbandry.safely_harvest_honey.title": "Bee Our Guest", + "advancements.husbandry.safely_harvest_honey.description": "Use a Campfire to collect Honey from a Beehive using a Bottle without aggravating the Bees", + "advancements.husbandry.silk_touch_nest.title": "Total Beelocation", + "advancements.husbandry.silk_touch_nest.description": "Move a Bee Nest, with 3 Bees inside, using Silk Touch", + "advancements.husbandry.wax_on.title": "Wax On", + "advancements.husbandry.wax_on.description": "Apply Honeycomb to a Copper block!", + "advancements.husbandry.wax_off.title": "Wax Off", + "advancements.husbandry.wax_off.description": "Scrape Wax off of a Copper block!", + "advancements.husbandry.allay_deliver_item_to_player.title": "You've Got a Friend in Me", + "advancements.husbandry.allay_deliver_item_to_player.description": "Have an Allay deliver items to you", + "advancements.husbandry.allay_deliver_cake_to_note_block.title": "Birthday Song", + "advancements.husbandry.allay_deliver_cake_to_note_block.description": "Have an Allay drop a Cake at a Note Block", + "advancements.end.dragon_breath.title": "You Need a Mint", + "advancements.end.dragon_breath.description": "Collect Dragon's Breath in a Glass Bottle", + "advancements.end.dragon_egg.title": "The Next Generation", + "advancements.end.dragon_egg.description": "Hold the Dragon Egg", + "advancements.end.elytra.title": "Sky's the Limit", + "advancements.end.elytra.description": "Find Elytra", + "advancements.end.enter_end_gateway.title": "Remote Getaway", + "advancements.end.enter_end_gateway.description": "Escape the island", + "advancements.end.find_end_city.title": "The City at the End of the Game", + "advancements.end.find_end_city.description": "Go on in, what could happen?", + "advancements.end.kill_dragon.title": "Free the End", + "advancements.end.kill_dragon.description": "Good luck", + "advancements.end.levitate.title": "Great View From Up Here", + "advancements.end.levitate.description": "Levitate up 50 blocks from the attacks of a Shulker", + "advancements.end.respawn_dragon.title": "The End... Again...", + "advancements.end.respawn_dragon.description": "Respawn the Ender Dragon", + "advancements.end.root.title": "The End", + "advancements.end.root.description": "Or the beginning?", + "advancements.nether.brew_potion.title": "Local Brewery", + "advancements.nether.brew_potion.description": "Brew a Potion", + "advancements.nether.all_potions.title": "A Furious Cocktail", + "advancements.nether.all_potions.description": "Have every potion effect applied at the same time", + "advancements.nether.all_effects.title": "How Did We Get Here?", + "advancements.nether.all_effects.description": "Have every effect applied at the same time", + "advancements.nether.create_beacon.title": "Bring Home the Beacon", + "advancements.nether.create_beacon.description": "Construct and place a Beacon", + "advancements.nether.create_full_beacon.title": "Beaconator", + "advancements.nether.create_full_beacon.description": "Bring a Beacon to full power", + "advancements.nether.find_fortress.title": "A Terrible Fortress", + "advancements.nether.find_fortress.description": "Break your way into a Nether Fortress", + "advancements.nether.get_wither_skull.title": "Spooky Scary Skeleton", + "advancements.nether.get_wither_skull.description": "Obtain a Wither Skeleton's skull", + "advancements.nether.obtain_blaze_rod.title": "Into Fire", + "advancements.nether.obtain_blaze_rod.description": "Relieve a Blaze of its rod", + "advancements.nether.return_to_sender.title": "Return to Sender", + "advancements.nether.return_to_sender.description": "Destroy a Ghast with a fireball", + "advancements.nether.root.title": "Nether", + "advancements.nether.root.description": "Bring summer clothes", + "advancements.nether.summon_wither.title": "Withering Heights", + "advancements.nether.summon_wither.description": "Summon the Wither", + "advancements.nether.fast_travel.title": "Subspace Bubble", + "advancements.nether.fast_travel.description": "Use the Nether to travel 7 km in the Overworld", + "advancements.nether.uneasy_alliance.title": "Uneasy Alliance", + "advancements.nether.uneasy_alliance.description": "Rescue a Ghast from the Nether, bring it safely home to the Overworld... and then kill it", + "advancements.nether.obtain_ancient_debris.title": "Hidden in the Depths", + "advancements.nether.obtain_ancient_debris.description": "Obtain Ancient Debris", + "advancements.nether.netherite_armor.title": "Cover Me in Debris", + "advancements.nether.netherite_armor.description": "Get a full suit of Netherite armor", + "advancements.nether.use_lodestone.title": "Country Lode, Take Me Home", + "advancements.nether.use_lodestone.description": "Use a Compass on a Lodestone", + "advancements.nether.obtain_crying_obsidian.title": "Who is Cutting Onions?", + "advancements.nether.obtain_crying_obsidian.description": "Obtain Crying Obsidian", + "advancements.nether.charge_respawn_anchor.title": "Not Quite \"Nine\" Lives", + "advancements.nether.charge_respawn_anchor.description": "Charge a Respawn Anchor to the maximum", + "advancements.nether.ride_strider.title": "This Boat Has Legs", + "advancements.nether.ride_strider.description": "Ride a Strider with a Warped Fungus on a Stick", + "advancements.nether.ride_strider_in_overworld_lava.title": "Feels Like Home", + "advancements.nether.ride_strider_in_overworld_lava.description": "Take a Strider for a loooong ride on a lava lake in the Overworld", + "advancements.nether.explore_nether.title": "Hot Tourist Destinations", + "advancements.nether.explore_nether.description": "Explore all Nether biomes", + "advancements.nether.find_bastion.title": "Those Were the Days", + "advancements.nether.find_bastion.description": "Enter a Bastion Remnant", + "advancements.nether.loot_bastion.title": "War Pigs", + "advancements.nether.loot_bastion.description": "Loot a Chest in a Bastion Remnant", + "advancements.nether.distract_piglin.title": "Oh Shiny", + "advancements.nether.distract_piglin.description": "Distract Piglins with gold", + "advancements.story.cure_zombie_villager.title": "Zombie Doctor", + "advancements.story.cure_zombie_villager.description": "Weaken and then cure a Zombie Villager", + "advancements.story.deflect_arrow.title": "Not Today, Thank You", + "advancements.story.deflect_arrow.description": "Deflect a projectile with a Shield", + "advancements.story.enchant_item.title": "Enchanter", + "advancements.story.enchant_item.description": "Enchant an item at an Enchanting Table", + "advancements.story.enter_the_end.title": "The End?", + "advancements.story.enter_the_end.description": "Enter the End Portal", + "advancements.story.enter_the_nether.title": "We Need to Go Deeper", + "advancements.story.enter_the_nether.description": "Build, light and enter a Nether Portal", + "advancements.story.follow_ender_eye.title": "Eye Spy", + "advancements.story.follow_ender_eye.description": "Follow an Eye of Ender", + "advancements.story.form_obsidian.title": "Ice Bucket Challenge", + "advancements.story.form_obsidian.description": "Obtain a block of Obsidian", + "advancements.story.iron_tools.title": "Isn't It Iron Pick", + "advancements.story.iron_tools.description": "Upgrade your Pickaxe", + "advancements.story.lava_bucket.title": "Hot Stuff", + "advancements.story.lava_bucket.description": "Fill a Bucket with lava", + "advancements.story.mine_diamond.title": "Diamonds!", + "advancements.story.mine_diamond.description": "Acquire diamonds", + "advancements.story.mine_stone.title": "Stone Age", + "advancements.story.mine_stone.description": "Mine Stone with your new Pickaxe", + "advancements.story.obtain_armor.title": "Suit Up", + "advancements.story.obtain_armor.description": "Protect yourself with a piece of iron armor", + "advancements.story.root.title": "Minecraft", + "advancements.story.root.description": "The heart and story of the game", + "advancements.story.shiny_gear.title": "Cover Me with Diamonds", + "advancements.story.shiny_gear.description": "Diamond armor saves lives", + "advancements.story.smelt_iron.title": "Acquire Hardware", + "advancements.story.smelt_iron.description": "Smelt an Iron Ingot", + "advancements.story.upgrade_tools.title": "Getting an Upgrade", + "advancements.story.upgrade_tools.description": "Construct a better Pickaxe", + "team.visibility.always": "Always", + "team.visibility.never": "Never", + "team.visibility.hideForOtherTeams": "Hide for other teams", + "team.visibility.hideForOwnTeam": "Hide for own team", + "team.collision.always": "Always", + "team.collision.never": "Never", + "team.collision.pushOtherTeams": "Push other teams", + "team.collision.pushOwnTeam": "Push own team", + "argument.uuid.invalid": "Invalid UUID", + "argument.entity.selector.nearestPlayer": "Nearest player", + "argument.entity.selector.randomPlayer": "Random player", + "argument.entity.selector.allPlayers": "All players", + "argument.entity.selector.allEntities": "All entities", + "argument.entity.selector.self": "Current entity", + "argument.entity.options.name.description": "Entity name", + "argument.entity.options.distance.description": "Distance to entity", + "argument.entity.options.level.description": "Experience level", + "argument.entity.options.x.description": "x position", + "argument.entity.options.y.description": "y position", + "argument.entity.options.z.description": "z position", + "argument.entity.options.dx.description": "Entities between x and x + dx", + "argument.entity.options.dy.description": "Entities between y and y + dy", + "argument.entity.options.dz.description": "Entities between z and z + dz", + "argument.entity.options.x_rotation.description": "Entity's x rotation", + "argument.entity.options.y_rotation.description": "Entity's y rotation", + "argument.entity.options.limit.description": "Maximum number of entities to return", + "argument.entity.options.sort.description": "Sort the entities", + "argument.entity.options.gamemode.description": "Players with gamemode", + "argument.entity.options.team.description": "Entities on team", + "argument.entity.options.type.description": "Entities of type", + "argument.entity.options.tag.description": "Entities with tag", + "argument.entity.options.nbt.description": "Entities with NBT", + "argument.entity.options.scores.description": "Entities with scores", + "argument.entity.options.advancements.description": "Players with advancements", + "argument.entity.options.predicate.description": "Custom predicate", + "argument.resource.not_found": "Can't find element '%s' of type '%s'", + "argument.resource.invalid_type": "Element '%s' has wrong type '%s' (expected '%s')", + "argument.resource_tag.not_found": "Can't find tag '%s' of type '%s'", + "argument.resource_tag.invalid_type": "Tag '%s' has wrong type '%s' (expected '%s')", + "command.failed": "An unexpected error occurred trying to execute that command", + "command.context.here": "<--[HERE]", + "command.context.parse_error": "%s at position %s: %s", + "commands.publish.started": "Local game hosted on port %s", + "commands.publish.failed": "Unable to host local game", + "commands.advancement.advancementNotFound": "No advancement was found by the name '%1$s'", + "commands.advancement.criterionNotFound": "The advancement %1$s does not contain the criterion '%2$s'", + "commands.advancement.grant.one.to.one.success": "Granted the advancement %s to %s", + "commands.advancement.grant.one.to.one.failure": "Couldn't grant advancement %s to %s as they already have it", + "commands.advancement.grant.one.to.many.success": "Granted the advancement %s to %s players", + "commands.advancement.grant.one.to.many.failure": "Couldn't grant advancement %s to %s players as they already have it", + "commands.advancement.grant.many.to.one.success": "Granted %s advancements to %s", + "commands.advancement.grant.many.to.one.failure": "Couldn't grant %s advancements to %s as they already have them", + "commands.advancement.grant.many.to.many.success": "Granted %s advancements to %s players", + "commands.advancement.grant.many.to.many.failure": "Couldn't grant %s advancements to %s players as they already have them", + "commands.advancement.grant.criterion.to.one.success": "Granted criterion '%s' of advancement %s to %s", + "commands.advancement.grant.criterion.to.one.failure": "Couldn't grant criterion '%s' of advancement %s to %s as they already have it", + "commands.advancement.grant.criterion.to.many.success": "Granted criterion '%s' of advancement %s to %s players", + "commands.advancement.grant.criterion.to.many.failure": "Couldn't grant criterion '%s' of advancement %s to %s players as they already have it", + "commands.advancement.revoke.one.to.one.success": "Revoked the advancement %s from %s", + "commands.advancement.revoke.one.to.one.failure": "Couldn't revoke advancement %s from %s as they don't have it", + "commands.advancement.revoke.one.to.many.success": "Revoked the advancement %s from %s players", + "commands.advancement.revoke.one.to.many.failure": "Couldn't revoke advancement %s from %s players as they don't have it", + "commands.advancement.revoke.many.to.one.success": "Revoked %s advancements from %s", + "commands.advancement.revoke.many.to.one.failure": "Couldn't revoke %s advancements from %s as they don't have them", + "commands.advancement.revoke.many.to.many.success": "Revoked %s advancements from %s players", + "commands.advancement.revoke.many.to.many.failure": "Couldn't revoke %s advancements from %s players as they don't have them", + "commands.advancement.revoke.criterion.to.one.success": "Revoked criterion '%s' of advancement %s from %s", + "commands.advancement.revoke.criterion.to.one.failure": "Couldn't revoke criterion '%s' of advancement %s from %s as they don't have it", + "commands.advancement.revoke.criterion.to.many.success": "Revoked criterion '%s' of advancement %s from %s players", + "commands.advancement.revoke.criterion.to.many.failure": "Couldn't revoke criterion '%s' of advancement %s from %s players as they don't have it", + "commands.attribute.failed.entity": "%s is not a valid entity for this command", + "commands.attribute.failed.no_attribute": "Entity %s has no attribute %s", + "commands.attribute.failed.no_modifier": "Attribute %s for entity %s has no modifier %s", + "commands.attribute.failed.modifier_already_present": "Modifier %s is already present on attribute %s for entity %s", + "commands.attribute.value.get.success": "Value of attribute %s for entity %s is %s", + "commands.attribute.base_value.get.success": "Base value of attribute %s for entity %s is %s", + "commands.attribute.base_value.set.success": "Base value for attribute %s for entity %s set to %s", + "commands.attribute.modifier.add.success": "Added modifier %s to attribute %s for entity %s", + "commands.attribute.modifier.remove.success": "Removed modifier %s from attribute %s for entity %s", + "commands.attribute.modifier.value.get.success": "Value of modifier %s on attribute %s for entity %s is %s", + "commands.forceload.added.failure": "No chunks were marked for force loading", + "commands.forceload.added.single": "Marked chunk %s in %s to be force loaded", + "commands.forceload.added.multiple": "Marked %s chunks in %s from %s to %s to be force loaded", + "commands.forceload.query.success": "Chunk at %s in %s is marked for force loading", + "commands.forceload.query.failure": "Chunk at %s in %s is not marked for force loading", + "commands.forceload.list.single": "A force loaded chunk was found in %s at: %s", + "commands.forceload.list.multiple": "%s force loaded chunks were found in %s at: %s", + "commands.forceload.added.none": "No force loaded chunks were found in %s", + "commands.forceload.removed.all": "Unmarked all force loaded chunks in %s", + "commands.forceload.removed.failure": "No chunks were removed from force loading", + "commands.forceload.removed.single": "Unmarked chunk %s in %s for force loading", + "commands.forceload.removed.multiple": "Unmarked %s chunks in %s from %s to %s for force loading", + "commands.forceload.toobig": "Too many chunks in the specified area (maximum %s, specified %s)", + "commands.clear.success.single": "Removed %s items from player %s", + "commands.clear.success.multiple": "Removed %s items from %s players", + "commands.clear.test.single": "Found %s matching items on player %s", + "commands.clear.test.multiple": "Found %s matching items on %s players", + "commands.clone.success": "Successfully cloned %s blocks", + "commands.debug.started": "Started tick profiling", + "commands.debug.stopped": "Stopped tick profiling after %s seconds and %s ticks (%s ticks per second)", + "commands.debug.notRunning": "The tick profiler hasn't started", + "commands.debug.alreadyRunning": "The tick profiler is already started", + "commands.debug.function.success.single": "Traced %s commands from function '%s' to output file %s", + "commands.debug.function.success.multiple": "Traced %s commands from %s functions to output file %s", + "commands.debug.function.noRecursion": "Can't trace from inside of function", + "commands.debug.function.traceFailed": "Failed to trace function", + "commands.defaultgamemode.success": "The default game mode is now %s", + "commands.difficulty.success": "The difficulty has been set to %s", + "commands.difficulty.query": "The difficulty is %s", + "commands.drop.no_held_items": "Entity can't hold any items", + "commands.drop.no_loot_table": "Entity %s has no loot table", + "commands.drop.success.single": "Dropped %s %s", + "commands.drop.success.single_with_table": "Dropped %s %s from loot table %s", + "commands.drop.success.multiple": "Dropped %s items", + "commands.drop.success.multiple_with_table": "Dropped %s items from loot table %s", + "commands.effect.give.success.single": "Applied effect %s to %s", + "commands.effect.give.success.multiple": "Applied effect %s to %s targets", + "commands.effect.clear.everything.success.single": "Removed every effect from %s", + "commands.effect.clear.everything.success.multiple": "Removed every effect from %s targets", + "commands.effect.clear.specific.success.single": "Removed effect %s from %s", + "commands.effect.clear.specific.success.multiple": "Removed effect %s from %s targets", + "commands.enchant.success.single": "Applied enchantment %s to %s's item", + "commands.enchant.success.multiple": "Applied enchantment %s to %s entities", + "commands.experience.add.points.success.single": "Gave %s experience points to %s", + "commands.experience.add.points.success.multiple": "Gave %s experience points to %s players", + "commands.experience.add.levels.success.single": "Gave %s experience levels to %s", + "commands.experience.add.levels.success.multiple": "Gave %s experience levels to %s players", + "commands.experience.set.points.success.single": "Set %s experience points on %s", + "commands.experience.set.points.success.multiple": "Set %s experience points on %s players", + "commands.experience.set.levels.success.single": "Set %s experience levels on %s", + "commands.experience.set.levels.success.multiple": "Set %s experience levels on %s players", + "commands.experience.query.points": "%s has %s experience points", + "commands.experience.query.levels": "%s has %s experience levels", + "commands.fill.success": "Successfully filled %s blocks", + "commands.function.success.single": "Executed %s commands from function '%s'", + "commands.function.success.multiple": "Executed %s commands from %s functions", + "commands.give.failed.toomanyitems": "Can't give more than %s of %s", + "commands.give.success.single": "Gave %s %s to %s", + "commands.give.success.multiple": "Gave %s %s to %s players", + "commands.playsound.success.single": "Played sound %s to %s", + "commands.playsound.success.multiple": "Played sound %s to %s players", + "commands.publish.success": "Multiplayer game is now hosted on port %s", + "commands.list.players": "There are %s of a max of %s players online: %s", + "commands.list.nameAndId": "%s (%s)", + "commands.kill.success.single": "Killed %s", + "commands.kill.success.multiple": "Killed %s entities", + "commands.kick.success": "Kicked %s: %s", + "commands.message.display.outgoing": "You whisper to %s: %s", + "commands.message.display.incoming": "%s whispers to you: %s", + "commands.op.success": "Made %s a server operator", + "commands.deop.success": "Made %s no longer a server operator", + "commands.ban.success": "Banned %s: %s", + "commands.pardon.success": "Unbanned %s", + "commands.particle.success": "Displaying particle %s", + "commands.perf.started": "Started 10 second performance profiling run (use '/perf stop' to stop early)", + "commands.perf.stopped": "Stopped performance profiling after %s seconds and %s ticks (%s ticks per second)", + "commands.perf.reportSaved": "Created debug report in %s", + "commands.perf.reportFailed": "Failed to create debug report", + "commands.perf.notRunning": "The performance profiler hasn't started", + "commands.perf.alreadyRunning": "The performance profiler is already started", + "commands.jfr.started": "JFR profiling started", + "commands.jfr.start.failed": "Failed to start JFR profiling", + "commands.jfr.stopped": "JFR profiling stopped and dumped to %s", + "commands.jfr.dump.failed": "Failed to dump JFR recording: %s", + "commands.seed.success": "Seed: %s", + "commands.stop.stopping": "Stopping the server", + "commands.time.query": "The time is %s", + "commands.time.set": "Set the time to %s", + "commands.schedule.created.function": "Scheduled function '%s' in %s ticks at gametime %s", + "commands.schedule.created.tag": "Scheduled tag '%s' in %s ticks at gametime %s", + "commands.schedule.cleared.success": "Removed %s schedules with id %s", + "commands.schedule.cleared.failure": "No schedules with id %s", + "commands.schedule.same_tick": "Can't schedule for current tick", + "commands.gamemode.success.self": "Set own game mode to %s", + "commands.gamemode.success.other": "Set %s's game mode to %s", + "commands.gamerule.query": "Gamerule %s is currently set to: %s", + "commands.gamerule.set": "Gamerule %s is now set to: %s", + "commands.save.disabled": "Automatic saving is now disabled", + "commands.save.enabled": "Automatic saving is now enabled", + "commands.save.saving": "Saving the game (this may take a moment!)", + "commands.save.success": "Saved the game", + "commands.setidletimeout.success": "The player idle timeout is now %s minutes", + "commands.banlist.none": "There are no bans", + "commands.banlist.list": "There are %s bans:", + "commands.banlist.entry": "%s was banned by %s: %s", + "commands.bossbar.create.success": "Created custom bossbar %s", + "commands.bossbar.remove.success": "Removed custom bossbar %s", + "commands.bossbar.list.bars.none": "There are no custom bossbars active", + "commands.bossbar.list.bars.some": "There are %s custom bossbars active: %s", + "commands.bossbar.set.players.success.none": "Custom bossbar %s no longer has any players", + "commands.bossbar.set.players.success.some": "Custom bossbar %s now has %s players: %s", + "commands.bossbar.set.name.success": "Custom bossbar %s has been renamed", + "commands.bossbar.set.color.success": "Custom bossbar %s has changed color", + "commands.bossbar.set.style.success": "Custom bossbar %s has changed style", + "commands.bossbar.set.value.success": "Custom bossbar %s has changed value to %s", + "commands.bossbar.set.max.success": "Custom bossbar %s has changed maximum to %s", + "commands.bossbar.set.visible.success.visible": "Custom bossbar %s is now visible", + "commands.bossbar.set.visible.success.hidden": "Custom bossbar %s is now hidden", + "commands.bossbar.get.value": "Custom bossbar %s has a value of %s", + "commands.bossbar.get.max": "Custom bossbar %s has a maximum of %s", + "commands.bossbar.get.visible.visible": "Custom bossbar %s is currently shown", + "commands.bossbar.get.visible.hidden": "Custom bossbar %s is currently hidden", + "commands.bossbar.get.players.none": "Custom bossbar %s has no players currently online", + "commands.bossbar.get.players.some": "Custom bossbar %s has %s players currently online: %s", + "commands.recipe.give.success.single": "Unlocked %s recipes for %s", + "commands.recipe.give.success.multiple": "Unlocked %s recipes for %s players", + "commands.recipe.take.success.single": "Took %s recipes from %s", + "commands.recipe.take.success.multiple": "Took %s recipes from %s players", + "commands.summon.success": "Summoned new %s", + "commands.whitelist.enabled": "Whitelist is now turned on", + "commands.whitelist.disabled": "Whitelist is now turned off", + "commands.whitelist.none": "There are no whitelisted players", + "commands.whitelist.list": "There are %s whitelisted players: %s", + "commands.whitelist.add.success": "Added %s to the whitelist", + "commands.whitelist.remove.success": "Removed %s from the whitelist", + "commands.whitelist.reloaded": "Reloaded the whitelist", + "commands.weather.set.clear": "Set the weather to clear", + "commands.weather.set.rain": "Set the weather to rain", + "commands.weather.set.thunder": "Set the weather to rain & thunder", + "commands.spawnpoint.success.single": "Set spawn point to %s, %s, %s [%s] in %s for %s", + "commands.spawnpoint.success.multiple": "Set spawn point to %s, %s, %s [%s] in %s for %s players", + "commands.stopsound.success.source.sound": "Stopped sound '%s' on source '%s'", + "commands.stopsound.success.source.any": "Stopped all '%s' sounds", + "commands.stopsound.success.sourceless.sound": "Stopped sound '%s'", + "commands.stopsound.success.sourceless.any": "Stopped all sounds", + "commands.setworldspawn.success": "Set the world spawn point to %s, %s, %s [%s]", + "commands.spreadplayers.success.teams": "Spread %s teams around %s, %s with an average distance of %s blocks apart", + "commands.spreadplayers.success.entities": "Spread %s players around %s, %s with an average distance of %s blocks apart", + "commands.setblock.success": "Changed the block at %s, %s, %s", + "commands.banip.success": "Banned IP %s: %s", + "commands.banip.info": "This ban affects %s players: %s", + "commands.pardonip.success": "Unbanned IP %s", + "commands.teleport.success.entity.single": "Teleported %s to %s", + "commands.teleport.success.entity.multiple": "Teleported %s entities to %s", + "commands.teleport.success.location.single": "Teleported %s to %s, %s, %s", + "commands.teleport.success.location.multiple": "Teleported %s entities to %s, %s, %s", + "commands.teleport.invalidPosition": "Invalid position for teleport", + "commands.title.cleared.single": "Cleared titles for %s", + "commands.title.cleared.multiple": "Cleared titles for %s players", + "commands.title.reset.single": "Reset title options for %s", + "commands.title.reset.multiple": "Reset title options for %s players", + "commands.title.show.title.single": "Showing new title for %s", + "commands.title.show.title.multiple": "Showing new title for %s players", + "commands.title.show.subtitle.single": "Showing new subtitle for %s", + "commands.title.show.subtitle.multiple": "Showing new subtitle for %s players", + "commands.title.show.actionbar.single": "Showing new actionbar title for %s", + "commands.title.show.actionbar.multiple": "Showing new actionbar title for %s players", + "commands.title.times.single": "Changed title display times for %s", + "commands.title.times.multiple": "Changed title display times for %s players", + "commands.worldborder.set.grow": "Growing the world border to %s blocks wide over %s seconds", + "commands.worldborder.set.shrink": "Shrinking the world border to %s blocks wide over %s seconds", + "commands.worldborder.set.immediate": "Set the world border to %s blocks wide", + "commands.worldborder.center.success": "Set the center of the world border to %s, %s", + "commands.worldborder.get": "The world border is currently %s blocks wide", + "commands.worldborder.damage.buffer.success": "Set the world border damage buffer to %s blocks", + "commands.worldborder.damage.amount.success": "Set the world border damage to %s per block each second", + "commands.worldborder.warning.time.success": "Set the world border warning time to %s seconds", + "commands.worldborder.warning.distance.success": "Set the world border warning distance to %s blocks", + "commands.tag.add.success.single": "Added tag '%s' to %s", + "commands.tag.add.success.multiple": "Added tag '%s' to %s entities", + "commands.tag.remove.success.single": "Removed tag '%s' from %s", + "commands.tag.remove.success.multiple": "Removed tag '%s' from %s entities", + "commands.tag.list.single.empty": "%s has no tags", + "commands.tag.list.single.success": "%s has %s tags: %s", + "commands.tag.list.multiple.empty": "There are no tags on the %s entities", + "commands.tag.list.multiple.success": "The %s entities have %s total tags: %s", + "commands.team.list.members.empty": "There are no members on team %s", + "commands.team.list.members.success": "Team %s has %s members: %s", + "commands.team.list.teams.empty": "There are no teams", + "commands.team.list.teams.success": "There are %s teams: %s", + "commands.team.add.success": "Created team %s", + "commands.team.remove.success": "Removed team %s", + "commands.team.empty.success": "Removed %s members from team %s", + "commands.team.option.color.success": "Updated the color for team %s to %s", + "commands.team.option.name.success": "Updated the name of team %s", + "commands.team.option.friendlyfire.enabled": "Enabled friendly fire for team %s", + "commands.team.option.friendlyfire.disabled": "Disabled friendly fire for team %s", + "commands.team.option.seeFriendlyInvisibles.enabled": "Team %s can now see invisible teammates", + "commands.team.option.seeFriendlyInvisibles.disabled": "Team %s can no longer see invisible teammates", + "commands.team.option.nametagVisibility.success": "Nametag visibility for team %s is now \"%s\"", + "commands.team.option.deathMessageVisibility.success": "Death message visibility for team %s is now \"%s\"", + "commands.team.option.collisionRule.success": "Collision rule for team %s is now \"%s\"", + "commands.team.option.prefix.success": "Team prefix set to %s", + "commands.team.option.suffix.success": "Team suffix set to %s", + "commands.team.join.success.single": "Added %s to team %s", + "commands.team.join.success.multiple": "Added %s members to team %s", + "commands.team.leave.success.single": "Removed %s from any team", + "commands.team.leave.success.multiple": "Removed %s members from any team", + "commands.trigger.simple.success": "Triggered %s", + "commands.trigger.add.success": "Triggered %s (added %s to value)", + "commands.trigger.set.success": "Triggered %s (set value to %s)", + "commands.scoreboard.objectives.list.empty": "There are no objectives", + "commands.scoreboard.objectives.list.success": "There are %s objectives: %s", + "commands.scoreboard.objectives.add.success": "Created new objective %s", + "commands.scoreboard.objectives.remove.success": "Removed objective %s", + "commands.scoreboard.objectives.display.cleared": "Cleared any objectives in display slot %s", + "commands.scoreboard.objectives.display.set": "Set display slot %s to show objective %s", + "commands.scoreboard.objectives.modify.displayname": "Changed the display name of %s to %s", + "commands.scoreboard.objectives.modify.rendertype": "Changed the render type of objective %s", + "commands.scoreboard.players.list.empty": "There are no tracked entities", + "commands.scoreboard.players.list.success": "There are %s tracked entities: %s", + "commands.scoreboard.players.list.entity.empty": "%s has no scores to show", + "commands.scoreboard.players.list.entity.success": "%s has %s scores:", + "commands.scoreboard.players.list.entity.entry": "%s: %s", + "commands.scoreboard.players.set.success.single": "Set %s for %s to %s", + "commands.scoreboard.players.set.success.multiple": "Set %s for %s entities to %s", + "commands.scoreboard.players.add.success.single": "Added %s to %s for %s (now %s)", + "commands.scoreboard.players.add.success.multiple": "Added %s to %s for %s entities", + "commands.scoreboard.players.remove.success.single": "Removed %s from %s for %s (now %s)", + "commands.scoreboard.players.remove.success.multiple": "Removed %s from %s for %s entities", + "commands.scoreboard.players.reset.all.single": "Reset all scores for %s", + "commands.scoreboard.players.reset.all.multiple": "Reset all scores for %s entities", + "commands.scoreboard.players.reset.specific.single": "Reset %s for %s", + "commands.scoreboard.players.reset.specific.multiple": "Reset %s for %s entities", + "commands.scoreboard.players.enable.success.single": "Enabled trigger %s for %s", + "commands.scoreboard.players.enable.success.multiple": "Enabled trigger %s for %s entities", + "commands.scoreboard.players.operation.success.single": "Set %s for %s to %s", + "commands.scoreboard.players.operation.success.multiple": "Updated %s for %s entities", + "commands.scoreboard.players.get.success": "%s has %s %s", + "commands.reload.success": "Reloading!", + "commands.reload.failure": "Reload failed; keeping old data", + "commands.data.entity.modified": "Modified entity data of %s", + "commands.data.entity.query": "%s has the following entity data: %s", + "commands.data.entity.get": "%s on %s after scale factor of %s is %s", + "commands.data.block.modified": "Modified block data of %s, %s, %s", + "commands.data.block.query": "%s, %s, %s has the following block data: %s", + "commands.data.block.get": "%s on block %s, %s, %s after scale factor of %s is %s", + "commands.data.storage.modified": "Modified storage %s", + "commands.data.storage.query": "Storage %s has the following contents: %s", + "commands.data.storage.get": "%s in storage %s after scale factor of %s is %s", + "commands.datapack.list.enabled.success": "There are %s data packs enabled: %s", + "commands.datapack.list.enabled.none": "There are no data packs enabled", + "commands.datapack.list.available.success": "There are %s data packs available: %s", + "commands.datapack.list.available.none": "There are no more data packs available", + "commands.datapack.modify.enable": "Enabling data pack %s", + "commands.datapack.modify.disable": "Disabling data pack %s", + "commands.spectate.success.stopped": "No longer spectating an entity", + "commands.spectate.success.started": "Now spectating %s", + "commands.spectate.not_spectator": "%s is not in spectator mode", + "commands.spectate.self": "Cannot spectate yourself", + "commands.item.target.not_a_container": "Target position %s, %s, %s is not a container", + "commands.item.source.not_a_container": "Source position %s, %s, %s is not a container", + "commands.item.target.no_such_slot": "The target does not have slot %s", + "commands.item.source.no_such_slot": "The source does not have slot %s", + "commands.item.target.no_changes": "No targets accepted item into slot %s", + "commands.item.target.no_changed.known_item": "No targets accepted item %s into slot %s", + "commands.item.block.set.success": "Replaced a slot at %s, %s, %s with %s", + "commands.item.entity.set.success.single": "Replaced a slot on %s with %s", + "commands.item.entity.set.success.multiple": "Replaced a slot on %s entities with %s", + "argument.range.empty": "Expected value or range of values", + "argument.range.ints": "Only whole numbers allowed, not decimals", + "argument.range.swapped": "Min cannot be bigger than max", + "permissions.requires.player": "A player is required to run this command here", + "permissions.requires.entity": "An entity is required to run this command here", + "argument.angle.incomplete": "Incomplete (expected 1 angle)", + "argument.angle.invalid": "Invalid angle", + "argument.entity.toomany": "Only one entity is allowed, but the provided selector allows more than one", + "argument.player.toomany": "Only one player is allowed, but the provided selector allows more than one", + "argument.player.entities": "Only players may be affected by this command, but the provided selector includes entities", + "argument.entity.notfound.entity": "No entity was found", + "argument.entity.notfound.player": "No player was found", + "argument.player.unknown": "That player does not exist", + "arguments.nbtpath.node.invalid": "Invalid NBT path element", + "arguments.nbtpath.too_deep": "Resulting NBT too deeply nested", + "arguments.nbtpath.too_large": "Resulting NBT too large", + "arguments.nbtpath.nothing_found": "Found no elements matching %s", + "arguments.operation.invalid": "Invalid operation", + "arguments.operation.div0": "Cannot divide by zero", + "argument.scoreHolder.empty": "No relevant score holders could be found", + "argument.block.tag.disallowed": "Tags aren't allowed here, only actual blocks", + "argument.block.property.unclosed": "Expected closing ] for block state properties", + "argument.pos.unloaded": "That position is not loaded", + "argument.pos.outofworld": "That position is out of this world!", + "argument.pos.outofbounds": "That position is outside the allowed boundaries.", + "argument.rotation.incomplete": "Incomplete (expected 2 coordinates)", + "arguments.swizzle.invalid": "Invalid swizzle, expected combination of 'x', 'y' and 'z'", + "argument.pos2d.incomplete": "Incomplete (expected 2 coordinates)", + "argument.pos3d.incomplete": "Incomplete (expected 3 coordinates)", + "argument.pos.mixed": "Cannot mix world & local coordinates (everything must either use ^ or not)", + "argument.pos.missing.double": "Expected a coordinate", + "argument.pos.missing.int": "Expected a block position", + "argument.item.tag.disallowed": "Tags aren't allowed here, only actual items", + "argument.entity.invalid": "Invalid name or UUID", + "argument.entity.selector.missing": "Missing selector type", + "argument.entity.selector.not_allowed": "Selector not allowed", + "argument.entity.options.unterminated": "Expected end of options", + "argument.entity.options.distance.negative": "Distance cannot be negative", + "argument.entity.options.level.negative": "Level shouldn't be negative", + "argument.entity.options.limit.toosmall": "Limit must be at least 1", + "argument.nbt.trailing": "Unexpected trailing data", + "argument.nbt.expected.key": "Expected key", + "argument.nbt.expected.value": "Expected value", + "argument.id.invalid": "Invalid ID", + "argument.time.invalid_unit": "Invalid unit", + "argument.time.invalid_tick_count": "Tick count must be non-negative", + "argument.enum.invalid": "Invalid value \"%s\"", + "commands.banip.invalid": "Invalid IP address or unknown player", + "commands.banip.failed": "Nothing changed. That IP is already banned", + "commands.ban.failed": "Nothing changed. The player is already banned", + "commands.bossbar.set.players.unchanged": "Nothing changed. Those players are already on the bossbar with nobody to add or remove", + "commands.bossbar.set.name.unchanged": "Nothing changed. That's already the name of this bossbar", + "commands.bossbar.set.color.unchanged": "Nothing changed. That's already the color of this bossbar", + "commands.bossbar.set.style.unchanged": "Nothing changed. That's already the style of this bossbar", + "commands.bossbar.set.value.unchanged": "Nothing changed. That's already the value of this bossbar", + "commands.bossbar.set.max.unchanged": "Nothing changed. That's already the max of this bossbar", + "commands.bossbar.set.visibility.unchanged.hidden": "Nothing changed. The bossbar is already hidden", + "commands.bossbar.set.visibility.unchanged.visible": "Nothing changed. The bossbar is already visible", + "commands.clone.overlap": "The source and destination areas cannot overlap", + "commands.clone.failed": "No blocks were cloned", + "commands.deop.failed": "Nothing changed. The player is not an operator", + "commands.effect.give.failed": "Unable to apply this effect (target is either immune to effects, or has something stronger)", + "commands.effect.clear.everything.failed": "Target has no effects to remove", + "commands.effect.clear.specific.failed": "Target doesn't have the requested effect", + "commands.enchant.failed": "Nothing changed. Targets either have no item in their hands or the enchantment could not be applied", + "commands.experience.set.points.invalid": "Cannot set experience points above the maximum points for the player's current level", + "commands.fill.failed": "No blocks were filled", + "argument.gamemode.invalid": "Unknown gamemode: %s", + "commands.help.failed": "Unknown command or insufficient permissions", + "commands.locate.structure.success": "The nearest %s is at %s (%s blocks away)", + "commands.locate.structure.not_found": "Could not find a structure of type \"%s\" nearby", + "commands.locate.structure.invalid": "There is no structure with type \"%s\"", + "commands.locate.biome.success": "The nearest %s is at %s (%s blocks away)", + "commands.locate.biome.not_found": "Could not find a biome of type \"%s\" within reasonable distance", + "commands.locate.poi.success": "The nearest %s is at %s (%s blocks away)", + "commands.locate.poi.not_found": "Could not find a point of interest of type \"%s\" within reasonable distance", + "commands.op.failed": "Nothing changed. The player already is an operator", + "commands.pardon.failed": "Nothing changed. The player isn't banned", + "commands.pardonip.invalid": "Invalid IP address", + "commands.pardonip.failed": "Nothing changed. That IP isn't banned", + "commands.particle.failed": "The particle was not visible for anybody", + "commands.place.feature.failed": "Failed to place feature", + "commands.place.feature.invalid": "There is no feature with type \"%s\"", + "commands.place.feature.success": "Placed \"%s\" at %s, %s, %s", + "commands.place.jigsaw.failed": "Failed to generate jigsaw", + "commands.place.jigsaw.invalid": "There is no template pool with type \"%s\"", + "commands.place.jigsaw.success": "Generated jigsaw at %s, %s, %s", + "commands.place.structure.failed": "Failed to place structure", + "commands.place.structure.invalid": "There is no structure with type \"%s\"", + "commands.place.structure.success": "Generated structure \"%s\" at %s, %s, %s", + "commands.place.template.failed": "Failed to place template", + "commands.place.template.invalid": "There is no template with id \"%s\"", + "commands.place.template.success": "Loaded template \"%s\" at %s, %s, %s", + "commands.playsound.failed": "The sound is too far away to be heard", + "commands.recipe.give.failed": "No new recipes were learned", + "commands.recipe.take.failed": "No recipes could be forgotten", + "commands.save.failed": "Unable to save the game (is there enough disk space?)", + "commands.save.alreadyOff": "Saving is already turned off", + "commands.save.alreadyOn": "Saving is already turned on", + "commands.scoreboard.objectives.add.duplicate": "An objective already exists by that name", + "commands.scoreboard.objectives.display.alreadyEmpty": "Nothing changed. That display slot is already empty", + "commands.scoreboard.objectives.display.alreadySet": "Nothing changed. That display slot is already showing that objective", + "commands.scoreboard.players.enable.failed": "Nothing changed. That trigger is already enabled", + "commands.scoreboard.players.enable.invalid": "Enable only works on trigger-objectives", + "commands.setblock.failed": "Could not set the block", + "commands.summon.failed": "Unable to summon entity", + "commands.summon.failed.uuid": "Unable to summon entity due to duplicate UUIDs", + "commands.summon.invalidPosition": "Invalid position for summon", + "commands.tag.add.failed": "Target either already has the tag or has too many tags", + "commands.tag.remove.failed": "Target does not have this tag", + "commands.team.add.duplicate": "A team already exists by that name", + "commands.team.empty.unchanged": "Nothing changed. That team is already empty", + "commands.team.option.color.unchanged": "Nothing changed. That team already has that color", + "commands.team.option.name.unchanged": "Nothing changed. That team already has that name", + "commands.team.option.friendlyfire.alreadyEnabled": "Nothing changed. Friendly fire is already enabled for that team", + "commands.team.option.friendlyfire.alreadyDisabled": "Nothing changed. Friendly fire is already disabled for that team", + "commands.team.option.seeFriendlyInvisibles.alreadyEnabled": "Nothing changed. That team can already see invisible teammates", + "commands.team.option.seeFriendlyInvisibles.alreadyDisabled": "Nothing changed. That team already can't see invisible teammates", + "commands.team.option.nametagVisibility.unchanged": "Nothing changed. Nametag visibility is already that value", + "commands.team.option.deathMessageVisibility.unchanged": "Nothing changed. Death message visibility is already that value", + "commands.team.option.collisionRule.unchanged": "Nothing changed. Collision rule is already that value", + "commands.trigger.failed.unprimed": "You cannot trigger this objective yet", + "commands.trigger.failed.invalid": "You can only trigger objectives that are 'trigger' type", + "commands.whitelist.alreadyOn": "Whitelist is already turned on", + "commands.whitelist.alreadyOff": "Whitelist is already turned off", + "commands.whitelist.add.failed": "Player is already whitelisted", + "commands.whitelist.remove.failed": "Player is not whitelisted", + "commands.worldborder.center.failed": "Nothing changed. The world border is already centered there", + "commands.worldborder.set.failed.nochange": "Nothing changed. The world border is already that size", + "commands.worldborder.set.failed.small": "World border cannot be smaller than 1 block wide", + "commands.worldborder.set.failed.big": "World border cannot be bigger than %s blocks wide", + "commands.worldborder.set.failed.far": "World border cannot be further out than %s blocks", + "commands.worldborder.warning.time.failed": "Nothing changed. The world border warning is already that amount of time", + "commands.worldborder.warning.distance.failed": "Nothing changed. The world border warning is already that distance", + "commands.worldborder.damage.buffer.failed": "Nothing changed. The world border damage buffer is already that distance", + "commands.worldborder.damage.amount.failed": "Nothing changed. The world border damage is already that amount", + "commands.data.block.invalid": "The target block is not a block entity", + "commands.data.merge.failed": "Nothing changed. The specified properties already have these values", + "commands.data.modify.expected_list": "Expected list, got: %s", + "commands.data.modify.expected_object": "Expected object, got: %s", + "commands.data.modify.invalid_index": "Invalid list index: %s", + "commands.data.get.multiple": "This argument accepts a single NBT value", + "commands.data.entity.invalid": "Unable to modify player data", + "commands.teammsg.failed.noteam": "You must be on a team to message your team", + "argument.color.invalid": "Unknown color '%s'", + "argument.dimension.invalid": "Unknown dimension '%s'", + "argument.component.invalid": "Invalid chat component: %s", + "argument.anchor.invalid": "Invalid entity anchor position %s", + "lectern.take_book": "Take Book", + "arguments.objective.notFound": "Unknown scoreboard objective '%s'", + "arguments.objective.readonly": "Scoreboard objective '%s' is read-only", + "argument.criteria.invalid": "Unknown criterion '%s'", + "particle.notFound": "Unknown particle: %s", + "argument.id.unknown": "Unknown ID: %s", + "advancement.advancementNotFound": "Unknown advancement: %s", + "recipe.notFound": "Unknown recipe: %s", + "entity.not_summonable": "Can't summon entity of type %s", + "predicate.unknown": "Unknown predicate: %s", + "item_modifier.unknown": "Unknown item modifier: %s", + "argument.scoreboardDisplaySlot.invalid": "Unknown display slot '%s'", + "slot.unknown": "Unknown slot '%s'", + "team.notFound": "Unknown team '%s'", + "arguments.block.tag.unknown": "Unknown block tag '%s'", + "argument.block.id.invalid": "Unknown block type '%s'", + "argument.block.property.unknown": "Block %s does not have property '%s'", + "argument.block.property.duplicate": "Property '%s' can only be set once for block %s", + "argument.block.property.invalid": "Block %s does not accept '%s' for %s property", + "argument.block.property.novalue": "Expected value for property '%s' on block %s", + "arguments.function.tag.unknown": "Unknown function tag '%s'", + "arguments.function.unknown": "Unknown function %s", + "arguments.item.overstacked": "%s can only stack up to %s", + "argument.item.id.invalid": "Unknown item '%s'", + "arguments.item.tag.unknown": "Unknown item tag '%s'", + "argument.entity.selector.unknown": "Unknown selector type '%s'", + "argument.entity.options.valueless": "Expected value for option '%s'", + "argument.entity.options.unknown": "Unknown option '%s'", + "argument.entity.options.inapplicable": "Option '%s' isn't applicable here", + "argument.entity.options.sort.irreversible": "Invalid or unknown sort type '%s'", + "argument.entity.options.mode.invalid": "Invalid or unknown game mode '%s'", + "argument.entity.options.type.invalid": "Invalid or unknown entity type '%s'", + "argument.nbt.list.mixed": "Can't insert %s into list of %s", + "argument.nbt.array.mixed": "Can't insert %s into %s", + "argument.nbt.array.invalid": "Invalid array type '%s'", + "commands.bossbar.create.failed": "A bossbar already exists with the ID '%s'", + "commands.bossbar.unknown": "No bossbar exists with the ID '%s'", + "clear.failed.single": "No items were found on player %s", + "clear.failed.multiple": "No items were found on %s players", + "commands.clone.toobig": "Too many blocks in the specified area (maximum %s, specified %s)", + "commands.datapack.unknown": "Unknown data pack '%s'", + "commands.datapack.enable.failed": "Pack '%s' is already enabled!", + "commands.datapack.enable.failed.no_flags": "Pack '%s' cannot be enabled, since required flags are not enabled in this world: %s!", + "commands.datapack.disable.failed": "Pack '%s' is not enabled!", + "commands.difficulty.failure": "The difficulty did not change; it is already set to %s", + "commands.enchant.failed.entity": "%s is not a valid entity for this command", + "commands.enchant.failed.itemless": "%s is not holding any item", + "commands.enchant.failed.incompatible": "%s cannot support that enchantment", + "commands.enchant.failed.level": "%s is higher than the maximum level of %s supported by that enchantment", + "commands.execute.blocks.toobig": "Too many blocks in the specified area (maximum %s, specified %s)", + "commands.execute.conditional.pass": "Test passed", + "commands.execute.conditional.pass_count": "Test passed, count: %s", + "commands.execute.conditional.fail": "Test failed", + "commands.execute.conditional.fail_count": "Test failed, count: %s", + "commands.fill.toobig": "Too many blocks in the specified area (maximum %s, specified %s)", + "commands.fillbiome.toobig": "Too many blocks in the specified volume (maximum %s, specified %s)", + "commands.fillbiome.success": "Biomes set between %s, %s, %s and %s, %s, %s", + "commands.fillbiome.success.count": "%s biome entries set between %s, %s, %s and %s, %s, %s", + "commands.publish.alreadyPublished": "Multiplayer game is already hosted on port %s", + "commands.scoreboard.players.get.null": "Can't get value of %s for %s; none is set", + "commands.spreadplayers.failed.teams": "Could not spread %s teams around %s, %s (too many entities for space - try using spread of at most %s)", + "commands.spreadplayers.failed.entities": "Could not spread %s entities around %s, %s (too many entities for space - try using spread of at most %s)", + "commands.spreadplayers.failed.invalid.height": "Invalid maxHeight %s; expected higher than world minimum %s", + "commands.data.get.invalid": "Can't get %s; only numeric tags are allowed", + "commands.data.get.unknown": "Can't get %s; tag doesn't exist", + "argument.double.low": "Double must not be less than %s, found %s", + "argument.double.big": "Double must not be more than %s, found %s", + "argument.float.low": "Float must not be less than %s, found %s", + "argument.float.big": "Float must not be more than %s, found %s", + "argument.integer.low": "Integer must not be less than %s, found %s", + "argument.integer.big": "Integer must not be more than %s, found %s", + "argument.long.low": "Long must not be less than %s, found %s", + "argument.long.big": "Long must not be more than %s, found %s", + "argument.literal.incorrect": "Expected literal %s", + "parsing.quote.expected.start": "Expected quote to start a string", + "parsing.quote.expected.end": "Unclosed quoted string", + "parsing.quote.escape": "Invalid escape sequence '\\%s' in quoted string", + "parsing.bool.invalid": "Invalid boolean, expected 'true' or 'false' but found '%s'", + "parsing.int.invalid": "Invalid integer '%s'", + "parsing.int.expected": "Expected integer", + "parsing.long.invalid": "Invalid long '%s'", + "parsing.long.expected": "Expected long", + "command.exception": "Could not parse command: %s", + "parsing.double.invalid": "Invalid double '%s'", + "parsing.double.expected": "Expected double", + "parsing.float.invalid": "Invalid float '%s'", + "parsing.float.expected": "Expected float", + "parsing.bool.expected": "Expected boolean", + "parsing.expected": "Expected '%s'", + "command.unknown.command": "Unknown or incomplete command, see below for error", + "command.unknown.argument": "Incorrect argument for command", + "command.expected.separator": "Expected whitespace to end one argument, but found trailing data", + "biome.minecraft.badlands": "Badlands", + "biome.minecraft.bamboo_jungle": "Bamboo Jungle", + "biome.minecraft.basalt_deltas": "Basalt Deltas", + "biome.minecraft.beach": "Beach", + "biome.minecraft.birch_forest": "Birch Forest", + "biome.minecraft.cold_ocean": "Cold Ocean", + "biome.minecraft.crimson_forest": "Crimson Forest", + "biome.minecraft.dark_forest": "Dark Forest", + "biome.minecraft.deep_cold_ocean": "Deep Cold Ocean", + "biome.minecraft.deep_dark": "Deep Dark", + "biome.minecraft.deep_frozen_ocean": "Deep Frozen Ocean", + "biome.minecraft.deep_lukewarm_ocean": "Deep Lukewarm Ocean", + "biome.minecraft.deep_ocean": "Deep Ocean", + "biome.minecraft.desert": "Desert", + "biome.minecraft.dripstone_caves": "Dripstone Caves", + "biome.minecraft.old_growth_birch_forest": "Old Growth Birch Forest", + "biome.minecraft.old_growth_pine_taiga": "Old Growth Pine Taiga", + "biome.minecraft.old_growth_spruce_taiga": "Old Growth Spruce Taiga", + "biome.minecraft.end_barrens": "End Barrens", + "biome.minecraft.end_highlands": "End Highlands", + "biome.minecraft.end_midlands": "End Midlands", + "biome.minecraft.eroded_badlands": "Eroded Badlands", + "biome.minecraft.flower_forest": "Flower Forest", + "biome.minecraft.forest": "Forest", + "biome.minecraft.frozen_ocean": "Frozen Ocean", + "biome.minecraft.frozen_peaks": "Frozen Peaks", + "biome.minecraft.frozen_river": "Frozen River", + "biome.minecraft.grove": "Grove", + "biome.minecraft.ice_spikes": "Ice Spikes", + "biome.minecraft.jagged_peaks": "Jagged Peaks", + "biome.minecraft.jungle": "Jungle", + "biome.minecraft.lukewarm_ocean": "Lukewarm Ocean", + "biome.minecraft.lush_caves": "Lush Caves", + "biome.minecraft.mangrove_swamp": "Mangrove Swamp", + "biome.minecraft.meadow": "Meadow", + "biome.minecraft.mushroom_fields": "Mushroom Fields", + "biome.minecraft.nether_wastes": "Nether Wastes", + "biome.minecraft.ocean": "Ocean", + "biome.minecraft.plains": "Plains", + "biome.minecraft.river": "River", + "biome.minecraft.savanna_plateau": "Savanna Plateau", + "biome.minecraft.savanna": "Savanna", + "biome.minecraft.small_end_islands": "Small End Islands", + "biome.minecraft.snowy_beach": "Snowy Beach", + "biome.minecraft.snowy_plains": "Snowy Plains", + "biome.minecraft.snowy_slopes": "Snowy Slopes", + "biome.minecraft.snowy_taiga": "Snowy Taiga", + "biome.minecraft.soul_sand_valley": "Soul Sand Valley", + "biome.minecraft.sparse_jungle": "Sparse Jungle", + "biome.minecraft.stony_peaks": "Stony Peaks", + "biome.minecraft.stony_shore": "Stony Shore", + "biome.minecraft.sunflower_plains": "Sunflower Plains", + "biome.minecraft.swamp": "Swamp", + "biome.minecraft.taiga": "Taiga", + "biome.minecraft.the_end": "The End", + "biome.minecraft.the_void": "The Void", + "biome.minecraft.warm_ocean": "Warm Ocean", + "biome.minecraft.warped_forest": "Warped Forest", + "biome.minecraft.windswept_forest": "Windswept Forest", + "biome.minecraft.windswept_gravelly_hills": "Windswept Gravelly Hills", + "biome.minecraft.windswept_hills": "Windswept Hills", + "biome.minecraft.windswept_savanna": "Windswept Savanna", + "biome.minecraft.wooded_badlands": "Wooded Badlands", + "realms.missing.module.error.text": "Realms could not be opened right now, please try again later", + "realms.missing.snapshot.error.text": "Realms is currently not supported in snapshots", + "color.minecraft.white": "White", + "color.minecraft.orange": "Orange", + "color.minecraft.magenta": "Magenta", + "color.minecraft.light_blue": "Light Blue", + "color.minecraft.yellow": "Yellow", + "color.minecraft.lime": "Lime", + "color.minecraft.pink": "Pink", + "color.minecraft.gray": "Gray", + "color.minecraft.light_gray": "Light Gray", + "color.minecraft.cyan": "Cyan", + "color.minecraft.purple": "Purple", + "color.minecraft.blue": "Blue", + "color.minecraft.brown": "Brown", + "color.minecraft.green": "Green", + "color.minecraft.red": "Red", + "color.minecraft.black": "Black", + "title.singleplayer": "Singleplayer", + "title.multiplayer.realms": "Multiplayer (Realms)", + "title.multiplayer.lan": "Multiplayer (LAN)", + "title.multiplayer.other": "Multiplayer (3rd-party Server)", + "gamerule.announceAdvancements": "Announce advancements", + "gamerule.commandBlockOutput": "Broadcast command block output", + "gamerule.disableElytraMovementCheck": "Disable elytra movement check", + "gamerule.disableRaids": "Disable raids", + "gamerule.doDaylightCycle": "Advance time of day", + "gamerule.doEntityDrops": "Drop entity equipment", + "gamerule.doEntityDrops.description": "Controls drops from minecarts (including inventories), item frames, boats, etc.", + "gamerule.doFireTick": "Update fire", + "gamerule.doImmediateRespawn": "Respawn immediately", + "gamerule.doInsomnia": "Spawn phantoms", + "gamerule.doLimitedCrafting": "Require recipe for crafting", + "gamerule.doLimitedCrafting.description": "If enabled, players will be able to craft only unlocked recipes", + "gamerule.doMobLoot": "Drop mob loot", + "gamerule.doMobLoot.description": "Controls resource drops from mobs, including experience orbs", + "gamerule.doMobSpawning": "Spawn mobs", + "gamerule.doMobSpawning.description": "Some entities might have separate rules", + "gamerule.doPatrolSpawning": "Spawn pillager patrols", + "gamerule.doTileDrops": "Drop blocks", + "gamerule.doTileDrops.description": "Controls resource drops from blocks, including experience orbs", + "gamerule.doTraderSpawning": "Spawn Wandering Traders", + "gamerule.doWardenSpawning": "Spawn Wardens", + "gamerule.doWeatherCycle": "Update weather", + "gamerule.drowningDamage": "Deal drowning damage", + "gamerule.fallDamage": "Deal fall damage", + "gamerule.fireDamage": "Deal fire damage", + "gamerule.freezeDamage": "Deal freeze damage", + "gamerule.forgiveDeadPlayers": "Forgive dead players", + "gamerule.forgiveDeadPlayers.description": "Angered neutral mobs stop being angry when the targeted player dies nearby.", + "gamerule.keepInventory": "Keep inventory after death", + "gamerule.logAdminCommands": "Broadcast admin commands", + "gamerule.maxCommandChainLength": "Command chain size limit", + "gamerule.maxCommandChainLength.description": "Applies to command block chains and functions", + "gamerule.maxEntityCramming": "Entity cramming threshold", + "gamerule.mobGriefing": "Allow destructive mob actions", + "gamerule.naturalRegeneration": "Regenerate health", + "gamerule.randomTickSpeed": "Random tick speed rate", + "gamerule.reducedDebugInfo": "Reduce debug info", + "gamerule.reducedDebugInfo.description": "Limits contents of debug screen", + "gamerule.sendCommandFeedback": "Send command feedback", + "gamerule.showDeathMessages": "Show death messages", + "gamerule.playersSleepingPercentage": "Sleep percentage", + "gamerule.playersSleepingPercentage.description": "The percentage of players who must be sleeping to skip the night.", + "gamerule.spawnRadius": "Respawn location radius", + "gamerule.spectatorsGenerateChunks": "Allow spectators to generate terrain", + "gamerule.universalAnger": "Universal anger", + "gamerule.universalAnger.description": "Angered neutral mobs attack any nearby player, not just the player that angered them. Works best if forgiveDeadPlayers is disabled.", + "gamerule.blockExplosionDropDecay": "In block interaction explosions, some blocks won't drop their loot", + "gamerule.blockExplosionDropDecay.description": "Some of the drops from blocks destroyed by explosions caused by block interactions are lost in the explosion.", + "gamerule.mobExplosionDropDecay": "In mob explosions, some blocks won't drop their loot", + "gamerule.mobExplosionDropDecay.description": "Some of the drops from blocks destroyed by explosions caused by mobs are lost in the explosion.", + "gamerule.tntExplosionDropDecay": "In TNT explosions, some blocks won't drop their loot", + "gamerule.tntExplosionDropDecay.description": "Some of the drops from blocks destroyed by explosions caused by TNT are lost in the explosion.", + "gamerule.snowAccumulationHeight": "Snow accumulation height", + "gamerule.snowAccumulationHeight.description": "When it snows, layers of snow form on the ground up to at most this number of layers.", + "gamerule.waterSourceConversion": "Water converts to source", + "gamerule.waterSourceConversion.description": "When flowing water is surrounded on two sides by water sources it converts into a source.", + "gamerule.lavaSourceConversion": "Lava converts to source", + "gamerule.lavaSourceConversion.description": "When flowing lava is surrounded on two sides by lava sources it converts into a source.", + "gamerule.globalSoundEvents": "Global sound events", + "gamerule.globalSoundEvents.description": "When certain game events happen, like a boss spawning, the sound is heard everywhere.", + "gamerule.category.chat": "Chat", + "gamerule.category.spawning": "Spawning", + "gamerule.category.updates": "World Updates", + "gamerule.category.drops": "Drops", + "gamerule.category.mobs": "Mobs", + "gamerule.category.player": "Player", + "gamerule.category.misc": "Miscellaneous", + "pack.source.builtin": "built-in", + "pack.source.feature": "feature", + "pack.source.world": "world", + "pack.source.local": "local", + "pack.source.server": "server", + "mirror.none": "|", + "mirror.left_right": "\u2190 \u2192", + "mirror.front_back": "\u2191 \u2193", + "sleep.not_possible": "No amount of rest can pass this night", + "sleep.players_sleeping": "%s/%s players sleeping", + "sleep.skipping_night": "Sleeping through this night", + "compliance.playtime.greaterThan24Hours": "You've been playing for greater than 24 hours", + "compliance.playtime.message": "Excessive gaming may interfere with normal daily life", + "compliance.playtime.hours": "You've been playing for %s hour(s)", + "outOfMemory.title": "Out of memory!", + "outOfMemory.message": "Minecraft has run out of memory.\n\nThis could be caused by a bug in the game or by the Java Virtual Machine not being allocated enough memory.\n\nTo prevent level corruption, the current game has quit. We've tried to free up enough memory to let you go back to the main menu and back to playing, but this may not have worked.\n\nPlease restart the game if you see this message again.", + "mco.gui.ok": "Ok", + "mco.gui.button": "Button", + "mco.terms.buttons.agree": "Agree", + "mco.terms.buttons.disagree": "Don't agree", + "mco.terms.title": "Realms Terms of Service", + "mco.terms.sentence.1": "I agree to the Minecraft Realms", + "mco.terms.sentence.2": "Terms of Service", + "mco.selectServer.play": "Play", + "mco.selectServer.configure": "Configure", + "mco.selectServer.configureRealm": "Configure realm", + "mco.selectServer.leave": "Leave realm", + "mco.selectServer.create": "Create realm", + "mco.selectServer.purchase": "Add Realm", + "mco.selectServer.buy": "Buy a realm!", + "mco.selectServer.trial": "Get a trial!", + "mco.selectServer.close": "Close", + "mco.selectServer.expiredTrial": "Your trial has ended", + "mco.selectServer.expiredList": "Your subscription has expired", + "mco.selectServer.expiredSubscribe": "Subscribe", + "mco.selectServer.expiredRenew": "Renew", + "mco.selectServer.expired": "Expired realm", + "mco.selectServer.open": "Open realm", + "mco.selectServer.closed": "Closed realm", + "mco.selectServer.openserver": "Open realm", + "mco.selectServer.closeserver": "Close realm", + "mco.selectServer.minigame": "Minigame:", + "mco.selectServer.uninitialized": "Click to start your new realm!", + "mco.selectServer.expires.days": "Expires in %s days", + "mco.selectServer.expires.day": "Expires in a day", + "mco.selectServer.expires.soon": "Expires soon", + "mco.selectServer.note": "Note:", + "mco.selectServer.mapOnlySupportedForVersion": "This map is unsupported in %s", + "mco.selectServer.minigameNotSupportedInVersion": "Can't play this minigame in %s", + "mco.selectServer.popup": "Realms is a safe, simple way to enjoy an online Minecraft world with up to ten friends at a time. It supports loads of minigames and plenty of custom worlds! Only the owner of the realm needs to pay.", + "mco.configure.world.settings.title": "Settings", + "mco.configure.world.title": "Configure realm:", + "mco.configure.worlds.title": "Worlds", + "mco.configure.world.name": "Realm name", + "mco.configure.world.description": "Realm description", + "mco.configure.world.location": "Location", + "mco.configure.world.invited": "Invited", + "mco.configure.world.invite.narration": "You have %s new invites", + "mco.configure.world.buttons.edit": "Settings", + "mco.configure.world.buttons.done": "Done", + "mco.configure.world.buttons.delete": "Delete", + "mco.configure.world.buttons.open": "Open realm", + "mco.configure.world.buttons.close": "Close realm", + "mco.configure.world.buttons.invite": "Invite player", + "mco.configure.world.buttons.activity": "Player activity", + "mco.configure.world.activityfeed.disabled": "Player feed temporarily disabled", + "mco.configure.world.buttons.moreoptions": "More options", + "mco.configure.world.invite.profile.name": "Name", + "mco.configure.world.uninvite.question": "Are you sure that you want to uninvite", + "mco.configure.world.status": "Status", + "mco.configure.world.invites.ops.tooltip": "Operator", + "mco.configure.world.invites.normal.tooltip": "Normal user", + "mco.configure.world.invites.remove.tooltip": "Remove", + "mco.configure.world.closing": "Closing the realm...", + "mco.configure.world.opening": "Opening the realm...", + "mco.configure.world.buttons.players": "Players", + "mco.configure.world.buttons.settings": "Settings", + "mco.configure.world.buttons.subscription": "Subscription", + "mco.configure.world.buttons.options": "World options", + "mco.configure.world.backup": "World backups", + "mco.configure.world.buttons.resetworld": "Reset world", + "mco.configure.world.buttons.switchminigame": "Switch minigame", + "mco.configure.current.minigame": "Current", + "mco.configure.world.subscription.title": "Your subscription", + "mco.configure.world.subscription.timeleft": "Time left", + "mco.configure.world.subscription.unknown": "Unknown", + "mco.configure.world.subscription.recurring.daysleft": "Renewed automatically in", + "mco.configure.world.subscription.less_than_a_day": "Less than a day", + "mco.configure.world.subscription.expired": "Expired", + "mco.configure.world.subscription.start": "Start date", + "mco.configure.world.subscription.extend": "Extend subscription", + "mco.configure.world.subscription.day": "day", + "mco.configure.world.subscription.month": "month", + "mco.configure.world.subscription.days": "days", + "mco.configure.world.subscription.months": "months", + "mco.configure.world.pvp": "PVP", + "mco.configure.world.spawn_toggle.title": "Warning!", + "mco.configure.world.spawn_toggle.message": "Turning this option off will REMOVE ALL existing entities of that type", + "mco.configure.world.spawn_toggle.message.npc": "Turning this option off will REMOVE ALL existing entities of that type, like Villagers", + "mco.configure.world.spawnAnimals": "Spawn animals", + "mco.configure.world.spawnNPCs": "Spawn NPCs", + "mco.configure.world.spawnMonsters": "Spawn monsters", + "mco.configure.world.spawnProtection": "Spawn protection", + "mco.configure.world.commandBlocks": "Command blocks", + "mco.configure.world.forceGameMode": "Force game mode", + "mco.configure.world.slot": "World %s", + "mco.configure.world.slot.empty": "Empty", + "mco.create.world.wait": "Creating the realm...", + "mco.create.world.error": "You must enter a name!", + "mco.create.world.subtitle": "Optionally, select what world to put on your new realm", + "mco.create.world.skip": "Skip", + "mco.reset.world.title": "Reset world", + "mco.reset.world.warning": "This will replace the current world of your realm", + "mco.reset.world.seed": "Seed (Optional)", + "mco.reset.world.resetting.screen.title": "Resetting world...", + "mco.reset.world.generate": "New world", + "mco.reset.world.upload": "Upload world", + "mco.reset.world.adventure": "Adventures", + "mco.reset.world.template": "World templates", + "mco.reset.world.experience": "Experiences", + "mco.reset.world.inspiration": "Inspiration", + "mco.minigame.world.title": "Switch realm to minigame", + "mco.minigame.world.info.line1": "This will temporarily replace your world with a minigame!", + "mco.minigame.world.info.line2": "You can later return to your original world without losing anything.", + "mco.minigame.world.selected": "Selected minigame:", + "mco.minigame.world.noSelection": "Please make a selection", + "mco.minigame.world.startButton": "Switch", + "mco.minigame.world.starting.screen.title": "Starting minigame...", + "mco.minigame.world.changeButton": "Select another minigame", + "mco.minigame.world.stopButton": "End minigame", + "mco.minigame.world.switch.title": "Switch minigame", + "mco.minigame.world.switch.new": "Select another minigame?", + "mco.minigame.world.restore.question.line1": "The minigame will end and your realm will be restored.", + "mco.minigame.world.restore.question.line2": "Are you sure you want to continue?", + "mco.minigame.world.restore": "Ending minigame...", + "mco.configure.world.slot.tooltip": "Switch to world", + "mco.configure.world.slot.tooltip.minigame": "Switch to minigame", + "mco.configure.world.slot.tooltip.active": "Join", + "mco.configure.world.close.question.line1": "Your realm will become unavailable.", + "mco.configure.world.close.question.line2": "Are you sure you want to continue?", + "mco.configure.world.leave.question.line1": "If you leave this realm you won't see it unless you are invited again", + "mco.configure.world.leave.question.line2": "Are you sure you want to continue?", + "mco.configure.world.resourcepack.question.line1": "You need a custom resource pack to play on this realm", + "mco.configure.world.resourcepack.question.line2": "Do you want to download it and play?", + "mco.configure.world.reset.question.line1": "Your world will be regenerated and your current world will be lost", + "mco.configure.world.reset.question.line2": "Are you sure you want to continue?", + "mco.configure.world.restore.question.line1": "Your world will be restored to date '%s' (%s)", + "mco.configure.world.restore.question.line2": "Are you sure you want to continue?", + "mco.configure.world.restore.download.question.line1": "The world will be downloaded and added to your single player worlds.", + "mco.configure.world.restore.download.question.line2": "Do you want to continue?", + "mco.configure.world.slot.switch.question.line1": "Your realm will be switched to another world", + "mco.configure.world.slot.switch.question.line2": "Are you sure you want to continue?", + "mco.configure.world.switch.slot": "Create world", + "mco.configure.world.switch.slot.subtitle": "This world is empty, choose how to create your world", + "mco.minigame.world.slot.screen.title": "Switching world...", + "mco.configure.world.edit.subscreen.adventuremap": "Some settings are disabled since your current world is an adventure", + "mco.configure.world.edit.subscreen.experience": "Some settings are disabled since your current world is an experience", + "mco.configure.world.edit.subscreen.inspiration": "Some settings are disabled since your current world is an inspiration", + "mco.configure.world.edit.slot.name": "World name", + "mco.configure.world.players.title": "Players", + "mco.configure.world.players.error": "A player with the provided name does not exist", + "mco.configure.world.delete.button": "Delete realm", + "mco.configure.world.delete.question.line1": "Your realm will be permanently deleted", + "mco.configure.world.delete.question.line2": "Are you sure you want to continue?", + "mco.connect.connecting": "Connecting to the realm...", + "mco.connect.authorizing": "Logging in...", + "mco.connect.failed": "Failed to connect to the realm", + "mco.connect.success": "Done", + "mco.create.world": "Create", + "mco.create.world.reset.title": "Creating world...", + "mco.client.incompatible.title": "Client incompatible!", + "mco.client.incompatible.msg.line1": "Your client is not compatible with Realms.", + "mco.client.incompatible.msg.line2": "Please use the most recent version of Minecraft.", + "mco.client.incompatible.msg.line3": "Realms is not compatible with snapshot versions.", + "mco.backup.button.restore": "Restore", + "mco.backup.generate.world": "Generate world", + "mco.backup.restoring": "Restoring your realm", + "mco.backup.button.download": "Download latest", + "mco.backup.changes.tooltip": "Changes", + "mco.backup.nobackups": "This realm doesn't have any backups currently.", + "mco.backup.button.upload": "Upload world", + "mco.backup.button.reset": "Reset world", + "mco.download.title": "Downloading latest world", + "mco.download.cancelled": "Download cancelled", + "mco.download.failed": "Download failed", + "mco.download.done": "Download done", + "mco.download.downloading": "Downloading", + "mco.download.extracting": "Extracting", + "mco.download.preparing": "Preparing download", + "mco.download.confirmation.line1": "The world you are going to download is larger than %s", + "mco.download.confirmation.line2": "You won't be able to upload this world to your realm again", + "mco.template.title": "World templates", + "mco.template.title.minigame": "Minigames", + "mco.template.button.select": "Select", + "mco.template.button.trailer": "Trailer", + "mco.template.button.publisher": "Publisher", + "mco.template.default.name": "World template", + "mco.template.name": "Template", + "mco.template.info.tooltip": "Publisher website", + "mco.template.trailer.tooltip": "Map trailer", + "mco.template.select.none": "Oops, it looks like this content category is currently empty.\nPlease check back later for new content, or if you're a creator,\n%s.", + "mco.template.select.none.linkTitle": "consider submitting something yourself", + "mco.template.select.failure": "We couldn't retrieve the list of content for this category.\nPlease check your internet connection, or try again later.", + "mco.template.select.narrate.authors" : "Authors: %s", + "mco.template.select.narrate.version" : "version %s", + "mco.invites.button.accept": "Accept", + "mco.invites.button.reject": "Reject", + "mco.invites.title": "Pending Invites", + "mco.invites.pending": "New invites!", + "mco.invites.nopending": "No pending invites!", + "mco.upload.select.world.title": "Upload world", + "mco.upload.select.world.subtitle": "Please select a singleplayer world to upload", + "mco.upload.select.world.none": "No singleplayer worlds found!", + "mco.upload.button.name": "Upload", + "mco.upload.verifying": "Verifying your world", + "mco.upload.preparing": "Preparing your world", + "mco.upload.close.failure": "Could not close your realm, please try again later", + "mco.upload.size.failure.line1": "'%s' is too big!", + "mco.upload.size.failure.line2": "It is %s. The maximum allowed size is %s.", + "mco.upload.uploading": "Uploading '%s'", + "mco.upload.done": "Upload done", + "mco.upload.failed": "Upload failed! (%s)", + "mco.upload.cancelled": "Upload cancelled", + "mco.upload.hardcore": "Hardcore worlds can't be uploaded!", + "mco.activity.title": "Player activity", + "mco.activity.noactivity": "No activity for the past %s days", + "mco.errorMessage.6001": "Client outdated", + "mco.errorMessage.6002": "Terms of service not accepted", + "mco.errorMessage.6003": "Download limit reached", + "mco.errorMessage.6004": "Upload limit reached", + "mco.errorMessage.connectionFailure": "An error occurred, please try again later.", + "mco.errorMessage.serviceBusy": "Realms is busy at the moment.\nPlease try connecting to your Realm again in a couple of minutes.", + "mco.trial.message.line1": "Want to get your own realm?", + "mco.trial.message.line2": "Click here for more info!", + "mco.brokenworld.play": "Play", + "mco.brokenworld.download": "Download", + "mco.brokenworld.downloaded": "Downloaded", + "mco.brokenworld.reset": "Reset", + "mco.brokenworld.title": "Your current world is no longer supported", + "mco.brokenworld.message.line1": "Please reset or select another world.", + "mco.brokenworld.message.line2": "You can also choose to download the world to singleplayer.", + "mco.brokenworld.minigame.title": "This minigame is no longer supported", + "mco.brokenworld.nonowner.title": "World is out of date", + "mco.brokenworld.nonowner.error": "Please wait for the realm owner to reset the world", + "mco.error.invalid.session.title": "Invalid session", + "mco.error.invalid.session.message": "Please try restarting Minecraft", + "mco.news": "Realms news", + "mco.account.privacyinfo": "Mojang implements certain procedures to help protect children and their privacy including complying with the Children’s Online Privacy Protection Act (COPPA) and General Data Protection Regulation (GDPR).\n\nYou may need to obtain parental consent before accessing your Realms account.\n\nIf you have an older Minecraft account (you log in with your username), you need to migrate the account to a Mojang account in order to access Realms.", + "mco.account.update": "Update account", + "mco.account.privacy.info": "Read more about Mojang and privacy laws" +} diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index 67c5cf72..39d00aa4 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -16,6 +16,7 @@ using Tomlet.Models; using static MinecraftClient.Settings.AppVarConfigHelper; using static MinecraftClient.Settings.ChatBotConfigHealper; using static MinecraftClient.Settings.ChatFormatConfigHelper; +using static MinecraftClient.Settings.ConsoleConfigHealper; using static MinecraftClient.Settings.HeadCommentHealper; using static MinecraftClient.Settings.LoggingConfigHealper; using static MinecraftClient.Settings.MainConfigHealper; @@ -31,10 +32,10 @@ namespace MinecraftClient private const int CommentsAlignPosition = 45; private readonly static Regex CommentRegex = new(@"^(.*)\s?#\s\$([\w\.]+)\$\s*$$", RegexOptions.Compiled); - //Other Settings - public static string TranslationsFile_FromMCDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\.minecraft\assets\objects\48\482e0dae05abfa35ab5cb076e41fda77b4fb9a08"; //MC 1.19 en_GB.lang - public static string TranslationsFile_Website_Index = "https://piston-meta.mojang.com/v1/packages/b5c7548ddb9e584e84a5f762da5b78211c715a63/1.19.json"; - public static string TranslationsFile_Website_Download = "http://resources.download.minecraft.net"; + // Other Settings + public const string TranslationsFile_Version = "1.19.3"; + public const string TranslationsFile_Website_Index = "https://piston-meta.mojang.com/v1/packages/c492375ded5da34b646b8c5c0842a0028bc69cec/2.json"; + public const string TranslationsFile_Website_Download = "http://resources.download.minecraft.net"; public const string TranslationProjectUrl = "https://crwd.in/minecraft-console-client"; @@ -90,6 +91,12 @@ namespace MinecraftClient set { LoggingConfigHealper.Config = value; LoggingConfigHealper.Config.OnSettingUpdate(); } } + public ConsoleConfig Console + { + get { return ConsoleConfigHealper.Config; } + set { ConsoleConfigHealper.Config = value; ConsoleConfigHealper.Config.OnSettingUpdate(); } + } + public AppVarConfig AppVar { get { return AppVarConfigHelper.Config; } @@ -345,12 +352,12 @@ namespace MinecraftClient "hy_am", "id_id", "ig_ng", "io_en", "is_is", "isv", "it_it", "ja_jp", "jbo_en", "ka_ge", "kk_kz", "kn_in", "ko_kr", "ksh", "kw_gb", "la_la", "lb_lu", "li_li", "lmo", "lol_us", "lt_lt", "lv_lv", "lzh", "mk_mk", - "mn_mn", "ms_my", "mt_mt", "nds_de", "nl_be", "nl_nl", "nn_no", "no_no", - "oc_fr", "ovd", "pl_pl", "pt_br", "pt_pt", "qya_aa", "ro_ro", "rpr", - "ru_ru", "se_no", "sk_sk", "sl_si", "so_so", "sq_al", "sr_sp", "sv_se", - "sxu", "szl", "ta_in", "th_th", "tl_ph", "tlh_aa", "tok", "tr_tr", - "tt_ru", "uk_ua", "val_es", "vec_it", "vi_vn", "yi_de", "yo_ng", "zh_cn", - "zh_hk", "zh_tw", "zlm_arab" + "mn_mn", "ms_my", "mt_mt", "nah", "nds_de", "nl_be", "nl_nl", "nn_no", + "no_no", "oc_fr", "ovd", "pl_pl", "pt_br", "pt_pt", "qya_aa", "ro_ro", + "rpr", "ru_ru", "ry_ua", "se_no", "sk_sk", "sl_si", "so_so", "sq_al", + "sr_sp", "sv_se", "sxu", "szl", "ta_in", "th_th", "tl_ph", "tlh_aa", + "tok", "tr_tr", "tt_ru", "uk_ua", "val_es", "vec_it", "vi_vn", "yi_de", + "yo_ng", "zh_cn", "zh_hk", "zh_tw", "zlm_arab" }; /// @@ -421,7 +428,7 @@ namespace MinecraftClient if (!Advanced.LoadMccTranslation) { - CultureInfo culture = CultureInfo.CreateSpecificCulture("en_gb"); + CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US"); CultureInfo.DefaultThreadCurrentCulture = culture; CultureInfo.DefaultThreadCurrentUICulture = culture; Program.ActualCulture = culture; @@ -491,7 +498,7 @@ namespace MinecraftClient public class AdvancedConfig { [TomlInlineComment("$Main.Advanced.language$")] - public string Language = "en_gb"; + public string Language = "en_us"; [TomlInlineComment("$Main.Advanced.LoadMccTrans$")] public bool LoadMccTranslation = true; @@ -767,6 +774,139 @@ namespace MinecraftClient } } + public static class ConsoleConfigHealper + { + public static ConsoleConfig Config = new(); + + [TomlDoNotInlineObject] + public class ConsoleConfig + { + public MainConfig General = new(); + + [TomlPrecedingComment("$Console.CommandSuggestion$")] + public CommandSuggestionConfig CommandSuggestion = new(); + + public void OnSettingUpdate() + { + ConsoleInteractive.ConsoleWriter.EnableColor = General.Enable_Color; + + ConsoleInteractive.ConsoleReader.DisplayUesrInput = General.Display_Uesr_Input; + + ConsoleInteractive.ConsoleSuggestion.EnableColor = CommandSuggestion.Enable_Color; + + CommandSuggestion.Max_Suggestion_Width = + ConsoleInteractive.ConsoleSuggestion.SetMaxSuggestionLength(CommandSuggestion.Max_Suggestion_Width); + + CommandSuggestion.Max_Displayed_Suggestions = + ConsoleInteractive.ConsoleSuggestion.SetMaxSuggestionCount(CommandSuggestion.Max_Displayed_Suggestions); + + // CommandSuggestion color settings + { + if (!CheckColorCode(CommandSuggestion.Text_Color)) + { + ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.TextColor", CommandSuggestion.Text_Color)); + CommandSuggestion.Text_Color = "#f8fafc"; + } + if (!CheckColorCode(CommandSuggestion.Text_Background_Color)) + { + ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.TextBackgroundColor", CommandSuggestion.Text_Background_Color)); + CommandSuggestion.Text_Background_Color = "#64748b"; + } + if (!CheckColorCode(CommandSuggestion.Highlight_Text_Color)) + { + ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.HighlightTextColor", CommandSuggestion.Highlight_Text_Color)); + CommandSuggestion.Highlight_Text_Color = "#334155"; + } + if (!CheckColorCode(CommandSuggestion.Highlight_Text_Background_Color)) + { + ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.HighlightTextBackgroundColor", CommandSuggestion.Highlight_Text_Background_Color)); + CommandSuggestion.Highlight_Text_Background_Color = "#fde047"; + } + if (!CheckColorCode(CommandSuggestion.Tooltip_Color)) + { + ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.TooltipColor", CommandSuggestion.Tooltip_Color)); + CommandSuggestion.Tooltip_Color = "#7dd3fc"; + } + if (!CheckColorCode(CommandSuggestion.Highlight_Tooltip_Color)) + { + ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.HighlightTooltipColor", CommandSuggestion.Highlight_Tooltip_Color)); + CommandSuggestion.Highlight_Tooltip_Color = "#3b82f6"; + } + if (!CheckColorCode(CommandSuggestion.Arrow_Symbol_Color)) + { + ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.ArrowSymbolColor", CommandSuggestion.Arrow_Symbol_Color)); + CommandSuggestion.Arrow_Symbol_Color = "#d1d5db"; + } + + ConsoleInteractive.ConsoleSuggestion.SetColors( + CommandSuggestion.Text_Color, CommandSuggestion.Text_Background_Color, + CommandSuggestion.Highlight_Text_Color, CommandSuggestion.Highlight_Text_Background_Color, + CommandSuggestion.Tooltip_Color, CommandSuggestion.Highlight_Tooltip_Color, + CommandSuggestion.Arrow_Symbol_Color); + } + } + + private static bool CheckColorCode(string? input) + { + if (string.IsNullOrWhiteSpace(input)) + return false; + if (input.Length < 6 || input.Length > 7) + return false; + if (input.Length == 6 && input[0] == '#') + return false; + if (input.Length == 7 && input[0] != '#') + return false; + try + { + Convert.ToInt32(input.Length == 7 ? input[1..] : input, 16); + return true; + } + catch + { + return false; + } + } + + [TomlDoNotInlineObject] + public class MainConfig + { + [TomlInlineComment("$Console.Enable_Color$")] + public bool Enable_Color = true; + + [TomlInlineComment("$Console.General.Display_Uesr_Input$")] + public bool Display_Uesr_Input = true; + } + + [TomlDoNotInlineObject] + public class CommandSuggestionConfig + { + [TomlInlineComment("$Console.CommandSuggestion.Enable$")] + public bool Enable = true; + + [TomlInlineComment("$Console.Enable_Color$")] + public bool Enable_Color = true; + + public int Max_Suggestion_Width = 30; + + public int Max_Displayed_Suggestions = 6; + + public string Text_Color = "#f8fafc"; + + public string Text_Background_Color = "#64748b"; + + public string Highlight_Text_Color = "#334155"; + + public string Highlight_Text_Background_Color = "#fde047"; + + public string Tooltip_Color = "#7dd3fc"; + + public string Highlight_Tooltip_Color = "#3b82f6"; + + public string Arrow_Symbol_Color = "#d1d5db"; + } + } + } + public static class AppVarConfigHelper { public static AppVarConfig Config = new(); @@ -1238,7 +1378,7 @@ namespace MinecraftClient public static string GetDefaultGameLanguage() { - string gameLanguage = "en_gb"; + string gameLanguage = "en_us"; string systemLanguage = string.IsNullOrWhiteSpace(Program.ActualCulture.Name) ? Program.ActualCulture.Parent.Name : Program.ActualCulture.Name; @@ -1326,6 +1466,9 @@ namespace MinecraftClient case "en-TT": case "en-ZA": case "en-ZW": + case "en-US": + gameLanguage = "en_us"; + break; case "en-GB": gameLanguage = "en_gb"; break; @@ -1335,9 +1478,6 @@ namespace MinecraftClient case "en-CA": gameLanguage = "en_ca"; break; - case "en-US": - gameLanguage = "en_us"; - break; case "en-NZ": gameLanguage = "en_nz"; break; diff --git a/MinecraftClient/UpgradeHelper.cs b/MinecraftClient/UpgradeHelper.cs index 77c694d4..cca5b163 100644 --- a/MinecraftClient/UpgradeHelper.cs +++ b/MinecraftClient/UpgradeHelper.cs @@ -63,7 +63,7 @@ namespace MinecraftClient { string OSInfo = GetOSIdentifier(); if (Settings.Config.Logging.DebugMessages || string.IsNullOrEmpty(OSInfo)) - ConsoleIO.WriteLine(string.Format("OS: {0}, Arch: {1}, Framework: {2}", + ConsoleIO.WriteLine(string.Format("OS: {0}, Arch: {1}, Framework: {2}", RuntimeInformation.OSDescription, RuntimeInformation.ProcessArchitecture, RuntimeInformation.FrameworkDescription)); if (string.IsNullOrEmpty(OSInfo)) { @@ -308,7 +308,7 @@ namespace MinecraftClient { string proxyAddress; if (!string.IsNullOrWhiteSpace(Settings.Config.Proxy.Username) && !string.IsNullOrWhiteSpace(Settings.Config.Proxy.Password)) - proxyAddress = string.Format("{0}://{3}:{4}@{1}:{2}", + proxyAddress = string.Format("{0}://{3}:{4}@{1}:{2}", Settings.Config.Proxy.Proxy_Type.ToString().ToLower(), Settings.Config.Proxy.Server.Host, Settings.Config.Proxy.Server.Port, From 127978615c182206a2ac670d5a4dced98be1d93a Mon Sep 17 00:00:00 2001 From: BruceChen Date: Sun, 11 Dec 2022 14:54:11 +0800 Subject: [PATCH 4/8] Update tip message --- .gitignore | 1 + MinecraftClient/Resources/Translations/Translations.Designer.cs | 2 +- MinecraftClient/Resources/Translations/Translations.resx | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 45f6cef2..22033cc8 100644 --- a/.gitignore +++ b/.gitignore @@ -409,6 +409,7 @@ FodyWeavers.xsd # translations /MinecraftClient/Resources/Translations/Translations.*.resx /MinecraftClient/Resources/AsciiArt/AsciiArt.*.resx +/MinecraftClient/Resources/ConfigComments/ConfigComments.*.resx /docs/.vuepress/translations/*.json !/docs/.vuepress/translations/en.json diff --git a/MinecraftClient/Resources/Translations/Translations.Designer.cs b/MinecraftClient/Resources/Translations/Translations.Designer.cs index 7af00b17..bc17ee17 100644 --- a/MinecraftClient/Resources/Translations/Translations.Designer.cs +++ b/MinecraftClient/Resources/Translations/Translations.Designer.cs @@ -2253,7 +2253,7 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to Downloading '{0}.lang' from Mojang servers.... + /// Looks up a localized string similar to Downloading '{0}.json' from Mojang servers.... /// internal static string chat_download { get { diff --git a/MinecraftClient/Resources/Translations/Translations.resx b/MinecraftClient/Resources/Translations/Translations.resx index 1888597a..dd806246 100644 --- a/MinecraftClient/Resources/Translations/Translations.resx +++ b/MinecraftClient/Resources/Translations/Translations.resx @@ -864,7 +864,7 @@ Add the ID of this chat to "Authorized_Chat_Ids" field in the configuration file Done. File saved as '{0}' - Downloading '{0}.lang' from Mojang servers... + Downloading '{0}.json' from Mojang servers... Failed to download the file. From 94a3c92b36d97fddd3bedb380d07d6f4d12d111f Mon Sep 17 00:00:00 2001 From: BruceChen Date: Sun, 11 Dec 2022 16:30:45 +0800 Subject: [PATCH 5/8] Bug fix --- MinecraftClient/ChatBots/AutoCraft.cs | 12 +-- MinecraftClient/ChatBots/AutoDig.cs | 16 ++-- MinecraftClient/ChatBots/AutoDrop.cs | 12 +-- MinecraftClient/ChatBots/AutoFishing.cs | 12 +-- MinecraftClient/ChatBots/DiscordBridge.cs | 12 +-- MinecraftClient/ChatBots/Farmer.cs | 12 +-- MinecraftClient/ChatBots/FollowPlayer.cs | 12 +-- MinecraftClient/ChatBots/Mailer.cs | 12 +-- MinecraftClient/ChatBots/Map.cs | 12 +-- MinecraftClient/ChatBots/ReplayCapture.cs | 12 +-- MinecraftClient/ChatBots/TelegramBridge.cs | 12 +-- MinecraftClient/Command.cs | 4 +- .../ArgumentType/BotNameArgumentType.cs | 2 +- .../ArgumentType/HotbarSlotArgumentType.cs | 2 +- .../ArgumentType/InventoryIdArgumentType.cs | 2 +- .../ArgumentType/InventorySlotArgumentType.cs | 2 +- .../ArgumentType/LocationArgumentType.cs | 2 +- .../ArgumentType/MapBotMapIdArgumentType.cs | 2 +- .../ArgumentType/PlayerNameArgumentType.cs | 2 +- MinecraftClient/CommandHandler/CmdResult.cs | 2 +- MinecraftClient/Commands/Animation.cs | 11 +-- MinecraftClient/Commands/Bed.cs | 17 +++-- MinecraftClient/Commands/BlockInfo.cs | 34 +++++---- MinecraftClient/Commands/Bots.cs | 14 ++-- MinecraftClient/Commands/ChangeSlot.cs | 7 +- MinecraftClient/Commands/Chunk.cs | 32 ++++---- MinecraftClient/Commands/Connect.cs | 8 +- MinecraftClient/Commands/Debug.cs | 2 +- MinecraftClient/Commands/Dig.cs | 12 +-- MinecraftClient/Commands/DropItem.cs | 7 +- MinecraftClient/Commands/Enchant.cs | 11 +-- MinecraftClient/Commands/Entitycmd.cs | 50 +++++++------ MinecraftClient/Commands/ExecIf.cs | 7 +- MinecraftClient/Commands/ExecMulti.cs | 7 +- MinecraftClient/Commands/Exit.cs | 2 +- MinecraftClient/Commands/Health.cs | 7 +- MinecraftClient/Commands/Help.cs | 7 +- MinecraftClient/Commands/Inventory.cs | 75 +++++++++++-------- MinecraftClient/Commands/List.cs | 7 +- MinecraftClient/Commands/Log.cs | 2 +- MinecraftClient/Commands/Look.cs | 32 ++++---- MinecraftClient/Commands/Move.cs | 62 ++++++++------- MinecraftClient/Commands/Reco.cs | 4 +- MinecraftClient/Commands/Reload.cs | 7 +- MinecraftClient/Commands/Respawn.cs | 7 +- MinecraftClient/Commands/Script.cs | 7 +- MinecraftClient/Commands/Send.cs | 7 +- MinecraftClient/Commands/Set.cs | 2 +- MinecraftClient/Commands/SetRnd.cs | 2 +- MinecraftClient/Commands/Sneak.cs | 7 +- MinecraftClient/Commands/Tps.cs | 7 +- MinecraftClient/Commands/Upgrade.cs | 2 +- MinecraftClient/Commands/UseItem.cs | 7 +- MinecraftClient/Commands/Useblock.cs | 7 +- MinecraftClient/ConsoleIO.cs | 4 +- MinecraftClient/McClient.cs | 6 +- .../ConfigComments/ConfigComments.Designer.cs | 9 +++ .../ConfigComments/ConfigComments.resx | 3 + .../Translations/Translations.Designer.cs | 2 +- .../Resources/Translations/Translations.resx | 2 +- MinecraftClient/Scripting/ChatBot.cs | 2 +- MinecraftClient/Settings.cs | 5 ++ 62 files changed, 371 insertions(+), 297 deletions(-) diff --git a/MinecraftClient/ChatBots/AutoCraft.cs b/MinecraftClient/ChatBots/AutoCraft.cs index 890f235c..4e9b10a8 100644 --- a/MinecraftClient/ChatBots/AutoCraft.cs +++ b/MinecraftClient/ChatBots/AutoCraft.cs @@ -296,7 +296,7 @@ namespace MinecraftClient.ChatBots return; } - Handler.dispatcher.Register(l => l.Literal("help") + McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Then(l => l.Literal("list") @@ -310,7 +310,7 @@ namespace MinecraftClient.ChatBots ) ); - Handler.dispatcher.Register(l => l.Literal(CommandName) + McClient.dispatcher.Register(l => l.Literal(CommandName) .Then(l => l.Literal("list") .Executes(r => OnCommandList(r.Source))) .Then(l => l.Literal("start") @@ -319,14 +319,14 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("stop") .Executes(r => OnCommandStop(r.Source))) .Then(l => l.Literal("_help") - .Redirect(Handler.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } public override void OnUnload() { - Handler.dispatcher.Unregister(CommandName); - Handler.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + McClient.dispatcher.Unregister(CommandName); + McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } private int OnCommandHelp(CmdResult r, string? cmd) @@ -339,7 +339,7 @@ namespace MinecraftClient.ChatBots "stop" => Translations.bot_autoCraft_help_stop, "help" => Translations.bot_autoCraft_help_help, _ => string.Format(Translations.bot_autoCraft_available_cmd, "load, list, reload, resetcfg, start, stop, help") - + '\n' + Handler.dispatcher.GetAllUsageString(CommandName, false), + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); } diff --git a/MinecraftClient/ChatBots/AutoDig.cs b/MinecraftClient/ChatBots/AutoDig.cs index 49b9b44e..859ce35c 100644 --- a/MinecraftClient/ChatBots/AutoDig.cs +++ b/MinecraftClient/ChatBots/AutoDig.cs @@ -123,7 +123,7 @@ namespace MinecraftClient.ChatBots if (!inventoryEnabled && Config.Auto_Tool_Switch) LogToConsole(Translations.bot_autodig_no_inv_handle); - Handler.dispatcher.Register(l => l.Literal("help") + McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Then(l => l.Literal("start") @@ -135,25 +135,25 @@ namespace MinecraftClient.ChatBots ) ); - var cmd = Handler.dispatcher.Register(l => l.Literal(CommandName) + var cmd = McClient.dispatcher.Register(l => l.Literal(CommandName) .Then(l => l.Literal("start") .Executes(r => OnCommandStart(r.Source))) .Then(l => l.Literal("stop") .Executes(r => OnCommandStop(r.Source))) .Then(l => l.Literal("_help") - .Redirect(Handler.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); - Handler.dispatcher.Register(l => l.Literal("digbot") + McClient.dispatcher.Register(l => l.Literal("digbot") .Redirect(cmd) ); } public override void OnUnload() { - Handler.dispatcher.Unregister("digbot"); - Handler.dispatcher.Unregister(CommandName); - Handler.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + McClient.dispatcher.Unregister("digbot"); + McClient.dispatcher.Unregister(CommandName); + McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } private int OnCommandHelp(CmdResult r, string? cmd) @@ -165,7 +165,7 @@ namespace MinecraftClient.ChatBots "stop" => Translations.bot_autodig_help_stop, "help" => Translations.bot_autodig_help_help, _ => string.Format(Translations.bot_autodig_available_cmd, "start, stop, help") - + '\n' + Handler.dispatcher.GetAllUsageString(CommandName, false), + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); } diff --git a/MinecraftClient/ChatBots/AutoDrop.cs b/MinecraftClient/ChatBots/AutoDrop.cs index 7dea2c18..5a301830 100644 --- a/MinecraftClient/ChatBots/AutoDrop.cs +++ b/MinecraftClient/ChatBots/AutoDrop.cs @@ -54,7 +54,7 @@ namespace MinecraftClient.ChatBots return; } - Handler.dispatcher.Register(l => l.Literal("help") + McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Then(l => l.Literal("add") @@ -66,7 +66,7 @@ namespace MinecraftClient.ChatBots ) ); - Handler.dispatcher.Register(l => l.Literal(CommandName) + McClient.dispatcher.Register(l => l.Literal(CommandName) .Then(l => l.Literal("on") .Executes(r => OnCommandEnable(r.Source, true))) .Then(l => l.Literal("off") @@ -87,14 +87,14 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("everything") .Executes(r => OnCommandMode(r.Source, DropMode.everything)))) .Then(l => l.Literal("_help") - .Redirect(Handler.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } public override void OnUnload() { - Handler.dispatcher.Unregister(CommandName); - Handler.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + McClient.dispatcher.Unregister(CommandName); + McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } private int OnCommandHelp(CmdResult r, string? cmd) @@ -106,7 +106,7 @@ namespace MinecraftClient.ChatBots "remove" => Translations.cmd_inventory_help_usage + ": remove ", "mode" => Translations.bot_autoDrop_unknown_mode, _ => string.Format(Translations.general_available_cmd, "on, off, add, remove, list, mode") - + '\n' + Handler.dispatcher.GetAllUsageString(CommandName, false), + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); } diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index 28886bfd..ff028536 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -187,7 +187,7 @@ namespace MinecraftClient.ChatBots if (!inventoryEnabled) LogToConsole(Translations.bot_autoFish_no_inv_handle); - Handler.dispatcher.Register(l => l.Literal("help") + McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Then(l => l.Literal("start") @@ -201,7 +201,7 @@ namespace MinecraftClient.ChatBots ) ); - Handler.dispatcher.Register(l => l.Literal(CommandName) + McClient.dispatcher.Register(l => l.Literal(CommandName) .Then(l => l.Literal("start") .Executes(r => OnCommandStart(r.Source))) .Then(l => l.Literal("stop") @@ -211,14 +211,14 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("clear") .Executes(r => OnCommandStatusClear(r.Source)))) .Then(l => l.Literal("_help") - .Redirect(Handler.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } public override void OnUnload() { - Handler.dispatcher.Unregister(CommandName); - Handler.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + McClient.dispatcher.Unregister(CommandName); + McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } private int OnCommandHelp(CmdResult r, string? cmd) @@ -231,7 +231,7 @@ namespace MinecraftClient.ChatBots "status" => Translations.bot_autoFish_help_status, "help" => Translations.bot_autoFish_help_help, _ => string.Format(Translations.bot_autoFish_available_cmd, "start, stop, status, help") - + '\n' + Handler.dispatcher.GetAllUsageString(CommandName, false), + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); } diff --git a/MinecraftClient/ChatBots/DiscordBridge.cs b/MinecraftClient/ChatBots/DiscordBridge.cs index c9aa29a2..a3280bf4 100644 --- a/MinecraftClient/ChatBots/DiscordBridge.cs +++ b/MinecraftClient/ChatBots/DiscordBridge.cs @@ -76,13 +76,13 @@ namespace MinecraftClient.ChatBots public override void Initialize() { - Handler.dispatcher.Register(l => l.Literal("help") + McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) .Executes(r => OnCommandHelp(r.Source, string.Empty)) ) ); - Handler.dispatcher.Register(l => l.Literal(CommandName) + McClient.dispatcher.Register(l => l.Literal(CommandName) .Then(l => l.Literal("direction") .Then(l => l.Literal("both") .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Both))) @@ -92,7 +92,7 @@ namespace MinecraftClient.ChatBots .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Discord))) ) .Then(l => l.Literal("_help") - .Redirect(Handler.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); Task.Run(async () => await MainAsync()); @@ -100,8 +100,8 @@ namespace MinecraftClient.ChatBots public override void OnUnload() { - Handler.dispatcher.Unregister(CommandName); - Handler.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + McClient.dispatcher.Unregister(CommandName); + McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); Disconnect(); } @@ -111,7 +111,7 @@ namespace MinecraftClient.ChatBots { #pragma warning disable format // @formatter:off _ => "dscbridge direction " - + '\n' + Handler.dispatcher.GetAllUsageString(CommandName, false), + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); } diff --git a/MinecraftClient/ChatBots/Farmer.cs b/MinecraftClient/ChatBots/Farmer.cs index 64373ed8..2bb11817 100644 --- a/MinecraftClient/ChatBots/Farmer.cs +++ b/MinecraftClient/ChatBots/Farmer.cs @@ -90,13 +90,13 @@ namespace MinecraftClient.ChatBots return; } - Handler.dispatcher.Register(l => l.Literal("help") + McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) .Executes(r => OnCommandHelp(r.Source, string.Empty)) ) ); - Handler.dispatcher.Register(l => l.Literal(CommandName) + McClient.dispatcher.Register(l => l.Literal(CommandName) .Then(l => l.Literal("stop") .Executes(r => OnCommandStop(r.Source))) .Then(l => l.Literal("start") @@ -105,14 +105,14 @@ namespace MinecraftClient.ChatBots .Then(l => l.Argument("OtherArgs", Arguments.GreedyString()) .Executes(r => OnCommandStart(r.Source, MccArguments.GetFarmerCropType(r, "CropType"), Arguments.GetString(r, "OtherArgs")))))) .Then(l => l.Literal("_help") - .Redirect(Handler.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } public override void OnUnload() { - Handler.dispatcher.Unregister(CommandName); - Handler.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + McClient.dispatcher.Unregister(CommandName); + McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } private int OnCommandHelp(CmdResult r, string? cmd) @@ -121,7 +121,7 @@ namespace MinecraftClient.ChatBots { #pragma warning disable format // @formatter:off _ => Translations.bot_farmer_desc + ": " + commandDescription - + '\n' + Handler.dispatcher.GetAllUsageString(CommandName, false), + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); } diff --git a/MinecraftClient/ChatBots/FollowPlayer.cs b/MinecraftClient/ChatBots/FollowPlayer.cs index 4ff6695a..cf707699 100644 --- a/MinecraftClient/ChatBots/FollowPlayer.cs +++ b/MinecraftClient/ChatBots/FollowPlayer.cs @@ -62,13 +62,13 @@ namespace MinecraftClient.ChatBots return; } - Handler.dispatcher.Register(l => l.Literal("help") + McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) .Executes(r => OnCommandHelp(r.Source, string.Empty)) ) ); - Handler.dispatcher.Register(l => l.Literal(CommandName) + McClient.dispatcher.Register(l => l.Literal(CommandName) .Then(l => l.Literal("start") .Then(l => l.Argument("PlayerName", MccArguments.PlayerName()) .Executes(r => OnCommandStart(r.Source, Arguments.GetString(r, "PlayerName"), takeRisk: false)) @@ -77,14 +77,14 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("stop") .Executes(r => OnCommandStop(r.Source))) .Then(l => l.Literal("_help") - .Redirect(Handler.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } public override void OnUnload() { - Handler.dispatcher.Unregister(CommandName); - Handler.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + McClient.dispatcher.Unregister(CommandName); + McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } private int OnCommandHelp(CmdResult r, string? cmd) @@ -93,7 +93,7 @@ namespace MinecraftClient.ChatBots { #pragma warning disable format // @formatter:off _ => Translations.cmd_follow_desc + ": " + Translations.cmd_follow_usage - + '\n' + Handler.dispatcher.GetAllUsageString(CommandName, false), + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); } diff --git a/MinecraftClient/ChatBots/Mailer.cs b/MinecraftClient/ChatBots/Mailer.cs index 8ef5c1d1..aba382d8 100644 --- a/MinecraftClient/ChatBots/Mailer.cs +++ b/MinecraftClient/ChatBots/Mailer.cs @@ -257,12 +257,12 @@ namespace MinecraftClient.ChatBots mailDbFileMonitor = new FileMonitor(Path.GetDirectoryName(Config.DatabaseFile)!, Path.GetFileName(Config.DatabaseFile), FileMonitorCallback); ignoreListFileMonitor = new FileMonitor(Path.GetDirectoryName(Config.IgnoreListFile)!, Path.GetFileName(Config.IgnoreListFile), FileMonitorCallback); - Handler.dispatcher.Register(l => l.Literal("help") + McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) .Executes(r => OnCommandHelp(string.Empty))) ); - Handler.dispatcher.Register(l => l.Literal(CommandName) + McClient.dispatcher.Register(l => l.Literal(CommandName) .Then(l => l.Literal("getmails") .Executes(r => OnCommandGetMails())) .Then(l => l.Literal("getignored") @@ -274,14 +274,14 @@ namespace MinecraftClient.ChatBots .Then(l => l.Argument("username", Arguments.String()) .Executes(r => OnCommandRemoveIgnored(Arguments.GetString(r, "username"))))) .Then(l => l.Literal("_help") - .Redirect(Handler.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } public override void OnUnload() { - Handler.dispatcher.Unregister(CommandName); - Handler.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + McClient.dispatcher.Unregister(CommandName); + McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } private int OnCommandHelp(string cmd) @@ -290,7 +290,7 @@ namespace MinecraftClient.ChatBots { #pragma warning disable format // @formatter:off _ => Translations.bot_mailer_cmd_help + ": /mailer " - + '\n' + Handler.dispatcher.GetAllUsageString(CommandName, false), + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); return 1; diff --git a/MinecraftClient/ChatBots/Map.cs b/MinecraftClient/ChatBots/Map.cs index 0839c2a8..4689c162 100644 --- a/MinecraftClient/ChatBots/Map.cs +++ b/MinecraftClient/ChatBots/Map.cs @@ -80,13 +80,13 @@ namespace MinecraftClient.ChatBots DeleteRenderedMaps(); - Handler.dispatcher.Register(l => l.Literal("help") + McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) .Executes(r => OnCommandHelp(r.Source, string.Empty)) ) ); - Handler.dispatcher.Register(l => l.Literal(CommandName) + McClient.dispatcher.Register(l => l.Literal(CommandName) .Executes(r => OnCommandList(r.Source)) .Then(l => l.Literal("list") .Executes(r => OnCommandList(r.Source))) @@ -94,14 +94,14 @@ namespace MinecraftClient.ChatBots .Then(l => l.Argument("MapID", MccArguments.MapBotMapId()) .Executes(r => OnCommandRender(r.Source, Arguments.GetInteger(r, "MapID"))))) .Then(l => l.Literal("_help") - .Redirect(Handler.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } public override void OnUnload() { - Handler.dispatcher.Unregister(CommandName); - Handler.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + McClient.dispatcher.Unregister(CommandName); + McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); DeleteRenderedMaps(); } @@ -111,7 +111,7 @@ namespace MinecraftClient.ChatBots { #pragma warning disable format // @formatter:off _ => Translations.error_usage + ": /maps >" - + '\n' + Handler.dispatcher.GetAllUsageString(CommandName, false), + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); } diff --git a/MinecraftClient/ChatBots/ReplayCapture.cs b/MinecraftClient/ChatBots/ReplayCapture.cs index 9db42ec2..f0a73a3a 100644 --- a/MinecraftClient/ChatBots/ReplayCapture.cs +++ b/MinecraftClient/ChatBots/ReplayCapture.cs @@ -46,26 +46,26 @@ namespace MinecraftClient.ChatBots replay.MetaData.serverName = GetServerHost() + GetServerPort(); backupCounter = Settings.DoubleToTick(Config.Backup_Interval); - Handler.dispatcher.Register(l => l.Literal("help") + McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) .Executes(r => OnCommandHelp(r.Source, string.Empty)) ) ); - Handler.dispatcher.Register(l => l.Literal(CommandName) + McClient.dispatcher.Register(l => l.Literal(CommandName) .Then(l => l.Literal("save") .Executes(r => OnCommandSave(r.Source))) .Then(l => l.Literal("stop") .Executes(r => OnCommandStop(r.Source))) .Then(l => l.Literal("_help") - .Redirect(Handler.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } public override void OnUnload() { - Handler.dispatcher.Unregister(CommandName); - Handler.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + McClient.dispatcher.Unregister(CommandName); + McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } private int OnCommandHelp(CmdResult r, string? cmd) @@ -74,7 +74,7 @@ namespace MinecraftClient.ChatBots { #pragma warning disable format // @formatter:off _ => string.Format(Translations.general_available_cmd, "save, stop") - + '\n' + Handler.dispatcher.GetAllUsageString(CommandName, false), + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); } diff --git a/MinecraftClient/ChatBots/TelegramBridge.cs b/MinecraftClient/ChatBots/TelegramBridge.cs index 392bc1cf..b92572db 100644 --- a/MinecraftClient/ChatBots/TelegramBridge.cs +++ b/MinecraftClient/ChatBots/TelegramBridge.cs @@ -76,13 +76,13 @@ namespace MinecraftClient.ChatBots public override void Initialize() { - Handler.dispatcher.Register(l => l.Literal("help") + McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) .Executes(r => OnCommandHelp(r.Source, string.Empty)) ) ); - Handler.dispatcher.Register(l => l.Literal(CommandName) + McClient.dispatcher.Register(l => l.Literal(CommandName) .Then(l => l.Literal("direction") .Then(l => l.Literal("both") .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Both))) @@ -91,7 +91,7 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("telegram") .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Telegram)))) .Then(l => l.Literal("_help") - .Redirect(Handler.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) + .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); Task.Run(async () => await MainAsync()); @@ -99,8 +99,8 @@ namespace MinecraftClient.ChatBots public override void OnUnload() { - Handler.dispatcher.Unregister(CommandName); - Handler.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); + McClient.dispatcher.Unregister(CommandName); + McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); Disconnect(); } @@ -110,7 +110,7 @@ namespace MinecraftClient.ChatBots { #pragma warning disable format // @formatter:off _ => Translations.error_usage + ": /tgbridge direction " - + '\n' + Handler.dispatcher.GetAllUsageString(CommandName, false), + + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); } diff --git a/MinecraftClient/Command.cs b/MinecraftClient/Command.cs index 796e56e0..e606f0dd 100644 --- a/MinecraftClient/Command.cs +++ b/MinecraftClient/Command.cs @@ -36,7 +36,7 @@ namespace MinecraftClient StringBuilder sb = new(); string s = (string.IsNullOrEmpty(CmdUsage) || string.IsNullOrEmpty(CmdDesc)) ? string.Empty : ": "; // If either one is empty, no colon : sb.Append("§e").Append(cmdChar).Append(CmdUsage).Append("§r").Append(s).AppendLine(CmdDesc); - sb.Append(CmdResult.client!.dispatcher.GetAllUsageString(CmdName, false)); + sb.Append(McClient.dispatcher.GetAllUsageString(CmdName, false)); return sb.ToString(); } @@ -48,7 +48,7 @@ namespace MinecraftClient /// /// Register the command. /// - public abstract void RegisterCommand(McClient handler, CommandDispatcher dispatcher); + public abstract void RegisterCommand(CommandDispatcher dispatcher); /// /// Check if at least one argument has been passed to the command diff --git a/MinecraftClient/CommandHandler/ArgumentType/BotNameArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/BotNameArgumentType.cs index 0681ae0d..1f49da98 100644 --- a/MinecraftClient/CommandHandler/ArgumentType/BotNameArgumentType.cs +++ b/MinecraftClient/CommandHandler/ArgumentType/BotNameArgumentType.cs @@ -16,7 +16,7 @@ namespace MinecraftClient.CommandHandler.ArgumentType public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) { - McClient? client = CmdResult.client; + McClient? client = CmdResult.currentHandler; if (client != null) { var botList = client.GetLoadedChatBots(); diff --git a/MinecraftClient/CommandHandler/ArgumentType/HotbarSlotArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/HotbarSlotArgumentType.cs index 16d07611..ebf05813 100644 --- a/MinecraftClient/CommandHandler/ArgumentType/HotbarSlotArgumentType.cs +++ b/MinecraftClient/CommandHandler/ArgumentType/HotbarSlotArgumentType.cs @@ -17,7 +17,7 @@ namespace MinecraftClient.CommandHandler.ArgumentType public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) { - McClient? client = CmdResult.client; + McClient? client = CmdResult.currentHandler; if (client != null) { Inventory.Container? inventory = client.GetInventory(0); diff --git a/MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs index 6c7ae2af..15164956 100644 --- a/MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs +++ b/MinecraftClient/CommandHandler/ArgumentType/InventoryIdArgumentType.cs @@ -17,7 +17,7 @@ namespace MinecraftClient.CommandHandler.ArgumentType public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) { - McClient? client = CmdResult.client; + McClient? client = CmdResult.currentHandler; if (client != null) { var invList = client.GetInventories(); diff --git a/MinecraftClient/CommandHandler/ArgumentType/InventorySlotArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/InventorySlotArgumentType.cs index ecc796ca..2536aa1e 100644 --- a/MinecraftClient/CommandHandler/ArgumentType/InventorySlotArgumentType.cs +++ b/MinecraftClient/CommandHandler/ArgumentType/InventorySlotArgumentType.cs @@ -18,7 +18,7 @@ namespace MinecraftClient.CommandHandler.ArgumentType public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) { - McClient? client = CmdResult.client; + McClient? client = CmdResult.currentHandler; if (client != null && context.Nodes.Count >= 2) { string invName = context.Nodes[1].Range.Get(builder.Input); diff --git a/MinecraftClient/CommandHandler/ArgumentType/LocationArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/LocationArgumentType.cs index 79f51d62..f2ef9b0a 100644 --- a/MinecraftClient/CommandHandler/ArgumentType/LocationArgumentType.cs +++ b/MinecraftClient/CommandHandler/ArgumentType/LocationArgumentType.cs @@ -47,7 +47,7 @@ namespace MinecraftClient.CommandHandler.ArgumentType public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) { - McClient? client = CmdResult.client; + McClient? client = CmdResult.currentHandler; string[] args = builder.Remaining.Split(' ', StringSplitOptions.TrimEntries); if (args.Length == 0 || (args.Length == 1 && string.IsNullOrWhiteSpace(args[0]))) { diff --git a/MinecraftClient/CommandHandler/ArgumentType/MapBotMapIdArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/MapBotMapIdArgumentType.cs index 55c05020..bd1ffee6 100644 --- a/MinecraftClient/CommandHandler/ArgumentType/MapBotMapIdArgumentType.cs +++ b/MinecraftClient/CommandHandler/ArgumentType/MapBotMapIdArgumentType.cs @@ -18,7 +18,7 @@ namespace MinecraftClient.CommandHandler.ArgumentType public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) { - McClient? client = CmdResult.client; + McClient? client = CmdResult.currentHandler; if (client != null) { var bot = (Map?)client.GetLoadedChatBots().Find(bot => bot.GetType().Name == "Map"); diff --git a/MinecraftClient/CommandHandler/ArgumentType/PlayerNameArgumentType.cs b/MinecraftClient/CommandHandler/ArgumentType/PlayerNameArgumentType.cs index d8b88093..b5092251 100644 --- a/MinecraftClient/CommandHandler/ArgumentType/PlayerNameArgumentType.cs +++ b/MinecraftClient/CommandHandler/ArgumentType/PlayerNameArgumentType.cs @@ -18,7 +18,7 @@ namespace MinecraftClient.CommandHandler.ArgumentType public override Task ListSuggestions(CommandContext context, SuggestionsBuilder builder) { - McClient? client = CmdResult.client; + McClient? client = CmdResult.currentHandler; if (client != null) { var entityList = client.GetEntities().Values.ToList(); diff --git a/MinecraftClient/CommandHandler/CmdResult.cs b/MinecraftClient/CommandHandler/CmdResult.cs index b5477763..4be40a4a 100644 --- a/MinecraftClient/CommandHandler/CmdResult.cs +++ b/MinecraftClient/CommandHandler/CmdResult.cs @@ -6,7 +6,7 @@ namespace MinecraftClient.CommandHandler { public static readonly CmdResult Empty = new(); - internal static McClient? client; + internal static McClient? currentHandler; public enum Status { diff --git a/MinecraftClient/Commands/Animation.cs b/MinecraftClient/Commands/Animation.cs index 41f7affe..f5290e3e 100644 --- a/MinecraftClient/Commands/Animation.cs +++ b/MinecraftClient/Commands/Animation.cs @@ -10,7 +10,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "animation "; } } public override string CmdDesc { get { return Translations.cmd_animation_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -23,11 +23,11 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => DoAnimation(r.Source, handler, mainhand: true)) + .Executes(r => DoAnimation(r.Source, mainhand: true)) .Then(l => l.Literal("mainhand") - .Executes(r => DoAnimation(r.Source, handler, mainhand: true))) + .Executes(r => DoAnimation(r.Source, mainhand: true))) .Then(l => l.Literal("offhand") - .Executes(r => DoAnimation(r.Source, handler, mainhand: false))) + .Executes(r => DoAnimation(r.Source, mainhand: false))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -45,8 +45,9 @@ namespace MinecraftClient.Commands }); } - private static int DoAnimation(CmdResult r, McClient handler, bool mainhand) + private static int DoAnimation(CmdResult r, bool mainhand) { + McClient handler = CmdResult.currentHandler!; return r.SetAndReturn(handler.DoAnimation(mainhand ? 1 : 0)); } } diff --git a/MinecraftClient/Commands/Bed.cs b/MinecraftClient/Commands/Bed.cs index fa6e6958..fbeb15fb 100644 --- a/MinecraftClient/Commands/Bed.cs +++ b/MinecraftClient/Commands/Bed.cs @@ -16,7 +16,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "bed leave|sleep |sleep "; } } public override string CmdDesc { get { return Translations.cmd_bed_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -30,12 +30,12 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Literal("leave") - .Executes(r => DoLeaveBed(r.Source, handler))) + .Executes(r => DoLeaveBed(r.Source))) .Then(l => l.Literal("sleep") .Then(l => l.Argument("Location", MccArguments.Location()) - .Executes(r => DoSleepBedWithLocation(r.Source, handler, MccArguments.GetLocation(r, "Location")))) + .Executes(r => DoSleepBedWithLocation(r.Source, MccArguments.GetLocation(r, "Location")))) .Then(l => l.Argument("Radius", Arguments.Double()) - .Executes(r => DoSleepBedWithRadius(r.Source, handler, Arguments.GetDouble(r, "Radius"))))) + .Executes(r => DoSleepBedWithRadius(r.Source, Arguments.GetDouble(r, "Radius"))))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -53,13 +53,15 @@ namespace MinecraftClient.Commands }); } - private static int DoLeaveBed(CmdResult r, McClient handler) + private static int DoLeaveBed(CmdResult r) { + McClient handler = CmdResult.currentHandler!; return r.SetAndReturn(Translations.cmd_bed_leaving, handler.SendEntityAction(Protocol.EntityActionType.LeaveBed)); } - private static int DoSleepBedWithRadius(CmdResult r, McClient handler, double radius) + private static int DoSleepBedWithRadius(CmdResult r, double radius) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); @@ -153,8 +155,9 @@ namespace MinecraftClient.Commands } } - private static int DoSleepBedWithLocation(CmdResult r, McClient handler, Location block) + private static int DoSleepBedWithLocation(CmdResult r, Location block) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); diff --git a/MinecraftClient/Commands/BlockInfo.cs b/MinecraftClient/Commands/BlockInfo.cs index dcc82d61..7ced900b 100644 --- a/MinecraftClient/Commands/BlockInfo.cs +++ b/MinecraftClient/Commands/BlockInfo.cs @@ -13,7 +13,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "blockinfo [-s]"; } } public override string CmdDesc { get { return Translations.cmd_blockinfo_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -24,13 +24,13 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => LogBlockInfo(r.Source, handler, handler.GetCurrentLocation(), false)) + .Executes(r => LogBlockInfo(r.Source, null, false)) .Then(l => l.Literal("-s") - .Executes(r => LogBlockInfo(r.Source, handler, handler.GetCurrentLocation(), true))) + .Executes(r => LogBlockInfo(r.Source, null, true))) .Then(l => l.Argument("Location", MccArguments.Location()) - .Executes(r => LogBlockInfo(r.Source, handler, MccArguments.GetLocation(r, "Location"), false)) + .Executes(r => LogBlockInfo(r.Source, MccArguments.GetLocation(r, "Location"), false)) .Then(l => l.Literal("-s") - .Executes(r => LogBlockInfo(r.Source, handler, MccArguments.GetLocation(r, "Location"), true)))) + .Executes(r => LogBlockInfo(r.Source, MccArguments.GetLocation(r, "Location"), true)))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -47,13 +47,18 @@ namespace MinecraftClient.Commands }); } - private static int LogBlockInfo(CmdResult r, McClient handler, Location targetBlock, bool reportSurrounding) + private static int LogBlockInfo(CmdResult r, Location? targetBlock, bool reportSurrounding) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); - targetBlock.ToAbsolute(handler.GetCurrentLocation()); - Block block = handler.GetWorld().GetBlock(targetBlock); + if (targetBlock.HasValue) + targetBlock.Value.ToAbsolute(handler.GetCurrentLocation()); + else + targetBlock = handler.GetCurrentLocation(); + + Block block = handler.GetWorld().GetBlock(targetBlock.Value); handler.Log.Info($"{Translations.cmd_blockinfo_BlockType}: {block.GetTypeString()}"); if (reportSurrounding) @@ -61,12 +66,13 @@ namespace MinecraftClient.Commands StringBuilder sb = new(); sb.AppendLine($"{Translations.cmd_blockinfo_BlocksAround}:"); - Block blockXPositive = handler.GetWorld().GetBlock(new Location(targetBlock.X + 1, targetBlock.Y, targetBlock.Z)); - Block blockXNegative = handler.GetWorld().GetBlock(new Location(targetBlock.X - 1, targetBlock.Y, targetBlock.Z)); - Block blockYPositive = handler.GetWorld().GetBlock(new Location(targetBlock.X, targetBlock.Y + 1, targetBlock.Z)); - Block blockYNegative = handler.GetWorld().GetBlock(new Location(targetBlock.X, targetBlock.Y - 1, targetBlock.Z)); - Block blockZPositive = handler.GetWorld().GetBlock(new Location(targetBlock.X, targetBlock.Y, targetBlock.Z + 1)); - Block blockZNegative = handler.GetWorld().GetBlock(new Location(targetBlock.X, targetBlock.Y, targetBlock.Z - 1)); + double X = targetBlock.Value.X, Y = targetBlock.Value.Y, Z = targetBlock.Value.Z; + Block blockXPositive = handler.GetWorld().GetBlock(new Location(X + 1, Y, Z)); + Block blockXNegative = handler.GetWorld().GetBlock(new Location(X - 1, Y, Z)); + Block blockYPositive = handler.GetWorld().GetBlock(new Location(X, Y + 1, Z)); + Block blockYNegative = handler.GetWorld().GetBlock(new Location(X, Y - 1, Z)); + Block blockZPositive = handler.GetWorld().GetBlock(new Location(X, Y, Z + 1)); + Block blockZNegative = handler.GetWorld().GetBlock(new Location(X, Y, Z - 1)); sb.AppendLine($"[X {Translations.cmd_blockinfo_Positive}] {Translations.cmd_blockinfo_BlockType}: {blockXPositive.GetTypeString()}"); sb.AppendLine($"[X {Translations.cmd_blockinfo_Negative}] {Translations.cmd_blockinfo_BlockType}: {blockXNegative.GetTypeString()}"); diff --git a/MinecraftClient/Commands/Bots.cs b/MinecraftClient/Commands/Bots.cs index 60e0b41c..da9250e4 100644 --- a/MinecraftClient/Commands/Bots.cs +++ b/MinecraftClient/Commands/Bots.cs @@ -13,7 +13,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "bots [list|unload ]"; } } public override string CmdDesc { get { return Translations.cmd_bots_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -26,12 +26,12 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => DoListBot(r.Source, handler)) + .Executes(r => DoListBot(r.Source)) .Then(l => l.Literal("list") - .Executes(r => DoListBot(r.Source, handler))) + .Executes(r => DoListBot(r.Source))) .Then(l => l.Literal("unload") .Then(l => l.Argument("BotName", MccArguments.BotName()) - .Executes(r => DoUnloadBot(r.Source, handler, Arguments.GetString(r, "BotName"))))) + .Executes(r => DoUnloadBot(r.Source, Arguments.GetString(r, "BotName"))))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -49,8 +49,9 @@ namespace MinecraftClient.Commands }); } - private int DoListBot(CmdResult r, McClient handler) + private int DoListBot(CmdResult r) { + McClient handler = CmdResult.currentHandler!; int length = handler.GetLoadedChatBots().Count; if (length == 0) return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_bots_noloaded); @@ -66,8 +67,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_bots_list + ": " + sb.ToString()); } - private int DoUnloadBot(CmdResult r, McClient handler, string botName) + private int DoUnloadBot(CmdResult r, string botName) { + McClient handler = CmdResult.currentHandler!; if (botName.ToLower().Equals("all", StringComparison.OrdinalIgnoreCase)) { if (handler.GetLoadedChatBots().Count == 0) diff --git a/MinecraftClient/Commands/ChangeSlot.cs b/MinecraftClient/Commands/ChangeSlot.cs index 0353fe1e..d7631f65 100644 --- a/MinecraftClient/Commands/ChangeSlot.cs +++ b/MinecraftClient/Commands/ChangeSlot.cs @@ -11,7 +11,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "changeslot <1-9>"; } } public override string CmdDesc { get { return Translations.cmd_changeSlot_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -21,7 +21,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Argument("Slot", MccArguments.HotbarSlot()) - .Executes(r => DoChangeSlot(r.Source, handler, Arguments.GetInteger(r, "Slot")))) + .Executes(r => DoChangeSlot(r.Source, Arguments.GetInteger(r, "Slot")))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -37,8 +37,9 @@ namespace MinecraftClient.Commands }); } - private int DoChangeSlot(CmdResult r, McClient handler, int slot) + private int DoChangeSlot(CmdResult r, int slot) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(Status.FailNeedInventory); diff --git a/MinecraftClient/Commands/Chunk.cs b/MinecraftClient/Commands/Chunk.cs index 5d225db1..58380c9e 100644 --- a/MinecraftClient/Commands/Chunk.cs +++ b/MinecraftClient/Commands/Chunk.cs @@ -14,7 +14,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "chunk status [chunkX chunkZ|locationX locationY locationZ]"; } } public override string CmdDesc { get { return Translations.cmd_chunk_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -32,26 +32,26 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Literal("status") - .Executes(r => LogChunkStatus(r.Source, handler)) + .Executes(r => LogChunkStatus(r.Source)) .Then(l => l.Argument("Location", MccArguments.Location()) - .Executes(r => LogChunkStatus(r.Source, handler, pos: MccArguments.GetLocation(r, "Location")))) + .Executes(r => LogChunkStatus(r.Source, pos: MccArguments.GetLocation(r, "Location")))) .Then(l => l.Argument("Chunk", MccArguments.Tuple()) - .Executes(r => LogChunkStatus(r.Source, handler, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) + .Executes(r => LogChunkStatus(r.Source, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) .Then(l => l.Literal("_setloading") .Then(l => l.Argument("Location", MccArguments.Location()) - .Executes(r => DebugSetLoading(r.Source, handler, pos: MccArguments.GetLocation(r, "Location")))) + .Executes(r => DebugSetLoading(r.Source, pos: MccArguments.GetLocation(r, "Location")))) .Then(l => l.Argument("Chunk", MccArguments.Tuple()) - .Executes(r => DebugSetLoading(r.Source, handler, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) + .Executes(r => DebugSetLoading(r.Source, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) .Then(l => l.Literal("_setloaded") .Then(l => l.Argument("Location", MccArguments.Location()) - .Executes(r => DebugSetLoaded(r.Source, handler, pos: MccArguments.GetLocation(r, "Location")))) + .Executes(r => DebugSetLoaded(r.Source, pos: MccArguments.GetLocation(r, "Location")))) .Then(l => l.Argument("Chunk", MccArguments.Tuple()) - .Executes(r => DebugSetLoaded(r.Source, handler, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) + .Executes(r => DebugSetLoaded(r.Source, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) .Then(l => l.Literal("_delete") .Then(l => l.Argument("Location", MccArguments.Location()) - .Executes(r => DebugDelete(r.Source, handler, pos: MccArguments.GetLocation(r, "Location")))) + .Executes(r => DebugDelete(r.Source, pos: MccArguments.GetLocation(r, "Location")))) .Then(l => l.Argument("Chunk", MccArguments.Tuple()) - .Executes(r => DebugDelete(r.Source, handler, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) + .Executes(r => DebugDelete(r.Source, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -71,8 +71,9 @@ namespace MinecraftClient.Commands }); } - private static int LogChunkStatus(CmdResult r, McClient handler, Location? pos = null, Tuple? markedChunkPos = null) + private static int LogChunkStatus(CmdResult r, Location? pos = null, Tuple? markedChunkPos = null) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); @@ -225,8 +226,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Done); } - private static int DebugSetLoading(CmdResult r, McClient handler, Location? pos = null, Tuple? markedChunkPos = null) + private static int DebugSetLoading(CmdResult r, Location? pos = null, Tuple? markedChunkPos = null) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); @@ -244,8 +246,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Done, string.Format("Successfully marked chunk ({0}, {1}) as loading.", chunkX, chunkZ)); } - private static int DebugSetLoaded(CmdResult r, McClient handler, Location? pos = null, Tuple? markedChunkPos = null) + private static int DebugSetLoaded(CmdResult r, Location? pos = null, Tuple? markedChunkPos = null) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); @@ -263,8 +266,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Done, string.Format("Successfully marked chunk ({0}, {1}) as loaded.", chunkX, chunkZ)); } - private static int DebugDelete(CmdResult r, McClient handler, Location? pos = null, Tuple? markedChunkPos = null) + private static int DebugDelete(CmdResult r, Location? pos = null, Tuple? markedChunkPos = null) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); diff --git a/MinecraftClient/Commands/Connect.cs b/MinecraftClient/Commands/Connect.cs index 79892fc4..0224c528 100644 --- a/MinecraftClient/Commands/Connect.cs +++ b/MinecraftClient/Commands/Connect.cs @@ -11,7 +11,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "connect [account]"; } } public override string CmdDesc { get { return Translations.cmd_connect_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -21,9 +21,9 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Argument("ServerNick", MccArguments.ServerNick()) - .Executes(r => DoConnect(r.Source, handler, Arguments.GetString(r, "ServerNick"), string.Empty)) + .Executes(r => DoConnect(r.Source, Arguments.GetString(r, "ServerNick"), string.Empty)) .Then(l => l.Argument("AccountNick", MccArguments.AccountNick()) - .Executes(r => DoConnect(r.Source, handler, Arguments.GetString(r, "ServerNick"), Arguments.GetString(r, "AccountNick"))))) + .Executes(r => DoConnect(r.Source, Arguments.GetString(r, "ServerNick"), Arguments.GetString(r, "AccountNick"))))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -39,7 +39,7 @@ namespace MinecraftClient.Commands }); } - private int DoConnect(CmdResult r, McClient handler, string server, string account) + private int DoConnect(CmdResult r, string server, string account) { if (!string.IsNullOrWhiteSpace(account) && !Settings.Config.Main.Advanced.SetAccount(account)) return r.SetAndReturn(Status.Fail, string.Format(Translations.cmd_connect_unknown, account)); diff --git a/MinecraftClient/Commands/Debug.cs b/MinecraftClient/Commands/Debug.cs index acb6f7e9..3517505a 100644 --- a/MinecraftClient/Commands/Debug.cs +++ b/MinecraftClient/Commands/Debug.cs @@ -10,7 +10,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "debug [on|off]"; } } public override string CmdDesc { get { return Translations.cmd_debug_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) diff --git a/MinecraftClient/Commands/Dig.cs b/MinecraftClient/Commands/Dig.cs index 2903a817..80bf946f 100644 --- a/MinecraftClient/Commands/Dig.cs +++ b/MinecraftClient/Commands/Dig.cs @@ -13,7 +13,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "dig "; } } public override string CmdDesc { get { return Translations.cmd_dig_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -22,9 +22,9 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => DigLookAt(r.Source, handler)) + .Executes(r => DigLookAt(r.Source)) .Then(l => l.Argument("Location", MccArguments.Location()) - .Executes(r => DigAt(r.Source, handler, MccArguments.GetLocation(r, "Location")))) + .Executes(r => DigAt(r.Source, MccArguments.GetLocation(r, "Location")))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -40,8 +40,9 @@ namespace MinecraftClient.Commands }); } - private int DigAt(CmdResult r, McClient handler, Location blockToBreak) + private int DigAt(CmdResult r, Location blockToBreak) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); @@ -61,8 +62,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Fail, Translations.cmd_dig_fail); } - private int DigLookAt(CmdResult r, McClient handler) + private int DigLookAt(CmdResult r) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); diff --git a/MinecraftClient/Commands/DropItem.cs b/MinecraftClient/Commands/DropItem.cs index 01e9ecb1..2ee05f0c 100644 --- a/MinecraftClient/Commands/DropItem.cs +++ b/MinecraftClient/Commands/DropItem.cs @@ -14,7 +14,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "dropitem "; } } public override string CmdDesc { get { return Translations.cmd_dropItem_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -24,7 +24,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Argument("ItemType", MccArguments.ItemType()) - .Executes(r => DoDropItem(r.Source, handler, MccArguments.GetItemType(r, "ItemType")))) + .Executes(r => DoDropItem(r.Source, MccArguments.GetItemType(r, "ItemType")))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -40,8 +40,9 @@ namespace MinecraftClient.Commands }); } - private int DoDropItem(CmdResult r, McClient handler, ItemType itemType) + private int DoDropItem(CmdResult r, ItemType itemType) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); diff --git a/MinecraftClient/Commands/Enchant.cs b/MinecraftClient/Commands/Enchant.cs index bc7c7e10..74e5a5ab 100644 --- a/MinecraftClient/Commands/Enchant.cs +++ b/MinecraftClient/Commands/Enchant.cs @@ -12,7 +12,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "enchant "; } } public override string CmdDesc { get { return Translations.cmd_enchant_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -28,11 +28,11 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Literal("top") - .Executes(r => DoEnchant(r.Source, handler, slotId: 0))) + .Executes(r => DoEnchant(r.Source, slotId: 0))) .Then(l => l.Literal("middle") - .Executes(r => DoEnchant(r.Source, handler, slotId: 1))) + .Executes(r => DoEnchant(r.Source, slotId: 1))) .Then(l => l.Literal("bottom") - .Executes(r => DoEnchant(r.Source, handler, slotId: 2))) + .Executes(r => DoEnchant(r.Source, slotId: 2))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -51,8 +51,9 @@ namespace MinecraftClient.Commands }); } - private int DoEnchant(CmdResult r, McClient handler, int slotId) + private int DoEnchant(CmdResult r, int slotId) { + McClient handler = CmdResult.currentHandler!; Container? enchantingTable = null; foreach (var (id, container) in handler.GetInventories()) diff --git a/MinecraftClient/Commands/Entitycmd.cs b/MinecraftClient/Commands/Entitycmd.cs index 0af7c1de..19f5fefe 100644 --- a/MinecraftClient/Commands/Entitycmd.cs +++ b/MinecraftClient/Commands/Entitycmd.cs @@ -19,7 +19,7 @@ namespace MinecraftClient.Commands private enum ActionType { Attack, Use, List }; - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -36,41 +36,41 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => GetFullEntityList(r.Source, handler)) + .Executes(r => GetFullEntityList(r.Source)) .Then(l => l.Literal("near") - .Executes(r => GetClosetEntityList(r.Source, handler)) + .Executes(r => GetClosetEntityList(r.Source)) .Then(l => l.Argument("EntityID", Arguments.Integer()) - .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.List)) + .Executes(r => OperateWithId(r.Source, Arguments.GetInteger(r, "EntityID"), ActionType.List)) .Then(l => l.Literal("attack") - .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.Attack))) + .Executes(r => OperateWithId(r.Source, Arguments.GetInteger(r, "EntityID"), ActionType.Attack))) .Then(l => l.Literal("use") - .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.Use))) + .Executes(r => OperateWithId(r.Source, Arguments.GetInteger(r, "EntityID"), ActionType.Use))) .Then(l => l.Literal("list") - .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.List)))) + .Executes(r => OperateWithId(r.Source, Arguments.GetInteger(r, "EntityID"), ActionType.List)))) .Then(l => l.Argument("EntityType", MccArguments.EntityType()) - .Executes(r => OperateWithType(r.Source, handler, true, MccArguments.GetEntityType(r, "EntityType"), ActionType.List)) + .Executes(r => OperateWithType(r.Source, true, MccArguments.GetEntityType(r, "EntityType"), ActionType.List)) .Then(l => l.Literal("attack") - .Executes(r => OperateWithType(r.Source, handler, near: true, MccArguments.GetEntityType(r, "EntityType"), ActionType.Attack))) + .Executes(r => OperateWithType(r.Source, near: true, MccArguments.GetEntityType(r, "EntityType"), ActionType.Attack))) .Then(l => l.Literal("use") - .Executes(r => OperateWithType(r.Source, handler, near: true, MccArguments.GetEntityType(r, "EntityType"), ActionType.Use))) + .Executes(r => OperateWithType(r.Source, near: true, MccArguments.GetEntityType(r, "EntityType"), ActionType.Use))) .Then(l => l.Literal("list") - .Executes(r => OperateWithType(r.Source, handler, near: true, MccArguments.GetEntityType(r, "EntityType"), ActionType.List))))) + .Executes(r => OperateWithType(r.Source, near: true, MccArguments.GetEntityType(r, "EntityType"), ActionType.List))))) .Then(l => l.Argument("EntityID", Arguments.Integer()) - .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.List)) + .Executes(r => OperateWithId(r.Source, Arguments.GetInteger(r, "EntityID"), ActionType.List)) .Then(l => l.Literal("attack") - .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.Attack))) + .Executes(r => OperateWithId(r.Source, Arguments.GetInteger(r, "EntityID"), ActionType.Attack))) .Then(l => l.Literal("use") - .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.Use))) + .Executes(r => OperateWithId(r.Source, Arguments.GetInteger(r, "EntityID"), ActionType.Use))) .Then(l => l.Literal("list") - .Executes(r => OperateWithId(r.Source, handler, Arguments.GetInteger(r, "EntityID"), ActionType.List)))) + .Executes(r => OperateWithId(r.Source, Arguments.GetInteger(r, "EntityID"), ActionType.List)))) .Then(l => l.Argument("EntityType", MccArguments.EntityType()) - .Executes(r => OperateWithType(r.Source, handler, true, MccArguments.GetEntityType(r, "EntityType"), ActionType.List)) + .Executes(r => OperateWithType(r.Source, true, MccArguments.GetEntityType(r, "EntityType"), ActionType.List)) .Then(l => l.Literal("attack") - .Executes(r => OperateWithType(r.Source, handler, near: false, MccArguments.GetEntityType(r, "EntityType"), ActionType.Attack))) + .Executes(r => OperateWithType(r.Source, near: false, MccArguments.GetEntityType(r, "EntityType"), ActionType.Attack))) .Then(l => l.Literal("use") - .Executes(r => OperateWithType(r.Source, handler, near: false, MccArguments.GetEntityType(r, "EntityType"), ActionType.Use))) + .Executes(r => OperateWithType(r.Source, near: false, MccArguments.GetEntityType(r, "EntityType"), ActionType.Use))) .Then(l => l.Literal("list") - .Executes(r => OperateWithType(r.Source, handler, near: false, MccArguments.GetEntityType(r, "EntityType"), ActionType.List)))) + .Executes(r => OperateWithType(r.Source, near: false, MccArguments.GetEntityType(r, "EntityType"), ActionType.List)))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -90,8 +90,9 @@ namespace MinecraftClient.Commands }); } - private int GetFullEntityList(CmdResult r, McClient handler) + private int GetFullEntityList(CmdResult r) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetEntityHandlingEnabled()) return r.SetAndReturn(Status.FailNeedEntity); @@ -106,8 +107,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Done); } - private int GetClosetEntityList(CmdResult r, McClient handler) + private int GetClosetEntityList(CmdResult r) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetEntityHandlingEnabled()) return r.SetAndReturn(Status.FailNeedEntity); @@ -120,8 +122,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Fail, Translations.cmd_entityCmd_not_found); } - private int OperateWithId(CmdResult r, McClient handler, int entityID, ActionType action) + private int OperateWithId(CmdResult r, int entityID, ActionType action) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetEntityHandlingEnabled()) return r.SetAndReturn(Status.FailNeedEntity); @@ -134,8 +137,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Fail, Translations.cmd_entityCmd_not_found); } - private int OperateWithType(CmdResult r, McClient handler, bool near, EntityType entityType, ActionType action) + private int OperateWithType(CmdResult r, bool near, EntityType entityType, ActionType action) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetEntityHandlingEnabled()) return r.SetAndReturn(Status.FailNeedEntity); diff --git a/MinecraftClient/Commands/ExecIf.cs b/MinecraftClient/Commands/ExecIf.cs index 3557e200..1e441794 100644 --- a/MinecraftClient/Commands/ExecIf.cs +++ b/MinecraftClient/Commands/ExecIf.cs @@ -13,7 +13,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "execif \"\" \"\""; } } public override string CmdDesc { get { return Translations.cmd_execif_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -24,7 +24,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Argument("Condition", Arguments.String()) .Then(l => l.Argument("Command", Arguments.String()) - .Executes(r => HandleCommand(r.Source, handler, Arguments.GetString(r, "Condition"), Arguments.GetString(r, "Command"))))) + .Executes(r => HandleCommand(r.Source, Arguments.GetString(r, "Condition"), Arguments.GetString(r, "Command"))))) ); } @@ -38,8 +38,9 @@ namespace MinecraftClient.Commands }); } - private int HandleCommand(CmdResult r, McClient handler, string expressionText, string resultCommand) + private int HandleCommand(CmdResult r, string expressionText, string resultCommand) { + McClient handler = CmdResult.currentHandler!; try { var interpreter = new Interpreter(); diff --git a/MinecraftClient/Commands/ExecMulti.cs b/MinecraftClient/Commands/ExecMulti.cs index bebff1a1..98c2fe7c 100644 --- a/MinecraftClient/Commands/ExecMulti.cs +++ b/MinecraftClient/Commands/ExecMulti.cs @@ -13,7 +13,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "execmulti -> -> -> ..."; } } public override string CmdDesc { get { return Translations.cmd_execmulti_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -23,7 +23,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Argument("Commands", Arguments.GreedyString()) - .Executes(r => HandleCommand(r.Source, handler, Arguments.GetString(r, "Commands")))) + .Executes(r => HandleCommand(r.Source, Arguments.GetString(r, "Commands")))) ); } @@ -37,8 +37,9 @@ namespace MinecraftClient.Commands }); } - private int HandleCommand(CmdResult r, McClient handler, string commandsString) + private int HandleCommand(CmdResult r, string commandsString) { + McClient handler = CmdResult.currentHandler!; if (commandsString.Contains("execmulti", StringComparison.OrdinalIgnoreCase) || commandsString.Contains("execif", StringComparison.OrdinalIgnoreCase)) return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_execmulti_prevent); diff --git a/MinecraftClient/Commands/Exit.cs b/MinecraftClient/Commands/Exit.cs index 5618b248..281bd980 100644 --- a/MinecraftClient/Commands/Exit.cs +++ b/MinecraftClient/Commands/Exit.cs @@ -10,7 +10,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "exit"; } } public override string CmdDesc { get { return Translations.cmd_exit_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) diff --git a/MinecraftClient/Commands/Health.cs b/MinecraftClient/Commands/Health.cs index 215b5d1a..308059b6 100644 --- a/MinecraftClient/Commands/Health.cs +++ b/MinecraftClient/Commands/Health.cs @@ -10,7 +10,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "health"; } } public override string CmdDesc { get { return Translations.cmd_health_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -19,7 +19,7 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => LogHealth(r.Source, handler)) + .Executes(r => LogHealth(r.Source)) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -35,8 +35,9 @@ namespace MinecraftClient.Commands }); } - private int LogHealth(CmdResult r, McClient handler) + private int LogHealth(CmdResult r) { + McClient handler = CmdResult.currentHandler!; return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_health_response, handler.GetHealth(), handler.GetSaturation(), handler.GetLevel(), handler.GetTotalExperience())); } } diff --git a/MinecraftClient/Commands/Help.cs b/MinecraftClient/Commands/Help.cs index 4727f2bb..18dbaf3e 100644 --- a/MinecraftClient/Commands/Help.cs +++ b/MinecraftClient/Commands/Help.cs @@ -12,16 +12,17 @@ namespace MinecraftClient.Commands public override string CmdDesc => throw new NotImplementedException(); public override string CmdUsage => throw new NotImplementedException(); - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") - .Executes(r => LogHelp(r.Source, handler, dispatcher)) + .Executes(r => LogHelp(r.Source, dispatcher)) ); } - private int LogHelp(CmdResult r, McClient handler, CommandDispatcher dispatcher) + private int LogHelp(CmdResult r, CommandDispatcher dispatcher) { + McClient handler = CmdResult.currentHandler!; var usage = dispatcher.GetSmartUsage(dispatcher.GetRoot(), CmdResult.Empty); StringBuilder sb = new(); foreach (var item in usage) diff --git a/MinecraftClient/Commands/Inventory.cs b/MinecraftClient/Commands/Inventory.cs index cc674cc3..fd13a1c3 100644 --- a/MinecraftClient/Commands/Inventory.cs +++ b/MinecraftClient/Commands/Inventory.cs @@ -15,7 +15,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return GetBasicUsage(); } } public override string CmdDesc { get { return Translations.cmd_inventory_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -42,65 +42,65 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => ListAllInventories(r.Source, handler)) + .Executes(r => ListAllInventories(r.Source)) .Then(l => l.Literal("creativegive") .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) .Then(l => l.Argument("ItemType", MccArguments.ItemType()) .Then(l => l.Argument("Count", Arguments.Integer(min: 1)) - .Executes(r => DoCreativeGive(r.Source, handler, Arguments.GetInteger(r, "Slot"), MccArguments.GetItemType(r, "ItemType"), Arguments.GetInteger(r, "Count"))))))) + .Executes(r => DoCreativeGive(r.Source, Arguments.GetInteger(r, "Slot"), MccArguments.GetItemType(r, "ItemType"), Arguments.GetInteger(r, "Count"))))))) .Then(l => l.Literal("creativedelete") .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) - .Executes(r => DoCreativeDelete(r.Source, handler, Arguments.GetInteger(r, "Slot"))))) + .Executes(r => DoCreativeDelete(r.Source, Arguments.GetInteger(r, "Slot"))))) .Then(l => l.Literal("inventories") - .Executes(r => ListAvailableInventories(r.Source, handler))) + .Executes(r => ListAvailableInventories(r.Source))) .Then(l => l.Literal("search") .Then(l => l.Argument("ItemType", MccArguments.ItemType()) - .Executes(r => SearchItem(r.Source, handler, MccArguments.GetItemType(r, "ItemType"), null)) + .Executes(r => SearchItem(r.Source, MccArguments.GetItemType(r, "ItemType"), null)) .Then(l => l.Argument("Count", Arguments.Integer(0, 64)) - .Executes(r => SearchItem(r.Source, handler, MccArguments.GetItemType(r, "ItemType"), Arguments.GetInteger(r, "Count")))))) + .Executes(r => SearchItem(r.Source, MccArguments.GetItemType(r, "ItemType"), Arguments.GetInteger(r, "Count")))))) .Then(l => l.Argument("InventoryId", MccArguments.InventoryId()) .Then(l => l.Literal("close") - .Executes(r => DoCloseAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId")))) + .Executes(r => DoCloseAction(r.Source, Arguments.GetInteger(r, "InventoryId")))) .Then(l => l.Literal("list") - .Executes(r => DoListAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId")))) + .Executes(r => DoListAction(r.Source, Arguments.GetInteger(r, "InventoryId")))) .Then(l => l.Literal("click") .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) - .Executes(r => DoClickAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) + .Executes(r => DoClickAction(r.Source, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) .Then(l => l.Argument("Action", MccArguments.InventoryAction()) - .Executes(r => DoClickAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) + .Executes(r => DoClickAction(r.Source, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) .Then(l => l.Literal("drop") .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) - .Executes(r => DoDropAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) + .Executes(r => DoDropAction(r.Source, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) .Then(l => l.Literal("all") - .Executes(r => DoDropAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) + .Executes(r => DoDropAction(r.Source, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) .Then(l => l.Literal("player") .Then(l => l.Literal("list") - .Executes(r => DoListAction(r.Source, handler, inventoryId: 0))) + .Executes(r => DoListAction(r.Source, inventoryId: 0))) .Then(l => l.Literal("click") .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) - .Executes(r => DoClickAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) + .Executes(r => DoClickAction(r.Source, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) .Then(l => l.Argument("Action", MccArguments.InventoryAction()) - .Executes(r => DoClickAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) + .Executes(r => DoClickAction(r.Source, inventoryId: 0, Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) .Then(l => l.Literal("drop") .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) - .Executes(r => DoDropAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) + .Executes(r => DoDropAction(r.Source, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) .Then(l => l.Literal("all") - .Executes(r => DoDropAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) + .Executes(r => DoDropAction(r.Source, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) .Then(l => l.Literal("container") .Then(l => l.Literal("close") - .Executes(r => DoCloseAction(r.Source, handler, inventoryId: null))) + .Executes(r => DoCloseAction(r.Source, inventoryId: null))) .Then(l => l.Literal("list") - .Executes(r => DoListAction(r.Source, handler, inventoryId: null))) + .Executes(r => DoListAction(r.Source, inventoryId: null))) .Then(l => l.Literal("click") .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) - .Executes(r => DoClickAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) + .Executes(r => DoClickAction(r.Source, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick)) .Then(l => l.Argument("Action", MccArguments.InventoryAction()) - .Executes(r => DoClickAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) + .Executes(r => DoClickAction(r.Source, inventoryId: null, Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action")))))) .Then(l => l.Literal("drop") .Then(l => l.Argument("Slot", MccArguments.InventorySlot()) - .Executes(r => DoDropAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) + .Executes(r => DoDropAction(r.Source, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem)) .Then(l => l.Literal("all") - .Executes(r => DoDropAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) + .Executes(r => DoDropAction(r.Source, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -133,8 +133,9 @@ namespace MinecraftClient.Commands return availableIds.Max(); // use foreground container } - private int ListAllInventories(CmdResult r, McClient handler) + private int ListAllInventories(CmdResult r) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) { handler.Log.Info(Translations.extra_inventory_required); @@ -149,8 +150,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(CmdResult.Status.Done); } - private int DoCreativeGive(CmdResult r, McClient handler, int slot, ItemType itemType, int count) + private int DoCreativeGive(CmdResult r, int slot, ItemType itemType, int count) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(CmdResult.Status.FailNeedInventory); @@ -167,8 +169,9 @@ namespace MinecraftClient.Commands } } - private int DoCreativeDelete(CmdResult r, McClient handler, int slot) + private int DoCreativeDelete(CmdResult r, int slot) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(CmdResult.Status.FailNeedInventory); @@ -185,8 +188,9 @@ namespace MinecraftClient.Commands } } - private int ListAvailableInventories(CmdResult r, McClient handler) + private int ListAvailableInventories(CmdResult r) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(CmdResult.Status.FailNeedInventory); @@ -202,8 +206,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(CmdResult.Status.Done); } - private int SearchItem(CmdResult r, McClient handler, ItemType itemType, int? itemCount) + private int SearchItem(CmdResult r, ItemType itemType, int? itemCount) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(CmdResult.Status.FailNeedInventory); @@ -256,8 +261,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(CmdResult.Status.Done); } - private int DoCloseAction(CmdResult r, McClient handler, int? inventoryId) + private int DoCloseAction(CmdResult r, int? inventoryId) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(CmdResult.Status.FailNeedInventory); @@ -278,8 +284,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_inventory_close_fail, inventoryId)); } - private int DoListAction(CmdResult r, McClient handler, int? inventoryId) + private int DoListAction(CmdResult r, int? inventoryId) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(CmdResult.Status.FailNeedInventory); @@ -320,8 +327,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(CmdResult.Status.Done); } - private int DoClickAction(CmdResult r, McClient handler, int? inventoryId, int slot, WindowActionType actionType) + private int DoClickAction(CmdResult r, int? inventoryId, int slot, WindowActionType actionType) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(CmdResult.Status.FailNeedInventory); @@ -349,8 +357,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(handler.DoWindowAction(inventoryId.Value, slot, actionType)); } - private int DoDropAction(CmdResult r, McClient handler, int? inventoryId, int slot, WindowActionType actionType) + private int DoDropAction(CmdResult r, int? inventoryId, int slot, WindowActionType actionType) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(CmdResult.Status.FailNeedInventory); diff --git a/MinecraftClient/Commands/List.cs b/MinecraftClient/Commands/List.cs index 82fd7f65..b06a4b9a 100644 --- a/MinecraftClient/Commands/List.cs +++ b/MinecraftClient/Commands/List.cs @@ -11,7 +11,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "list"; } } public override string CmdDesc { get { return Translations.cmd_list_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -20,7 +20,7 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => DoListPlayers(r.Source, handler)) + .Executes(r => DoListPlayers(r.Source)) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -36,8 +36,9 @@ namespace MinecraftClient.Commands }); } - private int DoListPlayers(CmdResult r, McClient handler) + private int DoListPlayers(CmdResult r) { + McClient handler = CmdResult.currentHandler!; return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_list_players, String.Join(", ", handler.GetOnlinePlayers()))); } } diff --git a/MinecraftClient/Commands/Log.cs b/MinecraftClient/Commands/Log.cs index e9181ed3..8cdf3ecf 100644 --- a/MinecraftClient/Commands/Log.cs +++ b/MinecraftClient/Commands/Log.cs @@ -10,7 +10,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "log "; } } public override string CmdDesc { get { return Translations.cmd_log_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) diff --git a/MinecraftClient/Commands/Look.cs b/MinecraftClient/Commands/Look.cs index 2376bbc1..5c78f47e 100644 --- a/MinecraftClient/Commands/Look.cs +++ b/MinecraftClient/Commands/Look.cs @@ -13,7 +13,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "look "; } } public override string CmdDesc { get { return Translations.cmd_look_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -28,24 +28,24 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => LogCurrentLooking(r.Source, handler)) + .Executes(r => LogCurrentLooking(r.Source)) .Then(l => l.Literal("up") - .Executes(r => LookAtDirection(r.Source, handler, Direction.Up))) + .Executes(r => LookAtDirection(r.Source, Direction.Up))) .Then(l => l.Literal("down") - .Executes(r => LookAtDirection(r.Source, handler, Direction.Down))) + .Executes(r => LookAtDirection(r.Source, Direction.Down))) .Then(l => l.Literal("east") - .Executes(r => LookAtDirection(r.Source, handler, Direction.East))) + .Executes(r => LookAtDirection(r.Source, Direction.East))) .Then(l => l.Literal("west") - .Executes(r => LookAtDirection(r.Source, handler, Direction.West))) + .Executes(r => LookAtDirection(r.Source, Direction.West))) .Then(l => l.Literal("north") - .Executes(r => LookAtDirection(r.Source, handler, Direction.North))) + .Executes(r => LookAtDirection(r.Source, Direction.North))) .Then(l => l.Literal("south") - .Executes(r => LookAtDirection(r.Source, handler, Direction.South))) + .Executes(r => LookAtDirection(r.Source, Direction.South))) .Then(l => l.Argument("Yaw", Arguments.Float()) .Then(l => l.Argument("Pitch", Arguments.Float()) - .Executes(r => LookAtAngle(r.Source, handler, Arguments.GetFloat(r, "Yaw"), Arguments.GetFloat(r, "Pitch"))))) + .Executes(r => LookAtAngle(r.Source, Arguments.GetFloat(r, "Yaw"), Arguments.GetFloat(r, "Pitch"))))) .Then(l => l.Argument("Location", MccArguments.Location()) - .Executes(r => LookAtLocation(r.Source, handler, MccArguments.GetLocation(r, "Location")))) + .Executes(r => LookAtLocation(r.Source, MccArguments.GetLocation(r, "Location")))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -64,8 +64,9 @@ namespace MinecraftClient.Commands }); } - private int LogCurrentLooking(CmdResult r, McClient handler) + private int LogCurrentLooking(CmdResult r) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); @@ -83,8 +84,9 @@ namespace MinecraftClient.Commands } } - private int LookAtDirection(CmdResult r, McClient handler, Direction direction) + private int LookAtDirection(CmdResult r, Direction direction) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); @@ -92,8 +94,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Done, "Looking " + direction.ToString()); } - private int LookAtAngle(CmdResult r, McClient handler, float yaw, float pitch) + private int LookAtAngle(CmdResult r, float yaw, float pitch) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); @@ -101,8 +104,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_look_at, yaw.ToString("0.00"), pitch.ToString("0.00"))); } - private int LookAtLocation(CmdResult r, McClient handler, Location location) + private int LookAtLocation(CmdResult r, Location location) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); diff --git a/MinecraftClient/Commands/Move.cs b/MinecraftClient/Commands/Move.cs index 734dc10d..89065765 100644 --- a/MinecraftClient/Commands/Move.cs +++ b/MinecraftClient/Commands/Move.cs @@ -13,7 +13,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "move [-f]"; } } public override string CmdDesc { get { return Translations.cmd_move_desc + " \"-f\": " + Translations.cmd_move_desc_force; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -37,47 +37,47 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Literal("on") - .Executes(r => SetMovementEnable(r.Source, handler, enable: true))) + .Executes(r => SetMovementEnable(r.Source, enable: true))) .Then(l => l.Literal("off") - .Executes(r => SetMovementEnable(r.Source, handler, enable: false))) + .Executes(r => SetMovementEnable(r.Source, enable: false))) .Then(l => l.Literal("gravity") - .Executes(r => SetGravityEnable(r.Source, handler, enable: null)) + .Executes(r => SetGravityEnable(r.Source, enable: null)) .Then(l => l.Literal("on") - .Executes(r => SetGravityEnable(r.Source, handler, enable: true))) + .Executes(r => SetGravityEnable(r.Source, enable: true))) .Then(l => l.Literal("off") - .Executes(r => SetGravityEnable(r.Source, handler, enable: false)))) + .Executes(r => SetGravityEnable(r.Source, enable: false)))) .Then(l => l.Literal("up") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.Up, false)) + .Executes(r => MoveOnDirection(r.Source, Direction.Up, false)) .Then(l => l.Literal("-f") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.Up, true)))) + .Executes(r => MoveOnDirection(r.Source, Direction.Up, true)))) .Then(l => l.Literal("down") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.Down, false)) + .Executes(r => MoveOnDirection(r.Source, Direction.Down, false)) .Then(l => l.Literal("-f") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.Down, true)))) + .Executes(r => MoveOnDirection(r.Source, Direction.Down, true)))) .Then(l => l.Literal("east") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.East, false)) + .Executes(r => MoveOnDirection(r.Source, Direction.East, false)) .Then(l => l.Literal("-f") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.East, true)))) + .Executes(r => MoveOnDirection(r.Source, Direction.East, true)))) .Then(l => l.Literal("west") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.West, false)) + .Executes(r => MoveOnDirection(r.Source, Direction.West, false)) .Then(l => l.Literal("-f") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.West, true)))) + .Executes(r => MoveOnDirection(r.Source, Direction.West, true)))) .Then(l => l.Literal("north") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.North, false)) + .Executes(r => MoveOnDirection(r.Source, Direction.North, false)) .Then(l => l.Literal("-f") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.North, true)))) + .Executes(r => MoveOnDirection(r.Source, Direction.North, true)))) .Then(l => l.Literal("south") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.South, false)) + .Executes(r => MoveOnDirection(r.Source, Direction.South, false)) .Then(l => l.Literal("-f") - .Executes(r => MoveOnDirection(r.Source, handler, Direction.South, true)))) + .Executes(r => MoveOnDirection(r.Source, Direction.South, true)))) .Then(l => l.Literal("center") - .Executes(r => MoveToCenter(r.Source, handler))) + .Executes(r => MoveToCenter(r.Source))) .Then(l => l.Literal("get") - .Executes(r => GetCurrentLocation(r.Source, handler))) + .Executes(r => GetCurrentLocation(r.Source))) .Then(l => l.Argument("location", MccArguments.Location()) - .Executes(r => MoveToLocation(r.Source, handler, MccArguments.GetLocation(r, "location"), false)) + .Executes(r => MoveToLocation(r.Source, MccArguments.GetLocation(r, "location"), false)) .Then(l => l.Literal("-f") - .Executes(r => MoveToLocation(r.Source, handler, MccArguments.GetLocation(r, "location"), true)))) + .Executes(r => MoveToLocation(r.Source, MccArguments.GetLocation(r, "location"), true)))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -100,8 +100,9 @@ namespace MinecraftClient.Commands }); } - private int SetMovementEnable(CmdResult r, McClient handler, bool enable) + private int SetMovementEnable(CmdResult r, bool enable) { + McClient handler = CmdResult.currentHandler!; if (enable) { handler.SetTerrainEnabled(true); @@ -114,8 +115,9 @@ namespace MinecraftClient.Commands } } - private int SetGravityEnable(CmdResult r, McClient handler, bool? enable) + private int SetGravityEnable(CmdResult r, bool? enable) { + McClient handler = CmdResult.currentHandler!; if (enable.HasValue) Settings.InternalConfig.GravityEnabled = enable.Value; @@ -125,16 +127,18 @@ namespace MinecraftClient.Commands return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_move_gravity_disabled); } - private int GetCurrentLocation(CmdResult r, McClient handler) + private int GetCurrentLocation(CmdResult r) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); return r.SetAndReturn(Status.Done, handler.GetCurrentLocation().ToString()); } - private int MoveToCenter(CmdResult r, McClient handler) + private int MoveToCenter(CmdResult r) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); @@ -144,8 +148,9 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_move_walk, currentCenter, current)); } - private int MoveOnDirection(CmdResult r, McClient handler, Direction direction, bool takeRisk) + private int MoveOnDirection(CmdResult r, Direction direction, bool takeRisk) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); @@ -167,8 +172,9 @@ namespace MinecraftClient.Commands } } - private int MoveToLocation(CmdResult r, McClient handler, Location goal, bool takeRisk) + private int MoveToLocation(CmdResult r, Location goal, bool takeRisk) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); diff --git a/MinecraftClient/Commands/Reco.cs b/MinecraftClient/Commands/Reco.cs index c2ef3081..569ca465 100644 --- a/MinecraftClient/Commands/Reco.cs +++ b/MinecraftClient/Commands/Reco.cs @@ -11,7 +11,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "reco [account]"; } } public override string CmdDesc { get { return Translations.cmd_reco_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -40,7 +40,7 @@ namespace MinecraftClient.Commands private int DoReconnect(CmdResult r, string account) { - if (string.IsNullOrWhiteSpace(account)) + if (!string.IsNullOrWhiteSpace(account)) { account = account.Trim(); if (!Settings.Config.Main.Advanced.SetAccount(account)) diff --git a/MinecraftClient/Commands/Reload.cs b/MinecraftClient/Commands/Reload.cs index f004c821..be8ba98d 100644 --- a/MinecraftClient/Commands/Reload.cs +++ b/MinecraftClient/Commands/Reload.cs @@ -10,7 +10,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "reload"; } } public override string CmdDesc { get { return Translations.cmd_reload_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -19,7 +19,7 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => DoReload(r.Source, handler)) + .Executes(r => DoReload(r.Source)) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -35,8 +35,9 @@ namespace MinecraftClient.Commands }); } - private int DoReload(CmdResult r, McClient handler) + private int DoReload(CmdResult r) { + McClient handler = CmdResult.currentHandler!; handler.Log.Info(Translations.cmd_reload_started); handler.ReloadSettings(); handler.Log.Warn(Translations.cmd_reload_warning1); diff --git a/MinecraftClient/Commands/Respawn.cs b/MinecraftClient/Commands/Respawn.cs index d9bfbcbf..d494e0b7 100644 --- a/MinecraftClient/Commands/Respawn.cs +++ b/MinecraftClient/Commands/Respawn.cs @@ -10,7 +10,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "respawn"; } } public override string CmdDesc { get { return Translations.cmd_respawn_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -19,7 +19,7 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => DoRespawn(r.Source, handler)) + .Executes(r => DoRespawn(r.Source)) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -35,8 +35,9 @@ namespace MinecraftClient.Commands }); } - private int DoRespawn(CmdResult r, McClient handler) + private int DoRespawn(CmdResult r) { + McClient handler = CmdResult.currentHandler!; handler.SendRespawnPacket(); return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_respawn_done); } diff --git a/MinecraftClient/Commands/Script.cs b/MinecraftClient/Commands/Script.cs index f7f850f2..3c8dd07c 100644 --- a/MinecraftClient/Commands/Script.cs +++ b/MinecraftClient/Commands/Script.cs @@ -11,7 +11,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "script "; } } public override string CmdDesc { get { return Translations.cmd_script_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -21,7 +21,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Argument("Script", Arguments.GreedyString()) - .Executes(r => DoExecuteScript(r.Source, handler, Arguments.GetString(r, "Script"), null))) + .Executes(r => DoExecuteScript(r.Source, Arguments.GetString(r, "Script"), null))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -37,8 +37,9 @@ namespace MinecraftClient.Commands }); } - private int DoExecuteScript(CmdResult r, McClient handler, string command, Dictionary? localVars) + private int DoExecuteScript(CmdResult r, string command, Dictionary? localVars) { + McClient handler = CmdResult.currentHandler!; handler.BotLoad(new ChatBots.Script(command.Trim(), null, localVars)); return r.SetAndReturn(CmdResult.Status.Done); } diff --git a/MinecraftClient/Commands/Send.cs b/MinecraftClient/Commands/Send.cs index d17bc3b5..cf6964ec 100644 --- a/MinecraftClient/Commands/Send.cs +++ b/MinecraftClient/Commands/Send.cs @@ -10,7 +10,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "send "; } } public override string CmdDesc { get { return Translations.cmd_send_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -20,7 +20,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Argument("any", Arguments.GreedyString()) - .Executes(r => DoSendText(r.Source, handler, Arguments.GetString(r, "any")))) + .Executes(r => DoSendText(r.Source, Arguments.GetString(r, "any")))) ); } @@ -34,8 +34,9 @@ namespace MinecraftClient.Commands }); } - private int DoSendText(CmdResult r, McClient handler, string command) + private int DoSendText(CmdResult r, string command) { + McClient handler = CmdResult.currentHandler!; handler.SendText(command); return r.SetAndReturn(CmdResult.Status.Done); } diff --git a/MinecraftClient/Commands/Set.cs b/MinecraftClient/Commands/Set.cs index 3bf6d86f..e46cfebb 100644 --- a/MinecraftClient/Commands/Set.cs +++ b/MinecraftClient/Commands/Set.cs @@ -10,7 +10,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "set varname=value"; } } public override string CmdDesc { get { return Translations.cmd_set_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) diff --git a/MinecraftClient/Commands/SetRnd.cs b/MinecraftClient/Commands/SetRnd.cs index 1f93ca24..c792b5d7 100644 --- a/MinecraftClient/Commands/SetRnd.cs +++ b/MinecraftClient/Commands/SetRnd.cs @@ -13,7 +13,7 @@ namespace MinecraftClient.Commands public override string CmdDesc { get { return Translations.cmd_setrnd_desc; } } private static readonly Random rand = new(); - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) diff --git a/MinecraftClient/Commands/Sneak.cs b/MinecraftClient/Commands/Sneak.cs index d21bea8a..f5401ffb 100644 --- a/MinecraftClient/Commands/Sneak.cs +++ b/MinecraftClient/Commands/Sneak.cs @@ -11,7 +11,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "sneak"; } } public override string CmdDesc { get { return Translations.cmd_sneak_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -20,7 +20,7 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => DoSneak(r.Source, handler)) + .Executes(r => DoSneak(r.Source)) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -36,8 +36,9 @@ namespace MinecraftClient.Commands }); } - private int DoSneak(CmdResult r, McClient handler) + private int DoSneak(CmdResult r) { + McClient handler = CmdResult.currentHandler!; if (sneaking) { var result = handler.SendEntityAction(Protocol.EntityActionType.StopSneaking); diff --git a/MinecraftClient/Commands/Tps.cs b/MinecraftClient/Commands/Tps.cs index 92fb0924..f96e9674 100644 --- a/MinecraftClient/Commands/Tps.cs +++ b/MinecraftClient/Commands/Tps.cs @@ -11,7 +11,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "tps"; } } public override string CmdDesc { get { return Translations.cmd_tps_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -20,7 +20,7 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => DoLogTps(r.Source, handler)) + .Executes(r => DoLogTps(r.Source)) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -36,8 +36,9 @@ namespace MinecraftClient.Commands }); } - private int DoLogTps(CmdResult r, McClient handler) + private int DoLogTps(CmdResult r) { + McClient handler = CmdResult.currentHandler!; var tps = Math.Round(handler.GetServerTPS(), 2); string color; if (tps < 10) diff --git a/MinecraftClient/Commands/Upgrade.cs b/MinecraftClient/Commands/Upgrade.cs index 625b5d5b..30757eaa 100644 --- a/MinecraftClient/Commands/Upgrade.cs +++ b/MinecraftClient/Commands/Upgrade.cs @@ -10,7 +10,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "upgrade [-f|check|cancel|download]"; } } public override string CmdDesc { get { return string.Empty; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) diff --git a/MinecraftClient/Commands/UseItem.cs b/MinecraftClient/Commands/UseItem.cs index 41f056da..1768cf38 100644 --- a/MinecraftClient/Commands/UseItem.cs +++ b/MinecraftClient/Commands/UseItem.cs @@ -11,7 +11,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "useitem"; } } public override string CmdDesc { get { return Translations.cmd_useitem_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -20,7 +20,7 @@ namespace MinecraftClient.Commands ); dispatcher.Register(l => l.Literal(CmdName) - .Executes(r => DoUseItem(r.Source, handler)) + .Executes(r => DoUseItem(r.Source)) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -36,8 +36,9 @@ namespace MinecraftClient.Commands }); } - private int DoUseItem(CmdResult r, McClient handler) + private int DoUseItem(CmdResult r) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(Status.FailNeedInventory); diff --git a/MinecraftClient/Commands/Useblock.cs b/MinecraftClient/Commands/Useblock.cs index 4973d6a6..1169c994 100644 --- a/MinecraftClient/Commands/Useblock.cs +++ b/MinecraftClient/Commands/Useblock.cs @@ -12,7 +12,7 @@ namespace MinecraftClient.Commands public override string CmdUsage { get { return "useblock "; } } public override string CmdDesc { get { return Translations.cmd_useblock_desc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CmdName) @@ -22,7 +22,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Then(l => l.Argument("Location", MccArguments.Location()) - .Executes(r => UseBlockAtLocation(r.Source, handler, MccArguments.GetLocation(r, "Location")))) + .Executes(r => UseBlockAtLocation(r.Source, MccArguments.GetLocation(r, "Location")))) .Then(l => l.Literal("_help") .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); @@ -38,8 +38,9 @@ namespace MinecraftClient.Commands }); } - private int UseBlockAtLocation(CmdResult r, McClient handler, Location block) + private int UseBlockAtLocation(CmdResult r, Location block) { + McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) return r.SetAndReturn(Status.FailNeedTerrain); diff --git a/MinecraftClient/ConsoleIO.cs b/MinecraftClient/ConsoleIO.cs index db2f849b..f5262f73 100644 --- a/MinecraftClient/ConsoleIO.cs +++ b/MinecraftClient/ConsoleIO.cs @@ -224,7 +224,7 @@ namespace MinecraftClient sugList.Add(new("/")); - var childs = CmdResult.client?.dispatcher.GetRoot().Children; + var childs = McClient.dispatcher.GetRoot().Children; if (childs != null) foreach (var child in childs) sugList.Add(new(child.Name)); @@ -246,7 +246,7 @@ namespace MinecraftClient } else { - CommandDispatcher? dispatcher = CmdResult.client?.dispatcher; + CommandDispatcher? dispatcher = McClient.dispatcher; if (dispatcher == null) return; diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index 2b38ab50..80defaf6 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -30,7 +30,7 @@ namespace MinecraftClient { public static int ReconnectionAttemptsLeft = 0; - public CommandDispatcher dispatcher = new(); + public static CommandDispatcher dispatcher = new(); private readonly Dictionary onlinePlayers = new(); private static bool commandsLoaded = false; @@ -150,7 +150,7 @@ namespace MinecraftClient /// ForgeInfo item stating that Forge is enabled public McClient(SessionToken session, PlayerKeyPair? playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo? forgeInfo) { - CmdResult.client = this; + CmdResult.currentHandler = this; terrainAndMovementsEnabled = Config.Main.Advanced.TerrainAndMovements; inventoryHandlingEnabled = Config.Main.Advanced.InventoryHandling; entityHandlingEnabled = Config.Main.Advanced.EntityHandling; @@ -674,7 +674,7 @@ namespace MinecraftClient try { Command cmd = (Command)Activator.CreateInstance(type)!; - cmd.RegisterCommand(this, dispatcher); + cmd.RegisterCommand(dispatcher); } catch (Exception e) { diff --git a/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs b/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs index c27a20e8..bf0cbc7f 100644 --- a/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs +++ b/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs @@ -1102,6 +1102,15 @@ namespace MinecraftClient { } } + /// + /// Looks up a localized string similar to Enable this option if the arrows in the command suggestions are not displayed properly in your terminal.. + /// + internal static string Console_CommandSuggestion_Use_Basic_Arrow { + get { + return ResourceManager.GetString("Console.CommandSuggestion.Use_Basic_Arrow", resourceCulture); + } + } + /// /// Looks up a localized string similar to If a garbled code like "←[0m" appears on the terminal, you can turn off this.. /// diff --git a/MinecraftClient/Resources/ConfigComments/ConfigComments.resx b/MinecraftClient/Resources/ConfigComments/ConfigComments.resx index 3413fd87..1b71fcd9 100644 --- a/MinecraftClient/Resources/ConfigComments/ConfigComments.resx +++ b/MinecraftClient/Resources/ConfigComments/ConfigComments.resx @@ -544,6 +544,9 @@ When this happens, you'll need to configure chat format below, see https://mccte Whether to display command suggestions in the console. + + Enable this option if the arrows in the command suggestions are not displayed properly in your terminal. + If a garbled code like "←[0m" appears on the terminal, you can turn off this. diff --git a/MinecraftClient/Resources/Translations/Translations.Designer.cs b/MinecraftClient/Resources/Translations/Translations.Designer.cs index bc17ee17..9c1b8d84 100644 --- a/MinecraftClient/Resources/Translations/Translations.Designer.cs +++ b/MinecraftClient/Resources/Translations/Translations.Designer.cs @@ -5341,7 +5341,7 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to Password(invisible): {0}. + /// Looks up a localized string similar to Password(invisible): . /// internal static string mcc_password_hidden { get { diff --git a/MinecraftClient/Resources/Translations/Translations.resx b/MinecraftClient/Resources/Translations/Translations.resx index dd806246..73e81493 100644 --- a/MinecraftClient/Resources/Translations/Translations.resx +++ b/MinecraftClient/Resources/Translations/Translations.resx @@ -1900,7 +1900,7 @@ Type '{0}quit' to leave the server. Please type the password for {0}. - Password(invisible): {0} + Password(invisible): You are dead. Type '{0}respawn' to respawn. diff --git a/MinecraftClient/Scripting/ChatBot.cs b/MinecraftClient/Scripting/ChatBot.cs index 025bb850..d73f0884 100644 --- a/MinecraftClient/Scripting/ChatBot.cs +++ b/MinecraftClient/Scripting/ChatBot.cs @@ -1667,7 +1667,7 @@ namespace MinecraftClient.Scripting public override string CmdUsage { get { return _cmdUsage; } } public override string CmdDesc { get { return _cmdDesc; } } - public override void RegisterCommand(McClient handler, CommandDispatcher dispatcher) + public override void RegisterCommand(CommandDispatcher dispatcher) { } diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index 39d00aa4..0a07bb40 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -794,6 +794,8 @@ namespace MinecraftClient ConsoleInteractive.ConsoleSuggestion.EnableColor = CommandSuggestion.Enable_Color; + ConsoleInteractive.ConsoleSuggestion.UseBasicArrow = CommandSuggestion.Use_Basic_Arrow; + CommandSuggestion.Max_Suggestion_Width = ConsoleInteractive.ConsoleSuggestion.SetMaxSuggestionLength(CommandSuggestion.Max_Suggestion_Width); @@ -886,6 +888,9 @@ namespace MinecraftClient [TomlInlineComment("$Console.Enable_Color$")] public bool Enable_Color = true; + [TomlInlineComment("$Console.CommandSuggestion.Use_Basic_Arrow$")] + public bool Use_Basic_Arrow = false; + public int Max_Suggestion_Width = 30; public int Max_Displayed_Suggestions = 6; From 7900108763d86a86188b0dc8940f2cf3b12f7776 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Sun, 11 Dec 2022 17:31:37 +0800 Subject: [PATCH 6/8] Bug fix --- MinecraftClient/ChatBots/AutoCraft.cs | 1 + MinecraftClient/ChatBots/AutoDig.cs | 1 + MinecraftClient/ChatBots/AutoDrop.cs | 1 + MinecraftClient/ChatBots/AutoFishing.cs | 1 + MinecraftClient/ChatBots/DiscordBridge.cs | 1 + MinecraftClient/ChatBots/Farmer.cs | 1 + MinecraftClient/ChatBots/FollowPlayer.cs | 1 + MinecraftClient/ChatBots/Mailer.cs | 9 +++++---- MinecraftClient/ChatBots/Map.cs | 1 + MinecraftClient/ChatBots/ReplayCapture.cs | 1 + MinecraftClient/ChatBots/TelegramBridge.cs | 1 + MinecraftClient/Commands/Animation.cs | 1 + MinecraftClient/Commands/Bed.cs | 1 + MinecraftClient/Commands/BlockInfo.cs | 1 + MinecraftClient/Commands/Bots.cs | 1 + MinecraftClient/Commands/ChangeSlot.cs | 1 + MinecraftClient/Commands/Chunk.cs | 1 + MinecraftClient/Commands/Connect.cs | 1 + MinecraftClient/Commands/Debug.cs | 1 + MinecraftClient/Commands/Dig.cs | 1 + MinecraftClient/Commands/DropItem.cs | 1 + MinecraftClient/Commands/Enchant.cs | 1 + MinecraftClient/Commands/Entitycmd.cs | 1 + MinecraftClient/Commands/Exit.cs | 1 + MinecraftClient/Commands/Health.cs | 1 + MinecraftClient/Commands/Inventory.cs | 1 + MinecraftClient/Commands/List.cs | 1 + MinecraftClient/Commands/Look.cs | 1 + MinecraftClient/Commands/Move.cs | 1 + MinecraftClient/Commands/Reco.cs | 1 + MinecraftClient/Commands/Reload.cs | 1 + MinecraftClient/Commands/Respawn.cs | 1 + MinecraftClient/Commands/Script.cs | 1 + MinecraftClient/Commands/Set.cs | 1 + MinecraftClient/Commands/Sneak.cs | 1 + MinecraftClient/Commands/Tps.cs | 1 + MinecraftClient/Commands/Upgrade.cs | 1 + MinecraftClient/Commands/UseItem.cs | 1 + MinecraftClient/Commands/Useblock.cs | 1 + 39 files changed, 43 insertions(+), 4 deletions(-) diff --git a/MinecraftClient/ChatBots/AutoCraft.cs b/MinecraftClient/ChatBots/AutoCraft.cs index 4e9b10a8..52d691ab 100644 --- a/MinecraftClient/ChatBots/AutoCraft.cs +++ b/MinecraftClient/ChatBots/AutoCraft.cs @@ -319,6 +319,7 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("stop") .Executes(r => OnCommandStop(r.Source))) .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } diff --git a/MinecraftClient/ChatBots/AutoDig.cs b/MinecraftClient/ChatBots/AutoDig.cs index 859ce35c..cddb6ffd 100644 --- a/MinecraftClient/ChatBots/AutoDig.cs +++ b/MinecraftClient/ChatBots/AutoDig.cs @@ -141,6 +141,7 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("stop") .Executes(r => OnCommandStop(r.Source))) .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); diff --git a/MinecraftClient/ChatBots/AutoDrop.cs b/MinecraftClient/ChatBots/AutoDrop.cs index 5a301830..36263a86 100644 --- a/MinecraftClient/ChatBots/AutoDrop.cs +++ b/MinecraftClient/ChatBots/AutoDrop.cs @@ -87,6 +87,7 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("everything") .Executes(r => OnCommandMode(r.Source, DropMode.everything)))) .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index ff028536..09ee140f 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -211,6 +211,7 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("clear") .Executes(r => OnCommandStatusClear(r.Source)))) .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } diff --git a/MinecraftClient/ChatBots/DiscordBridge.cs b/MinecraftClient/ChatBots/DiscordBridge.cs index a3280bf4..b9d5a50e 100644 --- a/MinecraftClient/ChatBots/DiscordBridge.cs +++ b/MinecraftClient/ChatBots/DiscordBridge.cs @@ -92,6 +92,7 @@ namespace MinecraftClient.ChatBots .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Discord))) ) .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); diff --git a/MinecraftClient/ChatBots/Farmer.cs b/MinecraftClient/ChatBots/Farmer.cs index 2bb11817..072fe270 100644 --- a/MinecraftClient/ChatBots/Farmer.cs +++ b/MinecraftClient/ChatBots/Farmer.cs @@ -105,6 +105,7 @@ namespace MinecraftClient.ChatBots .Then(l => l.Argument("OtherArgs", Arguments.GreedyString()) .Executes(r => OnCommandStart(r.Source, MccArguments.GetFarmerCropType(r, "CropType"), Arguments.GetString(r, "OtherArgs")))))) .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } diff --git a/MinecraftClient/ChatBots/FollowPlayer.cs b/MinecraftClient/ChatBots/FollowPlayer.cs index cf707699..0561bf0f 100644 --- a/MinecraftClient/ChatBots/FollowPlayer.cs +++ b/MinecraftClient/ChatBots/FollowPlayer.cs @@ -77,6 +77,7 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("stop") .Executes(r => OnCommandStop(r.Source))) .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } diff --git a/MinecraftClient/ChatBots/Mailer.cs b/MinecraftClient/ChatBots/Mailer.cs index aba382d8..41132d71 100644 --- a/MinecraftClient/ChatBots/Mailer.cs +++ b/MinecraftClient/ChatBots/Mailer.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using Brigadier.NET; using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; using MinecraftClient.CommandHandler.Patch; using MinecraftClient.Scripting; using Tomlet.Attributes; @@ -259,7 +260,7 @@ namespace MinecraftClient.ChatBots McClient.dispatcher.Register(l => l.Literal("help") .Then(l => l.Literal(CommandName) - .Executes(r => OnCommandHelp(string.Empty))) + .Executes(r => OnCommandHelp(r.Source, string.Empty))) ); McClient.dispatcher.Register(l => l.Literal(CommandName) @@ -274,6 +275,7 @@ namespace MinecraftClient.ChatBots .Then(l => l.Argument("username", Arguments.String()) .Executes(r => OnCommandRemoveIgnored(Arguments.GetString(r, "username"))))) .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } @@ -284,16 +286,15 @@ namespace MinecraftClient.ChatBots McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } - private int OnCommandHelp(string cmd) + private int OnCommandHelp(CmdResult r, string? cmd) { - LogToConsole(cmd switch + return r.SetAndReturn(cmd switch { #pragma warning disable format // @formatter:off _ => Translations.bot_mailer_cmd_help + ": /mailer " + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false), #pragma warning restore format // @formatter:on }); - return 1; } private int OnCommandGetMails() diff --git a/MinecraftClient/ChatBots/Map.cs b/MinecraftClient/ChatBots/Map.cs index 4689c162..fef48a90 100644 --- a/MinecraftClient/ChatBots/Map.cs +++ b/MinecraftClient/ChatBots/Map.cs @@ -94,6 +94,7 @@ namespace MinecraftClient.ChatBots .Then(l => l.Argument("MapID", MccArguments.MapBotMapId()) .Executes(r => OnCommandRender(r.Source, Arguments.GetInteger(r, "MapID"))))) .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } diff --git a/MinecraftClient/ChatBots/ReplayCapture.cs b/MinecraftClient/ChatBots/ReplayCapture.cs index f0a73a3a..eea74911 100644 --- a/MinecraftClient/ChatBots/ReplayCapture.cs +++ b/MinecraftClient/ChatBots/ReplayCapture.cs @@ -58,6 +58,7 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("stop") .Executes(r => OnCommandStop(r.Source))) .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); } diff --git a/MinecraftClient/ChatBots/TelegramBridge.cs b/MinecraftClient/ChatBots/TelegramBridge.cs index b92572db..6139a8d0 100644 --- a/MinecraftClient/ChatBots/TelegramBridge.cs +++ b/MinecraftClient/ChatBots/TelegramBridge.cs @@ -91,6 +91,7 @@ namespace MinecraftClient.ChatBots .Then(l => l.Literal("telegram") .Executes(r => OnCommandDirection(r.Source, BridgeDirection.Telegram)))) .Then(l => l.Literal("_help") + .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) ); diff --git a/MinecraftClient/Commands/Animation.cs b/MinecraftClient/Commands/Animation.cs index f5290e3e..dab51b6f 100644 --- a/MinecraftClient/Commands/Animation.cs +++ b/MinecraftClient/Commands/Animation.cs @@ -29,6 +29,7 @@ namespace MinecraftClient.Commands .Then(l => l.Literal("offhand") .Executes(r => DoAnimation(r.Source, mainhand: false))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Bed.cs b/MinecraftClient/Commands/Bed.cs index fbeb15fb..f3d4b995 100644 --- a/MinecraftClient/Commands/Bed.cs +++ b/MinecraftClient/Commands/Bed.cs @@ -37,6 +37,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("Radius", Arguments.Double()) .Executes(r => DoSleepBedWithRadius(r.Source, Arguments.GetDouble(r, "Radius"))))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/BlockInfo.cs b/MinecraftClient/Commands/BlockInfo.cs index 7ced900b..61e177d0 100644 --- a/MinecraftClient/Commands/BlockInfo.cs +++ b/MinecraftClient/Commands/BlockInfo.cs @@ -32,6 +32,7 @@ namespace MinecraftClient.Commands .Then(l => l.Literal("-s") .Executes(r => LogBlockInfo(r.Source, MccArguments.GetLocation(r, "Location"), true)))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Bots.cs b/MinecraftClient/Commands/Bots.cs index da9250e4..73574a14 100644 --- a/MinecraftClient/Commands/Bots.cs +++ b/MinecraftClient/Commands/Bots.cs @@ -33,6 +33,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("BotName", MccArguments.BotName()) .Executes(r => DoUnloadBot(r.Source, Arguments.GetString(r, "BotName"))))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/ChangeSlot.cs b/MinecraftClient/Commands/ChangeSlot.cs index d7631f65..acbe2e8d 100644 --- a/MinecraftClient/Commands/ChangeSlot.cs +++ b/MinecraftClient/Commands/ChangeSlot.cs @@ -23,6 +23,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("Slot", MccArguments.HotbarSlot()) .Executes(r => DoChangeSlot(r.Source, Arguments.GetInteger(r, "Slot")))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Chunk.cs b/MinecraftClient/Commands/Chunk.cs index 58380c9e..3452716b 100644 --- a/MinecraftClient/Commands/Chunk.cs +++ b/MinecraftClient/Commands/Chunk.cs @@ -53,6 +53,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("Chunk", MccArguments.Tuple()) .Executes(r => DebugDelete(r.Source, markedChunkPos: MccArguments.GetTuple(r, "Chunk"))))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Connect.cs b/MinecraftClient/Commands/Connect.cs index 0224c528..c8691340 100644 --- a/MinecraftClient/Commands/Connect.cs +++ b/MinecraftClient/Commands/Connect.cs @@ -25,6 +25,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("AccountNick", MccArguments.AccountNick()) .Executes(r => DoConnect(r.Source, Arguments.GetString(r, "ServerNick"), Arguments.GetString(r, "AccountNick"))))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Debug.cs b/MinecraftClient/Commands/Debug.cs index 3517505a..0302ea05 100644 --- a/MinecraftClient/Commands/Debug.cs +++ b/MinecraftClient/Commands/Debug.cs @@ -25,6 +25,7 @@ namespace MinecraftClient.Commands .Then(l => l.Literal("off") .Executes(r => SetDebugMode(r.Source, false, false))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Dig.cs b/MinecraftClient/Commands/Dig.cs index 80bf946f..3a30619a 100644 --- a/MinecraftClient/Commands/Dig.cs +++ b/MinecraftClient/Commands/Dig.cs @@ -26,6 +26,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("Location", MccArguments.Location()) .Executes(r => DigAt(r.Source, MccArguments.GetLocation(r, "Location")))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/DropItem.cs b/MinecraftClient/Commands/DropItem.cs index 2ee05f0c..38cfc4b6 100644 --- a/MinecraftClient/Commands/DropItem.cs +++ b/MinecraftClient/Commands/DropItem.cs @@ -26,6 +26,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("ItemType", MccArguments.ItemType()) .Executes(r => DoDropItem(r.Source, MccArguments.GetItemType(r, "ItemType")))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Enchant.cs b/MinecraftClient/Commands/Enchant.cs index 74e5a5ab..813c734f 100644 --- a/MinecraftClient/Commands/Enchant.cs +++ b/MinecraftClient/Commands/Enchant.cs @@ -34,6 +34,7 @@ namespace MinecraftClient.Commands .Then(l => l.Literal("bottom") .Executes(r => DoEnchant(r.Source, slotId: 2))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Entitycmd.cs b/MinecraftClient/Commands/Entitycmd.cs index 19f5fefe..7cd4d8b4 100644 --- a/MinecraftClient/Commands/Entitycmd.cs +++ b/MinecraftClient/Commands/Entitycmd.cs @@ -72,6 +72,7 @@ namespace MinecraftClient.Commands .Then(l => l.Literal("list") .Executes(r => OperateWithType(r.Source, near: false, MccArguments.GetEntityType(r, "EntityType"), ActionType.List)))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Exit.cs b/MinecraftClient/Commands/Exit.cs index 281bd980..d2ac389e 100644 --- a/MinecraftClient/Commands/Exit.cs +++ b/MinecraftClient/Commands/Exit.cs @@ -23,6 +23,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("ExitCode", Arguments.Integer()) .Executes(r => DoExit(r.Source, Arguments.GetInteger(r, "ExitCode")))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); diff --git a/MinecraftClient/Commands/Health.cs b/MinecraftClient/Commands/Health.cs index 308059b6..21df0efd 100644 --- a/MinecraftClient/Commands/Health.cs +++ b/MinecraftClient/Commands/Health.cs @@ -21,6 +21,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Executes(r => LogHealth(r.Source)) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Inventory.cs b/MinecraftClient/Commands/Inventory.cs index fd13a1c3..9b8325ea 100644 --- a/MinecraftClient/Commands/Inventory.cs +++ b/MinecraftClient/Commands/Inventory.cs @@ -102,6 +102,7 @@ namespace MinecraftClient.Commands .Then(l => l.Literal("all") .Executes(r => DoDropAction(r.Source, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack)))))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/List.cs b/MinecraftClient/Commands/List.cs index b06a4b9a..7e991f55 100644 --- a/MinecraftClient/Commands/List.cs +++ b/MinecraftClient/Commands/List.cs @@ -22,6 +22,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Executes(r => DoListPlayers(r.Source)) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Look.cs b/MinecraftClient/Commands/Look.cs index 5c78f47e..69f0dc2d 100644 --- a/MinecraftClient/Commands/Look.cs +++ b/MinecraftClient/Commands/Look.cs @@ -47,6 +47,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("Location", MccArguments.Location()) .Executes(r => LookAtLocation(r.Source, MccArguments.GetLocation(r, "Location")))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Move.cs b/MinecraftClient/Commands/Move.cs index 89065765..fa94a06b 100644 --- a/MinecraftClient/Commands/Move.cs +++ b/MinecraftClient/Commands/Move.cs @@ -79,6 +79,7 @@ namespace MinecraftClient.Commands .Then(l => l.Literal("-f") .Executes(r => MoveToLocation(r.Source, MccArguments.GetLocation(r, "location"), true)))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Reco.cs b/MinecraftClient/Commands/Reco.cs index 569ca465..482b4e0b 100644 --- a/MinecraftClient/Commands/Reco.cs +++ b/MinecraftClient/Commands/Reco.cs @@ -24,6 +24,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("AccountNick", MccArguments.AccountNick()) .Executes(r => DoReconnect(r.Source, Arguments.GetString(r, "AccountNick")))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Reload.cs b/MinecraftClient/Commands/Reload.cs index be8ba98d..95359159 100644 --- a/MinecraftClient/Commands/Reload.cs +++ b/MinecraftClient/Commands/Reload.cs @@ -21,6 +21,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Executes(r => DoReload(r.Source)) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Respawn.cs b/MinecraftClient/Commands/Respawn.cs index d494e0b7..f8dd542a 100644 --- a/MinecraftClient/Commands/Respawn.cs +++ b/MinecraftClient/Commands/Respawn.cs @@ -21,6 +21,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Executes(r => DoRespawn(r.Source)) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Script.cs b/MinecraftClient/Commands/Script.cs index 3c8dd07c..d2f310dd 100644 --- a/MinecraftClient/Commands/Script.cs +++ b/MinecraftClient/Commands/Script.cs @@ -23,6 +23,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("Script", Arguments.GreedyString()) .Executes(r => DoExecuteScript(r.Source, Arguments.GetString(r, "Script"), null))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Set.cs b/MinecraftClient/Commands/Set.cs index e46cfebb..75d8bbd0 100644 --- a/MinecraftClient/Commands/Set.cs +++ b/MinecraftClient/Commands/Set.cs @@ -22,6 +22,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("Expression", Arguments.GreedyString()) .Executes(r => DoSetVar(r.Source, Arguments.GetString(r, "Expression")))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Sneak.cs b/MinecraftClient/Commands/Sneak.cs index f5401ffb..01d470fa 100644 --- a/MinecraftClient/Commands/Sneak.cs +++ b/MinecraftClient/Commands/Sneak.cs @@ -22,6 +22,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Executes(r => DoSneak(r.Source)) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Tps.cs b/MinecraftClient/Commands/Tps.cs index f96e9674..a30749bb 100644 --- a/MinecraftClient/Commands/Tps.cs +++ b/MinecraftClient/Commands/Tps.cs @@ -22,6 +22,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Executes(r => DoLogTps(r.Source)) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Upgrade.cs b/MinecraftClient/Commands/Upgrade.cs index 30757eaa..35ae3783 100644 --- a/MinecraftClient/Commands/Upgrade.cs +++ b/MinecraftClient/Commands/Upgrade.cs @@ -37,6 +37,7 @@ namespace MinecraftClient.Commands .Then(l => l.Literal("cancel") .Executes(r => CancelDownloadUpdate(r.Source))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/UseItem.cs b/MinecraftClient/Commands/UseItem.cs index 1768cf38..4a0fe1f6 100644 --- a/MinecraftClient/Commands/UseItem.cs +++ b/MinecraftClient/Commands/UseItem.cs @@ -22,6 +22,7 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Executes(r => DoUseItem(r.Source)) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } diff --git a/MinecraftClient/Commands/Useblock.cs b/MinecraftClient/Commands/Useblock.cs index 1169c994..994e34ae 100644 --- a/MinecraftClient/Commands/Useblock.cs +++ b/MinecraftClient/Commands/Useblock.cs @@ -24,6 +24,7 @@ namespace MinecraftClient.Commands .Then(l => l.Argument("Location", MccArguments.Location()) .Executes(r => UseBlockAtLocation(r.Source, MccArguments.GetLocation(r, "Location")))) .Then(l => l.Literal("_help") + .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) ); } From 7ee08092d4f4888fb4465723bdef3bc91cf69795 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Wed, 14 Dec 2022 14:45:51 +0800 Subject: [PATCH 7/8] legacy color support --- .github/workflows/build-and-release.yml | 2 +- MinecraftClient.sln | 4 +- MinecraftClient/ChatBots/DiscordBridge.cs | 14 +++---- MinecraftClient/ChatBots/Farmer.cs | 18 ++++----- MinecraftClient/ChatBots/TelegramBridge.cs | 16 ++++---- MinecraftClient/ColorHelper.cs | 35 ++++++++++++++--- MinecraftClient/Commands/Chunk.cs | 8 ++-- MinecraftClient/Crypto/AesCfb8Stream.cs | 20 ++++------ MinecraftClient/MinecraftClient.csproj | 2 +- MinecraftClient/Program.cs | 13 +++---- .../Protocol/Message/ChatParser.cs | 8 ++-- .../ConfigComments/ConfigComments.Designer.cs | 22 ++++------- .../ConfigComments/ConfigComments.resx | 12 +++--- MinecraftClient/Settings.cs | 39 ++++++++++++------- 14 files changed, 116 insertions(+), 97 deletions(-) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 0ab15085..5e74359a 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -8,7 +8,7 @@ on: env: PROJECT: "MinecraftClient" - target-version: "net6.0" + target-version: "net7.0" compile-flags: "--self-contained=true -c Release -p:UseAppHost=true -p:IncludeNativeLibrariesForSelfExtract=true -p:DebugType=None" jobs: diff --git a/MinecraftClient.sln b/MinecraftClient.sln index d769e6ae..8f0049d8 100644 --- a/MinecraftClient.sln +++ b/MinecraftClient.sln @@ -26,8 +26,8 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - RESX_SortFileContentOnSave = True - SolutionGuid = {6DED60F4-9CF4-4DB3-8966-582B2EBE8487} RESX_ShowErrorsInErrorList = False + SolutionGuid = {6DED60F4-9CF4-4DB3-8966-582B2EBE8487} + RESX_SortFileContentOnSave = False EndGlobalSection EndGlobal diff --git a/MinecraftClient/ChatBots/DiscordBridge.cs b/MinecraftClient/ChatBots/DiscordBridge.cs index b9d5a50e..b46ad770 100644 --- a/MinecraftClient/ChatBots/DiscordBridge.cs +++ b/MinecraftClient/ChatBots/DiscordBridge.cs @@ -163,7 +163,7 @@ namespace MinecraftClient.ChatBots } catch (Exception e) { - LogToConsole("§w§l§f" + Translations.bot_DiscordBridge_canceled_sending); + LogToConsole("§§4§l§f" + Translations.bot_DiscordBridge_canceled_sending); LogDebugToConsole(e); } @@ -233,7 +233,7 @@ namespace MinecraftClient.ChatBots } catch (Exception e) { - LogToConsole("§w§l§f" + Translations.bot_DiscordBridge_canceled_sending); + LogToConsole("§§4§l§f" + Translations.bot_DiscordBridge_canceled_sending); LogDebugToConsole(e); } } @@ -249,7 +249,7 @@ namespace MinecraftClient.ChatBots } catch (Exception e) { - LogToConsole("§w§l§f" + Translations.bot_DiscordBridge_canceled_sending); + LogToConsole("§§4§l§f" + Translations.bot_DiscordBridge_canceled_sending); LogDebugToConsole(e); } } @@ -265,7 +265,7 @@ namespace MinecraftClient.ChatBots } catch (Exception e) { - LogToConsole("§w§l§f" + Translations.bot_DiscordBridge_canceled_sending); + LogToConsole("§§4§l§f" + Translations.bot_DiscordBridge_canceled_sending); LogDebugToConsole(e); } } @@ -291,7 +291,7 @@ namespace MinecraftClient.ChatBots } catch (Exception e) { - LogToConsole("§w§l§f" + Translations.bot_DiscordBridge_canceled_sending); + LogToConsole("§§4§l§f" + Translations.bot_DiscordBridge_canceled_sending); LogDebugToConsole(e); } } @@ -420,12 +420,12 @@ namespace MinecraftClient.ChatBots }); IsConnected = true; - LogToConsole("§y§l§f" + Translations.bot_DiscordBridge_connected); + LogToConsole("§§2§l§f" + Translations.bot_DiscordBridge_connected); await Task.Delay(-1); } catch (Exception e) { - LogToConsole("§w§l§f" + Translations.bot_DiscordBridge_unknown_error); + LogToConsole("§§4§l§f" + Translations.bot_DiscordBridge_unknown_error); LogToConsole(e); return; } diff --git a/MinecraftClient/ChatBots/Farmer.cs b/MinecraftClient/ChatBots/Farmer.cs index 072fe270..b035e22c 100644 --- a/MinecraftClient/ChatBots/Farmer.cs +++ b/MinecraftClient/ChatBots/Farmer.cs @@ -160,7 +160,7 @@ namespace MinecraftClient.ChatBots { if (!currentArg.Contains(':')) { - LogToConsole("§x§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)); + LogToConsole("§§6§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)); continue; } @@ -168,7 +168,7 @@ namespace MinecraftClient.ChatBots if (parts.Length != 2) { - LogToConsole("§x§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)); + LogToConsole("§§6§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)); continue; } @@ -177,11 +177,11 @@ namespace MinecraftClient.ChatBots case "r": case "radius": if (!int.TryParse(parts[1], NumberStyles.Any, CultureInfo.CurrentCulture, out radius)) - LogToConsole("§x§1§0" + Translations.bot_farmer_invalid_radius); + LogToConsole("§§6§1§0" + Translations.bot_farmer_invalid_radius); if (radius <= 0) { - LogToConsole("§x§1§0" + Translations.bot_farmer_invalid_radius); + LogToConsole("§§6§1§0" + Translations.bot_farmer_invalid_radius); radius = 30; } @@ -194,7 +194,7 @@ namespace MinecraftClient.ChatBots if (parts[1].Equals("true") || parts[1].Equals("1")) { - LogToConsole("§x§1§0" + Translations.bot_farmer_warining_force_unsafe); + LogToConsole("§§6§1§0" + Translations.bot_farmer_warining_force_unsafe); allowUnsafe = true; } else allowUnsafe = false; @@ -208,7 +208,7 @@ namespace MinecraftClient.ChatBots if (parts[1].Equals("true") || parts[1].Equals("1")) { - LogToConsole("§w§1§f" + Translations.bot_farmer_warining_allow_teleport); + LogToConsole("§§4§1§f" + Translations.bot_farmer_warining_allow_teleport); allowTeleport = true; } else allowTeleport = false; @@ -252,9 +252,9 @@ namespace MinecraftClient.ChatBots private void MainPorcess() { - LogToConsole("§y§1§f" + Translations.bot_farmer_started); - LogToConsole("§y§1§f " + Translations.bot_farmer_crop_type + ": " + cropType); - LogToConsole("§y§1§f " + Translations.bot_farmer_radius + ": " + farmingRadius); + LogToConsole("§§2§1§f" + Translations.bot_farmer_started); + LogToConsole("§§2§1§f " + Translations.bot_farmer_crop_type + ": " + cropType); + LogToConsole("§§2§1§f " + Translations.bot_farmer_radius + ": " + farmingRadius); while (running) { diff --git a/MinecraftClient/ChatBots/TelegramBridge.cs b/MinecraftClient/ChatBots/TelegramBridge.cs index 6139a8d0..eac48542 100644 --- a/MinecraftClient/ChatBots/TelegramBridge.cs +++ b/MinecraftClient/ChatBots/TelegramBridge.cs @@ -159,7 +159,7 @@ namespace MinecraftClient.ChatBots } catch (Exception e) { - LogToConsole("§w§l§f" + Translations.bot_TelegramBridge_canceled_sending); + LogToConsole("§§4§l§f" + Translations.bot_TelegramBridge_canceled_sending); LogDebugToConsole(e); } @@ -209,7 +209,7 @@ namespace MinecraftClient.ChatBots } catch (Exception e) { - LogToConsole("§w§l§f" + Translations.bot_TelegramBridge_canceled_sending); + LogToConsole("§§4§l§f" + Translations.bot_TelegramBridge_canceled_sending); LogDebugToConsole(e); } } @@ -232,7 +232,7 @@ namespace MinecraftClient.ChatBots } catch (Exception e) { - LogToConsole("§w§l§f" + Translations.bot_TelegramBridge_canceled_sending); + LogToConsole("§§4§l§f" + Translations.bot_TelegramBridge_canceled_sending); LogDebugToConsole(e); } } @@ -254,7 +254,7 @@ namespace MinecraftClient.ChatBots } if (string.IsNullOrEmpty(Config.ChannelId.Trim())) - LogToConsole("§w§l§f" + Translations.bot_TelegramBridge_missing_channel_id); + LogToConsole("§§4§l§f" + Translations.bot_TelegramBridge_missing_channel_id); botClient = new TelegramBotClient(Config.Token.Trim()); cancellationToken = new CancellationTokenSource(); @@ -273,12 +273,12 @@ namespace MinecraftClient.ChatBots IsConnected = true; SendMessage($"✅ {Translations.bot_TelegramBridge_connected}"); - LogToConsole($"§y§l§f{Translations.bot_TelegramBridge_connected}"); + LogToConsole($"§§2§l§f{Translations.bot_TelegramBridge_connected}"); if (Config.Authorized_Chat_Ids.Length == 0) { SendMessage($"⚠️ *{Translations.bot_TelegramBridge_missing_authorized_channels}* ⚠️"); - LogToConsole($"§w§l§f{Translations.bot_TelegramBridge_missing_authorized_channels}"); + LogToConsole($"§§4§l§f{Translations.bot_TelegramBridge_missing_authorized_channels}"); return; } @@ -286,7 +286,7 @@ namespace MinecraftClient.ChatBots } catch (Exception e) { - LogToConsole($"§w§l§f{Translations.bot_TelegramBridge_unknown_error}"); + LogToConsole($"§§4§l§f{Translations.bot_TelegramBridge_unknown_error}"); LogToConsole(e); return; } @@ -368,7 +368,7 @@ namespace MinecraftClient.ChatBots _ => exception.ToString() }; - LogToConsole("§w§l§f" + ErrorMessage); + LogToConsole("§§4§l§f" + ErrorMessage); return Task.CompletedTask; } } diff --git a/MinecraftClient/ColorHelper.cs b/MinecraftClient/ColorHelper.cs index 3f35b304..fe91a780 100644 --- a/MinecraftClient/ColorHelper.cs +++ b/MinecraftClient/ColorHelper.cs @@ -1,5 +1,5 @@ using System; -using static MinecraftClient.Settings.MainConfigHealper.MainConfig.AdvancedConfig; +using static MinecraftClient.Settings.ConsoleConfigHealper.ConsoleConfig; namespace MinecraftClient { @@ -75,14 +75,37 @@ namespace MinecraftClient public static string GetColorEscapeCode(byte R, byte G, byte B, bool foreground) { - return GetColorEscapeCode(R, G, B, foreground, Settings.Config.Main.Advanced.TerminalColorDepth); + return GetColorEscapeCode(R, G, B, foreground, Settings.Config.Console.General.ConsoleColorMode); } - public static string GetColorEscapeCode(byte R, byte G, byte B, bool foreground, TerminalColorDepthType colorDepth) + public static string GetColorEscapeCode(byte R, byte G, byte B, bool foreground, ConsoleColorModeType colorDepth) { switch (colorDepth) { - case TerminalColorDepthType.bit_4: + case ConsoleColorModeType.disable: + return string.Empty; + + case ConsoleColorModeType.legacy_4bit: + { + ColorRGBA color = new(R, G, B); + int best_idx = 0; + double min_distance = ColorMap4[0].Item1.Distance(color); + for (int i = 1; i < ColorMap4.Length; ++i) + { + double distance = ColorMap4[i].Item1.Distance(color); + if (distance < min_distance) + { + min_distance = distance; + best_idx = i; + } + } + if (foreground) + return $"§{best_idx:X}"; + else + return $"§§{best_idx:X}"; + } + + case ConsoleColorModeType.vt100_4bit: { ColorRGBA color = new(R, G, B); int best_idx = 0; @@ -99,7 +122,7 @@ namespace MinecraftClient return string.Format("\u001b[{0}m", ColorMap4[best_idx].Item2 - (foreground ? 10 : 0)); } - case TerminalColorDepthType.bit_8: + case ConsoleColorModeType.vt100_8bit: { ColorRGBA color = new(R, G, B); int R_idx = (int)(R <= 95 ? Math.Round(R / 95.0) : 1 + Math.Round((R - 95.0) / 40.0)); @@ -126,7 +149,7 @@ namespace MinecraftClient return string.Format("\u001B[{0};5;{1}m", (foreground ? 38 : 48), ColorMap8[best_idx].Item2); } - case TerminalColorDepthType.bit_24: + case ConsoleColorModeType.vt100_24bit: return string.Format("\u001B[{0};2;{1};{2};{3}m", (foreground ? 38 : 48), R, G, B); default: diff --git a/MinecraftClient/Commands/Chunk.cs b/MinecraftClient/Commands/Chunk.cs index 3452716b..cdc26e14 100644 --- a/MinecraftClient/Commands/Chunk.cs +++ b/MinecraftClient/Commands/Chunk.cs @@ -203,9 +203,9 @@ namespace MinecraftClient.Commands for (int x = leftMost; x <= rightMost; ++x) { if (z == current.ChunkZ && x == current.ChunkX) - sb.Append("§z"); // Player Location: background gray + sb.Append("§§7"); // Player Location: background gray else if (z == markChunkZ && x == markChunkX) - sb.Append("§w"); // Marked chunk: background red + sb.Append("§§4"); // Marked chunk: background red ChunkColumn? chunkColumn = world[x, z]; if (chunkColumn == null) @@ -216,12 +216,12 @@ namespace MinecraftClient.Commands sb.Append(chunkStatusStr[1]); if ((z == current.ChunkZ && x == current.ChunkX) || (z == markChunkZ && x == markChunkX)) - sb.Append("§r"); // Reset background color + sb.Append("§§r"); // Reset background color } sb.Append('\n'); } - sb.Append(string.Format(Translations.cmd_chunk_icon, "§z §r", "§w §r", chunkStatusStr[0], chunkStatusStr[1], chunkStatusStr[2])); + sb.Append(string.Format(Translations.cmd_chunk_icon, "§§7 §§r", "§§4 §§r", chunkStatusStr[0], chunkStatusStr[1], chunkStatusStr[2])); handler.Log.Info(sb.ToString()); return r.SetAndReturn(Status.Done); diff --git a/MinecraftClient/Crypto/AesCfb8Stream.cs b/MinecraftClient/Crypto/AesCfb8Stream.cs index f653546c..d50aaa54 100644 --- a/MinecraftClient/Crypto/AesCfb8Stream.cs +++ b/MinecraftClient/Crypto/AesCfb8Stream.cs @@ -9,7 +9,7 @@ namespace MinecraftClient.Crypto { public class AesCfb8Stream : Stream { - public static readonly int blockSize = 16; + public const int blockSize = 16; private readonly Aes? Aes = null; private readonly FastAes? FastAes = null; @@ -109,7 +109,7 @@ namespace MinecraftClient.Crypto if (inStreamEnded) return 0; - Span blockOutput = FastAes != null ? stackalloc byte[blockSize] : null; + Span blockOutput = stackalloc byte[blockSize]; byte[] inputBuf = new byte[blockSize + required]; Array.Copy(ReadStreamIV, inputBuf, blockSize); @@ -135,18 +135,12 @@ namespace MinecraftClient.Crypto } else { - OrderablePartitioner> rangePartitioner = curRead <= 256 ? - Partitioner.Create(readed, processEnd, 32) : Partitioner.Create(readed, processEnd); - Parallel.ForEach(rangePartitioner, (range, loopState) => + for (int idx = readed; idx < processEnd; idx++) { - Span blockOutput = stackalloc byte[blockSize]; - for (int idx = range.Item1; idx < range.Item2; idx++) - { - ReadOnlySpan blockInput = new(inputBuf, idx, blockSize); - Aes!.EncryptEcb(blockInput, blockOutput, PaddingMode.None); - buffer[outOffset + idx] = (byte)(blockOutput[0] ^ inputBuf[idx + blockSize]); - } - }); + ReadOnlySpan blockInput = new(inputBuf, idx, blockSize); + Aes!.EncryptEcb(blockInput, blockOutput, PaddingMode.None); + buffer[outOffset + idx] = (byte)(blockOutput[0] ^ inputBuf[idx + blockSize]); + } } } diff --git a/MinecraftClient/MinecraftClient.csproj b/MinecraftClient/MinecraftClient.csproj index 95597b42..b0faada9 100644 --- a/MinecraftClient/MinecraftClient.csproj +++ b/MinecraftClient/MinecraftClient.csproj @@ -1,6 +1,6 @@  - net6.0 + net7.0 Exe publish\ false diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index cd525fb4..503f4f40 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -18,6 +18,7 @@ using MinecraftClient.Scripting; using MinecraftClient.WinAPI; using Tomlet; using static MinecraftClient.Settings; +using static MinecraftClient.Settings.ConsoleConfigHealper.ConsoleConfig; using static MinecraftClient.Settings.MainConfigHealper.MainConfig.AdvancedConfig; using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig; @@ -98,9 +99,7 @@ namespace MinecraftClient //Build information to facilitate processing of bug reports if (BuildInfo != null) - { ConsoleIO.WriteLineFormatted("§8" + BuildInfo); - } //Debug input ? if (args.Length == 1 && args[0] == "--keyboard-debug") @@ -288,7 +287,7 @@ namespace MinecraftClient } } - if (Config.Main.Advanced.ConsoleTitle != "") + if (!string.IsNullOrWhiteSpace(Config.Main.Advanced.ConsoleTitle)) { InternalConfig.Username = "New Window"; Console.Title = Config.AppVar.ExpandVars(Config.Main.Advanced.ConsoleTitle); @@ -319,28 +318,28 @@ namespace MinecraftClient Random random = new(); { // Test 8 bit color StringBuilder sb = new(); - sb.Append("[0123456789]: (8bit)["); + sb.Append("[0123456789]: (vt100 8bit)["); for (int i = 0; i < 10; ++i) { sb.Append(ColorHelper.GetColorEscapeCode((byte)random.Next(255), (byte)random.Next(255), (byte)random.Next(255), true, - TerminalColorDepthType.bit_8)).Append(i); + ConsoleColorModeType.vt100_8bit)).Append(i); } sb.Append(ColorHelper.GetResetEscapeCode()).Append(']'); ConsoleIO.WriteLine(string.Format(Translations.debug_color_test, sb.ToString())); } { // Test 24 bit color StringBuilder sb = new(); - sb.Append("[0123456789]: (24bit)["); + sb.Append("[0123456789]: (vt100 24bit)["); for (int i = 0; i < 10; ++i) { sb.Append(ColorHelper.GetColorEscapeCode((byte)random.Next(255), (byte)random.Next(255), (byte)random.Next(255), true, - TerminalColorDepthType.bit_24)).Append(i); + ConsoleColorModeType.vt100_24bit)).Append(i); } sb.Append(ColorHelper.GetResetEscapeCode()).Append(']'); ConsoleIO.WriteLine(string.Format(Translations.debug_color_test, sb.ToString())); diff --git a/MinecraftClient/Protocol/Message/ChatParser.cs b/MinecraftClient/Protocol/Message/ChatParser.cs index 3df06572..2aa87b00 100644 --- a/MinecraftClient/Protocol/Message/ChatParser.cs +++ b/MinecraftClient/Protocol/Message/ChatParser.cs @@ -119,7 +119,7 @@ namespace MinecraftClient.Protocol.Message if (message.isSystemChat) { if (Config.Signature.MarkSystemMessage) - color = "§z §r "; // Custom color code §z : Background Gray + color = "§§7 §§r "; // Background Gray } else { @@ -128,18 +128,18 @@ namespace MinecraftClient.Protocol.Message if (Config.Signature.ShowModifiedChat && message.unsignedContent != null) { if (Config.Signature.MarkModifiedMsg) - color = "§x §r "; // Custom color code §x : Background Yellow + color = "§§6 §§r "; // Background Yellow } else { if (Config.Signature.MarkLegallySignedMsg) - color = "§y §r "; // Custom color code §y : Background Green + color = "§§2 §§r "; // Background Green } } else { if (Config.Signature.MarkIllegallySignedMsg) - color = "§w §r "; // Custom color code §w : Background Red + color = "§§4 §§r "; // Background Red } } return color + text; diff --git a/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs b/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs index bf0cbc7f..8f358c62 100644 --- a/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs +++ b/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs @@ -1085,7 +1085,8 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to The settings for command completion suggestions.. + /// Looks up a localized string similar to The settings for command completion suggestions. + ///Custom colors are only available when using "vt100_24bit" color mode.. /// internal static string Console_CommandSuggestion { get { @@ -1112,20 +1113,20 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to If a garbled code like "←[0m" appears on the terminal, you can turn off this.. + /// Looks up a localized string similar to Use "disable", "legacy_4bit", "vt100_4bit", "vt100_8bit" or "vt100_24bit". If a garbled code like "←[0m" appears on the terminal, you can try switching to "legacy_4bit" mode, or just disable it.. /// - internal static string Console_Enable_Color { + internal static string Console_General_ConsoleColorMode { get { - return ResourceManager.GetString("Console.Enable_Color", resourceCulture); + return ResourceManager.GetString("Console.General.ConsoleColorMode", resourceCulture); } } /// /// Looks up a localized string similar to You can use "Ctrl+P" to print out the current input and cursor position.. /// - internal static string Console_General_Display_Uesr_Input { + internal static string Console_General_Display_Input { get { - return ResourceManager.GetString("Console.General.Display_Uesr_Input", resourceCulture); + return ResourceManager.GetString("Console.General.Display_Input", resourceCulture); } } @@ -1559,15 +1560,6 @@ namespace MinecraftClient { } } - /// - /// Looks up a localized string similar to Use "none", "bit_4", "bit_8" or "bit_24". This can be checked by opening the debug log.. - /// - internal static string Main_Advanced_TerminalColorDepth { - get { - return ResourceManager.GetString("Main.Advanced.TerminalColorDepth", resourceCulture); - } - } - /// /// Looks up a localized string similar to Uses more ram, cpu, bandwidth but allows you to move around.. /// diff --git a/MinecraftClient/Resources/ConfigComments/ConfigComments.resx b/MinecraftClient/Resources/ConfigComments/ConfigComments.resx index 1b71fcd9..bd3a27de 100644 --- a/MinecraftClient/Resources/ConfigComments/ConfigComments.resx +++ b/MinecraftClient/Resources/ConfigComments/ConfigComments.resx @@ -539,7 +539,8 @@ When this happens, you'll need to configure chat format below, see https://mccte Console-related settings. - The settings for command completion suggestions. + The settings for command completion suggestions. +Custom colors are only available when using "vt100_24bit" color mode. Whether to display command suggestions in the console. @@ -547,10 +548,10 @@ When this happens, you'll need to configure chat format below, see https://mccte Enable this option if the arrows in the command suggestions are not displayed properly in your terminal. - - If a garbled code like "←[0m" appears on the terminal, you can turn off this. + + Use "disable", "legacy_4bit", "vt100_4bit", "vt100_8bit" or "vt100_24bit". If a garbled code like "←[0m" appears on the terminal, you can try switching to "legacy_4bit" mode, or just disable it. - + You can use "Ctrl+P" to print out the current input and cursor position. @@ -701,9 +702,6 @@ Usage examples: "/tell <mybot> connect Server1", "/connect Server2" Temporary fix for Badpacket issue on some servers. - - Use "none", "bit_4", "bit_8" or "bit_24". This can be checked by opening the debug log. - Uses more ram, cpu, bandwidth but allows you to move around. diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index 0a07bb40..8ddd556b 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -605,9 +605,6 @@ namespace MinecraftClient [TomlInlineComment("$Main.Advanced.enable_emoji$")] public bool EnableEmoji = true; - [TomlInlineComment("$Main.Advanced.TerminalColorDepth$")] - public TerminalColorDepthType TerminalColorDepth = TerminalColorDepthType.bit_24; - [TomlInlineComment("$Main.Advanced.MinTerminalWidth$")] public int MinTerminalWidth = 16; @@ -640,8 +637,6 @@ namespace MinecraftClient public enum ResolveSrvRecordType { no, fast, yes }; public enum ForgeConfigType { no, auto, force }; - - public enum TerminalColorDepthType { bit_4, bit_8, bit_24 }; } public struct AccountInfoConfig @@ -788,12 +783,26 @@ namespace MinecraftClient public void OnSettingUpdate() { - ConsoleInteractive.ConsoleWriter.EnableColor = General.Enable_Color; + // Reader + ConsoleInteractive.ConsoleReader.DisplayUesrInput = General.Display_Input; - ConsoleInteractive.ConsoleReader.DisplayUesrInput = General.Display_Uesr_Input; + // Writer + ConsoleInteractive.ConsoleWriter.EnableColor = General.ConsoleColorMode != ConsoleColorModeType.disable; + + ConsoleInteractive.ConsoleWriter.UseVT100ColorCode = General.ConsoleColorMode != ConsoleColorModeType.legacy_4bit; + + // Buffer + General.History_Input_Records = + ConsoleInteractive.ConsoleBuffer.SetBackreadBufferLimit(General.History_Input_Records); + + // Suggestion + if (General.ConsoleColorMode == ConsoleColorModeType.disable) + CommandSuggestion.Enable_Color = false; ConsoleInteractive.ConsoleSuggestion.EnableColor = CommandSuggestion.Enable_Color; + ConsoleInteractive.ConsoleSuggestion.Enable24bitColor = General.ConsoleColorMode == ConsoleColorModeType.vt100_24bit; + ConsoleInteractive.ConsoleSuggestion.UseBasicArrow = CommandSuggestion.Use_Basic_Arrow; CommandSuggestion.Max_Suggestion_Width = @@ -802,7 +811,7 @@ namespace MinecraftClient CommandSuggestion.Max_Displayed_Suggestions = ConsoleInteractive.ConsoleSuggestion.SetMaxSuggestionCount(CommandSuggestion.Max_Displayed_Suggestions); - // CommandSuggestion color settings + // Suggestion color settings { if (!CheckColorCode(CommandSuggestion.Text_Color)) { @@ -872,11 +881,14 @@ namespace MinecraftClient [TomlDoNotInlineObject] public class MainConfig { - [TomlInlineComment("$Console.Enable_Color$")] - public bool Enable_Color = true; + [TomlInlineComment("$Console.General.ConsoleColorMode$")] + public ConsoleColorModeType ConsoleColorMode = ConsoleColorModeType.vt100_24bit; - [TomlInlineComment("$Console.General.Display_Uesr_Input$")] - public bool Display_Uesr_Input = true; + [TomlInlineComment("$Console.General.Display_Input$")] + public bool Display_Input = true; + + [TomlInlineComment("$Console.General.History_Input_Records$")] + public int History_Input_Records = 32; } [TomlDoNotInlineObject] @@ -885,7 +897,6 @@ namespace MinecraftClient [TomlInlineComment("$Console.CommandSuggestion.Enable$")] public bool Enable = true; - [TomlInlineComment("$Console.Enable_Color$")] public bool Enable_Color = true; [TomlInlineComment("$Console.CommandSuggestion.Use_Basic_Arrow$")] @@ -909,6 +920,8 @@ namespace MinecraftClient public string Arrow_Symbol_Color = "#d1d5db"; } + + public enum ConsoleColorModeType { disable, legacy_4bit, vt100_4bit, vt100_8bit, vt100_24bit }; } } From 9c8afb7d3c20e98225d5c9583a865d92e244dc00 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Mon, 2 Jan 2023 18:52:49 +0800 Subject: [PATCH 8/8] Bug fix --- MinecraftClient/McClient.cs | 2 +- MinecraftClient/Program.cs | 6 +++--- MinecraftClient/Scripting/CSharpRunner.cs | 1 + MinecraftClient/Scripting/ChatBot.cs | 5 ----- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index 80defaf6..003dcbc2 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -203,7 +203,7 @@ namespace MinecraftClient Log.Info(string.Format(Translations.mcc_joined, Config.Main.Advanced.InternalCmdChar.ToLogString())); cmdprompt = new CancellationTokenSource(); - ConsoleInteractive.ConsoleReader.BeginReadThread(cmdprompt); + ConsoleInteractive.ConsoleReader.BeginReadThread(); ConsoleInteractive.ConsoleReader.MessageReceived += ConsoleReaderOnMessageReceived; ConsoleInteractive.ConsoleReader.OnInputChange += ConsoleIO.AutocompleteHandler; } diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index 503f4f40..7eaaafa8 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -287,7 +287,7 @@ namespace MinecraftClient } } - if (!string.IsNullOrWhiteSpace(Config.Main.Advanced.ConsoleTitle)) + if (OperatingSystem.IsWindows() && !string.IsNullOrWhiteSpace(Config.Main.Advanced.ConsoleTitle)) { InternalConfig.Username = "New Window"; Console.Title = Config.AppVar.ExpandVars(Config.Main.Advanced.ConsoleTitle); @@ -463,7 +463,7 @@ namespace MinecraftClient InternalConfig.Username = session.PlayerName; bool isRealms = false; - if (Config.Main.Advanced.ConsoleTitle != "") + if (OperatingSystem.IsWindows() && !string.IsNullOrWhiteSpace(Config.Main.Advanced.ConsoleTitle)) Console.Title = Config.AppVar.ExpandVars(Config.Main.Advanced.ConsoleTitle); if (Config.Main.Advanced.PlayerHeadAsIcon && OperatingSystem.IsWindows()) @@ -614,7 +614,7 @@ namespace MinecraftClient client = new McClient(session, playerKeyPair, InternalConfig.ServerIP, InternalConfig.ServerPort, protocolversion, forgeInfo); //Update console title - if (Config.Main.Advanced.ConsoleTitle != "") + if (OperatingSystem.IsWindows() && !string.IsNullOrWhiteSpace(Config.Main.Advanced.ConsoleTitle)) Console.Title = Config.AppVar.ExpandVars(Config.Main.Advanced.ConsoleTitle); } catch (NotSupportedException) diff --git a/MinecraftClient/Scripting/CSharpRunner.cs b/MinecraftClient/Scripting/CSharpRunner.cs index e6587440..d056a9a4 100644 --- a/MinecraftClient/Scripting/CSharpRunner.cs +++ b/MinecraftClient/Scripting/CSharpRunner.cs @@ -88,6 +88,7 @@ namespace MinecraftClient.Scripting "using System.Net;", "using System.Threading;", "using MinecraftClient;", + "using MinecraftClient.Scripting;", "using MinecraftClient.Mapping;", "using MinecraftClient.Inventory;", string.Join("\n", libs), diff --git a/MinecraftClient/Scripting/ChatBot.cs b/MinecraftClient/Scripting/ChatBot.cs index d73f0884..67bc3cb5 100644 --- a/MinecraftClient/Scripting/ChatBot.cs +++ b/MinecraftClient/Scripting/ChatBot.cs @@ -1672,11 +1672,6 @@ namespace MinecraftClient.Scripting } - public string Run(McClient handler, string command, Dictionary? localVars) - { - return Runner(command, GetArgs(command)); - } - /// /// ChatBotCommand Constructor ///