WIP: Added some strctured components

This commit is contained in:
Anon 2024-09-11 19:12:31 +02:00
parent 63b027d84a
commit 76e873ed54
36 changed files with 857 additions and 231 deletions

View file

@ -0,0 +1,3 @@
namespace MinecraftClient.Inventory;
public record Enchantment(Enchantments Type, int Level);

View file

@ -2,9 +2,9 @@
{
public class EnchantmentData
{
public Enchantment TopEnchantment { get; set; }
public Enchantment MiddleEnchantment { get; set; }
public Enchantment BottomEnchantment { get; set; }
public Enchantments TopEnchantment { get; set; }
public Enchantments MiddleEnchantment { get; set; }
public Enchantments BottomEnchantment { get; set; }
// Seed for rendering Standard Galactic Language (symbols in the enchanting table) (Useful for poeple who use MCC for the protocol)
public short Seed { get; set; }

View file

@ -10,184 +10,184 @@ namespace MinecraftClient.Inventory
{
#pragma warning disable format // @formatter:off
// 1.14 - 1.15.2
private static Dictionary<short, Enchantment> enchantmentMappings114 = new()
private static Dictionary<short, Enchantments> enchantmentMappings114 = new()
{
//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 }
{ 0, Enchantments.Protection },
{ 1, Enchantments.FireProtection },
{ 2, Enchantments.FeatherFalling },
{ 3, Enchantments.BlastProtection },
{ 4, Enchantments.ProjectileProtection },
{ 5, Enchantments.Respiration },
{ 6, Enchantments.AquaAffinity },
{ 7, Enchantments.Thorns },
{ 8, Enchantments.DepthStrieder },
{ 9, Enchantments.FrostWalker },
{ 10, Enchantments.BindingCurse },
{ 11, Enchantments.Sharpness },
{ 12, Enchantments.Smite },
{ 13, Enchantments.BaneOfArthropods },
{ 14, Enchantments.Knockback },
{ 15, Enchantments.FireAspect },
{ 16, Enchantments.Looting },
{ 17, Enchantments.Sweeping },
{ 18, Enchantments.Efficency },
{ 19, Enchantments.SilkTouch },
{ 20, Enchantments.Unbreaking },
{ 21, Enchantments.Fortune },
{ 22, Enchantments.Power },
{ 23, Enchantments.Punch },
{ 24, Enchantments.Flame },
{ 25, Enchantments.Infinity },
{ 26, Enchantments.LuckOfTheSea },
{ 27, Enchantments.Lure },
{ 28, Enchantments.Loyality },
{ 29, Enchantments.Impaling },
{ 30, Enchantments.Riptide },
{ 31, Enchantments.Channeling },
{ 32, Enchantments.Mending },
{ 33, Enchantments.VanishingCurse }
};
// 1.16 - 1.18
private static Dictionary<short, Enchantment> enchantmentMappings116 = new()
private static Dictionary<short, Enchantments> enchantmentMappings116 = new()
{
//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 }
{ 0, Enchantments.Protection },
{ 1, Enchantments.FireProtection },
{ 2, Enchantments.FeatherFalling },
{ 3, Enchantments.BlastProtection },
{ 4, Enchantments.ProjectileProtection },
{ 5, Enchantments.Respiration },
{ 6, Enchantments.AquaAffinity },
{ 7, Enchantments.Thorns },
{ 8, Enchantments.DepthStrieder },
{ 9, Enchantments.FrostWalker },
{ 10, Enchantments.BindingCurse },
{ 11, Enchantments.SoulSpeed },
{ 12, Enchantments.Sharpness },
{ 13, Enchantments.Smite },
{ 14, Enchantments.BaneOfArthropods },
{ 15, Enchantments.Knockback },
{ 16, Enchantments.FireAspect },
{ 17, Enchantments.Looting },
{ 18, Enchantments.Sweeping },
{ 19, Enchantments.Efficency },
{ 20, Enchantments.SilkTouch },
{ 21, Enchantments.Unbreaking },
{ 22, Enchantments.Fortune },
{ 23, Enchantments.Power },
{ 24, Enchantments.Punch },
{ 25, Enchantments.Flame },
{ 26, Enchantments.Infinity },
{ 27, Enchantments.LuckOfTheSea },
{ 28, Enchantments.Lure },
{ 29, Enchantments.Loyality },
{ 30, Enchantments.Impaling },
{ 31, Enchantments.Riptide },
{ 32, Enchantments.Channeling },
{ 33, Enchantments.Multishot },
{ 34, Enchantments.QuickCharge },
{ 35, Enchantments.Piercing },
{ 36, Enchantments.Mending },
{ 37, Enchantments.VanishingCurse }
};
// 1.19 - 1.20.4
private static Dictionary<short, Enchantment> enchantmentMappings119 = new()
private static Dictionary<short, Enchantments> enchantmentMappings119 = new()
{
//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 }
{ 0, Enchantments.Protection },
{ 1, Enchantments.FireProtection },
{ 2, Enchantments.FeatherFalling },
{ 3, Enchantments.BlastProtection },
{ 4, Enchantments.ProjectileProtection },
{ 5, Enchantments.Respiration },
{ 6, Enchantments.AquaAffinity },
{ 7, Enchantments.Thorns },
{ 8, Enchantments.DepthStrieder },
{ 9, Enchantments.FrostWalker },
{ 10, Enchantments.BindingCurse },
{ 11, Enchantments.SoulSpeed },
{ 12, Enchantments.SwiftSneak },
{ 13, Enchantments.Sharpness },
{ 14, Enchantments.Smite },
{ 15, Enchantments.BaneOfArthropods },
{ 16, Enchantments.Knockback },
{ 17, Enchantments.FireAspect },
{ 18, Enchantments.Looting },
{ 19, Enchantments.Sweeping },
{ 20, Enchantments.Efficency },
{ 21, Enchantments.SilkTouch },
{ 22, Enchantments.Unbreaking },
{ 23, Enchantments.Fortune },
{ 24, Enchantments.Power },
{ 25, Enchantments.Punch },
{ 26, Enchantments.Flame },
{ 27, Enchantments.Infinity },
{ 28, Enchantments.LuckOfTheSea },
{ 29, Enchantments.Lure },
{ 30, Enchantments.Loyality },
{ 31, Enchantments.Impaling },
{ 32, Enchantments.Riptide },
{ 33, Enchantments.Channeling },
{ 34, Enchantments.Multishot },
{ 35, Enchantments.QuickCharge },
{ 36, Enchantments.Piercing },
{ 37, Enchantments.Mending },
{ 38, Enchantments.VanishingCurse }
};
// 1.20.6+
private static Dictionary<short, Enchantment> enchantmentMappings = new()
private static Dictionary<short, Enchantments> enchantmentMappings = new()
{
//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.Density },
{ 38, Enchantment.Breach },
{ 39, Enchantment.WindBurst },
{ 40, Enchantment.Mending },
{ 41, Enchantment.VanishingCurse }
{ 0, Enchantments.Protection },
{ 1, Enchantments.FireProtection },
{ 2, Enchantments.FeatherFalling },
{ 3, Enchantments.BlastProtection },
{ 4, Enchantments.ProjectileProtection },
{ 5, Enchantments.Respiration },
{ 6, Enchantments.AquaAffinity },
{ 7, Enchantments.Thorns },
{ 8, Enchantments.DepthStrieder },
{ 9, Enchantments.FrostWalker },
{ 10, Enchantments.BindingCurse },
{ 11, Enchantments.SoulSpeed },
{ 12, Enchantments.SwiftSneak },
{ 13, Enchantments.Sharpness },
{ 14, Enchantments.Smite },
{ 15, Enchantments.BaneOfArthropods },
{ 16, Enchantments.Knockback },
{ 17, Enchantments.FireAspect },
{ 18, Enchantments.Looting },
{ 19, Enchantments.Sweeping },
{ 20, Enchantments.Efficency },
{ 21, Enchantments.SilkTouch },
{ 22, Enchantments.Unbreaking },
{ 23, Enchantments.Fortune },
{ 24, Enchantments.Power },
{ 25, Enchantments.Punch },
{ 26, Enchantments.Flame },
{ 27, Enchantments.Infinity },
{ 28, Enchantments.LuckOfTheSea },
{ 29, Enchantments.Lure },
{ 30, Enchantments.Loyality },
{ 31, Enchantments.Impaling },
{ 32, Enchantments.Riptide },
{ 33, Enchantments.Channeling },
{ 34, Enchantments.Multishot },
{ 35, Enchantments.QuickCharge },
{ 36, Enchantments.Piercing },
{ 37, Enchantments.Density },
{ 38, Enchantments.Breach },
{ 39, Enchantments.WindBurst },
{ 40, Enchantments.Mending },
{ 41, Enchantments.VanishingCurse }
};
#pragma warning restore format // @formatter:on
public static Enchantment GetEnchantmentById(int protocolVersion, short id)
public static Enchantments GetEnchantmentById(int protocolVersion, short id)
{
if (protocolVersion < Protocol18Handler.MC_1_14_Version)
throw new Exception("Enchantments mappings are not implemented bellow 1.14");
@ -206,9 +206,9 @@ namespace MinecraftClient.Inventory
return value;
}
public static string GetEnchantmentName(Enchantment enchantment)
public static string GetEnchantmentName(Enchantments enchantment)
{
var translation = ChatParser.TranslateString("enchantment.minecraft." + enchantment.ToString().ToUnderscoreCase());
var translation = ChatParser.TranslateString("Enchantments.minecraft." + enchantment.ToString().ToUnderscoreCase());
return string.IsNullOrEmpty(translation) ? $"Unknown Enchantment with ID: {(short)enchantment} (Probably not named in the code yet)" : translation;
}

View file

@ -1,7 +1,7 @@
namespace MinecraftClient.Inventory
{
// Not implemented for 1.14
public enum Enchantment : short
public enum Enchantments : short
{
AquaAffinity = 0,
BaneOfArthropods,

View file

@ -0,0 +1,9 @@
namespace MinecraftClient.Inventory;
public enum ItemRarity : int
{
Common = 0,
Uncommon,
Rare,
Epic
}

View file

@ -2948,27 +2948,27 @@ namespace MinecraftClient
// We got the last property for enchantment
if (propertyId == 9 && propertyValue != -1)
{
short topEnchantmentLevelRequirement = inventory.Properties[0];
short middleEnchantmentLevelRequirement = inventory.Properties[1];
short bottomEnchantmentLevelRequirement = inventory.Properties[2];
var topEnchantmentLevelRequirement = inventory.Properties[0];
var middleEnchantmentLevelRequirement = inventory.Properties[1];
var bottomEnchantmentLevelRequirement = inventory.Properties[2];
Enchantment topEnchantment = EnchantmentMapping.GetEnchantmentById(
var topEnchantment = EnchantmentMapping.GetEnchantmentById(
GetProtocolVersion(),
inventory.Properties[4]);
Enchantment middleEnchantment = EnchantmentMapping.GetEnchantmentById(
var middleEnchantment = EnchantmentMapping.GetEnchantmentById(
GetProtocolVersion(),
inventory.Properties[5]);
Enchantment bottomEnchantment = EnchantmentMapping.GetEnchantmentById(
var bottomEnchantment = EnchantmentMapping.GetEnchantmentById(
GetProtocolVersion(),
inventory.Properties[6]);
short topEnchantmentLevel = inventory.Properties[7];
short middleEnchantmentLevel = inventory.Properties[8];
short bottomEnchantmentLevel = inventory.Properties[9];
var topEnchantmentLevel = inventory.Properties[7];
var middleEnchantmentLevel = inventory.Properties[8];
var bottomEnchantmentLevel = inventory.Properties[9];
StringBuilder sb = new();
var sb = new StringBuilder();
sb.AppendLine(Translations.Enchantment_enchantments_available + ":");

View file

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
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;
public class AttributeModifiersComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public int NumberOfAttributes { get; set; }
public List<AttributeSubComponent1206> Attributes { get; set; } = new();
public bool ShowInTooltip { get; set; }
public override void Parse(Queue<byte> data)
{
NumberOfAttributes = dataTypes.ReadNextVarInt(data);
for (var i = 0; i < NumberOfAttributes; i++)
Attributes.Add((AttributeSubComponent1206)subComponentRegistry.ParseSubComponent(SubComponents.Attribute, data));
ShowInTooltip = dataTypes.ReadNextBool(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(NumberOfAttributes));
if(NumberOfAttributes > 0 && Attributes.Count == 0)
throw new ArgumentNullException($"Can not serialize a AttributeModifiersComponent when the Attributes is empty but NumberOfAttributes is > 0!");
foreach (var attribute in Attributes)
data.AddRange(attribute.Serialize());
data.AddRange(DataTypes.GetBool(ShowInTooltip));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
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;
public class CanBreakComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public int NumberOfPredicates { get; set; }
public List<BlockPredicateSubcomponent1206> BlockPredicates { get; set; } = new();
public bool ShowInTooltip { get; set; }
public override void Parse(Queue<byte> data)
{
NumberOfPredicates = dataTypes.ReadNextVarInt(data);
for (var i = 0; i < NumberOfPredicates; i++)
BlockPredicates.Add((BlockPredicateSubcomponent1206)subComponentRegistry.ParseSubComponent(SubComponents.BlockPredicate, data));
ShowInTooltip = dataTypes.ReadNextBool(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(NumberOfPredicates));
if(NumberOfPredicates > 0 && BlockPredicates.Count == 0)
throw new ArgumentNullException($"Can not serialize a CanBreakComponent when the BlockPredicates is empty but NumberOfPredicates is > 0!");
foreach (var blockPredicate in BlockPredicates)
data.AddRange(blockPredicate.Serialize());
data.AddRange(DataTypes.GetBool(ShowInTooltip));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
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;
public class CanPlaceOnComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public int NumberOfPredicates { get; set; }
public List<BlockPredicateSubcomponent1206> BlockPredicates { get; set; } = new();
public bool ShowInTooltip { get; set; }
public override void Parse(Queue<byte> data)
{
NumberOfPredicates = dataTypes.ReadNextVarInt(data);
for (var i = 0; i < NumberOfPredicates; i++)
BlockPredicates.Add((BlockPredicateSubcomponent1206)subComponentRegistry.ParseSubComponent(SubComponents.BlockPredicate, data));
ShowInTooltip = dataTypes.ReadNextBool(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(NumberOfPredicates));
if(NumberOfPredicates > 0 && BlockPredicates.Count == 0)
throw new ArgumentNullException($"Can not serialize a CanPlaceOnComponent when the BlockPredicates is empty but NumberOfPredicates is > 0!");
foreach (var blockPredicate in BlockPredicates)
data.AddRange(blockPredicate.Serialize());
data.AddRange(DataTypes.GetBool(ShowInTooltip));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,21 @@
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class CustomDataComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public Dictionary<string, object>? Nbt { get; set; } = new();
public override void Parse(Queue<byte> data)
{
Nbt = dataTypes.ReadNextNbt(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetNbt(Nbt));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,21 @@
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class CustomModelDataComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public int Value { get; set; }
public override void Parse(Queue<byte> data)
{
Value = dataTypes.ReadNextVarInt(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Value));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,22 @@
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class CustomNameComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public string CustomName { get; set; } = string.Empty;
public override void Parse(Queue<byte> data)
{
CustomName = ChatParser.ParseText(dataTypes.ReadNextString(data));
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetString(CustomName));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,21 @@
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class DamageComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public int Damage { get; set; }
public override void Parse(Queue<byte> data)
{
Damage = dataTypes.ReadNextVarInt(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Damage));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,35 @@
using System.Collections.Generic;
using MinecraftClient.Inventory;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class EnchantmentsComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public int NumberOfEnchantments { get; set; }
public List<Enchantment> Enchantments { get; set; } = new();
public bool ShowTooltip { get; set; }
public override void Parse(Queue<byte> data)
{
NumberOfEnchantments = dataTypes.ReadNextVarInt(data);
for (var i = 0; i < NumberOfEnchantments; i++)
Enchantments.Add(new Enchantment((Enchantments)dataTypes.ReadNextVarInt(data), dataTypes.ReadNextVarInt(data)));
ShowTooltip = dataTypes.ReadNextBool(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Enchantments.Count));
foreach (var enchantment in Enchantments)
{
data.AddRange(DataTypes.GetVarInt((int)enchantment.Type));
data.AddRange(DataTypes.GetVarInt(enchantment.Level));
}
data.AddRange(DataTypes.GetBool(ShowTooltip));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,5 @@
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class HideAdditionalTooltipComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : EmptyComponent(dataTypes, subComponentRegistry);

View file

@ -0,0 +1,5 @@
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class HideTooltipComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : EmptyComponent(dataTypes, subComponentRegistry);

View file

@ -0,0 +1,22 @@
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class ItemNameComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public string ItemName { get; set; } = string.Empty;
public override void Parse(Queue<byte> data)
{
ItemName = ChatParser.ParseText(dataTypes.ReadNextString(data));
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetString(ItemName));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,34 @@
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class LoreNameComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public int NumberOfLines { get; set; }
public List<string> Lines { get; set; } = [];
public override void Parse(Queue<byte> data)
{
NumberOfLines = dataTypes.ReadNextVarInt(data);
if (NumberOfLines <= 0) return;
for (var i = 0; i < NumberOfLines; i++)
Lines.Add(ChatParser.ParseText(dataTypes.ReadNextString(data)));
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Lines.Count));
if (Lines.Count <= 0) return new Queue<byte>(data);
foreach (var line in Lines)
data.AddRange(DataTypes.GetString(line));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,21 @@
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class MaxDamageComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public int MaxDamage { get; set; }
public override void Parse(Queue<byte> data)
{
MaxDamage = dataTypes.ReadNextVarInt(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(MaxDamage));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,21 @@
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class MaxStackSizeComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public int MaxStackSize { get; set; }
public override void Parse(Queue<byte> data)
{
MaxStackSize = dataTypes.ReadNextVarInt(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(MaxStackSize));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,22 @@
using System.Collections.Generic;
using MinecraftClient.Inventory;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class RarityComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public ItemRarity Rarity { get; set; }
public override void Parse(Queue<byte> data)
{
Rarity = (ItemRarity)dataTypes.ReadNextVarInt(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt((int)Rarity));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,21 @@
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
public class UnbrekableComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public bool Unbrekable { get; set; }
public override void Parse(Queue<byte> data)
{
Unbrekable = dataTypes.ReadNextBool(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetBool(Unbrekable));
return new Queue<byte>(data);
}
}

View file

@ -1,19 +1,16 @@
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components;
public class TestSubComonent(DataTypes dataTypes) : SubComponent(dataTypes)
public class EmptyComponent(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public int Test { get; set; }
public override void Parse(Queue<byte> data)
{
Test = DataTypes.ReadNextVarInt(data);
}
public override Queue<byte> Serialize()
{
throw new System.NotImplementedException();
return new Queue<byte>();
}
}

View file

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents._1_20_6;
public class AttributeSubComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : SubComponent(dataTypes, subComponentRegistry)
{
public int TypeId { get; set; }
public Guid Uuid { get; set; }
public string? Name { get; set; }
public double Value { get; set; }
public int Operation { get; set; }
public int Slot { get; set; }
protected override void Parse(Queue<byte> data)
{
TypeId = dataTypes.ReadNextVarInt(data);
Uuid = dataTypes.ReadNextUUID(data);
Name = dataTypes.ReadNextString(data);
Value = dataTypes.ReadNextDouble(data);
Operation = dataTypes.ReadNextVarInt(data);
Slot = dataTypes.ReadNextVarInt(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(TypeId));
data.AddRange(DataTypes.GetUUID(Uuid));
if (string.IsNullOrEmpty(Name?.Trim()))
throw new ArgumentNullException($"Can not serialize AttributeSubComponent due to Name being null or empty!");
data.AddRange(DataTypes.GetString(Name));
data.AddRange(DataTypes.GetDouble(Value));
data.AddRange(DataTypes.GetVarInt(Operation));
data.AddRange(DataTypes.GetVarInt(Slot));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents._1_20_6;
public class BlockPredicateSubcomponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : SubComponent(dataTypes, subComponentRegistry)
{
public bool HasBlocks { get; set; }
public BlockSetSubcomponent1206? BlockSet { get; set; }
public bool HasProperities { get; set; }
public List<PropertySubComponent1206>? Properties { get; set; }
public bool HasNbt { get; set; }
public Dictionary<string, object>? Nbt { get; set; }
protected override void Parse(Queue<byte> data)
{
HasBlocks = dataTypes.ReadNextBool(data);
if (HasBlocks)
BlockSet = (BlockSetSubcomponent1206)subComponentRegistry.ParseSubComponent(SubComponents.BlockSet, data);
HasProperities = dataTypes.ReadNextBool(data);
if (HasProperities)
{
Properties = new();
var numberOfProperties = dataTypes.ReadNextVarInt(data);
for (var i = 0; i < numberOfProperties; i++)
Properties.Add((PropertySubComponent1206)subComponentRegistry.ParseSubComponent(SubComponents.Property, data));
}
HasNbt = dataTypes.ReadNextBool(data);
if (HasNbt)
Nbt = dataTypes.ReadNextNbt(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
// Block Sets
data.AddRange(DataTypes.GetBool(HasBlocks));
if (HasBlocks)
{
if(BlockSet == null)
throw new ArgumentNullException($"Can not serialize a BlockPredicate when the BlockSet is empty but HasBlocks is true!");
data.AddRange(BlockSet.Serialize());
}
// Properites
data.AddRange(DataTypes.GetBool(HasProperities));
if (HasProperities)
{
if(Properties == null || Properties.Count == 0)
throw new ArgumentNullException($"Can not serialize a BlockPredicate when the Properties is empty but HasProperties is true!");
foreach (var property in Properties)
data.AddRange(property.Serialize());
}
// NBT
if (HasNbt)
{
if(Nbt == null)
throw new ArgumentNullException($"Can not serialize a BlockPredicate when the Nbt is empty but HasNbt is true!");
data.AddRange(DataTypes.GetNbt(Nbt));
}
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents._1_20_6;
public class BlockSetSubcomponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : SubComponent(dataTypes, subComponentRegistry)
{
public int Type { get; set; }
public string? TagName { get; set; }
public List<int>? BlockIds { get; set; }
protected override void Parse(Queue<byte> data)
{
Type = DataTypes.ReadNextVarInt(data);
if (Type == 0)
TagName = dataTypes.ReadNextString(data);
if (Type == 0) return;
BlockIds = [];
for (var i = 0; i < Type - 1; i++)
BlockIds.Add(dataTypes.ReadNextVarInt(data));
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Type));
if (Type == 0)
{
if (string.IsNullOrEmpty(TagName?.Trim()))
throw new ArgumentNullException($"Can not serialize an empty tag name when the Block Set type is 0!");
data.AddRange(DataTypes.GetString(TagName));
}
if (Type == 0) return new Queue<byte>(data);
if(BlockIds == null || BlockIds.Count == 0)
throw new ArgumentNullException($"Can not serialize an empty list of Block IDs in a Block Set when the type is not 0!");
for(var i = 0; i < Type - 1; i++)
data.AddRange(DataTypes.GetVarInt(BlockIds[i]));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents._1_20_6;
public class PropertySubComponent1206(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : SubComponent(dataTypes, subComponentRegistry)
{
public string? Name { get; set; }
public bool IsExactMatch { get; set; }
public string? ExactValue { get; set; }
public string? MinValue { get; set; }
public string? MaxValue { get; set; }
protected override void Parse(Queue<byte> data)
{
Name = dataTypes.ReadNextString(data);
IsExactMatch = dataTypes.ReadNextBool(data);
if (IsExactMatch)
ExactValue = dataTypes.ReadNextString(data);
else // Ranged Match
{
MinValue = dataTypes.ReadNextString(data);
MaxValue = dataTypes.ReadNextString(data);
}
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
if (string.IsNullOrEmpty(Name?.Trim()))
throw new ArgumentNullException($"Can not serialize a Property sub-component if the Name is null or empty!");
data.AddRange(DataTypes.GetString(Name));
data.AddRange(DataTypes.GetBool(IsExactMatch));
if (IsExactMatch)
{
if (string.IsNullOrEmpty(ExactValue?.Trim()))
throw new ArgumentNullException($"Can not serialize a Property sub-component if the ExactValue is null or empty when the type is Exact Match!");
data.AddRange(DataTypes.GetString(ExactValue));
}
else
{
if (string.IsNullOrEmpty(MinValue?.Trim()) || string.IsNullOrEmpty(MaxValue?.Trim()))
throw new ArgumentNullException($"Can not serialize a Property sub-component if the MinValue or MaxValue is null or empty when the type is not Exact Match!");
data.AddRange(DataTypes.GetString(MinValue));
data.AddRange(DataTypes.GetString(MaxValue));
}
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,9 @@
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents;
public class SubComponents
{
public const string BlockPredicate = "BlockPredicate";
public const string BlockSet = "BlockSet";
public const string Property = "Property";
public const string Attribute = "Attribute";
}

View file

@ -1,29 +0,0 @@
using System.Collections.Generic;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components;
public class TestComponent(DataTypes dataTypes, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, subComponentRegistry)
{
public int TestInt { get; set; }
public string TestString { get; set; } = null!;
public TestSubComonent TestSubComonent { get; set; } = null!;
public override void Parse(Queue<byte> data)
{
TestInt = dataTypes.ReadNextVarInt(data);
TestString = dataTypes.ReadNextString(data);
TestSubComonent = (SubComponentRegistry.ParseSubComponent("TestSubComponent", data) as TestSubComonent)!;
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(TestInt));
data.AddRange(DataTypes.GetString(TestString));
data.AddRange(TestSubComonent.Serialize());
return new Queue<byte>(data);
}
}

View file

@ -2,10 +2,11 @@ using System.Collections.Generic;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
public abstract class SubComponent(DataTypes dataTypes)
public abstract class SubComponent(DataTypes dataTypes, SubComponentRegistry subComponentRegistry)
{
protected DataTypes DataTypes { get; private set; } = dataTypes;
protected SubComponentRegistry SubComponentRegistry { get; private set; } = subComponentRegistry;
public abstract void Parse(Queue<byte> data);
protected abstract void Parse(Queue<byte> data);
public abstract Queue<byte> Serialize();
}

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
@ -20,10 +21,15 @@ public abstract class SubComponentRegistry(DataTypes dataTypes)
if(!_subComponentParsers.TryGetValue(name, out var subComponentParserType))
throw new Exception($"Sub component {name} not registered!");
var instance= Activator.CreateInstance(subComponentParserType, dataTypes) as SubComponent ??
var instance= Activator.CreateInstance(subComponentParserType, dataTypes, this) as SubComponent ??
throw new InvalidOperationException($"Could not create instance of a sub component parser type: {subComponentParserType.Name}");
instance.Parse(data);
var parseMethod = instance.GetType().GetMethod("Parse", BindingFlags.Instance | BindingFlags.NonPublic);
if (parseMethod == null)
throw new InvalidOperationException($"Sub component parser type {subComponentParserType.Name} does not have a Parse method.");
parseMethod.Invoke(instance, new object[] { data });
return instance;
}
}

View file

@ -1,4 +1,4 @@
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Registries;
@ -8,6 +8,21 @@ public class StructuredComponentsRegistry1206 : StructuredComponentRegistry
public StructuredComponentsRegistry1206(SubComponentRegistry subComponentRegistry, DataTypes dataTypes) : base(
subComponentRegistry, dataTypes)
{
RegisterComponent<TestComponent>(0, "minecraft:test");
RegisterComponent<CustomDataComponent1206>(0, "minecraft:custom_data");
RegisterComponent<MaxStackSizeComponent1206>(1, "minecraft:max_stack_size");
RegisterComponent<MaxDamageComponent1206>(2, "minecraft:max_damage");
RegisterComponent<DamageComponent1206>(3, "minecraft:damage");
RegisterComponent<UnbrekableComponent1206>(4, "minecraft:unbreakable");
RegisterComponent<CustomNameComponent1206>(5, "minecraft:custom_name");
RegisterComponent<ItemNameComponent1206>(6, "minecraft:item_name");
RegisterComponent<LoreNameComponent1206>(7, "minecraft:lore");
RegisterComponent<RarityComponent1206>(8, "minecraft:rarity");
RegisterComponent<EnchantmentsComponent1206>(9, "minecraft:enchantments");
RegisterComponent<CanPlaceOnComponent1206>(10, "minecraft:can_place_on");
RegisterComponent<CanBreakComponent1206>(11, "minecraft:can_break");
RegisterComponent<AttributeModifiersComponent1206>(12, "minecraft:attribute_modifiers");
RegisterComponent<CustomModelDataComponent1206>(13, "minecraft:custom_model_data");
RegisterComponent<HideAdditionalTooltipComponent1206>(14, "minecraft:hide_additional_tooltip");
RegisterComponent<HideTooltipComponent1206>(15, "minecraft:hide_tooltip");
}
}

View file

@ -0,0 +1,16 @@
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.Registries.Subcomponents;
public class SubComponentRegistry1206 : SubComponentRegistry
{
public SubComponentRegistry1206(DataTypes dataTypes) : base(dataTypes)
{
RegisterSubComponent<BlockPredicateSubcomponent1206>(SubComponents.BlockPredicate);
RegisterSubComponent<BlockSetSubcomponent1206>(SubComponents.BlockSet);
RegisterSubComponent<PropertySubComponent1206>(SubComponents.Property);
RegisterSubComponent<AttributeSubComponent1206>(SubComponents.Attribute);
}
}

View file

@ -1,12 +0,0 @@
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Registries.Subcomponents;
public class TestSubComponentRegistry : SubComponentRegistry
{
public TestSubComponentRegistry(DataTypes dataTypes) : base(dataTypes)
{
RegisterSubComponent<TestSubComonent>("TestSubcomponent");
}
}

View file

@ -18,7 +18,7 @@ public class StructuredComponentsHandler
// Get the appropriate subcomponent registry type based on the protocol version and then instantiate it
var subcomponentRegistryType = protocolVersion switch
{
Protocol18Handler.MC_1_20_6_Version => typeof(TestSubComponentRegistry),
Protocol18Handler.MC_1_20_6_Version => typeof(SubComponentRegistry1206),
_ => throw new NotSupportedException($"Protocol version {protocolVersion} is not supported for subcomponent registries!")
};

View file

@ -400,9 +400,9 @@ namespace MinecraftClient.Scripting
/// <param name="middleEnchantmentLevelRequirement">Levels required by player for the enchantment in the middle slot</param>
/// <param name="bottomEnchantmentLevelRequirement">Levels required by player for the enchantment in the bottom slot</param>
public virtual void OnEnchantments(
Enchantment topEnchantment,
Enchantment middleEnchantment,
Enchantment bottomEnchantment,
Enchantments topEnchantment,
Enchantments middleEnchantment,
Enchantments bottomEnchantment,
short topEnchantmentLevel,
short middleEnchantmentLevel,
short bottomEnchantmentLevel,