Implement command completion suggestions.

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

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots

View file

@ -1,5 +1,8 @@
using System; using System;
using Brigadier.NET;
using MinecraftClient.CommandHandler;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots
@ -90,7 +93,7 @@ namespace MinecraftClient.ChatBots
count = 0; count = 0;
} }
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
if (Config.Use_Terrain_Handling) if (Config.Use_Terrain_Handling)
{ {

View file

@ -1,6 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Brigadier.NET;
using MinecraftClient.CommandHandler;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots
@ -109,7 +112,7 @@ namespace MinecraftClient.ChatBots
attackPassive = Config.Attack_Passive; attackPassive = Config.Attack_Passive;
} }
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
if (!GetEntityHandlingEnabled()) if (!GetEntityHandlingEnabled())
{ {

View file

@ -2,8 +2,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
using static MinecraftClient.ChatBots.AutoCraft.Configs; using static MinecraftClient.ChatBots.AutoCraft.Configs;
@ -11,6 +16,8 @@ namespace MinecraftClient.ChatBots
{ {
public class AutoCraft : ChatBot public class AutoCraft : ChatBot
{ {
public const string CommandName = "autocraft";
public static Configs Config = new(); public static Configs Config = new();
[TomlDoNotInlineObject] [TomlDoNotInlineObject]
@ -40,7 +47,7 @@ namespace MinecraftClient.ChatBots
Name: "Recipe-Name-2", Name: "Recipe-Name-2",
Type: CraftTypeConfig.table, Type: CraftTypeConfig.table,
Result: ItemType.StoneBricks, Result: ItemType.StoneBricks,
Slots: new ItemType[9] { Slots: new ItemType[9] {
ItemType.Stone, ItemType.Stone, ItemType.Null, ItemType.Stone, ItemType.Stone, ItemType.Null,
ItemType.Stone, ItemType.Stone, ItemType.Null, ItemType.Stone, ItemType.Stone, ItemType.Null,
ItemType.Null, ItemType.Null, ItemType.Null, ItemType.Null, ItemType.Null, ItemType.Null,
@ -117,7 +124,7 @@ namespace MinecraftClient.ChatBots
public ItemType Result = ItemType.Air; 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, 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<CmdResult> dispatcher)
{ {
if (!GetInventoryEnabled()) if (!GetInventoryEnabled())
{ {
@ -288,81 +295,93 @@ namespace MinecraftClient.ChatBots
UnloadBot(); UnloadBot();
return; 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<CmdResult> dispatcher)
{ {
if (args.Length > 0) dispatcher.Unregister(CommandName);
{ dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName);
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();
} }
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"); return r.SetAndReturn(cmd switch
}
private string GetCommandHelp(string cmd)
{
return cmd.ToLower() switch
{ {
#pragma warning disable format // @formatter:off #pragma warning disable format // @formatter:off
"load" => Translations.bot_autoCraft_help_load,
"list" => Translations.bot_autoCraft_help_list, "list" => Translations.bot_autoCraft_help_list,
"reload" => Translations.bot_autoCraft_help_reload,
"resetcfg" => Translations.bot_autoCraft_help_resetcfg,
"start" => Translations.bot_autoCraft_help_start, "start" => Translations.bot_autoCraft_help_start,
"stop" => Translations.bot_autoCraft_help_stop, "stop" => Translations.bot_autoCraft_help_stop,
"help" => Translations.bot_autoCraft_help_help, "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 #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 #region Core part of auto-crafting
@ -442,7 +461,7 @@ namespace MinecraftClient.ChatBots
ItemType ResultItem = recipeConfig.Result; ItemType ResultItem = recipeConfig.Result;
ContainerType CraftingAreaType = ContainerType CraftingAreaType =
(recipeConfig.Type == CraftTypeConfig.player) ? ContainerType.PlayerInventory : ContainerType.Crafting; (recipeConfig.Type == CraftTypeConfig.player) ? ContainerType.PlayerInventory : ContainerType.Crafting;
PrepareCrafting(new Recipe(materials, ResultItem, CraftingAreaType)); PrepareCrafting(new Recipe(materials, ResultItem, CraftingAreaType));

View file

@ -1,13 +1,20 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots
{ {
public class AutoDig : ChatBot public class AutoDig : ChatBot
{ {
public const string CommandName = "autodig";
public static Configs Config = new(); public static Configs Config = new();
[TomlDoNotInlineObject] [TomlDoNotInlineObject]
@ -60,7 +67,7 @@ namespace MinecraftClient.ChatBots
{ {
if (Auto_Start_Delay >= 0) if (Auto_Start_Delay >= 0)
Auto_Start_Delay = Math.Max(0.1, Auto_Start_Delay); Auto_Start_Delay = Math.Max(0.1, Auto_Start_Delay);
if (Dig_Timeout >= 0) if (Dig_Timeout >= 0)
Dig_Timeout = Math.Max(0.1, Dig_Timeout); Dig_Timeout = Math.Max(0.1, Dig_Timeout);
@ -103,7 +110,7 @@ namespace MinecraftClient.ChatBots
Stopping, Stopping,
} }
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
if (!GetTerrainEnabled()) if (!GetTerrainEnabled())
{ {
@ -117,32 +124,67 @@ namespace MinecraftClient.ChatBots
if (!inventoryEnabled && Config.Auto_Tool_Switch) if (!inventoryEnabled && Config.Auto_Tool_Switch)
LogToConsole(Translations.bot_autodig_no_inv_handle); 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<CmdResult> 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]) #pragma warning disable format // @formatter:off
{ "start" => Translations.bot_autodig_help_start,
case "start": "stop" => Translations.bot_autodig_help_stop,
lock (stateLock) "help" => Translations.bot_autodig_help_help,
{ _ => string.Format(Translations.bot_autodig_available_cmd, "start, stop, help")
counter = 0; + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false),
state = State.WaitingStart; #pragma warning restore format // @formatter:on
} });
return Translations.bot_autodig_start; }
case "stop":
StopDigging(); private int OnCommandStart(CmdResult r)
return Translations.bot_autodig_stop; {
case "help": lock (stateLock)
return GetCommandHelp(args.Length >= 2 ? args[1] : ""); {
default: counter = 0;
return GetHelp(); 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() private void StartDigging()
@ -240,7 +282,7 @@ namespace MinecraftClient.ChatBots
else if ((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) || else if ((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) ||
(Config.List_Type == Configs.ListType.blacklist && !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))) (Config.Mode == Configs.ModeType.both && Config._Locations.Contains(blockLoc)))
{ {
if (DigBlock(blockLoc, lookAtBlock: false)) if (DigBlock(blockLoc, lookAtBlock: false))
@ -288,8 +330,8 @@ namespace MinecraftClient.ChatBots
foreach (Location location in Config._Locations) foreach (Location location in Config._Locations)
{ {
Block block = GetWorld().GetBlock(location); Block block = GetWorld().GetBlock(location);
if (block.Type != Material.Air && if (block.Type != Material.Air &&
((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) || ((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) ||
(Config.List_Type == Configs.ListType.blacklist && !Config.Blocks.Contains(block.Type)))) (Config.List_Type == Configs.ListType.blacklist && !Config.Blocks.Contains(block.Type))))
{ {
double distance = current.Distance(location); double distance = current.Distance(location);
@ -401,23 +443,5 @@ namespace MinecraftClient.ChatBots
return base.OnDisconnect(reason, message); 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
};
}
} }
} }

View file

@ -1,7 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
using static MinecraftClient.ChatBots.AutoDrop.Configs; using static MinecraftClient.ChatBots.AutoDrop.Configs;
@ -9,6 +14,8 @@ namespace MinecraftClient.ChatBots
{ {
public class AutoDrop : ChatBot public class AutoDrop : ChatBot
{ {
public const string CommandName = "autodrop";
public static Configs Config = new(); public static Configs Config = new();
[TomlDoNotInlineObject] [TomlDoNotInlineObject]
@ -38,111 +45,7 @@ namespace MinecraftClient.ChatBots
private readonly int updateDebounceValue = 2; private readonly int updateDebounceValue = 2;
private int inventoryUpdated = -1; private int inventoryUpdated = -1;
public string CommandHandler(string cmd, string[] args) public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{
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 <item name>";
}
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 <item name>";
}
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()
{ {
if (!GetInventoryEnabled()) if (!GetInventoryEnabled())
{ {
@ -151,8 +54,113 @@ namespace MinecraftClient.ChatBots
UnloadBot(); UnloadBot();
return; 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<CmdResult> 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 <item name>",
"remove" => Translations.cmd_inventory_help_usage + ": remove <item name>",
"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() public override void Update()

View file

@ -1,5 +1,6 @@
using System; using System;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots

View file

@ -2,8 +2,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
using static MinecraftClient.ChatBots.AutoFishing.Configs; using static MinecraftClient.ChatBots.AutoFishing.Configs;
@ -15,6 +20,8 @@ namespace MinecraftClient.ChatBots
/// </summary> /// </summary>
public class AutoFishing : ChatBot public class AutoFishing : ChatBot
{ {
public const string CommandName = "autofishing";
public static Configs Config = new(); public static Configs Config = new();
[TomlDoNotInlineObject] [TomlDoNotInlineObject]
@ -169,87 +176,119 @@ namespace MinecraftClient.ChatBots
Stopping, Stopping,
} }
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
if (!GetEntityHandlingEnabled()) if (!GetEntityHandlingEnabled())
{ {
LogToConsole(Translations.extra_entity_required); LogToConsole(Translations.extra_entity_required);
state = FishingState.WaitJoinGame; state = FishingState.WaitJoinGame;
} }
inventoryEnabled = GetInventoryEnabled(); inventoryEnabled = GetInventoryEnabled();
if (!inventoryEnabled) if (!inventoryEnabled)
LogToConsole(Translations.bot_autoFish_no_inv_handle); 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<CmdResult> 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]) #pragma warning disable format // @formatter:off
{ "start" => Translations.bot_autoFish_help_start,
case "start": "stop" => Translations.bot_autoFish_help_stop,
isFishing = false; "status" => Translations.bot_autoFish_help_status,
lock (stateLock) "help" => Translations.bot_autoFish_help_help,
{ _ => string.Format(Translations.bot_autoFish_available_cmd, "start, stop, status, help")
isFishing = false; + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false),
counter = 0; #pragma warning restore format // @formatter:on
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;
List<KeyValuePair<ItemType, uint>> orderedList = fishItemCnt.OrderBy(x => x.Value).ToList(); private int OnCommandStart(CmdResult r)
int maxLen = orderedList[^1].Value.ToString().Length; {
StringBuilder sb = new(); isFishing = false;
sb.Append(Translations.bot_autoFish_status_info); lock (stateLock)
foreach ((ItemType type, uint cnt) in orderedList) {
{ isFishing = false;
sb.Append(Environment.NewLine); counter = 0;
state = FishingState.StartMove;
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();
}
} }
else return r.SetAndReturn(CmdResult.Status.Done, Translations.bot_autoFish_start);
return GetHelp(); }
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<KeyValuePair<ItemType, uint>> 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() private void StartFishing()
@ -386,7 +425,7 @@ namespace MinecraftClient.ChatBots
public override void OnEntitySpawn(Entity entity) public override void OnEntitySpawn(Entity entity)
{ {
if (fishItemCounter < 15 && entity.Type == EntityType.Item && Math.Abs(entity.Location.Y - LastPos.Y) < 2.2 && 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) 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))); 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) 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)) (state == FishingState.WaitingFishToBite || state == FishingState.WaitingFishingBobber))
{ {
Location Pos = entity.Location; Location Pos = entity.Location;
@ -620,24 +659,5 @@ namespace MinecraftClient.ChatBots
return false; 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
};
}
} }
} }

View file

@ -1,4 +1,7 @@
using System; using System;
using Brigadier.NET;
using MinecraftClient.CommandHandler;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots
@ -43,7 +46,7 @@ namespace MinecraftClient.ChatBots
if (Delay.min > Delay.max) if (Delay.min > Delay.max)
(Delay.min, Delay.max) = (Delay.max, Delay.min); (Delay.min, Delay.max) = (Delay.max, Delay.min);
if (Retries == -1) if (Retries == -1)
Retries = int.MaxValue; Retries = int.MaxValue;
@ -82,7 +85,12 @@ namespace MinecraftClient.ChatBots
LogDebugToConsole(string.Format(Translations.bot_autoRelog_launch, Config.Retries)); LogDebugToConsole(string.Format(Translations.bot_autoRelog_launch, Config.Retries));
} }
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{
Initialize();
}
private void Initialize()
{ {
McClient.ReconnectionAttemptsLeft = Config.Retries; McClient.ReconnectionAttemptsLeft = Config.Retries;
if (Config.Ignore_Kick_Message) if (Config.Ignore_Kick_Message)

View file

@ -4,6 +4,10 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Brigadier.NET;
using MinecraftClient.CommandHandler;
using MinecraftClient.Scripting;
using PInvoke;
using Tomlet.Attributes; using Tomlet.Attributes;
using static MinecraftClient.Settings; using static MinecraftClient.Settings;
@ -183,7 +187,7 @@ namespace MinecraftClient.ChatBots
/// <summary> /// <summary>
/// Initialize the AutoRespond bot from the matches file /// Initialize the AutoRespond bot from the matches file
/// </summary> /// </summary>
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
if (File.Exists(Config.Matches_File)) if (File.Exists(Config.Matches_File))
{ {
@ -304,12 +308,12 @@ namespace MinecraftClient.ChatBots
{ {
Dictionary<string, object> localVars = new(); Dictionary<string, object> localVars = new();
string? toPerform = rule.Match(sender, message, msgType, localVars); 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)); LogToConsole(string.Format(Translations.bot_autoRespond_match_run, toPerform));
PerformInternalCommand(toPerform, ref response, localVars); PerformInternalCommand(toPerform, ref response, localVars);
if (!String.IsNullOrEmpty(response)) if (response.status != CmdResult.Status.Done || !string.IsNullOrWhiteSpace(response.result))
LogToConsole(response); LogToConsole(response);
} }
} }

View file

@ -1,5 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using MinecraftClient.CommandHandler;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots 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) if (saveInternal)
{ {

View file

@ -3,16 +3,23 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Brigadier.NET;
using Brigadier.NET.Builder;
using DSharpPlus; using DSharpPlus;
using DSharpPlus.Entities; using DSharpPlus.Entities;
using DSharpPlus.Exceptions; using DSharpPlus.Exceptions;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots
{ {
public class DiscordBridge : ChatBot public class DiscordBridge : ChatBot
{ {
public const string CommandName = "dscbridge";
private enum BridgeDirection private enum BridgeDirection
{ {
Both = 0, Both = 0,
@ -68,19 +75,75 @@ namespace MinecraftClient.ChatBots
instance = this; instance = this;
} }
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
RegisterChatBotCommand("dscbridge", "bot.DiscordBridge.desc", "dscbridge direction <both|mc|discord>", 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()); Task.Run(async () => await MainAsync());
} }
~DiscordBridge() public override void OnUnload(CommandDispatcher<CmdResult> dispatcher)
{ {
dispatcher.Unregister(CommandName);
dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName);
Disconnect(); 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 <both|mc|discord>"
+ '\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(); Disconnect();
} }
@ -114,47 +177,6 @@ namespace MinecraftClient.ChatBots
return instance; 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 <both|mc|discord>";
}
public override void GetText(string text) public override void GetText(string text)
{ {
if (!CanSendMessages()) if (!CanSendMessages())
@ -369,9 +391,8 @@ namespace MinecraftClient.ChatBots
message = message[1..]; message = message[1..];
await e.Message.CreateReactionAsync(DiscordEmoji.FromName(discordBotClient, ":gear:")); await e.Message.CreateReactionAsync(DiscordEmoji.FromName(discordBotClient, ":gear:"));
string? result = ""; CmdResult result = new();
PerformInternalCommand(message, ref result); PerformInternalCommand(message, ref result);
result = string.IsNullOrEmpty(result) ? "-" : result;
await e.Message.DeleteOwnReactionAsync(DiscordEmoji.FromName(discordBotClient, ":gear:")); await e.Message.DeleteOwnReactionAsync(DiscordEmoji.FromName(discordBotClient, ":gear:"));
await e.Message.CreateReactionAsync(DiscordEmoji.FromName(discordBotClient, ":white_check_mark:")); await e.Message.CreateReactionAsync(DiscordEmoji.FromName(discordBotClient, ":white_check_mark:"));

View file

@ -3,34 +3,22 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Protocol.Handlers; using MinecraftClient.Protocol.Handlers;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots
{ {
enum State
{
SearchingForCropsToBreak = 0,
SearchingForFarmlandToPlant,
PlantingCrops,
BonemealingCrops
}
enum CropType
{
Beetroot,
Carrot,
Melon,
Netherwart,
Pumpkin,
Potato,
Wheat
}
public class Farmer : ChatBot public class Farmer : ChatBot
{ {
public const string CommandName = "farmer";
public static Configs Config = new(); public static Configs Config = new();
[TomlDoNotInlineObject] [TomlDoNotInlineObject]
@ -42,15 +30,34 @@ namespace MinecraftClient.ChatBots
public bool Enabled = false; public bool Enabled = false;
[TomlInlineComment("$config.ChatBot.Farmer.Delay_Between_Tasks$")] [TomlInlineComment("$config.ChatBot.Farmer.Delay_Between_Tasks$")]
public int Delay_Between_Tasks = 1; public double Delay_Between_Tasks = 1.0;
public void OnSettingUpdate() public void OnSettingUpdate()
{ {
if (Delay_Between_Tasks <= 0) if (Delay_Between_Tasks < 1.0)
Delay_Between_Tasks = 1; 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 State state = State.SearchingForCropsToBreak;
private CropType cropType = CropType.Wheat; private CropType cropType = CropType.Wheat;
private int farmingRadius = 30; private int farmingRadius = 30;
@ -59,9 +66,11 @@ namespace MinecraftClient.ChatBots
private bool allowTeleport = false; private bool allowTeleport = false;
private bool debugEnabled = false; private bool debugEnabled = false;
public int Delay_Between_Tasks_Millisecond => (int)Math.Round(Config.Delay_Between_Tasks * 1000);
private const string commandDescription = "farmer <start <crop type> [radius:<radius = 30>] [unsafe:<true/false>] [teleport:<true/false>] [debug:<true/false>]|stop>"; private const string commandDescription = "farmer <start <crop type> [radius:<radius = 30>] [unsafe:<true/false>] [teleport:<true/false>] [debug:<true/false>]|stop>";
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
if (GetProtocolVersion() < Protocol18Handler.MC_1_13_Version) if (GetProtocolVersion() < Protocol18Handler.MC_1_13_Version)
{ {
@ -81,130 +90,152 @@ namespace MinecraftClient.ChatBots
return; 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<CmdResult> 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)) #pragma warning disable format // @formatter:off
{ _ => Translations.bot_farmer_desc + ": " + commandDescription
if (!running) + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false),
return Translations.bot_farmer_already_stopped; #pragma warning restore format // @formatter:on
});
}
running = false; private int OnCommandStop(CmdResult r)
return Translations.bot_farmer_stopping; {
} 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) LogToConsole("§x§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg));
return Translations.bot_farmer_already_running; continue;
}
if (!Enum.TryParse(args[1], true, out CropType whatToFarm)) string[] parts = currentArg.Split(":", StringSplitOptions.TrimEntries);
return Translations.bot_farmer_invalid_crop_type;
int radius = 30; if (parts.Length != 2)
{
LogToConsole("§x§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg));
continue;
}
state = State.SearchingForFarmlandToPlant; switch (parts[0])
cropType = whatToFarm; {
allowUnsafe = false; case "r":
allowTeleport = false; case "radius":
debugEnabled = false; if (!int.TryParse(parts[1], NumberStyles.Any, CultureInfo.CurrentCulture, out radius))
LogToConsole("§x§1§0" + Translations.bot_farmer_invalid_radius);
if (args.Length >= 3) if (radius <= 0)
{
for (int i = 2; i < args.Length; i++)
{ {
string currentArg = args[i].Trim().ToLower(); LogToConsole("§x§1§0" + Translations.bot_farmer_invalid_radius);
radius = 30;
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;
}
} }
}
farmingRadius = radius; break;
running = true;
new Thread(() => MainPorcess()).Start();
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() public override void AfterGameJoined()
@ -230,7 +261,7 @@ namespace MinecraftClient.ChatBots
if (AutoEat.Eating) if (AutoEat.Eating)
{ {
LogDebug("Eating..."); LogDebug("Eating...");
Thread.Sleep(Config.Delay_Between_Tasks * 1000); Thread.Sleep(Delay_Between_Tasks_Millisecond);
continue; continue;
} }
@ -246,7 +277,7 @@ namespace MinecraftClient.ChatBots
{ {
LogDebug("No seeds, trying to find some crops to break"); LogDebug("No seeds, trying to find some crops to break");
state = State.SearchingForCropsToBreak; state = State.SearchingForCropsToBreak;
Thread.Sleep(Config.Delay_Between_Tasks * 1000); Thread.Sleep(Delay_Between_Tasks_Millisecond);
continue; continue;
} }
@ -256,7 +287,7 @@ namespace MinecraftClient.ChatBots
{ {
LogDebug("Could not find any farmland, trying to find some crops to break"); LogDebug("Could not find any farmland, trying to find some crops to break");
state = State.SearchingForCropsToBreak; state = State.SearchingForCropsToBreak;
Thread.Sleep(Config.Delay_Between_Tasks * 1000); Thread.Sleep(Delay_Between_Tasks_Millisecond);
continue; continue;
} }
@ -272,7 +303,7 @@ namespace MinecraftClient.ChatBots
{ {
LogDebug("Ran out of seeds, looking for crops to break..."); LogDebug("Ran out of seeds, looking for crops to break...");
state = State.SearchingForCropsToBreak; state = State.SearchingForCropsToBreak;
Thread.Sleep(Config.Delay_Between_Tasks * 1000); Thread.Sleep(Delay_Between_Tasks_Millisecond);
continue; continue;
} }
} }
@ -321,7 +352,7 @@ namespace MinecraftClient.ChatBots
{ {
LogToConsole("No crops to break, trying to bonemeal ungrown ones"); LogToConsole("No crops to break, trying to bonemeal ungrown ones");
state = State.BonemealingCrops; state = State.BonemealingCrops;
Thread.Sleep(Config.Delay_Between_Tasks * 1000); Thread.Sleep(Delay_Between_Tasks_Millisecond);
continue; continue;
} }
@ -367,7 +398,7 @@ namespace MinecraftClient.ChatBots
if (cropType == CropType.Netherwart) if (cropType == CropType.Netherwart)
{ {
state = State.SearchingForFarmlandToPlant; state = State.SearchingForFarmlandToPlant;
Thread.Sleep(Config.Delay_Between_Tasks * 1000); Thread.Sleep(Delay_Between_Tasks_Millisecond);
continue; continue;
} }
@ -376,7 +407,7 @@ namespace MinecraftClient.ChatBots
{ {
LogDebug("No bonemeal, searching for some farmland to plant seeds on"); LogDebug("No bonemeal, searching for some farmland to plant seeds on");
state = State.SearchingForFarmlandToPlant; state = State.SearchingForFarmlandToPlant;
Thread.Sleep(Config.Delay_Between_Tasks * 1000); Thread.Sleep(Delay_Between_Tasks_Millisecond);
continue; continue;
} }
@ -386,7 +417,7 @@ namespace MinecraftClient.ChatBots
{ {
LogDebug("No crops to bonemeal, searching for farmland to plant seeds on"); LogDebug("No crops to bonemeal, searching for farmland to plant seeds on");
state = State.SearchingForFarmlandToPlant; state = State.SearchingForFarmlandToPlant;
Thread.Sleep(Config.Delay_Between_Tasks * 1000); Thread.Sleep(Delay_Between_Tasks_Millisecond);
continue; continue;
} }
@ -402,7 +433,7 @@ namespace MinecraftClient.ChatBots
{ {
LogDebug("Ran out of Bone Meal, looking for farmland to plant on..."); LogDebug("Ran out of Bone Meal, looking for farmland to plant on...");
state = State.SearchingForFarmlandToPlant; state = State.SearchingForFarmlandToPlant;
Thread.Sleep(Config.Delay_Between_Tasks * 1000); Thread.Sleep(Delay_Between_Tasks_Millisecond);
continue; continue;
} }
} }
@ -438,8 +469,8 @@ namespace MinecraftClient.ChatBots
break; break;
} }
LogDebug("Waiting for " + Config.Delay_Between_Tasks + " seconds for next cycle."); LogDebug(string.Format("Waiting for {0:0.00} seconds for next cycle.", Config.Delay_Between_Tasks));
Thread.Sleep(Config.Delay_Between_Tasks * 1000); Thread.Sleep(Delay_Between_Tasks_Millisecond);
} }
LogToConsole(Translations.bot_farmer_stopped); LogToConsole(Translations.bot_farmer_stopped);
@ -815,6 +846,7 @@ namespace MinecraftClient.ChatBots
{ {
return GetPlayerInventory().SearchItem(itemType).Length > 0; return GetPlayerInventory().SearchItem(itemType).Length > 0;
} }
private void LogDebug(object text) private void LogDebug(object text)
{ {
if (debugEnabled) if (debugEnabled)

View file

@ -1,12 +1,19 @@
using System; using System;
using System.Linq; using System.Linq;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots
{ {
public class FollowPlayer : ChatBot public class FollowPlayer : ChatBot
{ {
public const string CommandName = "follow";
public static Configs Config = new(); public static Configs Config = new();
[TomlDoNotInlineObject] [TomlDoNotInlineObject]
@ -37,7 +44,7 @@ namespace MinecraftClient.ChatBots
private int _updateCounter = 0; private int _updateCounter = 0;
private bool _unsafeEnabled = false; private bool _unsafeEnabled = false;
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
if (!GetEntityHandlingEnabled()) if (!GetEntityHandlingEnabled())
{ {
@ -55,58 +62,85 @@ namespace MinecraftClient.ChatBots
return; return;
} }
RegisterChatBotCommand("follow", "cmd.follow.desc", "follow <player name|stop>", 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<CmdResult> 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)) #pragma warning disable format // @formatter:off
{ _ => Translations.cmd_follow_desc + ": " + Translations.cmd_follow_usage
if (_playerToFollow == null) + '\n' + McClient.dispatcher.GetAllUsageString(CommandName, false),
return Translations.cmd_follow_already_stopped; #pragma warning restore format // @formatter:on
});
}
_playerToFollow = null; private int OnCommandStart(CmdResult r, string name, bool takeRisk)
return Translations.cmd_follow_stopping; {
} if (!IsValidName(name))
else return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_follow_invalid_name);
{
if (!IsValidName(args[0]))
return Translations.cmd_follow_invalid_name;
Entity? player = GetEntities().Values.ToList().Find(entity => Entity? player = GetEntities().Values.ToList().Find(entity =>
entity.Type == EntityType.Player && !string.IsNullOrEmpty(entity.Name) && entity.Name.Equals(args[0], StringComparison.OrdinalIgnoreCase)); entity.Type == EntityType.Player
&& !string.IsNullOrEmpty(entity.Name)
&& entity.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
if (player == null) if (player == null)
return Translations.cmd_follow_invalid_player; return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_follow_invalid_player);
if (!CanMoveThere(player.Location)) if (!CanMoveThere(player.Location))
return Translations.cmd_follow_cant_reach_player; return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_follow_cant_reach_player);
if (_playerToFollow != null && _playerToFollow.Equals(args[0], StringComparison.OrdinalIgnoreCase)) if (_playerToFollow != null && _playerToFollow.Equals(name, StringComparison.OrdinalIgnoreCase))
return string.Format(Translations.cmd_follow_already_following, _playerToFollow); return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_follow_already_following, _playerToFollow));
string result; string result;
if (_playerToFollow != null) if (_playerToFollow != null)
result = string.Format(Translations.cmd_follow_switched, player.Name!); result = string.Format(Translations.cmd_follow_switched, player.Name!);
else else
result = string.Format(Translations.cmd_follow_started, player.Name!); result = string.Format(Translations.cmd_follow_started, player.Name!);
_playerToFollow = args[0].Trim().ToLower(); _playerToFollow = name.ToLower();
LogToConsole(Translations.cmd_follow_note); if (takeRisk)
{
if (args.Length == 2 && args[1].Equals("-f", StringComparison.OrdinalIgnoreCase)) _unsafeEnabled = true;
{ return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_follow_note + '\n' + Translations.cmd_follow_unsafe_enabled);
_unsafeEnabled = true;
LogToConsole(Translations.cmd_follow_unsafe_enabled);
}
return result;
}
} }
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() public override void Update()

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Text; using System.Text;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots

View file

@ -3,6 +3,11 @@ using System.Collections.Generic;
using System.Data; using System.Data;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots
@ -12,6 +17,8 @@ namespace MinecraftClient.ChatBots
/// </summary> /// </summary>
public class Mailer : ChatBot public class Mailer : ChatBot
{ {
public const string CommandName = "mailer";
public static Configs Config = new(); public static Configs Config = new();
[TomlDoNotInlineObject] [TomlDoNotInlineObject]
@ -216,7 +223,7 @@ namespace MinecraftClient.ChatBots
/// <summary> /// <summary>
/// Initialization of the Mailer bot /// Initialization of the Mailer bot
/// </summary> /// </summary>
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
LogDebugToConsole(Translations.bot_mailer_init); LogDebugToConsole(Translations.bot_mailer_init);
LogDebugToConsole(Translations.bot_mailer_init_db + Config.DatabaseFile); 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); mailDbFileMonitor = new FileMonitor(Path.GetDirectoryName(Config.DatabaseFile)!, Path.GetFileName(Config.DatabaseFile), FileMonitorCallback);
ignoreListFileMonitor = new FileMonitor(Path.GetDirectoryName(Config.IgnoreListFile)!, Path.GetFileName(Config.IgnoreListFile), FileMonitorCallback); ignoreListFileMonitor = new FileMonitor(Path.GetDirectoryName(Config.IgnoreListFile)!, Path.GetFileName(Config.IgnoreListFile), FileMonitorCallback);
RegisterChatBotCommand("mailer", Translations.bot_mailer_cmd, "mailer <getmails|addignored|getignored|removeignored>", 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<CmdResult> 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 <getmails|addignored|getignored|removeignored>"
+ '\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;
}
} }
/// <summary> /// <summary>
@ -365,57 +488,5 @@ namespace MinecraftClient.ChatBots
ignoreList = IgnoreList.FromFile(Config.IgnoreListFile); ignoreList = IgnoreList.FromFile(Config.IgnoreListFile);
} }
} }
/// <summary>
/// Interprets local commands.
/// </summary>
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";
}
} }
} }

View file

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

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Text; using System.Text;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots

View file

@ -1,4 +1,6 @@
using System; using System;
using MinecraftClient.CommandHandler;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots
@ -32,17 +34,9 @@ namespace MinecraftClient.ChatBots
string command = "", sender = ""; string command = "", sender = "";
if (IsPrivateMessage(text, ref command, ref sender) && Settings.Config.Main.Advanced.BotOwners.Contains(sender.ToLower().Trim())) 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); PerformInternalCommand(command, ref response);
response = GetVerbatim(response); SendPrivateMessage(sender, response.ToString());
foreach (char disallowedChar in McClient.GetDisallowedChatCharacters())
{
response = response.Replace(disallowedChar.ToString(), String.Empty);
}
if (response.Length > 0)
{
SendPrivateMessage(sender, response);
}
} }
else if (Config.AutoTpaccept else if (Config.AutoTpaccept
&& IsTeleportRequest(text, ref sender) && IsTeleportRequest(text, ref sender)

View file

@ -1,6 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Protocol; using MinecraftClient.Protocol;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots
@ -10,6 +15,8 @@ namespace MinecraftClient.ChatBots
/// </summary> /// </summary>
public class ReplayCapture : ChatBot public class ReplayCapture : ChatBot
{ {
public const string CommandName = "replay";
public static Configs Config = new(); public static Configs Config = new();
[TomlDoNotInlineObject] [TomlDoNotInlineObject]
@ -33,14 +40,80 @@ namespace MinecraftClient.ChatBots
private ReplayHandler? replay; private ReplayHandler? replay;
private int backupCounter = -1; private int backupCounter = -1;
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
SetNetworkPacketEventEnabled(true); SetNetworkPacketEventEnabled(true);
replay = new ReplayHandler(GetProtocolVersion()); replay = new ReplayHandler(GetProtocolVersion());
replay.MetaData.serverName = GetServerHost() + GetServerPort(); replay.MetaData.serverName = GetServerHost() + GetServerPort();
backupCounter = Settings.DoubleToTick(Config.Backup_Interval); backupCounter = Settings.DoubleToTick(Config.Backup_Interval);
RegisterChatBotCommand("replay", Translations.bot_replayCapture_cmd, "replay <save|stop>", 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<CmdResult> 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<byte> packetData, bool isLogin, bool isInbound) public override void OnNetworkPacket(int packetID, List<byte> packetData, bool isLogin, bool isInbound)
@ -66,37 +139,5 @@ namespace MinecraftClient.ChatBots
replay!.OnShutDown(); replay!.OnShutDown();
return base.OnDisconnect(reason, message); 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;
}
}
} }
} }

View file

@ -5,6 +5,9 @@ using System.IO;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using Brigadier.NET;
using MinecraftClient.CommandHandler;
using MinecraftClient.Scripting;
namespace MinecraftClient.ChatBots namespace MinecraftClient.ChatBots
{ {
@ -124,7 +127,7 @@ namespace MinecraftClient.ChatBots
return false; return false;
} }
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
//Load the given file from the startup parameters //Load the given file from the startup parameters
if (LookForScript(ref file!)) if (LookForScript(ref file!))

View file

@ -1,4 +1,5 @@
using System; using System;
using MinecraftClient.Scripting;
using Tomlet.Attributes; using Tomlet.Attributes;
using static MinecraftClient.ChatBots.ScriptScheduler.Configs; using static MinecraftClient.ChatBots.ScriptScheduler.Configs;

View file

@ -3,6 +3,11 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; 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;
using Telegram.Bot.Exceptions; using Telegram.Bot.Exceptions;
using Telegram.Bot.Polling; using Telegram.Bot.Polling;
@ -16,6 +21,8 @@ namespace MinecraftClient.ChatBots
{ {
public class TelegramBridge : ChatBot public class TelegramBridge : ChatBot
{ {
public const string CommandName = "tgbridge";
private enum BridgeDirection private enum BridgeDirection
{ {
Both = 0, Both = 0,
@ -68,19 +75,74 @@ namespace MinecraftClient.ChatBots
instance = this; instance = this;
} }
public override void Initialize() public override void Initialize(CommandDispatcher<CmdResult> dispatcher)
{ {
RegisterChatBotCommand("tgbridge", "bot.TelegramBridge.desc", "tgbridge direction <both|mc|telegram>", 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()); Task.Run(async () => await MainAsync());
} }
~TelegramBridge() public override void OnUnload(CommandDispatcher<CmdResult> dispatcher)
{ {
dispatcher.Unregister(CommandName);
dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName);
Disconnect(); 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 <both|mc|telegram>"
+ '\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(); Disconnect();
} }
@ -110,47 +172,6 @@ namespace MinecraftClient.ChatBots
return instance; 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 <both|mc|discord>";
}
public override void GetText(string text) public override void GetText(string text)
{ {
if (!CanSendMessages()) if (!CanSendMessages())
@ -324,9 +345,8 @@ namespace MinecraftClient.ChatBots
{ {
var command = text[1..]; var command = text[1..];
string? result = ""; CmdResult result = new();
PerformInternalCommand(command, ref result); PerformInternalCommand(command, ref result);
result = string.IsNullOrEmpty(result) ? "-" : result;
await botClient.SendTextMessageAsync( await botClient.SendTextMessageAsync(
chatId: chatId, chatId: chatId,

View file

@ -1,4 +1,6 @@
namespace MinecraftClient.ChatBots using MinecraftClient.Scripting;
namespace MinecraftClient.ChatBots
{ {
/// <summary> /// <summary>
/// Example of message receiving. /// Example of message receiving.

View file

@ -2,8 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using Brigadier.NET; using Brigadier.NET;
using Microsoft.Extensions.Logging; using MinecraftClient.CommandHandler;
using MinecraftClient.Commands; using MinecraftClient.CommandHandler.Patch;
namespace MinecraftClient namespace MinecraftClient
{ {
@ -25,34 +25,19 @@ namespace MinecraftClient
/// </summary> /// </summary>
public abstract string CmdDesc { get; } public abstract string CmdDesc { get; }
public abstract void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher);
/// <summary> /// <summary>
/// Get the translated version of command description. /// Get the translated version of command description.
/// </summary> /// </summary>
/// <returns>Translated command description</returns> /// <returns>Translated command description</returns>
public string GetCmdDescTranslated() public string GetCmdDescTranslated()
{ {
string s = (string.IsNullOrEmpty(CmdUsage) || string.IsNullOrEmpty(CmdDesc)) ? "" : ": "; // If either one is empty, no colon : char cmdChar = Settings.Config.Main.Advanced.InternalCmdChar.ToChar();
return CmdUsage + s + CmdDesc;
}
public void LogUsage(Logger.ILogger logger) StringBuilder sb = new();
{ string s = (string.IsNullOrEmpty(CmdUsage) || string.IsNullOrEmpty(CmdDesc)) ? string.Empty : ": "; // If either one is empty, no colon :
logger.Info($"{Translations.Get("error.usage")}: {Settings.Config.Main.Advanced.InternalCmdChar.ToChar()}{CmdUsage}"); sb.Append("§e").Append(cmdChar).Append(CmdUsage).Append("§r").Append(s).AppendLine(CmdDesc);
} sb.Append(McClient.dispatcher.GetAllUsageString(CmdName, false));
return sb.ToString();
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;
} }
/// <summary> /// <summary>
@ -61,18 +46,9 @@ namespace MinecraftClient
public abstract string CmdUsage { get; } public abstract string CmdUsage { get; }
/// <summary> /// <summary>
/// Perform the command /// Register the command.
/// </summary> /// </summary>
/// <param name="command">The full command, eg: 'mycommand arg1 arg2'</param> public abstract void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> dispatcher);
/// <param name="localVars">Local variables passed along with the command (may be null)</param>
/// <returns>A confirmation/error message, or "" if no message</returns>
public abstract string Run(McClient handler, string command, Dictionary<string, object>? localVars);
/// <summary>
/// Return a list of aliases for this command.
/// Override this method if you wish to put aliases to the command
/// </summary>
public virtual IEnumerable<string> GetCMDAliases() { return Array.Empty<string>(); }
/// <summary> /// <summary>
/// Check if at least one argument has been passed to the command /// Check if at least one argument has been passed to the command

View file

@ -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<string>
{
public override string Parse(IStringReader reader)
{
reader.SkipWhitespace();
return reader.ReadString();
}
public override Task<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> context, SuggestionsBuilder builder)
{
var accountList = Settings.Config.Main.Advanced.AccountList;
foreach (var account in accountList)
builder.Suggest(account.Key);
return builder.BuildFuture();
}
}
}

View file

@ -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<string>
{
public override string Parse(IStringReader reader)
{
reader.SkipWhitespace();
return reader.ReadString();
}
public override Task<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> context, SuggestionsBuilder builder)
{
var recipeList = Settings.Config.ChatBot.AutoCraft.Recipes;
foreach (var recipe in recipeList)
builder.Suggest(recipe.Name);
return builder.BuildFuture();
}
}
}

View file

@ -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<string>
{
public override string Parse(IStringReader reader)
{
reader.SkipWhitespace();
return reader.ReadString();
}
public override Task<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> 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();
}
}
}

View file

@ -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<EntityType>
{
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<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> context, SuggestionsBuilder builder)
{
foreach (var result in Enum.GetNames(typeof(EntityType)))
builder.Suggest(result);
return builder.BuildFuture();
}
}
}

View file

@ -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<CropType>
{
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<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> context, SuggestionsBuilder builder)
{
foreach (var result in Enum.GetNames(typeof(CropType)))
builder.Suggest(result);
return builder.BuildFuture();
}
}
}

View file

@ -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<WindowActionType>
{
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<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> context, SuggestionsBuilder builder)
{
foreach (var action in SupportActions)
builder.Suggest(action.ToString());
return builder.BuildFuture();
}
}
}

View file

@ -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<int>
{
public override int Parse(IStringReader reader)
{
reader.SkipWhitespace();
return reader.ReadInt();
}
public override Task<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> 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();
}
}
}

View file

@ -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<ItemType>
{
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<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> context, SuggestionsBuilder builder)
{
foreach (var result in Enum.GetNames(typeof(ItemType)))
builder.Suggest(result);
return builder.BuildFuture();
}
}
}

View file

@ -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<Location>
{
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<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> 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();
}
}
}

View file

@ -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<int>
{
public override int Parse(IStringReader reader)
{
reader.SkipWhitespace();
return reader.ReadInt();
}
public override Task<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> 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();
}
}
}

View file

@ -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<string>
{
public override string Parse(IStringReader reader)
{
reader.SkipWhitespace();
return reader.ReadString();
}
public override Task<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> 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();
}
}
}

View file

@ -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<string>
{
public override string Parse(IStringReader reader)
{
reader.SkipWhitespace();
return reader.ReadString();
}
public override Task<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> context, SuggestionsBuilder builder)
{
var serverList = Settings.Config.Main.Advanced.ServerList;
foreach (var server in serverList)
builder.Suggest(server.Key);
return builder.BuildFuture();
}
}
}

View file

@ -0,0 +1,18 @@
using System;
using Brigadier.NET;
using Brigadier.NET.ArgumentTypes;
namespace MinecraftClient.CommandHandler.ArgumentType
{
public class TupleArgumentType : ArgumentType<Tuple<int, int>>
{
public override Tuple<int, int> Parse(IStringReader reader)
{
reader.SkipWhitespace();
int int1 = reader.ReadInt();
reader.SkipWhitespace();
int int2 = reader.ReadInt();
return new(int1, int2);
}
}
}

View file

@ -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();
}
}
}

View file

@ -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<TSource>(CommandContext<TSource> context, string name)
{
return context.GetArgument<Mapping.Location>(name);
}
public static TupleArgumentType Tuple()
{
return new TupleArgumentType();
}
public static Tuple<int, int> GetTuple<TSource>(CommandContext<TSource> context, string name)
{
return context.GetArgument<Tuple<int, int>>(name);
}
public static EntityTypeArgumentType EntityType()
{
return new EntityTypeArgumentType();
}
public static Mapping.EntityType GetEntityType<TSource>(CommandContext<TSource> context, string name)
{
return context.GetArgument<Mapping.EntityType>(name);
}
public static ItemTypeArgumentType ItemType()
{
return new ItemTypeArgumentType();
}
public static Inventory.ItemType GetItemType<TSource>(CommandContext<TSource> context, string name)
{
return context.GetArgument<Inventory.ItemType>(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<TSource>(CommandContext<TSource> context, string name)
{
return context.GetArgument<Inventory.WindowActionType>(name);
}
public static AutoCraftRecipeNameArgumentType AutoCraftRecipeName()
{
return new AutoCraftRecipeNameArgumentType();
}
public static FarmerCropTypeArgumentType FarmerCropType()
{
return new FarmerCropTypeArgumentType();
}
public static ChatBots.Farmer.CropType GetFarmerCropType<TSource>(CommandContext<TSource> context, string name)
{
return context.GetArgument<ChatBots.Farmer.CropType>(name);
}
public static PlayerNameArgumentType PlayerName()
{
return new PlayerNameArgumentType();
}
public static MapBotMapIdArgumentType MapBotMapId()
{
return new MapBotMapIdArgumentType();
}
}
}

View file

@ -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<CmdResult> commandDispatcher, string commandname)
{
commandDispatcher.GetRoot().RemoveChild(commandname);
}
public static string GetAllUsageString(this CommandDispatcher<CmdResult> 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();
}
}
}

View file

@ -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<CmdResult> commandNode, string name)
{
var children = (IDictionary<string, CommandNode<CmdResult>>)
typeof(CommandNode<CmdResult>)
.GetField("_children", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!
.GetValue(commandNode)!;
var literals = (IDictionary<string, LiteralCommandNode<CmdResult>>)
typeof(CommandNode<CmdResult>)
.GetField("_literals", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!
.GetValue(commandNode)!;
var arguments = (IDictionary<string, ArgumentCommandNode<CmdResult>>)
typeof(CommandNode<CmdResult>)
.GetField("_arguments", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!
.GetValue(commandNode)!;
children.Remove(name);
literals.Remove(name);
}
}
}

View file

@ -1,7 +1,6 @@
using System; using Brigadier.NET;
using System.Collections.Generic;
using Brigadier.NET;
using Brigadier.NET.Builder; using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -11,76 +10,44 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "animation <mainhand|offhand>"; } } public override string CmdUsage { get { return "animation <mainhand|offhand>"; } }
public override string CmdDesc { get { return Translations.cmd_animation_desc; } } public override string CmdDesc { get { return Translations.cmd_animation_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> dispatcher)
{ {
dispatcher.Register(l => dispatcher.Register(l => l.Literal("help")
l.Literal("help").Then(l => .Then(l => l.Literal(CmdName)
l.Literal(CmdName).Executes(c => { .Executes(r => GetUsage(r.Source, string.Empty))
LogUsage(handler.Log); .Then(l => l.Literal("mainhand")
return 1; .Executes(r => GetUsage(r.Source, "mainhand")))
}) .Then(l => l.Literal("offhand")
.Executes(r => GetUsage(r.Source, "offhand")))
) )
); );
dispatcher.Register(l => dispatcher.Register(l => l.Literal(CmdName)
l.Literal(CmdName).Then(l => .Executes(r => DoAnimation(r.Source, handler, mainhand: true))
l.Literal("mainhand") .Then(l => l.Literal("mainhand")
.Executes(c => { .Executes(r => DoAnimation(r.Source, handler, mainhand: true)))
return LogExecuteResult(handler.Log, handler.DoAnimation(0)); .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)))
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<string, object>? 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
if (args.Length > 0) "mainhand" => GetCmdDescTranslated(),
{ "offhand" => GetCmdDescTranslated(),
if (args[0] == "mainhand" || args[0] == "0") _ => GetCmdDescTranslated(),
{ #pragma warning restore format // @formatter:on
handler.DoAnimation(0); });
return Translations.general_done; }
}
else if (args[0] == "offhand" || args[0] == "1") private static int DoAnimation(CmdResult r, McClient handler, bool mainhand)
{ {
handler.DoAnimation(1); return r.SetAndReturn(handler.DoAnimation(mainhand ? 1 : 0));
return Translations.general_done;
}
else
{
return GetCmdDescTranslated();
}
}
else
{
return GetCmdDescTranslated();
}
}
else return GetCmdDescTranslated();
} }
} }
} }

View file

@ -1,10 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using static MinecraftClient.CommandHandler.CmdResult;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -14,142 +16,162 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "bed leave|sleep <x> <y> <z>|sleep <radius>"; } } public override string CmdUsage { get { return "bed leave|sleep <x> <y> <z>|sleep <radius>"; } }
public override string CmdDesc { get { return Translations.cmd_bed_desc; } } public override string CmdDesc { get { return Translations.cmd_bed_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? localVars) private int GetUsage(CmdResult r, string? cmd)
{ {
string[] args = GetArgs(command); return r.SetAndReturn(cmd switch
if (args.Length >= 1)
{ {
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<Location> beds = handler.GetWorld().FindBlock(current, material, radius);
if (beds.Count > 0)
{ {
handler.SendEntityAction(Protocol.EntityActionType.LeaveBed); found = true;
return Translations.cmd_bed_leaving; bedLocation = beds.First();
} break;
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<Location> 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
);
}
} }
} }
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
));
} }
} }
} }

View file

@ -1,7 +1,9 @@
using System.Collections.Generic; using System.Text;
using System.Text;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using static MinecraftClient.CommandHandler.CmdResult;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -11,40 +13,60 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "blockinfo <x> <y> <z> [-s]"; } } public override string CmdUsage { get { return "blockinfo <x> <y> <z> [-s]"; } }
public override string CmdDesc { get { return Translations.cmd_blockinfo_desc; } } public override string CmdDesc { get { return Translations.cmd_blockinfo_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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()) if (!handler.GetTerrainEnabled())
return Translations.error_terrain_not_enabled; return r.SetAndReturn(Status.FailNeedTerrain);
string[] args = GetArgs(command); targetBlock.ToAbsolute(handler.GetCurrentLocation());
Block block = handler.GetWorld().GetBlock(targetBlock);
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);
handler.Log.Info($"{Translations.cmd_blockinfo_BlockType}: {block.GetTypeString()}"); handler.Log.Info($"{Translations.cmd_blockinfo_BlockType}: {block.GetTypeString()}");
if (reportSurrounding) if (reportSurrounding)
{ {
StringBuilder sb = new(); StringBuilder sb = new();
sb.AppendLine($"{Translations.cmd_blockinfo_BlocksAround}:"); sb.AppendLine($"{Translations.cmd_blockinfo_BlocksAround}:");
Block blockXPositive = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X + 1, targetBlockLocation.Y, targetBlockLocation.Z)); Block blockXPositive = handler.GetWorld().GetBlock(new Location(targetBlock.X + 1, targetBlock.Y, targetBlock.Z));
Block blockXNegative = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X - 1, targetBlockLocation.Y, targetBlockLocation.Z)); Block blockXNegative = handler.GetWorld().GetBlock(new Location(targetBlock.X - 1, targetBlock.Y, targetBlock.Z));
Block blockYPositive = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X, targetBlockLocation.Y + 1, targetBlockLocation.Z)); Block blockYPositive = handler.GetWorld().GetBlock(new Location(targetBlock.X, targetBlock.Y + 1, targetBlock.Z));
Block blockYNegative = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X, targetBlockLocation.Y - 1, targetBlockLocation.Z)); Block blockYNegative = handler.GetWorld().GetBlock(new Location(targetBlock.X, targetBlock.Y - 1, targetBlock.Z));
Block blockZPositive = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X, targetBlockLocation.Y, targetBlockLocation.Z + 1)); Block blockZPositive = handler.GetWorld().GetBlock(new Location(targetBlock.X, targetBlock.Y, targetBlock.Z + 1));
Block blockZNegative = handler.GetWorld().GetBlock(new Location(targetBlockLocation.X, targetBlockLocation.Y, targetBlockLocation.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_Positive}] {Translations.cmd_blockinfo_BlockType}: {blockXPositive.GetTypeString()}");
sb.AppendLine($"[X {Translations.cmd_blockinfo_Negative}] {Translations.cmd_blockinfo_BlockType}: {blockXNegative.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()); handler.Log.Info(sb.ToString());
} }
return r.SetAndReturn(Status.Done);
return "";
} }
} }
} }

View file

@ -1,7 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.Text; using System.Text;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Scripting;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -11,69 +13,82 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "bots [list|unload <bot name|all>]"; } } public override string CmdUsage { get { return "bots [list|unload <bot name|all>]"; } }
public override string CmdDesc { get { return Translations.cmd_bots_desc; } } public override string CmdDesc { get { return Translations.cmd_bots_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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) private int DoListBot(CmdResult r, McClient handler)
{ {
if (args[0].Equals("list", StringComparison.OrdinalIgnoreCase)) int length = handler.GetLoadedChatBots().Count;
{ if (length == 0)
StringBuilder sb = new(); return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_bots_noloaded);
int length = handler.GetLoadedChatBots().Count; StringBuilder sb = new();
for (int i = 0; i < length; i++)
if (length == 0) {
return Translations.cmd_bots_noloaded; sb.Append(handler.GetLoadedChatBots()[i].GetType().Name);
if (i != length - 1)
for (int i = 0; i < length; i++) sb.Append(" ,");
{
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);
}
}
}
} }
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));
}
}
} }
} }
} }

View file

@ -1,6 +1,7 @@
using System; using Brigadier.NET;
using System.Collections.Generic; using Brigadier.NET.Builder;
using Brigadier.NET; using MinecraftClient.CommandHandler;
using static MinecraftClient.CommandHandler.CmdResult;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -10,39 +11,41 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "changeslot <1-9>"; } } public override string CmdUsage { get { return "changeslot <1-9>"; } }
public override string CmdDesc { get { return Translations.cmd_changeSlot_desc; } } public override string CmdDesc { get { return Translations.cmd_changeSlot_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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()) if (!handler.GetInventoryEnabled())
return Translations.extra_inventory_required; return r.SetAndReturn(Status.FailNeedInventory);
if (HasArg(command)) if (handler.ChangeSlot((short)(slot - 1)))
{ return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_changeSlot_changed, slot));
short slot; else
try return r.SetAndReturn(Status.Fail, Translations.cmd_changeSlot_fail);
{
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();
} }
} }
} }

View file

@ -1,9 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text; using System.Text;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using static MinecraftClient.CommandHandler.CmdResult;
namespace MinecraftClient.Commands 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 CmdUsage { get { return "chunk status [chunkX chunkZ|locationX locationY locationZ]"; } }
public override string CmdDesc { get { return Translations.cmd_chunk_desc; } } public override string CmdDesc { get { return Translations.cmd_chunk_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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
if (args.Length > 0) "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<int, int>? 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(); leftMost = Math.Min(leftMost, x);
Location current = handler.GetCurrentLocation(); rightMost = Math.Max(rightMost, x);
topMost = Math.Min(topMost, z);
Tuple<int, int>? markedChunkPos = ParseChunkPos(args); bottomMost = Math.Max(bottomMost, z);
(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();
} }
else if (args[0] == "setloading") // For debugging }
{ }
Tuple<int, int>? chunkPos = ParseChunkPos(args);
if (chunkPos != null) // Include the player's location
{ topMost = Math.Min(topMost, current.ChunkZ);
handler.Log.Info(Translations.cmd_chunk_for_debug); bottomMost = Math.Max(bottomMost, current.ChunkZ);
World world = handler.GetWorld(); leftMost = Math.Min(leftMost, current.ChunkX);
(int chunkX, int chunkZ) = chunkPos; rightMost = Math.Max(rightMost, current.ChunkX);
ChunkColumn? chunkColumn = world[chunkX, chunkZ];
if (chunkColumn != null) // Empty one row and one column each
chunkColumn.FullyLoaded = false; --leftMost; ++rightMost; --topMost; ++bottomMost;
return (chunkColumn == null) ? "Fail: chunk dosen't exist!" :
String.Format("Successfully marked chunk ({0}, {1}) as loading.", chunkX, chunkZ); // Resize according to limitations
} if ((bottomMost - topMost + 1) > consoleHeight)
else {
return GetCmdDescTranslated(); int delta = (bottomMost - topMost + 1) - consoleHeight;
} if (bottomMost - (delta + 1) / 2 < current.ChunkZ + 1)
else if (args[0] == "setloaded") // For debugging {
{ int bottomReduce = bottomMost - (current.ChunkZ + 1);
Tuple<int, int>? chunkPos = ParseChunkPos(args); bottomMost -= bottomReduce;
if (chunkPos != null) topMost += delta - bottomReduce;
{ }
handler.Log.Info(Translations.cmd_chunk_for_debug); else if (topMost + delta / 2 > current.ChunkZ - 1)
World world = handler.GetWorld(); {
(int chunkX, int chunkZ) = chunkPos; int topAdd = topMost - (current.ChunkZ - 1);
ChunkColumn? chunkColumn = world[chunkX, chunkZ]; topMost += topAdd;
if (chunkColumn != null) bottomMost -= delta - topAdd;
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<int, int>? 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();
} }
else 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 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<int, int>? ParseChunkPos(string[] args) private static int DebugSetLoading(CmdResult r, McClient handler, Location? pos = null, Tuple<int, int>? markedChunkPos = null)
{ {
try if (!handler.GetTerrainEnabled())
{ return r.SetAndReturn(Status.FailNeedTerrain);
int chunkX, chunkZ;
if (args.Length == 1 + 3) if (pos.HasValue)
{ pos.Value.ToAbsolute(handler.GetCurrentLocation());
Location pos = new( handler.Log.Info(Translations.cmd_chunk_for_debug);
double.Parse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture), (int chunkX, int chunkZ) = markedChunkPos ?? new(pos!.Value.ChunkX, pos!.Value.ChunkZ);
double.Parse(args[2], NumberStyles.Any, CultureInfo.CurrentCulture), ChunkColumn? chunkColumn = handler.GetWorld()[chunkX, chunkZ];
double.Parse(args[3], NumberStyles.Any, CultureInfo.CurrentCulture) if (chunkColumn != null)
); chunkColumn.FullyLoaded = false;
chunkX = pos.ChunkX;
chunkZ = pos.ChunkZ; if (chunkColumn == null)
} return r.SetAndReturn(Status.Fail, "Fail: chunk dosen't exist!");
else if (args.Length == 1 + 2) else
{ return r.SetAndReturn(Status.Done, string.Format("Successfully marked chunk ({0}, {1}) as loading.", chunkX, chunkZ));
chunkX = int.Parse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture); }
chunkZ = int.Parse(args[2], NumberStyles.Any, CultureInfo.CurrentCulture);
} private static int DebugSetLoaded(CmdResult r, McClient handler, Location? pos = null, Tuple<int, int>? markedChunkPos = null)
else {
return null; if (!handler.GetTerrainEnabled())
return new(chunkX, chunkZ); return r.SetAndReturn(Status.FailNeedTerrain);
}
catch (FormatException) if (pos.HasValue)
{ pos.Value.ToAbsolute(handler.GetCurrentLocation());
return null; 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<int, int>? 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));
} }
} }
} }

View file

@ -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;
}
}

View file

@ -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 namespace MinecraftClient.Commands
{ {
@ -9,31 +11,65 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "connect <server> [account]"; } } public override string CmdUsage { get { return "connect <server> [account]"; } }
public override string CmdDesc { get { return Translations.cmd_connect_desc; } } public override string CmdDesc { get { return Translations.cmd_connect_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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
if (args.Length > 1) _ => GetCmdDescTranslated(),
{ #pragma warning restore format // @formatter:on
if (!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)) private int DoConnect(CmdResult r, McClient handler, string server, string account)
{ {
Program.Restart(keepAccountAndServerSettings: true); if (!string.IsNullOrWhiteSpace(account) && !Settings.Config.Main.Advanced.SetAccount(account))
return ""; return r.SetAndReturn(Status.Fail, string.Format(Translations.cmd_connect_unknown, account));
}
else return string.Format(Translations.cmd_connect_invalid_ip, args[0]); 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();
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using Brigadier.NET;
using Brigadier.NET; using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -9,20 +10,46 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "debug [on|off]"; } } public override string CmdUsage { get { return "debug [on|off]"; } }
public override string CmdDesc { get { return Translations.cmd_debug_desc; } } public override string CmdDesc { get { return Translations.cmd_debug_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? localVars) private int GetUsage(CmdResult r, string? cmd)
{ {
if (HasArg(command)) return r.SetAndReturn(cmd switch
Settings.Config.Logging.DebugMessages = (GetArg(command).ToLower() == "on"); {
else #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; Settings.Config.Logging.DebugMessages = !Settings.Config.Logging.DebugMessages;
if (Settings.Config.Logging.DebugMessages)
return Translations.cmd_debug_state_on;
else 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);
} }
} }
} }

View file

@ -1,7 +1,9 @@
using System; using System;
using System.Collections.Generic;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using static MinecraftClient.CommandHandler.CmdResult;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -11,53 +13,68 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "dig <x> <y> <z>"; } } public override string CmdUsage { get { return "dig <x> <y> <z>"; } }
public override string CmdDesc { get { return Translations.cmd_dig_desc; } } public override string CmdDesc { get { return Translations.cmd_dig_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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()) if (!handler.GetTerrainEnabled())
return Translations.extra_terrainandmovement_required; return r.SetAndReturn(Status.FailNeedTerrain);
string[] args = GetArgs(command); Location current = handler.GetCurrentLocation();
if (args.Length == 0) 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); blockToBreak = blockToBreak.ToCenter();
if (!hasBlock) return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_dig_dig, blockToBreak.X, blockToBreak.Y, blockToBreak.Z, block.GetTypeString()));
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(); }
} }
else else
{ return r.SetAndReturn(Status.Fail, Translations.cmd_dig_fail);
return GetCmdDescTranslated(); }
}
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);
} }
} }
} }

View file

@ -1,57 +1,64 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using static MinecraftClient.CommandHandler.CmdResult;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
class DropItem : Command class DropItem : Command
{ {
public override string CmdName { get { return "dropitem"; } } public override string CmdName { get { return "dropitem"; } }
public override string CmdUsage { get { return "/dropitem <itemtype>"; } } public override string CmdUsage { get { return "dropitem <itemtype>"; } }
public override string CmdDesc { get { return Translations.cmd_dropItem_desc; } } public override string CmdDesc { get { return Translations.cmd_dropItem_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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()) if (!handler.GetInventoryEnabled())
{ return r.SetAndReturn(Status.FailNeedTerrain);
return Translations.extra_inventory_required;
} int inventoryId;
if (HasArg(command)) var inventories = handler.GetInventories();
{ List<int> availableIds = inventories.Keys.ToList();
string arg = GetArg(command); availableIds.Remove(0); // remove player inventory ID from list
if (Enum.TryParse(arg, true, out ItemType itemType)) if (availableIds.Count == 1)
{ inventoryId = availableIds[0]; // one container, use it
int inventoryId;
var inventories = handler.GetInventories();
List<int> 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);
}
}
else else
{ inventoryId = 0;
return CmdUsage; 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));
} }
} }
} }

View file

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Linq;
using System.Linq;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
@ -11,80 +12,96 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "enchant <top|middle|bottom>"; } } public override string CmdUsage { get { return "enchant <top|middle|bottom>"; } }
public override string CmdDesc { get { return Translations.cmd_enchant_desc; } } public override string CmdDesc { get { return Translations.cmd_enchant_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? localVars) private int GetUsage(CmdResult r, string? cmd)
{ {
if (!handler.GetInventoryEnabled()) return r.SetAndReturn(cmd switch
return Translations.error_inventoryhandling_not_enabled;
if (HasArg(command))
{ {
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, enchantingTable = container;
"middle" => 1, break;
"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;
}
} }
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);
}
} }
} }
} }

View file

@ -1,172 +1,321 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Diagnostics.CodeAnalysis;
using System.Text; using System.Text;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using static MinecraftClient.CommandHandler.CmdResult;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
class Entitycmd : Command class Entitycmd : Command
{ {
public override string CmdName { get { return "entity"; } } public override string CmdName { get { return "entity"; } }
public override string CmdUsage { get { return "entity <id|entitytype> <attack|use>"; } } public override string CmdUsage { get { return "entity [near] <id|entitytype> <attack|use>"; } }
public override string CmdDesc { get { return string.Empty; } } public override string CmdDesc { get { return string.Empty; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) private enum ActionType { Attack, Use, List };
public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? localVars) private int GetUsage(CmdResult r, string? cmd)
{ {
if (handler.GetEntityHandlingEnabled()) return r.SetAndReturn(cmd switch
{ {
string[] args = GetArgs(command); #pragma warning disable format // @formatter:off
if (args.Length >= 1) "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<int, Entity> 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 (entity2.Value.Type == entityType)
if (entityID != 0)
{ {
if (handler.GetEntities().ContainsKey(entityID)) if (action == ActionType.Attack)
{ {
string action = args.Length > 1 handler.InteractEntity(entity2.Key, InteractType.Attack);
? args[1].ToLower() actionst = Translations.cmd_entityCmd_attacked;
: "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();
}
} }
else return Translations.cmd_entityCmd_not_found; else if (action == ActionType.Use)
}
else
{
EntityType interacttype = Enum.Parse<EntityType>(args[0]);
string actionst = Translations.cmd_entityCmd_attacked;
int actioncount = 0;
foreach (var entity2 in handler.GetEntities())
{ {
if (entity2.Value.Type == interacttype) handler.InteractEntity(entity2.Key, InteractType.Interact);
{ actionst = Translations.cmd_entityCmd_used;
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();
}
} }
return actioncount + " " + actionst; actioncount++;
} }
} }
catch (FormatException) { return GetCmdDescTranslated(); } handler.Log.Info(actioncount + " " + actionst);
return r.SetAndReturn(Status.Done);
} }
else else
{ {
Dictionary<int, Entity> entities = handler.GetEntities();
StringBuilder response = new(); StringBuilder response = new();
response.AppendLine(Translations.cmd_entityCmd_entities); response.AppendLine(Translations.cmd_entityCmd_entities);
foreach (var entity2 in entities) foreach (var entity2 in handler.GetEntities())
{ {
int id = entity2.Key; if (entity2.Value.Type == entityType)
float health = entity2.Value.Health; {
int latency = entity2.Value.Latency; response.AppendLine(GetEntityInfoShort(entity2.Value));
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}");
} }
response.Append(GetCmdDescTranslated()); 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<int, Entity> 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;
}
} }
} }
} }

View file

@ -1,99 +1,94 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using DynamicExpresso; using DynamicExpresso;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
class ExecIf : Command class ExecIf : Command
{ {
public override string CmdName { get { return "execif"; } } public override string CmdName { get { return "execif"; } }
public override string CmdUsage { get { return "execif <condition/expression> ---> <command>"; } } public override string CmdUsage { get { return "execif \"<condition/expression>\" \"<command>\""; } }
public override string CmdDesc { get { return Translations.cmd_execif_desc; } } public override string CmdDesc { get { return Translations.cmd_execif_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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("--->")) private int HandleCommand(CmdResult r, McClient handler, string expressionText, string resultCommand)
return GetCmdDescTranslated(); {
try
{
var interpreter = new Interpreter();
interpreter.SetVariable("MCC", handler);
string[] parts = commandsString.Split("--->", StringSplitOptions.TrimEntries) foreach (KeyValuePair<string, object> entry in Settings.Config.AppVar.GetVariables())
.ToList() interpreter.SetVariable(entry.Key, entry.Value);
.ConvertAll(command => command.Trim())
.ToArray();
if (parts.Length == 0) var result = interpreter.Eval<bool>(expressionText);
return GetCmdDescTranslated();
string expressionText = parts[0]; bool shouldExec = result;
string resultCommand = parts[1];
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(); CmdResult output = new();
interpreter.SetVariable("MCC", handler); handler.PerformInternalCommand(resultCommand, ref output);
foreach (KeyValuePair<string, object> entry in Settings.Config.AppVar.GetVariables()) return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_execif_executed, expressionText, resultCommand, output));
interpreter.SetVariable(entry.Key, entry.Value);
var result = interpreter.Eval<bool>(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 "";
} }
catch (Exception e) else
{ {
handler.Log.Error(string.Format(Translations.cmd_execif_error_occured, command)); return r.SetAndReturn(CmdResult.Status.Done);
handler.Log.Error(string.Format(Translations.cmd_execif_error, e.Message));
return "";
} }
} }
catch (Exception e)
return GetCmdDescTranslated(); {
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));
}
} }
} }
} }

View file

@ -2,6 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -11,42 +13,47 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "execmulti <command 1> -> <command2> -> <command 3> -> ..."; } } public override string CmdUsage { get { return "execmulti <command 1> -> <command2> -> <command 3> -> ..."; } }
public override string CmdDesc { get { return Translations.cmd_execmulti_desc; } } public override string CmdDesc { get { return Translations.cmd_execmulti_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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)) private int HandleCommand(CmdResult r, McClient handler, string commandsString)
return Translations.cmd_execmulti_prevent; {
if (commandsString.Contains("execmulti", StringComparison.OrdinalIgnoreCase) || commandsString.Contains("execif", StringComparison.OrdinalIgnoreCase))
return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_execmulti_prevent);
IEnumerable<string> commands = commandsString.Split("->", StringSplitOptions.TrimEntries) IEnumerable<string> commands = commandsString.Split("->", StringSplitOptions.TrimEntries)
.ToList() .ToList()
.FindAll(command => !string.IsNullOrEmpty(command)); .FindAll(command => !string.IsNullOrEmpty(command));
foreach (string cmd in commands) foreach (string cmd in commands)
{ {
string? output = ""; CmdResult output = new();
handler.PerformInternalCommand(cmd, ref output); handler.PerformInternalCommand(cmd, ref output);
handler.Log.Info(string.Format(Translations.cmd_execmulti_executed, cmd, string.Format(Translations.cmd_execmulti_result, 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 "";
} }
return GetCmdDescTranslated(); return r.SetAndReturn(CmdResult.Status.Done);
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using Brigadier.NET;
using Brigadier.NET; using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -9,19 +10,48 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "exit"; } } public override string CmdUsage { get { return "exit"; } }
public override string CmdDesc { get { return Translations.cmd_exit_desc; } } public override string CmdDesc { get { return Translations.cmd_exit_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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(); Program.Exit();
return ""; return string.Empty;
}
public override IEnumerable<string> GetCMDAliases()
{
return new string[] { "quit" };
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -9,13 +10,34 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "health"; } } public override string CmdUsage { get { return "health"; } }
public override string CmdDesc { get { return Translations.cmd_health_desc; } } public override string CmdDesc { get { return Translations.cmd_health_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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()));
} }
} }
} }

View file

@ -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<CmdResult> dispatcher)
{
dispatcher.Register(l =>
l.Literal("help")
.Executes(r => LogHelp(r.Source, handler, dispatcher))
);
}
private int LogHelp(CmdResult r, McClient handler, CommandDispatcher<CmdResult> 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);
}
}
}

View file

@ -1,9 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
@ -14,270 +15,374 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return GetBasicUsage(); } } public override string CmdUsage { get { return GetBasicUsage(); } }
public override string CmdDesc { get { return Translations.cmd_inventory_desc; } } public override string CmdDesc { get { return Translations.cmd_inventory_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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); #pragma warning disable format // @formatter:off
if (args.Length >= 1) "list" => Translations.cmd_inventory_help_list + usageStr + "/inventory <player|container|<id>> list",
{ "close" => Translations.cmd_inventory_help_close + usageStr + "/inventory <player|container|<id>> close",
int inventoryId; "click" => Translations.cmd_inventory_help_click + usageStr + "/inventory <player|container|<id>> click <slot> [left|right|middle|shift]\nDefault is left click",
if (args[0].ToLower() == "creativegive") "drop" => Translations.cmd_inventory_help_drop + usageStr + "/inventory <player|container|<id>> drop <slot> [all]\nAll means drop full stack",
{ "creativegive" => Translations.cmd_inventory_help_creativegive + usageStr + "/inventory creativegive <slot> <itemtype> <amount>",
if (args.Length >= 4) "creativedelete" => Translations.cmd_inventory_help_creativedelete + usageStr + "/inventory creativedelete <slot>",
{ "inventories" => Translations.cmd_inventory_help_inventories + usageStr + "/inventory inventories",
if (!int.TryParse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture, out int slot)) "search" => Translations.cmd_inventory_help_search + usageStr + "/inventory search <item type> [count]",
return GetCmdDescTranslated(); "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)) private int GetMaximumInventoryId(McClient handler)
{ {
if (handler.GetGamemode() == 1) List<int> availableIds = handler.GetInventories().Keys.ToList();
{ return availableIds.Max(); // use foreground container
if (!int.TryParse(args[3], NumberStyles.Any, CultureInfo.CurrentCulture, out int count)) }
return GetCmdDescTranslated();
if (handler.DoCreativeGive(slot, itemType, count, null)) private int ListAllInventories(CmdResult r, McClient handler)
return string.Format(Translations.cmd_inventory_creative_done, itemType, count, slot); {
else if (!handler.GetInventoryEnabled())
return Translations.cmd_inventory_creative_fail; {
} handler.Log.Info(Translations.extra_inventory_required);
else return -1;
return Translations.cmd_inventory_need_creative; }
} StringBuilder response = new();
else response.Append(Translations.cmd_inventory_inventories).Append(":\n");
return GetCmdDescTranslated(); foreach ((int invId, Container inv) in handler.GetInventories())
} response.AppendLine(String.Format(" #{0}: {1}§8", invId, inv.Title));
else response.Append(CmdUsage);
return GetCmdDescTranslated(); handler.Log.Info(response.ToString());
} return r.SetAndReturn(CmdResult.Status.Done);
else if (args[0].ToLower() == "creativedelete") }
{
if (args.Length >= 2)
{
if (!int.TryParse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture, out int slot))
return GetCmdDescTranslated();
if (handler.GetGamemode() == 1) private int DoCreativeGive(CmdResult r, McClient handler, int slot, ItemType itemType, int count)
{ {
if (handler.DoCreativeGive(slot, ItemType.Null, 0, null)) if (!handler.GetInventoryEnabled())
return string.Format(Translations.cmd_inventory_creative_delete, slot); return r.SetAndReturn(CmdResult.Status.FailNeedInventory);
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<int> 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<int, Container> inventories = handler.GetInventories();
List<int> availableIds = inventories.Keys.ToList();
StringBuilder response = new();
response.AppendLine(Translations.cmd_inventory_inventories_available);
foreach (int id in availableIds) if (handler.GetGamemode() == 1)
response.AppendLine(String.Format(" #{0} - {1}§8", id, inventories[id].Title)); {
if (handler.DoCreativeGive(slot, itemType, count, null))
return response.ToString(); return r.SetAndReturn(CmdResult.Status.Done, string.Format(Translations.cmd_inventory_creative_done, itemType, count, slot));
}
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<int, Container> inventories = handler.GetInventories();
Dictionary<int, List<Item>> foundItems = new();
List<Container> 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>() { item });
return;
}
List<Item> 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<Item> itemsList) in new SortedDictionary<int, List<Item>>(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<int, Item>(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();
}
else else
{ return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_inventory_creative_fail);
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();
}
} }
else 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<int, Container> inventories = handler.GetInventories();
List<int> 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<int, Container> inventories = handler.GetInventories();
Dictionary<int, List<Item>> foundItems = new();
List<Container> 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>() { item });
return;
}
List<Item> 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<Item> itemsList) in new SortedDictionary<int, List<Item>>(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<int, Item>(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 #region Methods for commands help
private static string GetAvailableActions() private static string GetAvailableActions()
@ -290,31 +395,6 @@ namespace MinecraftClient.Commands
return Translations.cmd_inventory_help_basic + ": /inventory <player|container|<id>> <action>."; return Translations.cmd_inventory_help_basic + ": /inventory <player|container|<id>> <action>.";
} }
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 <player|container|<id>> list",
"close" => Translations.cmd_inventory_help_close + usageStr + "/inventory <player|container|<id>> close",
"click" => Translations.cmd_inventory_help_click + usageStr + "/inventory <player|container|<id>> click <slot> [left|right|middle]\nDefault is left click",
"shiftclick" => Translations.cmd_inventory_help_shiftclick + usageStr + "/inventory <player|container|<id>> shiftclick <slot>",
"drop" => Translations.cmd_inventory_help_drop + usageStr + "/inventory <player|container|<id>> drop <slot> [all]\nAll means drop full stack",
"creativegive" => Translations.cmd_inventory_help_creativegive + usageStr + "/inventory creativegive <slot> <itemtype> <amount>",
"creativedelete" => Translations.cmd_inventory_help_creativedelete + usageStr + "/inventory creativedelete <slot>",
"inventories" => Translations.cmd_inventory_help_inventories + usageStr + "/inventory inventories",
"search" => Translations.cmd_inventory_help_search + usageStr + "/inventory search <item type> [count]",
"help" => GetHelp(),
_ => Translations.cmd_inventory_help_unknown + GetAvailableActions(),
#pragma warning restore format // @formatter:on
};
}
#endregion #endregion
} }
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -10,13 +11,34 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "list"; } } public override string CmdUsage { get { return "list"; } }
public override string CmdDesc { get { return Translations.cmd_list_desc; } } public override string CmdDesc { get { return Translations.cmd_list_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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())));
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using Brigadier.NET;
using Brigadier.NET; using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -9,18 +10,35 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "log <text>"; } } public override string CmdUsage { get { return "log <text>"; } }
public override string CmdDesc { get { return Translations.cmd_log_desc; } } public override string CmdDesc { get { return Translations.cmd_log_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? localVars) private int GetUsage(CmdResult r, string? cmd)
{ {
if (HasArg(command)) return r.SetAndReturn(cmd switch
{ {
ConsoleIO.WriteLogLine(GetArg(command)); #pragma warning disable format // @formatter:off
return ""; _ => GetCmdDescTranslated(),
} #pragma warning restore format // @formatter:on
else return GetCmdDescTranslated(); });
}
private int DoLog(CmdResult r, string command)
{
return r.SetAndReturn(CmdResult.Status.Done, command);
} }
} }
} }

View file

@ -1,8 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.Globalization;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using static MinecraftClient.CommandHandler.CmdResult;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -12,74 +13,102 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "look <x y z|yaw pitch|up|down|east|west|north|south>"; } } public override string CmdUsage { get { return "look <x y z|yaw pitch|up|down|east|west|north|south>"; } }
public override string CmdDesc { get { return Translations.cmd_look_desc; } } public override string CmdDesc { get { return Translations.cmd_look_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? localVars) private int GetUsage(CmdResult r, string? cmd)
{ {
if (handler.GetTerrainEnabled()) return r.SetAndReturn(cmd switch
{ {
string[] args = GetArgs(command); #pragma warning disable format // @formatter:off
if (args.Length == 0) "direction" => GetCmdDescTranslated(),
{ "angle" => GetCmdDescTranslated(),
const double maxDistance = 8.0; "location" => GetCmdDescTranslated(),
(bool hasBlock, Location target, Block block) = RaycastHelper.RaycastBlock(handler, maxDistance, false); _ => GetCmdDescTranslated(),
if (!hasBlock) #pragma warning restore format // @formatter:on
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);
}
handler.UpdateLocation(handler.GetCurrentLocation(), direction); private int LogCurrentLooking(CmdResult r, McClient handler)
return "Looking " + dirStr; {
} if (!handler.GetTerrainEnabled())
else if (args.Length == 2) return r.SetAndReturn(Status.FailNeedTerrain);
{
try
{
float yaw = float.Parse(args[0], NumberStyles.Any, CultureInfo.CurrentCulture);
float pitch = float.Parse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture);
handler.UpdateLocation(handler.GetCurrentLocation(), yaw, pitch); const double maxDistance = 8.0;
return string.Format(Translations.cmd_look_at, yaw.ToString("0.00"), pitch.ToString("0.00")); (bool hasBlock, Location target, Block block) = RaycastHelper.RaycastBlock(handler, maxDistance, false);
} if (!hasBlock)
catch (FormatException) { return GetCmdDescTranslated(); } {
} return r.SetAndReturn(Status.Fail, string.Format(Translations.cmd_look_noinspection, maxDistance));
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();
} }
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));
} }
} }
} }

View file

@ -1,8 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using static MinecraftClient.CommandHandler.CmdResult;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -12,111 +13,183 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "move <on|off|get|up|down|east|west|north|south|center|x y z|gravity [on|off]> [-f]"; } } public override string CmdUsage { get { return "move <on|off|get|up|down|east|west|north|south|center|x y z|gravity [on|off]> [-f]"; } }
public override string CmdDesc { get { return Translations.cmd_move_desc + " \"-f\": " + Translations.cmd_move_desc_force; } } public override string CmdDesc { get { return Translations.cmd_move_desc + " \"-f\": " + Translations.cmd_move_desc_force; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? localVars) private int GetUsage(CmdResult r, string? cmd)
{ {
List<string> args = GetArgs(command.ToLower()).ToList(); return r.SetAndReturn(cmd switch
bool takeRisk = false;
if (args.Count < 1)
{ {
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()) private int SetMovementEnable(CmdResult r, McClient handler, bool enable)
handler.Log.Info(World.GetChunkLoadingStatus(handler.GetWorld())); {
if (enable)
return desc;
}
if (args.Contains("-f"))
{
takeRisk = true;
args.Remove("-f");
}
if (args[0] == "on")
{ {
handler.SetTerrainEnabled(true); 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); 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) if (handler.MoveTo(goal, allowUnsafe: takeRisk))
Settings.InternalConfig.GravityEnabled = (args[1] == "on"); return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_move_moving, direction.ToString()));
if (Settings.InternalConfig.GravityEnabled) else
return Translations.cmd_move_gravity_enabled; return r.SetAndReturn(Status.Fail, takeRisk ? Translations.cmd_move_dir_fail : Translations.cmd_move_suggestforce);
else return Translations.cmd_move_gravity_disabled;
} }
else if (handler.GetTerrainEnabled()) else
{ {
if (args.Count == 1) return r.SetAndReturn(Status.Fail, Translations.cmd_move_dir_fail);
{ }
Direction direction; }
switch (args[0])
{ private int MoveToLocation(CmdResult r, McClient handler, Location goal, bool takeRisk)
case "up": direction = Direction.Up; break; {
case "down": direction = Direction.Down; break; if (!handler.GetTerrainEnabled())
case "east": direction = Direction.East; break; return r.SetAndReturn(Status.FailNeedTerrain);
case "west": direction = Direction.West; break;
case "north": direction = Direction.North; break; Location current = handler.GetCurrentLocation(), currentCenter = current.ToCenter();
case "south": direction = Direction.South; break; goal.ToAbsolute(current);
case "center":
Location current = handler.GetCurrentLocation(); if (!Movement.CheckChunkLoading(handler.GetWorld(), current, goal))
Location currentCenter = new(Math.Floor(current.X) + 0.5, current.Y, Math.Floor(current.Z) + 0.5); return r.SetAndReturn(Status.FailChunkNotLoad, string.Format(Translations.cmd_move_chunk_not_loaded, goal.X, goal.Y, goal.Z));
handler.MoveTo(currentCenter, allowDirectTeleport: true);
return string.Format(Translations.cmd_move_walk, currentCenter, current); if (takeRisk || Movement.PlayerFitsHere(handler.GetWorld(), goal))
case "get": return handler.GetCurrentLocation().ToString(); {
default: return string.Format(Translations.cmd_look_unknown, args[0]); if (current.ToFloor() == goal.ToFloor())
} handler.MoveTo(goal, allowDirectTeleport: true);
else if (!handler.MoveTo(goal, allowUnsafe: takeRisk))
Location goal = Movement.Move(handler.GetCurrentLocation(), direction); 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));
if (!Movement.CheckChunkLoading(handler.GetWorld(), handler.GetCurrentLocation(), goal)) }
return string.Format(Translations.cmd_move_chunk_not_loaded, goal.X, goal.Y, goal.Z); else
{
if (Movement.CanMove(handler.GetWorld(), handler.GetCurrentLocation(), direction)) return r.SetAndReturn(Status.Fail, string.Format(Translations.cmd_move_suggestforce, goal));
{
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();
} }
else return Translations.extra_terrainandmovement_required;
} }
} }
} }

View file

@ -1,5 +1,7 @@
using System.Collections.Generic; using System;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -9,22 +11,58 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "reco [account]"; } } public override string CmdUsage { get { return "reco [account]"; } }
public override string CmdDesc { get { return Translations.cmd_reco_desc; } } public override string CmdDesc { get { return Translations.cmd_reco_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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); string[] args = GetArgs(command);
if (args.Length > 0) 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); Program.Restart(keepAccountAndServerSettings: true);
return ""; return String.Empty;
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -9,11 +10,32 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "reload"; } } public override string CmdUsage { get { return "reload"; } }
public override string CmdDesc { get { return Translations.cmd_reload_desc; } } public override string CmdDesc { get { return Translations.cmd_reload_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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.Log.Info(Translations.cmd_reload_started);
handler.ReloadSettings(); handler.ReloadSettings();
@ -22,7 +44,7 @@ namespace MinecraftClient.Commands
handler.Log.Warn(Translations.cmd_reload_warning3); handler.Log.Warn(Translations.cmd_reload_warning3);
handler.Log.Warn(Translations.cmd_reload_warning4); handler.Log.Warn(Translations.cmd_reload_warning4);
return Translations.cmd_reload_finished; return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_reload_finished);
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using Brigadier.NET;
using Brigadier.NET; using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -9,14 +10,35 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "respawn"; } } public override string CmdUsage { get { return "respawn"; } }
public override string CmdDesc { get { return Translations.cmd_respawn_desc; } } public override string CmdDesc { get { return Translations.cmd_respawn_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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(); handler.SendRespawnPacket();
return Translations.cmd_respawn_done; return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_respawn_done);
} }
} }
} }

View file

@ -1,5 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -9,18 +11,36 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "script <scriptname>"; } } public override string CmdUsage { get { return "script <scriptname>"; } }
public override string CmdDesc { get { return Translations.cmd_script_desc; } } public override string CmdDesc { get { return Translations.cmd_script_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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)); #pragma warning disable format // @formatter:off
return ""; _ => GetCmdDescTranslated(),
} #pragma warning restore format // @formatter:on
else return GetCmdDescTranslated(); });
}
private int DoExecuteScript(CmdResult r, McClient handler, string command, Dictionary<string, object>? localVars)
{
handler.BotLoad(new ChatBots.Script(command.Trim(), null, localVars));
return r.SetAndReturn(CmdResult.Status.Done);
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using Brigadier.NET;
using Brigadier.NET; using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -9,18 +10,34 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "send <text>"; } } public override string CmdUsage { get { return "send <text>"; } }
public override string CmdDesc { get { return Translations.cmd_send_desc; } } public override string CmdDesc { get { return Translations.cmd_send_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? localVars) private int GetUsage(CmdResult r, string? cmd)
{ {
if (HasArg(command)) return r.SetAndReturn(cmd switch
{ {
handler.SendText(GetArg(command)); #pragma warning disable format // @formatter:off
return ""; _ => GetCmdDescTranslated(),
} #pragma warning restore format // @formatter:on
else return GetCmdDescTranslated(); });
}
private int DoSendText(CmdResult r, McClient handler, string command)
{
handler.SendText(command);
return r.SetAndReturn(CmdResult.Status.Done);
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using Brigadier.NET;
using Brigadier.NET; using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -9,27 +10,50 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "set varname=value"; } } public override string CmdUsage { get { return "set varname=value"; } }
public override string CmdDesc { get { return Translations.cmd_set_desc; } } public override string CmdDesc { get { return Translations.cmd_set_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? localVars) private int GetUsage(CmdResult r, string? cmd)
{ {
if (HasArg(command)) return r.SetAndReturn(cmd switch
{ {
string[] temp = GetArg(command).Split('='); #pragma warning disable format // @formatter:off
if (temp.Length > 1) _ => 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 r.SetAndReturn(CmdResult.Status.Done); //Success
return ""; //Success
else
return Translations.cmd_set_format;
} }
else else
return GetCmdDescTranslated(); {
return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_set_format);
}
} }
else else
return GetCmdDescTranslated(); {
return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_set_format);
}
} }
} }
} }

View file

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -11,65 +13,61 @@ namespace MinecraftClient.Commands
public override string CmdDesc { get { return Translations.cmd_setrnd_desc; } } public override string CmdDesc { get { return Translations.cmd_setrnd_desc; } }
private static readonly Random rand = new(); private static readonly Random rand = new();
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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) private int DoSetRnd(CmdResult r, string var, string argString)
{ {
// detect "to" keyword in string // process all arguments similar to regular terminals with quotes and escaping
if (args.Length == 2 && args[1].Contains("to")) List<string> values = ParseCommandLine(argString);
{
int num1;
int num2;
// try to extract the two numbers from the string // create a variable or set it to one of the values
try 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)));
num1 = Convert.ToInt32(args[1][..args[1].IndexOf('t')]); else
num2 = Convert.ToInt32(args[1].Substring(args[1].IndexOf('o') + 1, args[1].Length - 1 - args[1].IndexOf('o'))); return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_setrndstr_format);
} }
catch (Exception)
{
return Translations.cmd_setrndnum_format;
}
// switch the values if they were entered in the wrong way private int DoSetRnd(CmdResult r, string var, long min, long max)
if (num2 < num1) {
(num2, num1) = (num1, num2); // 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 // create a variable or set it to num1 <= varlue < num2
if (Settings.Config.AppVar.SetVar(args[0], rand.Next(num1, 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)));
return string.Format("Set %{0}% to {1}.", args[0], Settings.Config.AppVar.GetVar(args[0])); //Success else
} return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_setrndstr_format);
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<string> 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();
} }
} }
} }

View file

@ -1,34 +1,62 @@
using System.Collections.Generic; using Brigadier.NET;
using Brigadier.NET; using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
public class Sneak : Command public class Sneak : Command
{ {
private bool sneaking = false; private bool sneaking = false;
public override string CmdName { get { return "Sneak"; } } public override string CmdName { get { return "sneak"; } }
public override string CmdUsage { get { return "Sneak"; } } public override string CmdUsage { get { return "sneak"; } }
public override string CmdDesc { get { return Translations.cmd_sneak_desc; } } public override string CmdDesc { get { return Translations.cmd_sneak_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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) if (sneaking)
{ {
var result = handler.SendEntityAction(Protocol.EntityActionType.StopSneaking); var result = handler.SendEntityAction(Protocol.EntityActionType.StopSneaking);
if (result) if (result)
sneaking = false; 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 else
{ {
var result = handler.SendEntityAction(Protocol.EntityActionType.StartSneaking); var result = handler.SendEntityAction(Protocol.EntityActionType.StartSneaking);
if (result) if (result)
sneaking = true; 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);
} }
} }
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -10,11 +11,32 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "tps"; } } public override string CmdUsage { get { return "tps"; } }
public override string CmdDesc { get { return Translations.cmd_tps_desc; } } public override string CmdDesc { get { return Translations.cmd_tps_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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); var tps = Math.Round(handler.GetServerTPS(), 2);
string color; string color;
@ -22,9 +44,9 @@ namespace MinecraftClient.Commands
color = "§c"; // Red color = "§c"; // Red
else if (tps < 15) else if (tps < 15)
color = "§e"; // Yellow color = "§e"; // Yellow
else else
color = "§a"; // Green color = "§a"; // Green
return Translations.cmd_tps_current + ": " + color + tps; return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_tps_current + ": " + color + tps);
} }
} }
} }

View file

@ -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 namespace MinecraftClient.Commands
{ {
@ -9,18 +11,38 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "useitem"; } } public override string CmdUsage { get { return "useitem"; } }
public override string CmdDesc { get { return Translations.cmd_useitem_desc; } } public override string CmdDesc { get { return Translations.cmd_useitem_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? localVars) private int GetUsage(CmdResult r, string? cmd)
{ {
if (handler.GetInventoryEnabled()) return r.SetAndReturn(cmd switch
{ {
handler.UseItemOnHand(); #pragma warning disable format // @formatter:off
return Translations.cmd_useitem_use; _ => GetCmdDescTranslated(),
} #pragma warning restore format // @formatter:on
else return Translations.extra_inventory_required; });
}
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);
} }
} }
} }

View file

@ -1,6 +1,8 @@
using System.Collections.Generic;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using static MinecraftClient.CommandHandler.CmdResult;
namespace MinecraftClient.Commands namespace MinecraftClient.Commands
{ {
@ -10,29 +12,42 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "useblock <x> <y> <z>"; } } public override string CmdUsage { get { return "useblock <x> <y> <z>"; } }
public override string CmdDesc { get { return Translations.cmd_useblock_desc; } } public override string CmdDesc { get { return Translations.cmd_useblock_desc; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CommandSource> dispatcher) public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> 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<string, object>? 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()) if (!handler.GetTerrainEnabled())
return Translations.extra_terrainandmovement_required; return r.SetAndReturn(Status.FailNeedTerrain);
else if (HasArg(command))
{ Location current = handler.GetCurrentLocation();
string[] args = GetArgs(command); block = block.ToAbsolute(current).ToFloor();
if (args.Length >= 3) Location blockCenter = block.ToCenter();
{ bool res = handler.PlaceBlock(block, Direction.Down);
Location block = Location.Parse(handler.GetCurrentLocation().ToFloor(), args[0], args[1], args[2]).ToFloor(); return r.SetAndReturn(string.Format(Translations.cmd_useblock_use, blockCenter.X, blockCenter.Y, blockCenter.Z, res ? "succeeded" : "failed"), res);
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();
} }
} }
} }

View file

@ -1,6 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FuzzySharp;
using MinecraftClient.CommandHandler;
using MinecraftClient.Scripting;
using static MinecraftClient.Settings;
namespace MinecraftClient namespace MinecraftClient
{ {
@ -175,16 +182,151 @@ namespace MinecraftClient
#endregion #endregion
public static void AutocompleteHandler(object? sender, ConsoleKey e)
internal static bool AutoCompleteDone = false;
internal static string[] AutoCompleteResult = Array.Empty<string>();
private static HashSet<string> Commands = new();
private static string[] CommandsFromAutoComplete = Array.Empty<string>();
private static string[] CommandsFromDeclareCommands = Array.Empty<string>();
private static Task _latestTask = Task.CompletedTask;
private static CancellationTokenSource? _cancellationTokenSource;
private static void MccAutocompleteHandler(ConsoleInteractive.ConsoleReader.Buffer buffer)
{ {
if (e != ConsoleKey.Tab) return; string fullCommand = buffer.Text;
if (string.IsNullOrEmpty(fullCommand))
if (autocomplete_engine == null) {
ConsoleInteractive.ConsoleSuggestion.ClearSuggestions();
return; return;
}
var buffer = ConsoleInteractive.ConsoleReader.GetBufferContent(); var InternalCmdChar = Config.Main.Advanced.InternalCmdChar;
ConsoleIO.WriteLine("AutoComplete " + buffer); if (InternalCmdChar == MainConfigHealper.MainConfig.AdvancedConfig.InternalCmdCharType.none || fullCommand[0] == InternalCmdChar.ToChar())
autocomplete_engine.AutoComplete(buffer.Text[..buffer.CursorPosition]); {
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<int, int> 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<string>();
CommandsFromAutoComplete = Array.Empty<string>();
CommandsFromDeclareCommands = Array.Empty<string>();
}
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
/// </summary> /// </summary>
/// <param name="BehindCursor">Text behind the cursor, e.g. "my input comm"</param> /// <param name="BehindCursor">Text behind the cursor, e.g. "my input comm"</param>
/// <returns>List of auto-complete words, e.g. ["command", "comment"]</returns> /// <returns>List of auto-complete words, e.g. ["command", "comment"]</returns>
IEnumerable<string> AutoComplete(string BehindCursor); int AutoComplete(string BehindCursor);
} }
} }

View file

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using MinecraftClient.Protocol.Handlers; using MinecraftClient.Protocol.Handlers;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Inventory namespace MinecraftClient.Inventory
{ {
@ -158,7 +159,7 @@ namespace MinecraftClient.Inventory
public static string GetEnchantmentName(Enchantment enchantment) 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)) if (string.IsNullOrEmpty(trans))
return "Unknown Enchantment with ID: " + ((short)enchantment) + " (Probably not named in the code yet)"; return "Unknown Enchantment with ID: " + ((short)enchantment) + " (Probably not named in the code yet)";
else else

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Inventory namespace MinecraftClient.Inventory
{ {
@ -64,7 +65,7 @@ namespace MinecraftClient.Inventory
{ {
string? displayName = displayProperties["Name"] as string; string? displayName = displayProperties["Name"] as string;
if (!String.IsNullOrEmpty(displayName)) if (!String.IsNullOrEmpty(displayName))
return MinecraftClient.Protocol.ChatParser.ParseText(displayProperties["Name"].ToString() ?? string.Empty); return ChatParser.ParseText(displayProperties["Name"].ToString() ?? string.Empty);
} }
} }
return null; return null;
@ -85,7 +86,7 @@ namespace MinecraftClient.Inventory
{ {
object[] displayName = (object[])displayProperties["Lore"]; object[] displayName = (object[])displayProperties["Lore"];
lores.AddRange(from string st in displayName lores.AddRange(from string st in displayName
let str = MinecraftClient.Protocol.ChatParser.ParseText(st.ToString()) let str = ChatParser.ParseText(st.ToString())
select str); select str);
return lores.ToArray(); return lores.ToArray();
} }
@ -117,10 +118,10 @@ namespace MinecraftClient.Inventory
{ {
string type_str = type.ToString(); string type_str = type.ToString();
string type_renamed = type_str.ToUnderscoreCase(); 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)) if (!string.IsNullOrEmpty(res1))
return res1; return res1;
string? res2 = Protocol.ChatParser.TranslateString("block.minecraft." + type_renamed); string? res2 = ChatParser.TranslateString("block.minecraft." + type_renamed);
if (!string.IsNullOrEmpty(res2)) if (!string.IsNullOrEmpty(res2))
return res2; return res2;
return type_str; return type_str;
@ -145,8 +146,8 @@ namespace MinecraftClient.Inventory
short level = (short)enchantment["lvl"]; short level = (short)enchantment["lvl"];
string id = ((string)enchantment["id"]).Replace(':', '.'); string id = ((string)enchantment["id"]).Replace(':', '.');
sb.AppendFormat(" | {0} {1}", sb.AppendFormat(" | {0} {1}",
Protocol.ChatParser.TranslateString("enchantment." + id) ?? id, ChatParser.TranslateString("enchantment." + id) ?? id,
Protocol.ChatParser.TranslateString("enchantment.level." + level) ?? level.ToString()); ChatParser.TranslateString("enchantment.level." + level) ?? level.ToString());
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using MinecraftClient.Scripting;
namespace MinecraftClient.Inventory namespace MinecraftClient.Inventory
{ {

View file

@ -1,4 +1,4 @@
namespace MinecraftClient.Mapping namespace MinecraftClient.Inventory
{ {
/// <summary> /// <summary>
/// Properties of a villager /// Properties of a villager

View file

@ -103,7 +103,7 @@ namespace MinecraftClient
&& IsHex(toparse[cursorpos + 5])) && IsHex(toparse[cursorpos + 5]))
{ {
//"abc\u0123abc" => "0123" => 0123 => Unicode char n°0123 => Add char to string //"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)); System.Globalization.NumberStyles.HexNumber));
cursorpos += 6; continue; cursorpos += 6; continue;
} }

View file

@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using MinecraftClient.Scripting;
namespace MinecraftClient.Logger namespace MinecraftClient.Logger
{ {

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using MinecraftClient.Mapping.BlockPalettes; using MinecraftClient.Mapping.BlockPalettes;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Mapping namespace MinecraftClient.Mapping
{ {
@ -115,7 +116,7 @@ namespace MinecraftClient.Mapping
public string GetTypeString() public string GetTypeString()
{ {
string typeStr = Type.ToString(); 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; return string.IsNullOrEmpty(trans) ? typeStr : trans;
} }

View file

@ -139,9 +139,9 @@ namespace MinecraftClient.Mapping
try try
{ {
var monsterSpawnLightLevelObj = nbt["monster_spawn_light_level"]; var monsterSpawnLightLevelObj = nbt["monster_spawn_light_level"];
try try
{ {
monsterSpawnMinLightLevel = monsterSpawnMaxLightLevel = Convert.ToInt32(monsterSpawnLightLevelObj); monsterSpawnMinLightLevel = monsterSpawnMaxLightLevel = Convert.ToInt32(monsterSpawnLightLevelObj);
} }
catch (Exception) catch (Exception)
{ {

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Mapping namespace MinecraftClient.Mapping
{ {
@ -158,7 +159,7 @@ namespace MinecraftClient.Mapping
public string GetTypeString() public string GetTypeString()
{ {
string typeStr = Type.ToString(); 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; return string.IsNullOrEmpty(trans) ? typeStr : trans;
} }
} }

View file

@ -26,6 +26,15 @@ namespace MinecraftClient.Mapping
/// </summary> /// </summary>
public double Z; public double Z;
/// <summary>
/// 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)
/// </summary>
public byte Status;
/// <summary> /// <summary>
/// Create a new location /// Create a new location
/// </summary> /// </summary>
@ -34,6 +43,18 @@ namespace MinecraftClient.Mapping
X = x; X = x;
Y = y; Y = y;
Z = z; Z = z;
Status = 0;
}
/// <summary>
/// Create a new location
/// </summary>
public Location(double x, double y, double z, byte status)
{
X = x;
Y = y;
Z = z;
Status = status;
} }
/// <summary> /// <summary>
@ -44,6 +65,7 @@ namespace MinecraftClient.Mapping
X = loc.X; X = loc.X;
Y = loc.Y; Y = loc.Y;
Z = loc.Z; Z = loc.Z;
Status = loc.Status;
} }
/// <summary> /// <summary>
@ -60,6 +82,19 @@ namespace MinecraftClient.Mapping
X = chunkX * Chunk.SizeX + blockX; X = chunkX * Chunk.SizeX + blockX;
Y = blockY; Y = blockY;
Z = chunkZ * Chunk.SizeZ + blockZ; 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;
} }
/// <summary> /// <summary>

View file

@ -36,7 +36,7 @@ namespace MinecraftClient.Mapping
{ {
if (start == end) if (start == end)
return new(false, Location.Zero, Block.Air); return new(false, Location.Zero, Block.Air);
double start_x = MathHelper.Lerp(-1.0E-7, start.X, end.X); 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_y = MathHelper.Lerp(-1.0E-7, start.Y, end.Y);
double start_z = MathHelper.Lerp(-1.0E-7, start.Z, end.Z); double start_z = MathHelper.Lerp(-1.0E-7, start.Z, end.Z);
@ -87,7 +87,7 @@ namespace MinecraftClient.Mapping
res_location.Z += dz_sign; res_location.Z += dz_sign;
z_frac += z_step; z_frac += z_step;
} }
block = CheckRaycastResult(world, res_location, includeFluids); block = CheckRaycastResult(world, res_location, includeFluids);
if (block.Type != Material.Air) if (block.Type != Material.Air)
return new(true, res_location, block); return new(true, res_location, block);

View file

@ -153,7 +153,7 @@ namespace MinecraftClient.Mapping
/// <param name="block">Block type</param> /// <param name="block">Block type</param>
/// <param name="radius">Search radius - larger is slower: O^3 complexity</param> /// <param name="radius">Search radius - larger is slower: O^3 complexity</param>
/// <returns>Block matching the specified block type</returns> /// <returns>Block matching the specified block type</returns>
public List<Location> FindBlock(Location from, Material block, int radius) public List<Location> FindBlock(Location from, Material block, double radius)
{ {
return FindBlock(from, block, radius, radius, radius); return FindBlock(from, block, radius, radius, radius);
} }
@ -167,7 +167,7 @@ namespace MinecraftClient.Mapping
/// <param name="radiusy">Search radius on the Y axis</param> /// <param name="radiusy">Search radius on the Y axis</param>
/// <param name="radiusz">Search radius on the Z axis</param> /// <param name="radiusz">Search radius on the Z axis</param>
/// <returns>Block matching the specified block type</returns> /// <returns>Block matching the specified block type</returns>
public List<Location> FindBlock(Location from, Material block, int radiusx, int radiusy, int radiusz) public List<Location> 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 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); Location maxPoint = new Location(from.X + radiusx, from.Y + radiusy, from.Z + radiusz);

View file

@ -2,22 +2,23 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Cryptography.Pkcs;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using Brigadier.NET; using Brigadier.NET;
using Brigadier.NET.Exceptions; using Brigadier.NET.Exceptions;
using MinecraftClient.ChatBots; using MinecraftClient.ChatBots;
using MinecraftClient.Commands; using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using MinecraftClient.Logger; using MinecraftClient.Logger;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Protocol; using MinecraftClient.Protocol;
using MinecraftClient.Protocol.Handlers.Forge; using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Protocol.Keys;
using MinecraftClient.Protocol.Message; using MinecraftClient.Protocol.Message;
using MinecraftClient.Protocol.ProfileKey;
using MinecraftClient.Protocol.Session; using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy; using MinecraftClient.Proxy;
using MinecraftClient.Scripting;
using static MinecraftClient.Settings; using static MinecraftClient.Settings;
namespace MinecraftClient namespace MinecraftClient
@ -29,10 +30,7 @@ namespace MinecraftClient
{ {
public static int ReconnectionAttemptsLeft = 0; public static int ReconnectionAttemptsLeft = 0;
public static readonly CommandSource cmd_source = new(); public static CommandDispatcher<CmdResult> dispatcher = new();
public static readonly CommandDispatcher<CommandSource> dispatcher = new();
//private static readonly List<string> cmd_names = new();
//private static readonly Dictionary<string, Command> cmds = new();
private readonly Dictionary<Guid, PlayerInfo> onlinePlayers = new(); private readonly Dictionary<Guid, PlayerInfo> onlinePlayers = new();
private static bool commandsLoaded = false; private static bool commandsLoaded = false;
@ -152,6 +150,8 @@ namespace MinecraftClient
/// <param name="forgeInfo">ForgeInfo item stating that Forge is enabled</param> /// <param name="forgeInfo">ForgeInfo item stating that Forge is enabled</param>
public McClient(SessionToken session, PlayerKeyPair? playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo? forgeInfo) 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; terrainAndMovementsEnabled = Config.Main.Advanced.TerrainAndMovements;
inventoryHandlingEnabled = Config.Main.Advanced.InventoryHandling; inventoryHandlingEnabled = Config.Main.Advanced.InventoryHandling;
entityHandlingEnabled = Config.Main.Advanced.EntityHandling; entityHandlingEnabled = Config.Main.Advanced.EntityHandling;
@ -206,7 +206,7 @@ namespace MinecraftClient
cmdprompt = new CancellationTokenSource(); cmdprompt = new CancellationTokenSource();
ConsoleInteractive.ConsoleReader.BeginReadThread(cmdprompt); ConsoleInteractive.ConsoleReader.BeginReadThread(cmdprompt);
ConsoleInteractive.ConsoleReader.MessageReceived += ConsoleReaderOnMessageReceived; ConsoleInteractive.ConsoleReader.MessageReceived += ConsoleReaderOnMessageReceived;
ConsoleInteractive.ConsoleReader.OnKeyInput += ConsoleIO.AutocompleteHandler; ConsoleInteractive.ConsoleReader.OnInputChange += ConsoleIO.AutocompleteHandler;
} }
else else
{ {
@ -230,7 +230,7 @@ namespace MinecraftClient
return; return;
Retry: Retry:
if (timeoutdetector != null) if (timeoutdetector != null)
{ {
timeoutdetector.Item2.Cancel(); timeoutdetector.Item2.Cancel();
@ -247,7 +247,7 @@ namespace MinecraftClient
{ {
ConsoleInteractive.ConsoleReader.StopReadThread(); ConsoleInteractive.ConsoleReader.StopReadThread();
ConsoleInteractive.ConsoleReader.MessageReceived -= ConsoleReaderOnMessageReceived; ConsoleInteractive.ConsoleReader.MessageReceived -= ConsoleReaderOnMessageReceived;
ConsoleInteractive.ConsoleReader.OnKeyInput -= ConsoleIO.AutocompleteHandler; ConsoleInteractive.ConsoleReader.OnInputChange -= ConsoleIO.AutocompleteHandler;
Program.HandleFailure(); Program.HandleFailure();
} }
@ -456,6 +456,8 @@ namespace MinecraftClient
/// </summary> /// </summary>
public void OnConnectionLost(ChatBot.DisconnectReason reason, string message) public void OnConnectionLost(ChatBot.DisconnectReason reason, string message)
{ {
ConsoleIO.CancelAutocomplete();
handler.Dispose(); handler.Dispose();
world.Clear(); world.Clear();
@ -514,7 +516,7 @@ namespace MinecraftClient
{ {
ConsoleInteractive.ConsoleReader.StopReadThread(); ConsoleInteractive.ConsoleReader.StopReadThread();
ConsoleInteractive.ConsoleReader.MessageReceived -= ConsoleReaderOnMessageReceived; ConsoleInteractive.ConsoleReader.MessageReceived -= ConsoleReaderOnMessageReceived;
ConsoleInteractive.ConsoleReader.OnKeyInput -= ConsoleIO.AutocompleteHandler; ConsoleInteractive.ConsoleReader.OnInputChange -= ConsoleIO.AutocompleteHandler;
Program.HandleFailure(); Program.HandleFailure();
} }
} }
@ -553,7 +555,9 @@ namespace MinecraftClient
switch (command[0].ToLower()) switch (command[0].ToLower())
{ {
case "autocomplete": 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); else ConsoleIO.WriteLine((char)0x00 + "autocomplete" + (char)0x00);
break; break;
} }
@ -561,70 +565,44 @@ namespace MinecraftClient
else else
{ {
text = text.Trim(); 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..]; 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); 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);
}
} }
} }
} }
/// <summary>
/// Register a custom console command
/// </summary>
/// <param name="cmdName">Name of the command</param>
/// <param name="cmdDesc">Description/usage of the command</param>
/// <param name="callback">Method for handling the command</param>
/// <returns>True if successfully registered</returns>
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;
}
/// <summary>
/// Unregister a console command
/// </summary>
/// <remarks>
/// There is no check for the command is registered by above method or is embedded command.
/// Which mean this can unload any command
/// </remarks>
/// <param name="cmdName">The name of command to be unregistered</param>
/// <returns></returns>
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;
}
/// <summary> /// <summary>
/// Perform an internal MCC command (not a server command, use SendText() instead for that!) /// Perform an internal MCC command (not a server command, use SendText() instead for that!)
/// </summary> /// </summary>
@ -632,82 +610,55 @@ namespace MinecraftClient
/// <param name="response_msg">May contain a confirmation or error message after processing the command, or "" otherwise.</param> /// <param name="response_msg">May contain a confirmation or error message after processing the command, or "" otherwise.</param>
/// <param name="localVars">Local variables passed along with the command</param> /// <param name="localVars">Local variables passed along with the command</param>
/// <returns>TRUE if the command was indeed an internal MCC command</returns> /// <returns>TRUE if the command was indeed an internal MCC command</returns>
public bool PerformInternalCommand(string command, ref string? response_msg, Dictionary<string, object>? localVars = null) public bool PerformInternalCommand(string command, ref CmdResult result, Dictionary<string, object>? localVars = null)
{ {
/* Process the provided command */ /* Process the provided command */
ParseResults<CommandSource> parse; ParseResults<CmdResult> parse;
try try
{ {
parse = dispatcher.Parse(command, cmd_source); parse = dispatcher.Parse(command, result);
} }
catch (Exception e) catch (Exception e)
{ {
Log.Error(e.GetFullMessage()); Log.Debug("Parse fail: " + e.GetFullMessage());
return true; return false;
} }
try try
{ {
int res = dispatcher.Execute(parse); dispatcher.Execute(parse);
Log.Info("res = " + res);
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; return true;
} }
catch (CommandSyntaxException e) catch (CommandSyntaxException e)
{ {
Log.Warn(e.GetFullMessage()); if (parse.Context.Nodes.Count == 0)
return true; {
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() public void LoadCommands()
@ -725,10 +676,6 @@ namespace MinecraftClient
{ {
Command cmd = (Command)Activator.CreateInstance(type)!; Command cmd = (Command)Activator.CreateInstance(type)!;
cmd.RegisterCommand(this, dispatcher); 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) catch (Exception e)
{ {
@ -863,7 +810,7 @@ namespace MinecraftClient
b.SetHandler(this); b.SetHandler(this);
bots.Add(b); bots.Add(b);
if (init) if (init)
DispatchBotEvent(bot => bot.Initialize(), new ChatBot[] { b }); DispatchBotEvent(bot => bot.Initialize(dispatcher), new ChatBot[] { b });
if (handler != null) if (handler != null)
DispatchBotEvent(bot => bot.AfterGameJoined(), new ChatBot[] { b }); DispatchBotEvent(bot => bot.AfterGameJoined(), new ChatBot[] { b });
} }
@ -879,8 +826,9 @@ namespace MinecraftClient
return; return;
} }
b.OnUnload(); b.OnUnload(dispatcher);
bots.RemoveAll(item => object.ReferenceEquals(item, b));
bots.RemoveAll(item => ReferenceEquals(item, b));
// ToList is needed to avoid an InvalidOperationException from modfiying the list while it's being iterated upon. // 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(); var botRegistrations = registeredBotPluginChannels.Where(entry => entry.Value.Contains(b)).ToList();
@ -2449,6 +2397,8 @@ namespace MinecraftClient
ClearInventories(); ClearInventories();
DispatchBotEvent(bot => bot.AfterGameJoined()); DispatchBotEvent(bot => bot.AfterGameJoined());
ConsoleIO.InitAutocomplete();
} }
/// <summary> /// <summary>
@ -3471,6 +3421,16 @@ namespace MinecraftClient
DispatchBotEvent(bot => bot.OnBlockChange(location, block)); DispatchBotEvent(bot => bot.OnBlockChange(location, block));
} }
/// <summary>
/// Called when "AutoComplete" completes.
/// </summary>
/// <param name="transactionId">The number of this result.</param>
/// <param name="result">All commands.</param>
public void OnAutoCompleteDone(int transactionId, string[] result)
{
ConsoleIO.OnAutoCompleteDone(transactionId, result);
}
/// <summary> /// <summary>
/// Send a click container button packet to the server. /// Send a click container button packet to the server.
/// Used for Enchanting table, Lectern, stone cutter and loom /// Used for Enchanting table, Lectern, stone cutter and loom

View file

@ -28,20 +28,21 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Brigadier.NET" Version="1.2.13" /> <PackageReference Include="Brigadier.NET" Version="1.2.13" />
<PackageReference Include="DnsClient" Version="1.6.1" /> <PackageReference Include="DnsClient" Version="1.7.0" />
<PackageReference Include="DotNetZip" Version="1.16.0" /> <PackageReference Include="DotNetZip" Version="1.16.0" />
<PackageReference Include="DSharpPlus" Version="4.2.0" /> <PackageReference Include="DSharpPlus" Version="4.2.0" />
<PackageReference Include="DynamicExpresso.Core" Version="2.13.0" /> <PackageReference Include="DynamicExpresso.Core" Version="2.13.0" />
<PackageReference Include="Magick.NET-Q16-AnyCPU" Version="12.2.0" /> <PackageReference Include="FuzzySharp" Version="2.0.2" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.1" /> <PackageReference Include="Magick.NET-Q16-AnyCPU" Version="12.2.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Windows.Compatibility" Version="6.0.0" /> <PackageReference Include="Microsoft.Windows.Compatibility" Version="7.0.0" />
<PackageReference Include="Samboy063.Tomlet" Version="5.0.0" /> <PackageReference Include="Samboy063.Tomlet" Version="5.0.1" />
<PackageReference Include="SingleFileExtractor.Core" Version="1.0.1" /> <PackageReference Include="SingleFileExtractor.Core" Version="1.0.1" />
<PackageReference Include="starksoft.aspen" Version="1.1.8"> <PackageReference Include="starksoft.aspen" Version="1.1.8">
<NoWarn>NU1701</NoWarn> <NoWarn>NU1701</NoWarn>
</PackageReference> </PackageReference>
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" />
<PackageReference Include="Telegram.Bot" Version="18.0.0" /> <PackageReference Include="Telegram.Bot" Version="18.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -14,8 +14,9 @@ using MinecraftClient.Mapping.BlockPalettes;
using MinecraftClient.Mapping.EntityPalettes; using MinecraftClient.Mapping.EntityPalettes;
using MinecraftClient.Protocol; using MinecraftClient.Protocol;
using MinecraftClient.Protocol.Handlers.Forge; using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Protocol.Keys; using MinecraftClient.Protocol.ProfileKey;
using MinecraftClient.Protocol.Session; using MinecraftClient.Protocol.Session;
using MinecraftClient.Scripting;
using MinecraftClient.WinAPI; using MinecraftClient.WinAPI;
using Tomlet; using Tomlet;
using static MinecraftClient.Settings; 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 //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)))) ((Config.Main.Advanced.EnableForge == ForgeConfigType.force) && !ProtocolHandler.ProtocolMayForceForge(protocolversion))))
{ {
if (protocolversion != 0) 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) && (InternalConfig.Account.Password != "-" || Config.Main.General.Method == LoginMethod.browser)
&& Config.Signature.LoginWithSecureProfile && Config.Signature.LoginWithSecureProfile
&& protocolversion >= 759 /* 1.19 and above */) && protocolversion >= 759 /* 1.19 and above */)
{ {
// Load cached profile key from disk if necessary // Load cached profile key from disk if necessary
@ -683,7 +684,7 @@ namespace MinecraftClient
/// </summary> /// </summary>
public static void ReloadSettings(bool keepAccountAndServerSettings = false) 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)); ConsoleIO.WriteLine(string.Format(Translations.config_load, settingsIniPath));
} }
@ -720,6 +721,7 @@ namespace MinecraftClient
public static void DoExit(int exitcode = 0) public static void DoExit(int exitcode = 0)
{ {
WriteBackSettings(true); WriteBackSettings(true);
ConsoleInteractive.ConsoleSuggestion.ClearSuggestions();
ConsoleIO.WriteLineFormatted(string.Format(Translations.config_saving, settingsIniPath)); ConsoleIO.WriteLineFormatted(string.Format(Translations.config_saving, settingsIniPath));
if (client != null) { client.Disconnect(); ConsoleIO.Reset(); } if (client != null) { client.Disconnect(); ConsoleIO.Reset(); }
@ -807,7 +809,7 @@ namespace MinecraftClient
if (command.StartsWith("reco")) 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 == "") if (message == "")
{ {
exitThread = true; exitThread = true;
@ -816,7 +818,7 @@ namespace MinecraftClient
} }
else if (command.StartsWith("connect")) 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 == "") if (message == "")
{ {
exitThread = true; exitThread = true;
@ -825,7 +827,7 @@ namespace MinecraftClient
} }
else if (command.StartsWith("exit") || command.StartsWith("quit")) 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")) else if (command.StartsWith("help"))
{ {
@ -844,7 +846,7 @@ namespace MinecraftClient
} }
else else
{ {
_ = new Commands.Exit().Run(null, Config.AppVar.ExpandVars(command), null); Commands.Exit.DoExit(Config.AppVar.ExpandVars(command));
} }
} }

View file

@ -54,7 +54,22 @@ namespace MinecraftClient.Protocol.Handlers.packet.s2c
Nodes[i] = new(flags, childs, redirectNode, name, paser, suggestionsType); 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<string> 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<Tuple<string, string>> CollectSignArguments(string command) public static List<Tuple<string, string>> CollectSignArguments(string command)
@ -113,7 +128,7 @@ namespace MinecraftClient.Protocol.Handlers.packet.s2c
public string? Name; public string? Name;
public Paser? Paser; public Paser? Paser;
public string? SuggestionsType; public string? SuggestionsType;
public CommandNode(byte Flags, public CommandNode(byte Flags,
int[] Clildren, int[] Clildren,

View file

@ -9,10 +9,11 @@ using System.Threading;
using MinecraftClient.Crypto; using MinecraftClient.Crypto;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Protocol.Keys;
using MinecraftClient.Protocol.Message; using MinecraftClient.Protocol.Message;
using MinecraftClient.Protocol.ProfileKey;
using MinecraftClient.Protocol.Session; using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy; using MinecraftClient.Proxy;
using MinecraftClient.Scripting;
using static MinecraftClient.Settings; using static MinecraftClient.Settings;
namespace MinecraftClient.Protocol.Handlers namespace MinecraftClient.Protocol.Handlers
@ -24,8 +25,6 @@ namespace MinecraftClient.Protocol.Handlers
class Protocol16Handler : IMinecraftCom class Protocol16Handler : IMinecraftCom
{ {
readonly IMinecraftComHandler handler; readonly IMinecraftComHandler handler;
private bool autocomplete_received = false;
private string autocomplete_result = "";
private bool encrypted = false; private bool encrypted = false;
private readonly int protocolversion; private readonly int protocolversion;
private Tuple<Thread, CancellationTokenSource>? netRead = null; private Tuple<Thread, CancellationTokenSource>? netRead = null;
@ -193,7 +192,14 @@ namespace MinecraftClient.Protocol.Handlers
if (online) { handler.OnPlayerJoin(new PlayerInfo(name, FakeUUID)); } else { handler.OnPlayerLeave(FakeUUID); } if (online) { handler.OnPlayerJoin(new PlayerInfo(name, FakeUUID)); } else { handler.OnPlayerLeave(FakeUUID); }
break; break;
case 0xCA: if (protocolversion >= 72) { ReadData(9); } else ReadData(3); 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 0xCC: ReadNextString(); ReadData(4); break;
case 0xCD: ReadData(1); break; case 0xCD: ReadData(1); break;
case 0xCE: if (protocolversion > 51) { ReadNextString(); ReadNextString(); 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; } catch (System.IO.IOException) { return false; }
} }
IEnumerable<string> IAutoComplete.AutoComplete(string BehindCursor) int IAutoComplete.AutoComplete(string BehindCursor)
{ {
if (String.IsNullOrEmpty(BehindCursor)) if (String.IsNullOrEmpty(BehindCursor))
return Array.Empty<string>(); return -1;
byte[] autocomplete = new byte[3 + (BehindCursor.Length * 2)]; byte[] autocomplete = new byte[3 + (BehindCursor.Length * 2)];
autocomplete[0] = 0xCB; autocomplete[0] = 0xCB;
byte[] msglen = BitConverter.GetBytes((short)BehindCursor.Length); 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); byte[] msg = Encoding.BigEndianUnicode.GetBytes(BehindCursor);
msg.CopyTo(autocomplete, 3); msg.CopyTo(autocomplete, 3);
ConsoleIO.AutoCompleteDone = false;
autocomplete_received = false;
autocomplete_result = BehindCursor;
Send(autocomplete); Send(autocomplete);
return 0;
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);
} }
private static byte[] ConcatBytes(params byte[][] bytes) private static byte[] ConcatBytes(params byte[][] bytes)

View file

@ -19,10 +19,11 @@ using MinecraftClient.Mapping.EntityPalettes;
using MinecraftClient.Protocol.Handlers.Forge; using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Protocol.Handlers.packet.s2c; using MinecraftClient.Protocol.Handlers.packet.s2c;
using MinecraftClient.Protocol.Handlers.PacketPalettes; using MinecraftClient.Protocol.Handlers.PacketPalettes;
using MinecraftClient.Protocol.Keys;
using MinecraftClient.Protocol.Message; using MinecraftClient.Protocol.Message;
using MinecraftClient.Protocol.ProfileKey;
using MinecraftClient.Protocol.Session; using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy; using MinecraftClient.Proxy;
using MinecraftClient.Scripting;
using static MinecraftClient.Settings; using static MinecraftClient.Settings;
namespace MinecraftClient.Protocol.Handlers namespace MinecraftClient.Protocol.Handlers
@ -64,9 +65,7 @@ namespace MinecraftClient.Protocol.Handlers
internal const int MC_1_19_2_Version = 760; internal const int MC_1_19_2_Version = 760;
private int compression_treshold = 0; private int compression_treshold = 0;
private bool autocomplete_received = false;
private int autocomplete_transaction_id = 0; private int autocomplete_transaction_id = 0;
private readonly List<string> autocomplete_result = new();
private readonly Dictionary<int, short> window_actions = new(); private readonly Dictionary<int, short> window_actions = new();
private bool login_phase = true; private bool login_phase = true;
private readonly int protocolVersion; private readonly int protocolVersion;
@ -1325,6 +1324,7 @@ namespace MinecraftClient.Protocol.Handlers
} }
break; break;
case PacketTypesIn.TabComplete: case PacketTypesIn.TabComplete:
int old_transaction_id = autocomplete_transaction_id;
if (protocolVersion >= MC_1_13_Version) if (protocolVersion >= MC_1_13_Version)
{ {
autocomplete_transaction_id = dataTypes.ReadNextVarInt(packetData); autocomplete_transaction_id = dataTypes.ReadNextVarInt(packetData);
@ -1333,20 +1333,19 @@ namespace MinecraftClient.Protocol.Handlers
} }
int autocomplete_count = dataTypes.ReadNextVarInt(packetData); int autocomplete_count = dataTypes.ReadNextVarInt(packetData);
autocomplete_result.Clear();
string[] autocomplete_result = new string[autocomplete_count];
for (int i = 0; i < autocomplete_count; i++) 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) 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)) if (dataTypes.ReadNextBool(packetData))
dataTypes.SkipNextString(packetData); dataTypes.SkipNextString(packetData);
} }
} }
handler.OnAutoCompleteDone(old_transaction_id, autocomplete_result);
autocomplete_received = true;
break; break;
case PacketTypesIn.PluginMessage: case PacketTypesIn.PluginMessage:
String channel = dataTypes.ReadNextString(packetData); String channel = dataTypes.ReadNextString(packetData);
@ -2110,18 +2109,10 @@ namespace MinecraftClient.Protocol.Handlers
/// </summary> /// </summary>
/// <param name="BehindCursor">Text behind cursor</param> /// <param name="BehindCursor">Text behind cursor</param>
/// <returns>Completed text</returns> /// <returns>Completed text</returns>
IEnumerable<string> IAutoComplete.AutoComplete(string BehindCursor) int IAutoComplete.AutoComplete(string BehindCursor)
{ {
var sug = McClient.dispatcher.GetCompletionSuggestions(McClient.dispatcher.Parse(BehindCursor[1..], McClient.cmd_source)); if (string.IsNullOrEmpty(BehindCursor))
sug.Wait(); return -1;
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<string>();
byte[] transaction_id = dataTypes.GetVarInt(autocomplete_transaction_id); byte[] transaction_id = dataTypes.GetVarInt(autocomplete_transaction_id);
byte[] assume_command = new byte[] { 0x00 }; byte[] assume_command = new byte[] { 0x00 };
@ -2134,16 +2125,14 @@ namespace MinecraftClient.Protocol.Handlers
if (protocolVersion >= MC_1_13_Version) if (protocolVersion >= MC_1_13_Version)
{ {
tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, transaction_id); 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 else
{ {
tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, dataTypes.GetString(BehindCursor)); tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, dataTypes.GetString(BehindCursor));
if (protocolVersion >= MC_1_9_Version) if (protocolVersion >= MC_1_9_Version)
{
tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, assume_command); tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, assume_command);
}
tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, has_position); tabcomplete_packet = dataTypes.ConcatBytes(tabcomplete_packet, has_position);
} }
@ -2152,22 +2141,9 @@ namespace MinecraftClient.Protocol.Handlers
{ {
tabcomplete_packet = dataTypes.ConcatBytes(dataTypes.GetString(BehindCursor)); tabcomplete_packet = dataTypes.ConcatBytes(dataTypes.GetString(BehindCursor));
} }
ConsoleIO.AutoCompleteDone = false;
autocomplete_received = false;
autocomplete_result.Clear();
autocomplete_result.Add(BehindCursor);
SendPacket(PacketTypesOut.TabComplete, tabcomplete_packet); SendPacket(PacketTypesOut.TabComplete, tabcomplete_packet);
return autocomplete_transaction_id;
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;
} }
/// <summary> /// <summary>

View file

@ -4,6 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using MinecraftClient.Protocol.Handlers.Forge; using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Protocol.Message;
using MinecraftClient.Scripting;
namespace MinecraftClient.Protocol.Handlers namespace MinecraftClient.Protocol.Handlers
{ {

View file

@ -2,7 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Protocol.Keys; using MinecraftClient.Protocol.ProfileKey;
namespace MinecraftClient.Protocol namespace MinecraftClient.Protocol
{ {

View file

@ -4,6 +4,7 @@ using MinecraftClient.Inventory;
using MinecraftClient.Logger; using MinecraftClient.Logger;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Protocol.Message; using MinecraftClient.Protocol.Message;
using MinecraftClient.Scripting;
namespace MinecraftClient.Protocol namespace MinecraftClient.Protocol
{ {
@ -456,6 +457,13 @@ namespace MinecraftClient.Protocol
/// <param name="block">The block</param> /// <param name="block">The block</param>
public void OnBlockChange(Location location, Block block); public void OnBlockChange(Location location, Block block);
/// <summary>
/// Called when "AutoComplete" completes.
/// </summary>
/// <param name="transactionId">The number of this result.</param>
/// <param name="result">All commands.</param>
public void OnAutoCompleteDone(int transactionId, string[] result);
/// <summary> /// <summary>
/// Send a click container button packet to the server. /// Send a click container button packet to the server.
/// Used for Enchanting table, Lectern, stone cutter and loom /// Used for Enchanting table, Lectern, stone cutter and loom

View file

@ -4,10 +4,9 @@ using System.IO;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using MinecraftClient.Protocol.Message;
using static MinecraftClient.Settings; using static MinecraftClient.Settings;
namespace MinecraftClient.Protocol namespace MinecraftClient.Protocol.Message
{ {
/// <summary> /// <summary>
/// This class parses JSON chat data from MC 1.6+ and returns the appropriate string to be printed. /// 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(); HttpClient httpClient = new();
try try
{ {
Task<string> fetch_index = httpClient.GetStringAsync(Settings.TranslationsFile_Website_Index); Task<string> fetch_index = httpClient.GetStringAsync(TranslationsFile_Website_Index);
fetch_index.Wait(); fetch_index.Wait();
string assets_index = fetch_index.Result; string assets_index = fetch_index.Result;
fetch_index.Dispose(); 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); 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); tmp = tmp[1].Split(new string[] { "hash\": \"" }, StringSplitOptions.None);
string hash = tmp[1].Split('"')[0]; //Translations file identifier on Mojang's servers string hash = tmp[1].Split('"')[0]; //Translations file identifier on Mojang's servers
string translation_file_location = Settings.TranslationsFile_Website_Download + '/' + hash[..2] + '/' + hash; string translation_file_location = TranslationsFile_Website_Download + '/' + hash[..2] + '/' + hash;
if (Settings.Config.Logging.DebugMessages) if (Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(string.Format(Translations.chat_request, translation_file_location)); ConsoleIO.WriteLineFormatted(string.Format(Translations.chat_request, translation_file_location));
Task<string> fetch_file = httpClient.GetStringAsync(translation_file_location); Task<string> fetch_file = httpClient.GetStringAsync(translation_file_location);
@ -242,7 +241,7 @@ namespace MinecraftClient.Protocol
StringBuilder stringBuilder = new(); StringBuilder stringBuilder = new();
foreach (KeyValuePair<string, Json.JSONData> entry in Json.ParseJson(translation_file).Properties) foreach (KeyValuePair<string, Json.JSONData> 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()); File.WriteAllText(Language_File, stringBuilder.ToString());
ConsoleIO.WriteLineFormatted(string.Format(Translations.chat_done, Language_File)); 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 //Download Failed? Defaulting to en_GB.lang if the game is installed
if (!File.Exists(Language_File) //Try en_GB.lang 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); 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); ConsoleIO.WriteLineFormatted(Translations.chat_loaded, acceptnewlines: true);
} }
else //No external dictionnary found. else //No external dictionnary found.

View file

@ -214,7 +214,7 @@ namespace MinecraftClient.Protocol
fetchTask.Dispose(); fetchTask.Dispose();
} }
catch (Exception) catch (Exception)
{ {
return new MojangServiceStatus(); return new MojangServiceStatus();
} }

Some files were not shown because too many files have changed in this diff Show more