// 
// 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 java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public class BlockType
{
    public static final int NULLABLE_BIT_FIELD_SIZE = 4;
    public static final int FIXED_BLOCK_SIZE = 163;
    public static final int VARIABLE_FIELD_COUNT = 24;
    public static final int VARIABLE_BLOCK_START = 259;
    public static final int MAX_SIZE = 1677721600;
    @Nullable
    public String item;
    @Nullable
    public String name;
    public boolean unknown;
    @Nonnull
    public DrawType drawType;
    @Nonnull
    public BlockMaterial material;
    @Nonnull
    public Opacity opacity;
    @Nullable
    public ShaderType[] shaderEffect;
    public int hitbox;
    public int interactionHitbox;
    @Nullable
    public String model;
    @Nullable
    public ModelTexture[] modelTexture;
    public float modelScale;
    @Nullable
    public String modelAnimation;
    public boolean looping;
    public int maxSupportDistance;
    @Nonnull
    public BlockSupportsRequiredForType blockSupportsRequiredFor;
    @Nullable
    public Map<BlockNeighbor, RequiredBlockFaceSupport[]> support;
    @Nullable
    public Map<BlockNeighbor, BlockFaceSupport[]> supporting;
    public boolean requiresAlphaBlending;
    @Nullable
    public BlockTextures[] cubeTextures;
    @Nullable
    public String cubeSideMaskTexture;
    @Nonnull
    public ShadingMode cubeShadingMode;
    @Nonnull
    public RandomRotation randomRotation;
    @Nonnull
    public VariantRotation variantRotation;
    @Nonnull
    public Rotation rotationYawPlacementOffset;
    public int blockSoundSetIndex;
    public int ambientSoundEventIndex;
    @Nullable
    public ModelParticle[] particles;
    @Nullable
    public String blockParticleSetId;
    @Nullable
    public String blockBreakingDecalId;
    @Nullable
    public Color particleColor;
    @Nullable
    public ColorLight light;
    @Nullable
    public Tint tint;
    @Nullable
    public Tint biomeTint;
    public int group;
    @Nullable
    public String transitionTexture;
    @Nullable
    public int[] transitionToGroups;
    @Nullable
    public BlockMovementSettings movementSettings;
    @Nullable
    public BlockFlags flags;
    @Nullable
    public String interactionHint;
    @Nullable
    public BlockGathering gathering;
    @Nullable
    public BlockPlacementSettings placementSettings;
    @Nullable
    public ModelDisplay display;
    @Nullable
    public RailConfig rail;
    public boolean ignoreSupportWhenPlaced;
    @Nullable
    public Map<InteractionType, Integer> interactions;
    @Nullable
    public Map<String, Integer> states;
    public int transitionToTag;
    @Nullable
    public int[] tagIndexes;
    @Nullable
    public Bench bench;
    @Nullable
    public ConnectedBlockRuleSet connectedBlockRuleSet;
    
    public BlockType() {
        this.drawType = DrawType.Empty;
        this.material = BlockMaterial.Empty;
        this.opacity = Opacity.Solid;
        this.blockSupportsRequiredFor = BlockSupportsRequiredForType.Any;
        this.cubeShadingMode = ShadingMode.Standard;
        this.randomRotation = RandomRotation.None;
        this.variantRotation = VariantRotation.None;
        this.rotationYawPlacementOffset = Rotation.None;
    }
    
    public BlockType(@Nullable final String item, @Nullable final String name, final boolean unknown, @Nonnull final DrawType drawType, @Nonnull final BlockMaterial material, @Nonnull final Opacity opacity, @Nullable final ShaderType[] shaderEffect, final int hitbox, final int interactionHitbox, @Nullable final String model, @Nullable final ModelTexture[] modelTexture, final float modelScale, @Nullable final String modelAnimation, final boolean looping, final int maxSupportDistance, @Nonnull final BlockSupportsRequiredForType blockSupportsRequiredFor, @Nullable final Map<BlockNeighbor, RequiredBlockFaceSupport[]> support, @Nullable final Map<BlockNeighbor, BlockFaceSupport[]> supporting, final boolean requiresAlphaBlending, @Nullable final BlockTextures[] cubeTextures, @Nullable final String cubeSideMaskTexture, @Nonnull final ShadingMode cubeShadingMode, @Nonnull final RandomRotation randomRotation, @Nonnull final VariantRotation variantRotation, @Nonnull final Rotation rotationYawPlacementOffset, final int blockSoundSetIndex, final int ambientSoundEventIndex, @Nullable final ModelParticle[] particles, @Nullable final String blockParticleSetId, @Nullable final String blockBreakingDecalId, @Nullable final Color particleColor, @Nullable final ColorLight light, @Nullable final Tint tint, @Nullable final Tint biomeTint, final int group, @Nullable final String transitionTexture, @Nullable final int[] transitionToGroups, @Nullable final BlockMovementSettings movementSettings, @Nullable final BlockFlags flags, @Nullable final String interactionHint, @Nullable final BlockGathering gathering, @Nullable final BlockPlacementSettings placementSettings, @Nullable final ModelDisplay display, @Nullable final RailConfig rail, final boolean ignoreSupportWhenPlaced, @Nullable final Map<InteractionType, Integer> interactions, @Nullable final Map<String, Integer> states, final int transitionToTag, @Nullable final int[] tagIndexes, @Nullable final Bench bench, @Nullable final ConnectedBlockRuleSet connectedBlockRuleSet) {
        this.drawType = DrawType.Empty;
        this.material = BlockMaterial.Empty;
        this.opacity = Opacity.Solid;
        this.blockSupportsRequiredFor = BlockSupportsRequiredForType.Any;
        this.cubeShadingMode = ShadingMode.Standard;
        this.randomRotation = RandomRotation.None;
        this.variantRotation = VariantRotation.None;
        this.rotationYawPlacementOffset = Rotation.None;
        this.item = item;
        this.name = name;
        this.unknown = unknown;
        this.drawType = drawType;
        this.material = material;
        this.opacity = opacity;
        this.shaderEffect = shaderEffect;
        this.hitbox = hitbox;
        this.interactionHitbox = interactionHitbox;
        this.model = model;
        this.modelTexture = modelTexture;
        this.modelScale = modelScale;
        this.modelAnimation = modelAnimation;
        this.looping = looping;
        this.maxSupportDistance = maxSupportDistance;
        this.blockSupportsRequiredFor = blockSupportsRequiredFor;
        this.support = support;
        this.supporting = supporting;
        this.requiresAlphaBlending = requiresAlphaBlending;
        this.cubeTextures = cubeTextures;
        this.cubeSideMaskTexture = cubeSideMaskTexture;
        this.cubeShadingMode = cubeShadingMode;
        this.randomRotation = randomRotation;
        this.variantRotation = variantRotation;
        this.rotationYawPlacementOffset = rotationYawPlacementOffset;
        this.blockSoundSetIndex = blockSoundSetIndex;
        this.ambientSoundEventIndex = ambientSoundEventIndex;
        this.particles = particles;
        this.blockParticleSetId = blockParticleSetId;
        this.blockBreakingDecalId = blockBreakingDecalId;
        this.particleColor = particleColor;
        this.light = light;
        this.tint = tint;
        this.biomeTint = biomeTint;
        this.group = group;
        this.transitionTexture = transitionTexture;
        this.transitionToGroups = transitionToGroups;
        this.movementSettings = movementSettings;
        this.flags = flags;
        this.interactionHint = interactionHint;
        this.gathering = gathering;
        this.placementSettings = placementSettings;
        this.display = display;
        this.rail = rail;
        this.ignoreSupportWhenPlaced = ignoreSupportWhenPlaced;
        this.interactions = interactions;
        this.states = states;
        this.transitionToTag = transitionToTag;
        this.tagIndexes = tagIndexes;
        this.bench = bench;
        this.connectedBlockRuleSet = connectedBlockRuleSet;
    }
    
    public BlockType(@Nonnull final BlockType other) {
        this.drawType = DrawType.Empty;
        this.material = BlockMaterial.Empty;
        this.opacity = Opacity.Solid;
        this.blockSupportsRequiredFor = BlockSupportsRequiredForType.Any;
        this.cubeShadingMode = ShadingMode.Standard;
        this.randomRotation = RandomRotation.None;
        this.variantRotation = VariantRotation.None;
        this.rotationYawPlacementOffset = Rotation.None;
        this.item = other.item;
        this.name = other.name;
        this.unknown = other.unknown;
        this.drawType = other.drawType;
        this.material = other.material;
        this.opacity = other.opacity;
        this.shaderEffect = other.shaderEffect;
        this.hitbox = other.hitbox;
        this.interactionHitbox = other.interactionHitbox;
        this.model = other.model;
        this.modelTexture = other.modelTexture;
        this.modelScale = other.modelScale;
        this.modelAnimation = other.modelAnimation;
        this.looping = other.looping;
        this.maxSupportDistance = other.maxSupportDistance;
        this.blockSupportsRequiredFor = other.blockSupportsRequiredFor;
        this.support = other.support;
        this.supporting = other.supporting;
        this.requiresAlphaBlending = other.requiresAlphaBlending;
        this.cubeTextures = other.cubeTextures;
        this.cubeSideMaskTexture = other.cubeSideMaskTexture;
        this.cubeShadingMode = other.cubeShadingMode;
        this.randomRotation = other.randomRotation;
        this.variantRotation = other.variantRotation;
        this.rotationYawPlacementOffset = other.rotationYawPlacementOffset;
        this.blockSoundSetIndex = other.blockSoundSetIndex;
        this.ambientSoundEventIndex = other.ambientSoundEventIndex;
        this.particles = other.particles;
        this.blockParticleSetId = other.blockParticleSetId;
        this.blockBreakingDecalId = other.blockBreakingDecalId;
        this.particleColor = other.particleColor;
        this.light = other.light;
        this.tint = other.tint;
        this.biomeTint = other.biomeTint;
        this.group = other.group;
        this.transitionTexture = other.transitionTexture;
        this.transitionToGroups = other.transitionToGroups;
        this.movementSettings = other.movementSettings;
        this.flags = other.flags;
        this.interactionHint = other.interactionHint;
        this.gathering = other.gathering;
        this.placementSettings = other.placementSettings;
        this.display = other.display;
        this.rail = other.rail;
        this.ignoreSupportWhenPlaced = other.ignoreSupportWhenPlaced;
        this.interactions = other.interactions;
        this.states = other.states;
        this.transitionToTag = other.transitionToTag;
        this.tagIndexes = other.tagIndexes;
        this.bench = other.bench;
        this.connectedBlockRuleSet = other.connectedBlockRuleSet;
    }
    
    @Nonnull
    public static BlockType deserialize(@Nonnull final ByteBuf buf, final int offset) {
        final BlockType obj = new BlockType();
        final byte[] nullBits = PacketIO.readBytes(buf, offset, 4);
        obj.unknown = (buf.getByte(offset + 4) != 0);
        obj.drawType = DrawType.fromValue(buf.getByte(offset + 5));
        obj.material = BlockMaterial.fromValue(buf.getByte(offset + 6));
        obj.opacity = Opacity.fromValue(buf.getByte(offset + 7));
        obj.hitbox = buf.getIntLE(offset + 8);
        obj.interactionHitbox = buf.getIntLE(offset + 12);
        obj.modelScale = buf.getFloatLE(offset + 16);
        obj.looping = (buf.getByte(offset + 20) != 0);
        obj.maxSupportDistance = buf.getIntLE(offset + 21);
        obj.blockSupportsRequiredFor = BlockSupportsRequiredForType.fromValue(buf.getByte(offset + 25));
        obj.requiresAlphaBlending = (buf.getByte(offset + 26) != 0);
        obj.cubeShadingMode = ShadingMode.fromValue(buf.getByte(offset + 27));
        obj.randomRotation = RandomRotation.fromValue(buf.getByte(offset + 28));
        obj.variantRotation = VariantRotation.fromValue(buf.getByte(offset + 29));
        obj.rotationYawPlacementOffset = Rotation.fromValue(buf.getByte(offset + 30));
        obj.blockSoundSetIndex = buf.getIntLE(offset + 31);
        obj.ambientSoundEventIndex = buf.getIntLE(offset + 35);
        if ((nullBits[0] & 0x1) != 0x0) {
            obj.particleColor = Color.deserialize(buf, offset + 39);
        }
        if ((nullBits[0] & 0x2) != 0x0) {
            obj.light = ColorLight.deserialize(buf, offset + 42);
        }
        if ((nullBits[0] & 0x4) != 0x0) {
            obj.tint = Tint.deserialize(buf, offset + 46);
        }
        if ((nullBits[0] & 0x8) != 0x0) {
            obj.biomeTint = Tint.deserialize(buf, offset + 70);
        }
        obj.group = buf.getIntLE(offset + 94);
        if ((nullBits[0] & 0x10) != 0x0) {
            obj.movementSettings = BlockMovementSettings.deserialize(buf, offset + 98);
        }
        if ((nullBits[0] & 0x20) != 0x0) {
            obj.flags = BlockFlags.deserialize(buf, offset + 140);
        }
        if ((nullBits[0] & 0x40) != 0x0) {
            obj.placementSettings = BlockPlacementSettings.deserialize(buf, offset + 142);
        }
        obj.ignoreSupportWhenPlaced = (buf.getByte(offset + 158) != 0);
        obj.transitionToTag = buf.getIntLE(offset + 159);
        if ((nullBits[0] & 0x80) != 0x0) {
            final int varPos0 = offset + 259 + buf.getIntLE(offset + 163);
            final int itemLen = VarInt.peek(buf, varPos0);
            if (itemLen < 0) {
                throw ProtocolException.negativeLength("Item", itemLen);
            }
            if (itemLen > 4096000) {
                throw ProtocolException.stringTooLong("Item", itemLen, 4096000);
            }
            obj.item = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8);
        }
        if ((nullBits[1] & 0x1) != 0x0) {
            final int varPos2 = offset + 259 + buf.getIntLE(offset + 167);
            final int nameLen = VarInt.peek(buf, varPos2);
            if (nameLen < 0) {
                throw ProtocolException.negativeLength("Name", nameLen);
            }
            if (nameLen > 4096000) {
                throw ProtocolException.stringTooLong("Name", nameLen, 4096000);
            }
            obj.name = PacketIO.readVarString(buf, varPos2, PacketIO.UTF8);
        }
        if ((nullBits[1] & 0x2) != 0x0) {
            final int varPos3 = offset + 259 + buf.getIntLE(offset + 171);
            final int shaderEffectCount = VarInt.peek(buf, varPos3);
            if (shaderEffectCount < 0) {
                throw ProtocolException.negativeLength("ShaderEffect", shaderEffectCount);
            }
            if (shaderEffectCount > 4096000) {
                throw ProtocolException.arrayTooLong("ShaderEffect", shaderEffectCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos3);
            if (varPos3 + varIntLen + shaderEffectCount * 1L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("ShaderEffect", varPos3 + varIntLen + shaderEffectCount * 1, buf.readableBytes());
            }
            obj.shaderEffect = new ShaderType[shaderEffectCount];
            int elemPos = varPos3 + varIntLen;
            for (int i = 0; i < shaderEffectCount; ++i) {
                obj.shaderEffect[i] = ShaderType.fromValue(buf.getByte(elemPos));
                ++elemPos;
            }
        }
        if ((nullBits[1] & 0x4) != 0x0) {
            final int varPos4 = offset + 259 + buf.getIntLE(offset + 175);
            final int modelLen = VarInt.peek(buf, varPos4);
            if (modelLen < 0) {
                throw ProtocolException.negativeLength("Model", modelLen);
            }
            if (modelLen > 4096000) {
                throw ProtocolException.stringTooLong("Model", modelLen, 4096000);
            }
            obj.model = PacketIO.readVarString(buf, varPos4, PacketIO.UTF8);
        }
        if ((nullBits[1] & 0x8) != 0x0) {
            final int varPos5 = offset + 259 + buf.getIntLE(offset + 179);
            final int modelTextureCount = VarInt.peek(buf, varPos5);
            if (modelTextureCount < 0) {
                throw ProtocolException.negativeLength("ModelTexture", modelTextureCount);
            }
            if (modelTextureCount > 4096000) {
                throw ProtocolException.arrayTooLong("ModelTexture", modelTextureCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos5);
            if (varPos5 + varIntLen + modelTextureCount * 5L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("ModelTexture", varPos5 + varIntLen + modelTextureCount * 5, buf.readableBytes());
            }
            obj.modelTexture = new ModelTexture[modelTextureCount];
            int elemPos = varPos5 + varIntLen;
            for (int i = 0; i < modelTextureCount; ++i) {
                obj.modelTexture[i] = ModelTexture.deserialize(buf, elemPos);
                elemPos += ModelTexture.computeBytesConsumed(buf, elemPos);
            }
        }
        if ((nullBits[1] & 0x10) != 0x0) {
            final int varPos6 = offset + 259 + buf.getIntLE(offset + 183);
            final int modelAnimationLen = VarInt.peek(buf, varPos6);
            if (modelAnimationLen < 0) {
                throw ProtocolException.negativeLength("ModelAnimation", modelAnimationLen);
            }
            if (modelAnimationLen > 4096000) {
                throw ProtocolException.stringTooLong("ModelAnimation", modelAnimationLen, 4096000);
            }
            obj.modelAnimation = PacketIO.readVarString(buf, varPos6, PacketIO.UTF8);
        }
        if ((nullBits[1] & 0x20) != 0x0) {
            final int varPos7 = offset + 259 + buf.getIntLE(offset + 187);
            final int supportCount = VarInt.peek(buf, varPos7);
            if (supportCount < 0) {
                throw ProtocolException.negativeLength("Support", supportCount);
            }
            if (supportCount > 4096000) {
                throw ProtocolException.dictionaryTooLarge("Support", supportCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos7);
            obj.support = new HashMap<BlockNeighbor, RequiredBlockFaceSupport[]>(supportCount);
            int dictPos = varPos7 + varIntLen;
            for (int i = 0; i < supportCount; ++i) {
                final BlockNeighbor key = BlockNeighbor.fromValue(buf.getByte(dictPos));
                ++dictPos;
                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 * 17L > buf.readableBytes()) {
                    throw ProtocolException.bufferTooSmall("val", dictPos + valVarLen + valLen * 17, buf.readableBytes());
                }
                dictPos += valVarLen;
                final RequiredBlockFaceSupport[] val = new RequiredBlockFaceSupport[valLen];
                for (int valIdx = 0; valIdx < valLen; ++valIdx) {
                    val[valIdx] = RequiredBlockFaceSupport.deserialize(buf, dictPos);
                    dictPos += RequiredBlockFaceSupport.computeBytesConsumed(buf, dictPos);
                }
                if (obj.support.put(key, val) != null) {
                    throw ProtocolException.duplicateKey("support", key);
                }
            }
        }
        if ((nullBits[1] & 0x40) != 0x0) {
            final int varPos8 = offset + 259 + buf.getIntLE(offset + 191);
            final int supportingCount = VarInt.peek(buf, varPos8);
            if (supportingCount < 0) {
                throw ProtocolException.negativeLength("Supporting", supportingCount);
            }
            if (supportingCount > 4096000) {
                throw ProtocolException.dictionaryTooLarge("Supporting", supportingCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos8);
            obj.supporting = new HashMap<BlockNeighbor, BlockFaceSupport[]>(supportingCount);
            int dictPos = varPos8 + varIntLen;
            for (int i = 0; i < supportingCount; ++i) {
                final BlockNeighbor key = BlockNeighbor.fromValue(buf.getByte(dictPos));
                ++dictPos;
                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 * 1L > buf.readableBytes()) {
                    throw ProtocolException.bufferTooSmall("val", dictPos + valVarLen + valLen * 1, buf.readableBytes());
                }
                dictPos += valVarLen;
                final BlockFaceSupport[] val2 = new BlockFaceSupport[valLen];
                for (int valIdx = 0; valIdx < valLen; ++valIdx) {
                    val2[valIdx] = BlockFaceSupport.deserialize(buf, dictPos);
                    dictPos += BlockFaceSupport.computeBytesConsumed(buf, dictPos);
                }
                if (obj.supporting.put(key, val2) != null) {
                    throw ProtocolException.duplicateKey("supporting", key);
                }
            }
        }
        if ((nullBits[1] & 0x80) != 0x0) {
            final int varPos9 = offset + 259 + buf.getIntLE(offset + 195);
            final int cubeTexturesCount = VarInt.peek(buf, varPos9);
            if (cubeTexturesCount < 0) {
                throw ProtocolException.negativeLength("CubeTextures", cubeTexturesCount);
            }
            if (cubeTexturesCount > 4096000) {
                throw ProtocolException.arrayTooLong("CubeTextures", cubeTexturesCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos9);
            if (varPos9 + varIntLen + cubeTexturesCount * 5L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("CubeTextures", varPos9 + varIntLen + cubeTexturesCount * 5, buf.readableBytes());
            }
            obj.cubeTextures = new BlockTextures[cubeTexturesCount];
            int elemPos = varPos9 + varIntLen;
            for (int i = 0; i < cubeTexturesCount; ++i) {
                obj.cubeTextures[i] = BlockTextures.deserialize(buf, elemPos);
                elemPos += BlockTextures.computeBytesConsumed(buf, elemPos);
            }
        }
        if ((nullBits[2] & 0x1) != 0x0) {
            final int varPos10 = offset + 259 + buf.getIntLE(offset + 199);
            final int cubeSideMaskTextureLen = VarInt.peek(buf, varPos10);
            if (cubeSideMaskTextureLen < 0) {
                throw ProtocolException.negativeLength("CubeSideMaskTexture", cubeSideMaskTextureLen);
            }
            if (cubeSideMaskTextureLen > 4096000) {
                throw ProtocolException.stringTooLong("CubeSideMaskTexture", cubeSideMaskTextureLen, 4096000);
            }
            obj.cubeSideMaskTexture = PacketIO.readVarString(buf, varPos10, PacketIO.UTF8);
        }
        if ((nullBits[2] & 0x2) != 0x0) {
            final int varPos11 = offset + 259 + buf.getIntLE(offset + 203);
            final int particlesCount = VarInt.peek(buf, varPos11);
            if (particlesCount < 0) {
                throw ProtocolException.negativeLength("Particles", particlesCount);
            }
            if (particlesCount > 4096000) {
                throw ProtocolException.arrayTooLong("Particles", particlesCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos11);
            if (varPos11 + varIntLen + particlesCount * 34L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("Particles", varPos11 + varIntLen + particlesCount * 34, buf.readableBytes());
            }
            obj.particles = new ModelParticle[particlesCount];
            int elemPos = varPos11 + varIntLen;
            for (int i = 0; i < particlesCount; ++i) {
                obj.particles[i] = ModelParticle.deserialize(buf, elemPos);
                elemPos += ModelParticle.computeBytesConsumed(buf, elemPos);
            }
        }
        if ((nullBits[2] & 0x4) != 0x0) {
            final int varPos12 = offset + 259 + buf.getIntLE(offset + 207);
            final int blockParticleSetIdLen = VarInt.peek(buf, varPos12);
            if (blockParticleSetIdLen < 0) {
                throw ProtocolException.negativeLength("BlockParticleSetId", blockParticleSetIdLen);
            }
            if (blockParticleSetIdLen > 4096000) {
                throw ProtocolException.stringTooLong("BlockParticleSetId", blockParticleSetIdLen, 4096000);
            }
            obj.blockParticleSetId = PacketIO.readVarString(buf, varPos12, PacketIO.UTF8);
        }
        if ((nullBits[2] & 0x8) != 0x0) {
            final int varPos13 = offset + 259 + buf.getIntLE(offset + 211);
            final int blockBreakingDecalIdLen = VarInt.peek(buf, varPos13);
            if (blockBreakingDecalIdLen < 0) {
                throw ProtocolException.negativeLength("BlockBreakingDecalId", blockBreakingDecalIdLen);
            }
            if (blockBreakingDecalIdLen > 4096000) {
                throw ProtocolException.stringTooLong("BlockBreakingDecalId", blockBreakingDecalIdLen, 4096000);
            }
            obj.blockBreakingDecalId = PacketIO.readVarString(buf, varPos13, PacketIO.UTF8);
        }
        if ((nullBits[2] & 0x10) != 0x0) {
            final int varPos14 = offset + 259 + buf.getIntLE(offset + 215);
            final int transitionTextureLen = VarInt.peek(buf, varPos14);
            if (transitionTextureLen < 0) {
                throw ProtocolException.negativeLength("TransitionTexture", transitionTextureLen);
            }
            if (transitionTextureLen > 4096000) {
                throw ProtocolException.stringTooLong("TransitionTexture", transitionTextureLen, 4096000);
            }
            obj.transitionTexture = PacketIO.readVarString(buf, varPos14, PacketIO.UTF8);
        }
        if ((nullBits[2] & 0x20) != 0x0) {
            final int varPos15 = offset + 259 + buf.getIntLE(offset + 219);
            final int transitionToGroupsCount = VarInt.peek(buf, varPos15);
            if (transitionToGroupsCount < 0) {
                throw ProtocolException.negativeLength("TransitionToGroups", transitionToGroupsCount);
            }
            if (transitionToGroupsCount > 4096000) {
                throw ProtocolException.arrayTooLong("TransitionToGroups", transitionToGroupsCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos15);
            if (varPos15 + varIntLen + transitionToGroupsCount * 4L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("TransitionToGroups", varPos15 + varIntLen + transitionToGroupsCount * 4, buf.readableBytes());
            }
            obj.transitionToGroups = new int[transitionToGroupsCount];
            for (int j = 0; j < transitionToGroupsCount; ++j) {
                obj.transitionToGroups[j] = buf.getIntLE(varPos15 + varIntLen + j * 4);
            }
        }
        if ((nullBits[2] & 0x40) != 0x0) {
            final int varPos16 = offset + 259 + buf.getIntLE(offset + 223);
            final int interactionHintLen = VarInt.peek(buf, varPos16);
            if (interactionHintLen < 0) {
                throw ProtocolException.negativeLength("InteractionHint", interactionHintLen);
            }
            if (interactionHintLen > 4096000) {
                throw ProtocolException.stringTooLong("InteractionHint", interactionHintLen, 4096000);
            }
            obj.interactionHint = PacketIO.readVarString(buf, varPos16, PacketIO.UTF8);
        }
        if ((nullBits[2] & 0x80) != 0x0) {
            final int varPos17 = offset + 259 + buf.getIntLE(offset + 227);
            obj.gathering = BlockGathering.deserialize(buf, varPos17);
        }
        if ((nullBits[3] & 0x1) != 0x0) {
            final int varPos18 = offset + 259 + buf.getIntLE(offset + 231);
            obj.display = ModelDisplay.deserialize(buf, varPos18);
        }
        if ((nullBits[3] & 0x2) != 0x0) {
            final int varPos19 = offset + 259 + buf.getIntLE(offset + 235);
            obj.rail = RailConfig.deserialize(buf, varPos19);
        }
        if ((nullBits[3] & 0x4) != 0x0) {
            final int varPos20 = offset + 259 + buf.getIntLE(offset + 239);
            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 key2 = InteractionType.fromValue(buf.getByte(dictPos));
                ++dictPos;
                final int val3 = buf.getIntLE(dictPos);
                dictPos += 4;
                if (obj.interactions.put(key2, val3) != null) {
                    throw ProtocolException.duplicateKey("interactions", key2);
                }
            }
        }
        if ((nullBits[3] & 0x8) != 0x0) {
            final int varPos21 = offset + 259 + buf.getIntLE(offset + 243);
            final int statesCount = VarInt.peek(buf, varPos21);
            if (statesCount < 0) {
                throw ProtocolException.negativeLength("States", statesCount);
            }
            if (statesCount > 4096000) {
                throw ProtocolException.dictionaryTooLarge("States", statesCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos21);
            obj.states = new HashMap<String, Integer>(statesCount);
            int dictPos = varPos21 + varIntLen;
            for (int i = 0; i < statesCount; ++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 key3 = PacketIO.readVarString(buf, dictPos);
                dictPos += keyVarLen + keyLen;
                final int val4 = buf.getIntLE(dictPos);
                dictPos += 4;
                if (obj.states.put(key3, val4) != null) {
                    throw ProtocolException.duplicateKey("states", key3);
                }
            }
        }
        if ((nullBits[3] & 0x10) != 0x0) {
            final int varPos22 = offset + 259 + buf.getIntLE(offset + 247);
            final int tagIndexesCount = VarInt.peek(buf, varPos22);
            if (tagIndexesCount < 0) {
                throw ProtocolException.negativeLength("TagIndexes", tagIndexesCount);
            }
            if (tagIndexesCount > 4096000) {
                throw ProtocolException.arrayTooLong("TagIndexes", tagIndexesCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos22);
            if (varPos22 + varIntLen + tagIndexesCount * 4L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("TagIndexes", varPos22 + varIntLen + tagIndexesCount * 4, buf.readableBytes());
            }
            obj.tagIndexes = new int[tagIndexesCount];
            for (int j = 0; j < tagIndexesCount; ++j) {
                obj.tagIndexes[j] = buf.getIntLE(varPos22 + varIntLen + j * 4);
            }
        }
        if ((nullBits[3] & 0x20) != 0x0) {
            final int varPos23 = offset + 259 + buf.getIntLE(offset + 251);
            obj.bench = Bench.deserialize(buf, varPos23);
        }
        if ((nullBits[3] & 0x40) != 0x0) {
            final int varPos24 = offset + 259 + buf.getIntLE(offset + 255);
            obj.connectedBlockRuleSet = ConnectedBlockRuleSet.deserialize(buf, varPos24);
        }
        return obj;
    }
    
    public static int computeBytesConsumed(@Nonnull final ByteBuf buf, final int offset) {
        final byte[] nullBits = PacketIO.readBytes(buf, offset, 4);
        int maxEnd = 259;
        if ((nullBits[0] & 0x80) != 0x0) {
            final int fieldOffset0 = buf.getIntLE(offset + 163);
            int pos0 = offset + 259 + fieldOffset0;
            final int sl = VarInt.peek(buf, pos0);
            pos0 += VarInt.length(buf, pos0) + sl;
            if (pos0 - offset > maxEnd) {
                maxEnd = pos0 - offset;
            }
        }
        if ((nullBits[1] & 0x1) != 0x0) {
            final int fieldOffset2 = buf.getIntLE(offset + 167);
            int pos2 = offset + 259 + fieldOffset2;
            final int sl = VarInt.peek(buf, pos2);
            pos2 += VarInt.length(buf, pos2) + sl;
            if (pos2 - offset > maxEnd) {
                maxEnd = pos2 - offset;
            }
        }
        if ((nullBits[1] & 0x2) != 0x0) {
            final int fieldOffset3 = buf.getIntLE(offset + 171);
            int pos3 = offset + 259 + fieldOffset3;
            final int arrLen = VarInt.peek(buf, pos3);
            pos3 += VarInt.length(buf, pos3) + arrLen * 1;
            if (pos3 - offset > maxEnd) {
                maxEnd = pos3 - offset;
            }
        }
        if ((nullBits[1] & 0x4) != 0x0) {
            final int fieldOffset4 = buf.getIntLE(offset + 175);
            int pos4 = offset + 259 + fieldOffset4;
            final int sl = VarInt.peek(buf, pos4);
            pos4 += VarInt.length(buf, pos4) + sl;
            if (pos4 - offset > maxEnd) {
                maxEnd = pos4 - offset;
            }
        }
        if ((nullBits[1] & 0x8) != 0x0) {
            final int fieldOffset5 = buf.getIntLE(offset + 179);
            int pos5 = offset + 259 + fieldOffset5;
            final int arrLen = VarInt.peek(buf, pos5);
            pos5 += VarInt.length(buf, pos5);
            for (int i = 0; i < arrLen; ++i) {
                pos5 += ModelTexture.computeBytesConsumed(buf, pos5);
            }
            if (pos5 - offset > maxEnd) {
                maxEnd = pos5 - offset;
            }
        }
        if ((nullBits[1] & 0x10) != 0x0) {
            final int fieldOffset6 = buf.getIntLE(offset + 183);
            int pos6 = offset + 259 + fieldOffset6;
            final int sl = VarInt.peek(buf, pos6);
            pos6 += VarInt.length(buf, pos6) + sl;
            if (pos6 - offset > maxEnd) {
                maxEnd = pos6 - offset;
            }
        }
        if ((nullBits[1] & 0x20) != 0x0) {
            final int fieldOffset7 = buf.getIntLE(offset + 187);
            int pos7 = offset + 259 + fieldOffset7;
            final int dictLen = VarInt.peek(buf, pos7);
            pos7 += VarInt.length(buf, pos7);
            for (int i = 0; i < dictLen; ++i) {
                ++pos7;
                final int al = VarInt.peek(buf, pos7);
                pos7 += VarInt.length(buf, pos7);
                for (int j = 0; j < al; ++j) {
                    pos7 += RequiredBlockFaceSupport.computeBytesConsumed(buf, pos7);
                }
            }
            if (pos7 - offset > maxEnd) {
                maxEnd = pos7 - offset;
            }
        }
        if ((nullBits[1] & 0x40) != 0x0) {
            final int fieldOffset8 = buf.getIntLE(offset + 191);
            int pos8 = offset + 259 + fieldOffset8;
            final int dictLen = VarInt.peek(buf, pos8);
            pos8 += VarInt.length(buf, pos8);
            for (int i = 0; i < dictLen; ++i) {
                ++pos8;
                final int al = VarInt.peek(buf, pos8);
                pos8 += VarInt.length(buf, pos8);
                for (int j = 0; j < al; ++j) {
                    pos8 += BlockFaceSupport.computeBytesConsumed(buf, pos8);
                }
            }
            if (pos8 - offset > maxEnd) {
                maxEnd = pos8 - offset;
            }
        }
        if ((nullBits[1] & 0x80) != 0x0) {
            final int fieldOffset9 = buf.getIntLE(offset + 195);
            int pos9 = offset + 259 + fieldOffset9;
            final int arrLen = VarInt.peek(buf, pos9);
            pos9 += VarInt.length(buf, pos9);
            for (int i = 0; i < arrLen; ++i) {
                pos9 += BlockTextures.computeBytesConsumed(buf, pos9);
            }
            if (pos9 - offset > maxEnd) {
                maxEnd = pos9 - offset;
            }
        }
        if ((nullBits[2] & 0x1) != 0x0) {
            final int fieldOffset10 = buf.getIntLE(offset + 199);
            int pos10 = offset + 259 + fieldOffset10;
            final int sl = VarInt.peek(buf, pos10);
            pos10 += VarInt.length(buf, pos10) + sl;
            if (pos10 - offset > maxEnd) {
                maxEnd = pos10 - offset;
            }
        }
        if ((nullBits[2] & 0x2) != 0x0) {
            final int fieldOffset11 = buf.getIntLE(offset + 203);
            int pos11 = offset + 259 + fieldOffset11;
            final int arrLen = VarInt.peek(buf, pos11);
            pos11 += VarInt.length(buf, pos11);
            for (int i = 0; i < arrLen; ++i) {
                pos11 += ModelParticle.computeBytesConsumed(buf, pos11);
            }
            if (pos11 - offset > maxEnd) {
                maxEnd = pos11 - offset;
            }
        }
        if ((nullBits[2] & 0x4) != 0x0) {
            final int fieldOffset12 = buf.getIntLE(offset + 207);
            int pos12 = offset + 259 + fieldOffset12;
            final int sl = VarInt.peek(buf, pos12);
            pos12 += VarInt.length(buf, pos12) + sl;
            if (pos12 - offset > maxEnd) {
                maxEnd = pos12 - offset;
            }
        }
        if ((nullBits[2] & 0x8) != 0x0) {
            final int fieldOffset13 = buf.getIntLE(offset + 211);
            int pos13 = offset + 259 + fieldOffset13;
            final int sl = VarInt.peek(buf, pos13);
            pos13 += VarInt.length(buf, pos13) + sl;
            if (pos13 - offset > maxEnd) {
                maxEnd = pos13 - offset;
            }
        }
        if ((nullBits[2] & 0x10) != 0x0) {
            final int fieldOffset14 = buf.getIntLE(offset + 215);
            int pos14 = offset + 259 + fieldOffset14;
            final int sl = VarInt.peek(buf, pos14);
            pos14 += VarInt.length(buf, pos14) + sl;
            if (pos14 - offset > maxEnd) {
                maxEnd = pos14 - offset;
            }
        }
        if ((nullBits[2] & 0x20) != 0x0) {
            final int fieldOffset15 = buf.getIntLE(offset + 219);
            int pos15 = offset + 259 + fieldOffset15;
            final int arrLen = VarInt.peek(buf, pos15);
            pos15 += VarInt.length(buf, pos15) + arrLen * 4;
            if (pos15 - offset > maxEnd) {
                maxEnd = pos15 - offset;
            }
        }
        if ((nullBits[2] & 0x40) != 0x0) {
            final int fieldOffset16 = buf.getIntLE(offset + 223);
            int pos16 = offset + 259 + fieldOffset16;
            final int sl = VarInt.peek(buf, pos16);
            pos16 += VarInt.length(buf, pos16) + sl;
            if (pos16 - offset > maxEnd) {
                maxEnd = pos16 - offset;
            }
        }
        if ((nullBits[2] & 0x80) != 0x0) {
            final int fieldOffset17 = buf.getIntLE(offset + 227);
            int pos17 = offset + 259 + fieldOffset17;
            pos17 += BlockGathering.computeBytesConsumed(buf, pos17);
            if (pos17 - offset > maxEnd) {
                maxEnd = pos17 - offset;
            }
        }
        if ((nullBits[3] & 0x1) != 0x0) {
            final int fieldOffset18 = buf.getIntLE(offset + 231);
            int pos18 = offset + 259 + fieldOffset18;
            pos18 += ModelDisplay.computeBytesConsumed(buf, pos18);
            if (pos18 - offset > maxEnd) {
                maxEnd = pos18 - offset;
            }
        }
        if ((nullBits[3] & 0x2) != 0x0) {
            final int fieldOffset19 = buf.getIntLE(offset + 235);
            int pos19 = offset + 259 + fieldOffset19;
            pos19 += RailConfig.computeBytesConsumed(buf, pos19);
            if (pos19 - offset > maxEnd) {
                maxEnd = pos19 - offset;
            }
        }
        if ((nullBits[3] & 0x4) != 0x0) {
            final int fieldOffset20 = buf.getIntLE(offset + 239);
            int pos20 = offset + 259 + 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] & 0x8) != 0x0) {
            final int fieldOffset21 = buf.getIntLE(offset + 243);
            int pos21 = offset + 259 + 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] & 0x10) != 0x0) {
            final int fieldOffset22 = buf.getIntLE(offset + 247);
            int pos22 = offset + 259 + fieldOffset22;
            final int arrLen = VarInt.peek(buf, pos22);
            pos22 += VarInt.length(buf, pos22) + arrLen * 4;
            if (pos22 - offset > maxEnd) {
                maxEnd = pos22 - offset;
            }
        }
        if ((nullBits[3] & 0x20) != 0x0) {
            final int fieldOffset23 = buf.getIntLE(offset + 251);
            int pos23 = offset + 259 + fieldOffset23;
            pos23 += Bench.computeBytesConsumed(buf, pos23);
            if (pos23 - offset > maxEnd) {
                maxEnd = pos23 - offset;
            }
        }
        if ((nullBits[3] & 0x40) != 0x0) {
            final int fieldOffset24 = buf.getIntLE(offset + 255);
            int pos24 = offset + 259 + fieldOffset24;
            pos24 += ConnectedBlockRuleSet.computeBytesConsumed(buf, pos24);
            if (pos24 - offset > maxEnd) {
                maxEnd = pos24 - offset;
            }
        }
        return maxEnd;
    }
    
    public void serialize(@Nonnull final ByteBuf buf) {
        final int startPos = buf.writerIndex();
        final byte[] nullBits = new byte[4];
        if (this.particleColor != null) {
            final byte[] array = nullBits;
            final int n = 0;
            array[n] |= 0x1;
        }
        if (this.light != null) {
            final byte[] array2 = nullBits;
            final int n2 = 0;
            array2[n2] |= 0x2;
        }
        if (this.tint != null) {
            final byte[] array3 = nullBits;
            final int n3 = 0;
            array3[n3] |= 0x4;
        }
        if (this.biomeTint != null) {
            final byte[] array4 = nullBits;
            final int n4 = 0;
            array4[n4] |= 0x8;
        }
        if (this.movementSettings != null) {
            final byte[] array5 = nullBits;
            final int n5 = 0;
            array5[n5] |= 0x10;
        }
        if (this.flags != null) {
            final byte[] array6 = nullBits;
            final int n6 = 0;
            array6[n6] |= 0x20;
        }
        if (this.placementSettings != null) {
            final byte[] array7 = nullBits;
            final int n7 = 0;
            array7[n7] |= 0x40;
        }
        if (this.item != null) {
            final byte[] array8 = nullBits;
            final int n8 = 0;
            array8[n8] |= (byte)128;
        }
        if (this.name != null) {
            final byte[] array9 = nullBits;
            final int n9 = 1;
            array9[n9] |= 0x1;
        }
        if (this.shaderEffect != null) {
            final byte[] array10 = nullBits;
            final int n10 = 1;
            array10[n10] |= 0x2;
        }
        if (this.model != null) {
            final byte[] array11 = nullBits;
            final int n11 = 1;
            array11[n11] |= 0x4;
        }
        if (this.modelTexture != null) {
            final byte[] array12 = nullBits;
            final int n12 = 1;
            array12[n12] |= 0x8;
        }
        if (this.modelAnimation != null) {
            final byte[] array13 = nullBits;
            final int n13 = 1;
            array13[n13] |= 0x10;
        }
        if (this.support != null) {
            final byte[] array14 = nullBits;
            final int n14 = 1;
            array14[n14] |= 0x20;
        }
        if (this.supporting != null) {
            final byte[] array15 = nullBits;
            final int n15 = 1;
            array15[n15] |= 0x40;
        }
        if (this.cubeTextures != null) {
            final byte[] array16 = nullBits;
            final int n16 = 1;
            array16[n16] |= (byte)128;
        }
        if (this.cubeSideMaskTexture != null) {
            final byte[] array17 = nullBits;
            final int n17 = 2;
            array17[n17] |= 0x1;
        }
        if (this.particles != null) {
            final byte[] array18 = nullBits;
            final int n18 = 2;
            array18[n18] |= 0x2;
        }
        if (this.blockParticleSetId != null) {
            final byte[] array19 = nullBits;
            final int n19 = 2;
            array19[n19] |= 0x4;
        }
        if (this.blockBreakingDecalId != null) {
            final byte[] array20 = nullBits;
            final int n20 = 2;
            array20[n20] |= 0x8;
        }
        if (this.transitionTexture != null) {
            final byte[] array21 = nullBits;
            final int n21 = 2;
            array21[n21] |= 0x10;
        }
        if (this.transitionToGroups != null) {
            final byte[] array22 = nullBits;
            final int n22 = 2;
            array22[n22] |= 0x20;
        }
        if (this.interactionHint != null) {
            final byte[] array23 = nullBits;
            final int n23 = 2;
            array23[n23] |= 0x40;
        }
        if (this.gathering != null) {
            final byte[] array24 = nullBits;
            final int n24 = 2;
            array24[n24] |= (byte)128;
        }
        if (this.display != null) {
            final byte[] array25 = nullBits;
            final int n25 = 3;
            array25[n25] |= 0x1;
        }
        if (this.rail != null) {
            final byte[] array26 = nullBits;
            final int n26 = 3;
            array26[n26] |= 0x2;
        }
        if (this.interactions != null) {
            final byte[] array27 = nullBits;
            final int n27 = 3;
            array27[n27] |= 0x4;
        }
        if (this.states != 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.bench != null) {
            final byte[] array30 = nullBits;
            final int n30 = 3;
            array30[n30] |= 0x20;
        }
        if (this.connectedBlockRuleSet != null) {
            final byte[] array31 = nullBits;
            final int n31 = 3;
            array31[n31] |= 0x40;
        }
        buf.writeBytes(nullBits);
        buf.writeByte(this.unknown ? 1 : 0);
        buf.writeByte(this.drawType.getValue());
        buf.writeByte(this.material.getValue());
        buf.writeByte(this.opacity.getValue());
        buf.writeIntLE(this.hitbox);
        buf.writeIntLE(this.interactionHitbox);
        buf.writeFloatLE(this.modelScale);
        buf.writeByte(this.looping ? 1 : 0);
        buf.writeIntLE(this.maxSupportDistance);
        buf.writeByte(this.blockSupportsRequiredFor.getValue());
        buf.writeByte(this.requiresAlphaBlending ? 1 : 0);
        buf.writeByte(this.cubeShadingMode.getValue());
        buf.writeByte(this.randomRotation.getValue());
        buf.writeByte(this.variantRotation.getValue());
        buf.writeByte(this.rotationYawPlacementOffset.getValue());
        buf.writeIntLE(this.blockSoundSetIndex);
        buf.writeIntLE(this.ambientSoundEventIndex);
        if (this.particleColor != null) {
            this.particleColor.serialize(buf);
        }
        else {
            buf.writeZero(3);
        }
        if (this.light != null) {
            this.light.serialize(buf);
        }
        else {
            buf.writeZero(4);
        }
        if (this.tint != null) {
            this.tint.serialize(buf);
        }
        else {
            buf.writeZero(24);
        }
        if (this.biomeTint != null) {
            this.biomeTint.serialize(buf);
        }
        else {
            buf.writeZero(24);
        }
        buf.writeIntLE(this.group);
        if (this.movementSettings != null) {
            this.movementSettings.serialize(buf);
        }
        else {
            buf.writeZero(42);
        }
        if (this.flags != null) {
            this.flags.serialize(buf);
        }
        else {
            buf.writeZero(2);
        }
        if (this.placementSettings != null) {
            this.placementSettings.serialize(buf);
        }
        else {
            buf.writeZero(16);
        }
        buf.writeByte(this.ignoreSupportWhenPlaced ? 1 : 0);
        buf.writeIntLE(this.transitionToTag);
        final int itemOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int nameOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int shaderEffectOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int modelOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int modelTextureOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int modelAnimationOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int supportOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int supportingOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int cubeTexturesOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int cubeSideMaskTextureOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int particlesOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int blockParticleSetIdOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int blockBreakingDecalIdOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int transitionTextureOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int transitionToGroupsOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int interactionHintOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int gatheringOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int displayOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int railOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int interactionsOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int statesOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int tagIndexesOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int benchOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int connectedBlockRuleSetOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int varBlockStart = buf.writerIndex();
        if (this.item != null) {
            buf.setIntLE(itemOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.item, 4096000);
        }
        else {
            buf.setIntLE(itemOffsetSlot, -1);
        }
        if (this.name != null) {
            buf.setIntLE(nameOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.name, 4096000);
        }
        else {
            buf.setIntLE(nameOffsetSlot, -1);
        }
        if (this.shaderEffect != null) {
            buf.setIntLE(shaderEffectOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.shaderEffect.length > 4096000) {
                throw ProtocolException.arrayTooLong("ShaderEffect", this.shaderEffect.length, 4096000);
            }
            VarInt.write(buf, this.shaderEffect.length);
            for (final ShaderType item : this.shaderEffect) {
                buf.writeByte(item.getValue());
            }
        }
        else {
            buf.setIntLE(shaderEffectOffsetSlot, -1);
        }
        if (this.model != null) {
            buf.setIntLE(modelOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.model, 4096000);
        }
        else {
            buf.setIntLE(modelOffsetSlot, -1);
        }
        if (this.modelTexture != null) {
            buf.setIntLE(modelTextureOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.modelTexture.length > 4096000) {
                throw ProtocolException.arrayTooLong("ModelTexture", this.modelTexture.length, 4096000);
            }
            VarInt.write(buf, this.modelTexture.length);
            for (final ModelTexture item2 : this.modelTexture) {
                item2.serialize(buf);
            }
        }
        else {
            buf.setIntLE(modelTextureOffsetSlot, -1);
        }
        if (this.modelAnimation != null) {
            buf.setIntLE(modelAnimationOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.modelAnimation, 4096000);
        }
        else {
            buf.setIntLE(modelAnimationOffsetSlot, -1);
        }
        if (this.support != null) {
            buf.setIntLE(supportOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.support.size() > 4096000) {
                throw ProtocolException.dictionaryTooLarge("Support", this.support.size(), 4096000);
            }
            VarInt.write(buf, this.support.size());
            for (final Map.Entry<BlockNeighbor, RequiredBlockFaceSupport[]> e : this.support.entrySet()) {
                buf.writeByte(e.getKey().getValue());
                VarInt.write(buf, e.getValue().length);
                for (final RequiredBlockFaceSupport arrItem : e.getValue()) {
                    arrItem.serialize(buf);
                }
            }
        }
        else {
            buf.setIntLE(supportOffsetSlot, -1);
        }
        if (this.supporting != null) {
            buf.setIntLE(supportingOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.supporting.size() > 4096000) {
                throw ProtocolException.dictionaryTooLarge("Supporting", this.supporting.size(), 4096000);
            }
            VarInt.write(buf, this.supporting.size());
            for (final Map.Entry<BlockNeighbor, BlockFaceSupport[]> e2 : this.supporting.entrySet()) {
                buf.writeByte(e2.getKey().getValue());
                VarInt.write(buf, e2.getValue().length);
                for (final BlockFaceSupport arrItem2 : e2.getValue()) {
                    arrItem2.serialize(buf);
                }
            }
        }
        else {
            buf.setIntLE(supportingOffsetSlot, -1);
        }
        if (this.cubeTextures != null) {
            buf.setIntLE(cubeTexturesOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.cubeTextures.length > 4096000) {
                throw ProtocolException.arrayTooLong("CubeTextures", this.cubeTextures.length, 4096000);
            }
            VarInt.write(buf, this.cubeTextures.length);
            for (final BlockTextures item3 : this.cubeTextures) {
                item3.serialize(buf);
            }
        }
        else {
            buf.setIntLE(cubeTexturesOffsetSlot, -1);
        }
        if (this.cubeSideMaskTexture != null) {
            buf.setIntLE(cubeSideMaskTextureOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.cubeSideMaskTexture, 4096000);
        }
        else {
            buf.setIntLE(cubeSideMaskTextureOffsetSlot, -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 item4 : this.particles) {
                item4.serialize(buf);
            }
        }
        else {
            buf.setIntLE(particlesOffsetSlot, -1);
        }
        if (this.blockParticleSetId != null) {
            buf.setIntLE(blockParticleSetIdOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.blockParticleSetId, 4096000);
        }
        else {
            buf.setIntLE(blockParticleSetIdOffsetSlot, -1);
        }
        if (this.blockBreakingDecalId != null) {
            buf.setIntLE(blockBreakingDecalIdOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.blockBreakingDecalId, 4096000);
        }
        else {
            buf.setIntLE(blockBreakingDecalIdOffsetSlot, -1);
        }
        if (this.transitionTexture != null) {
            buf.setIntLE(transitionTextureOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.transitionTexture, 4096000);
        }
        else {
            buf.setIntLE(transitionTextureOffsetSlot, -1);
        }
        if (this.transitionToGroups != null) {
            buf.setIntLE(transitionToGroupsOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.transitionToGroups.length > 4096000) {
                throw ProtocolException.arrayTooLong("TransitionToGroups", this.transitionToGroups.length, 4096000);
            }
            VarInt.write(buf, this.transitionToGroups.length);
            for (final int item5 : this.transitionToGroups) {
                buf.writeIntLE(item5);
            }
        }
        else {
            buf.setIntLE(transitionToGroupsOffsetSlot, -1);
        }
        if (this.interactionHint != null) {
            buf.setIntLE(interactionHintOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.interactionHint, 4096000);
        }
        else {
            buf.setIntLE(interactionHintOffsetSlot, -1);
        }
        if (this.gathering != null) {
            buf.setIntLE(gatheringOffsetSlot, buf.writerIndex() - varBlockStart);
            this.gathering.serialize(buf);
        }
        else {
            buf.setIntLE(gatheringOffsetSlot, -1);
        }
        if (this.display != null) {
            buf.setIntLE(displayOffsetSlot, buf.writerIndex() - varBlockStart);
            this.display.serialize(buf);
        }
        else {
            buf.setIntLE(displayOffsetSlot, -1);
        }
        if (this.rail != null) {
            buf.setIntLE(railOffsetSlot, buf.writerIndex() - varBlockStart);
            this.rail.serialize(buf);
        }
        else {
            buf.setIntLE(railOffsetSlot, -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> e3 : this.interactions.entrySet()) {
                buf.writeByte(e3.getKey().getValue());
                buf.writeIntLE(e3.getValue());
            }
        }
        else {
            buf.setIntLE(interactionsOffsetSlot, -1);
        }
        if (this.states != null) {
            buf.setIntLE(statesOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.states.size() > 4096000) {
                throw ProtocolException.dictionaryTooLarge("States", this.states.size(), 4096000);
            }
            VarInt.write(buf, this.states.size());
            for (final Map.Entry<String, Integer> e4 : this.states.entrySet()) {
                PacketIO.writeVarString(buf, e4.getKey(), 4096000);
                buf.writeIntLE(e4.getValue());
            }
        }
        else {
            buf.setIntLE(statesOffsetSlot, -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.bench != null) {
            buf.setIntLE(benchOffsetSlot, buf.writerIndex() - varBlockStart);
            this.bench.serialize(buf);
        }
        else {
            buf.setIntLE(benchOffsetSlot, -1);
        }
        if (this.connectedBlockRuleSet != null) {
            buf.setIntLE(connectedBlockRuleSetOffsetSlot, buf.writerIndex() - varBlockStart);
            this.connectedBlockRuleSet.serialize(buf);
        }
        else {
            buf.setIntLE(connectedBlockRuleSetOffsetSlot, -1);
        }
    }
    
    public int computeSize() {
        int size = 259;
        if (this.item != null) {
            size += PacketIO.stringSize(this.item);
        }
        if (this.name != null) {
            size += PacketIO.stringSize(this.name);
        }
        if (this.shaderEffect != null) {
            size += VarInt.size(this.shaderEffect.length) + this.shaderEffect.length * 1;
        }
        if (this.model != null) {
            size += PacketIO.stringSize(this.model);
        }
        if (this.modelTexture != null) {
            int modelTextureSize = 0;
            for (final ModelTexture elem : this.modelTexture) {
                modelTextureSize += elem.computeSize();
            }
            size += VarInt.size(this.modelTexture.length) + modelTextureSize;
        }
        if (this.modelAnimation != null) {
            size += PacketIO.stringSize(this.modelAnimation);
        }
        if (this.support != null) {
            int supportSize = 0;
            for (final Map.Entry<BlockNeighbor, RequiredBlockFaceSupport[]> kvp : this.support.entrySet()) {
                supportSize += 1 + VarInt.size(kvp.getValue().length) + Arrays.stream(kvp.getValue()).mapToInt(inner -> inner.computeSize()).sum();
            }
            size += VarInt.size(this.support.size()) + supportSize;
        }
        if (this.supporting != null) {
            int supportingSize = 0;
            for (final Map.Entry<BlockNeighbor, BlockFaceSupport[]> kvp2 : this.supporting.entrySet()) {
                supportingSize += 1 + VarInt.size(kvp2.getValue().length) + Arrays.stream(kvp2.getValue()).mapToInt(inner -> inner.computeSize()).sum();
            }
            size += VarInt.size(this.supporting.size()) + supportingSize;
        }
        if (this.cubeTextures != null) {
            int cubeTexturesSize = 0;
            for (final BlockTextures elem2 : this.cubeTextures) {
                cubeTexturesSize += elem2.computeSize();
            }
            size += VarInt.size(this.cubeTextures.length) + cubeTexturesSize;
        }
        if (this.cubeSideMaskTexture != null) {
            size += PacketIO.stringSize(this.cubeSideMaskTexture);
        }
        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.blockParticleSetId != null) {
            size += PacketIO.stringSize(this.blockParticleSetId);
        }
        if (this.blockBreakingDecalId != null) {
            size += PacketIO.stringSize(this.blockBreakingDecalId);
        }
        if (this.transitionTexture != null) {
            size += PacketIO.stringSize(this.transitionTexture);
        }
        if (this.transitionToGroups != null) {
            size += VarInt.size(this.transitionToGroups.length) + this.transitionToGroups.length * 4;
        }
        if (this.interactionHint != null) {
            size += PacketIO.stringSize(this.interactionHint);
        }
        if (this.gathering != null) {
            size += this.gathering.computeSize();
        }
        if (this.display != null) {
            size += this.display.computeSize();
        }
        if (this.rail != null) {
            size += this.rail.computeSize();
        }
        if (this.interactions != null) {
            size += VarInt.size(this.interactions.size()) + this.interactions.size() * 5;
        }
        if (this.states != null) {
            int statesSize = 0;
            for (final Map.Entry<String, Integer> kvp3 : this.states.entrySet()) {
                statesSize += PacketIO.stringSize(kvp3.getKey()) + 4;
            }
            size += VarInt.size(this.states.size()) + statesSize;
        }
        if (this.tagIndexes != null) {
            size += VarInt.size(this.tagIndexes.length) + this.tagIndexes.length * 4;
        }
        if (this.bench != null) {
            size += this.bench.computeSize();
        }
        if (this.connectedBlockRuleSet != null) {
            size += this.connectedBlockRuleSet.computeSize();
        }
        return size;
    }
    
    public static ValidationResult validateStructure(@Nonnull final ByteBuf buffer, final int offset) {
        if (buffer.readableBytes() - offset < 259) {
            return ValidationResult.error("Buffer too small: expected at least 259 bytes");
        }
        final byte[] nullBits = PacketIO.readBytes(buffer, offset, 4);
        if ((nullBits[0] & 0x80) != 0x0) {
            final int itemOffset = buffer.getIntLE(offset + 163);
            if (itemOffset < 0) {
                return ValidationResult.error("Invalid offset for Item");
            }
            int pos = offset + 259 + itemOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Item");
            }
            final int itemLen = VarInt.peek(buffer, pos);
            if (itemLen < 0) {
                return ValidationResult.error("Invalid string length for Item");
            }
            if (itemLen > 4096000) {
                return ValidationResult.error("Item exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += itemLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading Item");
            }
        }
        if ((nullBits[1] & 0x1) != 0x0) {
            final int nameOffset = buffer.getIntLE(offset + 167);
            if (nameOffset < 0) {
                return ValidationResult.error("Invalid offset for Name");
            }
            int pos = offset + 259 + nameOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Name");
            }
            final int nameLen = VarInt.peek(buffer, pos);
            if (nameLen < 0) {
                return ValidationResult.error("Invalid string length for Name");
            }
            if (nameLen > 4096000) {
                return ValidationResult.error("Name exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += nameLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading Name");
            }
        }
        if ((nullBits[1] & 0x2) != 0x0) {
            final int shaderEffectOffset = buffer.getIntLE(offset + 171);
            if (shaderEffectOffset < 0) {
                return ValidationResult.error("Invalid offset for ShaderEffect");
            }
            int pos = offset + 259 + shaderEffectOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for ShaderEffect");
            }
            final int shaderEffectCount = VarInt.peek(buffer, pos);
            if (shaderEffectCount < 0) {
                return ValidationResult.error("Invalid array count for ShaderEffect");
            }
            if (shaderEffectCount > 4096000) {
                return ValidationResult.error("ShaderEffect exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += shaderEffectCount * 1;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading ShaderEffect");
            }
        }
        if ((nullBits[1] & 0x4) != 0x0) {
            final int modelOffset = buffer.getIntLE(offset + 175);
            if (modelOffset < 0) {
                return ValidationResult.error("Invalid offset for Model");
            }
            int pos = offset + 259 + 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[1] & 0x8) != 0x0) {
            final int modelTextureOffset = buffer.getIntLE(offset + 179);
            if (modelTextureOffset < 0) {
                return ValidationResult.error("Invalid offset for ModelTexture");
            }
            int pos = offset + 259 + modelTextureOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for ModelTexture");
            }
            final int modelTextureCount = VarInt.peek(buffer, pos);
            if (modelTextureCount < 0) {
                return ValidationResult.error("Invalid array count for ModelTexture");
            }
            if (modelTextureCount > 4096000) {
                return ValidationResult.error("ModelTexture exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < modelTextureCount; ++i) {
                final ValidationResult structResult = ModelTexture.validateStructure(buffer, pos);
                if (!structResult.isValid()) {
                    return ValidationResult.error("Invalid ModelTexture in ModelTexture[" + i + "]: " + structResult.error());
                }
                pos += ModelTexture.computeBytesConsumed(buffer, pos);
            }
        }
        if ((nullBits[1] & 0x10) != 0x0) {
            final int modelAnimationOffset = buffer.getIntLE(offset + 183);
            if (modelAnimationOffset < 0) {
                return ValidationResult.error("Invalid offset for ModelAnimation");
            }
            int pos = offset + 259 + modelAnimationOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for ModelAnimation");
            }
            final int modelAnimationLen = VarInt.peek(buffer, pos);
            if (modelAnimationLen < 0) {
                return ValidationResult.error("Invalid string length for ModelAnimation");
            }
            if (modelAnimationLen > 4096000) {
                return ValidationResult.error("ModelAnimation exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += modelAnimationLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading ModelAnimation");
            }
        }
        if ((nullBits[1] & 0x20) != 0x0) {
            final int supportOffset = buffer.getIntLE(offset + 187);
            if (supportOffset < 0) {
                return ValidationResult.error("Invalid offset for Support");
            }
            int pos = offset + 259 + supportOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Support");
            }
            final int supportCount = VarInt.peek(buffer, pos);
            if (supportCount < 0) {
                return ValidationResult.error("Invalid dictionary count for Support");
            }
            if (supportCount > 4096000) {
                return ValidationResult.error("Support exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < supportCount; ++i) {
                ++pos;
                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 += RequiredBlockFaceSupport.computeBytesConsumed(buffer, pos);
                }
            }
        }
        if ((nullBits[1] & 0x40) != 0x0) {
            final int supportingOffset = buffer.getIntLE(offset + 191);
            if (supportingOffset < 0) {
                return ValidationResult.error("Invalid offset for Supporting");
            }
            int pos = offset + 259 + supportingOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Supporting");
            }
            final int supportingCount = VarInt.peek(buffer, pos);
            if (supportingCount < 0) {
                return ValidationResult.error("Invalid dictionary count for Supporting");
            }
            if (supportingCount > 4096000) {
                return ValidationResult.error("Supporting exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < supportingCount; ++i) {
                ++pos;
                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 += BlockFaceSupport.computeBytesConsumed(buffer, pos);
                }
            }
        }
        if ((nullBits[1] & 0x80) != 0x0) {
            final int cubeTexturesOffset = buffer.getIntLE(offset + 195);
            if (cubeTexturesOffset < 0) {
                return ValidationResult.error("Invalid offset for CubeTextures");
            }
            int pos = offset + 259 + cubeTexturesOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for CubeTextures");
            }
            final int cubeTexturesCount = VarInt.peek(buffer, pos);
            if (cubeTexturesCount < 0) {
                return ValidationResult.error("Invalid array count for CubeTextures");
            }
            if (cubeTexturesCount > 4096000) {
                return ValidationResult.error("CubeTextures exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < cubeTexturesCount; ++i) {
                final ValidationResult structResult = BlockTextures.validateStructure(buffer, pos);
                if (!structResult.isValid()) {
                    return ValidationResult.error("Invalid BlockTextures in CubeTextures[" + i + "]: " + structResult.error());
                }
                pos += BlockTextures.computeBytesConsumed(buffer, pos);
            }
        }
        if ((nullBits[2] & 0x1) != 0x0) {
            final int cubeSideMaskTextureOffset = buffer.getIntLE(offset + 199);
            if (cubeSideMaskTextureOffset < 0) {
                return ValidationResult.error("Invalid offset for CubeSideMaskTexture");
            }
            int pos = offset + 259 + cubeSideMaskTextureOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for CubeSideMaskTexture");
            }
            final int cubeSideMaskTextureLen = VarInt.peek(buffer, pos);
            if (cubeSideMaskTextureLen < 0) {
                return ValidationResult.error("Invalid string length for CubeSideMaskTexture");
            }
            if (cubeSideMaskTextureLen > 4096000) {
                return ValidationResult.error("CubeSideMaskTexture exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += cubeSideMaskTextureLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading CubeSideMaskTexture");
            }
        }
        if ((nullBits[2] & 0x2) != 0x0) {
            final int particlesOffset = buffer.getIntLE(offset + 203);
            if (particlesOffset < 0) {
                return ValidationResult.error("Invalid offset for Particles");
            }
            int pos = offset + 259 + 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] & 0x4) != 0x0) {
            final int blockParticleSetIdOffset = buffer.getIntLE(offset + 207);
            if (blockParticleSetIdOffset < 0) {
                return ValidationResult.error("Invalid offset for BlockParticleSetId");
            }
            int pos = offset + 259 + blockParticleSetIdOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for BlockParticleSetId");
            }
            final int blockParticleSetIdLen = VarInt.peek(buffer, pos);
            if (blockParticleSetIdLen < 0) {
                return ValidationResult.error("Invalid string length for BlockParticleSetId");
            }
            if (blockParticleSetIdLen > 4096000) {
                return ValidationResult.error("BlockParticleSetId exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += blockParticleSetIdLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading BlockParticleSetId");
            }
        }
        if ((nullBits[2] & 0x8) != 0x0) {
            final int blockBreakingDecalIdOffset = buffer.getIntLE(offset + 211);
            if (blockBreakingDecalIdOffset < 0) {
                return ValidationResult.error("Invalid offset for BlockBreakingDecalId");
            }
            int pos = offset + 259 + blockBreakingDecalIdOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for BlockBreakingDecalId");
            }
            final int blockBreakingDecalIdLen = VarInt.peek(buffer, pos);
            if (blockBreakingDecalIdLen < 0) {
                return ValidationResult.error("Invalid string length for BlockBreakingDecalId");
            }
            if (blockBreakingDecalIdLen > 4096000) {
                return ValidationResult.error("BlockBreakingDecalId exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += blockBreakingDecalIdLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading BlockBreakingDecalId");
            }
        }
        if ((nullBits[2] & 0x10) != 0x0) {
            final int transitionTextureOffset = buffer.getIntLE(offset + 215);
            if (transitionTextureOffset < 0) {
                return ValidationResult.error("Invalid offset for TransitionTexture");
            }
            int pos = offset + 259 + transitionTextureOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for TransitionTexture");
            }
            final int transitionTextureLen = VarInt.peek(buffer, pos);
            if (transitionTextureLen < 0) {
                return ValidationResult.error("Invalid string length for TransitionTexture");
            }
            if (transitionTextureLen > 4096000) {
                return ValidationResult.error("TransitionTexture exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += transitionTextureLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading TransitionTexture");
            }
        }
        if ((nullBits[2] & 0x20) != 0x0) {
            final int transitionToGroupsOffset = buffer.getIntLE(offset + 219);
            if (transitionToGroupsOffset < 0) {
                return ValidationResult.error("Invalid offset for TransitionToGroups");
            }
            int pos = offset + 259 + transitionToGroupsOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for TransitionToGroups");
            }
            final int transitionToGroupsCount = VarInt.peek(buffer, pos);
            if (transitionToGroupsCount < 0) {
                return ValidationResult.error("Invalid array count for TransitionToGroups");
            }
            if (transitionToGroupsCount > 4096000) {
                return ValidationResult.error("TransitionToGroups exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += transitionToGroupsCount * 4;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading TransitionToGroups");
            }
        }
        if ((nullBits[2] & 0x40) != 0x0) {
            final int interactionHintOffset = buffer.getIntLE(offset + 223);
            if (interactionHintOffset < 0) {
                return ValidationResult.error("Invalid offset for InteractionHint");
            }
            int pos = offset + 259 + interactionHintOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for InteractionHint");
            }
            final int interactionHintLen = VarInt.peek(buffer, pos);
            if (interactionHintLen < 0) {
                return ValidationResult.error("Invalid string length for InteractionHint");
            }
            if (interactionHintLen > 4096000) {
                return ValidationResult.error("InteractionHint exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += interactionHintLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading InteractionHint");
            }
        }
        if ((nullBits[2] & 0x80) != 0x0) {
            final int gatheringOffset = buffer.getIntLE(offset + 227);
            if (gatheringOffset < 0) {
                return ValidationResult.error("Invalid offset for Gathering");
            }
            int pos = offset + 259 + gatheringOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Gathering");
            }
            final ValidationResult gatheringResult = BlockGathering.validateStructure(buffer, pos);
            if (!gatheringResult.isValid()) {
                return ValidationResult.error("Invalid Gathering: " + gatheringResult.error());
            }
            pos += BlockGathering.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[3] & 0x1) != 0x0) {
            final int displayOffset = buffer.getIntLE(offset + 231);
            if (displayOffset < 0) {
                return ValidationResult.error("Invalid offset for Display");
            }
            int pos = offset + 259 + displayOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Display");
            }
            final ValidationResult displayResult = ModelDisplay.validateStructure(buffer, pos);
            if (!displayResult.isValid()) {
                return ValidationResult.error("Invalid Display: " + displayResult.error());
            }
            pos += ModelDisplay.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[3] & 0x2) != 0x0) {
            final int railOffset = buffer.getIntLE(offset + 235);
            if (railOffset < 0) {
                return ValidationResult.error("Invalid offset for Rail");
            }
            int pos = offset + 259 + railOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Rail");
            }
            final ValidationResult railResult = RailConfig.validateStructure(buffer, pos);
            if (!railResult.isValid()) {
                return ValidationResult.error("Invalid Rail: " + railResult.error());
            }
            pos += RailConfig.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[3] & 0x4) != 0x0) {
            final int interactionsOffset = buffer.getIntLE(offset + 239);
            if (interactionsOffset < 0) {
                return ValidationResult.error("Invalid offset for Interactions");
            }
            int pos = offset + 259 + 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] & 0x8) != 0x0) {
            final int statesOffset = buffer.getIntLE(offset + 243);
            if (statesOffset < 0) {
                return ValidationResult.error("Invalid offset for States");
            }
            int pos = offset + 259 + statesOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for States");
            }
            final int statesCount = VarInt.peek(buffer, pos);
            if (statesCount < 0) {
                return ValidationResult.error("Invalid dictionary count for States");
            }
            if (statesCount > 4096000) {
                return ValidationResult.error("States exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < statesCount; ++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] & 0x10) != 0x0) {
            final int tagIndexesOffset = buffer.getIntLE(offset + 247);
            if (tagIndexesOffset < 0) {
                return ValidationResult.error("Invalid offset for TagIndexes");
            }
            int pos = offset + 259 + 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 benchOffset = buffer.getIntLE(offset + 251);
            if (benchOffset < 0) {
                return ValidationResult.error("Invalid offset for Bench");
            }
            int pos = offset + 259 + benchOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Bench");
            }
            final ValidationResult benchResult = Bench.validateStructure(buffer, pos);
            if (!benchResult.isValid()) {
                return ValidationResult.error("Invalid Bench: " + benchResult.error());
            }
            pos += Bench.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[3] & 0x40) != 0x0) {
            final int connectedBlockRuleSetOffset = buffer.getIntLE(offset + 255);
            if (connectedBlockRuleSetOffset < 0) {
                return ValidationResult.error("Invalid offset for ConnectedBlockRuleSet");
            }
            int pos = offset + 259 + connectedBlockRuleSetOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for ConnectedBlockRuleSet");
            }
            final ValidationResult connectedBlockRuleSetResult = ConnectedBlockRuleSet.validateStructure(buffer, pos);
            if (!connectedBlockRuleSetResult.isValid()) {
                return ValidationResult.error("Invalid ConnectedBlockRuleSet: " + connectedBlockRuleSetResult.error());
            }
            pos += ConnectedBlockRuleSet.computeBytesConsumed(buffer, pos);
        }
        return ValidationResult.OK;
    }
    
    public BlockType clone() {
        final BlockType copy = new BlockType();
        copy.item = this.item;
        copy.name = this.name;
        copy.unknown = this.unknown;
        copy.drawType = this.drawType;
        copy.material = this.material;
        copy.opacity = this.opacity;
        copy.shaderEffect = (ShaderType[])((this.shaderEffect != null) ? ((ShaderType[])Arrays.copyOf(this.shaderEffect, this.shaderEffect.length)) : null);
        copy.hitbox = this.hitbox;
        copy.interactionHitbox = this.interactionHitbox;
        copy.model = this.model;
        Map.Entry<BlockNeighbor, RequiredBlockFaceSupport[]> e = null;
        copy.modelTexture = (ModelTexture[])((this.modelTexture != null) ? ((ModelTexture[])Arrays.stream(this.modelTexture).map(e -> e.clone()).toArray(ModelTexture[]::new)) : null);
        copy.modelScale = this.modelScale;
        copy.modelAnimation = this.modelAnimation;
        copy.looping = this.looping;
        copy.maxSupportDistance = this.maxSupportDistance;
        copy.blockSupportsRequiredFor = this.blockSupportsRequiredFor;
        if (this.support != null) {
            final Map<BlockNeighbor, RequiredBlockFaceSupport[]> m = new HashMap<BlockNeighbor, RequiredBlockFaceSupport[]>();
            final Iterator<Map.Entry<BlockNeighbor, RequiredBlockFaceSupport[]>> iterator = this.support.entrySet().iterator();
            while (iterator.hasNext()) {
                e = iterator.next();
                m.put(e.getKey(), Arrays.stream(e.getValue()).map(x -> x.clone()).toArray(RequiredBlockFaceSupport[]::new));
            }
            copy.support = m;
        }
        if (this.supporting != null) {
            final Map<BlockNeighbor, BlockFaceSupport[]> i = new HashMap<BlockNeighbor, BlockFaceSupport[]>();
            for (final Map.Entry<BlockNeighbor, BlockFaceSupport[]> e2 : this.supporting.entrySet()) {
                i.put(e2.getKey(), Arrays.stream(e2.getValue()).map(x -> x.clone()).toArray(BlockFaceSupport[]::new));
            }
            copy.supporting = i;
        }
        copy.requiresAlphaBlending = this.requiresAlphaBlending;
        copy.cubeTextures = (BlockTextures[])((this.cubeTextures != null) ? ((BlockTextures[])Arrays.stream(this.cubeTextures).map(e -> e.clone()).toArray(BlockTextures[]::new)) : null);
        copy.cubeSideMaskTexture = this.cubeSideMaskTexture;
        copy.cubeShadingMode = this.cubeShadingMode;
        copy.randomRotation = this.randomRotation;
        copy.variantRotation = this.variantRotation;
        copy.rotationYawPlacementOffset = this.rotationYawPlacementOffset;
        copy.blockSoundSetIndex = this.blockSoundSetIndex;
        copy.ambientSoundEventIndex = this.ambientSoundEventIndex;
        copy.particles = (ModelParticle[])((this.particles != null) ? ((ModelParticle[])Arrays.stream(this.particles).map(e -> e.clone()).toArray(ModelParticle[]::new)) : null);
        copy.blockParticleSetId = this.blockParticleSetId;
        copy.blockBreakingDecalId = this.blockBreakingDecalId;
        copy.particleColor = ((this.particleColor != null) ? this.particleColor.clone() : null);
        copy.light = ((this.light != null) ? this.light.clone() : null);
        copy.tint = ((this.tint != null) ? this.tint.clone() : null);
        copy.biomeTint = ((this.biomeTint != null) ? this.biomeTint.clone() : null);
        copy.group = this.group;
        copy.transitionTexture = this.transitionTexture;
        copy.transitionToGroups = (int[])((this.transitionToGroups != null) ? Arrays.copyOf(this.transitionToGroups, this.transitionToGroups.length) : null);
        copy.movementSettings = ((this.movementSettings != null) ? this.movementSettings.clone() : null);
        copy.flags = ((this.flags != null) ? this.flags.clone() : null);
        copy.interactionHint = this.interactionHint;
        copy.gathering = ((this.gathering != null) ? this.gathering.clone() : null);
        copy.placementSettings = ((this.placementSettings != null) ? this.placementSettings.clone() : null);
        copy.display = ((this.display != null) ? this.display.clone() : null);
        copy.rail = ((this.rail != null) ? this.rail.clone() : null);
        copy.ignoreSupportWhenPlaced = this.ignoreSupportWhenPlaced;
        copy.interactions = ((this.interactions != null) ? new HashMap<InteractionType, Integer>(this.interactions) : null);
        copy.states = ((this.states != null) ? new HashMap<String, Integer>(this.states) : null);
        copy.transitionToTag = this.transitionToTag;
        copy.tagIndexes = (int[])((this.tagIndexes != null) ? Arrays.copyOf(this.tagIndexes, this.tagIndexes.length) : null);
        copy.bench = ((this.bench != null) ? this.bench.clone() : null);
        copy.connectedBlockRuleSet = ((this.connectedBlockRuleSet != null) ? this.connectedBlockRuleSet.clone() : null);
        return copy;
    }
    
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof final BlockType other) {
            return Objects.equals(this.item, other.item) && Objects.equals(this.name, other.name) && this.unknown == other.unknown && Objects.equals(this.drawType, other.drawType) && Objects.equals(this.material, other.material) && Objects.equals(this.opacity, other.opacity) && Arrays.equals(this.shaderEffect, other.shaderEffect) && this.hitbox == other.hitbox && this.interactionHitbox == other.interactionHitbox && Objects.equals(this.model, other.model) && Arrays.equals(this.modelTexture, other.modelTexture) && this.modelScale == other.modelScale && Objects.equals(this.modelAnimation, other.modelAnimation) && this.looping == other.looping && this.maxSupportDistance == other.maxSupportDistance && Objects.equals(this.blockSupportsRequiredFor, other.blockSupportsRequiredFor) && Objects.equals(this.support, other.support) && Objects.equals(this.supporting, other.supporting) && this.requiresAlphaBlending == other.requiresAlphaBlending && Arrays.equals(this.cubeTextures, other.cubeTextures) && Objects.equals(this.cubeSideMaskTexture, other.cubeSideMaskTexture) && Objects.equals(this.cubeShadingMode, other.cubeShadingMode) && Objects.equals(this.randomRotation, other.randomRotation) && Objects.equals(this.variantRotation, other.variantRotation) && Objects.equals(this.rotationYawPlacementOffset, other.rotationYawPlacementOffset) && this.blockSoundSetIndex == other.blockSoundSetIndex && this.ambientSoundEventIndex == other.ambientSoundEventIndex && Arrays.equals(this.particles, other.particles) && Objects.equals(this.blockParticleSetId, other.blockParticleSetId) && Objects.equals(this.blockBreakingDecalId, other.blockBreakingDecalId) && Objects.equals(this.particleColor, other.particleColor) && Objects.equals(this.light, other.light) && Objects.equals(this.tint, other.tint) && Objects.equals(this.biomeTint, other.biomeTint) && this.group == other.group && Objects.equals(this.transitionTexture, other.transitionTexture) && Arrays.equals(this.transitionToGroups, other.transitionToGroups) && Objects.equals(this.movementSettings, other.movementSettings) && Objects.equals(this.flags, other.flags) && Objects.equals(this.interactionHint, other.interactionHint) && Objects.equals(this.gathering, other.gathering) && Objects.equals(this.placementSettings, other.placementSettings) && Objects.equals(this.display, other.display) && Objects.equals(this.rail, other.rail) && this.ignoreSupportWhenPlaced == other.ignoreSupportWhenPlaced && Objects.equals(this.interactions, other.interactions) && Objects.equals(this.states, other.states) && this.transitionToTag == other.transitionToTag && Arrays.equals(this.tagIndexes, other.tagIndexes) && Objects.equals(this.bench, other.bench) && Objects.equals(this.connectedBlockRuleSet, other.connectedBlockRuleSet);
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        int result = 1;
        result = 31 * result + Objects.hashCode(this.item);
        result = 31 * result + Objects.hashCode(this.name);
        result = 31 * result + Boolean.hashCode(this.unknown);
        result = 31 * result + Objects.hashCode(this.drawType);
        result = 31 * result + Objects.hashCode(this.material);
        result = 31 * result + Objects.hashCode(this.opacity);
        result = 31 * result + Arrays.hashCode(this.shaderEffect);
        result = 31 * result + Integer.hashCode(this.hitbox);
        result = 31 * result + Integer.hashCode(this.interactionHitbox);
        result = 31 * result + Objects.hashCode(this.model);
        result = 31 * result + Arrays.hashCode(this.modelTexture);
        result = 31 * result + Float.hashCode(this.modelScale);
        result = 31 * result + Objects.hashCode(this.modelAnimation);
        result = 31 * result + Boolean.hashCode(this.looping);
        result = 31 * result + Integer.hashCode(this.maxSupportDistance);
        result = 31 * result + Objects.hashCode(this.blockSupportsRequiredFor);
        result = 31 * result + Objects.hashCode(this.support);
        result = 31 * result + Objects.hashCode(this.supporting);
        result = 31 * result + Boolean.hashCode(this.requiresAlphaBlending);
        result = 31 * result + Arrays.hashCode(this.cubeTextures);
        result = 31 * result + Objects.hashCode(this.cubeSideMaskTexture);
        result = 31 * result + Objects.hashCode(this.cubeShadingMode);
        result = 31 * result + Objects.hashCode(this.randomRotation);
        result = 31 * result + Objects.hashCode(this.variantRotation);
        result = 31 * result + Objects.hashCode(this.rotationYawPlacementOffset);
        result = 31 * result + Integer.hashCode(this.blockSoundSetIndex);
        result = 31 * result + Integer.hashCode(this.ambientSoundEventIndex);
        result = 31 * result + Arrays.hashCode(this.particles);
        result = 31 * result + Objects.hashCode(this.blockParticleSetId);
        result = 31 * result + Objects.hashCode(this.blockBreakingDecalId);
        result = 31 * result + Objects.hashCode(this.particleColor);
        result = 31 * result + Objects.hashCode(this.light);
        result = 31 * result + Objects.hashCode(this.tint);
        result = 31 * result + Objects.hashCode(this.biomeTint);
        result = 31 * result + Integer.hashCode(this.group);
        result = 31 * result + Objects.hashCode(this.transitionTexture);
        result = 31 * result + Arrays.hashCode(this.transitionToGroups);
        result = 31 * result + Objects.hashCode(this.movementSettings);
        result = 31 * result + Objects.hashCode(this.flags);
        result = 31 * result + Objects.hashCode(this.interactionHint);
        result = 31 * result + Objects.hashCode(this.gathering);
        result = 31 * result + Objects.hashCode(this.placementSettings);
        result = 31 * result + Objects.hashCode(this.display);
        result = 31 * result + Objects.hashCode(this.rail);
        result = 31 * result + Boolean.hashCode(this.ignoreSupportWhenPlaced);
        result = 31 * result + Objects.hashCode(this.interactions);
        result = 31 * result + Objects.hashCode(this.states);
        result = 31 * result + Integer.hashCode(this.transitionToTag);
        result = 31 * result + Arrays.hashCode(this.tagIndexes);
        result = 31 * result + Objects.hashCode(this.bench);
        result = 31 * result + Objects.hashCode(this.connectedBlockRuleSet);
        return result;
    }
}
