blob: 6686a2ae3527555e3e9b28add57318bede168798 [file] [log] [blame] [raw]
package protocolsupport.protocol.serializer;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.bukkit.Bukkit;
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.ProtocolType;
import protocolsupport.api.ProtocolVersion;
import protocolsupport.api.events.ItemStackWriteEvent;
import protocolsupport.protocol.typeremapper.itemstack.ItemStackRemapper;
import protocolsupport.zplatform.ServerPlatform;
import protocolsupport.zplatform.itemstack.ItemStackWrapper;
import protocolsupport.zplatform.itemstack.NBTTagCompoundWrapper;
public class ItemStackSerializer {
public static ItemStackWrapper readItemStack(ByteBuf from, ProtocolVersion version) {
int type = from.readShort();
if (type >= 0) {
ItemStackWrapper itemstack = ServerPlatform.get().getWrapperFactory().createItemStack(type);
itemstack.setAmount(from.readByte());
itemstack.setData(from.readShort());
itemstack.setTag(readTag(from, version));
return ItemStackRemapper.remapServerbound(version, itemstack.cloneItemStack());
}
return ServerPlatform.get().getWrapperFactory().createNullItemStack();
}
public static void writeItemStack(ByteBuf to, ProtocolVersion version, ItemStackWrapper itemstack, boolean fireEvent) {
if (itemstack.isNull()) {
to.writeShort(-1);
return;
}
ItemStackWrapper remapped = ItemStackRemapper.remapClientbound(version, itemstack.cloneItemStack());
if (fireEvent && ItemStackWriteEvent.getHandlerList().getRegisteredListeners().length > 0) {
ItemStackWriteEvent event = new InternalItemStackWriteEvent(version, itemstack, remapped);
Bukkit.getPluginManager().callEvent(event);
}
to.writeShort(ItemStackRemapper.ITEM_ID_REMAPPING_REGISTRY.getTable(version).getRemap(remapped.getTypeId()));
to.writeByte(remapped.getAmount());
to.writeShort(remapped.getData());
writeTag(to, version, remapped.getTag());
}
public static NBTTagCompoundWrapper readTag(ByteBuf from, ProtocolVersion version) {
try {
if (isUsingShortLengthNBT(version)) {
final short length = from.readShort();
if (length < 0) {
return ServerPlatform.get().getWrapperFactory().createNullNBTCompound();
}
try (InputStream inputstream = new GZIPInputStream(new ByteBufInputStream(from.readSlice(length)))) {
return ServerPlatform.get().getWrapperFactory().createNBTCompoundFromStream(inputstream);
}
} else if (isUsingDirectOrZeroIfNoneNBT(version)) {
from.markReaderIndex();
if (from.readByte() == 0) {
return ServerPlatform.get().getWrapperFactory().createNullNBTCompound();
}
from.resetReaderIndex();
try (DataInputStream datainputstream = new DataInputStream(new ByteBufInputStream(from))) {
return ServerPlatform.get().getWrapperFactory().createNBTCompoundFromStream(datainputstream);
}
} else {
throw new IllegalArgumentException(MessageFormat.format("Don't know how to read nbt of version {0}", version));
}
} catch (IOException e) {
throw new DecoderException(e);
}
}
public static void writeTag(ByteBuf to, ProtocolVersion version, NBTTagCompoundWrapper tag) {
try {
if (isUsingShortLengthNBT(version)) {
if (tag.isNull()) {
to.writeShort(-1);
} else {
int writerIndex = to.writerIndex();
//fake length
to.writeShort(0);
//actual nbt
try (OutputStream outputstream = new GZIPOutputStream(new ByteBufOutputStream(to))) {
tag.writeToStream(outputstream);
}
//now replace fake length with real length
to.setShort(writerIndex, to.writerIndex() - writerIndex - Short.BYTES);
}
} else if (isUsingDirectOrZeroIfNoneNBT(version)) {
if (tag.isNull()) {
to.writeByte(0);
} else {
try (OutputStream outputstream = new ByteBufOutputStream(to)) {
tag.writeToStream(outputstream);
}
}
} else {
throw new IllegalArgumentException(MessageFormat.format("Don't know how to write nbt of version {0}", version));
}
} catch (Throwable ioexception) {
throw new EncoderException(ioexception);
}
}
private static final boolean isUsingShortLengthNBT(ProtocolVersion version) {
return (version.getProtocolType() == ProtocolType.PC) && version.isBeforeOrEq(ProtocolVersion.MINECRAFT_1_7_10);
}
private static final boolean isUsingDirectOrZeroIfNoneNBT(ProtocolVersion version) {
return (version.getProtocolType() == ProtocolType.PC) && version.isAfterOrEq(ProtocolVersion.MINECRAFT_1_8);
}
public static class InternalItemStackWriteEvent extends ItemStackWriteEvent {
private final org.bukkit.inventory.ItemStack wrapped;
public InternalItemStackWriteEvent(ProtocolVersion version, ItemStackWrapper original, ItemStackWrapper itemstack) {
super(version, original.asBukkitMirror());
this.wrapped = itemstack.asBukkitMirror();
}
@Override
public org.bukkit.inventory.ItemStack getResult() {
return wrapped;
}
}
}