blob: f3be8f9aeabd9188c992d878591c3c17e264f8df [file] [log] [blame] [raw]
package protocolsupport.protocol.codec;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.EncoderException;
import protocolsupport.api.ProtocolVersion;
import protocolsupport.protocol.typeremapper.itemstack.ItemStackRemappingHelper;
import protocolsupport.protocol.types.NetworkItemStack;
import protocolsupport.protocol.types.nbt.NBTCompound;
import protocolsupport.protocol.types.nbt.NBTEnd;
import protocolsupport.protocol.types.nbt.serializer.DefaultNBTSerializer;
import protocolsupport.protocol.utils.ProtocolVersionsHelper;
import protocolsupport.protocol.utils.SimpleTypeDeserializer;
import protocolsupport.protocol.utils.SimpleTypeSerializer;
import protocolsupportbuildprocessor.Preload;
@Preload
public class ItemStackCodec {
private ItemStackCodec() {
}
public static final SimpleTypeDeserializer<NetworkItemStack> ITEMSTACK_DESERIALIZER = new SimpleTypeDeserializer<>(
Map.entry(ItemStackCodec::readItemStack, ProtocolVersion.getAllAfterI(ProtocolVersion.MINECRAFT_1_13_2)),
Map.entry(from -> {
int typeId = from.readShort();
if (typeId < 0) {
return NetworkItemStack.NULL;
} else {
NetworkItemStack itemstack = new NetworkItemStack();
itemstack.setTypeId(typeId);
itemstack.setAmount(from.readByte());
itemstack.setNBT(readDirectTag(from));
return itemstack;
}
}, ProtocolVersion.getAllBetween(ProtocolVersion.MINECRAFT_1_13, ProtocolVersion.MINECRAFT_1_13_1)),
Map.entry(from -> {
int typeId = from.readShort();
if (typeId < 0) {
return NetworkItemStack.NULL;
} else {
NetworkItemStack itemstack = new NetworkItemStack();
itemstack.setTypeId(typeId);
itemstack.setAmount(from.readByte());
itemstack.setLegacyData(from.readShort());
itemstack.setNBT(readDirectTag(from));
return itemstack;
}
}, ProtocolVersion.getAllBetween(ProtocolVersion.MINECRAFT_1_12_2, ProtocolVersion.MINECRAFT_1_8)),
Map.entry(from -> {
int typeId = from.readShort();
if (typeId < 0) {
return NetworkItemStack.NULL;
} else {
NetworkItemStack itemstack = new NetworkItemStack();
itemstack.setTypeId(typeId);
itemstack.setAmount(from.readByte());
itemstack.setLegacyData(from.readShort());
itemstack.setNBT(readShortTag(from));
return itemstack;
}
}, ProtocolVersionsHelper.DOWN_1_7_10)
);
public static final SimpleTypeSerializer<NetworkItemStack> ITEMSTACK_SERIALIZER = new SimpleTypeSerializer<>(
Map.entry(ItemStackCodec::writeItemStack, ProtocolVersion.getAllAfterI(ProtocolVersion.MINECRAFT_1_13_2)),
Map.entry((to, itemstack) -> {
if (itemstack.isNull()) {
to.writeShort(-1);
} else {
to.writeShort(itemstack.getTypeId());
to.writeByte(itemstack.getAmount());
writeDirectTag(to, itemstack.getNBT());
}
}, ProtocolVersion.getAllBetween(ProtocolVersion.MINECRAFT_1_13, ProtocolVersion.MINECRAFT_1_13_1)),
Map.entry((to, itemstack) -> {
if (itemstack.isNull()) {
to.writeShort(-1);
} else {
to.writeShort(itemstack.getTypeId());
to.writeByte(itemstack.getAmount());
to.writeShort(itemstack.getLegacyData());
writeDirectTag(to, itemstack.getNBT());
}
}, ProtocolVersion.getAllBetween(ProtocolVersion.MINECRAFT_1_12_2, ProtocolVersion.MINECRAFT_1_8)),
Map.entry((to, itemstack) -> {
if (itemstack.isNull()) {
to.writeShort(-1);
} else {
to.writeShort(itemstack.getTypeId());
to.writeByte(itemstack.getAmount());
to.writeShort(itemstack.getLegacyData());
writeShortTag(to, itemstack.getNBT());
}
}, ProtocolVersionsHelper.DOWN_1_7_10)
);
/**
* Reads itemstack using latest protocol version format
* @param from buffer to read from
* @return itemstack itemstack
*/
public static NetworkItemStack readItemStack(ByteBuf from) {
if (!from.readBoolean()) {
return NetworkItemStack.NULL;
}
NetworkItemStack itemstack = new NetworkItemStack();
itemstack.setTypeId(VarNumberCodec.readVarInt(from));
itemstack.setAmount(from.readByte());
itemstack.setNBT(readDirectTag(from));
return itemstack;
}
/**
* Reads itemstack using provided protocol version format<br>
* @param from buffer to read from
* @param version protocol version
* @return itemstack itemstack
*/
public static NetworkItemStack readItemStack(ByteBuf from, ProtocolVersion version) {
NetworkItemStack itemstack = ITEMSTACK_DESERIALIZER.get(version).apply(from);
if (!itemstack.isNull()) {
itemstack = ItemStackRemappingHelper.fromLegacyItemFormat(version, itemstack);
}
return itemstack;
}
/**
* Writes itemstack using latest protocol version format
* @param to buffer to write to
* @param itemstack itemstack
*/
public static void writeItemStack(ByteBuf to, NetworkItemStack itemstack) {
if (itemstack.isNull()) {
to.writeBoolean(false);
} else {
to.writeBoolean(true);
VarNumberCodec.writeVarInt(to, itemstack.getTypeId());
to.writeByte(itemstack.getAmount());
writeTag(to, ProtocolVersionsHelper.LATEST_PC, itemstack.getNBT());
}
}
/**
* Writes itemstack using provided protocol version format
* @param to buffer to write to
* @param version protocol version
* @param itemstack itemstack
*/
public static void writeItemStack(ByteBuf to, ProtocolVersion version, NetworkItemStack itemstack) {
ITEMSTACK_SERIALIZER.get(version).accept(to, itemstack);
}
/**
* Transforms and writes itemstack using provided protocol version format
* @param to buffer to write to
* @param version protocol version
* @param locale client locale
* @param itemstack itemstack
*/
public static void writeItemStack(ByteBuf to, ProtocolVersion version, String locale, NetworkItemStack itemstack) {
writeItemStack(to, version, ItemStackRemappingHelper.toLegacyItemDataFormat(version, locale, itemstack));
}
public static final SimpleTypeDeserializer<NBTCompound> TAG_DESERIALIZER = new SimpleTypeDeserializer<>(
Map.entry(ItemStackCodec::readDirectTag, ProtocolVersionsHelper.UP_1_8),
Map.entry(ItemStackCodec::readShortTag, ProtocolVersionsHelper.DOWN_1_7_10)
);
public static final SimpleTypeSerializer<NBTCompound> TAG_SERIALIZER = new SimpleTypeSerializer<>(
Map.entry(ItemStackCodec::writeDirectTag, ProtocolVersionsHelper.UP_1_8),
Map.entry(ItemStackCodec::writeShortTag, ProtocolVersionsHelper.DOWN_1_7_10)
);
public static NBTCompound readTag(ByteBuf from, ProtocolVersion version) {
return TAG_DESERIALIZER.get(version).apply(from);
}
public static NBTCompound readDirectTag(ByteBuf from) {
try {
return (NBTCompound) DefaultNBTSerializer.INSTANCE.deserializeTag(new ByteBufInputStream(from));
} catch (IOException e) {
throw new DecoderException(e);
}
}
public static NBTCompound readShortTag(ByteBuf from) {
try {
final short length = from.readShort();
if (length < 0) {
return null;
}
try (DataInputStream stream = new DataInputStream(new GZIPInputStream(new ByteBufInputStream(from.readSlice(length))))) {
return (NBTCompound) DefaultNBTSerializer.INSTANCE.deserializeTag(stream);
}
} catch (IOException e) {
throw new DecoderException(e);
}
}
/**
* Writes tag using provided protocol version format
* @param to buffer to write to
* @param version protocol version
* @param tag nbt compound
*/
public static void writeTag(ByteBuf to, ProtocolVersion version, NBTCompound tag) {
TAG_SERIALIZER.get(version).accept(to, tag);
}
/**
* Writes tag using latest protocol version format (Directly serializes nbt to buffer).
* @param to buffer to write to
* @param tag nbt compound
*/
public static void writeDirectTag(ByteBuf to, NBTCompound tag) {
try (ByteBufOutputStream outputstream = new ByteBufOutputStream(to)) {
if (tag != null) {
DefaultNBTSerializer.INSTANCE.serializeTag(outputstream, tag);
} else {
DefaultNBTSerializer.INSTANCE.serializeTag(outputstream, NBTEnd.INSTANCE);
}
} catch (IOException e) {
throw new EncoderException(e);
}
}
/**
* Writes tag using legacy protocol version format (Prefixes serialized nbt data with short length).
* @param to buffer to write to
* @param tag nbt compound
*/
public static void writeShortTag(ByteBuf to, NBTCompound tag) {
if (tag == null) {
to.writeShort(-1);
} else {
MiscDataCodec.writeShortLengthPrefixedType(to, tag, (lTo, lTag) -> {
try (DataOutputStream outputstream = new DataOutputStream(new GZIPOutputStream(new ByteBufOutputStream(lTo)))) {
DefaultNBTSerializer.INSTANCE.serializeTag(outputstream, lTag);
} catch (Exception e) {
throw new EncoderException(e);
}
});
}
}
}