diff --git a/MinecraftClient/Commands/NameItem.cs b/MinecraftClient/Commands/NameItem.cs new file mode 100644 index 00000000..7c07dc38 --- /dev/null +++ b/MinecraftClient/Commands/NameItem.cs @@ -0,0 +1,63 @@ +using System.Linq; +using Brigadier.NET; +using Brigadier.NET.Builder; +using MinecraftClient.CommandHandler; +using MinecraftClient.Inventory; + +namespace MinecraftClient.Commands +{ + public class NameItem : Command + { + public override string CmdName => "nameitem"; + public override string CmdUsage => "nameitem "; + + public override string CmdDesc => Translations.cmd_nameitem_desc; + + public override void RegisterCommand(CommandDispatcher dispatcher) + { + dispatcher.Register(l => l.Literal("help") + .Then(l => l.Literal(CmdName) + .Executes(r => GetUsage(r.Source, string.Empty)) + ) + ); + + dispatcher.Register(l => l.Literal(CmdName) + .Then(l => l.Argument("any", Arguments.GreedyString()) + .Executes(r => DoSetItemName(r.Source, Arguments.GetString(r, "any")))) + ); + } + + 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 DoSetItemName(CmdResult r, string itemName) + { + var handler = CmdResult.currentHandler!; + + if (itemName.Trim().Length == 0) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_nameitem_item_name_empty); + + var currentInventory = handler.GetInventories().Count == 0 + ? null + : handler.GetInventories().Values.ToList().Last(); + + if (currentInventory is not { Type: ContainerType.Anvil }) + return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_nameitem_no_anvil_inventory_open); + + if (currentInventory.Items[0].IsEmpty) + return r.SetAndReturn(CmdResult.Status.Fail, + Translations.cmd_nameitem_first_slot_empty); + + return handler.SendRenameItem(itemName) + ? r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_nameitem_successful) + : r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_nameitem_failed); + } + } +} \ No newline at end of file diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index a970faea..808d8a79 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -2390,6 +2390,21 @@ namespace MinecraftClient return false; } } + + /// + /// Send the server a command to type in the item name in the Anvil inventory when it's open. + /// + /// The new item name + public bool SendRenameItem(string itemName) + { + if (inventories.Count == 0) + return false; + + if (inventories.Values.ToList().Last().Type != ContainerType.Anvil) + return false; + + return handler.SendRenameItem(itemName); + } #endregion #region Event handlers: An event occurs on the Server diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index b2e73863..884f4495 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -909,6 +909,11 @@ namespace MinecraftClient.Protocol.Handlers { return false; //Currently not implemented } + + public bool SendRenameItem(string itemName) + { + return false; + } public bool SendPlayerSession(PlayerKeyPair? playerKeyPair) { diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 3af50e55..623273e1 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -4150,6 +4150,29 @@ namespace MinecraftClient.Protocol.Handlers } } + public bool SendRenameItem(string itemName) + { + try + { + List packet = new(); + packet.AddRange(dataTypes.GetString(itemName.Length > 50 ? itemName[..50] : itemName)); + SendPacket(PacketTypesOut.NameItem, packet); + return true; + } + catch (SocketException) + { + return false; + } + catch (System.IO.IOException) + { + return false; + } + catch (ObjectDisposedException) + { + return false; + } + } + private byte[] GenerateSalt() { byte[] salt = new byte[8]; diff --git a/MinecraftClient/Protocol/IMinecraftCom.cs b/MinecraftClient/Protocol/IMinecraftCom.cs index 97ad8ca1..e8135452 100644 --- a/MinecraftClient/Protocol/IMinecraftCom.cs +++ b/MinecraftClient/Protocol/IMinecraftCom.cs @@ -260,6 +260,12 @@ namespace MinecraftClient.Protocol /// /// bool SendPlayerSession(PlayerKeyPair? playerKeyPair); + + /// + /// Send the server a command to type in the item name in the Anvil inventory when it's open. + /// + /// The new item name + bool SendRenameItem(string itemName); /// /// Get net read thread (main thread) ID diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs index 58636d1c..25b8ad15 100644 --- a/MinecraftClient/Protocol/IMinecraftComHandler.cs +++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs @@ -477,5 +477,13 @@ namespace MinecraftClient.Protocol /// True if packet was successfully sent bool ClickContainerButton(int windowId, int buttonId); + + /// + /// Send a rename item packet when the anvil inventory is open and there is an item in the first slot + /// + /// New name (max 50 characters) + /// True if packet was successfully sent + + bool SendRenameItem(string itemName); } } diff --git a/MinecraftClient/Resources/Translations/Translations.Designer.cs b/MinecraftClient/Resources/Translations/Translations.Designer.cs index 94768050..f7db2aaf 100644 --- a/MinecraftClient/Resources/Translations/Translations.Designer.cs +++ b/MinecraftClient/Resources/Translations/Translations.Designer.cs @@ -3854,5 +3854,41 @@ namespace MinecraftClient { return ResourceManager.GetString("cmd.items.collector.stopped", resourceCulture); } } + + internal static string cmd_nameitem_item_name_empty { + get { + return ResourceManager.GetString("cmd.nameitem.item.name.empty", resourceCulture); + } + } + + internal static string cmd_nameitem_no_anvil_inventory_open { + get { + return ResourceManager.GetString("cmd.nameitem.no.anvil.inventory.open", resourceCulture); + } + } + + internal static string cmd_nameitem_first_slot_empty { + get { + return ResourceManager.GetString("cmd.nameitem.first.slot.empty", resourceCulture); + } + } + + internal static string cmd_nameitem_failed { + get { + return ResourceManager.GetString("cmd.nameitem.failed", resourceCulture); + } + } + + internal static string cmd_nameitem_successful { + get { + return ResourceManager.GetString("cmd.nameitem.successful", resourceCulture); + } + } + + internal static string cmd_nameitem_desc { + get { + return ResourceManager.GetString("cmd.nameitem.desc", resourceCulture); + } + } } } diff --git a/MinecraftClient/Resources/Translations/Translations.resx b/MinecraftClient/Resources/Translations/Translations.resx index db1a75f7..5c758164 100644 --- a/MinecraftClient/Resources/Translations/Translations.resx +++ b/MinecraftClient/Resources/Translations/Translations.resx @@ -2058,4 +2058,22 @@ Logging in... Stopped collecting items. + + The item name cannot be empty! + + + You need to have an Anvil inventory opened and active in order to use this command! + + + You need to place an item in the first slot (slot id: 0) of the Anvil inventory! + + + Failed to send the packet for naming an item, try agian! + + + Succesfully sent the item name to the server, you can now clikc on the slot number 2 in the Anvil inventory to rename the item. + + + Set an item name when an Anvil inventory is active and the item is in the first slot. + \ No newline at end of file