Fixed the component system from 1.20.6 - 1.21.11

This commit is contained in:
Anon 2026-03-25 01:08:27 +01:00
parent 6f30f9b79a
commit 17808bb652
17 changed files with 749 additions and 25 deletions

View file

@ -6,17 +6,47 @@ namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_2
public class CustomModelDataComponent(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry) : StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int Value { get; set; }
public List<float> Floats { get; set; } = [];
public List<bool> Flags { get; set; } = [];
public List<string> Strings { get; set; } = [];
public List<int> Colors { get; set; } = [];
public override void Parse(Queue<byte> data)
{
Value = DataTypes.ReadNextVarInt(data);
Floats = ReadList(data, static (dataTypes, componentData) => dataTypes.ReadNextFloat(componentData));
Flags = ReadList(data, static (dataTypes, componentData) => dataTypes.ReadNextBool(componentData));
Strings = ReadList(data, static (dataTypes, componentData) => dataTypes.ReadNextString(componentData));
Colors = ReadList(data, static (dataTypes, componentData) => dataTypes.ReadNextInt(componentData));
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Value));
WriteList(data, Floats, static (dataTypes, value) => dataTypes.GetFloat(value));
WriteList(data, Flags, static (dataTypes, value) => dataTypes.GetBool(value));
WriteList(data, Strings, static (dataTypes, value) => dataTypes.GetString(value));
WriteList(data, Colors, static (_, value) => DataTypes.GetInt(value));
return new Queue<byte>(data);
}
}
private List<T> ReadList<T>(Queue<byte> data, ReadDelegate<T> read)
{
var count = DataTypes.ReadNextVarInt(data);
var values = new List<T>(count);
for (var i = 0; i < count; i++)
values.Add(read(DataTypes, data));
return values;
}
private void WriteList<T>(List<byte> data, List<T> values, WriteDelegate<T> write)
{
data.AddRange(DataTypes.GetVarInt(values.Count));
foreach (var value in values)
data.AddRange(write(DataTypes, value));
}
private delegate T ReadDelegate<out T>(DataTypes dataTypes, Queue<byte> data);
private delegate byte[] WriteDelegate<in T>(DataTypes dataTypes, T value);
}

View file

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

View file

@ -0,0 +1,81 @@
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_21;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21;
public class JukeBoxPlayableComponent121(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public bool IsHolder { get; set; }
public int HolderId { get; set; }
public string? ResourceKey { get; set; }
public SoundEventSubComponent? SoundEvent { get; set; }
public Dictionary<string, object>? DescriptionNbt { get; set; }
public string Description { get; set; } = string.Empty;
public float Duration { get; set; }
public int ComparatorOutput { get; set; }
public bool ShowTooltip { get; set; }
public override void Parse(Queue<byte> data)
{
IsHolder = DataTypes.ReadNextBool(data);
if (IsHolder)
{
HolderId = DataTypes.ReadNextVarInt(data);
if (HolderId == 0)
{
SoundEvent = (SoundEventSubComponent)SubComponentRegistry.ParseSubComponent(SubComponents.SoundEvent, data);
DescriptionNbt = DataTypes.ReadNextNbt(data);
Description = ChatParser.ParseText(DescriptionNbt);
Duration = DataTypes.ReadNextFloat(data);
ComparatorOutput = DataTypes.ReadNextVarInt(data);
}
}
else
{
ResourceKey = DataTypes.ReadNextString(data);
}
ShowTooltip = DataTypes.ReadNextBool(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetBool(IsHolder));
if (IsHolder)
{
data.AddRange(DataTypes.GetVarInt(HolderId));
if (HolderId == 0)
{
if (SoundEvent is null)
throw new ArgumentNullException(nameof(SoundEvent), "Inline jukebox song requires a sound event.");
if (DescriptionNbt is null)
throw new ArgumentNullException(nameof(DescriptionNbt), "Inline jukebox song requires a description.");
data.AddRange(SoundEvent.Serialize());
data.AddRange(DataTypes.GetNbt(DescriptionNbt));
data.AddRange(DataTypes.GetFloat(Duration));
data.AddRange(DataTypes.GetVarInt(ComparatorOutput));
}
}
else
{
if (string.IsNullOrEmpty(ResourceKey))
throw new ArgumentNullException(nameof(ResourceKey), "Resource key is required for key-backed jukebox songs.");
data.AddRange(DataTypes.GetString(ResourceKey));
}
data.AddRange(DataTypes.GetBool(ShowTooltip));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,61 @@
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_21_2;
public class PotionContentsComponent1212(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public bool HasPotionId { get; set; }
public int PotionId { get; set; }
public bool HasCustomColor { get; set; }
public int CustomColor { get; set; }
public List<PotionEffectSubComponent> Effects { get; set; } = [];
public bool HasCustomName { get; set; }
public string? CustomName { get; set; }
public override void Parse(Queue<byte> data)
{
HasPotionId = DataTypes.ReadNextBool(data);
if (HasPotionId)
PotionId = DataTypes.ReadNextVarInt(data);
HasCustomColor = DataTypes.ReadNextBool(data);
if (HasCustomColor)
CustomColor = DataTypes.ReadNextInt(data);
var numberOfEffects = DataTypes.ReadNextVarInt(data);
Effects = new List<PotionEffectSubComponent>(numberOfEffects);
for (var i = 0; i < numberOfEffects; i++)
Effects.Add((PotionEffectSubComponent)SubComponentRegistry.ParseSubComponent(SubComponents.PotionEffect, data));
HasCustomName = DataTypes.ReadNextBool(data);
if (HasCustomName)
CustomName = DataTypes.ReadNextString(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetBool(HasPotionId));
if (HasPotionId)
data.AddRange(DataTypes.GetVarInt(PotionId));
data.AddRange(DataTypes.GetBool(HasCustomColor));
if (HasCustomColor)
data.AddRange(DataTypes.GetInt(CustomColor));
data.AddRange(DataTypes.GetVarInt(Effects.Count));
foreach (var effect in Effects)
data.AddRange(effect.Serialize());
data.AddRange(DataTypes.GetBool(HasCustomName));
if (HasCustomName && CustomName is not null)
data.AddRange(DataTypes.GetString(CustomName));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_5;
public class AttributeModifiersComponent1215(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int NumberOfAttributes { get; set; }
public List<SubComponent> Attributes { get; set; } = [];
public override void Parse(Queue<byte> data)
{
NumberOfAttributes = DataTypes.ReadNextVarInt(data);
Attributes = new List<SubComponent>(NumberOfAttributes);
for (var i = 0; i < NumberOfAttributes; i++)
Attributes.Add(SubComponentRegistry.ParseSubComponent(SubComponents.Attribute, data));
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(NumberOfAttributes));
if (Attributes.Count != NumberOfAttributes)
throw new ArgumentNullException(nameof(Attributes), "Attributes count must match NumberOfAttributes.");
foreach (var attribute in Attributes)
data.AddRange(attribute.Serialize());
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,104 @@
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_21;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_5;
public class EquippableComponent1215(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int Slot { get; set; }
public SoundEventSubComponent? EquipSound { get; set; }
public bool HasAssetId { get; set; }
public string? AssetId { get; set; }
public bool HasCameraOverlay { get; set; }
public string? CameraOverlay { get; set; }
public bool HasAllowedEntities { get; set; }
public int AllowedEntitiesType { get; set; }
public string? AllowedEntitiesTag { get; set; }
public List<int>? AllowedEntitiesIds { get; set; }
public bool Dispensable { get; set; }
public bool Swappable { get; set; }
public bool DamageOnHurt { get; set; }
public bool EquipOnInteract { get; set; }
public override void Parse(Queue<byte> data)
{
Slot = DataTypes.ReadNextVarInt(data);
EquipSound = (SoundEventSubComponent)SubComponentRegistry.ParseSubComponent(SubComponents.SoundEvent, data);
HasAssetId = DataTypes.ReadNextBool(data);
if (HasAssetId)
AssetId = DataTypes.ReadNextString(data);
HasCameraOverlay = DataTypes.ReadNextBool(data);
if (HasCameraOverlay)
CameraOverlay = DataTypes.ReadNextString(data);
HasAllowedEntities = DataTypes.ReadNextBool(data);
if (HasAllowedEntities)
{
AllowedEntitiesType = DataTypes.ReadNextVarInt(data);
if (AllowedEntitiesType == 0)
{
AllowedEntitiesTag = DataTypes.ReadNextString(data);
AllowedEntitiesIds = null;
}
else
{
AllowedEntitiesTag = null;
AllowedEntitiesIds = new List<int>(Math.Max(AllowedEntitiesType - 1, 0));
for (var i = 0; i < AllowedEntitiesType - 1; i++)
AllowedEntitiesIds.Add(DataTypes.ReadNextVarInt(data));
}
}
Dispensable = DataTypes.ReadNextBool(data);
Swappable = DataTypes.ReadNextBool(data);
DamageOnHurt = DataTypes.ReadNextBool(data);
EquipOnInteract = DataTypes.ReadNextBool(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Slot));
if (EquipSound is null)
throw new ArgumentNullException(nameof(EquipSound), "EquipSound is required.");
data.AddRange(EquipSound.Serialize());
data.AddRange(DataTypes.GetBool(HasAssetId));
if (HasAssetId && AssetId is not null)
data.AddRange(DataTypes.GetString(AssetId));
data.AddRange(DataTypes.GetBool(HasCameraOverlay));
if (HasCameraOverlay && CameraOverlay is not null)
data.AddRange(DataTypes.GetString(CameraOverlay));
data.AddRange(DataTypes.GetBool(HasAllowedEntities));
if (HasAllowedEntities)
{
data.AddRange(DataTypes.GetVarInt(AllowedEntitiesType));
if (AllowedEntitiesType == 0 && AllowedEntitiesTag is not null)
{
data.AddRange(DataTypes.GetString(AllowedEntitiesTag));
}
else if (AllowedEntitiesIds is not null)
{
foreach (var id in AllowedEntitiesIds)
data.AddRange(DataTypes.GetVarInt(id));
}
}
data.AddRange(DataTypes.GetBool(Dispensable));
data.AddRange(DataTypes.GetBool(Swappable));
data.AddRange(DataTypes.GetBool(DamageOnHurt));
data.AddRange(DataTypes.GetBool(EquipOnInteract));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,77 @@
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_21;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_5;
public class JukeBoxPlayableComponent1215(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public bool IsHolder { get; set; }
public int HolderId { get; set; }
public string? ResourceKey { get; set; }
public SoundEventSubComponent? SoundEvent { get; set; }
public Dictionary<string, object>? DescriptionNbt { get; set; }
public string Description { get; set; } = string.Empty;
public float Duration { get; set; }
public int ComparatorOutput { get; set; }
public override void Parse(Queue<byte> data)
{
IsHolder = DataTypes.ReadNextBool(data);
if (IsHolder)
{
HolderId = DataTypes.ReadNextVarInt(data);
if (HolderId == 0)
{
SoundEvent = (SoundEventSubComponent)SubComponentRegistry.ParseSubComponent(SubComponents.SoundEvent, data);
DescriptionNbt = DataTypes.ReadNextNbt(data);
Description = ChatParser.ParseText(DescriptionNbt);
Duration = DataTypes.ReadNextFloat(data);
ComparatorOutput = DataTypes.ReadNextVarInt(data);
}
}
else
{
ResourceKey = DataTypes.ReadNextString(data);
}
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetBool(IsHolder));
if (IsHolder)
{
data.AddRange(DataTypes.GetVarInt(HolderId));
if (HolderId == 0)
{
if (SoundEvent is null)
throw new ArgumentNullException(nameof(SoundEvent), "Inline jukebox song requires a sound event.");
if (DescriptionNbt is null)
throw new ArgumentNullException(nameof(DescriptionNbt), "Inline jukebox song requires a description.");
data.AddRange(SoundEvent.Serialize());
data.AddRange(DataTypes.GetNbt(DescriptionNbt));
data.AddRange(DataTypes.GetFloat(Duration));
data.AddRange(DataTypes.GetVarInt(ComparatorOutput));
}
}
else
{
if (string.IsNullOrEmpty(ResourceKey))
throw new ArgumentNullException(nameof(ResourceKey), "Resource key is required for key-backed jukebox songs.");
data.AddRange(DataTypes.GetString(ResourceKey));
}
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,48 @@
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_21_5;
public class ToolComponent1215(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int NumberOfRules { get; set; }
public List<RuleSubComponent> Rules { get; set; } = [];
public float DefaultMiningSpeed { get; set; }
public int DamagePerBlock { get; set; }
public bool CanDestroyBlocksInCreative { get; set; }
public override void Parse(Queue<byte> data)
{
NumberOfRules = DataTypes.ReadNextVarInt(data);
Rules = new List<RuleSubComponent>(NumberOfRules);
for (var i = 0; i < NumberOfRules; i++)
Rules.Add((RuleSubComponent)SubComponentRegistry.ParseSubComponent(SubComponents.Rule, data));
DefaultMiningSpeed = DataTypes.ReadNextFloat(data);
DamagePerBlock = DataTypes.ReadNextVarInt(data);
CanDestroyBlocksInCreative = DataTypes.ReadNextBool(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(NumberOfRules));
if (Rules.Count != NumberOfRules)
throw new ArgumentNullException(nameof(Rules), "Rules count must match NumberOfRules.");
foreach (var rule in Rules)
data.AddRange(rule.Serialize());
data.AddRange(DataTypes.GetFloat(DefaultMiningSpeed));
data.AddRange(DataTypes.GetVarInt(DamagePerBlock));
data.AddRange(DataTypes.GetBool(CanDestroyBlocksInCreative));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.IO;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_8;
public class AttributeModifiersComponent1218(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int NumberOfAttributes { get; set; }
public List<SubComponent> Attributes { get; set; } = [];
public List<AttributeModifierDisplay> Displays { get; set; } = [];
public override void Parse(Queue<byte> data)
{
NumberOfAttributes = DataTypes.ReadNextVarInt(data);
Attributes = new List<SubComponent>(NumberOfAttributes);
Displays = new List<AttributeModifierDisplay>(NumberOfAttributes);
for (var i = 0; i < NumberOfAttributes; i++)
{
Attributes.Add(SubComponentRegistry.ParseSubComponent(SubComponents.Attribute, data));
Displays.Add(ReadDisplay(data));
}
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(NumberOfAttributes));
if (Attributes.Count != NumberOfAttributes)
throw new ArgumentNullException(nameof(Attributes), "Attributes count must match NumberOfAttributes.");
if (Displays.Count != NumberOfAttributes)
throw new ArgumentNullException(nameof(Displays), "Displays count must match NumberOfAttributes.");
for (var i = 0; i < NumberOfAttributes; i++)
{
data.AddRange(Attributes[i].Serialize());
data.AddRange(SerializeDisplay(Displays[i]));
}
return new Queue<byte>(data);
}
private AttributeModifierDisplay ReadDisplay(Queue<byte> data)
{
var displayType = DataTypes.ReadNextVarInt(data);
return displayType switch
{
0 => new AttributeModifierDisplay(AttributeModifierDisplayType.Default),
1 => new AttributeModifierDisplay(AttributeModifierDisplayType.Hidden),
2 => ReadOverrideDisplay(data),
_ => throw new InvalidDataException($"Unknown attribute modifier display type: {displayType}")
};
}
private AttributeModifierDisplay ReadOverrideDisplay(Queue<byte> data)
{
var overrideTextNbt = DataTypes.ReadNextNbt(data);
var overrideText = ChatParser.ParseText(overrideTextNbt);
return new AttributeModifierDisplay(AttributeModifierDisplayType.Override, overrideTextNbt, overrideText);
}
private Queue<byte> SerializeDisplay(AttributeModifierDisplay display)
{
var data = new List<byte>
{
};
data.AddRange(DataTypes.GetVarInt((int)display.Type));
if (display.Type == AttributeModifierDisplayType.Override)
{
if (display.OverrideTextNbt is null)
throw new ArgumentNullException(nameof(display.OverrideTextNbt), "Override display requires component NBT.");
data.AddRange(DataTypes.GetNbt(display.OverrideTextNbt));
}
return new Queue<byte>(data);
}
}
public sealed record AttributeModifierDisplay(
AttributeModifierDisplayType Type,
Dictionary<string, object>? OverrideTextNbt = null,
string? OverrideText = null);
public enum AttributeModifierDisplayType
{
Default = 0,
Hidden = 1,
Override = 2
}

View file

@ -0,0 +1,113 @@
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_21;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_8;
public class EquippableComponent1218(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int Slot { get; set; }
public SoundEventSubComponent? EquipSound { get; set; }
public bool HasAssetId { get; set; }
public string? AssetId { get; set; }
public bool HasCameraOverlay { get; set; }
public string? CameraOverlay { get; set; }
public bool HasAllowedEntities { get; set; }
public int AllowedEntitiesType { get; set; }
public string? AllowedEntitiesTag { get; set; }
public List<int>? AllowedEntitiesIds { get; set; }
public bool Dispensable { get; set; }
public bool Swappable { get; set; }
public bool DamageOnHurt { get; set; }
public bool EquipOnInteract { get; set; }
public bool CanBeSheared { get; set; }
public SoundEventSubComponent? ShearingSound { get; set; }
public override void Parse(Queue<byte> data)
{
Slot = DataTypes.ReadNextVarInt(data);
EquipSound = (SoundEventSubComponent)SubComponentRegistry.ParseSubComponent(SubComponents.SoundEvent, data);
HasAssetId = DataTypes.ReadNextBool(data);
if (HasAssetId)
AssetId = DataTypes.ReadNextString(data);
HasCameraOverlay = DataTypes.ReadNextBool(data);
if (HasCameraOverlay)
CameraOverlay = DataTypes.ReadNextString(data);
HasAllowedEntities = DataTypes.ReadNextBool(data);
if (HasAllowedEntities)
{
AllowedEntitiesType = DataTypes.ReadNextVarInt(data);
if (AllowedEntitiesType == 0)
{
AllowedEntitiesTag = DataTypes.ReadNextString(data);
AllowedEntitiesIds = null;
}
else
{
AllowedEntitiesTag = null;
AllowedEntitiesIds = new List<int>(Math.Max(AllowedEntitiesType - 1, 0));
for (var i = 0; i < AllowedEntitiesType - 1; i++)
AllowedEntitiesIds.Add(DataTypes.ReadNextVarInt(data));
}
}
Dispensable = DataTypes.ReadNextBool(data);
Swappable = DataTypes.ReadNextBool(data);
DamageOnHurt = DataTypes.ReadNextBool(data);
EquipOnInteract = DataTypes.ReadNextBool(data);
CanBeSheared = DataTypes.ReadNextBool(data);
ShearingSound = (SoundEventSubComponent)SubComponentRegistry.ParseSubComponent(SubComponents.SoundEvent, data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Slot));
if (EquipSound is null)
throw new ArgumentNullException(nameof(EquipSound), "EquipSound is required.");
if (ShearingSound is null)
throw new ArgumentNullException(nameof(ShearingSound), "ShearingSound is required.");
data.AddRange(EquipSound.Serialize());
data.AddRange(DataTypes.GetBool(HasAssetId));
if (HasAssetId && AssetId is not null)
data.AddRange(DataTypes.GetString(AssetId));
data.AddRange(DataTypes.GetBool(HasCameraOverlay));
if (HasCameraOverlay && CameraOverlay is not null)
data.AddRange(DataTypes.GetString(CameraOverlay));
data.AddRange(DataTypes.GetBool(HasAllowedEntities));
if (HasAllowedEntities)
{
data.AddRange(DataTypes.GetVarInt(AllowedEntitiesType));
if (AllowedEntitiesType == 0 && AllowedEntitiesTag is not null)
{
data.AddRange(DataTypes.GetString(AllowedEntitiesTag));
}
else if (AllowedEntitiesIds is not null)
{
foreach (var id in AllowedEntitiesIds)
data.AddRange(DataTypes.GetVarInt(id));
}
}
data.AddRange(DataTypes.GetBool(Dispensable));
data.AddRange(DataTypes.GetBool(Swappable));
data.AddRange(DataTypes.GetBool(DamageOnHurt));
data.AddRange(DataTypes.GetBool(EquipOnInteract));
data.AddRange(DataTypes.GetBool(CanBeSheared));
data.AddRange(ShearingSound.Serialize());
return new Queue<byte>(data);
}
}