977 lines
34 KiB
Java
977 lines
34 KiB
Java
package com.hypixel.hytale.protocol.packets.buildertools;
|
|
|
|
import com.hypixel.hytale.protocol.io.PacketIO;
|
|
import com.hypixel.hytale.protocol.io.ProtocolException;
|
|
import com.hypixel.hytale.protocol.io.ValidationResult;
|
|
import com.hypixel.hytale.protocol.io.VarInt;
|
|
import io.netty.buffer.ByteBuf;
|
|
import java.util.Arrays;
|
|
import java.util.Objects;
|
|
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 BuilderToolIntArg width,
|
|
@Nullable BuilderToolIntArg height,
|
|
@Nullable BuilderToolIntArg thickness,
|
|
@Nullable BuilderToolBoolArg capped,
|
|
@Nullable BuilderToolBrushShapeArg shape,
|
|
@Nullable BuilderToolBrushOriginArg origin,
|
|
@Nullable BuilderToolBoolArg originRotation,
|
|
@Nullable BuilderToolBrushAxisArg rotationAxis,
|
|
@Nullable BuilderToolRotationArg rotationAngle,
|
|
@Nullable BuilderToolBrushAxisArg mirrorAxis,
|
|
@Nullable BuilderToolBlockArg material,
|
|
@Nullable BuilderToolBlockArg[] favoriteMaterials,
|
|
@Nullable BuilderToolMaskArg mask,
|
|
@Nullable BuilderToolMaskArg maskAbove,
|
|
@Nullable BuilderToolMaskArg maskNot,
|
|
@Nullable BuilderToolMaskArg maskBelow,
|
|
@Nullable BuilderToolMaskArg maskAdjacent,
|
|
@Nullable BuilderToolMaskArg maskNeighbor,
|
|
@Nullable BuilderToolStringArg[] maskCommands,
|
|
@Nullable BuilderToolBoolArg useMaskCommands,
|
|
@Nullable 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 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 ByteBuf buf, int offset) {
|
|
BuilderToolBrushData obj = new BuilderToolBrushData();
|
|
byte[] nullBits = PacketIO.readBytes(buf, offset, 3);
|
|
if ((nullBits[0] & 1) != 0) {
|
|
obj.width = BuilderToolIntArg.deserialize(buf, offset + 3);
|
|
}
|
|
|
|
if ((nullBits[0] & 2) != 0) {
|
|
obj.height = BuilderToolIntArg.deserialize(buf, offset + 15);
|
|
}
|
|
|
|
if ((nullBits[0] & 4) != 0) {
|
|
obj.thickness = BuilderToolIntArg.deserialize(buf, offset + 27);
|
|
}
|
|
|
|
if ((nullBits[0] & 8) != 0) {
|
|
obj.capped = BuilderToolBoolArg.deserialize(buf, offset + 39);
|
|
}
|
|
|
|
if ((nullBits[0] & 16) != 0) {
|
|
obj.shape = BuilderToolBrushShapeArg.deserialize(buf, offset + 40);
|
|
}
|
|
|
|
if ((nullBits[0] & 32) != 0) {
|
|
obj.origin = BuilderToolBrushOriginArg.deserialize(buf, offset + 41);
|
|
}
|
|
|
|
if ((nullBits[0] & 64) != 0) {
|
|
obj.originRotation = BuilderToolBoolArg.deserialize(buf, offset + 42);
|
|
}
|
|
|
|
if ((nullBits[0] & 128) != 0) {
|
|
obj.rotationAxis = BuilderToolBrushAxisArg.deserialize(buf, offset + 43);
|
|
}
|
|
|
|
if ((nullBits[1] & 1) != 0) {
|
|
obj.rotationAngle = BuilderToolRotationArg.deserialize(buf, offset + 44);
|
|
}
|
|
|
|
if ((nullBits[1] & 2) != 0) {
|
|
obj.mirrorAxis = BuilderToolBrushAxisArg.deserialize(buf, offset + 45);
|
|
}
|
|
|
|
if ((nullBits[2] & 8) != 0) {
|
|
obj.useMaskCommands = BuilderToolBoolArg.deserialize(buf, offset + 46);
|
|
}
|
|
|
|
if ((nullBits[2] & 16) != 0) {
|
|
obj.invertMask = BuilderToolBoolArg.deserialize(buf, offset + 47);
|
|
}
|
|
|
|
if ((nullBits[1] & 4) != 0) {
|
|
int varPos0 = offset + 84 + buf.getIntLE(offset + 48);
|
|
obj.material = BuilderToolBlockArg.deserialize(buf, varPos0);
|
|
}
|
|
|
|
if ((nullBits[1] & 8) != 0) {
|
|
int varPos1 = offset + 84 + buf.getIntLE(offset + 52);
|
|
int favoriteMaterialsCount = VarInt.peek(buf, varPos1);
|
|
if (favoriteMaterialsCount < 0) {
|
|
throw ProtocolException.negativeLength("FavoriteMaterials", favoriteMaterialsCount);
|
|
}
|
|
|
|
if (favoriteMaterialsCount > 4096000) {
|
|
throw ProtocolException.arrayTooLong("FavoriteMaterials", favoriteMaterialsCount, 4096000);
|
|
}
|
|
|
|
int varIntLen = VarInt.length(buf, varPos1);
|
|
if (varPos1 + varIntLen + favoriteMaterialsCount * 2L > buf.readableBytes()) {
|
|
throw ProtocolException.bufferTooSmall("FavoriteMaterials", varPos1 + varIntLen + favoriteMaterialsCount * 2, buf.readableBytes());
|
|
}
|
|
|
|
obj.favoriteMaterials = new BuilderToolBlockArg[favoriteMaterialsCount];
|
|
int elemPos = varPos1 + varIntLen;
|
|
|
|
for (int i = 0; i < favoriteMaterialsCount; i++) {
|
|
obj.favoriteMaterials[i] = BuilderToolBlockArg.deserialize(buf, elemPos);
|
|
elemPos += BuilderToolBlockArg.computeBytesConsumed(buf, elemPos);
|
|
}
|
|
}
|
|
|
|
if ((nullBits[1] & 16) != 0) {
|
|
int varPos2 = offset + 84 + buf.getIntLE(offset + 56);
|
|
obj.mask = BuilderToolMaskArg.deserialize(buf, varPos2);
|
|
}
|
|
|
|
if ((nullBits[1] & 32) != 0) {
|
|
int varPos3 = offset + 84 + buf.getIntLE(offset + 60);
|
|
obj.maskAbove = BuilderToolMaskArg.deserialize(buf, varPos3);
|
|
}
|
|
|
|
if ((nullBits[1] & 64) != 0) {
|
|
int varPos4 = offset + 84 + buf.getIntLE(offset + 64);
|
|
obj.maskNot = BuilderToolMaskArg.deserialize(buf, varPos4);
|
|
}
|
|
|
|
if ((nullBits[1] & 128) != 0) {
|
|
int varPos5 = offset + 84 + buf.getIntLE(offset + 68);
|
|
obj.maskBelow = BuilderToolMaskArg.deserialize(buf, varPos5);
|
|
}
|
|
|
|
if ((nullBits[2] & 1) != 0) {
|
|
int varPos6 = offset + 84 + buf.getIntLE(offset + 72);
|
|
obj.maskAdjacent = BuilderToolMaskArg.deserialize(buf, varPos6);
|
|
}
|
|
|
|
if ((nullBits[2] & 2) != 0) {
|
|
int varPos7 = offset + 84 + buf.getIntLE(offset + 76);
|
|
obj.maskNeighbor = BuilderToolMaskArg.deserialize(buf, varPos7);
|
|
}
|
|
|
|
if ((nullBits[2] & 4) != 0) {
|
|
int varPos8 = offset + 84 + buf.getIntLE(offset + 80);
|
|
int maskCommandsCount = VarInt.peek(buf, varPos8);
|
|
if (maskCommandsCount < 0) {
|
|
throw ProtocolException.negativeLength("MaskCommands", maskCommandsCount);
|
|
}
|
|
|
|
if (maskCommandsCount > 4096000) {
|
|
throw ProtocolException.arrayTooLong("MaskCommands", maskCommandsCount, 4096000);
|
|
}
|
|
|
|
int varIntLen = VarInt.length(buf, varPos8);
|
|
if (varPos8 + varIntLen + maskCommandsCount * 1L > buf.readableBytes()) {
|
|
throw ProtocolException.bufferTooSmall("MaskCommands", varPos8 + varIntLen + maskCommandsCount * 1, buf.readableBytes());
|
|
}
|
|
|
|
obj.maskCommands = new BuilderToolStringArg[maskCommandsCount];
|
|
int elemPos = varPos8 + 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 ByteBuf buf, int offset) {
|
|
byte[] nullBits = PacketIO.readBytes(buf, offset, 3);
|
|
int maxEnd = 84;
|
|
if ((nullBits[1] & 4) != 0) {
|
|
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] & 8) != 0) {
|
|
int fieldOffset1 = buf.getIntLE(offset + 52);
|
|
int pos1 = offset + 84 + fieldOffset1;
|
|
int arrLen = VarInt.peek(buf, pos1);
|
|
pos1 += VarInt.length(buf, pos1);
|
|
|
|
for (int i = 0; i < arrLen; i++) {
|
|
pos1 += BuilderToolBlockArg.computeBytesConsumed(buf, pos1);
|
|
}
|
|
|
|
if (pos1 - offset > maxEnd) {
|
|
maxEnd = pos1 - offset;
|
|
}
|
|
}
|
|
|
|
if ((nullBits[1] & 16) != 0) {
|
|
int fieldOffset2 = buf.getIntLE(offset + 56);
|
|
int pos2 = offset + 84 + fieldOffset2;
|
|
pos2 += BuilderToolMaskArg.computeBytesConsumed(buf, pos2);
|
|
if (pos2 - offset > maxEnd) {
|
|
maxEnd = pos2 - offset;
|
|
}
|
|
}
|
|
|
|
if ((nullBits[1] & 32) != 0) {
|
|
int fieldOffset3 = buf.getIntLE(offset + 60);
|
|
int pos3 = offset + 84 + fieldOffset3;
|
|
pos3 += BuilderToolMaskArg.computeBytesConsumed(buf, pos3);
|
|
if (pos3 - offset > maxEnd) {
|
|
maxEnd = pos3 - offset;
|
|
}
|
|
}
|
|
|
|
if ((nullBits[1] & 64) != 0) {
|
|
int fieldOffset4 = buf.getIntLE(offset + 64);
|
|
int pos4 = offset + 84 + fieldOffset4;
|
|
pos4 += BuilderToolMaskArg.computeBytesConsumed(buf, pos4);
|
|
if (pos4 - offset > maxEnd) {
|
|
maxEnd = pos4 - offset;
|
|
}
|
|
}
|
|
|
|
if ((nullBits[1] & 128) != 0) {
|
|
int fieldOffset5 = buf.getIntLE(offset + 68);
|
|
int pos5 = offset + 84 + fieldOffset5;
|
|
pos5 += BuilderToolMaskArg.computeBytesConsumed(buf, pos5);
|
|
if (pos5 - offset > maxEnd) {
|
|
maxEnd = pos5 - offset;
|
|
}
|
|
}
|
|
|
|
if ((nullBits[2] & 1) != 0) {
|
|
int fieldOffset6 = buf.getIntLE(offset + 72);
|
|
int pos6 = offset + 84 + fieldOffset6;
|
|
pos6 += BuilderToolMaskArg.computeBytesConsumed(buf, pos6);
|
|
if (pos6 - offset > maxEnd) {
|
|
maxEnd = pos6 - offset;
|
|
}
|
|
}
|
|
|
|
if ((nullBits[2] & 2) != 0) {
|
|
int fieldOffset7 = buf.getIntLE(offset + 76);
|
|
int pos7 = offset + 84 + fieldOffset7;
|
|
pos7 += BuilderToolMaskArg.computeBytesConsumed(buf, pos7);
|
|
if (pos7 - offset > maxEnd) {
|
|
maxEnd = pos7 - offset;
|
|
}
|
|
}
|
|
|
|
if ((nullBits[2] & 4) != 0) {
|
|
int fieldOffset8 = buf.getIntLE(offset + 80);
|
|
int pos8 = offset + 84 + fieldOffset8;
|
|
int arrLen = VarInt.peek(buf, pos8);
|
|
pos8 += VarInt.length(buf, pos8);
|
|
|
|
for (int i = 0; i < arrLen; i++) {
|
|
pos8 += BuilderToolStringArg.computeBytesConsumed(buf, pos8);
|
|
}
|
|
|
|
if (pos8 - offset > maxEnd) {
|
|
maxEnd = pos8 - offset;
|
|
}
|
|
}
|
|
|
|
return maxEnd;
|
|
}
|
|
|
|
public void serialize(@Nonnull ByteBuf buf) {
|
|
int startPos = buf.writerIndex();
|
|
byte[] nullBits = new byte[3];
|
|
if (this.width != null) {
|
|
nullBits[0] = (byte)(nullBits[0] | 1);
|
|
}
|
|
|
|
if (this.height != null) {
|
|
nullBits[0] = (byte)(nullBits[0] | 2);
|
|
}
|
|
|
|
if (this.thickness != null) {
|
|
nullBits[0] = (byte)(nullBits[0] | 4);
|
|
}
|
|
|
|
if (this.capped != null) {
|
|
nullBits[0] = (byte)(nullBits[0] | 8);
|
|
}
|
|
|
|
if (this.shape != null) {
|
|
nullBits[0] = (byte)(nullBits[0] | 16);
|
|
}
|
|
|
|
if (this.origin != null) {
|
|
nullBits[0] = (byte)(nullBits[0] | 32);
|
|
}
|
|
|
|
if (this.originRotation != null) {
|
|
nullBits[0] = (byte)(nullBits[0] | 64);
|
|
}
|
|
|
|
if (this.rotationAxis != null) {
|
|
nullBits[0] = (byte)(nullBits[0] | 128);
|
|
}
|
|
|
|
if (this.rotationAngle != null) {
|
|
nullBits[1] = (byte)(nullBits[1] | 1);
|
|
}
|
|
|
|
if (this.mirrorAxis != null) {
|
|
nullBits[1] = (byte)(nullBits[1] | 2);
|
|
}
|
|
|
|
if (this.material != null) {
|
|
nullBits[1] = (byte)(nullBits[1] | 4);
|
|
}
|
|
|
|
if (this.favoriteMaterials != null) {
|
|
nullBits[1] = (byte)(nullBits[1] | 8);
|
|
}
|
|
|
|
if (this.mask != null) {
|
|
nullBits[1] = (byte)(nullBits[1] | 16);
|
|
}
|
|
|
|
if (this.maskAbove != null) {
|
|
nullBits[1] = (byte)(nullBits[1] | 32);
|
|
}
|
|
|
|
if (this.maskNot != null) {
|
|
nullBits[1] = (byte)(nullBits[1] | 64);
|
|
}
|
|
|
|
if (this.maskBelow != null) {
|
|
nullBits[1] = (byte)(nullBits[1] | 128);
|
|
}
|
|
|
|
if (this.maskAdjacent != null) {
|
|
nullBits[2] = (byte)(nullBits[2] | 1);
|
|
}
|
|
|
|
if (this.maskNeighbor != null) {
|
|
nullBits[2] = (byte)(nullBits[2] | 2);
|
|
}
|
|
|
|
if (this.maskCommands != null) {
|
|
nullBits[2] = (byte)(nullBits[2] | 4);
|
|
}
|
|
|
|
if (this.useMaskCommands != null) {
|
|
nullBits[2] = (byte)(nullBits[2] | 8);
|
|
}
|
|
|
|
if (this.invertMask != null) {
|
|
nullBits[2] = (byte)(nullBits[2] | 16);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
int materialOffsetSlot = buf.writerIndex();
|
|
buf.writeIntLE(0);
|
|
int favoriteMaterialsOffsetSlot = buf.writerIndex();
|
|
buf.writeIntLE(0);
|
|
int maskOffsetSlot = buf.writerIndex();
|
|
buf.writeIntLE(0);
|
|
int maskAboveOffsetSlot = buf.writerIndex();
|
|
buf.writeIntLE(0);
|
|
int maskNotOffsetSlot = buf.writerIndex();
|
|
buf.writeIntLE(0);
|
|
int maskBelowOffsetSlot = buf.writerIndex();
|
|
buf.writeIntLE(0);
|
|
int maskAdjacentOffsetSlot = buf.writerIndex();
|
|
buf.writeIntLE(0);
|
|
int maskNeighborOffsetSlot = buf.writerIndex();
|
|
buf.writeIntLE(0);
|
|
int maskCommandsOffsetSlot = buf.writerIndex();
|
|
buf.writeIntLE(0);
|
|
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 (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 (BuilderToolStringArg item : this.maskCommands) {
|
|
item.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 (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 (BuilderToolStringArg elem : this.maskCommands) {
|
|
maskCommandsSize += elem.computeSize();
|
|
}
|
|
|
|
size += VarInt.size(this.maskCommands.length) + maskCommandsSize;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
|
|
if (buffer.readableBytes() - offset < 84) {
|
|
return ValidationResult.error("Buffer too small: expected at least 84 bytes");
|
|
} else {
|
|
byte[] nullBits = PacketIO.readBytes(buffer, offset, 3);
|
|
if ((nullBits[1] & 4) != 0) {
|
|
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");
|
|
}
|
|
|
|
ValidationResult materialResult = BuilderToolBlockArg.validateStructure(buffer, pos);
|
|
if (!materialResult.isValid()) {
|
|
return ValidationResult.error("Invalid Material: " + materialResult.error());
|
|
}
|
|
|
|
pos += BuilderToolBlockArg.computeBytesConsumed(buffer, pos);
|
|
}
|
|
|
|
if ((nullBits[1] & 8) != 0) {
|
|
int favoriteMaterialsOffset = buffer.getIntLE(offset + 52);
|
|
if (favoriteMaterialsOffset < 0) {
|
|
return ValidationResult.error("Invalid offset for FavoriteMaterials");
|
|
}
|
|
|
|
int posx = offset + 84 + favoriteMaterialsOffset;
|
|
if (posx >= buffer.writerIndex()) {
|
|
return ValidationResult.error("Offset out of bounds for FavoriteMaterials");
|
|
}
|
|
|
|
int favoriteMaterialsCount = VarInt.peek(buffer, posx);
|
|
if (favoriteMaterialsCount < 0) {
|
|
return ValidationResult.error("Invalid array count for FavoriteMaterials");
|
|
}
|
|
|
|
if (favoriteMaterialsCount > 4096000) {
|
|
return ValidationResult.error("FavoriteMaterials exceeds max length 4096000");
|
|
}
|
|
|
|
posx += VarInt.length(buffer, posx);
|
|
|
|
for (int i = 0; i < favoriteMaterialsCount; i++) {
|
|
ValidationResult structResult = BuilderToolBlockArg.validateStructure(buffer, posx);
|
|
if (!structResult.isValid()) {
|
|
return ValidationResult.error("Invalid BuilderToolBlockArg in FavoriteMaterials[" + i + "]: " + structResult.error());
|
|
}
|
|
|
|
posx += BuilderToolBlockArg.computeBytesConsumed(buffer, posx);
|
|
}
|
|
}
|
|
|
|
if ((nullBits[1] & 16) != 0) {
|
|
int maskOffset = buffer.getIntLE(offset + 56);
|
|
if (maskOffset < 0) {
|
|
return ValidationResult.error("Invalid offset for Mask");
|
|
}
|
|
|
|
int posxx = offset + 84 + maskOffset;
|
|
if (posxx >= buffer.writerIndex()) {
|
|
return ValidationResult.error("Offset out of bounds for Mask");
|
|
}
|
|
|
|
ValidationResult maskResult = BuilderToolMaskArg.validateStructure(buffer, posxx);
|
|
if (!maskResult.isValid()) {
|
|
return ValidationResult.error("Invalid Mask: " + maskResult.error());
|
|
}
|
|
|
|
posxx += BuilderToolMaskArg.computeBytesConsumed(buffer, posxx);
|
|
}
|
|
|
|
if ((nullBits[1] & 32) != 0) {
|
|
int maskAboveOffset = buffer.getIntLE(offset + 60);
|
|
if (maskAboveOffset < 0) {
|
|
return ValidationResult.error("Invalid offset for MaskAbove");
|
|
}
|
|
|
|
int posxxx = offset + 84 + maskAboveOffset;
|
|
if (posxxx >= buffer.writerIndex()) {
|
|
return ValidationResult.error("Offset out of bounds for MaskAbove");
|
|
}
|
|
|
|
ValidationResult maskAboveResult = BuilderToolMaskArg.validateStructure(buffer, posxxx);
|
|
if (!maskAboveResult.isValid()) {
|
|
return ValidationResult.error("Invalid MaskAbove: " + maskAboveResult.error());
|
|
}
|
|
|
|
posxxx += BuilderToolMaskArg.computeBytesConsumed(buffer, posxxx);
|
|
}
|
|
|
|
if ((nullBits[1] & 64) != 0) {
|
|
int maskNotOffset = buffer.getIntLE(offset + 64);
|
|
if (maskNotOffset < 0) {
|
|
return ValidationResult.error("Invalid offset for MaskNot");
|
|
}
|
|
|
|
int posxxxx = offset + 84 + maskNotOffset;
|
|
if (posxxxx >= buffer.writerIndex()) {
|
|
return ValidationResult.error("Offset out of bounds for MaskNot");
|
|
}
|
|
|
|
ValidationResult maskNotResult = BuilderToolMaskArg.validateStructure(buffer, posxxxx);
|
|
if (!maskNotResult.isValid()) {
|
|
return ValidationResult.error("Invalid MaskNot: " + maskNotResult.error());
|
|
}
|
|
|
|
posxxxx += BuilderToolMaskArg.computeBytesConsumed(buffer, posxxxx);
|
|
}
|
|
|
|
if ((nullBits[1] & 128) != 0) {
|
|
int maskBelowOffset = buffer.getIntLE(offset + 68);
|
|
if (maskBelowOffset < 0) {
|
|
return ValidationResult.error("Invalid offset for MaskBelow");
|
|
}
|
|
|
|
int posxxxxx = offset + 84 + maskBelowOffset;
|
|
if (posxxxxx >= buffer.writerIndex()) {
|
|
return ValidationResult.error("Offset out of bounds for MaskBelow");
|
|
}
|
|
|
|
ValidationResult maskBelowResult = BuilderToolMaskArg.validateStructure(buffer, posxxxxx);
|
|
if (!maskBelowResult.isValid()) {
|
|
return ValidationResult.error("Invalid MaskBelow: " + maskBelowResult.error());
|
|
}
|
|
|
|
posxxxxx += BuilderToolMaskArg.computeBytesConsumed(buffer, posxxxxx);
|
|
}
|
|
|
|
if ((nullBits[2] & 1) != 0) {
|
|
int maskAdjacentOffset = buffer.getIntLE(offset + 72);
|
|
if (maskAdjacentOffset < 0) {
|
|
return ValidationResult.error("Invalid offset for MaskAdjacent");
|
|
}
|
|
|
|
int posxxxxxx = offset + 84 + maskAdjacentOffset;
|
|
if (posxxxxxx >= buffer.writerIndex()) {
|
|
return ValidationResult.error("Offset out of bounds for MaskAdjacent");
|
|
}
|
|
|
|
ValidationResult maskAdjacentResult = BuilderToolMaskArg.validateStructure(buffer, posxxxxxx);
|
|
if (!maskAdjacentResult.isValid()) {
|
|
return ValidationResult.error("Invalid MaskAdjacent: " + maskAdjacentResult.error());
|
|
}
|
|
|
|
posxxxxxx += BuilderToolMaskArg.computeBytesConsumed(buffer, posxxxxxx);
|
|
}
|
|
|
|
if ((nullBits[2] & 2) != 0) {
|
|
int maskNeighborOffset = buffer.getIntLE(offset + 76);
|
|
if (maskNeighborOffset < 0) {
|
|
return ValidationResult.error("Invalid offset for MaskNeighbor");
|
|
}
|
|
|
|
int posxxxxxxx = offset + 84 + maskNeighborOffset;
|
|
if (posxxxxxxx >= buffer.writerIndex()) {
|
|
return ValidationResult.error("Offset out of bounds for MaskNeighbor");
|
|
}
|
|
|
|
ValidationResult maskNeighborResult = BuilderToolMaskArg.validateStructure(buffer, posxxxxxxx);
|
|
if (!maskNeighborResult.isValid()) {
|
|
return ValidationResult.error("Invalid MaskNeighbor: " + maskNeighborResult.error());
|
|
}
|
|
|
|
posxxxxxxx += BuilderToolMaskArg.computeBytesConsumed(buffer, posxxxxxxx);
|
|
}
|
|
|
|
if ((nullBits[2] & 4) != 0) {
|
|
int maskCommandsOffset = buffer.getIntLE(offset + 80);
|
|
if (maskCommandsOffset < 0) {
|
|
return ValidationResult.error("Invalid offset for MaskCommands");
|
|
}
|
|
|
|
int posxxxxxxxx = offset + 84 + maskCommandsOffset;
|
|
if (posxxxxxxxx >= buffer.writerIndex()) {
|
|
return ValidationResult.error("Offset out of bounds for MaskCommands");
|
|
}
|
|
|
|
int maskCommandsCount = VarInt.peek(buffer, posxxxxxxxx);
|
|
if (maskCommandsCount < 0) {
|
|
return ValidationResult.error("Invalid array count for MaskCommands");
|
|
}
|
|
|
|
if (maskCommandsCount > 4096000) {
|
|
return ValidationResult.error("MaskCommands exceeds max length 4096000");
|
|
}
|
|
|
|
posxxxxxxxx += VarInt.length(buffer, posxxxxxxxx);
|
|
|
|
for (int i = 0; i < maskCommandsCount; i++) {
|
|
ValidationResult structResult = BuilderToolStringArg.validateStructure(buffer, posxxxxxxxx);
|
|
if (!structResult.isValid()) {
|
|
return ValidationResult.error("Invalid BuilderToolStringArg in MaskCommands[" + i + "]: " + structResult.error());
|
|
}
|
|
|
|
posxxxxxxxx += BuilderToolStringArg.computeBytesConsumed(buffer, posxxxxxxxx);
|
|
}
|
|
}
|
|
|
|
return ValidationResult.OK;
|
|
}
|
|
}
|
|
|
|
public BuilderToolBrushData clone() {
|
|
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 = this.favoriteMaterials != null
|
|
? 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 = this.maskCommands != null ? 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(Object obj) {
|
|
if (this == obj) {
|
|
return true;
|
|
} else {
|
|
return !(obj instanceof BuilderToolBrushData other)
|
|
? false
|
|
: 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((Object[])this.favoriteMaterials, (Object[])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((Object[])this.maskCommands, (Object[])other.maskCommands)
|
|
&& Objects.equals(this.useMaskCommands, other.useMaskCommands)
|
|
&& Objects.equals(this.invertMask, other.invertMask);
|
|
}
|
|
}
|
|
|
|
@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((Object[])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((Object[])this.maskCommands);
|
|
result = 31 * result + Objects.hashCode(this.useMaskCommands);
|
|
return 31 * result + Objects.hashCode(this.invertMask);
|
|
}
|
|
}
|