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

package com.hypixel.hytale.protocol.packets.buildertools;

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

public class BuilderToolBrushData
{
    public static final int NULLABLE_BIT_FIELD_SIZE = 3;
    public static final int FIXED_BLOCK_SIZE = 48;
    public static final int VARIABLE_FIELD_COUNT = 9;
    public static final int VARIABLE_BLOCK_START = 84;
    public static final int MAX_SIZE = 1677721600;
    @Nullable
    public BuilderToolIntArg width;
    @Nullable
    public BuilderToolIntArg height;
    @Nullable
    public BuilderToolIntArg thickness;
    @Nullable
    public BuilderToolBoolArg capped;
    @Nullable
    public BuilderToolBrushShapeArg shape;
    @Nullable
    public BuilderToolBrushOriginArg origin;
    @Nullable
    public BuilderToolBoolArg originRotation;
    @Nullable
    public BuilderToolBrushAxisArg rotationAxis;
    @Nullable
    public BuilderToolRotationArg rotationAngle;
    @Nullable
    public BuilderToolBrushAxisArg mirrorAxis;
    @Nullable
    public BuilderToolBlockArg material;
    @Nullable
    public BuilderToolBlockArg[] favoriteMaterials;
    @Nullable
    public BuilderToolMaskArg mask;
    @Nullable
    public BuilderToolMaskArg maskAbove;
    @Nullable
    public BuilderToolMaskArg maskNot;
    @Nullable
    public BuilderToolMaskArg maskBelow;
    @Nullable
    public BuilderToolMaskArg maskAdjacent;
    @Nullable
    public BuilderToolMaskArg maskNeighbor;
    @Nullable
    public BuilderToolStringArg[] maskCommands;
    @Nullable
    public BuilderToolBoolArg useMaskCommands;
    @Nullable
    public BuilderToolBoolArg invertMask;
    
    public BuilderToolBrushData() {
    }
    
    public BuilderToolBrushData(@Nullable final BuilderToolIntArg width, @Nullable final BuilderToolIntArg height, @Nullable final BuilderToolIntArg thickness, @Nullable final BuilderToolBoolArg capped, @Nullable final BuilderToolBrushShapeArg shape, @Nullable final BuilderToolBrushOriginArg origin, @Nullable final BuilderToolBoolArg originRotation, @Nullable final BuilderToolBrushAxisArg rotationAxis, @Nullable final BuilderToolRotationArg rotationAngle, @Nullable final BuilderToolBrushAxisArg mirrorAxis, @Nullable final BuilderToolBlockArg material, @Nullable final BuilderToolBlockArg[] favoriteMaterials, @Nullable final BuilderToolMaskArg mask, @Nullable final BuilderToolMaskArg maskAbove, @Nullable final BuilderToolMaskArg maskNot, @Nullable final BuilderToolMaskArg maskBelow, @Nullable final BuilderToolMaskArg maskAdjacent, @Nullable final BuilderToolMaskArg maskNeighbor, @Nullable final BuilderToolStringArg[] maskCommands, @Nullable final BuilderToolBoolArg useMaskCommands, @Nullable final BuilderToolBoolArg invertMask) {
        this.width = width;
        this.height = height;
        this.thickness = thickness;
        this.capped = capped;
        this.shape = shape;
        this.origin = origin;
        this.originRotation = originRotation;
        this.rotationAxis = rotationAxis;
        this.rotationAngle = rotationAngle;
        this.mirrorAxis = mirrorAxis;
        this.material = material;
        this.favoriteMaterials = favoriteMaterials;
        this.mask = mask;
        this.maskAbove = maskAbove;
        this.maskNot = maskNot;
        this.maskBelow = maskBelow;
        this.maskAdjacent = maskAdjacent;
        this.maskNeighbor = maskNeighbor;
        this.maskCommands = maskCommands;
        this.useMaskCommands = useMaskCommands;
        this.invertMask = invertMask;
    }
    
    public BuilderToolBrushData(@Nonnull final BuilderToolBrushData other) {
        this.width = other.width;
        this.height = other.height;
        this.thickness = other.thickness;
        this.capped = other.capped;
        this.shape = other.shape;
        this.origin = other.origin;
        this.originRotation = other.originRotation;
        this.rotationAxis = other.rotationAxis;
        this.rotationAngle = other.rotationAngle;
        this.mirrorAxis = other.mirrorAxis;
        this.material = other.material;
        this.favoriteMaterials = other.favoriteMaterials;
        this.mask = other.mask;
        this.maskAbove = other.maskAbove;
        this.maskNot = other.maskNot;
        this.maskBelow = other.maskBelow;
        this.maskAdjacent = other.maskAdjacent;
        this.maskNeighbor = other.maskNeighbor;
        this.maskCommands = other.maskCommands;
        this.useMaskCommands = other.useMaskCommands;
        this.invertMask = other.invertMask;
    }
    
    @Nonnull
    public static BuilderToolBrushData deserialize(@Nonnull final ByteBuf buf, final int offset) {
        final BuilderToolBrushData obj = new BuilderToolBrushData();
        final byte[] nullBits = PacketIO.readBytes(buf, offset, 3);
        if ((nullBits[0] & 0x1) != 0x0) {
            obj.width = BuilderToolIntArg.deserialize(buf, offset + 3);
        }
        if ((nullBits[0] & 0x2) != 0x0) {
            obj.height = BuilderToolIntArg.deserialize(buf, offset + 15);
        }
        if ((nullBits[0] & 0x4) != 0x0) {
            obj.thickness = BuilderToolIntArg.deserialize(buf, offset + 27);
        }
        if ((nullBits[0] & 0x8) != 0x0) {
            obj.capped = BuilderToolBoolArg.deserialize(buf, offset + 39);
        }
        if ((nullBits[0] & 0x10) != 0x0) {
            obj.shape = BuilderToolBrushShapeArg.deserialize(buf, offset + 40);
        }
        if ((nullBits[0] & 0x20) != 0x0) {
            obj.origin = BuilderToolBrushOriginArg.deserialize(buf, offset + 41);
        }
        if ((nullBits[0] & 0x40) != 0x0) {
            obj.originRotation = BuilderToolBoolArg.deserialize(buf, offset + 42);
        }
        if ((nullBits[0] & 0x80) != 0x0) {
            obj.rotationAxis = BuilderToolBrushAxisArg.deserialize(buf, offset + 43);
        }
        if ((nullBits[1] & 0x1) != 0x0) {
            obj.rotationAngle = BuilderToolRotationArg.deserialize(buf, offset + 44);
        }
        if ((nullBits[1] & 0x2) != 0x0) {
            obj.mirrorAxis = BuilderToolBrushAxisArg.deserialize(buf, offset + 45);
        }
        if ((nullBits[1] & 0x4) != 0x0) {
            obj.useMaskCommands = BuilderToolBoolArg.deserialize(buf, offset + 46);
        }
        if ((nullBits[1] & 0x8) != 0x0) {
            obj.invertMask = BuilderToolBoolArg.deserialize(buf, offset + 47);
        }
        if ((nullBits[1] & 0x10) != 0x0) {
            final int varPos0 = offset + 84 + buf.getIntLE(offset + 48);
            obj.material = BuilderToolBlockArg.deserialize(buf, varPos0);
        }
        if ((nullBits[1] & 0x20) != 0x0) {
            final int varPos2 = offset + 84 + buf.getIntLE(offset + 52);
            final int favoriteMaterialsCount = VarInt.peek(buf, varPos2);
            if (favoriteMaterialsCount < 0) {
                throw ProtocolException.negativeLength("FavoriteMaterials", favoriteMaterialsCount);
            }
            if (favoriteMaterialsCount > 4096000) {
                throw ProtocolException.arrayTooLong("FavoriteMaterials", favoriteMaterialsCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos2);
            if (varPos2 + varIntLen + favoriteMaterialsCount * 2L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("FavoriteMaterials", varPos2 + varIntLen + favoriteMaterialsCount * 2, buf.readableBytes());
            }
            obj.favoriteMaterials = new BuilderToolBlockArg[favoriteMaterialsCount];
            int elemPos = varPos2 + varIntLen;
            for (int i = 0; i < favoriteMaterialsCount; ++i) {
                obj.favoriteMaterials[i] = BuilderToolBlockArg.deserialize(buf, elemPos);
                elemPos += BuilderToolBlockArg.computeBytesConsumed(buf, elemPos);
            }
        }
        if ((nullBits[1] & 0x40) != 0x0) {
            final int varPos3 = offset + 84 + buf.getIntLE(offset + 56);
            obj.mask = BuilderToolMaskArg.deserialize(buf, varPos3);
        }
        if ((nullBits[1] & 0x80) != 0x0) {
            final int varPos4 = offset + 84 + buf.getIntLE(offset + 60);
            obj.maskAbove = BuilderToolMaskArg.deserialize(buf, varPos4);
        }
        if ((nullBits[2] & 0x1) != 0x0) {
            final int varPos5 = offset + 84 + buf.getIntLE(offset + 64);
            obj.maskNot = BuilderToolMaskArg.deserialize(buf, varPos5);
        }
        if ((nullBits[2] & 0x2) != 0x0) {
            final int varPos6 = offset + 84 + buf.getIntLE(offset + 68);
            obj.maskBelow = BuilderToolMaskArg.deserialize(buf, varPos6);
        }
        if ((nullBits[2] & 0x4) != 0x0) {
            final int varPos7 = offset + 84 + buf.getIntLE(offset + 72);
            obj.maskAdjacent = BuilderToolMaskArg.deserialize(buf, varPos7);
        }
        if ((nullBits[2] & 0x8) != 0x0) {
            final int varPos8 = offset + 84 + buf.getIntLE(offset + 76);
            obj.maskNeighbor = BuilderToolMaskArg.deserialize(buf, varPos8);
        }
        if ((nullBits[2] & 0x10) != 0x0) {
            final int varPos9 = offset + 84 + buf.getIntLE(offset + 80);
            final int maskCommandsCount = VarInt.peek(buf, varPos9);
            if (maskCommandsCount < 0) {
                throw ProtocolException.negativeLength("MaskCommands", maskCommandsCount);
            }
            if (maskCommandsCount > 4096000) {
                throw ProtocolException.arrayTooLong("MaskCommands", maskCommandsCount, 4096000);
            }
            final int varIntLen = VarInt.length(buf, varPos9);
            if (varPos9 + varIntLen + maskCommandsCount * 1L > buf.readableBytes()) {
                throw ProtocolException.bufferTooSmall("MaskCommands", varPos9 + varIntLen + maskCommandsCount * 1, buf.readableBytes());
            }
            obj.maskCommands = new BuilderToolStringArg[maskCommandsCount];
            int elemPos = varPos9 + varIntLen;
            for (int i = 0; i < maskCommandsCount; ++i) {
                obj.maskCommands[i] = BuilderToolStringArg.deserialize(buf, elemPos);
                elemPos += BuilderToolStringArg.computeBytesConsumed(buf, elemPos);
            }
        }
        return obj;
    }
    
    public static int computeBytesConsumed(@Nonnull final ByteBuf buf, final int offset) {
        final byte[] nullBits = PacketIO.readBytes(buf, offset, 3);
        int maxEnd = 84;
        if ((nullBits[1] & 0x10) != 0x0) {
            final int fieldOffset0 = buf.getIntLE(offset + 48);
            int pos0 = offset + 84 + fieldOffset0;
            pos0 += BuilderToolBlockArg.computeBytesConsumed(buf, pos0);
            if (pos0 - offset > maxEnd) {
                maxEnd = pos0 - offset;
            }
        }
        if ((nullBits[1] & 0x20) != 0x0) {
            final int fieldOffset2 = buf.getIntLE(offset + 52);
            int pos2 = offset + 84 + fieldOffset2;
            final int arrLen = VarInt.peek(buf, pos2);
            pos2 += VarInt.length(buf, pos2);
            for (int i = 0; i < arrLen; ++i) {
                pos2 += BuilderToolBlockArg.computeBytesConsumed(buf, pos2);
            }
            if (pos2 - offset > maxEnd) {
                maxEnd = pos2 - offset;
            }
        }
        if ((nullBits[1] & 0x40) != 0x0) {
            final int fieldOffset3 = buf.getIntLE(offset + 56);
            int pos3 = offset + 84 + fieldOffset3;
            pos3 += BuilderToolMaskArg.computeBytesConsumed(buf, pos3);
            if (pos3 - offset > maxEnd) {
                maxEnd = pos3 - offset;
            }
        }
        if ((nullBits[1] & 0x80) != 0x0) {
            final int fieldOffset4 = buf.getIntLE(offset + 60);
            int pos4 = offset + 84 + fieldOffset4;
            pos4 += BuilderToolMaskArg.computeBytesConsumed(buf, pos4);
            if (pos4 - offset > maxEnd) {
                maxEnd = pos4 - offset;
            }
        }
        if ((nullBits[2] & 0x1) != 0x0) {
            final int fieldOffset5 = buf.getIntLE(offset + 64);
            int pos5 = offset + 84 + fieldOffset5;
            pos5 += BuilderToolMaskArg.computeBytesConsumed(buf, pos5);
            if (pos5 - offset > maxEnd) {
                maxEnd = pos5 - offset;
            }
        }
        if ((nullBits[2] & 0x2) != 0x0) {
            final int fieldOffset6 = buf.getIntLE(offset + 68);
            int pos6 = offset + 84 + fieldOffset6;
            pos6 += BuilderToolMaskArg.computeBytesConsumed(buf, pos6);
            if (pos6 - offset > maxEnd) {
                maxEnd = pos6 - offset;
            }
        }
        if ((nullBits[2] & 0x4) != 0x0) {
            final int fieldOffset7 = buf.getIntLE(offset + 72);
            int pos7 = offset + 84 + fieldOffset7;
            pos7 += BuilderToolMaskArg.computeBytesConsumed(buf, pos7);
            if (pos7 - offset > maxEnd) {
                maxEnd = pos7 - offset;
            }
        }
        if ((nullBits[2] & 0x8) != 0x0) {
            final int fieldOffset8 = buf.getIntLE(offset + 76);
            int pos8 = offset + 84 + fieldOffset8;
            pos8 += BuilderToolMaskArg.computeBytesConsumed(buf, pos8);
            if (pos8 - offset > maxEnd) {
                maxEnd = pos8 - offset;
            }
        }
        if ((nullBits[2] & 0x10) != 0x0) {
            final int fieldOffset9 = buf.getIntLE(offset + 80);
            int pos9 = offset + 84 + fieldOffset9;
            final int arrLen = VarInt.peek(buf, pos9);
            pos9 += VarInt.length(buf, pos9);
            for (int i = 0; i < arrLen; ++i) {
                pos9 += BuilderToolStringArg.computeBytesConsumed(buf, pos9);
            }
            if (pos9 - offset > maxEnd) {
                maxEnd = pos9 - offset;
            }
        }
        return maxEnd;
    }
    
    public void serialize(@Nonnull final ByteBuf buf) {
        final int startPos = buf.writerIndex();
        final byte[] nullBits = new byte[3];
        if (this.width != null) {
            final byte[] array = nullBits;
            final int n = 0;
            array[n] |= 0x1;
        }
        if (this.height != null) {
            final byte[] array2 = nullBits;
            final int n2 = 0;
            array2[n2] |= 0x2;
        }
        if (this.thickness != null) {
            final byte[] array3 = nullBits;
            final int n3 = 0;
            array3[n3] |= 0x4;
        }
        if (this.capped != null) {
            final byte[] array4 = nullBits;
            final int n4 = 0;
            array4[n4] |= 0x8;
        }
        if (this.shape != null) {
            final byte[] array5 = nullBits;
            final int n5 = 0;
            array5[n5] |= 0x10;
        }
        if (this.origin != null) {
            final byte[] array6 = nullBits;
            final int n6 = 0;
            array6[n6] |= 0x20;
        }
        if (this.originRotation != null) {
            final byte[] array7 = nullBits;
            final int n7 = 0;
            array7[n7] |= 0x40;
        }
        if (this.rotationAxis != null) {
            final byte[] array8 = nullBits;
            final int n8 = 0;
            array8[n8] |= (byte)128;
        }
        if (this.rotationAngle != null) {
            final byte[] array9 = nullBits;
            final int n9 = 1;
            array9[n9] |= 0x1;
        }
        if (this.mirrorAxis != null) {
            final byte[] array10 = nullBits;
            final int n10 = 1;
            array10[n10] |= 0x2;
        }
        if (this.useMaskCommands != null) {
            final byte[] array11 = nullBits;
            final int n11 = 1;
            array11[n11] |= 0x4;
        }
        if (this.invertMask != null) {
            final byte[] array12 = nullBits;
            final int n12 = 1;
            array12[n12] |= 0x8;
        }
        if (this.material != null) {
            final byte[] array13 = nullBits;
            final int n13 = 1;
            array13[n13] |= 0x10;
        }
        if (this.favoriteMaterials != null) {
            final byte[] array14 = nullBits;
            final int n14 = 1;
            array14[n14] |= 0x20;
        }
        if (this.mask != null) {
            final byte[] array15 = nullBits;
            final int n15 = 1;
            array15[n15] |= 0x40;
        }
        if (this.maskAbove != null) {
            final byte[] array16 = nullBits;
            final int n16 = 1;
            array16[n16] |= (byte)128;
        }
        if (this.maskNot != null) {
            final byte[] array17 = nullBits;
            final int n17 = 2;
            array17[n17] |= 0x1;
        }
        if (this.maskBelow != null) {
            final byte[] array18 = nullBits;
            final int n18 = 2;
            array18[n18] |= 0x2;
        }
        if (this.maskAdjacent != null) {
            final byte[] array19 = nullBits;
            final int n19 = 2;
            array19[n19] |= 0x4;
        }
        if (this.maskNeighbor != null) {
            final byte[] array20 = nullBits;
            final int n20 = 2;
            array20[n20] |= 0x8;
        }
        if (this.maskCommands != null) {
            final byte[] array21 = nullBits;
            final int n21 = 2;
            array21[n21] |= 0x10;
        }
        buf.writeBytes(nullBits);
        if (this.width != null) {
            this.width.serialize(buf);
        }
        else {
            buf.writeZero(12);
        }
        if (this.height != null) {
            this.height.serialize(buf);
        }
        else {
            buf.writeZero(12);
        }
        if (this.thickness != null) {
            this.thickness.serialize(buf);
        }
        else {
            buf.writeZero(12);
        }
        if (this.capped != null) {
            this.capped.serialize(buf);
        }
        else {
            buf.writeZero(1);
        }
        if (this.shape != null) {
            this.shape.serialize(buf);
        }
        else {
            buf.writeZero(1);
        }
        if (this.origin != null) {
            this.origin.serialize(buf);
        }
        else {
            buf.writeZero(1);
        }
        if (this.originRotation != null) {
            this.originRotation.serialize(buf);
        }
        else {
            buf.writeZero(1);
        }
        if (this.rotationAxis != null) {
            this.rotationAxis.serialize(buf);
        }
        else {
            buf.writeZero(1);
        }
        if (this.rotationAngle != null) {
            this.rotationAngle.serialize(buf);
        }
        else {
            buf.writeZero(1);
        }
        if (this.mirrorAxis != null) {
            this.mirrorAxis.serialize(buf);
        }
        else {
            buf.writeZero(1);
        }
        if (this.useMaskCommands != null) {
            this.useMaskCommands.serialize(buf);
        }
        else {
            buf.writeZero(1);
        }
        if (this.invertMask != null) {
            this.invertMask.serialize(buf);
        }
        else {
            buf.writeZero(1);
        }
        final int materialOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int favoriteMaterialsOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int maskOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int maskAboveOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int maskNotOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int maskBelowOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int maskAdjacentOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int maskNeighborOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int maskCommandsOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int varBlockStart = buf.writerIndex();
        if (this.material != null) {
            buf.setIntLE(materialOffsetSlot, buf.writerIndex() - varBlockStart);
            this.material.serialize(buf);
        }
        else {
            buf.setIntLE(materialOffsetSlot, -1);
        }
        if (this.favoriteMaterials != null) {
            buf.setIntLE(favoriteMaterialsOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.favoriteMaterials.length > 4096000) {
                throw ProtocolException.arrayTooLong("FavoriteMaterials", this.favoriteMaterials.length, 4096000);
            }
            VarInt.write(buf, this.favoriteMaterials.length);
            for (final BuilderToolBlockArg item : this.favoriteMaterials) {
                item.serialize(buf);
            }
        }
        else {
            buf.setIntLE(favoriteMaterialsOffsetSlot, -1);
        }
        if (this.mask != null) {
            buf.setIntLE(maskOffsetSlot, buf.writerIndex() - varBlockStart);
            this.mask.serialize(buf);
        }
        else {
            buf.setIntLE(maskOffsetSlot, -1);
        }
        if (this.maskAbove != null) {
            buf.setIntLE(maskAboveOffsetSlot, buf.writerIndex() - varBlockStart);
            this.maskAbove.serialize(buf);
        }
        else {
            buf.setIntLE(maskAboveOffsetSlot, -1);
        }
        if (this.maskNot != null) {
            buf.setIntLE(maskNotOffsetSlot, buf.writerIndex() - varBlockStart);
            this.maskNot.serialize(buf);
        }
        else {
            buf.setIntLE(maskNotOffsetSlot, -1);
        }
        if (this.maskBelow != null) {
            buf.setIntLE(maskBelowOffsetSlot, buf.writerIndex() - varBlockStart);
            this.maskBelow.serialize(buf);
        }
        else {
            buf.setIntLE(maskBelowOffsetSlot, -1);
        }
        if (this.maskAdjacent != null) {
            buf.setIntLE(maskAdjacentOffsetSlot, buf.writerIndex() - varBlockStart);
            this.maskAdjacent.serialize(buf);
        }
        else {
            buf.setIntLE(maskAdjacentOffsetSlot, -1);
        }
        if (this.maskNeighbor != null) {
            buf.setIntLE(maskNeighborOffsetSlot, buf.writerIndex() - varBlockStart);
            this.maskNeighbor.serialize(buf);
        }
        else {
            buf.setIntLE(maskNeighborOffsetSlot, -1);
        }
        if (this.maskCommands != null) {
            buf.setIntLE(maskCommandsOffsetSlot, buf.writerIndex() - varBlockStart);
            if (this.maskCommands.length > 4096000) {
                throw ProtocolException.arrayTooLong("MaskCommands", this.maskCommands.length, 4096000);
            }
            VarInt.write(buf, this.maskCommands.length);
            for (final BuilderToolStringArg item2 : this.maskCommands) {
                item2.serialize(buf);
            }
        }
        else {
            buf.setIntLE(maskCommandsOffsetSlot, -1);
        }
    }
    
    public int computeSize() {
        int size = 84;
        if (this.material != null) {
            size += this.material.computeSize();
        }
        if (this.favoriteMaterials != null) {
            int favoriteMaterialsSize = 0;
            for (final BuilderToolBlockArg elem : this.favoriteMaterials) {
                favoriteMaterialsSize += elem.computeSize();
            }
            size += VarInt.size(this.favoriteMaterials.length) + favoriteMaterialsSize;
        }
        if (this.mask != null) {
            size += this.mask.computeSize();
        }
        if (this.maskAbove != null) {
            size += this.maskAbove.computeSize();
        }
        if (this.maskNot != null) {
            size += this.maskNot.computeSize();
        }
        if (this.maskBelow != null) {
            size += this.maskBelow.computeSize();
        }
        if (this.maskAdjacent != null) {
            size += this.maskAdjacent.computeSize();
        }
        if (this.maskNeighbor != null) {
            size += this.maskNeighbor.computeSize();
        }
        if (this.maskCommands != null) {
            int maskCommandsSize = 0;
            for (final BuilderToolStringArg elem2 : this.maskCommands) {
                maskCommandsSize += elem2.computeSize();
            }
            size += VarInt.size(this.maskCommands.length) + maskCommandsSize;
        }
        return size;
    }
    
    public static ValidationResult validateStructure(@Nonnull final ByteBuf buffer, final int offset) {
        if (buffer.readableBytes() - offset < 84) {
            return ValidationResult.error("Buffer too small: expected at least 84 bytes");
        }
        final byte[] nullBits = PacketIO.readBytes(buffer, offset, 3);
        if ((nullBits[1] & 0x10) != 0x0) {
            final int materialOffset = buffer.getIntLE(offset + 48);
            if (materialOffset < 0) {
                return ValidationResult.error("Invalid offset for Material");
            }
            int pos = offset + 84 + materialOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Material");
            }
            final ValidationResult materialResult = BuilderToolBlockArg.validateStructure(buffer, pos);
            if (!materialResult.isValid()) {
                return ValidationResult.error("Invalid Material: " + materialResult.error());
            }
            pos += BuilderToolBlockArg.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[1] & 0x20) != 0x0) {
            final int favoriteMaterialsOffset = buffer.getIntLE(offset + 52);
            if (favoriteMaterialsOffset < 0) {
                return ValidationResult.error("Invalid offset for FavoriteMaterials");
            }
            int pos = offset + 84 + favoriteMaterialsOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for FavoriteMaterials");
            }
            final int favoriteMaterialsCount = VarInt.peek(buffer, pos);
            if (favoriteMaterialsCount < 0) {
                return ValidationResult.error("Invalid array count for FavoriteMaterials");
            }
            if (favoriteMaterialsCount > 4096000) {
                return ValidationResult.error("FavoriteMaterials exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < favoriteMaterialsCount; ++i) {
                final ValidationResult structResult = BuilderToolBlockArg.validateStructure(buffer, pos);
                if (!structResult.isValid()) {
                    return ValidationResult.error("Invalid BuilderToolBlockArg in FavoriteMaterials[" + i + "]: " + structResult.error());
                }
                pos += BuilderToolBlockArg.computeBytesConsumed(buffer, pos);
            }
        }
        if ((nullBits[1] & 0x40) != 0x0) {
            final int maskOffset = buffer.getIntLE(offset + 56);
            if (maskOffset < 0) {
                return ValidationResult.error("Invalid offset for Mask");
            }
            int pos = offset + 84 + maskOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for Mask");
            }
            final ValidationResult maskResult = BuilderToolMaskArg.validateStructure(buffer, pos);
            if (!maskResult.isValid()) {
                return ValidationResult.error("Invalid Mask: " + maskResult.error());
            }
            pos += BuilderToolMaskArg.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[1] & 0x80) != 0x0) {
            final int maskAboveOffset = buffer.getIntLE(offset + 60);
            if (maskAboveOffset < 0) {
                return ValidationResult.error("Invalid offset for MaskAbove");
            }
            int pos = offset + 84 + maskAboveOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for MaskAbove");
            }
            final ValidationResult maskAboveResult = BuilderToolMaskArg.validateStructure(buffer, pos);
            if (!maskAboveResult.isValid()) {
                return ValidationResult.error("Invalid MaskAbove: " + maskAboveResult.error());
            }
            pos += BuilderToolMaskArg.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[2] & 0x1) != 0x0) {
            final int maskNotOffset = buffer.getIntLE(offset + 64);
            if (maskNotOffset < 0) {
                return ValidationResult.error("Invalid offset for MaskNot");
            }
            int pos = offset + 84 + maskNotOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for MaskNot");
            }
            final ValidationResult maskNotResult = BuilderToolMaskArg.validateStructure(buffer, pos);
            if (!maskNotResult.isValid()) {
                return ValidationResult.error("Invalid MaskNot: " + maskNotResult.error());
            }
            pos += BuilderToolMaskArg.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[2] & 0x2) != 0x0) {
            final int maskBelowOffset = buffer.getIntLE(offset + 68);
            if (maskBelowOffset < 0) {
                return ValidationResult.error("Invalid offset for MaskBelow");
            }
            int pos = offset + 84 + maskBelowOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for MaskBelow");
            }
            final ValidationResult maskBelowResult = BuilderToolMaskArg.validateStructure(buffer, pos);
            if (!maskBelowResult.isValid()) {
                return ValidationResult.error("Invalid MaskBelow: " + maskBelowResult.error());
            }
            pos += BuilderToolMaskArg.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[2] & 0x4) != 0x0) {
            final int maskAdjacentOffset = buffer.getIntLE(offset + 72);
            if (maskAdjacentOffset < 0) {
                return ValidationResult.error("Invalid offset for MaskAdjacent");
            }
            int pos = offset + 84 + maskAdjacentOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for MaskAdjacent");
            }
            final ValidationResult maskAdjacentResult = BuilderToolMaskArg.validateStructure(buffer, pos);
            if (!maskAdjacentResult.isValid()) {
                return ValidationResult.error("Invalid MaskAdjacent: " + maskAdjacentResult.error());
            }
            pos += BuilderToolMaskArg.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[2] & 0x8) != 0x0) {
            final int maskNeighborOffset = buffer.getIntLE(offset + 76);
            if (maskNeighborOffset < 0) {
                return ValidationResult.error("Invalid offset for MaskNeighbor");
            }
            int pos = offset + 84 + maskNeighborOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for MaskNeighbor");
            }
            final ValidationResult maskNeighborResult = BuilderToolMaskArg.validateStructure(buffer, pos);
            if (!maskNeighborResult.isValid()) {
                return ValidationResult.error("Invalid MaskNeighbor: " + maskNeighborResult.error());
            }
            pos += BuilderToolMaskArg.computeBytesConsumed(buffer, pos);
        }
        if ((nullBits[2] & 0x10) != 0x0) {
            final int maskCommandsOffset = buffer.getIntLE(offset + 80);
            if (maskCommandsOffset < 0) {
                return ValidationResult.error("Invalid offset for MaskCommands");
            }
            int pos = offset + 84 + maskCommandsOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for MaskCommands");
            }
            final int maskCommandsCount = VarInt.peek(buffer, pos);
            if (maskCommandsCount < 0) {
                return ValidationResult.error("Invalid array count for MaskCommands");
            }
            if (maskCommandsCount > 4096000) {
                return ValidationResult.error("MaskCommands exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            for (int i = 0; i < maskCommandsCount; ++i) {
                final ValidationResult structResult = BuilderToolStringArg.validateStructure(buffer, pos);
                if (!structResult.isValid()) {
                    return ValidationResult.error("Invalid BuilderToolStringArg in MaskCommands[" + i + "]: " + structResult.error());
                }
                pos += BuilderToolStringArg.computeBytesConsumed(buffer, pos);
            }
        }
        return ValidationResult.OK;
    }
    
    public BuilderToolBrushData clone() {
        final BuilderToolBrushData copy = new BuilderToolBrushData();
        copy.width = ((this.width != null) ? this.width.clone() : null);
        copy.height = ((this.height != null) ? this.height.clone() : null);
        copy.thickness = ((this.thickness != null) ? this.thickness.clone() : null);
        copy.capped = ((this.capped != null) ? this.capped.clone() : null);
        copy.shape = ((this.shape != null) ? this.shape.clone() : null);
        copy.origin = ((this.origin != null) ? this.origin.clone() : null);
        copy.originRotation = ((this.originRotation != null) ? this.originRotation.clone() : null);
        copy.rotationAxis = ((this.rotationAxis != null) ? this.rotationAxis.clone() : null);
        copy.rotationAngle = ((this.rotationAngle != null) ? this.rotationAngle.clone() : null);
        copy.mirrorAxis = ((this.mirrorAxis != null) ? this.mirrorAxis.clone() : null);
        copy.material = ((this.material != null) ? this.material.clone() : null);
        copy.favoriteMaterials = (BuilderToolBlockArg[])((this.favoriteMaterials != null) ? ((BuilderToolBlockArg[])Arrays.stream(this.favoriteMaterials).map(e -> e.clone()).toArray(BuilderToolBlockArg[]::new)) : null);
        copy.mask = ((this.mask != null) ? this.mask.clone() : null);
        copy.maskAbove = ((this.maskAbove != null) ? this.maskAbove.clone() : null);
        copy.maskNot = ((this.maskNot != null) ? this.maskNot.clone() : null);
        copy.maskBelow = ((this.maskBelow != null) ? this.maskBelow.clone() : null);
        copy.maskAdjacent = ((this.maskAdjacent != null) ? this.maskAdjacent.clone() : null);
        copy.maskNeighbor = ((this.maskNeighbor != null) ? this.maskNeighbor.clone() : null);
        copy.maskCommands = (BuilderToolStringArg[])((this.maskCommands != null) ? ((BuilderToolStringArg[])Arrays.stream(this.maskCommands).map(e -> e.clone()).toArray(BuilderToolStringArg[]::new)) : null);
        copy.useMaskCommands = ((this.useMaskCommands != null) ? this.useMaskCommands.clone() : null);
        copy.invertMask = ((this.invertMask != null) ? this.invertMask.clone() : null);
        return copy;
    }
    
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof final BuilderToolBrushData other) {
            return Objects.equals(this.width, other.width) && Objects.equals(this.height, other.height) && Objects.equals(this.thickness, other.thickness) && Objects.equals(this.capped, other.capped) && Objects.equals(this.shape, other.shape) && Objects.equals(this.origin, other.origin) && Objects.equals(this.originRotation, other.originRotation) && Objects.equals(this.rotationAxis, other.rotationAxis) && Objects.equals(this.rotationAngle, other.rotationAngle) && Objects.equals(this.mirrorAxis, other.mirrorAxis) && Objects.equals(this.material, other.material) && Arrays.equals(this.favoriteMaterials, other.favoriteMaterials) && Objects.equals(this.mask, other.mask) && Objects.equals(this.maskAbove, other.maskAbove) && Objects.equals(this.maskNot, other.maskNot) && Objects.equals(this.maskBelow, other.maskBelow) && Objects.equals(this.maskAdjacent, other.maskAdjacent) && Objects.equals(this.maskNeighbor, other.maskNeighbor) && Arrays.equals(this.maskCommands, other.maskCommands) && Objects.equals(this.useMaskCommands, other.useMaskCommands) && Objects.equals(this.invertMask, other.invertMask);
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        int result = 1;
        result = 31 * result + Objects.hashCode(this.width);
        result = 31 * result + Objects.hashCode(this.height);
        result = 31 * result + Objects.hashCode(this.thickness);
        result = 31 * result + Objects.hashCode(this.capped);
        result = 31 * result + Objects.hashCode(this.shape);
        result = 31 * result + Objects.hashCode(this.origin);
        result = 31 * result + Objects.hashCode(this.originRotation);
        result = 31 * result + Objects.hashCode(this.rotationAxis);
        result = 31 * result + Objects.hashCode(this.rotationAngle);
        result = 31 * result + Objects.hashCode(this.mirrorAxis);
        result = 31 * result + Objects.hashCode(this.material);
        result = 31 * result + Arrays.hashCode(this.favoriteMaterials);
        result = 31 * result + Objects.hashCode(this.mask);
        result = 31 * result + Objects.hashCode(this.maskAbove);
        result = 31 * result + Objects.hashCode(this.maskNot);
        result = 31 * result + Objects.hashCode(this.maskBelow);
        result = 31 * result + Objects.hashCode(this.maskAdjacent);
        result = 31 * result + Objects.hashCode(this.maskNeighbor);
        result = 31 * result + Arrays.hashCode(this.maskCommands);
        result = 31 * result + Objects.hashCode(this.useMaskCommands);
        result = 31 * result + Objects.hashCode(this.invertMask);
        return result;
    }
}
