From 4dc1b420f5b8797049cba6a3ac99985bcd44980b Mon Sep 17 00:00:00 2001 From: Milutinke Date: Wed, 12 Oct 2022 19:51:01 +0200 Subject: [PATCH] Added enchanting --- MinecraftClient/Commands/Enchant.cs | 50 ++++++ MinecraftClient/Inventory/Container.cs | 13 ++ .../Inventory/EnchantmentMapping.cs | 159 ++++++++++++++++++ .../Inventory/EnchantmentPropertyInfo.cs | 23 +++ MinecraftClient/Inventory/Enchantments.cs | 45 +++++ MinecraftClient/McClient.cs | 73 +++++++- .../Protocol/Handlers/Protocol16.cs | 5 + .../Protocol/Handlers/Protocol18.cs | 22 +++ MinecraftClient/Protocol/IMinecraftCom.cs | 10 ++ .../Protocol/IMinecraftComHandler.cs | 19 +++ MinecraftClient/Resources/lang/en.ini | 46 +++++ MinecraftClient/Scripting/ChatBot.cs | 10 ++ 12 files changed, 474 insertions(+), 1 deletion(-) create mode 100644 MinecraftClient/Commands/Enchant.cs create mode 100644 MinecraftClient/Inventory/EnchantmentMapping.cs create mode 100644 MinecraftClient/Inventory/EnchantmentPropertyInfo.cs create mode 100644 MinecraftClient/Inventory/Enchantments.cs diff --git a/MinecraftClient/Commands/Enchant.cs b/MinecraftClient/Commands/Enchant.cs new file mode 100644 index 00000000..1830b147 --- /dev/null +++ b/MinecraftClient/Commands/Enchant.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Globalization; +using MinecraftClient.Inventory; + +namespace MinecraftClient.Commands +{ + public class Enchant : Command + { + public override string CmdName { get { return "enchant"; } } + public override string CmdUsage { get { return "enchant "; } } + public override string CmdDesc { get { return "cmd.enchant.desc"; } } + + public override string Run(McClient handler, string command, Dictionary? localVars) + { + if (HasArg(command)) + { + string slot = GetArg(command).ToLower().Trim(); + + int slotId = slot switch + { + "top" => 0, + "middle" => 1, + "bottom" => 2, + _ => -1 + }; + + if (slotId == -1) + return Translations.TryGet("cmd.enchant.invalid_slot"); + + int containerId = -1; + + foreach (var (id, container) in handler.GetInventories()) + { + if (container.Type == ContainerType.Enchantment) + { + containerId = id; + break; + } + } + + if (containerId == -1) + return Translations.TryGet("cmd.enchant.enchanting_table_not_opened"); + + return handler.ClickContainerButton(containerId, slotId) ? Translations.TryGet("cmd.enchant.clicked") : Translations.TryGet("cmd.enchant.not_clicked"); + } + + return GetCmdDescTranslated(); + } + } +} diff --git a/MinecraftClient/Inventory/Container.cs b/MinecraftClient/Inventory/Container.cs index 35a438b3..f1201275 100644 --- a/MinecraftClient/Inventory/Container.cs +++ b/MinecraftClient/Inventory/Container.cs @@ -32,6 +32,13 @@ namespace MinecraftClient.Inventory /// public Dictionary Items; + /// + /// Container Properties + /// Used for Frunaces, Enchanting Table, Beacon, Brewing stand, Stone cutter, Loom and Lectern + /// More info about: https://wiki.vg/Protocol#Set_Container_Property + /// + public Dictionary Properties; + /// /// Create an empty container with ID, Type and Title /// @@ -44,6 +51,7 @@ namespace MinecraftClient.Inventory Type = type; Title = title; Items = new Dictionary(); + Properties = new Dictionary(); } /// @@ -59,6 +67,7 @@ namespace MinecraftClient.Inventory Type = type; Title = title; Items = items; + Properties = new Dictionary(); } /// @@ -73,6 +82,7 @@ namespace MinecraftClient.Inventory Title = title; Type = ConvertType.ToNew(type); Items = new Dictionary(); + Properties = new Dictionary(); } /// @@ -87,6 +97,7 @@ namespace MinecraftClient.Inventory Type = GetContainerType(typeID); Title = title; Items = new Dictionary(); + Properties = new Dictionary(); } /// @@ -99,6 +110,7 @@ namespace MinecraftClient.Inventory Type = type; Title = null; Items = new Dictionary(); + Properties = new Dictionary(); } /// @@ -112,6 +124,7 @@ namespace MinecraftClient.Inventory Type = type; Title = null; Items = items; + Properties = new Dictionary(); } /// diff --git a/MinecraftClient/Inventory/EnchantmentMapping.cs b/MinecraftClient/Inventory/EnchantmentMapping.cs new file mode 100644 index 00000000..4f18e72a --- /dev/null +++ b/MinecraftClient/Inventory/EnchantmentMapping.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using MinecraftClient.Protocol.Handlers; + +namespace MinecraftClient.Inventory +{ + public class EnchantmentMapping + { + // 1.14 - 1.15.2 + private static Dictionary enchantmentMappings114 = new Dictionary() + { + //id type + { 0, Enchantment.Protection }, + { 1, Enchantment.FireProtection }, + { 2, Enchantment.FeatherFalling }, + { 3, Enchantment.BlastProtection }, + { 4, Enchantment.ProjectileProtection }, + { 5, Enchantment.Respiration }, + { 6, Enchantment.AquaAffinity }, + { 7, Enchantment.Thorns }, + { 8, Enchantment.DepthStrieder }, + { 9, Enchantment.FrostWalker }, + { 10, Enchantment.BindingCurse }, + { 11, Enchantment.Sharpness }, + { 12, Enchantment.Smite }, + { 13, Enchantment.BaneOfArthropods }, + { 14, Enchantment.Knockback }, + { 15, Enchantment.FireAspect }, + { 16, Enchantment.Looting }, + { 17, Enchantment.Sweeping }, + { 18, Enchantment.Efficency }, + { 19, Enchantment.SilkTouch }, + { 20, Enchantment.Unbreaking }, + { 21, Enchantment.Fortune }, + { 22, Enchantment.Power }, + { 23, Enchantment.Punch }, + { 24, Enchantment.Flame }, + { 25, Enchantment.Infinity }, + { 26, Enchantment.LuckOfTheSea }, + { 27, Enchantment.Lure }, + { 28, Enchantment.Loyality }, + { 29, Enchantment.Impaling }, + { 30, Enchantment.Riptide }, + { 31, Enchantment.Channeling }, + { 32, Enchantment.Mending }, + { 33, Enchantment.VanishingCurse } + }; + + private static Dictionary enchantmentMappings116Plus = new Dictionary() + { + //id type + { 0, Enchantment.Protection }, + { 1, Enchantment.FireProtection }, + { 2, Enchantment.FeatherFalling }, + { 3, Enchantment.BlastProtection }, + { 4, Enchantment.ProjectileProtection }, + { 5, Enchantment.Respiration }, + { 6, Enchantment.AquaAffinity }, + { 7, Enchantment.Thorns }, + { 8, Enchantment.DepthStrieder }, + { 9, Enchantment.FrostWalker }, + { 10, Enchantment.BindingCurse }, + { 11, Enchantment.SoulSpeed }, + { 12, Enchantment.Sharpness }, + { 13, Enchantment.Smite }, + { 14, Enchantment.BaneOfArthropods }, + { 15, Enchantment.Knockback }, + { 16, Enchantment.FireAspect }, + { 17, Enchantment.Looting }, + { 18, Enchantment.Sweeping }, + { 19, Enchantment.Efficency }, + { 20, Enchantment.SilkTouch }, + { 21, Enchantment.Unbreaking }, + { 22, Enchantment.Fortune }, + { 23, Enchantment.Power }, + { 24, Enchantment.Punch }, + { 25, Enchantment.Flame }, + { 26, Enchantment.Infinity }, + { 27, Enchantment.LuckOfTheSea }, + { 28, Enchantment.Lure }, + { 29, Enchantment.Loyality }, + { 30, Enchantment.Impaling }, + { 31, Enchantment.Riptide }, + { 32, Enchantment.Channeling }, + { 33, Enchantment.Multishot }, + { 34, Enchantment.QuickCharge }, + { 35, Enchantment.Piercing }, + { 36, Enchantment.Mending }, + { 37, Enchantment.VanishingCurse } + }; + + private static Dictionary enchantmentNames = new Dictionary() + { + //type + { Enchantment.Protection, "Enchantment.Protection" } , + { Enchantment.FireProtection, "Enchantment.FireProtection" }, + { Enchantment.FeatherFalling, "Enchantment.FeatherFalling" }, + { Enchantment.BlastProtection, "Enchantment.BlastProtection" }, + { Enchantment.ProjectileProtection, "Enchantment.ProjectileProtection" }, + { Enchantment.Respiration, "Enchantment.Respiration" }, + { Enchantment.AquaAffinity, "Enchantment.AquaAffinity" }, + { Enchantment.Thorns, "Enchantment.Thorns" }, + { Enchantment.DepthStrieder, "Enchantment.DepthStrieder" }, + { Enchantment.FrostWalker, "Enchantment.FrostWalker" }, + { Enchantment.BindingCurse, "Enchantment.BindingCurse" }, + { Enchantment.SoulSpeed, "Enchantment.SoulSpeed" }, + { Enchantment.Sharpness, "Enchantment.Sharpness" }, + { Enchantment.Smite, "Enchantment.Smite" }, + { Enchantment.BaneOfArthropods, "Enchantment.BaneOfArthropods" }, + { Enchantment.Knockback, "Enchantment.Knockback" }, + { Enchantment.FireAspect, "Enchantment.FireAspect" }, + { Enchantment.Looting, "Enchantment.Looting" }, + { Enchantment.Sweeping, "Enchantment.Sweeping" }, + { Enchantment.Efficency, "Enchantment.Efficency" }, + { Enchantment.SilkTouch, "Enchantment.SilkTouch" }, + { Enchantment.Unbreaking, "Enchantment.Unbreaking" }, + { Enchantment.Fortune, "Enchantment.Fortune" }, + { Enchantment.Power, "Enchantment.Power" }, + { Enchantment.Punch, "Enchantment.Punch" }, + { Enchantment.Flame, "Enchantment.Flame" }, + { Enchantment.Infinity, "Enchantment.Infinity" }, + { Enchantment.LuckOfTheSea, "Enchantment.LuckOfTheSea" }, + { Enchantment.Lure, "Enchantment.Lure" }, + { Enchantment.Loyality, "Enchantment.Loyality" }, + { Enchantment.Impaling, "Enchantment.Impaling" }, + { Enchantment.Riptide, "Enchantment.Riptide" }, + { Enchantment.Channeling, "Enchantment.Channeling" }, + { Enchantment.Multishot, "Enchantment.Multishot" }, + { Enchantment.QuickCharge, "Enchantment.QuickCharge" }, + { Enchantment.Piercing, "Enchantment.Piercing" }, + { Enchantment.Mending, "Enchantment.Mending" }, + { Enchantment.VanishingCurse, "Enchantment.VanishingCurse" } + }; + + public static Enchantment GetEnchantmentById(int protocolVersion, short id) + { + if (protocolVersion < Protocol18Handler.MC_1_14_Version) + throw new Exception("Enchantments mappings are not implemented bellow 1.14"); + + Dictionary map = enchantmentMappings116Plus; + + if (protocolVersion >= Protocol18Handler.MC_1_14_Version && protocolVersion < Protocol18Handler.MC_1_16_Version) + map = enchantmentMappings114; + + if (!map.ContainsKey(id)) + throw new Exception("Got an Unknown Enchantment ID '" + id + "', please update the Mappings!"); + + return map[id]; + } + + public static string GetEnchantmentName(Enchantment enchantment) + { + if (!enchantmentNames.ContainsKey(enchantment)) + return "Unknown Enchantment with ID: " + ((int)enchantment) + " (Probably not named in the code yet)"; + + return Translations.TryGet(enchantmentNames[enchantment]); + } + } +} diff --git a/MinecraftClient/Inventory/EnchantmentPropertyInfo.cs b/MinecraftClient/Inventory/EnchantmentPropertyInfo.cs new file mode 100644 index 00000000..20c93d94 --- /dev/null +++ b/MinecraftClient/Inventory/EnchantmentPropertyInfo.cs @@ -0,0 +1,23 @@ +namespace MinecraftClient.Inventory +{ + public enum EnchantmentPropertyInfo + { + // Levels that are required to enchant an item + TopEnchantmentLevelRequirement = 0, + MiddleEnchantmentLevelRequirement, + BottomEnchantmentLevelRequirement, + + // Seed + EnchantmentSeed, + + // Enchantment ids + TopEnchantmentId, + MiddleEnchantmentId, + BottomEnchantmentId, + + // Shown on mouse hover over the top, middle and bottom slot + TopEnchantmentLevel, + MiddleEnchantmentLevel, + BottomEnchantmentLevel + } +} diff --git a/MinecraftClient/Inventory/Enchantments.cs b/MinecraftClient/Inventory/Enchantments.cs new file mode 100644 index 00000000..10baf22d --- /dev/null +++ b/MinecraftClient/Inventory/Enchantments.cs @@ -0,0 +1,45 @@ +namespace MinecraftClient.Inventory +{ + // Not implemented for 1.14 + public enum Enchantment : short + { + Protection = 0, + FireProtection, + FeatherFalling, + BlastProtection, + ProjectileProtection, + Respiration, + AquaAffinity, + Thorns, + DepthStrieder, + FrostWalker, + BindingCurse, + SoulSpeed, + Sharpness, + Smite, + BaneOfArthropods, + Knockback, + FireAspect, + Looting, + Sweeping, + Efficency, + SilkTouch, + Unbreaking, + Fortune, + Power, + Punch, + Flame, + Infinity, + LuckOfTheSea, + Lure, + Loyality, + Impaling, + Riptide, + Channeling, + Multishot, + QuickCharge, + Piercing, + Mending, + VanishingCurse + } +} diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index c70ecb5c..61060ecb 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -223,7 +223,7 @@ namespace MinecraftClient return; - Retry: + Retry: if (timeoutdetector != null) { timeoutdetector.Item2.Cancel(); @@ -2650,6 +2650,64 @@ namespace MinecraftClient } } + /// + /// When received window properties from server. + /// Used for Frunaces, Enchanting Table, Beacon, Brewing stand, Stone cutter, Loom and Lectern + /// More info about: https://wiki.vg/Protocol#Set_Container_Property + /// + /// Inventory ID + /// Property ID + /// Property Value + public void OnWindowProperties(byte inventoryID, short propertyId, short propertyValue) + { + if (!inventories.ContainsKey(inventoryID)) + return; + + Container inventory = inventories[inventoryID]; + + //Log.Info("Got a property " + propertyId + " with value: " + propertyValue); + + if (inventory.Properties.ContainsKey(propertyId)) + inventory.Properties.Remove(propertyId); + + inventory.Properties.Add(propertyId, propertyValue); + + DispatchBotEvent(bot => bot.OnInventoryProperties(inventoryID, propertyId, propertyValue)); + + if (inventory.Type == ContainerType.Enchantment) + { + // We got the last property for enchantment + if ((int)propertyId == (int)EnchantmentPropertyInfo.BottomEnchantmentLevel && propertyValue != -1) + { + short topEnchantmentLevelRequirement = inventory.Properties[(int)EnchantmentPropertyInfo.TopEnchantmentLevelRequirement]; + short middleEnchantmentLevelRequirement = inventory.Properties[(int)EnchantmentPropertyInfo.MiddleEnchantmentLevelRequirement]; + short bottomEnchantmentLevelRequirement = inventory.Properties[(int)EnchantmentPropertyInfo.BottomEnchantmentLevelRequirement]; + + short enchantmentSeed = inventory.Properties[(int)EnchantmentPropertyInfo.EnchantmentSeed]; + + Enchantment topEnchantment = EnchantmentMapping.GetEnchantmentById( + GetProtocolVersion(), + inventory.Properties[(int)EnchantmentPropertyInfo.TopEnchantmentId]); + + Enchantment middleEnchantment = EnchantmentMapping.GetEnchantmentById( + GetProtocolVersion(), + inventory.Properties[(int)EnchantmentPropertyInfo.MiddleEnchantmentId]); + + Enchantment bottomEnchantment = EnchantmentMapping.GetEnchantmentById( + GetProtocolVersion(), + inventory.Properties[(int)EnchantmentPropertyInfo.BottomEnchantmentId]); + + short topEnchantmentLevel = inventory.Properties[(int)EnchantmentPropertyInfo.TopEnchantmentId]; + short middleEnchantmentLevel = inventory.Properties[(int)EnchantmentPropertyInfo.MiddleEnchantmentId]; + short bottomEnchantmentLevel = inventory.Properties[(int)EnchantmentPropertyInfo.BottomEnchantmentId]; + + Log.Info(EnchantmentMapping.GetEnchantmentName(topEnchantment) + " " + topEnchantmentLevel + " > " + topEnchantmentLevelRequirement + " Levels"); + Log.Info(EnchantmentMapping.GetEnchantmentName(middleEnchantment) + " " + middleEnchantmentLevel + " > " + middleEnchantmentLevelRequirement + " Levels"); + Log.Info(EnchantmentMapping.GetEnchantmentName(bottomEnchantment) + " " + bottomEnchantmentLevel + " > " + bottomEnchantmentLevelRequirement + " Levels"); + } + } + } + /// /// When received window items from server. /// @@ -3304,6 +3362,19 @@ namespace MinecraftClient DispatchBotEvent(bot => bot.OnBlockChange(location, block)); } + /// + /// Send a click container button packet to the server. + /// Used for Enchanting table, Lectern, stone cutter and loom + /// + /// Id of the window being clicked + /// Id of the clicked button + /// True if packet was successfully sent + + public bool ClickContainerButton(int windowId, int buttonId) + { + return handler.ClickContainerButton(windowId, buttonId); + } + #endregion } } diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index a84b61ea..d3577358 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -770,6 +770,11 @@ namespace MinecraftClient.Protocol.Handlers return false; //Currently not implemented } + public bool ClickContainerButton(int windowId, int buttonId) + { + return false; //Currently not implemented + } + public bool SendCloseWindow(int windowId) { return false; //Currently not implemented diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 5b00b26e..f1f6298e 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -1364,6 +1364,13 @@ namespace MinecraftClient.Protocol.Handlers handler.OnWindowItems(windowId, inventorySlots, stateId); } break; + case PacketTypesIn.WindowProperty: + byte containerId = dataTypes.ReadNextByte(packetData); + short propertyId = dataTypes.ReadNextShort(packetData); + short propertyValue = dataTypes.ReadNextShort(packetData); + + handler.OnWindowProperties(containerId, propertyId, propertyValue); + break; case PacketTypesIn.SetSlot: if (handler.GetInventoryEnabled()) { @@ -2866,6 +2873,21 @@ namespace MinecraftClient.Protocol.Handlers catch (ObjectDisposedException) { return false; } } + public bool ClickContainerButton(int windowId, int buttonId) + { + try + { + List packet = new(); + packet.Add((byte)windowId); + packet.Add((byte)buttonId); + SendPacket(PacketTypesOut.ClickWindowButton, packet); + return true; + } + catch (SocketException) { return false; } + catch (System.IO.IOException) { return false; } + catch (ObjectDisposedException) { return false; } + } + public bool SendAnimation(int animation, int playerid) { try diff --git a/MinecraftClient/Protocol/IMinecraftCom.cs b/MinecraftClient/Protocol/IMinecraftCom.cs index a78383ff..afe5b1ba 100644 --- a/MinecraftClient/Protocol/IMinecraftCom.cs +++ b/MinecraftClient/Protocol/IMinecraftCom.cs @@ -179,6 +179,16 @@ namespace MinecraftClient.Protocol /// TRUE if item given successfully bool SendCreativeInventoryAction(int slot, ItemType itemType, int count, Dictionary? nbt); + /// + /// Send a click container button packet to the server. + /// Used for Enchanting table, Lectern, stone cutter and loom + /// + /// Id of the window being clicked + /// Id of the clicked button + /// True if packet was successfully sent + + bool ClickContainerButton(int windowId, int buttonId); + /// /// Plays animation /// diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs index 089fe342..de3a6ede 100644 --- a/MinecraftClient/Protocol/IMinecraftComHandler.cs +++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs @@ -280,6 +280,15 @@ namespace MinecraftClient.Protocol /// Time of Day void OnTimeUpdate(long worldAge, long timeOfDay); + /// + /// When received window properties from server. + /// + /// + /// Inventory ID + /// Property ID + /// Property Value + public void OnWindowProperties(byte inventoryID, short propertyId, short propertyValue); + /// /// Called when inventory items have been received /// @@ -439,5 +448,15 @@ namespace MinecraftClient.Protocol /// The location of the block. /// The block public void OnBlockChange(Location location, Block block); + + /// + /// Send a click container button packet to the server. + /// Used for Enchanting table, Lectern, stone cutter and loom + /// + /// Id of the window being clicked + /// Id of the clicked button + /// True if packet was successfully sent + + bool ClickContainerButton(int windowId, int buttonId); } } diff --git a/MinecraftClient/Resources/lang/en.ini b/MinecraftClient/Resources/lang/en.ini index 97fece71..223919e8 100644 --- a/MinecraftClient/Resources/lang/en.ini +++ b/MinecraftClient/Resources/lang/en.ini @@ -152,6 +152,45 @@ extra.inventory_close=Inventory # {0} closed. extra.entity_disabled=§cEntities are currently not handled for that MC version. extra.entity_required=Please enable EntityHandling in the config file first. +# Enchantments +Enchantment.Protection=Protection +Enchantment.FireProtection=Fire Protection +Enchantment.FeatherFalling=Feather Falling +Enchantment.BlastProtection=Blast Protection +Enchantment.ProjectileProtection=Projectile Protection +Enchantment.Respiration=Respiration +Enchantment.AquaAffinity=Aqua Affinity +Enchantment.Thorns=Thorns +Enchantment.DepthStrieder=Depth Strieder +Enchantment.FrostWalker=Frost Walker +Enchantment.BindingCurse=Curse of Binding +Enchantment.SoulSpeed=Soul Speed +Enchantment.Sharpness=Sharpness +Enchantment.Smite=Smite +Enchantment.BaneOfArthropods=Bane of Arthropods +Enchantment.Knockback=Knockback +Enchantment.FireAspect=Fire Aspect +Enchantment.Looting=Looting +Enchantment.Sweeping=Sweeping +Enchantment.Efficency=Efficency +Enchantment.SilkTouch=Silk Touch +Enchantment.Unbreaking=Unbreaking +Enchantment.Fortune=Fortune +Enchantment.Power=Power +Enchantment.Punch=Punch +Enchantment.Flame=Flame +Enchantment.Infinity=Infinity +Enchantment.LuckOfTheSea=Luck of the Sea +Enchantment.Lure=Lure +Enchantment.Loyality=Loyality +Enchantment.Impaling=Impaling +Enchantment.Riptide=Riptide +Enchantment.Channeling=Channeling +Enchantment.Multishot=Multishot +Enchantment.QuickCharge=Quick Charge +Enchantment.Piercing=Piercing +Enchantment.Mending=Mending +Enchantment.VanishingCurse=Curse of Vanishing [forge] # Messages from Forge handler @@ -263,6 +302,13 @@ cmd.dig.no_block=No block at this location (Air) cmd.dig.dig=Attempting to dig block at {0} {1} {2} ({3}) cmd.dig.fail=Failed to start digging block. +# Enchantment Command + +cmd.enchant.invalid_slot=Invalid slot provided (Available: top, middle, bottom)! +cmd.enchant.enchanting_table_not_opened=You must open a an enchanting table in order to use this option! +cmd.enchant.clicked=Sent a click to the server, if you have enough levels and if you have placed the items in the correct slots it should enchant! +cmd.enchant.not_clicked=Could not click! + # Entitycmd cmd.entityCmd.attacked=Entity attacked cmd.entityCmd.used=Entity used diff --git a/MinecraftClient/Scripting/ChatBot.cs b/MinecraftClient/Scripting/ChatBot.cs index 7730d274..45e976f1 100644 --- a/MinecraftClient/Scripting/ChatBot.cs +++ b/MinecraftClient/Scripting/ChatBot.cs @@ -358,6 +358,16 @@ namespace MinecraftClient /// public virtual void OnInventoryClose(int inventoryId) { } + /// + /// When received inventory/container/window properties from the server. + /// Used for Frunaces, Enchanting Table, Beacon, Brewing stand, Stone cutter, Loom and Lectern + /// More info about: https://wiki.vg/Protocol#Set_Container_Property + /// + /// Inventory ID + /// Property ID + /// Property Value + public virtual void OnInventoryProperties(byte inventoryID, short propertyId, short propertyValue) { } + /// /// Called when a player joined the game ///