From 4dc1b420f5b8797049cba6a3ac99985bcd44980b Mon Sep 17 00:00:00 2001 From: Milutinke Date: Wed, 12 Oct 2022 19:51:01 +0200 Subject: [PATCH 1/3] 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 /// From c47add39a4b69e89d730474c4d2168dd41ef38e3 Mon Sep 17 00:00:00 2001 From: Milutinke Date: Fri, 14 Oct 2022 15:33:33 +0200 Subject: [PATCH 2/3] Added Enchanting Table ASCII Art. Added ChatBot method for enchantments. Changed the how the list of enchantments looks, now looks cleaner + has Roman numbers. Added safe guards to the echant command. --- MinecraftClient/Commands/Enchant.cs | 25 ++- .../DefaultConfigResource.Designer.cs | 176 +++++++++++------- MinecraftClient/DefaultConfigResource.resx | 3 + .../Inventory/ContainerTypeExtensions.cs | 2 +- .../Inventory/EnchantmentMapping.cs | 37 +++- MinecraftClient/McClient.cs | 66 +++++-- .../ContainerType.EnchantingTable.txt | 22 +++ MinecraftClient/Resources/lang/en.ini | 8 + MinecraftClient/Scripting/ChatBot.cs | 26 +++ 9 files changed, 277 insertions(+), 88 deletions(-) create mode 100644 MinecraftClient/Resources/containers/ContainerType.EnchantingTable.txt diff --git a/MinecraftClient/Commands/Enchant.cs b/MinecraftClient/Commands/Enchant.cs index 1830b147..db7a9f18 100644 --- a/MinecraftClient/Commands/Enchant.cs +++ b/MinecraftClient/Commands/Enchant.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Globalization; +using System.Linq; using MinecraftClient.Inventory; namespace MinecraftClient.Commands @@ -27,21 +28,37 @@ namespace MinecraftClient.Commands if (slotId == -1) return Translations.TryGet("cmd.enchant.invalid_slot"); - int containerId = -1; + Container? enchantingTable = null; foreach (var (id, container) in handler.GetInventories()) { if (container.Type == ContainerType.Enchantment) { - containerId = id; + enchantingTable = container; break; } } - if (containerId == -1) + if (enchantingTable == null) 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"); + int[] emptySlots = enchantingTable.GetEmpytSlots(); + + if (emptySlots.Contains(0)) + return Translations.TryGet("cmd.enchant.enchanting_no_item"); + + if (emptySlots.Contains(1)) + return Translations.TryGet("cmd.enchant.enchanting_no_lapis"); + + Item lapisSlot = enchantingTable.Items[1]; + + if (lapisSlot.Type != ItemType.LapisLazuli) + return Translations.TryGet("cmd.enchant.enchanting_no_lapis"); + + if (lapisSlot.Count < 3) + return Translations.TryGet("cmd.enchant.enchanting_no_lapis"); + + return handler.ClickContainerButton(enchantingTable.ID, slotId) ? Translations.TryGet("cmd.enchant.clicked") : Translations.TryGet("cmd.enchant.not_clicked"); } return GetCmdDescTranslated(); diff --git a/MinecraftClient/DefaultConfigResource.Designer.cs b/MinecraftClient/DefaultConfigResource.Designer.cs index cb31f5aa..f7ec6226 100644 --- a/MinecraftClient/DefaultConfigResource.Designer.cs +++ b/MinecraftClient/DefaultConfigResource.Designer.cs @@ -8,10 +8,11 @@ // //------------------------------------------------------------------------------ -namespace MinecraftClient { +namespace MinecraftClient +{ using System; - - + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -22,44 +23,52 @@ namespace MinecraftClient { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class DefaultConfigResource { - + internal class DefaultConfigResource + { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal DefaultConfigResource() { + internal DefaultConfigResource() + { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if (object.ReferenceEquals(resourceMan, null)) + { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MinecraftClient.DefaultConfigResource", typeof(DefaultConfigResource).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { + internal static global::System.Globalization.CultureInfo Culture + { + get + { return resourceCulture; } - set { + set + { resourceCulture = value; } } - + /// /// Looks up a localized string similar to ╔═════════════════════════════════════╗ ///║ Brewing Stand ║ @@ -75,12 +84,14 @@ namespace MinecraftClient { ///║║ 5 ║ 6 ║ 7 ║ 8 ║ 9 ║10 ║11 ║12 ║13 ║║ ///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]";. /// - internal static string ContainerType_BrewingStand { - get { + internal static string ContainerType_BrewingStand + { + get + { return ResourceManager.GetString("ContainerType_BrewingStand", resourceCulture); } } - + /// /// Looks up a localized string similar to ╔═════════════════════════════════════╗ ///║ Crafting ║ @@ -96,12 +107,21 @@ namespace MinecraftClient { ///║║10 ║11 ║12 ║13 ║14 ║15 ║16 ║17 ║18 ║║ ///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]";. /// - internal static string ContainerType_Crafting { - get { + internal static string ContainerType_Crafting + { + get + { return ResourceManager.GetString("ContainerType_Crafting", resourceCulture); } } - + internal static string ContainerType_EnchantingTable + { + get + { + return ResourceManager.GetString("ContainerType_EnchantingTable", resourceCulture); + } + } + /// /// Looks up a localized string similar to ╔═════════════════════════════════════╗ ///║ Container ║ @@ -117,12 +137,14 @@ namespace MinecraftClient { ///║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║ ///║║ 3 ║ 4 ║ 5 ║ 6 ║ 7 [rest of string was truncated]";. /// - internal static string ContainerType_Furnace { - get { + internal static string ContainerType_Furnace + { + get + { return ResourceManager.GetString("ContainerType_Furnace", resourceCulture); } } - + /// /// Looks up a localized string similar to ╔═════════════════════════════════════╗ ///║ Container ║ @@ -138,12 +160,14 @@ namespace MinecraftClient { ///║║ 9 ║10 ║11 ║12 ║13 ║14 ║15 ║16 ║17 ║║ ///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]";. /// - internal static string ContainerType_Generic_3x3 { - get { + internal static string ContainerType_Generic_3x3 + { + get + { return ResourceManager.GetString("ContainerType_Generic_3x3", resourceCulture); } } - + /// /// Looks up a localized string similar to ╔═════════════════════════════════════╗ ///║ Container ║ @@ -159,12 +183,14 @@ namespace MinecraftClient { ///║║27 ║28 ║29 ║30 ║31 ║32 ║33 ║34 ║35 ║║ ///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]";. /// - internal static string ContainerType_Generic_9x3 { - get { + internal static string ContainerType_Generic_9x3 + { + get + { return ResourceManager.GetString("ContainerType_Generic_9x3", resourceCulture); } } - + /// /// Looks up a localized string similar to ╔═════════════════════════════════════╗ ///║ Container ║ @@ -180,12 +206,14 @@ namespace MinecraftClient { ///║║36 ║37 ║38 ║39 ║40 ║41 ║42 ║43 ║44 ║║ ///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]";. /// - internal static string ContainerType_Generic_9x6 { - get { + internal static string ContainerType_Generic_9x6 + { + get + { return ResourceManager.GetString("ContainerType_Generic_9x6", resourceCulture); } } - + /// /// Looks up a localized string similar to ╔═════════════════════════════════════╗ ///║ Repair & Disenchant ║ @@ -201,12 +229,14 @@ namespace MinecraftClient { ///║ ╚══╝ ╚══╝ ║ ///║ [rest of string was truncated]";. /// - internal static string ContainerType_Grindstone { - get { + internal static string ContainerType_Grindstone + { + get + { return ResourceManager.GetString("ContainerType_Grindstone", resourceCulture); } } - + /// /// Looks up a localized string similar to ╔═════════════════════════════════════╗ ///║ Container ║ @@ -222,12 +252,14 @@ namespace MinecraftClient { ///║║23 ║24 ║25 ║26 ║27 ║28 ║29 ║30 ║31 ║║ ///║╚═══╩═══╩═══╩═══╩══ [rest of string was truncated]";. /// - internal static string ContainerType_Hopper { - get { + internal static string ContainerType_Hopper + { + get + { return ResourceManager.GetString("ContainerType_Hopper", resourceCulture); } } - + /// /// Looks up a localized string similar to ╔═════════════════════════════════════╗ ///║╔═══╦═══════════╗ ║ @@ -243,12 +275,14 @@ namespace MinecraftClient { ///║║ 9 ║10 ║11 ║12 ║13 ║14 ║15 ║16 ║17 ║║ ///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]";. /// - internal static string ContainerType_PlayerInventory { - get { + internal static string ContainerType_PlayerInventory + { + get + { return ResourceManager.GetString("ContainerType_PlayerInventory", resourceCulture); } } - + /// /// Looks up a localized string similar to [mcc] ///# Messages from MCC itself @@ -265,12 +299,14 @@ namespace MinecraftClient { ///mcc.session_invalid=§8Gespeicherte Session ungültig oder abgelaufen. ///mcc.session_valid=§8Gespeicherte Ses [rest of string was truncated]";. /// - internal static string Translation_de { - get { + internal static string Translation_de + { + get + { return ResourceManager.GetString("Translation_de", resourceCulture); } } - + /// /// Looks up a localized string similar to [mcc] ///# Messages from MCC itself @@ -285,12 +321,14 @@ namespace MinecraftClient { ///mcc.password_hidden=Password(invisible): {0} ///mcc.off [rest of string was truncated]";. /// - internal static string Translation_en { - get { + internal static string Translation_en + { + get + { return ResourceManager.GetString("Translation_en", resourceCulture); } } - + /// /// Looks up a localized string similar to [mcc] ///# Messages from MCC itself @@ -307,12 +345,14 @@ namespace MinecraftClient { ///mcc.session_invalid=§8Le cache de la session est invalide ou a expiré. ///mcc.session_va [rest of string was truncated]";. /// - internal static string Translation_fr { - get { + internal static string Translation_fr + { + get + { return ResourceManager.GetString("Translation_fr", resourceCulture); } } - + /// /// Looks up a localized string similar to [mcc] ///# Messages from MCC itself @@ -329,12 +369,14 @@ namespace MinecraftClient { ///mcc.session_invalid=§8Кэшированная сессия недействительна или истекла. ///mcc.session_valid=§8Кэшированная се [rest of string was truncated]";. /// - internal static string Translation_ru { - get { + internal static string Translation_ru + { + get + { return ResourceManager.GetString("Translation_ru", resourceCulture); } } - + /// /// Looks up a localized string similar to [mcc] ///# Messages from MCC itself @@ -352,12 +394,14 @@ namespace MinecraftClient { ///mcc.session_valid=§8Phiên vẫn còn hợp lệ cho {0}. ///mcc.profile_ke [rest of string was truncated]";. /// - internal static string Translation_vi { - get { + internal static string Translation_vi + { + get + { return ResourceManager.GetString("Translation_vi", resourceCulture); } } - + /// /// Looks up a localized string similar to [mcc] ///# Messages from MCC itself @@ -376,12 +420,14 @@ namespace MinecraftClient { ///mcc.profile_key_invalid=§8缓存的聊天签名密钥需要刷新。 ///mcc.profile_key_valid=§8{0 [rest of string was truncated]";. /// - internal static string Translation_zh_Hans { - get { + internal static string Translation_zh_Hans + { + get + { return ResourceManager.GetString("Translation_zh_Hans", resourceCulture); } } - + /// /// Looks up a localized string similar to [mcc] ///# Messages from MCC itself @@ -400,8 +446,10 @@ namespace MinecraftClient { ///mcc.profile_key_invalid=§8快取的聊天簽名金鑰需要重新整理。 ///mcc.profile_key_valid [rest of string was truncated]";. /// - internal static string Translation_zh_Hant { - get { + internal static string Translation_zh_Hant + { + get + { return ResourceManager.GetString("Translation_zh_Hant", resourceCulture); } } diff --git a/MinecraftClient/DefaultConfigResource.resx b/MinecraftClient/DefaultConfigResource.resx index 8bc4ea56..e6b21245 100644 --- a/MinecraftClient/DefaultConfigResource.resx +++ b/MinecraftClient/DefaultConfigResource.resx @@ -124,6 +124,9 @@ Resources\containers\ContainerType.Crafting.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + Resources\containers\ContainerType.EnchantingTable.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + Resources\containers\ContainerType.Furnace.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 diff --git a/MinecraftClient/Inventory/ContainerTypeExtensions.cs b/MinecraftClient/Inventory/ContainerTypeExtensions.cs index 166693e9..41c2217c 100644 --- a/MinecraftClient/Inventory/ContainerTypeExtensions.cs +++ b/MinecraftClient/Inventory/ContainerTypeExtensions.cs @@ -56,7 +56,7 @@ ContainerType.BlastFurnace => DefaultConfigResource.ContainerType_Furnace, ContainerType.Furnace => DefaultConfigResource.ContainerType_Furnace, ContainerType.Smoker => DefaultConfigResource.ContainerType_Furnace, - ContainerType.Enchantment => null, + ContainerType.Enchantment => DefaultConfigResource.ContainerType_EnchantingTable, ContainerType.BrewingStand => DefaultConfigResource.ContainerType_BrewingStand, ContainerType.Merchant => null, ContainerType.Beacon => null, diff --git a/MinecraftClient/Inventory/EnchantmentMapping.cs b/MinecraftClient/Inventory/EnchantmentMapping.cs index 4f18e72a..791cdf37 100644 --- a/MinecraftClient/Inventory/EnchantmentMapping.cs +++ b/MinecraftClient/Inventory/EnchantmentMapping.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; +using System.Linq; +using MinecraftClient.Commands; using MinecraftClient.Protocol.Handlers; namespace MinecraftClient.Inventory { public class EnchantmentMapping { + #pragma warning disable format // @formatter:off // 1.14 - 1.15.2 private static Dictionary enchantmentMappings114 = new Dictionary() { @@ -92,7 +95,7 @@ namespace MinecraftClient.Inventory private static Dictionary enchantmentNames = new Dictionary() { //type - { Enchantment.Protection, "Enchantment.Protection" } , + { Enchantment.Protection, "Enchantment.Protection" }, { Enchantment.FireProtection, "Enchantment.FireProtection" }, { Enchantment.FeatherFalling, "Enchantment.FeatherFalling" }, { Enchantment.BlastProtection, "Enchantment.BlastProtection" }, @@ -131,6 +134,7 @@ namespace MinecraftClient.Inventory { Enchantment.Mending, "Enchantment.Mending" }, { Enchantment.VanishingCurse, "Enchantment.VanishingCurse" } }; +#pragma warning restore format // @formatter:on public static Enchantment GetEnchantmentById(int protocolVersion, short id) { @@ -151,9 +155,38 @@ namespace MinecraftClient.Inventory 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 "Unknown Enchantment with ID: " + ((short)enchantment) + " (Probably not named in the code yet)"; return Translations.TryGet(enchantmentNames[enchantment]); } + + public static string ConvertLevelToRomanNumbers(int num) + { + string result = string.Empty; + Dictionary romanNumbers = new Dictionary + { + {"M", 1000 }, + {"CM", 900}, + {"D", 500}, + {"CD", 400}, + {"C", 100}, + {"XC", 90}, + {"L", 50}, + {"XL", 40}, + {"X", 10}, + {"IX", 9}, + {"V", 5}, + {"IV", 4}, + {"I", 1} + }; + + foreach (var pair in romanNumbers) + { + result += string.Join(string.Empty, Enumerable.Repeat(pair.Key, num / pair.Value)); + num %= pair.Value; + } + + return result; + } } } diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index 61060ecb..6667660e 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading; +using System.Transactions; using MinecraftClient.ChatBots; using MinecraftClient.Inventory; using MinecraftClient.Logger; @@ -2665,45 +2666,76 @@ namespace MinecraftClient 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); + Log.Info("Got a property " + propertyId + " with value: " + 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) + if (propertyId == 9 && 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]; + short topEnchantmentLevelRequirement = inventory.Properties[0]; + short middleEnchantmentLevelRequirement = inventory.Properties[1]; + short bottomEnchantmentLevelRequirement = inventory.Properties[2]; Enchantment topEnchantment = EnchantmentMapping.GetEnchantmentById( GetProtocolVersion(), - inventory.Properties[(int)EnchantmentPropertyInfo.TopEnchantmentId]); + inventory.Properties[4]); Enchantment middleEnchantment = EnchantmentMapping.GetEnchantmentById( GetProtocolVersion(), - inventory.Properties[(int)EnchantmentPropertyInfo.MiddleEnchantmentId]); + inventory.Properties[5]); Enchantment bottomEnchantment = EnchantmentMapping.GetEnchantmentById( GetProtocolVersion(), - inventory.Properties[(int)EnchantmentPropertyInfo.BottomEnchantmentId]); + inventory.Properties[6]); - short topEnchantmentLevel = inventory.Properties[(int)EnchantmentPropertyInfo.TopEnchantmentId]; - short middleEnchantmentLevel = inventory.Properties[(int)EnchantmentPropertyInfo.MiddleEnchantmentId]; - short bottomEnchantmentLevel = inventory.Properties[(int)EnchantmentPropertyInfo.BottomEnchantmentId]; + short topEnchantmentLevel = inventory.Properties[7]; + short middleEnchantmentLevel = inventory.Properties[8]; + short bottomEnchantmentLevel = inventory.Properties[9]; - Log.Info(EnchantmentMapping.GetEnchantmentName(topEnchantment) + " " + topEnchantmentLevel + " > " + topEnchantmentLevelRequirement + " Levels"); - Log.Info(EnchantmentMapping.GetEnchantmentName(middleEnchantment) + " " + middleEnchantmentLevel + " > " + middleEnchantmentLevelRequirement + " Levels"); - Log.Info(EnchantmentMapping.GetEnchantmentName(bottomEnchantment) + " " + bottomEnchantmentLevel + " > " + bottomEnchantmentLevelRequirement + " Levels"); + StringBuilder sb = new(); + + sb.AppendLine(Translations.TryGet("Enchantment.enchantments_available") + ":"); + + sb.AppendLine(Translations.TryGet("Enchantment.tops_slot") + ":\t" + + EnchantmentMapping.GetEnchantmentName(topEnchantment) + " " + + EnchantmentMapping.ConvertLevelToRomanNumbers(topEnchantmentLevel) + " (" + + topEnchantmentLevelRequirement + " " + Translations.TryGet("Enchantment.levels") + ")"); + + sb.AppendLine(Translations.TryGet("Enchantment.middle_slot") + ":\t" + + EnchantmentMapping.GetEnchantmentName(middleEnchantment) + " " + + EnchantmentMapping.ConvertLevelToRomanNumbers(middleEnchantmentLevel) + " (" + + middleEnchantmentLevelRequirement + " " + Translations.TryGet("Enchantment.levels") + ")"); + + sb.AppendLine(Translations.TryGet("Enchantment.bottom_slot") + ":\t" + + EnchantmentMapping.GetEnchantmentName(bottomEnchantment) + " " + + EnchantmentMapping.ConvertLevelToRomanNumbers(bottomEnchantmentLevel) + " (" + + bottomEnchantmentLevelRequirement + " " + Translations.TryGet("Enchantment.levels") + ")"); + + Log.Info(sb.ToString()); + + DispatchBotEvent(bot => bot.OnEnchantments( + // Enchantments + topEnchantment, + middleEnchantment, + bottomEnchantment, + + // Enchantment levels + topEnchantmentLevel, + middleEnchantmentLevel, + bottomEnchantmentLevel, + + // Required levels for enchanting + topEnchantmentLevelRequirement, + middleEnchantmentLevelRequirement, + bottomEnchantmentLevelRequirement)); } } } diff --git a/MinecraftClient/Resources/containers/ContainerType.EnchantingTable.txt b/MinecraftClient/Resources/containers/ContainerType.EnchantingTable.txt new file mode 100644 index 00000000..1ec0dd57 --- /dev/null +++ b/MinecraftClient/Resources/containers/ContainerType.EnchantingTable.txt @@ -0,0 +1,22 @@ +╔═════════════════════════════════════╗ +║ Enchant ║ +║ ╔════════════════════╗ ║ +║ ║ Top ║ ║ +║ ╔═══╦═══╗ ╠════════════════════╣ ║ +║ ║ 0 ║ 1 ║ ║ Middle ║ ║ +║ ╚═══╩═══╝ ╠════════════════════╣ ║ +║ ║ Bottom ║ ║ +║ ╚════════════════════╝ ║ +║ Inventory ║ +║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║ +║║ 2 ║ 3 ║ 4 ║ 5 ║ 6 ║ 7 ║ 8 ║ 9 ║10 ║║ +║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣║ +║║11 ║12 ║13 ║14 ║15 ║16 ║17 ║18 ║19 ║║ +║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣║ +║║20 ║21 ║22 ║23 ║24 ║25 ║26 ║27 ║28 ║║ +║╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝║ +║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║ +║║29 ║30 ║31 ║32 ║33 ║34 ║35 ║36 ║37 ║║ +║╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝║ +║ 1 2 3 4 5 6 7 8 9 ║ +╚═════════════════════════════════════╝ \ No newline at end of file diff --git a/MinecraftClient/Resources/lang/en.ini b/MinecraftClient/Resources/lang/en.ini index 223919e8..a3e4a6ab 100644 --- a/MinecraftClient/Resources/lang/en.ini +++ b/MinecraftClient/Resources/lang/en.ini @@ -153,6 +153,12 @@ 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.enchantments_available=Enchantments available +Enchantment.tops_slot=Top slot +Enchantment.middle_slot=Middle slot +Enchantment.bottom_slot=Bottom slot +Enchantment.levels=Levels + Enchantment.Protection=Protection Enchantment.FireProtection=Fire Protection Enchantment.FeatherFalling=Feather Falling @@ -308,6 +314,8 @@ 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! +cmd.enchant.enchanting_no_item=You must put an item inside the enchanting table in slot 0! +cmd.enchant.enchanting_no_lapis=You must put at least 3 lapis lazuli inside the enchanting table in slot 1! # Entitycmd cmd.entityCmd.attacked=Entity attacked diff --git a/MinecraftClient/Scripting/ChatBot.cs b/MinecraftClient/Scripting/ChatBot.cs index 45e976f1..6404f133 100644 --- a/MinecraftClient/Scripting/ChatBot.cs +++ b/MinecraftClient/Scripting/ChatBot.cs @@ -368,6 +368,32 @@ namespace MinecraftClient /// Property Value public virtual void OnInventoryProperties(byte inventoryID, short propertyId, short propertyValue) { } + /// + /// When received enchantments from the server this method is called + /// Enchantment levels are the levels of enchantment (eg. I, II, III, IV, V) (eg. Smite IV, Power III, Knockback II ..) + /// Enchantment level requirements are the levels that player needs to have in order to enchant the item + /// + /// Enchantment in the top most slot + /// Enchantment in the middle slot + /// Enchantment in the bottom slot + /// Enchantment level for the enchantment in the top most slot + /// Enchantment level for the enchantment in the middle slot + /// Enchantment level for the enchantment in the bottom slot + /// Levels required by player for the enchantment in the top most slot + /// Levels required by player for the enchantment in the middle slot + /// Levels required by player for the enchantment in the bottom slot + public virtual void OnEnchantments( + Enchantment topEnchantment, + Enchantment middleEnchantment, + Enchantment bottomEnchantment, + short topEnchantmentLevel, + short middleEnchantmentLevel, + short bottomEnchantmentLevel, + short topEnchantmentLevelRequirement, + short middleEnchantmentLevelRequirement, + short bottomEnchantmentLevelRequirement) + { } + /// /// Called when a player joined the game /// From 6365e1273551479e0577fb488f68db6c1a321ed3 Mon Sep 17 00:00:00 2001 From: Milutinke Date: Fri, 14 Oct 2022 16:29:08 +0200 Subject: [PATCH 3/3] Fixed Enchantment mappings for 1.19. Added Swift Sneak. --- .../Inventory/EnchantmentMapping.cs | 53 ++++++++++++++++++- MinecraftClient/Inventory/Enchantments.cs | 1 + MinecraftClient/McClient.cs | 2 - MinecraftClient/Resources/lang/en.ini | 1 + 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/MinecraftClient/Inventory/EnchantmentMapping.cs b/MinecraftClient/Inventory/EnchantmentMapping.cs index 791cdf37..8b82f156 100644 --- a/MinecraftClient/Inventory/EnchantmentMapping.cs +++ b/MinecraftClient/Inventory/EnchantmentMapping.cs @@ -49,7 +49,8 @@ namespace MinecraftClient.Inventory { 33, Enchantment.VanishingCurse } }; - private static Dictionary enchantmentMappings116Plus = new Dictionary() + // 1.16 - 1.18 + private static Dictionary enchantmentMappings116 = new Dictionary() { //id type { 0, Enchantment.Protection }, @@ -92,6 +93,51 @@ namespace MinecraftClient.Inventory { 37, Enchantment.VanishingCurse } }; + // 1.19+ + private static Dictionary enchantmentMappings = 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.SwiftSneak }, + { 13, Enchantment.Sharpness }, + { 14, Enchantment.Smite }, + { 15, Enchantment.BaneOfArthropods }, + { 16, Enchantment.Knockback }, + { 17, Enchantment.FireAspect }, + { 18, Enchantment.Looting }, + { 19, Enchantment.Sweeping }, + { 20, Enchantment.Efficency }, + { 21, Enchantment.SilkTouch }, + { 22, Enchantment.Unbreaking }, + { 23, Enchantment.Fortune }, + { 24, Enchantment.Power }, + { 25, Enchantment.Punch }, + { 26, Enchantment.Flame }, + { 27, Enchantment.Infinity }, + { 28, Enchantment.LuckOfTheSea }, + { 29, Enchantment.Lure }, + { 30, Enchantment.Loyality }, + { 31, Enchantment.Impaling }, + { 32, Enchantment.Riptide }, + { 33, Enchantment.Channeling }, + { 34, Enchantment.Multishot }, + { 35, Enchantment.QuickCharge }, + { 36, Enchantment.Piercing }, + { 37, Enchantment.Mending }, + { 38, Enchantment.VanishingCurse } + }; + private static Dictionary enchantmentNames = new Dictionary() { //type @@ -107,6 +153,7 @@ namespace MinecraftClient.Inventory { Enchantment.FrostWalker, "Enchantment.FrostWalker" }, { Enchantment.BindingCurse, "Enchantment.BindingCurse" }, { Enchantment.SoulSpeed, "Enchantment.SoulSpeed" }, + { Enchantment.SwiftSneak, "Enchantment.SwiftSneak" }, { Enchantment.Sharpness, "Enchantment.Sharpness" }, { Enchantment.Smite, "Enchantment.Smite" }, { Enchantment.BaneOfArthropods, "Enchantment.BaneOfArthropods" }, @@ -141,10 +188,12 @@ namespace MinecraftClient.Inventory if (protocolVersion < Protocol18Handler.MC_1_14_Version) throw new Exception("Enchantments mappings are not implemented bellow 1.14"); - Dictionary map = enchantmentMappings116Plus; + Dictionary map = enchantmentMappings; if (protocolVersion >= Protocol18Handler.MC_1_14_Version && protocolVersion < Protocol18Handler.MC_1_16_Version) map = enchantmentMappings114; + else if (protocolVersion >= Protocol18Handler.MC_1_16_Version && protocolVersion < Protocol18Handler.MC_1_19_Version) + map = enchantmentMappings116; if (!map.ContainsKey(id)) throw new Exception("Got an Unknown Enchantment ID '" + id + "', please update the Mappings!"); diff --git a/MinecraftClient/Inventory/Enchantments.cs b/MinecraftClient/Inventory/Enchantments.cs index 10baf22d..34279de0 100644 --- a/MinecraftClient/Inventory/Enchantments.cs +++ b/MinecraftClient/Inventory/Enchantments.cs @@ -15,6 +15,7 @@ FrostWalker, BindingCurse, SoulSpeed, + SwiftSneak, Sharpness, Smite, BaneOfArthropods, diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index 6667660e..5008cbaa 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -2671,8 +2671,6 @@ namespace MinecraftClient inventory.Properties.Add(propertyId, propertyValue); - Log.Info("Got a property " + propertyId + " with value: " + propertyValue); - DispatchBotEvent(bot => bot.OnInventoryProperties(inventoryID, propertyId, propertyValue)); if (inventory.Type == ContainerType.Enchantment) diff --git a/MinecraftClient/Resources/lang/en.ini b/MinecraftClient/Resources/lang/en.ini index a3e4a6ab..3a352f44 100644 --- a/MinecraftClient/Resources/lang/en.ini +++ b/MinecraftClient/Resources/lang/en.ini @@ -171,6 +171,7 @@ Enchantment.DepthStrieder=Depth Strieder Enchantment.FrostWalker=Frost Walker Enchantment.BindingCurse=Curse of Binding Enchantment.SoulSpeed=Soul Speed +Enchantment.SwiftSneak=Swift Sneak Enchantment.Sharpness=Sharpness Enchantment.Smite=Smite Enchantment.BaneOfArthropods=Bane of Arthropods