diff --git a/MinecraftClient/Commands/Useblock.cs b/MinecraftClient/Commands/Useblock.cs index 994e34ae..2df6a92f 100644 --- a/MinecraftClient/Commands/Useblock.cs +++ b/MinecraftClient/Commands/Useblock.cs @@ -1,4 +1,4 @@ -using Brigadier.NET; +using Brigadier.NET; using Brigadier.NET.Builder; using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; @@ -48,7 +48,7 @@ namespace MinecraftClient.Commands Location current = handler.GetCurrentLocation(); block = block.ToAbsolute(current).ToFloor(); Location blockCenter = block.ToCenter(); - bool res = handler.PlaceBlock(block, Direction.Down); + bool res = handler.PlaceBlock(block, Direction.Down, lookAtBlock: true); return r.SetAndReturn(string.Format(Translations.cmd_useblock_use, blockCenter.X, blockCenter.Y, blockCenter.Z, res ? "succeeded" : "failed"), res); } } diff --git a/MinecraftClient/Inventory/EnchantmentMapping.cs b/MinecraftClient/Inventory/EnchantmentMapping.cs index 4d576bcf..cf25ea94 100644 --- a/MinecraftClient/Inventory/EnchantmentMapping.cs +++ b/MinecraftClient/Inventory/EnchantmentMapping.cs @@ -207,9 +207,74 @@ namespace MinecraftClient.Inventory } private static Dictionary? reverseEnchantmentMappings; + private static Dictionary? dynamicEnchantmentIdMap; + + private static readonly Dictionary nameToEnchantment = new() + { + { "protection", Enchantments.Protection }, + { "fire_protection", Enchantments.FireProtection }, + { "feather_falling", Enchantments.FeatherFalling }, + { "blast_protection", Enchantments.BlastProtection }, + { "projectile_protection", Enchantments.ProjectileProtection }, + { "respiration", Enchantments.Respiration }, + { "aqua_affinity", Enchantments.AquaAffinity }, + { "thorns", Enchantments.Thorns }, + { "depth_strider", Enchantments.DepthStrider }, + { "frost_walker", Enchantments.FrostWalker }, + { "binding_curse", Enchantments.BindingCurse }, + { "soul_speed", Enchantments.SoulSpeed }, + { "swift_sneak", Enchantments.SwiftSneak }, + { "sharpness", Enchantments.Sharpness }, + { "smite", Enchantments.Smite }, + { "bane_of_arthropods", Enchantments.BaneOfArthropods }, + { "knockback", Enchantments.Knockback }, + { "fire_aspect", Enchantments.FireAspect }, + { "looting", Enchantments.Looting }, + { "sweeping_edge", Enchantments.Sweeping }, + { "efficiency", Enchantments.Efficiency }, + { "silk_touch", Enchantments.SilkTouch }, + { "unbreaking", Enchantments.Unbreaking }, + { "fortune", Enchantments.Fortune }, + { "power", Enchantments.Power }, + { "punch", Enchantments.Punch }, + { "flame", Enchantments.Flame }, + { "infinity", Enchantments.Infinity }, + { "luck_of_the_sea", Enchantments.LuckOfTheSea }, + { "lure", Enchantments.Lure }, + { "loyalty", Enchantments.Loyalty }, + { "impaling", Enchantments.Impaling }, + { "riptide", Enchantments.Riptide }, + { "channeling", Enchantments.Channeling }, + { "multishot", Enchantments.Multishot }, + { "quick_charge", Enchantments.QuickCharge }, + { "piercing", Enchantments.Piercing }, + { "density", Enchantments.Density }, + { "breach", Enchantments.Breach }, + { "wind_burst", Enchantments.WindBurst }, + { "mending", Enchantments.Mending }, + { "vanishing_curse", Enchantments.VanishingCurse }, + }; + + /// + /// Set the dynamic enchantment ID map from server RegistryData. + /// Called during configuration phase when receiving minecraft:enchantment registry. + /// + public static void SetDynamicEnchantmentIdMap(Dictionary idMap) + { + dynamicEnchantmentIdMap = new Dictionary(); + foreach (var kvp in idMap) + { + var name = kvp.Value.StartsWith("minecraft:") ? kvp.Value.Substring("minecraft:".Length) : kvp.Value; + if (nameToEnchantment.TryGetValue(name, out var enchantment)) + dynamicEnchantmentIdMap[kvp.Key] = enchantment; + } + reverseEnchantmentMappings = null; + } public static Enchantments GetEnchantmentByRegistryId1206(int id) { + if (dynamicEnchantmentIdMap != null && dynamicEnchantmentIdMap.TryGetValue(id, out var dynValue)) + return dynValue; if (enchantmentMappings.TryGetValue((short)id, out var value)) return value; return (Enchantments)(-1); @@ -220,8 +285,16 @@ namespace MinecraftClient.Inventory if (reverseEnchantmentMappings == null) { reverseEnchantmentMappings = new Dictionary(); - foreach (var kvp in enchantmentMappings) - reverseEnchantmentMappings[kvp.Value] = kvp.Key; + if (dynamicEnchantmentIdMap != null) + { + foreach (var kvp in dynamicEnchantmentIdMap) + reverseEnchantmentMappings[kvp.Value] = (short)kvp.Key; + } + else + { + foreach (var kvp in enchantmentMappings) + reverseEnchantmentMappings[kvp.Value] = kvp.Key; + } } return reverseEnchantmentMappings.TryGetValue(enchantment, out var id) ? id : -1; } diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index c632569b..86d205d1 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -2392,10 +2392,19 @@ namespace MinecraftClient /// /// Location to place block to /// Block face (e.g. Direction.Down when clicking on the block below to place this block) + /// Also look at the block before interacting /// TRUE if successfully placed - public bool PlaceBlock(Location location, Direction blockFace, Hand hand = Hand.MainHand) + public bool PlaceBlock(Location location, Direction blockFace, Hand hand = Hand.MainHand, bool lookAtBlock = false) { - return InvokeOnMainThread(() => handler.SendPlayerBlockPlacement((int)hand, location, blockFace, sequenceId++)); + return InvokeOnMainThread(() => + { + if (lookAtBlock) + { + UpdateLocation(GetCurrentLocation(), location.ToCenter()); + handler.SendLocationUpdate(GetCurrentLocation(), Movement.IsOnGround(world, GetCurrentLocation()), _yaw, _pitch); + } + return handler.SendPlayerBlockPlacement((int)hand, location, blockFace, sequenceId++); + }); } diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 735ce498..3f5590a9 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -465,10 +465,12 @@ namespace MinecraftClient.Protocol.Handlers var isChat = registryId == "minecraft:chat_type"; var isDimension = registryId == "minecraft:dimension_type"; var isAttribute = registryId == "minecraft:attribute"; + var isEnchantment = registryId == "minecraft:enchantment"; var availableChats = isChat ? new Dictionary() : null; var dimensionIdMap = isDimension ? new Dictionary() : null; var attributeIdMap = isAttribute ? new Dictionary() : null; + var enchantmentIdMap = isEnchantment ? new Dictionary() : null; for (var i = 0; i < entryCount; i++) { @@ -489,12 +491,13 @@ namespace MinecraftClient.Protocol.Handlers } else if (isAttribute) { - // Strip "minecraft:" prefix to match the format used in EntityProperties packets var attrName = entryId.StartsWith("minecraft:") ? entryId.Substring("minecraft:".Length) : entryId; attributeIdMap!.Add(i, attrName); } + else if (isEnchantment) + enchantmentIdMap!.Add(i, entryId); } if (isChat) @@ -507,6 +510,8 @@ namespace MinecraftClient.Protocol.Handlers } else if (isAttribute) World.SetAttributeIdMap(attributeIdMap!); + else if (isEnchantment) + EnchantmentMapping.SetDynamicEnchantmentIdMap(enchantmentIdMap!); } break; @@ -2339,6 +2344,8 @@ namespace MinecraftClient.Protocol.Handlers { if (entity.Type == EntityType.Player) handler.OnSpawnPlayer(entity.ID, entity.UUID, entity.Location, (byte)entity.Yaw, (byte)entity.Pitch); + else + handler.OnSpawnEntity(entity); break; } diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_20_6/AttributeModifiersComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_20_6/AttributeModifiersComponent.cs index d969d1b4..3cac3667 100644 --- a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_20_6/AttributeModifiersComponent.cs +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_20_6/AttributeModifiersComponent.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using MinecraftClient.Inventory.ItemPalettes; using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents; -using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents._1_20_6; using MinecraftClient.Protocol.Handlers.StructuredComponents.Core; namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6; @@ -11,7 +10,7 @@ public class AttributeModifiersComponent(DataTypes dataTypes, ItemPalette itemPa : StructuredComponent(dataTypes, itemPalette, subComponentRegistry) { public int NumberOfAttributes { get; set; } - public List Attributes { get; set; } = new(); + public List Attributes { get; set; } = new(); public bool ShowInTooltip { get; set; } public override void Parse(Queue data) @@ -19,7 +18,7 @@ public class AttributeModifiersComponent(DataTypes dataTypes, ItemPalette itemPa NumberOfAttributes = dataTypes.ReadNextVarInt(data); for (var i = 0; i < NumberOfAttributes; i++) - Attributes.Add((AttributeSubComponent)subComponentRegistry.ParseSubComponent(SubComponents.Attribute, data)); + Attributes.Add(subComponentRegistry.ParseSubComponent(SubComponents.Attribute, data)); ShowInTooltip = dataTypes.ReadNextBool(data); }