// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.protocol;

import java.util.Objects;
import com.hypixel.hytale.protocol.io.ValidationResult;
import java.util.Arrays;
import java.util.Iterator;
import java.util.HashMap;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.VarInt;
import com.hypixel.hytale.protocol.io.PacketIO;
import io.netty.buffer.ByteBuf;
import javax.annotation.Nonnull;
import java.util.Map;
import javax.annotation.Nullable;

public class ItemBase
{
    public static final int NULLABLE_BIT_FIELD_SIZE = 4;
    public static final int FIXED_BLOCK_SIZE = 147;
    public static final int VARIABLE_FIELD_COUNT = 26;
    public static final int VARIABLE_BLOCK_START = 251;
    public static final int MAX_SIZE = 1677721600;
    @Nullable
    public String id;
    @Nullable
    public String model;
    public float scale;
    @Nullable
    public String texture;
    @Nullable
    public String animation;
    @Nullable
    public String playerAnimationsId;
    public boolean usePlayerAnimations;
    public int maxStack;
    public int reticleIndex;
    @Nullable
    public String icon;
    @Nullable
    public AssetIconProperties iconProperties;
    @Nullable
    public ItemTranslationProperties translationProperties;
    public int itemLevel;
    public int qualityIndex;
    @Nullable
    public ItemResourceType[] resourceTypes;
    public boolean consumable;
    public boolean variant;
    public int blockId;
    @Nullable
    public ItemTool tool;
    @Nullable
    public ItemWeapon weapon;
    @Nullable
    public ItemArmor armor;
    @Nullable
    public ItemGlider gliderConfig;
    @Nullable
    public ItemUtility utility;
    @Nullable
    public BlockSelectorToolData blockSelectorTool;
    @Nullable
    public ItemBuilderToolData builderToolData;
    @Nullable
    public ItemEntityConfig itemEntity;
    @Nullable
    public String set;
    @Nullable
    public String[] categories;
    @Nullable
    public ModelParticle[] particles;
    @Nullable
    public ModelParticle[] firstPersonParticles;
    @Nullable
    public ModelTrail[] trails;
    @Nullable
    public ColorLight light;
    public double durability;
    public int soundEventIndex;
    public int itemSoundSetIndex;
    @Nullable
    public Map<InteractionType, Integer> interactions;
    @Nullable
    public Map<String, Integer> interactionVars;
    @Nullable
    public InteractionConfiguration interactionConfig;
    @Nullable
    public String droppedItemAnimation;
    @Nullable
    public int[] tagIndexes;
    @Nullable
    public Map<Integer, ItemAppearanceCondition[]> itemAppearanceConditions;
    @Nullable
    public int[] displayEntityStatsHUD;
    @Nullable
    public ItemPullbackConfiguration pullbackConfig;
    public boolean clipsGeometry;
    public boolean renderDeployablePreview;
    
    public ItemBase() {
    }
    
    public ItemBase(@Nullable final String id, @Nullable final String model, final float scale, @Nullable final String texture, @Nullable final String animation, @Nullable final String playerAnimationsId, final boolean usePlayerAnimations, final int maxStack, final int reticleIndex, @Nullable final String icon, @Nullable final AssetIconProperties iconProperties, @Nullable final ItemTranslationProperties translationProperties, final int itemLevel, final int qualityIndex, @Nullable final ItemResourceType[] resourceTypes, final boolean consumable, final boolean variant, final int blockId, @Nullable final ItemTool tool, @Nullable final ItemWeapon weapon, @Nullable final ItemArmor armor, @Nullable final ItemGlider gliderConfig, @Nullable final ItemUtility utility, @Nullable final BlockSelectorToolData blockSelectorTool, @Nullable final ItemBuilderToolData builderToolData, @Nullable final ItemEntityConfig itemEntity, @Nullable final String set, @Nullable final String[] categories, @Nullable final ModelParticle[] particles, @Nullable final ModelParticle[] firstPersonParticles, @Nullable final ModelTrail[] trails, @Nullable final ColorLight light, final double durability, final int soundEventIndex, final int itemSoundSetIndex, @Nullable final Map<InteractionType, Integer> interactions, @Nullable final Map<String, Integer> interactionVars, @Nullable final InteractionConfiguration interactionConfig, @Nullable final String droppedItemAnimation, @Nullable final int[] tagIndexes, @Nullable final Map<Integer, ItemAppearanceCondition[]> itemAppearanceConditions, @Nullable final int[] displayEntityStatsHUD, @Nullable final ItemPullbackConfiguration pullbackConfig, final boolean clipsGeometry, final boolean renderDeployablePreview) {
        this.id = id;
        this.model = model;
        this.scale = scale;
        this.texture = texture;
        this.animation = animation;
        this.playerAnimationsId = playerAnimationsId;
        this.usePlayerAnimations = usePlayerAnimations;
        this.maxStack = maxStack;
        this.reticleIndex = reticleIndex;
        this.icon = icon;
        this.iconProperties = iconProperties;
        this.translationProperties = translationProperties;
        this.itemLevel = itemLevel;
        this.qualityIndex = qualityIndex;
        this.resourceTypes = resourceTypes;
        this.consumable = consumable;
        this.variant = variant;
        this.blockId = blockId;
        this.tool = tool;
        this.weapon = weapon;
        this.armor = armor;
        this.gliderConfig = gliderConfig;
        this.utility = utility;
        this.blockSelectorTool = blockSelectorTool;
        this.builderToolData = builderToolData;
        this.itemEntity = itemEntity;
        this.set = set;
        this.categories = categories;
        this.particles = particles;
        this.firstPersonParticles = firstPersonParticles;
        this.trails = trails;
        this.light = light;
        this.durability = durability;
        this.soundEventIndex = soundEventIndex;
        this.itemSoundSetIndex = itemSoundSetIndex;
        this.interactions = interactions;
        this.interactionVars = interactionVars;
        this.interactionConfig = interactionConfig;
        this.droppedItemAnimation = droppedItemAnimation;
        this.tagIndexes = tagIndexes;
        this.itemAppearanceConditions = itemAppearanceConditions;
        this.displayEntityStatsHUD = displayEntityStatsHUD;
        this.pullbackConfig = pullbackConfig;
        this.clipsGeometry = clipsGeometry;
        this.renderDeployablePreview = renderDeployablePreview;
    }
    
    public ItemBase(@Nonnull final ItemBase other) {
        this.id = other.id;
        this.model = other.model;
        this.scale = other.scale;
        this.texture = other.texture;
        this.animation = other.animation;
        this.playerAnimationsId = other.playerAnimationsId;
        this.usePlayerAnimations = other.usePlayerAnimations;
        this.maxStack = other.maxStack;
        this.reticleIndex = other.reticleIndex;
        this.icon = other.icon;
        this.iconProperties = other.iconProperties;
        this.translationProperties = other.translationProperties;
        this.itemLevel = other.itemLevel;
        this.qualityIndex = other.qualityIndex;
        this.resourceTypes = other.resourceTypes;
        this.consumable = other.consumable;
        this.variant = other.variant;
        this.blockId = other.blockId;
        this.tool = other.tool;
        this.weapon = other.weapon;
        this.armor = other.armor;
        this.gliderConfig = other.gliderConfig;
        this.utility = other.utility;
        this.blockSelectorTool = other.blockSelectorTool;
        this.builderToolData = other.builderToolData;
        this.itemEntity = other.itemEntity;
        this.set = other.set;
        this.categories = other.categories;
        this.particles = other.particles;
        this.firstPersonParticles = other.firstPersonParticles;
        this.trails = other.trails;
        this.light = other.light;
        this.durability = other.durability;
        this.soundEventIndex = other.soundEventIndex;
        this.itemSoundSetIndex = other.itemSoundSetIndex;
        this.interactions = other.interactions;
        this.interactionVars = other.interactionVars;
        this.interactionConfig = other.interactionConfig;
        this.droppedItemAnimation = other.droppedItemAnimation;
        this.tagIndexes = other.tagIndexes;
        this.itemAppearanceConditions = other.itemAppearanceConditions;
        this.displayEntityStatsHUD = other.displayEntityStatsHUD;
        this.pullbackConfig = other.pullbackConfig;
        this.clipsGeometry = other.clipsGeometry;
        this.renderDeployablePreview = other.renderDeployablePreview;
    }
    
    @Nonnull
    public static ItemBase deserialize(@Nonnull final ByteBuf buf, final int offset) {
        final ItemBase obj = new ItemBase();
        final byte[] nullBits = PacketIO.readBytes(buf, offset, 4);
        obj.scale = buf.getFloatLE(offset + 4);
        obj.usePlayerAnimations = (buf.getByte(offset + 8) != 0);
        obj.maxStack = buf.getIntLE(offset + 9);
        obj.reticleIndex = buf.getIntLE(offset + 13);
        if ((nullBits[0] & 0x1) != 0x0) {
            obj.iconProperties = AssetIconProperties.deserialize(buf, offset + 17);
        }
        obj.itemLevel = buf.getIntLE(offset + 42);
        obj.qualityIndex = buf.getIntLE(offset + 46);
        obj.consumable = (buf.getByte(offset + 50) != 0);
        obj.variant = (buf.getByte(offset + 51) != 0);
        obj.blockId = buf.getIntLE(offset + 52);
        if ((nullBits[0] & 0x2) != 0x0) {
            obj.gliderConfig = ItemGlider.deserialize(buf, offset + 56);
        }
        if ((nullBits[0] & 0x4) != 0x0) {
            obj.blockSelectorTool = BlockSelectorToolData.deserialize(buf, offset + 72);
        }
        if ((nullBits[0] & 0x8) != 0x0) {
            obj.light = ColorLight.deserialize(buf, offset + 76);
        }
        obj.durability = buf.getDoubleLE(offset + 80);
        obj.soundEventIndex = buf.getIntLE(offset + 88);
        obj.itemSoundSetIndex = buf.getIntLE(offset + 92);
        if ((nullBits[0] & 0x10) != 0x0) {
            obj.pullbackConfig = ItemPullbackConfiguration.deserialize(buf, offset + 96);
        }
        obj.clipsGeometry = (buf.getByte(offset + 145) != 0);
        obj.renderDeployablePreview = (buf.getByte(offset + 146) != 0);
        if ((nullBits[0] & 0x20) != 0x0) {
            final int varPos0 = offset + 251 + buf.getIntLE(offset + 147);
            final int idLen = VarInt.peek(buf, varPos0);
            if (idLen < 0) {
                throw ProtocolException.negativeLength("Id", idLen);
            }
            if (idLen > 4096000) {
                throw ProtocolException.stringTooLong("Id", idLen, 4096000);
            }
            obj.id = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8);
        }
        if ((nullBits[0] & 0x40) != 0x0) {
            final int varPos2 = offset + 251 + buf.getIntLE(offset + 151);
            final int modelLen = VarInt.peek(buf, varPos2);
            if (modelLen < 0) {
                throw ProtocolException.negativeLength("Model", modelLen);
            }
            if (modelLen > 4096000) {
                throw ProtocolException.stringTooLong("Model", modelLen, 4096000);
            }
            obj.model = PacketIO.readVarString(buf, varPos2, PacketIO.UTF8);
        }
        if ((nullBits[0] & 0x80) != 0x0) {
            final int varPos3 = offset + 251 + buf.getIntLE(offset + 155);
            final int textureLen = VarInt.peek(buf, varPos3);
            if (textureLen < 0) {
                throw ProtocolException.negativeLength("Texture", textureLen);
            }
            if (textureLen > 4096000) {
                throw ProtocolException.stringTooLong("Texture", textureLen, 4096000);
            }
            obj.texture = PacketIO.readVarString(buf, varPos3, PacketIO.UTF8);
        }
        if ((nullBits[1] & 0x1) != 0x0) {
            final int varPos4 = offset + 251 + buf.getIntLE(offset + 159);
            final int animationLen = VarInt.peek(buf, varPos4);
            if (animationLen < 0) {
                throw ProtocolException.negativeLength("Animation", animationLen);
            }
            if (animationLen > 4096000) {
                throw ProtocolException.stringTooLong("Animation", animationLen, 4096000);
            }
            obj.animation = PacketIO.readVarString(buf, varPos4, PacketIO.UTF8);
        }
        if ((nullBits[1] & 0x2) != 0x0) {
            final int varPos5 = offset + 251 + buf.getIntLE(offset + 163);
            final int playerAnimationsIdLen = VarInt.peek(buf, varPos5);
            if (playerAnimationsIdLen < 0) {
                throw ProtocolException.negativeLength("PlayerAnimationsId", playerAnimationsIdLen);
            }
            if (playerAnimationsIdLen > 4096000) {
                throw ProtocolException.stringTooLong("PlayerAnimationsId", playerAnimationsIdLen, 4096000);
            }
            obj.playerAnimationsId = PacketIO.readVarString(buf, varPos5, PacketIO.UTF8);
        }
        if ((nullBits[1] & 0x4) != 0x0) {
            final int varPos6 = offset + 251 + buf.getIntLE(offset + 167);
            final int iconLen = VarInt.peek(buf, varPos6);
            if (iconLen < 0) {
                throw ProtocolException.negativeLength("Icon", iconLen);
            }
            if (iconLen > 4096000) {
                throw ProtocolException.stringTooLong("Icon", iconLen, 4096000);
            }
            obj.icon = PacketIO.readVarString(buf, varPos6, PacketIO.UTF8);
        }
        if ((nullBits[1] & 0x8) != 0x0) {
            final int varPos7 = offset + 251 + buf.getIntLE(offset + 171);
            obj.translationProperties = ItemTranslationProperties.deserialize(buf, varPos7);
        }
        if ((nullBits[1] & 0x10) != 0x0) {
            final int varPos8 = offset + 251 + buf.getIntLE(offset + 175);
            final int resourceTypesCount = VarInt.peek(buf, varPos8);
            if (resourceTypesCount < 0) {
                throw ProtocolException.negativeLength("ResourceTypes", resourceTypesCount);
            }
            if (resourceTypesCount > 4096000) {
                throw ProtocolException.arrayTooLong("ResourceTypes", resourceTypesCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos8);
            if (varPos8 + varIntLen + resourceTypesCount * 5L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("ResourceTypes", varPos8 + varIntLen + resourceTypesCount * 5, buf.readableBytes());
            }
            obj.resourceTypes = new ItemResourceType[resourceTypesCount];
            int elemPos = varPos8 + varIntLen;
            for (int i = 0; i < resourceTypesCount; ++i) {
                obj.resourceTypes[i] = ItemResourceType.deserialize(buf, elemPos);
                elemPos += ItemResourceType.computeBytesConsumed(buf, elemPos);
            }
        }
        if ((nullBits[1] & 0x20) != 0x0) {
            final int varPos9 = offset + 251 + buf.getIntLE(offset + 179);
            obj.tool = ItemTool.deserialize(buf, varPos9);
        }
        if ((nullBits[1] & 0x40) != 0x0) {
            final int varPos10 = offset + 251 + buf.getIntLE(offset + 183);
            obj.weapon = ItemWeapon.deserialize(buf, varPos10);
        }
        if ((nullBits[1] & 0x80) != 0x0) {
            final int varPos11 = offset + 251 + buf.getIntLE(offset + 187);
            obj.armor = ItemArmor.deserialize(buf, varPos11);
        }
        if ((nullBits[2] & 0x1) != 0x0) {
            final int varPos12 = offset + 251 + buf.getIntLE(offset + 191);
            obj.utility = ItemUtility.deserialize(buf, varPos12);
        }
        if ((nullBits[2] & 0x2) != 0x0) {
            final int varPos13 = offset + 251 + buf.getIntLE(offset + 195);
            obj.builderToolData = ItemBuilderToolData.deserialize(buf, varPos13);
        }
        if ((nullBits[2] & 0x4) != 0x0) {
            final int varPos14 = offset + 251 + buf.getIntLE(offset + 199);
            obj.itemEntity = ItemEntityConfig.deserialize(buf, varPos14);
        }
        if ((nullBits[2] & 0x8) != 0x0) {
            final int varPos15 = offset + 251 + buf.getIntLE(offset + 203);
            final int setLen = VarInt.peek(buf, varPos15);
            if (setLen < 0) {
                throw ProtocolException.negativeLength("Set", setLen);
            }
            if (setLen > 4096000) {
                throw ProtocolException.stringTooLong("Set", setLen, 4096000);
            }
            obj.set = PacketIO.readVarString(buf, varPos15, PacketIO.UTF8);
        }
        if ((nullBits[2] & 0x10) != 0x0) {
            final int varPos16 = offset + 251 + buf.getIntLE(offset + 207);
            final int categoriesCount = VarInt.peek(buf, varPos16);
            if (categoriesCount < 0) {
                throw ProtocolException.negativeLength("Categories", categoriesCount);
            }
            if (categoriesCount > 4096000) {
                throw ProtocolException.arrayTooLong("Categories", categoriesCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos16);
            if (varPos16 + varIntLen + categoriesCount * 1L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("Categories", varPos16 + varIntLen + categoriesCount * 1, buf.readableBytes());
            }
            obj.categories = new String[categoriesCount];
            int elemPos = varPos16 + varIntLen;
            for (int i = 0; i < categoriesCount; ++i) {
                final int strLen = VarInt.peek(buf, elemPos);
                if (strLen < 0) {
                    throw ProtocolException.negativeLength("categories[" + i, strLen);
                }
                if (strLen > 4096000) {
                    throw ProtocolException.stringTooLong("categories[" + i, strLen, 4096000);
                }
                final int strVarLen = VarInt.length(buf, elemPos);
                obj.categories[i] = PacketIO.readVarString(buf, elemPos);
                elemPos += strVarLen + strLen;
            }
        }
        if ((nullBits[2] & 0x20) != 0x0) {
            final int varPos17 = offset + 251 + buf.getIntLE(offset + 211);
            final int particlesCount = VarInt.peek(buf, varPos17);
            if (particlesCount < 0) {
                throw ProtocolException.negativeLength("Particles", particlesCount);
            }
            if (particlesCount > 4096000) {
                throw ProtocolException.arrayTooLong("Particles", particlesCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos17);
            if (varPos17 + varIntLen + particlesCount * 34L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("Particles", varPos17 + varIntLen + particlesCount * 34, buf.readableBytes());
            }
            obj.particles = new ModelParticle[particlesCount];
            int elemPos = varPos17 + varIntLen;
            for (int i = 0; i < particlesCount; ++i) {
                obj.particles[i] = ModelParticle.deserialize(buf, elemPos);
                elemPos += ModelParticle.computeBytesConsumed(buf, elemPos);
            }
        }
        if ((nullBits[2] & 0x40) != 0x0) {
            final int varPos18 = offset + 251 + buf.getIntLE(offset + 215);
            final int firstPersonParticlesCount = VarInt.peek(buf, varPos18);
            if (firstPersonParticlesCount < 0) {
                throw ProtocolException.negativeLength("FirstPersonParticles", firstPersonParticlesCount);
            }
            if (firstPersonParticlesCount > 4096000) {
                throw ProtocolException.arrayTooLong("FirstPersonParticles", firstPersonParticlesCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos18);
            if (varPos18 + varIntLen + firstPersonParticlesCount * 34L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("FirstPersonParticles", varPos18 + varIntLen + firstPersonParticlesCount * 34, buf.readableBytes());
            }
            obj.firstPersonParticles = new ModelParticle[firstPersonParticlesCount];
            int elemPos = varPos18 + varIntLen;
            for (int i = 0; i < firstPersonParticlesCount; ++i) {
                obj.firstPersonParticles[i] = ModelParticle.deserialize(buf, elemPos);
                elemPos += ModelParticle.computeBytesConsumed(buf, elemPos);
            }
        }
        if ((nullBits[2] & 0x80) != 0x0) {
            final int varPos19 = offset + 251 + buf.getIntLE(offset + 219);
            final int trailsCount = VarInt.peek(buf, varPos19);
            if (trailsCount < 0) {
                throw ProtocolException.negativeLength("Trails", trailsCount);
            }
            if (trailsCount > 4096000) {
                throw ProtocolException.arrayTooLong("Trails", trailsCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos19);
            if (varPos19 + varIntLen + trailsCount * 27L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("Trails", varPos19 + varIntLen + trailsCount * 27, buf.readableBytes());
            }
            obj.trails = new ModelTrail[trailsCount];
            int elemPos = varPos19 + varIntLen;
            for (int i = 0; i < trailsCount; ++i) {
                obj.trails[i] = ModelTrail.deserialize(buf, elemPos);
                elemPos += ModelTrail.computeBytesConsumed(buf, elemPos);
            }
        }
        if ((nullBits[3] & 0x1) != 0x0) {
            final int varPos20 = offset + 251 + buf.getIntLE(offset + 223);
            final int interactionsCount = VarInt.peek(buf, varPos20);
            if (interactionsCount < 0) {
                throw ProtocolException.negativeLength("Interactions", interactionsCount);
            }
            if (interactionsCount > 4096000) {
                throw ProtocolException.dictionaryTooLarge("Interactions", interactionsCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos20);
            obj.interactions = new HashMap<InteractionType, Integer>(interactionsCount);
            int dictPos = varPos20 + varIntLen;
            for (int i = 0; i < interactionsCount; ++i) {
                final InteractionType key = InteractionType.fromValue(buf.getByte(dictPos));
                ++dictPos;
                final int val = buf.getIntLE(dictPos);
                dictPos += 4;
                if (obj.interactions.put(key, val) != null) {
                    throw ProtocolException.duplicateKey("interactions", key);
                }
            }
        }
        if ((nullBits[3] & 0x2) != 0x0) {
            final int varPos21 = offset + 251 + buf.getIntLE(offset + 227);
            final int interactionVarsCount = VarInt.peek(buf, varPos21);
            if (interactionVarsCount < 0) {
                throw ProtocolException.negativeLength("InteractionVars", interactionVarsCount);
            }
            if (interactionVarsCount > 4096000) {
                throw ProtocolException.dictionaryTooLarge("InteractionVars", interactionVarsCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos21);
            obj.interactionVars = new HashMap<String, Integer>(interactionVarsCount);
            int dictPos = varPos21 + varIntLen;
            for (int i = 0; i < interactionVarsCount; ++i) {
                final int keyLen = VarInt.peek(buf, dictPos);
                if (keyLen < 0) {
                    throw ProtocolException.negativeLength("key", keyLen);
                }
                if (keyLen > 4096000) {
                    throw ProtocolException.stringTooLong("key", keyLen, 4096000);
                }
                final int keyVarLen = VarInt.length(buf, dictPos);
                final String key2 = PacketIO.readVarString(buf, dictPos);
                dictPos += keyVarLen + keyLen;
                final int val2 = buf.getIntLE(dictPos);
                dictPos += 4;
                if (obj.interactionVars.put(key2, val2) != null) {
                    throw ProtocolException.duplicateKey("interactionVars", key2);
                }
            }
        }
        if ((nullBits[3] & 0x4) != 0x0) {
            final int varPos22 = offset + 251 + buf.getIntLE(offset + 231);
            obj.interactionConfig = InteractionConfiguration.deserialize(buf, varPos22);
        }
        if ((nullBits[3] & 0x8) != 0x0) {
            final int varPos23 = offset + 251 + buf.getIntLE(offset + 235);
            final int droppedItemAnimationLen = VarInt.peek(buf, varPos23);
            if (droppedItemAnimationLen < 0) {
                throw ProtocolException.negativeLength("DroppedItemAnimation", droppedItemAnimationLen);
            }
            if (droppedItemAnimationLen > 4096000) {
                throw ProtocolException.stringTooLong("DroppedItemAnimation", droppedItemAnimationLen, 4096000);
            }
            obj.droppedItemAnimation = PacketIO.readVarString(buf, varPos23, PacketIO.UTF8);
        }
        if ((nullBits[3] & 0x10) != 0x0) {
            final int varPos24 = offset + 251 + buf.getIntLE(offset + 239);
            final int tagIndexesCount = VarInt.peek(buf, varPos24);
            if (tagIndexesCount < 0) {
                throw ProtocolException.negativeLength("TagIndexes", tagIndexesCount);
            }
            if (tagIndexesCount > 4096000) {
                throw ProtocolException.arrayTooLong("TagIndexes", tagIndexesCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos24);
            if (varPos24 + varIntLen + tagIndexesCount * 4L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("TagIndexes", varPos24 + varIntLen + tagIndexesCount * 4, buf.readableBytes());
            }
            obj.tagIndexes = new int[tagIndexesCount];
            for (int j = 0; j < tagIndexesCount; ++j) {
                obj.tagIndexes[j] = buf.getIntLE(varPos24 + varIntLen + j * 4);
            }
        }
        if ((nullBits[3] & 0x20) != 0x0) {
            final int varPos25 = offset + 251 + buf.getIntLE(offset + 243);
            final int itemAppearanceConditionsCount = VarInt.peek(buf, varPos25);
            if (itemAppearanceConditionsCount < 0) {
                throw ProtocolException.negativeLength("ItemAppearanceConditions", itemAppearanceConditionsCount);
            }
            if (itemAppearanceConditionsCount > 4096000) {
                throw ProtocolException.dictionaryTooLarge("ItemAppearanceConditions", itemAppearanceConditionsCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos25);
            obj.itemAppearanceConditions = new HashMap<Integer, ItemAppearanceCondition[]>(itemAppearanceConditionsCount);
            int dictPos = varPos25 + varIntLen;
            for (int i = 0; i < itemAppearanceConditionsCount; ++i) {
                final int key3 = buf.getIntLE(dictPos);
                dictPos += 4;
                final int valLen = VarInt.peek(buf, dictPos);
                if (valLen < 0) {
                    throw ProtocolException.negativeLength("val", valLen);
                }
                if (valLen > 64) {
                    throw ProtocolException.arrayTooLong("val", valLen, 64);
                }
                final int valVarLen = VarInt.length(buf, dictPos);
                if (dictPos + valVarLen + valLen * 18L > buf.readableBytes()) {
                    throw ProtocolException.bufferTooSmall("val", dictPos + valVarLen + valLen * 18, buf.readableBytes());
                }
                dictPos += valVarLen;
                final ItemAppearanceCondition[] val3 = new ItemAppearanceCondition[valLen];
                for (int valIdx = 0; valIdx < valLen; ++valIdx) {
                    val3[valIdx] = ItemAppearanceCondition.deserialize(buf, dictPos);
                    dictPos += ItemAppearanceCondition.computeBytesConsumed(buf, dictPos);
                }
                if (obj.itemAppearanceConditions.put(key3, val3) != null) {
                    throw ProtocolException.duplicateKey("itemAppearanceConditions", key3);
                }
            }
        }
        if ((nullBits[3] & 0x40) != 0x0) {
            final int varPos26 = offset + 251 + buf.getIntLE(offset + 247);
            final int displayEntityStatsHUDCount = VarInt.peek(buf, varPos26);
            if (displayEntityStatsHUDCount < 0) {
                throw ProtocolException.negativeLength("DisplayEntityStatsHUD", displayEntityStatsHUDCount);
            }
            if (displayEntityStatsHUDCount > 4096000) {
                throw ProtocolException.arrayTooLong("DisplayEntityStatsHUD", displayEntityStatsHUDCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos26);
            if (varPos26 + varIntLen + displayEntityStatsHUDCount * 4L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("DisplayEntityStatsHUD", varPos26 + varIntLen + displayEntityStatsHUDCount * 4, buf.readableBytes());
            }
            obj.displayEntityStatsHUD = new int[displayEntityStatsHUDCount];
            for (int j = 0; j < displayEntityStatsHUDCount; ++j) {
                obj.displayEntityStatsHUD[j] = buf.getIntLE(varPos26 + varIntLen + j * 4);
            }
        }
        return obj;
    }
    
    public static int computeBytesConsumed(@Nonnull final ByteBuf buf, final int offset) {
        final byte[] nullBits = PacketIO.readBytes(buf, offset, 4);
        int maxEnd = 251;
        if ((nullBits[0] & 0x20) != 0x0) {
            final int fieldOffset0 = buf.getIntLE(offset + 147);
            int pos0 = offset + 251 + fieldOffset0;
            final int sl = VarInt.peek(buf, pos0);
            pos0 += VarInt.length(buf, pos0) + sl;
            if (pos0 - offset > maxEnd) {
                maxEnd = pos0 - offset;
            }
        }
        if ((nullBits[0] & 0x40) != 0x0) {
            final int fieldOffset2 = buf.getIntLE(offset + 151);
            int pos2 = offset + 251 + fieldOffset2;
            final int sl = VarInt.peek(buf, pos2);
            pos2 += VarInt.length(buf, pos2) + sl;
            if (pos2 - offset > maxEnd) {
                maxEnd = pos2 - offset;
            }
        }
        if ((nullBits[0] & 0x80) != 0x0) {
            final int fieldOffset3 = buf.getIntLE(offset + 155);
            int pos3 = offset + 251 + fieldOffset3;
            final int sl = VarInt.peek(buf, pos3);
            pos3 += VarInt.length(buf, pos3) + sl;
            if (pos3 - offset > maxEnd) {
                maxEnd = pos3 - offset;
            }
        }
        if ((nullBits[1] & 0x1) != 0x0) {
            final int fieldOffset4 = buf.getIntLE(offset + 159);
            int pos4 = offset + 251 + fieldOffset4;
            final int sl = VarInt.peek(buf, pos4);
            pos4 += VarInt.length(buf, pos4) + sl;
            if (pos4 - offset > maxEnd) {
                maxEnd = pos4 - offset;
            }
        }
        if ((nullBits[1] & 0x2) != 0x0) {
            final int fieldOffset5 = buf.getIntLE(offset + 163);
            int pos5 = offset + 251 + fieldOffset5;
            final int sl = VarInt.peek(buf, pos5);
            pos5 += VarInt.length(buf, pos5) + sl;
            if (pos5 - offset > maxEnd) {
                maxEnd = pos5 - offset;
            }
        }
        if ((nullBits[1] & 0x4) != 0x0) {
            final int fieldOffset6 = buf.getIntLE(offset + 167);
            int pos6 = offset + 251 + fieldOffset6;
            final int sl = VarInt.peek(buf, pos6);
            pos6 += VarInt.length(buf, pos6) + sl;
            if (pos6 - offset > maxEnd) {
                maxEnd = pos6 - offset;
            }
        }
        if ((nullBits[1] & 0x8) != 0x0) {
            final int fieldOffset7 = buf.getIntLE(offset + 171);
            int pos7 = offset + 251 + fieldOffset7;
            pos7 += ItemTranslationProperties.computeBytesConsumed(buf, pos7);
            if (pos7 - offset > maxEnd) {
                maxEnd = pos7 - offset;
            }
        }
        if ((nullBits[1] & 0x10) != 0x0) {
            final int fieldOffset8 = buf.getIntLE(offset + 175);
            int pos8 = offset + 251 + fieldOffset8;
            final int arrLen = VarInt.peek(buf, pos8);
            pos8 += VarInt.length(buf, pos8);
            for (int i = 0; i < arrLen; ++i) {
                pos8 += ItemResourceType.computeBytesConsumed(buf, pos8);
            }
            if (pos8 - offset > maxEnd) {
                maxEnd = pos8 - offset;
            }
        }
        if ((nullBits[1] & 0x20) != 0x0) {
            final int fieldOffset9 = buf.getIntLE(offset + 179);
            int pos9 = offset + 251 + fieldOffset9;
            pos9 += ItemTool.computeBytesConsumed(buf, pos9);
            if (pos9 - offset > maxEnd) {
                maxEnd = pos9 - offset;
            }
        }
        if ((nullBits[1] & 0x40) != 0x0) {
            final int fieldOffset10 = buf.getIntLE(offset + 183);
            int pos10 = offset + 251 + fieldOffset10;
            pos10 += ItemWeapon.computeBytesConsumed(buf, pos10);
            if (pos10 - offset > maxEnd) {
                maxEnd = pos10 - offset;
            }
        }
        if ((nullBits[1] & 0x80) != 0x0) {
            final int fieldOffset11 = buf.getIntLE(offset + 187);
            int pos11 = offset + 251 + fieldOffset11;
            pos11 += ItemArmor.computeBytesConsumed(buf, pos11);
            if (pos11 - offset > maxEnd) {
                maxEnd = pos11 - offset;
            }
        }
        if ((nullBits[2] & 0x1) != 0x0) {
            final int fieldOffset12 = buf.getIntLE(offset + 191);
            int pos12 = offset + 251 + fieldOffset12;
            pos12 += ItemUtility.computeBytesConsumed(buf, pos12);
            if (pos12 - offset > maxEnd) {
                maxEnd = pos12 - offset;
            }
        }
        if ((nullBits[2] & 0x2) != 0x0) {
            final int fieldOffset13 = buf.getIntLE(offset + 195);
            int pos13 = offset + 251 + fieldOffset13;
            pos13 += ItemBuilderToolData.computeBytesConsumed(buf, pos13);
            if (pos13 - offset > maxEnd) {
                maxEnd = pos13 - offset;
            }
        }
        if ((nullBits[2] & 0x4) != 0x0) {
            final int fieldOffset14 = buf.getIntLE(offset + 199);
            int pos14 = offset + 251 + fieldOffset14;
            pos14 += ItemEntityConfig.computeBytesConsumed(buf, pos14);
            if (pos14 - offset > maxEnd) {
                maxEnd = pos14 - offset;
            }
        }
        if ((nullBits[2] & 0x8) != 0x0) {
            final int fieldOffset15 = buf.getIntLE(offset + 203);
            int pos15 = offset + 251 + fieldOffset15;
            final int sl = VarInt.peek(buf, pos15);
            pos15 += VarInt.length(buf, pos15) + sl;
            if (pos15 - offset > maxEnd) {
                maxEnd = pos15 - offset;
            }
        }
        if ((nullBits[2] & 0x10) != 0x0) {
            final int fieldOffset16 = buf.getIntLE(offset + 207);
            int pos16 = offset + 251 + fieldOffset16;
            final int arrLen = VarInt.peek(buf, pos16);
            pos16 += VarInt.length(buf, pos16);
            for (int i = 0; i < arrLen; ++i) {
                final int sl2 = VarInt.peek(buf, pos16);
                pos16 += VarInt.length(buf, pos16) + sl2;
            }
            if (pos16 - offset > maxEnd) {
                maxEnd = pos16 - offset;
            }
        }
        if ((nullBits[2] & 0x20) != 0x0) {
            final int fieldOffset17 = buf.getIntLE(offset + 211);
            int pos17 = offset + 251 + fieldOffset17;
            final int arrLen = VarInt.peek(buf, pos17);
            pos17 += VarInt.length(buf, pos17);
            for (int i = 0; i < arrLen; ++i) {
                pos17 += ModelParticle.computeBytesConsumed(buf, pos17);
            }
            if (pos17 - offset > maxEnd) {
                maxEnd = pos17 - offset;
            }
        }
        if ((nullBits[2] & 0x40) != 0x0) {
            final int fieldOffset18 = buf.getIntLE(offset + 215);
            int pos18 = offset + 251 + fieldOffset18;
            final int arrLen = VarInt.peek(buf, pos18);
            pos18 += VarInt.length(buf, pos18);
            for (int i = 0; i < arrLen; ++i) {
                pos18 += ModelParticle.computeBytesConsumed(buf, pos18);
            }
            if (pos18 - offset > maxEnd) {
                maxEnd = pos18 - offset;
            }
        }
        if ((nullBits[2] & 0x80) != 0x0) {
            final int fieldOffset19 = buf.getIntLE(offset + 219);
            int pos19 = offset + 251 + fieldOffset19;
            final int arrLen = VarInt.peek(buf, pos19);
            pos19 += VarInt.length(buf, pos19);
            for (int i = 0; i < arrLen; ++i) {
                pos19 += ModelTrail.computeBytesConsumed(buf, pos19);
            }
            if (pos19 - offset > maxEnd) {
                maxEnd = pos19 - offset;
            }
        }
        if ((nullBits[3] & 0x1) != 0x0) {
            final int fieldOffset20 = buf.getIntLE(offset + 223);
            int pos20 = offset + 251 + fieldOffset20;
            final int dictLen = VarInt.peek(buf, pos20);
            pos20 += VarInt.length(buf, pos20);
            for (int i = 0; i < dictLen; ++i) {
                ++pos20;
                pos20 += 4;
            }
            if (pos20 - offset > maxEnd) {
                maxEnd = pos20 - offset;
            }
        }
        if ((nullBits[3] & 0x2) != 0x0) {
            final int fieldOffset21 = buf.getIntLE(offset + 227);
            int pos21 = offset + 251 + fieldOffset21;
            final int dictLen = VarInt.peek(buf, pos21);
            pos21 += VarInt.length(buf, pos21);
            for (int i = 0; i < dictLen; ++i) {
                final int sl2 = VarInt.peek(buf, pos21);
                pos21 += VarInt.length(buf, pos21) + sl2;
                pos21 += 4;
            }
            if (pos21 - offset > maxEnd) {
                maxEnd = pos21 - offset;
            }
        }
        if ((nullBits[3] & 0x4) != 0x0) {
            final int fieldOffset22 = buf.getIntLE(offset + 231);
            int pos22 = offset + 251 + fieldOffset22;
            pos22 += InteractionConfiguration.computeBytesConsumed(buf, pos22);
            if (pos22 - offset > maxEnd) {
                maxEnd = pos22 - offset;
            }
        }
        if ((nullBits[3] & 0x8) != 0x0) {
            final int fieldOffset23 = buf.getIntLE(offset + 235);
            int pos23 = offset + 251 + fieldOffset23;
            final int sl = VarInt.peek(buf, pos23);
            pos23 += VarInt.length(buf, pos23) + sl;
            if (pos23 - offset > maxEnd) {
                maxEnd = pos23 - offset;
            }
        }
        if ((nullBits[3] & 0x10) != 0x0) {
            final int fieldOffset24 = buf.getIntLE(offset + 239);
            int pos24 = offset + 251 + fieldOffset24;
            final int arrLen = VarInt.peek(buf, pos24);
            pos24 += VarInt.length(buf, pos24) + arrLen * 4;
            if (pos24 - offset > maxEnd) {
                maxEnd = pos24 - offset;
            }
        }
        if ((nullBits[3] & 0x20) != 0x0) {
            final int fieldOffset25 = buf.getIntLE(offset + 243);
            int pos25 = offset + 251 + fieldOffset25;
            final int dictLen = VarInt.peek(buf, pos25);
            pos25 += VarInt.length(buf, pos25);
            for (int i = 0; i < dictLen; ++i) {
                pos25 += 4;
                final int al = VarInt.peek(buf, pos25);
                pos25 += VarInt.length(buf, pos25);
                for (int j = 0; j < al; ++j) {
                    pos25 += ItemAppearanceCondition.computeBytesConsumed(buf, pos25);
                }
            }
            if (pos25 - offset > maxEnd) {
                maxEnd = pos25 - offset;
            }
        }
        if ((nullBits[3] & 0x40) != 0x0) {
            final int fieldOffset26 = buf.getIntLE(offset + 247);
            int pos26 = offset + 251 + fieldOffset26;
            final int arrLen = VarInt.peek(buf, pos26);
            pos26 += VarInt.length(buf, pos26) + arrLen * 4;
            if (pos26 - offset > maxEnd) {
                maxEnd = pos26 - offset;
            }
        }
        return maxEnd;
    }
    
    public void serialize(@Nonnull final ByteBuf buf) {
        final int startPos = buf.writerIndex();
        final byte[] nullBits = new byte[4];
        if (this.iconProperties != null) {
            final byte[] array = nullBits;
            final int n = 0;
            array[n] |= 0x1;
        }
        if (this.gliderConfig != null) {
            final byte[] array2 = nullBits;
            final int n2 = 0;
            array2[n2] |= 0x2;
        }
        if (this.blockSelectorTool != null) {
            final byte[] array3 = nullBits;
            final int n3 = 0;
            array3[n3] |= 0x4;
        }
        if (this.light != null) {
            final byte[] array4 = nullBits;
            final int n4 = 0;
            array4[n4] |= 0x8;
        }
        if (this.pullbackConfig != null) {
            final byte[] array5 = nullBits;
            final int n5 = 0;
            array5[n5] |= 0x10;
        }
        if (this.id != null) {
            final byte[] array6 = nullBits;
            final int n6 = 0;
            array6[n6] |= 0x20;
        }
        if (this.model != null) {
            final byte[] array7 = nullBits;
            final int n7 = 0;
            array7[n7] |= 0x40;
        }
        if (this.texture != null) {
            final byte[] array8 = nullBits;
            final int n8 = 0;
            array8[n8] |= (byte)128;
        }
        if (this.animation != null) {
            final byte[] array9 = nullBits;
            final int n9 = 1;
            array9[n9] |= 0x1;
        }
        if (this.playerAnimationsId != null) {
            final byte[] array10 = nullBits;
            final int n10 = 1;
            array10[n10] |= 0x2;
        }
        if (this.icon != null) {
            final byte[] array11 = nullBits;
            final int n11 = 1;
            array11[n11] |= 0x4;
        }
        if (this.translationProperties != null) {
            final byte[] array12 = nullBits;
            final int n12 = 1;
            array12[n12] |= 0x8;
        }
        if (this.resourceTypes != null) {
            final byte[] array13 = nullBits;
            final int n13 = 1;
            array13[n13] |= 0x10;
        }
        if (this.tool != null) {
            final byte[] array14 = nullBits;
            final int n14 = 1;
            array14[n14] |= 0x20;
        }
        if (this.weapon != null) {
            final byte[] array15 = nullBits;
            final int n15 = 1;
            array15[n15] |= 0x40;
        }
        if (this.armor != null) {
            final byte[] array16 = nullBits;
            final int n16 = 1;
            array16[n16] |= (byte)128;
        }
        if (this.utility != null) {
            final byte[] array17 = nullBits;
            final int n17 = 2;
            array17[n17] |= 0x1;
        }
        if (this.builderToolData != null) {
            final byte[] array18 = nullBits;
            final int n18 = 2;
            array18[n18] |= 0x2;
        }
        if (this.itemEntity != null) {
            final byte[] array19 = nullBits;
            final int n19 = 2;
            array19[n19] |= 0x4;
        }
        if (this.set != null) {
            final byte[] array20 = nullBits;
            final int n20 = 2;
            array20[n20] |= 0x8;
        }
        if (this.categories != null) {
            final byte[] array21 = nullBits;
            final int n21 = 2;
            array21[n21] |= 0x10;
        }
        if (this.particles != null) {
            final byte[] array22 = nullBits;
            final int n22 = 2;
            array22[n22] |= 0x20;
        }
        if (this.firstPersonParticles != null) {
            final byte[] array23 = nullBits;
            final int n23 = 2;
            array23[n23] |= 0x40;
        }
        if (this.trails != null) {
            final byte[] array24 = nullBits;
            final int n24 = 2;
            array24[n24] |= (byte)128;
        }
        if (this.interactions != null) {
            final byte[] array25 = nullBits;
            final int n25 = 3;
            array25[n25] |= 0x1;
        }
        if (this.interactionVars != null) {
            final byte[] array26 = nullBits;
            final int n26 = 3;
            array26[n26] |= 0x2;
        }
        if (this.interactionConfig != null) {
            final byte[] array27 = nullBits;
            final int n27 = 3;
            array27[n27] |= 0x4;
        }
        if (this.droppedItemAnimation != null) {
            final byte[] array28 = nullBits;
            final int n28 = 3;
            array28[n28] |= 0x8;
        }
        if (this.tagIndexes != null) {
            final byte[] array29 = nullBits;
            final int n29 = 3;
            array29[n29] |= 0x10;
        }
        if (this.itemAppearanceConditions != null) {
            final byte[] array30 = nullBits;
            final int n30 = 3;
            array30[n30] |= 0x20;
        }
        if (this.displayEntityStatsHUD != null) {
            final byte[] array31 = nullBits;
            final int n31 = 3;
            array31[n31] |= 0x40;
        }
        buf.writeBytes(nullBits);
        buf.writeFloatLE(this.scale);
        buf.writeByte(this.usePlayerAnimations ? 1 : 0);
        buf.writeIntLE(this.maxStack);
        buf.writeIntLE(this.reticleIndex);
        if (this.iconProperties != null) {
            this.iconProperties.serialize(buf);
        }
        else {
            buf.writeZero(25);
        }
        buf.writeIntLE(this.itemLevel);
        buf.writeIntLE(this.qualityIndex);
        buf.writeByte(this.consumable ? 1 : 0);
        buf.writeByte(this.variant ? 1 : 0);
        buf.writeIntLE(this.blockId);
        if (this.gliderConfig != null) {
            this.gliderConfig.serialize(buf);
        }
        else {
            buf.writeZero(16);
        }
        if (this.blockSelectorTool != null) {
            this.blockSelectorTool.serialize(buf);
        }
        else {
            buf.writeZero(4);
        }
        if (this.light != null) {
            this.light.serialize(buf);
        }
        else {
            buf.writeZero(4);
        }
        buf.writeDoubleLE(this.durability);
        buf.writeIntLE(this.soundEventIndex);
        buf.writeIntLE(this.itemSoundSetIndex);
        if (this.pullbackConfig != null) {
            this.pullbackConfig.serialize(buf);
        }
        else {
            buf.writeZero(49);
        }
        buf.writeByte(this.clipsGeometry ? 1 : 0);
        buf.writeByte(this.renderDeployablePreview ? 1 : 0);
        final int idOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int modelOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int textureOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int animationOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int playerAnimationsIdOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int iconOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int translationPropertiesOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int resourceTypesOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int toolOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int weaponOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int armorOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int utilityOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int builderToolDataOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int itemEntityOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int setOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int categoriesOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int particlesOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int firstPersonParticlesOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int trailsOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int interactionsOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int interactionVarsOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int interactionConfigOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int droppedItemAnimationOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int tagIndexesOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int itemAppearanceConditionsOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int displayEntityStatsHUDOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int varBlockStart = buf.writerIndex();
        if (this.id != null) {
            buf.setIntLE(idOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.id, 4096000);
        }
        else {
            buf.setIntLE(idOffsetSlot, -1);
        }
        if (this.model != null) {
            buf.setIntLE(modelOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.model, 4096000);
        }
        else {
            buf.setIntLE(modelOffsetSlot, -1);
        }
        if (this.texture != null) {
            buf.setIntLE(textureOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.texture, 4096000);
        }
        else {
            buf.setIntLE(textureOffsetSlot, -1);
        }
        if (this.animation != null) {
            buf.setIntLE(animationOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.animation, 4096000);
        }
        else {
            buf.setIntLE(animationOffsetSlot, -1);
        }
        if (this.playerAnimationsId != null) {
            buf.setIntLE(playerAnimationsIdOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.playerAnimationsId, 4096000);
        }
        else {
            buf.setIntLE(playerAnimationsIdOffsetSlot, -1);
        }
        if (this.icon != null) {
            buf.setIntLE(iconOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.icon, 4096000);
        }
        else {
            buf.setIntLE(iconOffsetSlot, -1);
        }
        if (this.translationProperties != null) {
            buf.setIntLE(translationPropertiesOffsetSlot, buf.writerIndex() - varBlockStart);
            this.translationProperties.serialize(buf);
        }
        else {
            buf.setIntLE(translationPropertiesOffsetSlot, -1);
        }
        if (this.resourceTypes != null) {
            buf.setIntLE(resourceTypesOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.resourceTypes.length > 4096000) {
                throw ProtocolException.arrayTooLong("ResourceTypes", this.resourceTypes.length, 4096000);
            }
            VarInt.write(buf, this.resourceTypes.length);
            for (final ItemResourceType item : this.resourceTypes) {
                item.serialize(buf);
            }
        }
        else {
            buf.setIntLE(resourceTypesOffsetSlot, -1);
        }
        if (this.tool != null) {
            buf.setIntLE(toolOffsetSlot, buf.writerIndex() - varBlockStart);
            this.tool.serialize(buf);
        }
        else {
            buf.setIntLE(toolOffsetSlot, -1);
        }
        if (this.weapon != null) {
            buf.setIntLE(weaponOffsetSlot, buf.writerIndex() - varBlockStart);
            this.weapon.serialize(buf);
        }
        else {
            buf.setIntLE(weaponOffsetSlot, -1);
        }
        if (this.armor != null) {
            buf.setIntLE(armorOffsetSlot, buf.writerIndex() - varBlockStart);
            this.armor.serialize(buf);
        }
        else {
            buf.setIntLE(armorOffsetSlot, -1);
        }
        if (this.utility != null) {
            buf.setIntLE(utilityOffsetSlot, buf.writerIndex() - varBlockStart);
            this.utility.serialize(buf);
        }
        else {
            buf.setIntLE(utilityOffsetSlot, -1);
        }
        if (this.builderToolData != null) {
            buf.setIntLE(builderToolDataOffsetSlot, buf.writerIndex() - varBlockStart);
            this.builderToolData.serialize(buf);
        }
        else {
            buf.setIntLE(builderToolDataOffsetSlot, -1);
        }
        if (this.itemEntity != null) {
            buf.setIntLE(itemEntityOffsetSlot, buf.writerIndex() - varBlockStart);
            this.itemEntity.serialize(buf);
        }
        else {
            buf.setIntLE(itemEntityOffsetSlot, -1);
        }
        if (this.set != null) {
            buf.setIntLE(setOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.set, 4096000);
        }
        else {
            buf.setIntLE(setOffsetSlot, -1);
        }
        if (this.categories != null) {
            buf.setIntLE(categoriesOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.categories.length > 4096000) {
                throw ProtocolException.arrayTooLong("Categories", this.categories.length, 4096000);
            }
            VarInt.write(buf, this.categories.length);
            for (final String item2 : this.categories) {
                PacketIO.writeVarString(buf, item2, 4096000);
            }
        }
        else {
            buf.setIntLE(categoriesOffsetSlot, -1);
        }
        if (this.particles != null) {
            buf.setIntLE(particlesOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.particles.length > 4096000) {
                throw ProtocolException.arrayTooLong("Particles", this.particles.length, 4096000);
            }
            VarInt.write(buf, this.particles.length);
            for (final ModelParticle item3 : this.particles) {
                item3.serialize(buf);
            }
        }
        else {
            buf.setIntLE(particlesOffsetSlot, -1);
        }
        if (this.firstPersonParticles != null) {
            buf.setIntLE(firstPersonParticlesOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.firstPersonParticles.length > 4096000) {
                throw ProtocolException.arrayTooLong("FirstPersonParticles", this.firstPersonParticles.length, 4096000);
            }
            VarInt.write(buf, this.firstPersonParticles.length);
            for (final ModelParticle item3 : this.firstPersonParticles) {
                item3.serialize(buf);
            }
        }
        else {
            buf.setIntLE(firstPersonParticlesOffsetSlot, -1);
        }
        if (this.trails != null) {
            buf.setIntLE(trailsOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.trails.length > 4096000) {
                throw ProtocolException.arrayTooLong("Trails", this.trails.length, 4096000);
            }
            VarInt.write(buf, this.trails.length);
            for (final ModelTrail item4 : this.trails) {
                item4.serialize(buf);
            }
        }
        else {
            buf.setIntLE(trailsOffsetSlot, -1);
        }
        if (this.interactions != null) {
            buf.setIntLE(interactionsOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.interactions.size() > 4096000) {
                throw ProtocolException.dictionaryTooLarge("Interactions", this.interactions.size(), 4096000);
            }
            VarInt.write(buf, this.interactions.size());
            for (final Map.Entry<InteractionType, Integer> e : this.interactions.entrySet()) {
                buf.writeByte(e.getKey().getValue());
                buf.writeIntLE(e.getValue());
            }
        }
        else {
            buf.setIntLE(interactionsOffsetSlot, -1);
        }
        if (this.interactionVars != null) {
            buf.setIntLE(interactionVarsOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.interactionVars.size() > 4096000) {
                throw ProtocolException.dictionaryTooLarge("InteractionVars", this.interactionVars.size(), 4096000);
            }
            VarInt.write(buf, this.interactionVars.size());
            for (final Map.Entry<String, Integer> e2 : this.interactionVars.entrySet()) {
                PacketIO.writeVarString(buf, e2.getKey(), 4096000);
                buf.writeIntLE(e2.getValue());
            }
        }
        else {
            buf.setIntLE(interactionVarsOffsetSlot, -1);
        }
        if (this.interactionConfig != null) {
            buf.setIntLE(interactionConfigOffsetSlot, buf.writerIndex() - varBlockStart);
            this.interactionConfig.serialize(buf);
        }
        else {
            buf.setIntLE(interactionConfigOffsetSlot, -1);
        }
        if (this.droppedItemAnimation != null) {
            buf.setIntLE(droppedItemAnimationOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.droppedItemAnimation, 4096000);
        }
        else {
            buf.setIntLE(droppedItemAnimationOffsetSlot, -1);
        }
        if (this.tagIndexes != null) {
            buf.setIntLE(tagIndexesOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.tagIndexes.length > 4096000) {
                throw ProtocolException.arrayTooLong("TagIndexes", this.tagIndexes.length, 4096000);
            }
            VarInt.write(buf, this.tagIndexes.length);
            for (final int item5 : this.tagIndexes) {
                buf.writeIntLE(item5);
            }
        }
        else {
            buf.setIntLE(tagIndexesOffsetSlot, -1);
        }
        if (this.itemAppearanceConditions != null) {
            buf.setIntLE(itemAppearanceConditionsOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.itemAppearanceConditions.size() > 4096000) {
                throw ProtocolException.dictionaryTooLarge("ItemAppearanceConditions", this.itemAppearanceConditions.size(), 4096000);
            }
            VarInt.write(buf, this.itemAppearanceConditions.size());
            for (final Map.Entry<Integer, ItemAppearanceCondition[]> e3 : this.itemAppearanceConditions.entrySet()) {
                buf.writeIntLE(e3.getKey());
                VarInt.write(buf, e3.getValue().length);
                for (final ItemAppearanceCondition arrItem : e3.getValue()) {
                    arrItem.serialize(buf);
                }
            }
        }
        else {
            buf.setIntLE(itemAppearanceConditionsOffsetSlot, -1);
        }
        if (this.displayEntityStatsHUD != null) {
            buf.setIntLE(displayEntityStatsHUDOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.displayEntityStatsHUD.length > 4096000) {
                throw ProtocolException.arrayTooLong("DisplayEntityStatsHUD", this.displayEntityStatsHUD.length, 4096000);
            }
            VarInt.write(buf, this.displayEntityStatsHUD.length);
            for (final int item5 : this.displayEntityStatsHUD) {
                buf.writeIntLE(item5);
            }
        }
        else {
            buf.setIntLE(displayEntityStatsHUDOffsetSlot, -1);
        }
    }
    
    public int computeSize() {
        int size = 251;
        if (this.id != null) {
            size += PacketIO.stringSize(this.id);
        }
        if (this.model != null) {
            size += PacketIO.stringSize(this.model);
        }
        if (this.texture != null) {
            size += PacketIO.stringSize(this.texture);
        }
        if (this.animation != null) {
            size += PacketIO.stringSize(this.animation);
        }
        if (this.playerAnimationsId != null) {
            size += PacketIO.stringSize(this.playerAnimationsId);
        }
        if (this.icon != null) {
            size += PacketIO.stringSize(this.icon);
        }
        if (this.translationProperties != null) {
            size += this.translationProperties.computeSize();
        }
        if (this.resourceTypes != null) {
            int resourceTypesSize = 0;
            for (final ItemResourceType elem : this.resourceTypes) {
                resourceTypesSize += elem.computeSize();
            }
            size += VarInt.size(this.resourceTypes.length) + resourceTypesSize;
        }
        if (this.tool != null) {
            size += this.tool.computeSize();
        }
        if (this.weapon != null) {
            size += this.weapon.computeSize();
        }
        if (this.armor != null) {
            size += this.armor.computeSize();
        }
        if (this.utility != null) {
            size += this.utility.computeSize();
        }
        if (this.builderToolData != null) {
            size += this.builderToolData.computeSize();
        }
        if (this.itemEntity != null) {
            size += this.itemEntity.computeSize();
        }
        if (this.set != null) {
            size += PacketIO.stringSize(this.set);
        }
        if (this.categories != null) {
            int categoriesSize = 0;
            for (final String elem2 : this.categories) {
                categoriesSize += PacketIO.stringSize(elem2);
            }
            size += VarInt.size(this.categories.length) + categoriesSize;
        }
        if (this.particles != null) {
            int particlesSize = 0;
            for (final ModelParticle elem3 : this.particles) {
                particlesSize += elem3.computeSize();
            }
            size += VarInt.size(this.particles.length) + particlesSize;
        }
        if (this.firstPersonParticles != null) {
            int firstPersonParticlesSize = 0;
            for (final ModelParticle elem3 : this.firstPersonParticles) {
                firstPersonParticlesSize += elem3.computeSize();
            }
            size += VarInt.size(this.firstPersonParticles.length) + firstPersonParticlesSize;
        }
        if (this.trails != null) {
            int trailsSize = 0;
            for (final ModelTrail elem4 : this.trails) {
                trailsSize += elem4.computeSize();
            }
            size += VarInt.size(this.trails.length) + trailsSize;
        }
        if (this.interactions != null) {
            size += VarInt.size(this.interactions.size()) + this.interactions.size() * 5;
        }
        if (this.interactionVars != null) {
            int interactionVarsSize = 0;
            for (final Map.Entry<String, Integer> kvp : this.interactionVars.entrySet()) {
                interactionVarsSize += PacketIO.stringSize(kvp.getKey()) + 4;
            }
            size += VarInt.size(this.interactionVars.size()) + interactionVarsSize;
        }
        if (this.interactionConfig != null) {
            size += this.interactionConfig.computeSize();
        }
        if (this.droppedItemAnimation != null) {
            size += PacketIO.stringSize(this.droppedItemAnimation);
        }
        if (this.tagIndexes != null) {
            size += VarInt.size(this.tagIndexes.length) + this.tagIndexes.length * 4;
        }
        if (this.itemAppearanceConditions != null) {
            int itemAppearanceConditionsSize = 0;
            for (final Map.Entry<Integer, ItemAppearanceCondition[]> kvp2 : this.itemAppearanceConditions.entrySet()) {
                itemAppearanceConditionsSize += 4 + VarInt.size(kvp2.getValue().length) + Arrays.stream(kvp2.getValue()).mapToInt(inner -> inner.computeSize()).sum();
            }
            size += VarInt.size(this.itemAppearanceConditions.size()) + itemAppearanceConditionsSize;
        }
        if (this.displayEntityStatsHUD != null) {
            size += VarInt.size(this.displayEntityStatsHUD.length) + this.displayEntityStatsHUD.length * 4;
        }
        return size;
    }
    
    public static ValidationResult validateStructure(@Nonnull final ByteBuf buffer, final int offset) {
        if (buffer.readableBytes() - offset < 251) {
            return ValidationResult.error("Buffer too small: expected at least 251 bytes");
        }
        final byte[] nullBits = PacketIO.readBytes(buffer, offset, 4);
        if ((nullBits[0] & 0x20) != 0x0) {
            final int idOffset = buffer.getIntLE(offset + 147);
            if (idOffset < 0) {
                return ValidationResult.error("Invalid offset for Id");
            }
            int pos = offset + 251 + idOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Id");
            }
            final int idLen = VarInt.peek(buffer, pos);
            if (idLen < 0) {
                return ValidationResult.error("Invalid string length for Id");
            }
            if (idLen > 4096000) {
                return ValidationResult.error("Id exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += idLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading Id");
            }
        }
        if ((nullBits[0] & 0x40) != 0x0) {
            final int modelOffset = buffer.getIntLE(offset + 151);
            if (modelOffset < 0) {
                return ValidationResult.error("Invalid offset for Model");
            }
            int pos = offset + 251 + modelOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Model");
            }
            final int modelLen = VarInt.peek(buffer, pos);
            if (modelLen < 0) {
                return ValidationResult.error("Invalid string length for Model");
            }
            if (modelLen > 4096000) {
                return ValidationResult.error("Model exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += modelLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading Model");
            }
        }
        if ((nullBits[0] & 0x80) != 0x0) {
            final int textureOffset = buffer.getIntLE(offset + 155);
            if (textureOffset < 0) {
                return ValidationResult.error("Invalid offset for Texture");
            }
            int pos = offset + 251 + textureOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Texture");
            }
            final int textureLen = VarInt.peek(buffer, pos);
            if (textureLen < 0) {
                return ValidationResult.error("Invalid string length for Texture");
            }
            if (textureLen > 4096000) {
                return ValidationResult.error("Texture exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += textureLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading Texture");
            }
        }
        if ((nullBits[1] & 0x1) != 0x0) {
            final int animationOffset = buffer.getIntLE(offset + 159);
            if (animationOffset < 0) {
                return ValidationResult.error("Invalid offset for Animation");
            }
            int pos = offset + 251 + animationOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Animation");
            }
            final int animationLen = VarInt.peek(buffer, pos);
            if (animationLen < 0) {
                return ValidationResult.error("Invalid string length for Animation");
            }
            if (animationLen > 4096000) {
                return ValidationResult.error("Animation exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += animationLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading Animation");
            }
        }
        if ((nullBits[1] & 0x2) != 0x0) {
            final int playerAnimationsIdOffset = buffer.getIntLE(offset + 163);
            if (playerAnimationsIdOffset < 0) {
                return ValidationResult.error("Invalid offset for PlayerAnimationsId");
            }
            int pos = offset + 251 + playerAnimationsIdOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for PlayerAnimationsId");
            }
            final int playerAnimationsIdLen = VarInt.peek(buffer, pos);
            if (playerAnimationsIdLen < 0) {
                return ValidationResult.error("Invalid string length for PlayerAnimationsId");
            }
            if (playerAnimationsIdLen > 4096000) {
                return ValidationResult.error("PlayerAnimationsId exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += playerAnimationsIdLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading PlayerAnimationsId");
            }
        }
        if ((nullBits[1] & 0x4) != 0x0) {
            final int iconOffset = buffer.getIntLE(offset + 167);
            if (iconOffset < 0) {
                return ValidationResult.error("Invalid offset for Icon");
            }
            int pos = offset + 251 + iconOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Icon");
            }
            final int iconLen = VarInt.peek(buffer, pos);
            if (iconLen < 0) {
                return ValidationResult.error("Invalid string length for Icon");
            }
            if (iconLen > 4096000) {
                return ValidationResult.error("Icon exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += iconLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading Icon");
            }
        }
        if ((nullBits[1] & 0x8) != 0x0) {
            final int translationPropertiesOffset = buffer.getIntLE(offset + 171);
            if (translationPropertiesOffset < 0) {
                return ValidationResult.error("Invalid offset for TranslationProperties");
            }
            int pos = offset + 251 + translationPropertiesOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for TranslationProperties");
            }
            final ValidationResult translationPropertiesResult = ItemTranslationProperties.validateStructure(buffer, pos);
            if (!translationPropertiesResult.isValid()) {
                return ValidationResult.error("Invalid TranslationProperties: " + translationPropertiesResult.error());
            }
            pos += ItemTranslationProperties.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[1] & 0x10) != 0x0) {
            final int resourceTypesOffset = buffer.getIntLE(offset + 175);
            if (resourceTypesOffset < 0) {
                return ValidationResult.error("Invalid offset for ResourceTypes");
            }
            int pos = offset + 251 + resourceTypesOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for ResourceTypes");
            }
            final int resourceTypesCount = VarInt.peek(buffer, pos);
            if (resourceTypesCount < 0) {
                return ValidationResult.error("Invalid array count for ResourceTypes");
            }
            if (resourceTypesCount > 4096000) {
                return ValidationResult.error("ResourceTypes exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < resourceTypesCount; ++i) {
                final ValidationResult structResult = ItemResourceType.validateStructure(buffer, pos);
                if (!structResult.isValid()) {
                    return ValidationResult.error("Invalid ItemResourceType in ResourceTypes[" + i + "]: " + structResult.error());
                }
                pos += ItemResourceType.computeBytesConsumed(buffer, pos);
            }
        }
        if ((nullBits[1] & 0x20) != 0x0) {
            final int toolOffset = buffer.getIntLE(offset + 179);
            if (toolOffset < 0) {
                return ValidationResult.error("Invalid offset for Tool");
            }
            int pos = offset + 251 + toolOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Tool");
            }
            final ValidationResult toolResult = ItemTool.validateStructure(buffer, pos);
            if (!toolResult.isValid()) {
                return ValidationResult.error("Invalid Tool: " + toolResult.error());
            }
            pos += ItemTool.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[1] & 0x40) != 0x0) {
            final int weaponOffset = buffer.getIntLE(offset + 183);
            if (weaponOffset < 0) {
                return ValidationResult.error("Invalid offset for Weapon");
            }
            int pos = offset + 251 + weaponOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Weapon");
            }
            final ValidationResult weaponResult = ItemWeapon.validateStructure(buffer, pos);
            if (!weaponResult.isValid()) {
                return ValidationResult.error("Invalid Weapon: " + weaponResult.error());
            }
            pos += ItemWeapon.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[1] & 0x80) != 0x0) {
            final int armorOffset = buffer.getIntLE(offset + 187);
            if (armorOffset < 0) {
                return ValidationResult.error("Invalid offset for Armor");
            }
            int pos = offset + 251 + armorOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Armor");
            }
            final ValidationResult armorResult = ItemArmor.validateStructure(buffer, pos);
            if (!armorResult.isValid()) {
                return ValidationResult.error("Invalid Armor: " + armorResult.error());
            }
            pos += ItemArmor.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[2] & 0x1) != 0x0) {
            final int utilityOffset = buffer.getIntLE(offset + 191);
            if (utilityOffset < 0) {
                return ValidationResult.error("Invalid offset for Utility");
            }
            int pos = offset + 251 + utilityOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Utility");
            }
            final ValidationResult utilityResult = ItemUtility.validateStructure(buffer, pos);
            if (!utilityResult.isValid()) {
                return ValidationResult.error("Invalid Utility: " + utilityResult.error());
            }
            pos += ItemUtility.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[2] & 0x2) != 0x0) {
            final int builderToolDataOffset = buffer.getIntLE(offset + 195);
            if (builderToolDataOffset < 0) {
                return ValidationResult.error("Invalid offset for BuilderToolData");
            }
            int pos = offset + 251 + builderToolDataOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for BuilderToolData");
            }
            final ValidationResult builderToolDataResult = ItemBuilderToolData.validateStructure(buffer, pos);
            if (!builderToolDataResult.isValid()) {
                return ValidationResult.error("Invalid BuilderToolData: " + builderToolDataResult.error());
            }
            pos += ItemBuilderToolData.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[2] & 0x4) != 0x0) {
            final int itemEntityOffset = buffer.getIntLE(offset + 199);
            if (itemEntityOffset < 0) {
                return ValidationResult.error("Invalid offset for ItemEntity");
            }
            int pos = offset + 251 + itemEntityOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for ItemEntity");
            }
            final ValidationResult itemEntityResult = ItemEntityConfig.validateStructure(buffer, pos);
            if (!itemEntityResult.isValid()) {
                return ValidationResult.error("Invalid ItemEntity: " + itemEntityResult.error());
            }
            pos += ItemEntityConfig.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[2] & 0x8) != 0x0) {
            final int setOffset = buffer.getIntLE(offset + 203);
            if (setOffset < 0) {
                return ValidationResult.error("Invalid offset for Set");
            }
            int pos = offset + 251 + setOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Set");
            }
            final int setLen = VarInt.peek(buffer, pos);
            if (setLen < 0) {
                return ValidationResult.error("Invalid string length for Set");
            }
            if (setLen > 4096000) {
                return ValidationResult.error("Set exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += setLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading Set");
            }
        }
        if ((nullBits[2] & 0x10) != 0x0) {
            final int categoriesOffset = buffer.getIntLE(offset + 207);
            if (categoriesOffset < 0) {
                return ValidationResult.error("Invalid offset for Categories");
            }
            int pos = offset + 251 + categoriesOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Categories");
            }
            final int categoriesCount = VarInt.peek(buffer, pos);
            if (categoriesCount < 0) {
                return ValidationResult.error("Invalid array count for Categories");
            }
            if (categoriesCount > 4096000) {
                return ValidationResult.error("Categories exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < categoriesCount; ++i) {
                final int strLen = VarInt.peek(buffer, pos);
                if (strLen < 0) {
                    return ValidationResult.error("Invalid string length in Categories");
                }
                pos += VarInt.length(buffer, pos);
                pos += strLen;
                if (pos > buffer.writerIndex()) {
                    return ValidationResult.error("Buffer overflow reading string in Categories");
                }
            }
        }
        if ((nullBits[2] & 0x20) != 0x0) {
            final int particlesOffset = buffer.getIntLE(offset + 211);
            if (particlesOffset < 0) {
                return ValidationResult.error("Invalid offset for Particles");
            }
            int pos = offset + 251 + particlesOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Particles");
            }
            final int particlesCount = VarInt.peek(buffer, pos);
            if (particlesCount < 0) {
                return ValidationResult.error("Invalid array count for Particles");
            }
            if (particlesCount > 4096000) {
                return ValidationResult.error("Particles exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < particlesCount; ++i) {
                final ValidationResult structResult = ModelParticle.validateStructure(buffer, pos);
                if (!structResult.isValid()) {
                    return ValidationResult.error("Invalid ModelParticle in Particles[" + i + "]: " + structResult.error());
                }
                pos += ModelParticle.computeBytesConsumed(buffer, pos);
            }
        }
        if ((nullBits[2] & 0x40) != 0x0) {
            final int firstPersonParticlesOffset = buffer.getIntLE(offset + 215);
            if (firstPersonParticlesOffset < 0) {
                return ValidationResult.error("Invalid offset for FirstPersonParticles");
            }
            int pos = offset + 251 + firstPersonParticlesOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for FirstPersonParticles");
            }
            final int firstPersonParticlesCount = VarInt.peek(buffer, pos);
            if (firstPersonParticlesCount < 0) {
                return ValidationResult.error("Invalid array count for FirstPersonParticles");
            }
            if (firstPersonParticlesCount > 4096000) {
                return ValidationResult.error("FirstPersonParticles exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < firstPersonParticlesCount; ++i) {
                final ValidationResult structResult = ModelParticle.validateStructure(buffer, pos);
                if (!structResult.isValid()) {
                    return ValidationResult.error("Invalid ModelParticle in FirstPersonParticles[" + i + "]: " + structResult.error());
                }
                pos += ModelParticle.computeBytesConsumed(buffer, pos);
            }
        }
        if ((nullBits[2] & 0x80) != 0x0) {
            final int trailsOffset = buffer.getIntLE(offset + 219);
            if (trailsOffset < 0) {
                return ValidationResult.error("Invalid offset for Trails");
            }
            int pos = offset + 251 + trailsOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Trails");
            }
            final int trailsCount = VarInt.peek(buffer, pos);
            if (trailsCount < 0) {
                return ValidationResult.error("Invalid array count for Trails");
            }
            if (trailsCount > 4096000) {
                return ValidationResult.error("Trails exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < trailsCount; ++i) {
                final ValidationResult structResult = ModelTrail.validateStructure(buffer, pos);
                if (!structResult.isValid()) {
                    return ValidationResult.error("Invalid ModelTrail in Trails[" + i + "]: " + structResult.error());
                }
                pos += ModelTrail.computeBytesConsumed(buffer, pos);
            }
        }
        if ((nullBits[3] & 0x1) != 0x0) {
            final int interactionsOffset = buffer.getIntLE(offset + 223);
            if (interactionsOffset < 0) {
                return ValidationResult.error("Invalid offset for Interactions");
            }
            int pos = offset + 251 + interactionsOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Interactions");
            }
            final int interactionsCount = VarInt.peek(buffer, pos);
            if (interactionsCount < 0) {
                return ValidationResult.error("Invalid dictionary count for Interactions");
            }
            if (interactionsCount > 4096000) {
                return ValidationResult.error("Interactions exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < interactionsCount; ++i) {
                ++pos;
                pos += 4;
                if (pos > buffer.writerIndex()) {
                    return ValidationResult.error("Buffer overflow reading value");
                }
            }
        }
        if ((nullBits[3] & 0x2) != 0x0) {
            final int interactionVarsOffset = buffer.getIntLE(offset + 227);
            if (interactionVarsOffset < 0) {
                return ValidationResult.error("Invalid offset for InteractionVars");
            }
            int pos = offset + 251 + interactionVarsOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for InteractionVars");
            }
            final int interactionVarsCount = VarInt.peek(buffer, pos);
            if (interactionVarsCount < 0) {
                return ValidationResult.error("Invalid dictionary count for InteractionVars");
            }
            if (interactionVarsCount > 4096000) {
                return ValidationResult.error("InteractionVars exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < interactionVarsCount; ++i) {
                final int keyLen = VarInt.peek(buffer, pos);
                if (keyLen < 0) {
                    return ValidationResult.error("Invalid string length for key");
                }
                if (keyLen > 4096000) {
                    return ValidationResult.error("key exceeds max length 4096000");
                }
                pos += VarInt.length(buffer, pos);
                pos += keyLen;
                if (pos > buffer.writerIndex()) {
                    return ValidationResult.error("Buffer overflow reading key");
                }
                pos += 4;
                if (pos > buffer.writerIndex()) {
                    return ValidationResult.error("Buffer overflow reading value");
                }
            }
        }
        if ((nullBits[3] & 0x4) != 0x0) {
            final int interactionConfigOffset = buffer.getIntLE(offset + 231);
            if (interactionConfigOffset < 0) {
                return ValidationResult.error("Invalid offset for InteractionConfig");
            }
            int pos = offset + 251 + interactionConfigOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for InteractionConfig");
            }
            final ValidationResult interactionConfigResult = InteractionConfiguration.validateStructure(buffer, pos);
            if (!interactionConfigResult.isValid()) {
                return ValidationResult.error("Invalid InteractionConfig: " + interactionConfigResult.error());
            }
            pos += InteractionConfiguration.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[3] & 0x8) != 0x0) {
            final int droppedItemAnimationOffset = buffer.getIntLE(offset + 235);
            if (droppedItemAnimationOffset < 0) {
                return ValidationResult.error("Invalid offset for DroppedItemAnimation");
            }
            int pos = offset + 251 + droppedItemAnimationOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for DroppedItemAnimation");
            }
            final int droppedItemAnimationLen = VarInt.peek(buffer, pos);
            if (droppedItemAnimationLen < 0) {
                return ValidationResult.error("Invalid string length for DroppedItemAnimation");
            }
            if (droppedItemAnimationLen > 4096000) {
                return ValidationResult.error("DroppedItemAnimation exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += droppedItemAnimationLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading DroppedItemAnimation");
            }
        }
        if ((nullBits[3] & 0x10) != 0x0) {
            final int tagIndexesOffset = buffer.getIntLE(offset + 239);
            if (tagIndexesOffset < 0) {
                return ValidationResult.error("Invalid offset for TagIndexes");
            }
            int pos = offset + 251 + tagIndexesOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for TagIndexes");
            }
            final int tagIndexesCount = VarInt.peek(buffer, pos);
            if (tagIndexesCount < 0) {
                return ValidationResult.error("Invalid array count for TagIndexes");
            }
            if (tagIndexesCount > 4096000) {
                return ValidationResult.error("TagIndexes exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += tagIndexesCount * 4;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading TagIndexes");
            }
        }
        if ((nullBits[3] & 0x20) != 0x0) {
            final int itemAppearanceConditionsOffset = buffer.getIntLE(offset + 243);
            if (itemAppearanceConditionsOffset < 0) {
                return ValidationResult.error("Invalid offset for ItemAppearanceConditions");
            }
            int pos = offset + 251 + itemAppearanceConditionsOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for ItemAppearanceConditions");
            }
            final int itemAppearanceConditionsCount = VarInt.peek(buffer, pos);
            if (itemAppearanceConditionsCount < 0) {
                return ValidationResult.error("Invalid dictionary count for ItemAppearanceConditions");
            }
            if (itemAppearanceConditionsCount > 4096000) {
                return ValidationResult.error("ItemAppearanceConditions exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < itemAppearanceConditionsCount; ++i) {
                pos += 4;
                if (pos > buffer.writerIndex()) {
                    return ValidationResult.error("Buffer overflow reading key");
                }
                final int valueArrCount = VarInt.peek(buffer, pos);
                if (valueArrCount < 0) {
                    return ValidationResult.error("Invalid array count for value");
                }
                pos += VarInt.length(buffer, pos);
                for (int valueArrIdx = 0; valueArrIdx < valueArrCount; ++valueArrIdx) {
                    pos += ItemAppearanceCondition.computeBytesConsumed(buffer, pos);
                }
            }
        }
        if ((nullBits[3] & 0x40) != 0x0) {
            final int displayEntityStatsHUDOffset = buffer.getIntLE(offset + 247);
            if (displayEntityStatsHUDOffset < 0) {
                return ValidationResult.error("Invalid offset for DisplayEntityStatsHUD");
            }
            int pos = offset + 251 + displayEntityStatsHUDOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for DisplayEntityStatsHUD");
            }
            final int displayEntityStatsHUDCount = VarInt.peek(buffer, pos);
            if (displayEntityStatsHUDCount < 0) {
                return ValidationResult.error("Invalid array count for DisplayEntityStatsHUD");
            }
            if (displayEntityStatsHUDCount > 4096000) {
                return ValidationResult.error("DisplayEntityStatsHUD exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += displayEntityStatsHUDCount * 4;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading DisplayEntityStatsHUD");
            }
        }
        return ValidationResult.OK;
    }
    
    public ItemBase clone() {
        final ItemBase copy = new ItemBase();
        copy.id = this.id;
        copy.model = this.model;
        copy.scale = this.scale;
        copy.texture = this.texture;
        copy.animation = this.animation;
        copy.playerAnimationsId = this.playerAnimationsId;
        copy.usePlayerAnimations = this.usePlayerAnimations;
        copy.maxStack = this.maxStack;
        copy.reticleIndex = this.reticleIndex;
        copy.icon = this.icon;
        copy.iconProperties = ((this.iconProperties != null) ? this.iconProperties.clone() : null);
        copy.translationProperties = ((this.translationProperties != null) ? this.translationProperties.clone() : null);
        copy.itemLevel = this.itemLevel;
        copy.qualityIndex = this.qualityIndex;
        Map.Entry<Integer, ItemAppearanceCondition[]> e = null;
        copy.resourceTypes = (ItemResourceType[])((this.resourceTypes != null) ? ((ItemResourceType[])Arrays.stream(this.resourceTypes).map(e -> e.clone()).toArray(ItemResourceType[]::new)) : null);
        copy.consumable = this.consumable;
        copy.variant = this.variant;
        copy.blockId = this.blockId;
        copy.tool = ((this.tool != null) ? this.tool.clone() : null);
        copy.weapon = ((this.weapon != null) ? this.weapon.clone() : null);
        copy.armor = ((this.armor != null) ? this.armor.clone() : null);
        copy.gliderConfig = ((this.gliderConfig != null) ? this.gliderConfig.clone() : null);
        copy.utility = ((this.utility != null) ? this.utility.clone() : null);
        copy.blockSelectorTool = ((this.blockSelectorTool != null) ? this.blockSelectorTool.clone() : null);
        copy.builderToolData = ((this.builderToolData != null) ? this.builderToolData.clone() : null);
        copy.itemEntity = ((this.itemEntity != null) ? this.itemEntity.clone() : null);
        copy.set = this.set;
        copy.categories = (String[])((this.categories != null) ? ((String[])Arrays.copyOf(this.categories, this.categories.length)) : null);
        copy.particles = (ModelParticle[])((this.particles != null) ? ((ModelParticle[])Arrays.stream(this.particles).map(e -> e.clone()).toArray(ModelParticle[]::new)) : null);
        copy.firstPersonParticles = (ModelParticle[])((this.firstPersonParticles != null) ? ((ModelParticle[])Arrays.stream(this.firstPersonParticles).map(e -> e.clone()).toArray(ModelParticle[]::new)) : null);
        copy.trails = (ModelTrail[])((this.trails != null) ? ((ModelTrail[])Arrays.stream(this.trails).map(e -> e.clone()).toArray(ModelTrail[]::new)) : null);
        copy.light = ((this.light != null) ? this.light.clone() : null);
        copy.durability = this.durability;
        copy.soundEventIndex = this.soundEventIndex;
        copy.itemSoundSetIndex = this.itemSoundSetIndex;
        copy.interactions = ((this.interactions != null) ? new HashMap<InteractionType, Integer>(this.interactions) : null);
        copy.interactionVars = ((this.interactionVars != null) ? new HashMap<String, Integer>(this.interactionVars) : null);
        copy.interactionConfig = ((this.interactionConfig != null) ? this.interactionConfig.clone() : null);
        copy.droppedItemAnimation = this.droppedItemAnimation;
        copy.tagIndexes = (int[])((this.tagIndexes != null) ? Arrays.copyOf(this.tagIndexes, this.tagIndexes.length) : null);
        if (this.itemAppearanceConditions != null) {
            final Map<Integer, ItemAppearanceCondition[]> m = new HashMap<Integer, ItemAppearanceCondition[]>();
            final Iterator<Map.Entry<Integer, ItemAppearanceCondition[]>> iterator = this.itemAppearanceConditions.entrySet().iterator();
            while (iterator.hasNext()) {
                e = iterator.next();
                m.put(e.getKey(), Arrays.stream(e.getValue()).map(x -> x.clone()).toArray(ItemAppearanceCondition[]::new));
            }
            copy.itemAppearanceConditions = m;
        }
        copy.displayEntityStatsHUD = (int[])((this.displayEntityStatsHUD != null) ? Arrays.copyOf(this.displayEntityStatsHUD, this.displayEntityStatsHUD.length) : null);
        copy.pullbackConfig = ((this.pullbackConfig != null) ? this.pullbackConfig.clone() : null);
        copy.clipsGeometry = this.clipsGeometry;
        copy.renderDeployablePreview = this.renderDeployablePreview;
        return copy;
    }
    
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof final ItemBase other) {
            return Objects.equals(this.id, other.id) && Objects.equals(this.model, other.model) && this.scale == other.scale && Objects.equals(this.texture, other.texture) && Objects.equals(this.animation, other.animation) && Objects.equals(this.playerAnimationsId, other.playerAnimationsId) && this.usePlayerAnimations == other.usePlayerAnimations && this.maxStack == other.maxStack && this.reticleIndex == other.reticleIndex && Objects.equals(this.icon, other.icon) && Objects.equals(this.iconProperties, other.iconProperties) && Objects.equals(this.translationProperties, other.translationProperties) && this.itemLevel == other.itemLevel && this.qualityIndex == other.qualityIndex && Arrays.equals(this.resourceTypes, other.resourceTypes) && this.consumable == other.consumable && this.variant == other.variant && this.blockId == other.blockId && Objects.equals(this.tool, other.tool) && Objects.equals(this.weapon, other.weapon) && Objects.equals(this.armor, other.armor) && Objects.equals(this.gliderConfig, other.gliderConfig) && Objects.equals(this.utility, other.utility) && Objects.equals(this.blockSelectorTool, other.blockSelectorTool) && Objects.equals(this.builderToolData, other.builderToolData) && Objects.equals(this.itemEntity, other.itemEntity) && Objects.equals(this.set, other.set) && Arrays.equals(this.categories, other.categories) && Arrays.equals(this.particles, other.particles) && Arrays.equals(this.firstPersonParticles, other.firstPersonParticles) && Arrays.equals(this.trails, other.trails) && Objects.equals(this.light, other.light) && this.durability == other.durability && this.soundEventIndex == other.soundEventIndex && this.itemSoundSetIndex == other.itemSoundSetIndex && Objects.equals(this.interactions, other.interactions) && Objects.equals(this.interactionVars, other.interactionVars) && Objects.equals(this.interactionConfig, other.interactionConfig) && Objects.equals(this.droppedItemAnimation, other.droppedItemAnimation) && Arrays.equals(this.tagIndexes, other.tagIndexes) && Objects.equals(this.itemAppearanceConditions, other.itemAppearanceConditions) && Arrays.equals(this.displayEntityStatsHUD, other.displayEntityStatsHUD) && Objects.equals(this.pullbackConfig, other.pullbackConfig) && this.clipsGeometry == other.clipsGeometry && this.renderDeployablePreview == other.renderDeployablePreview;
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        int result = 1;
        result = 31 * result + Objects.hashCode(this.id);
        result = 31 * result + Objects.hashCode(this.model);
        result = 31 * result + Float.hashCode(this.scale);
        result = 31 * result + Objects.hashCode(this.texture);
        result = 31 * result + Objects.hashCode(this.animation);
        result = 31 * result + Objects.hashCode(this.playerAnimationsId);
        result = 31 * result + Boolean.hashCode(this.usePlayerAnimations);
        result = 31 * result + Integer.hashCode(this.maxStack);
        result = 31 * result + Integer.hashCode(this.reticleIndex);
        result = 31 * result + Objects.hashCode(this.icon);
        result = 31 * result + Objects.hashCode(this.iconProperties);
        result = 31 * result + Objects.hashCode(this.translationProperties);
        result = 31 * result + Integer.hashCode(this.itemLevel);
        result = 31 * result + Integer.hashCode(this.qualityIndex);
        result = 31 * result + Arrays.hashCode(this.resourceTypes);
        result = 31 * result + Boolean.hashCode(this.consumable);
        result = 31 * result + Boolean.hashCode(this.variant);
        result = 31 * result + Integer.hashCode(this.blockId);
        result = 31 * result + Objects.hashCode(this.tool);
        result = 31 * result + Objects.hashCode(this.weapon);
        result = 31 * result + Objects.hashCode(this.armor);
        result = 31 * result + Objects.hashCode(this.gliderConfig);
        result = 31 * result + Objects.hashCode(this.utility);
        result = 31 * result + Objects.hashCode(this.blockSelectorTool);
        result = 31 * result + Objects.hashCode(this.builderToolData);
        result = 31 * result + Objects.hashCode(this.itemEntity);
        result = 31 * result + Objects.hashCode(this.set);
        result = 31 * result + Arrays.hashCode(this.categories);
        result = 31 * result + Arrays.hashCode(this.particles);
        result = 31 * result + Arrays.hashCode(this.firstPersonParticles);
        result = 31 * result + Arrays.hashCode(this.trails);
        result = 31 * result + Objects.hashCode(this.light);
        result = 31 * result + Double.hashCode(this.durability);
        result = 31 * result + Integer.hashCode(this.soundEventIndex);
        result = 31 * result + Integer.hashCode(this.itemSoundSetIndex);
        result = 31 * result + Objects.hashCode(this.interactions);
        result = 31 * result + Objects.hashCode(this.interactionVars);
        result = 31 * result + Objects.hashCode(this.interactionConfig);
        result = 31 * result + Objects.hashCode(this.droppedItemAnimation);
        result = 31 * result + Arrays.hashCode(this.tagIndexes);
        result = 31 * result + Objects.hashCode(this.itemAppearanceConditions);
        result = 31 * result + Arrays.hashCode(this.displayEntityStatsHUD);
        result = 31 * result + Objects.hashCode(this.pullbackConfig);
        result = 31 * result + Boolean.hashCode(this.clipsGeometry);
        result = 31 * result + Boolean.hashCode(this.renderDeployablePreview);
        return result;
    }
}
